modal.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { useIdeRedesignSwitcherContext } from '@/features/ide-react/context/ide-redesign-switcher-context'
  2. import OLButton from '@/features/ui/components/ol/ol-button'
  3. import OLModal, {
  4. OLModalBody,
  5. OLModalFooter,
  6. OLModalHeader,
  7. OLModalTitle,
  8. } from '@/features/ui/components/ol/ol-modal'
  9. import { FC, useCallback } from 'react'
  10. import {
  11. canUseNewEditor,
  12. useIsNewEditorEnabled,
  13. } from '../../utils/new-editor-utils'
  14. import Notification from '@/shared/components/notification'
  15. import { useSwitchEnableNewEditorState } from '../../hooks/use-switch-enable-new-editor-state'
  16. import { Trans, useTranslation } from 'react-i18next'
  17. import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
  18. import { useFeatureFlag } from '@/shared/context/split-test-context'
  19. import { useSurveyUrl } from '../../hooks/use-survey-url'
  20. export const IdeRedesignSwitcherModal = () => {
  21. const { t } = useTranslation()
  22. const { showSwitcherModal, setShowSwitcherModal } =
  23. useIdeRedesignSwitcherContext()
  24. const onHide = useCallback(
  25. () => setShowSwitcherModal(false),
  26. [setShowSwitcherModal]
  27. )
  28. const { loading, error, setEditorRedesignStatus } =
  29. useSwitchEnableNewEditorState()
  30. const enabled = useIsNewEditorEnabled()
  31. const hasAccess = canUseNewEditor()
  32. if (!hasAccess) {
  33. return null
  34. }
  35. const Content = enabled
  36. ? SwitcherModalContentEnabled
  37. : SwitcherModalContentDisabled
  38. return (
  39. <OLModal
  40. show={showSwitcherModal}
  41. onHide={onHide}
  42. className="ide-redesign-switcher-modal"
  43. >
  44. <OLModalHeader closeButton>
  45. <OLModalTitle>{t('the_new_overleaf_editor')}</OLModalTitle>
  46. </OLModalHeader>
  47. {error && <Notification type="error" content={error} isDismissible />}
  48. <Content
  49. setEditorRedesignStatus={setEditorRedesignStatus}
  50. hide={onHide}
  51. loading={loading}
  52. />
  53. </OLModal>
  54. )
  55. }
  56. type ModalContentProps = {
  57. setEditorRedesignStatus: (enabled: boolean) => Promise<void>
  58. hide: () => void
  59. loading: boolean
  60. }
  61. const SwitcherModalContentEnabled: FC<ModalContentProps> = ({
  62. setEditorRedesignStatus,
  63. hide,
  64. loading,
  65. }) => {
  66. const { t } = useTranslation()
  67. const { sendEvent } = useEditorAnalytics()
  68. const disable = useCallback(() => {
  69. sendEvent('editor-redesign-toggle', {
  70. action: 'disable',
  71. location: 'modal',
  72. })
  73. setEditorRedesignStatus(false)
  74. .then(hide)
  75. .catch(() => {
  76. // do nothing, we're already showing the error
  77. })
  78. }, [setEditorRedesignStatus, hide, sendEvent])
  79. const surveyURL = useSurveyUrl()
  80. return (
  81. <>
  82. <OLModalBody>
  83. <h3>{t('youre_helping_us_shape_the_future_of_overleaf')}</h3>
  84. <p>
  85. {t(
  86. 'thanks_for_being_part_of_this_labs_experiment_your_feedback_will_help_us_make_the_new_editor_the_best_yet'
  87. )}
  88. </p>
  89. <SwitcherWhatsNew />
  90. <LeavingNote />
  91. </OLModalBody>
  92. <OLModalFooter>
  93. <OLButton
  94. onClick={disable}
  95. variant="secondary"
  96. className="me-auto"
  97. disabled={loading}
  98. >
  99. {t('switch_to_old_editor')}
  100. </OLButton>
  101. <OLButton onClick={hide} variant="secondary">
  102. {t('cancel')}
  103. </OLButton>
  104. <OLButton
  105. href={surveyURL}
  106. target="_blank"
  107. rel="noopener noreferrer"
  108. variant="primary"
  109. >
  110. {t('give_feedback')}
  111. </OLButton>
  112. </OLModalFooter>
  113. </>
  114. )
  115. }
  116. const SwitcherModalContentDisabled: FC<ModalContentProps> = ({
  117. setEditorRedesignStatus,
  118. hide,
  119. loading,
  120. }) => {
  121. const { t } = useTranslation()
  122. const { sendEvent } = useEditorAnalytics()
  123. const enable = useCallback(() => {
  124. sendEvent('editor-redesign-toggle', {
  125. action: 'enable',
  126. location: 'modal',
  127. })
  128. setEditorRedesignStatus(true)
  129. .then(hide)
  130. .catch(() => {
  131. // do nothing, we're already showing the error
  132. })
  133. }, [setEditorRedesignStatus, hide, sendEvent])
  134. return (
  135. <>
  136. <OLModalBody>
  137. <h3>{t('help_shape_the_future_of_overleaf')}</h3>
  138. <p>{t('were_redesigning_our_editor_to_make_it_easier_to_use')}</p>
  139. <SwitcherWhatsNew />
  140. <LeavingNote />
  141. </OLModalBody>
  142. <OLModalFooter>
  143. <OLButton onClick={hide} variant="secondary">
  144. {t('cancel')}
  145. </OLButton>
  146. <OLButton onClick={enable} variant="primary" disabled={loading}>
  147. {t('switch_to_new_editor')}
  148. </OLButton>
  149. </OLModalFooter>
  150. </>
  151. )
  152. }
  153. const SwitcherWhatsNew = () => {
  154. const { t } = useTranslation()
  155. const newErrorlogs = useFeatureFlag('new-editor-error-logs-redesign')
  156. return (
  157. <div className="ide-redesign-switcher-modal-whats-new">
  158. <h4>{t('latest_updates')}</h4>
  159. <ul>
  160. {newErrorlogs && <li>{t('new_error_logs_panel')}</li>}
  161. <li>{t('searching_all_project_files_is_now_available')}</li>
  162. <li>{t('double_clicking_on_the_pdf_shows')}</li>
  163. </ul>
  164. <hr />
  165. <h4>{t('whats_different_in_the_new_editor')}</h4>
  166. <ul>
  167. <li>{t('new_look_and_feel')}</li>
  168. <li>
  169. {t('new_navigation_introducing_left_hand_side_rail_and_top_menus')}
  170. </li>
  171. <li>{t('new_look_and_placement_of_the_settings')}</li>
  172. <li>{t('improved_dark_mode')}</li>
  173. <li>{t('review_panel_and_error_logs_moved_to_the_left')}</li>
  174. </ul>
  175. </div>
  176. )
  177. }
  178. const LeavingNote = () => {
  179. return (
  180. <p className="ide-redesign-switcher-modal-leave-text">
  181. <Trans
  182. i18nKey="you_can_leave_the_experiment_from_your_account_settings_at_any_time"
  183. // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
  184. components={[<a href="/user/settings" />]}
  185. shouldUnescape
  186. tOptions={{ interpolation: { escapeValue: true } }}
  187. />
  188. </p>
  189. )
  190. }