Procházet zdrojové kódy

Compile timeout Paywall - Adding the second component that will be displayed after paywall dismissal (#23413)

* copy pasting the code into new redesign file from old paywall file

* creating a new file for redesign - pdf-log-entry-redesign and copy pasting the old file content for now

* adding redesign file for header and copy pasting old file content for now

* using pdf-log-entry-redesign

* adding first round of styling for headint title under BS5 styling

* adding hasBorder property on the inhouse button component

* adding a cta container for 2 buttons

* adding the icon and fixing the class hierarchy

* fixing the spacing so spacing matches the figma design

* adding a translation for heading

* adding bg color and spacing for heading

* removing no thanks button

* changing the font size

* adding the link colors

* adding the required spacing on the new website redesign logs pane components

* seperating the whole component into a new component TimeoutMessageAfterPaywallDismissal for easy display later in

* removing the class that I had added earlier

* deleting the website redesign folder because files dupliocated in that folder did not have any content changes, redesign only needs styling changes for now

* adding try for free translation

* adding the unfilled icon and ficing the heading sizew

* fixing the padding of log-entry-formatted-content

* running npm run extract-translations

GitOrigin-RevId: 810ddd6037cbad0761ea23a9a2e0693a7ad7130a
Davinder Singh před 1 rokem
rodič
revize
09ab193239

+ 2 - 0
services/web/frontend/extracted-translations.json

@@ -1198,6 +1198,7 @@
   "professional": "",
   "progress_bar_percentage": "",
   "project_approaching_file_limit": "",
+  "project_failed_to_compile": "",
   "project_figure_modal": "",
   "project_files": "",
   "project_flagged_too_many_compiles": "",
@@ -1777,6 +1778,7 @@
   "tried_to_register_with_email": "",
   "troubleshooting_tip": "",
   "try_again": "",
+  "try_for_free": "",
   "try_it_for_free": "",
   "try_now": "",
   "try_premium_for_free": "",

binární
services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2


+ 1 - 0
services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs

@@ -21,4 +21,5 @@ export default /** @type {const} */ ([
   'table_chart',
   'upload_file',
   'web_asset',
+  'error',
 ])

+ 196 - 0
services/web/frontend/js/features/pdf-preview/components/timeout-message-after-paywall-dismissal.tsx

@@ -0,0 +1,196 @@
+import getMeta from '@/utils/meta'
+import { Trans, useTranslation } from 'react-i18next'
+import { memo, useCallback } from 'react'
+import { useDetachCompileContext } from '@/shared/context/detach-compile-context'
+import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
+import MaterialIcon from '@/shared/components/material-icon'
+import OLButton from '@/features/ui/components/ol/ol-button'
+import { useStopOnFirstError } from '@/shared/hooks/use-stop-on-first-error'
+import PdfLogEntry from './pdf-log-entry'
+
+function TimeoutMessageAfterPaywallDismissal() {
+  const {
+    startCompile,
+    lastCompileOptions,
+    setAnimateCompileDropdownArrow,
+    isProjectOwner,
+  } = useDetachCompileContext()
+
+  const { enableStopOnFirstError } = useStopOnFirstError({
+    eventSource: 'timeout-new',
+  })
+
+  const handleEnableStopOnFirstErrorClick = useCallback(() => {
+    enableStopOnFirstError()
+    startCompile({ stopOnFirstError: true })
+    setAnimateCompileDropdownArrow(true)
+  }, [enableStopOnFirstError, startCompile, setAnimateCompileDropdownArrow])
+
+  return (
+    <div className="website-redesign timeout-upgrade-paywall-prompt">
+      <CompileTimeout isProjectOwner={isProjectOwner} />
+      {getMeta('ol-ExposedSettings').enableSubscriptions && (
+        <PreventTimeoutHelpMessage
+          handleEnableStopOnFirstErrorClick={handleEnableStopOnFirstErrorClick}
+          lastCompileOptions={lastCompileOptions}
+          isProjectOwner={isProjectOwner}
+        />
+      )}
+    </div>
+  )
+}
+
+type CompileTimeoutProps = {
+  isProjectOwner: boolean
+}
+
+const CompileTimeout = memo(function CompileTimeout({
+  isProjectOwner,
+}: CompileTimeoutProps) {
+  const { t } = useTranslation()
+
+  const hasNewPaywallCta = useFeatureFlag('paywall-cta')
+
+  return (
+    <PdfLogEntry
+      headerTitle={t('project_failed_to_compile')}
+      headerIcon={
+        <MaterialIcon
+          type="error"
+          className="log-entry-header-title"
+          size="2x"
+          unfilled
+        />
+      }
+      formattedContent={
+        getMeta('ol-ExposedSettings').enableSubscriptions && (
+          <>
+            <p>
+              {isProjectOwner
+                ? t('your_project_exceeded_compile_timeout_limit_on_free_plan')
+                : t('this_project_exceeded_compile_timeout_limit_on_free_plan')}
+            </p>
+
+            {isProjectOwner === false && (
+              <Trans
+                i18nKey="tell_the_project_owner_and_ask_them_to_upgrade"
+                components={[
+                  // eslint-disable-next-line react/jsx-key
+                  <strong />,
+                ]}
+              />
+            )}
+
+            {isProjectOwner && (
+              <div className="log-entry-cta-container">
+                <StartFreeTrialButton
+                  source="compile-timeout"
+                  buttonProps={{ variant: 'secondary' }}
+                >
+                  {hasNewPaywallCta
+                    ? t('get_more_compile_time')
+                    : t('try_for_free')}
+                </StartFreeTrialButton>
+              </div>
+            )}
+          </>
+        )
+      }
+      // @ts-ignore
+      entryAriaLabel={t('your_compile_timed_out')}
+      level="error"
+    />
+  )
+})
+
+type PreventTimeoutHelpMessageProps = {
+  lastCompileOptions: any
+  handleEnableStopOnFirstErrorClick: () => void
+  isProjectOwner: boolean
+}
+
+const PreventTimeoutHelpMessage = memo(function PreventTimeoutHelpMessage({
+  lastCompileOptions,
+  handleEnableStopOnFirstErrorClick,
+  isProjectOwner,
+}: PreventTimeoutHelpMessageProps) {
+  const { t } = useTranslation()
+
+  return (
+    <PdfLogEntry
+      headerTitle={t('reasons_for_compile_timeouts')}
+      formattedContent={
+        <>
+          <p>{t('common_causes_of_compile_timeouts_include')}:</p>
+          <ul>
+            <li>
+              <Trans
+                i18nKey="large_or_high-resolution_images_taking_too_long"
+                components={[
+                  // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
+                  <a
+                    href="/learn/how-to/Optimising_very_large_image_files"
+                    rel="noopener noreferrer"
+                    target="_blank"
+                  />,
+                ]}
+              />
+            </li>
+            <li>
+              <Trans
+                i18nKey="a_fatal_compile_error_that_completely_blocks_compilation"
+                components={[
+                  // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
+                  <a
+                    href="/learn/how-to/Fixing_and_preventing_compile_timeouts#Step_3:_Assess_your_project_for_time-consuming_tasks_and_fatal_errors"
+                    rel="noopener noreferrer"
+                    target="_blank"
+                  />,
+                ]}
+              />
+              {!lastCompileOptions.stopOnFirstError && (
+                <>
+                  {' '}
+                  <Trans
+                    i18nKey="enable_stop_on_first_error_under_recompile_dropdown_menu"
+                    components={[
+                      // eslint-disable-next-line react/jsx-key
+                      <OLButton
+                        variant="link"
+                        className="btn-inline-link fw-bold"
+                        size="sm"
+                        onClick={handleEnableStopOnFirstErrorClick}
+                        bs3Props={{ bsSize: 'xsmall' }}
+                      />,
+                      // eslint-disable-next-line react/jsx-key
+                      <strong />,
+                    ]}
+                  />{' '}
+                </>
+              )}
+            </li>
+          </ul>
+          <p className="mb-0">
+            <Trans
+              i18nKey="learn_more_about_other_causes_of_compile_timeouts"
+              components={[
+                // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
+                <a
+                  href="/learn/how-to/Fixing_and_preventing_compile_timeouts"
+                  rel="noopener noreferrer"
+                  target="_blank"
+                />,
+              ]}
+            />
+          </p>
+        </>
+      }
+      // @ts-ignore
+      entryAriaLabel={t('reasons_for_compile_timeouts')}
+      level="raw"
+    />
+  )
+})
+
+export default memo(TimeoutMessageAfterPaywallDismissal)

+ 3 - 1
services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-paywall-prompt.tsx

@@ -1,5 +1,6 @@
 import getMeta from '@/utils/meta'
 import { useMemo } from 'react'
+import TimeoutMessageAfterPaywallDismissal from './timeout-message-after-paywall-dismissal'
 
 const studentRoles = [
   'High-school student',
@@ -8,14 +9,15 @@ const studentRoles = [
   'Doctoral student (e.g. PhD, MD, EngD)',
 ]
 
+// We can display TimeoutMessageAfterPaywallDismissal after the user has dismissed the paywall. That logic can be implemented in this file or somewhere else?
 function TimeoutUpgradePaywallPrompt() {
   const odcRole = getMeta('ol-odcRole')
   const isStudent = useMemo(() => studentRoles.includes(odcRole), [odcRole])
 
   return (
     <div>
-      <p>Hello world from new paywall component</p>
       <p>Current user is {!isStudent && 'not'} a student.</p>
+      <TimeoutMessageAfterPaywallDismissal />
     </div>
   )
 }

+ 55 - 0
services/web/frontend/stylesheets/bootstrap-5/pages/editor/logs.scss

@@ -209,3 +209,58 @@
     text-align: left;
   }
 }
