use-project-uploader.tsx 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { useEffect, useState } from 'react'
  2. import Uppy, { ErrorResponse } from '@uppy/core'
  3. import XHRUpload from '@uppy/xhr-upload'
  4. import getMeta from '@/utils/meta'
  5. type UploaderConfig = {
  6. endpoint: string
  7. allowedFileTypes: string[]
  8. onSuccess: (projectId: string) => void
  9. onError?: (response: ErrorResponse | undefined) => void
  10. onFileAdded?: () => void
  11. onFileRemoved?: () => void
  12. }
  13. type ImportResponse = {
  14. project_id?: string
  15. }
  16. export function useProjectUploader({
  17. endpoint,
  18. allowedFileTypes,
  19. onSuccess,
  20. onError,
  21. onFileAdded,
  22. onFileRemoved,
  23. }: UploaderConfig) {
  24. const { maxUploadSize, projectUploadTimeout } = getMeta('ol-ExposedSettings')
  25. const [ableToUpload, setAbleToUpload] = useState(false)
  26. const [uppy] = useState(() => {
  27. return new Uppy({
  28. allowMultipleUploadBatches: false,
  29. restrictions: {
  30. maxNumberOfFiles: 1,
  31. maxFileSize: maxUploadSize,
  32. allowedFileTypes,
  33. },
  34. })
  35. .use(XHRUpload, {
  36. endpoint,
  37. headers: {
  38. 'X-CSRF-TOKEN': getMeta('ol-csrfToken'),
  39. },
  40. limit: 1,
  41. fieldName: 'qqfile',
  42. timeout: projectUploadTimeout,
  43. })
  44. .on('file-added', () => {
  45. // this function can be invoked multiple times depending on maxNumberOfFiles
  46. // in this case, since have maxNumberOfFiles = 1, this function will be invoked
  47. // once if the correct file were added
  48. // if user dragged more files than the maxNumberOfFiles allow,
  49. // the rest of the files will appear on the 'restriction-failed' event callback
  50. setAbleToUpload(true)
  51. })
  52. .on('upload-error', (_file, _err, response) => {
  53. // refresh state so they can try uploading a new file
  54. setAbleToUpload(false)
  55. onError?.(response)
  56. })
  57. .on('upload-success', (_file, response) => {
  58. const { project_id: projectId }: ImportResponse = response.body
  59. if (projectId) {
  60. onSuccess(projectId)
  61. }
  62. })
  63. .on('restriction-failed', () => {
  64. // 'restriction-failed event will be invoked when one of the "restrictions" above
  65. // is not complied:
  66. // 1. maxNumberOfFiles: if the uploaded files is more than 1, the rest of the files will appear here
  67. // for example, user drop 5 files to the uploader, this function will be invoked 4 times and the `file-added` event
  68. // will be invoked once
  69. // 2. maxFileSize: if the uploaded file has size > maxFileSize, it will appear here
  70. // 3. allowedFileTypes: if the file type is not allowed by allowedFileTypes, it will also appear here
  71. // reset state so they can try uploading a different file, etc
  72. setAbleToUpload(false)
  73. })
  74. .on('file-added', () => {
  75. onFileAdded?.()
  76. })
  77. .on('file-removed', () => {
  78. onFileRemoved?.()
  79. })
  80. })
  81. useEffect(() => {
  82. if (ableToUpload) {
  83. uppy.upload()
  84. }
  85. }, [ableToUpload, uppy])
  86. return uppy
  87. }