error-message.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { useTranslation } from 'react-i18next'
  2. import { FetchError } from '../../../../infrastructure/fetch-json'
  3. import RedirectToLogin from './redirect-to-login'
  4. import {
  5. BlockedFilenameError,
  6. DuplicateFilenameError,
  7. InvalidFilenameError,
  8. } from '../../errors'
  9. import DangerMessage from './danger-message'
  10. // TODO: Update the error type when we properly type FileTreeActionableContext
  11. export default function ErrorMessage({
  12. error,
  13. }: {
  14. error: string | Record<string, any>
  15. }) {
  16. const { t } = useTranslation()
  17. const fileNameLimit = 150
  18. // the error is a string
  19. // TODO: translate? always? is this a key or a message?
  20. if (typeof error === 'string') {
  21. switch (error) {
  22. case 'name-exists':
  23. return <DangerMessage>{t('file_already_exists')}</DangerMessage>
  24. case 'too-many-files':
  25. return <DangerMessage>{t('project_has_too_many_files')}</DangerMessage>
  26. case 'remote-service-error':
  27. return <DangerMessage>{t('remote_service_error')}</DangerMessage>
  28. case 'folder_not_found':
  29. return (
  30. <DangerMessage>
  31. {t('the_target_folder_could_not_be_found')}
  32. </DangerMessage>
  33. )
  34. case 'invalid_filename':
  35. return (
  36. <DangerMessage>
  37. {t('invalid_filename', {
  38. nameLimit: fileNameLimit,
  39. })}
  40. </DangerMessage>
  41. )
  42. case 'duplicate_file_name':
  43. return (
  44. <DangerMessage>
  45. {t('file_or_folder_name_already_exists')}
  46. </DangerMessage>
  47. )
  48. case 'rate-limit-hit':
  49. return (
  50. <DangerMessage>
  51. {t('too_many_files_uploaded_throttled_short_period')}
  52. </DangerMessage>
  53. )
  54. case 'not-logged-in':
  55. return (
  56. <DangerMessage>
  57. <RedirectToLogin />
  58. </DangerMessage>
  59. )
  60. case 'linked-project-compile-error':
  61. return (
  62. <DangerMessage>
  63. {t('generic_linked_file_compile_error')}
  64. </DangerMessage>
  65. )
  66. default:
  67. // TODO: convert error.response.data to an error key and try again?
  68. // return error
  69. return (
  70. <DangerMessage>{t('generic_something_went_wrong')}</DangerMessage>
  71. )
  72. }
  73. }
  74. // the error is an object
  75. // TODO: error.name?
  76. switch (error.constructor) {
  77. case FetchError: {
  78. const message = error.data?.message
  79. if (message) {
  80. return <DangerMessage>{message.text || message}</DangerMessage>
  81. }
  82. // TODO: translations
  83. switch (error.response?.status) {
  84. case 400:
  85. return <DangerMessage>{t('invalid_request')}</DangerMessage>
  86. case 403:
  87. return <DangerMessage>{t('session_error')}</DangerMessage>
  88. case 429:
  89. return <DangerMessage>{t('too_many_attempts')}</DangerMessage>
  90. default:
  91. return (
  92. <DangerMessage>{t('something_went_wrong_server')}</DangerMessage>
  93. )
  94. }
  95. }
  96. // these are handled by the filename input component
  97. case DuplicateFilenameError:
  98. case InvalidFilenameError:
  99. case BlockedFilenameError:
  100. return null
  101. // a generic error message
  102. default:
  103. // return error.message
  104. return <DangerMessage>{t('generic_something_went_wrong')}</DangerMessage>
  105. }
  106. }