share-project-modal-content.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { useTranslation } from 'react-i18next'
  2. import { useEditorContext } from '@/shared/context/editor-context'
  3. import { lazy, Suspense } from 'react'
  4. import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
  5. import ClickableElementEnhancer from '@/shared/components/clickable-element-enhancer'
  6. import OLModal, {
  7. OLModalBody,
  8. OLModalFooter,
  9. OLModalHeader,
  10. OLModalTitle,
  11. } from '@/features/ui/components/ol/ol-modal'
  12. import OLNotification from '@/features/ui/components/ol/ol-notification'
  13. import OLButton from '@/features/ui/components/ol/ol-button'
  14. import { Spinner } from 'react-bootstrap'
  15. const ReadOnlyTokenLink = lazy(() =>
  16. import('./link-sharing').then(({ ReadOnlyTokenLink }) => ({
  17. // re-export as default -- lazy can only handle default exports.
  18. default: ReadOnlyTokenLink,
  19. }))
  20. )
  21. const ShareModalBody = lazy(() => import('./share-modal-body'))
  22. type ShareProjectModalContentProps = {
  23. cancel: () => void
  24. show: boolean
  25. animation: boolean
  26. inFlight: boolean
  27. error: string | undefined
  28. }
  29. export default function ShareProjectModalContent({
  30. show,
  31. cancel,
  32. animation,
  33. inFlight,
  34. error,
  35. }: ShareProjectModalContentProps) {
  36. const { t } = useTranslation()
  37. const { isRestrictedTokenMember } = useEditorContext()
  38. return (
  39. <OLModal show={show} onHide={cancel} animation={animation}>
  40. <OLModalHeader closeButton>
  41. <OLModalTitle>{t('share_project')}</OLModalTitle>
  42. </OLModalHeader>
  43. <OLModalBody className="modal-body-share modal-link-share">
  44. <div className="container-fluid">
  45. <Suspense fallback={<FullSizeLoadingSpinner minHeight="15rem" />}>
  46. {isRestrictedTokenMember ? (
  47. <ReadOnlyTokenLink />
  48. ) : (
  49. <ShareModalBody />
  50. )}
  51. </Suspense>
  52. {error && (
  53. <OLNotification
  54. type="error"
  55. content={<ErrorMessage error={error} />}
  56. className="mb-0 mt-3"
  57. />
  58. )}
  59. </div>
  60. </OLModalBody>
  61. <OLModalFooter>
  62. <div className="me-auto">
  63. {inFlight && (
  64. <Spinner
  65. animation="border"
  66. aria-hidden="true"
  67. size="sm"
  68. role="status"
  69. />
  70. )}
  71. </div>
  72. <ClickableElementEnhancer
  73. onClick={cancel}
  74. as={OLButton}
  75. variant="secondary"
  76. disabled={inFlight}
  77. >
  78. {t('close')}
  79. </ClickableElementEnhancer>
  80. </OLModalFooter>
  81. </OLModal>
  82. )
  83. }
  84. function ErrorMessage({ error }: Pick<ShareProjectModalContentProps, 'error'>) {
  85. const { t } = useTranslation()
  86. switch (error) {
  87. case 'cannot_invite_non_user':
  88. return <>{t('cannot_invite_non_user')}</>
  89. case 'cannot_verify_user_not_robot':
  90. return <>{t('cannot_verify_user_not_robot')}</>
  91. case 'cannot_invite_self':
  92. return <>{t('cannot_invite_self')}</>
  93. case 'invalid_email':
  94. return <>{t('invalid_email')}</>
  95. case 'too_many_requests':
  96. return <>{t('too_many_requests')}</>
  97. case 'invite_expired':
  98. return <>{t('invite_expired')}</>
  99. case 'invite_resend_limit_hit':
  100. return <>{t('invite_resend_limit_hit')}</>
  101. default:
  102. return <>{t('generic_something_went_wrong')}</>
  103. }
  104. }