+
+// As part of compile time paywall redesign, we are only migrating the necessary classes needed for the split test
+// Other classes should be migrated too as a part of website redesign project later on.
+
+.timeout-upgrade-paywall-prompt {
+  display: flex;
+  flex-direction: column;
+  gap: 10px; // adding this value to match existing spacing in logs pane, there is no variable for 10px
+}
+
+.website-redesign {
+  .log-entry-header {
+    @include heading-sm;
+
+    font-weight: 600;
+    padding: var(--spacing-05) var(--spacing-06);
+  }
+
+  .log-entry-content {
+    padding: 0;
+  }
+
+  .log-entry-formatted-content {
+    @include body-sm;
+
+    padding: var(--spacing-06);
+    color: var(--neutral-70);
+
+    a,
+    .btn-inline-link {
+      color: var(--blue-50);
+    }
+  }
+
+  .log-entry-cta-container {
+    padding-top: var(--spacing-06);
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .log-entry-header-error {
+    background-color: var(--red-10);
+
+    .log-entry-header-title {
+      @include heading-sm;
+
+      color: var(--red-50);
+    }
+  }
+
+  .log-entry-header-raw {
+    background-color: var(--neutral-60);
+    padding: var(--spacing-04) var(--spacing-06);
+  }
+}

+ 1 - 0
services/web/locales/en.json

@@ -1617,6 +1617,7 @@
   "progress_bar_percentage": "Progress bar from 0 to 100%",
   "project": "project",
   "project_approaching_file_limit": "This project is approaching the file limit",
+  "project_failed_to_compile": "Your project failed to compile",
   "project_figure_modal": "Project",
   "project_files": "Project files",
   "project_flagged_too_many_compiles": "This project has been flagged for compiling too often. The limit will be lifted shortly.",