file-view.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { useState, useCallback } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import FileViewHeader from './file-view-header'
  4. import FileViewImage from './file-view-image'
  5. import FileViewPdf from './file-view-pdf'
  6. import FileViewText from './file-view-text'
  7. import LoadingSpinner from '@/shared/components/loading-spinner'
  8. import getMeta from '@/utils/meta'
  9. import { BinaryFile } from '../types/binary-file'
  10. const imageExtensions = ['png', 'jpg', 'jpeg', 'gif']
  11. export default function FileView({ file }: { file: BinaryFile }) {
  12. const [contentLoading, setContentLoading] = useState(true)
  13. const [hasError, setHasError] = useState(false)
  14. const { t } = useTranslation()
  15. const { textExtensions, editableFilenames } = getMeta('ol-ExposedSettings')
  16. const extension = file.name.split('.')?.pop()?.toLowerCase()
  17. const isEditableTextFile =
  18. (extension && textExtensions.includes(extension)) ||
  19. editableFilenames.includes(file.name.toLowerCase())
  20. const isImageFile = !!extension && imageExtensions.includes(extension)
  21. const isPdfFile = extension === 'pdf'
  22. const isUnpreviewableFile = !isEditableTextFile && !isImageFile && !isPdfFile
  23. const handleLoad = useCallback(() => {
  24. setContentLoading(false)
  25. }, [])
  26. const handleError = useCallback(() => {
  27. if (!hasError) {
  28. setContentLoading(false)
  29. setHasError(true)
  30. }
  31. }, [hasError])
  32. const content = (
  33. <>
  34. <FileViewHeader file={file} />
  35. {isImageFile && (
  36. <FileViewImage file={file} onLoad={handleLoad} onError={handleError} />
  37. )}
  38. {isEditableTextFile && (
  39. <FileViewText file={file} onLoad={handleLoad} onError={handleError} />
  40. )}
  41. {isPdfFile && (
  42. <FileViewPdf
  43. fileId={file.id}
  44. onLoad={handleLoad}
  45. onError={handleError}
  46. />
  47. )}
  48. </>
  49. )
  50. return (
  51. <div className="file-view">
  52. {!hasError && content}
  53. {!isUnpreviewableFile && contentLoading && <FileViewLoadingIndicator />}
  54. {(isUnpreviewableFile || hasError) && (
  55. <p className="no-preview">{t('no_preview_available')}</p>
  56. )}
  57. </div>
  58. )
  59. }
  60. function FileViewLoadingIndicator() {
  61. return (
  62. <div
  63. className="loading-panel loading-panel-file-view"
  64. data-testid="loading-panel-file-view"
  65. >
  66. <LoadingSpinner />
  67. </div>
  68. )
  69. }