loading.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import { FC, useEffect, useState } from 'react'
  2. import LoadingBranded from '@/shared/components/loading-branded'
  3. import useWaitForI18n from '@/shared/hooks/use-wait-for-i18n'
  4. import getMeta from '@/utils/meta'
  5. import { useConnectionContext } from '../context/connection-context'
  6. import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
  7. import { LoadingError, LoadingErrorProps } from './loading-error'
  8. import useThemedPage from '@/shared/hooks/use-themed-page'
  9. type Part = 'initial' | 'render' | 'connection' | 'translations' | 'project'
  10. const initialParts = new Set<Part>(['initial'])
  11. const totalParts = new Set<Part>([
  12. 'initial',
  13. 'render',
  14. 'connection',
  15. 'translations',
  16. 'project',
  17. ])
  18. export const Loading: FC<{
  19. setLoaded: (value: boolean) => void
  20. }> = ({ setLoaded }) => {
  21. const [loadedParts, setLoadedParts] = useState(initialParts)
  22. useThemedPage()
  23. const progress = (loadedParts.size / totalParts.size) * 100
  24. useEffect(() => {
  25. setLoaded(progress === 100)
  26. }, [progress, setLoaded])
  27. const { connectionState, isConnected } = useConnectionContext()
  28. const i18n = useWaitForI18n()
  29. const { projectJoined } = useIdeReactContext()
  30. useEffect(() => {
  31. setLoadedParts(value => new Set(value).add('render'))
  32. }, [])
  33. useEffect(() => {
  34. if (isConnected) {
  35. setLoadedParts(value => new Set(value).add('connection'))
  36. }
  37. }, [isConnected])
  38. useEffect(() => {
  39. if (i18n.isReady) {
  40. setLoadedParts(value => new Set(value).add('translations'))
  41. }
  42. }, [i18n.isReady])
  43. useEffect(() => {
  44. if (projectJoined) {
  45. setLoadedParts(value => new Set(value).add('project'))
  46. }
  47. }, [projectJoined])
  48. // Use loading text from the server, because i18n will not be ready initially
  49. const label = getMeta('ol-loadingText')
  50. const errorCode = connectionState.error ?? (i18n.error ? 'i18n-error' : '')
  51. return <LoadingUI progress={progress} label={label} errorCode={errorCode} />
  52. }
  53. type LoadingUiProps = {
  54. progress: number
  55. label: string
  56. errorCode: LoadingErrorProps['errorCode']
  57. }
  58. export const LoadingUI: FC<LoadingUiProps> = ({
  59. progress,
  60. label,
  61. errorCode,
  62. }) => {
  63. return (
  64. <div className="loading-screen">
  65. <LoadingBranded
  66. loadProgress={progress}
  67. label={label}
  68. hasError={Boolean(errorCode)}
  69. />
  70. {Boolean(errorCode) && <LoadingError errorCode={errorCode} />}
  71. </div>
  72. )
  73. }