export-document-toasts.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { GlobalToastGeneratorEntry } from '@/features/ide-react/components/global-toasts'
  2. import { Trans, useTranslation } from 'react-i18next'
  3. const PreparingExportToast = () => {
  4. const { t } = useTranslation()
  5. return <span>{t('preparing_for_export')}</span>
  6. }
  7. const ExportDocumentErrorToast = ({ data }: { data?: any }) => {
  8. const { t } = useTranslation()
  9. const errorMessage =
  10. typeof data?.errorMessage === 'string' ? data.errorMessage : null
  11. return (
  12. <>
  13. <p>
  14. <b>{t('we_couldnt_export_this_document')}</b>
  15. </p>
  16. <Trans
  17. i18nKey="the_document_contains_formatting_we_werent_able_to_convert"
  18. components={[
  19. // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
  20. <a
  21. href="https://docs.overleaf.com/managing-projects-and-files/importing-and-exporting-files#common-issues-and-how-to-address-them"
  22. target="_BLANK"
  23. rel="noopener noreferrer"
  24. />,
  25. ]}
  26. />
  27. {errorMessage && (
  28. <details>
  29. <summary>{t('conversion_error_details')}</summary>
  30. <pre
  31. style={{ maxWidth: '800px', maxHeight: '300px', overflow: 'auto' }}
  32. >
  33. <code>{errorMessage}</code>
  34. </pre>
  35. </details>
  36. )}
  37. </>
  38. )
  39. }
  40. const ExportDocumentSuccessToast = ({ data }: { data?: any }) => {
  41. const type = data?.type
  42. if (type === 'docx') {
  43. return (
  44. <Trans
  45. i18nKey="docx_export_feedback_message"
  46. components={[
  47. // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
  48. <a
  49. href="https://forms.gle/Fg4BUXV2yv61hStX8"
  50. target="_BLANK"
  51. rel="noopener noreferrer"
  52. />,
  53. ]}
  54. />
  55. )
  56. } else if (type === 'markdown') {
  57. return (
  58. <Trans
  59. i18nKey="markdown_export_feedback_message"
  60. components={[
  61. // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
  62. <a
  63. href="https://forms.gle/wc43zEukeqpec9mAA"
  64. target="_BLANK"
  65. rel="noopener noreferrer"
  66. />,
  67. ]}
  68. />
  69. )
  70. } else {
  71. return (
  72. <Trans
  73. i18nKey="generic_export_feedback_message"
  74. components={[
  75. // eslint-disable-next-line react/jsx-key, jsx-a11y/anchor-has-content
  76. <a href="/contact" target="_BLANK" rel="noopener noreferrer" />,
  77. ]}
  78. />
  79. )
  80. }
  81. }
  82. const generators: GlobalToastGeneratorEntry[] = [
  83. {
  84. key: 'export-document:error',
  85. generator: (data: any) => ({
  86. content: <ExportDocumentErrorToast data={data} />,
  87. type: 'error',
  88. // Only auto-hide if we have no extra details
  89. autoHide: !data?.errorMessage,
  90. delay: 5000,
  91. isDismissible: true,
  92. }),
  93. },
  94. {
  95. key: 'export-document:preparing',
  96. generator: () => ({
  97. content: <PreparingExportToast />,
  98. type: 'info',
  99. autoHide: false,
  100. isDismissible: true,
  101. }),
  102. },
  103. {
  104. key: 'export-document:success',
  105. generator: (data: any) => ({
  106. content: <ExportDocumentSuccessToast data={data} />,
  107. type: 'success',
  108. autoHide: true,
  109. delay: 45000,
  110. isDismissible: true,
  111. }),
  112. },
  113. ]
  114. export default generators
  115. // We only ever care about the latest error toast, so use a static handle.
  116. const EXPORT_DOCUMENT_ERROR_HANDLE = 'export-document-error'
  117. export const showExportDocumentError = (errorMessage?: string) => {
  118. window.dispatchEvent(
  119. new CustomEvent('ide:show-toast', {
  120. detail: {
  121. key: 'export-document:error',
  122. handle: EXPORT_DOCUMENT_ERROR_HANDLE,
  123. errorMessage,
  124. },
  125. })
  126. )
  127. }
  128. export const hideExportDocumentError = () => {
  129. window.dispatchEvent(
  130. new CustomEvent('ide:dismiss-toast', {
  131. detail: { handle: EXPORT_DOCUMENT_ERROR_HANDLE },
  132. })
  133. )
  134. }
  135. export const showPreparingExportToast = () => {
  136. const handle = `export-document-preparing-${Date.now()}`
  137. window.dispatchEvent(
  138. new CustomEvent('ide:show-toast', {
  139. detail: { key: 'export-document:preparing', handle },
  140. })
  141. )
  142. return handle
  143. }
  144. export const hidePreparingExportToast = (handle: string) => {
  145. window.dispatchEvent(
  146. new CustomEvent('ide:dismiss-toast', {
  147. detail: { key: 'export-document:preparing', handle },
  148. })
  149. )
  150. }
  151. export const showExportDocumentSuccess = (type: 'docx' | 'markdown') => {
  152. window.dispatchEvent(
  153. new CustomEvent('ide:show-toast', {
  154. detail: { key: 'export-document:success', type },
  155. })
  156. )
  157. }