file-view.jsx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { useState, useCallback } from 'react'
  2. import PropTypes from 'prop-types'
  3. import { useTranslation } from 'react-i18next'
  4. import FileViewHeader from './file-view-header'
  5. import FileViewImage from './file-view-image'
  6. import FileViewPdf from './file-view-pdf'
  7. import FileViewText from './file-view-text'
  8. import Icon from '../../../shared/components/icon'
  9. import getMeta from '@/utils/meta'
  10. const imageExtensions = ['png', 'jpg', 'jpeg', 'gif']
  11. export default function FileView({ file }) {
  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. textExtensions.includes(extension) ||
  19. editableFilenames.includes(file.name.toLowerCase())
  20. const isImageFile = 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
  37. fileName={file.name}
  38. fileId={file.id}
  39. onLoad={handleLoad}
  40. onError={handleError}
  41. />
  42. )}
  43. {isEditableTextFile && (
  44. <FileViewText file={file} onLoad={handleLoad} onError={handleError} />
  45. )}
  46. {isPdfFile && (
  47. <FileViewPdf
  48. fileId={file.id}
  49. onLoad={handleLoad}
  50. onError={handleError}
  51. />
  52. )}
  53. </>
  54. )
  55. return (
  56. <div className="file-view full-size">
  57. {!hasError && content}
  58. {!isUnpreviewableFile && contentLoading && <FileViewLoadingIndicator />}
  59. {(isUnpreviewableFile || hasError) && (
  60. <p className="no-preview">{t('no_preview_available')}</p>
  61. )}
  62. </div>
  63. )
  64. }
  65. function FileViewLoadingIndicator() {
  66. const { t } = useTranslation()
  67. return (
  68. <div className="loading-panel loading-panel-file-view">
  69. <span>
  70. <Icon type="refresh" spin />
  71. &nbsp;&nbsp;{t('loading')}…
  72. </span>
  73. </div>
  74. )
  75. }
  76. FileView.propTypes = {
  77. file: PropTypes.shape({
  78. id: PropTypes.string,
  79. name: PropTypes.string,
  80. }).isRequired,
  81. }