file-view.jsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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 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 full-size">
  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. const { t } = useTranslation()
  62. return (
  63. <div className="loading-panel loading-panel-file-view">
  64. <span>
  65. <Icon type="refresh" spin />
  66. &nbsp;&nbsp;{t('loading')}…
  67. </span>
  68. </div>
  69. )
  70. }
  71. FileView.propTypes = {
  72. file: PropTypes.shape({
  73. id: PropTypes.string,
  74. name: PropTypes.string,
  75. hash: PropTypes.string,
  76. }).isRequired,
  77. }