file-tree-create-name-input.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { useRef, useEffect } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { useFileTreeCreateName } from '../../contexts/file-tree-create-name'
  4. import {
  5. BlockedFilenameError,
  6. DuplicateFilenameError,
  7. InvalidFilenameError,
  8. } from '../../errors'
  9. import OLFormGroup from '@/shared/components/ol/ol-form-group'
  10. import OLFormLabel from '@/shared/components/ol/ol-form-label'
  11. import OLFormControl from '@/shared/components/ol/ol-form-control'
  12. import OLNotification from '@/shared/components/ol/ol-notification'
  13. /**
  14. * A form component that renders a text input with label,
  15. * plus a validation warning and/or an error message when needed
  16. */
  17. export default function FileTreeCreateNameInput({
  18. label,
  19. focusName = false,
  20. classes = {},
  21. placeholder,
  22. error,
  23. inFlight,
  24. }: {
  25. label?: string
  26. focusName?: boolean
  27. classes?: {
  28. formGroup?: string
  29. }
  30. placeholder?: string
  31. error?: string | Record<string, any>
  32. inFlight: boolean
  33. }) {
  34. const { t } = useTranslation()
  35. // the value is stored in a context provider, so it's available elsewhere in the form
  36. const { name, setName, touchedName, validName } = useFileTreeCreateName()
  37. // focus the first part of the filename if needed
  38. const inputRef = useRef<HTMLInputElement>(null)
  39. useEffect(() => {
  40. if (inputRef.current && focusName) {
  41. window.requestAnimationFrame(() => {
  42. if (inputRef.current) {
  43. inputRef.current.focus()
  44. inputRef.current.setSelectionRange(
  45. 0,
  46. inputRef.current.value.lastIndexOf('.')
  47. )
  48. }
  49. })
  50. }
  51. }, [focusName])
  52. return (
  53. <OLFormGroup controlId="new-doc-name" className={classes.formGroup}>
  54. <OLFormLabel>{label || t('file_name')}</OLFormLabel>
  55. <OLFormControl
  56. type="text"
  57. placeholder={placeholder || t('file_name')}
  58. required
  59. value={name}
  60. onChange={event => setName(event.target.value)}
  61. ref={inputRef}
  62. disabled={inFlight}
  63. />
  64. {touchedName && !validName && (
  65. <OLNotification
  66. type="error"
  67. className="row-spaced-small"
  68. content={t('files_cannot_include_invalid_characters')}
  69. />
  70. )}
  71. {error && <ErrorMessage error={error} />}
  72. </OLFormGroup>
  73. )
  74. }
  75. function ErrorMessage({ error }: { error: string | Record<string, any> }) {
  76. const { t } = useTranslation()
  77. // if (typeof error === 'string') {
  78. // return error
  79. // }
  80. switch (error.constructor) {
  81. case DuplicateFilenameError:
  82. return (
  83. <OLNotification
  84. type="error"
  85. className="row-spaced-small"
  86. content={t('file_already_exists')}
  87. />
  88. )
  89. case InvalidFilenameError:
  90. return (
  91. <OLNotification
  92. type="error"
  93. className="row-spaced-small"
  94. content={t('files_cannot_include_invalid_characters')}
  95. />
  96. )
  97. case BlockedFilenameError:
  98. return (
  99. <OLNotification
  100. type="error"
  101. className="row-spaced-small"
  102. content={t('blocked_filename')}
  103. />
  104. )
  105. default:
  106. // return <Trans i18nKey="generic_something_went_wrong" />
  107. return null // other errors are displayed elsewhere
  108. }
  109. }