loading.tsx 2.3 KB

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