timeout-upgrade-prompt-new.tsx 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import { Trans, useTranslation } from 'react-i18next'
  2. import { useDetachCompileContext } from '../../../shared/context/detach-compile-context'
  3. import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
  4. import { memo, useCallback, useMemo, useState } from 'react'
  5. import PdfLogEntry from './pdf-log-entry'
  6. import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
  7. import OLButton from '@/shared/components/ol/ol-button'
  8. import * as eventTracking from '../../../infrastructure/event-tracking'
  9. import getMeta from '@/utils/meta'
  10. import { populateEditorRedesignSegmentation } from '@/shared/hooks/use-editor-analytics'
  11. import CompileTimeoutPaywallModal from '@/features/pdf-preview/components/compile-timeout-paywall-modal'
  12. import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
  13. import { isSplitTestEnabled } from '@/utils/splitTestUtils'
  14. function TimeoutUpgradePromptNew() {
  15. const {
  16. startCompile,
  17. lastCompileOptions,
  18. setAnimateCompileDropdownArrow,
  19. isProjectOwner,
  20. } = useDetachCompileContext()
  21. const newEditor = useIsNewEditorEnabled()
  22. const shouldHideCompileTimeoutInfo = isSplitTestEnabled(
  23. 'compile-timeout-remove-info'
  24. )
  25. const isCompileTimeoutTargetPlansEnabled = isSplitTestEnabled(
  26. 'compile-timeout-target-plans'
  27. )
  28. const [showCompileTimeoutPaywall, setShowCompileTimeoutPaywall] =
  29. useState(false)
  30. const { enableStopOnFirstError } = useStopOnFirstError({
  31. eventSource: 'timeout-new',
  32. })
  33. const handleEnableStopOnFirstErrorClick = useCallback(() => {
  34. enableStopOnFirstError()
  35. startCompile({ stopOnFirstError: true })
  36. setAnimateCompileDropdownArrow(true)
  37. }, [enableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
  38. const { compileTimeout } = getMeta('ol-compileSettings')
  39. const sharedSegmentation = useMemo(
  40. () =>
  41. populateEditorRedesignSegmentation(
  42. {
  43. 'is-owner': isProjectOwner,
  44. compileTime: compileTimeout,
  45. location: 'logs',
  46. },
  47. newEditor
  48. ),
  49. [isProjectOwner, compileTimeout, newEditor]
  50. )
  51. return (
  52. <>
  53. <CompileTimeout
  54. isProjectOwner={isProjectOwner}
  55. segmentation={sharedSegmentation}
  56. onShowPaywallModal={() => setShowCompileTimeoutPaywall(true)}
  57. isCompileTimeoutTargetPlansEnabled={isCompileTimeoutTargetPlansEnabled}
  58. />
  59. {getMeta('ol-ExposedSettings').enableSubscriptions &&
  60. !shouldHideCompileTimeoutInfo && (
  61. <PreventTimeoutHelpMessage
  62. handleEnableStopOnFirstErrorClick={
  63. handleEnableStopOnFirstErrorClick
  64. }
  65. lastCompileOptions={lastCompileOptions}
  66. />
  67. )}
  68. <CompileTimeoutPaywallModal
  69. show={showCompileTimeoutPaywall}
  70. onHide={() => setShowCompileTimeoutPaywall(false)}
  71. />
  72. </>
  73. )
  74. }
  75. type CompileTimeoutProps = {
  76. isProjectOwner: boolean
  77. segmentation: eventTracking.Segmentation
  78. onShowPaywallModal: () => void
  79. isCompileTimeoutTargetPlansEnabled: boolean
  80. }
  81. const CompileTimeout = memo(function CompileTimeout({
  82. isProjectOwner,
  83. segmentation,
  84. onShowPaywallModal,
  85. isCompileTimeoutTargetPlansEnabled,
  86. }: CompileTimeoutProps) {
  87. const { t } = useTranslation()
  88. const newEditor = useIsNewEditorEnabled()
  89. const extraSearchParams = useMemo(() => {
  90. return {
  91. itm_content: newEditor ? 'new-editor' : 'old-editor',
  92. }
  93. }, [newEditor])
  94. const handleFreeTrialClick = useCallback(
  95. (event: React.MouseEvent<HTMLButtonElement>) => {
  96. if (isCompileTimeoutTargetPlansEnabled) {
  97. event.preventDefault()
  98. event.stopPropagation()
  99. onShowPaywallModal()
  100. }
  101. },
  102. [isCompileTimeoutTargetPlansEnabled, onShowPaywallModal]
  103. )
  104. return (
  105. <PdfLogEntry
  106. autoExpand
  107. headerTitle={t('your_compile_timed_out')}
  108. formattedContent={
  109. getMeta('ol-ExposedSettings').enableSubscriptions && (
  110. <>
  111. <p>
  112. {isProjectOwner
  113. ? t('your_project_exceeded_compile_timeout_limit_on_free_plan')
  114. : t('this_project_exceeded_compile_timeout_limit_on_free_plan')}
  115. </p>
  116. {isProjectOwner ? (
  117. <p>
  118. <strong>{t('upgrade_for_more_compile_time')}</strong>{' '}
  119. {t(
  120. 'plus_additional_collaborators_document_history_track_changes_and_more'
  121. )}
  122. </p>
  123. ) : (
  124. <Trans
  125. i18nKey="tell_the_project_owner_and_ask_them_to_upgrade"
  126. components={[
  127. // eslint-disable-next-line react/jsx-key
  128. <strong />,
  129. ]}
  130. />
  131. )}
  132. {isProjectOwner && (
  133. <p className="text-center">
  134. <StartFreeTrialButton
  135. source="compile-timeout"
  136. buttonProps={{ variant: 'primary', className: 'w-100' }}
  137. segmentation={segmentation}
  138. extraSearchParams={extraSearchParams}
  139. handleClick={handleFreeTrialClick}
  140. >
  141. {t('start_a_free_trial')}
  142. </StartFreeTrialButton>
  143. </p>
  144. )}
  145. </>
  146. )
  147. }
  148. // @ts-ignore
  149. entryAriaLabel={t('your_compile_timed_out')}
  150. level="error"
  151. />
  152. )
  153. })
  154. type PreventTimeoutHelpMessageProps = {
  155. lastCompileOptions: any
  156. handleEnableStopOnFirstErrorClick: () => void
  157. }
  158. const PreventTimeoutHelpMessage = memo(function PreventTimeoutHelpMessage({
  159. lastCompileOptions,
  160. handleEnableStopOnFirstErrorClick,
  161. }: PreventTimeoutHelpMessageProps) {
  162. const { t } = useTranslation()
  163. return (
  164. <PdfLogEntry
  165. autoExpand
  166. headerTitle={t('reasons_for_compile_timeouts')}
  167. formattedContent={
  168. <>
  169. <p>{t('common_causes_of_compile_timeouts_include')}:</p>
  170. <ul>
  171. <li>
  172. <Trans
  173. i18nKey="project_timed_out_optimize_images"
  174. components={[
  175. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  176. <a
  177. href="/learn/how-to/Optimising_very_large_image_files"
  178. rel="noopener noreferrer"
  179. target="_blank"
  180. onClick={() => {
  181. eventTracking.sendMB('paywall-info-click', {
  182. 'paywall-type': 'compile-timeout',
  183. content: 'docs',
  184. type: 'optimize',
  185. })
  186. }}
  187. />,
  188. ]}
  189. />
  190. </li>
  191. <li>
  192. <Trans
  193. i18nKey="a_fatal_compile_error_that_completely_blocks_compilation"
  194. components={[
  195. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  196. <a
  197. href="/learn/how-to/Fixing_and_preventing_compile_timeouts#Step_3:_Assess_your_project_for_time-consuming_tasks_and_fatal_errors"
  198. rel="noopener noreferrer"
  199. target="_blank"
  200. onClick={() => {
  201. eventTracking.sendMB('paywall-info-click', {
  202. 'paywall-type': 'compile-timeout',
  203. content: 'docs',
  204. type: 'fatal-error',
  205. })
  206. }}
  207. />,
  208. ]}
  209. />
  210. {!lastCompileOptions.stopOnFirstError && (
  211. <>
  212. {' '}
  213. <Trans
  214. i18nKey="enable_stop_on_first_error_under_recompile_dropdown_menu"
  215. components={[
  216. // eslint-disable-next-line react/jsx-key
  217. <OLButton
  218. variant="link"
  219. className="btn-inline-link fw-bold"
  220. size="sm"
  221. onClick={handleEnableStopOnFirstErrorClick}
  222. />,
  223. // eslint-disable-next-line react/jsx-key
  224. <strong />,
  225. ]}
  226. />{' '}
  227. </>
  228. )}
  229. </li>
  230. </ul>
  231. <p>
  232. <Trans
  233. i18nKey="project_timed_out_learn_more"
  234. components={[
  235. // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
  236. <a
  237. href="/learn/how-to/Fixing_and_preventing_compile_timeouts"
  238. rel="noopener noreferrer"
  239. target="_blank"
  240. onClick={() => {
  241. eventTracking.sendMB('paywall-info-click', {
  242. 'paywall-type': 'compile-timeout',
  243. content: 'docs',
  244. type: 'learn-more',
  245. })
  246. }}
  247. />,
  248. ]}
  249. />
  250. </p>
  251. </>
  252. }
  253. // @ts-ignore
  254. entryAriaLabel={t('reasons_for_compile_timeouts')}
  255. level="raw"
  256. />
  257. )
  258. })
  259. export default memo(TimeoutUpgradePromptNew)