invite-root.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import useWaitForI18n from '@/shared/hooks/use-wait-for-i18n'
  2. import getMeta from '@/utils/meta'
  3. import Invite from '@/features/share-project/invite'
  4. import useAsync from '@/shared/hooks/use-async'
  5. import { postJSON } from '@/infrastructure/fetch-json'
  6. import { useLocation } from '@/shared/hooks/use-location'
  7. import { debugConsole } from '@/utils/debugging'
  8. import InviteNotValid from './invite-not-valid'
  9. import { useEffect, useState } from 'react'
  10. type ValidateResponse = {
  11. valid: boolean
  12. projectName?: string
  13. redirect?: boolean
  14. }
  15. export default function InviteRoot() {
  16. const user = getMeta('ol-user')
  17. const projectName = getMeta('ol-projectName')
  18. const projectId = getMeta('ol-project_id')
  19. const token = getMeta('ol-inviteToken')
  20. const location = useLocation()
  21. const hashToken = document.location.hash.replace('#', '')
  22. const { isLoading, runAsync } = useAsync()
  23. const { isReady } = useWaitForI18n()
  24. const [validateResponse, setValidateResponse] = useState<ValidateResponse>({
  25. valid: false,
  26. })
  27. // If a sharing link (ie. token is in hash), validate the user can use this link
  28. useEffect(() => {
  29. const validate = async () => {
  30. if (hashToken) {
  31. try {
  32. const result = await runAsync(
  33. postJSON(`/project/${projectId}/share/validate`, {
  34. body: { token: hashToken },
  35. })
  36. )
  37. setValidateResponse(result)
  38. if (result.redirect) {
  39. location.replace(`/project/${projectId}`)
  40. }
  41. } catch (err) {
  42. debugConsole.error('Error validating sharing link', err)
  43. setValidateResponse({ valid: false })
  44. }
  45. } else {
  46. setValidateResponse({ valid: false })
  47. }
  48. }
  49. // Always treat URL tokens as valid, they are validated on the backend before
  50. // rendering this page.
  51. if (token) {
  52. setValidateResponse({ valid: true })
  53. return
  54. }
  55. validate()
  56. }, [token, hashToken, projectId, runAsync, location])
  57. const handleSubmit = () => {
  58. if (token) {
  59. runAsync(postJSON(`/project/${projectId}/invite/token/${token}/accept`))
  60. .then(() => location.assign(`/project/${projectId}`))
  61. .catch(debugConsole.error)
  62. } else if (hashToken) {
  63. runAsync(
  64. postJSON(`/project/${projectId}/share`, { body: { token: hashToken } })
  65. )
  66. .then(() => location.assign(`/project/${projectId}`))
  67. .catch(debugConsole.error)
  68. }
  69. }
  70. if (!isReady || isLoading || validateResponse.redirect) {
  71. return null
  72. }
  73. if ((!token && !hashToken) || !validateResponse.valid) {
  74. return <InviteNotValid email={user?.email} />
  75. }
  76. return (
  77. <Invite
  78. projectName={validateResponse.projectName || projectName}
  79. email={user.email}
  80. submitHandler={handleSubmit}
  81. isLoading={isLoading}
  82. />
  83. )
  84. }