11// global FileReader
2- import React , { useContext , useState , useEffect } from 'react'
2+ import React , { useContext , useState , useEffect , useRef , useCallback , useMemo } from 'react'
33import { Button , Input , message , Modal , Space , Upload } from 'antd'
44import { InboxOutlined } from '@ant-design/icons'
55import { AppContext } from '../contexts/GlobalContext'
@@ -34,12 +34,52 @@ const enrichFileMetadata = (uploadFile) => {
3434 if ( folderPath ) {
3535 enhancedFile . folderPath = folderPath
3636 }
37+ if ( ! enhancedFile . originalName ) {
38+ const derivedOriginalName =
39+ uploadFile ?. originFileObj ?. name ||
40+ uploadFile ?. name ||
41+ enhancedFile . name
42+ if ( derivedOriginalName ) {
43+ enhancedFile . originalName = derivedOriginalName
44+ }
45+ }
3746 return enhancedFile
3847}
3948
4049export function Dragger ( ) {
4150 const context = useContext ( AppContext )
42- const { setFiles, files } = context
51+ const {
52+ setFiles,
53+ files,
54+ setFileList,
55+ setImageFileList,
56+ setLabelFileList,
57+ resetFileState
58+ } = context
59+ const objectUrlMapRef = useRef ( new Map ( ) )
60+
61+ const revokeObjectUrl = useCallback ( ( uid ) => {
62+ const url = objectUrlMapRef . current . get ( uid )
63+ if ( url ) {
64+ URL . revokeObjectURL ( url )
65+ objectUrlMapRef . current . delete ( uid )
66+ }
67+ } , [ ] )
68+
69+ const revokeAllObjectUrls = useCallback ( ( ) => {
70+ objectUrlMapRef . current . forEach ( ( url ) => URL . revokeObjectURL ( url ) )
71+ objectUrlMapRef . current . clear ( )
72+ } , [ ] )
73+
74+ const filesByUid = useMemo ( ( ) => {
75+ const map = new Map ( )
76+ if ( Array . isArray ( files ) ) {
77+ files . forEach ( ( file ) => {
78+ map . set ( file . uid , file )
79+ } )
80+ }
81+ return map
82+ } , [ files ] )
4383
4484 // const getBase64 = (file) =>
4585 // new Promise((resolve, reject) => {
@@ -64,9 +104,11 @@ export function Dragger () {
64104 } else if ( status === 'error' ) {
65105 console . log ( 'error' )
66106 message . error ( `${ info . file . name } file upload failed.` )
107+ revokeObjectUrl ( info . file . uid )
67108 } else if ( status === 'removed' ) {
68109 console . log ( info . fileList )
69110 setFiles ( info . fileList . map ( enrichFileMetadata ) )
111+ revokeObjectUrl ( info . file . uid )
70112 }
71113 }
72114
@@ -114,49 +156,86 @@ export function Dragger () {
114156 const fetchFile = async ( file ) => {
115157 try {
116158 if ( fileType === 'Label' ) {
117- context . setLabelFileList ( ( prevLabelList ) => [ ...prevLabelList , file ] )
159+ setLabelFileList ( ( prevLabelList ) => [ ...prevLabelList , file ] )
118160 } else if ( fileType === 'Image' ) {
119- context . setImageFileList ( ( prevImageList ) => [ ...prevImageList , file ] )
161+ setImageFileList ( ( prevImageList ) => [ ...prevImageList , file ] )
120162 }
121163 } catch ( error ) {
122164 console . error ( error )
123165 }
124166 }
125167
126- const handleSubmit = ( type ) => {
127- console . log ( 'submitting path' , previewFileFolderPath )
168+ const handleSubmit = ( ) => {
169+ if ( ! fileUID ) return
170+ const targetFile = filesByUid . get ( fileUID )
171+ if ( ! targetFile ) return
172+
173+ const updates = { }
128174 if ( previewFileFolderPath !== '' ) {
129- context . files . find (
130- ( targetFile ) => targetFile . uid === fileUID
131- ) . folderPath = previewFileFolderPath
175+ updates . folderPath = previewFileFolderPath
132176 setPreviewFileFolderPath ( '' )
133177 }
134178 if ( value !== '' ) {
135- context . files . find ( ( targetFile ) => targetFile . uid === fileUID ) . name =
136- value
137- context . fileList . find (
138- ( targetFile ) => targetFile . value === fileUID
139- ) . label = value
179+ updates . name = value
140180 setValue ( '' )
141181 }
142- fetchFile ( context . files . find ( ( targetFile ) => targetFile . uid === fileUID ) )
182+
183+ const updatedFile = Object . keys ( updates ) . length > 0
184+ ? { ...targetFile , ...updates }
185+ : targetFile
186+
187+ if ( Object . keys ( updates ) . length > 0 ) {
188+ setFiles ( ( prevFiles ) =>
189+ prevFiles . map ( ( file ) =>
190+ file . uid === fileUID ? { ...file , ...updates } : file
191+ )
192+ )
193+
194+ if ( updates . name ) {
195+ setFileList ( ( prevList ) =>
196+ prevList . map ( ( entry ) =>
197+ entry . value === fileUID ? { ...entry , label : updates . name } : entry
198+ )
199+ )
200+ }
201+ }
202+
203+ fetchFile ( updatedFile )
143204 setPreviewOpen ( false )
144205 }
145206
146207 const handleClearCache = async ( ) => {
147- context . setFileList ( [ ] )
148- context . setImageFileList ( [ ] )
149- context . setLabelFileList ( [ ] )
150- message . success ( 'File list cleared successfully.' )
208+ try {
209+ revokeAllObjectUrls ( )
210+ await resetFileState ( )
211+ message . success ( 'File cache cleared successfully.' )
212+ } catch ( error ) {
213+ console . error ( 'Failed to clear file cache:' , error )
214+ message . error ( 'Failed to clear file cache.' )
215+ }
151216 }
152217
153218 const handleRevert = ( ) => {
154- const oldName = context . files . find ( ( targetFile ) => targetFile . uid === fileUID )
155- . originFileObj . name
156- context . files . find ( ( targetFile ) => targetFile . uid === fileUID ) . name =
157- oldName
158- context . fileList . find ( ( targetFile ) => targetFile . value === fileUID ) . label =
159- oldName
219+ if ( ! fileUID ) {
220+ setPreviewOpen ( false )
221+ return
222+ }
223+ const targetFile = filesByUid . get ( fileUID )
224+ const oldName = targetFile ?. originFileObj ?. name || targetFile ?. originalName
225+ if ( ! oldName ) {
226+ setPreviewOpen ( false )
227+ return
228+ }
229+ setFiles ( ( prevFiles ) =>
230+ prevFiles . map ( ( file ) =>
231+ file . uid === fileUID ? { ...file , name : oldName } : file
232+ )
233+ )
234+ setFileList ( ( prevList ) =>
235+ prevList . map ( ( entry ) =>
236+ entry . value === fileUID ? { ...entry , label : oldName } : entry
237+ )
238+ )
160239 setPreviewOpen ( false )
161240 }
162241
@@ -214,13 +293,9 @@ export function Dragger () {
214293 setPreviewOpen ( true )
215294 setPreviewImage ( file . thumbUrl )
216295 setPreviewTitle ( file . name || file . url . substring ( file . url . lastIndexOf ( '/' ) + 1 ) )
217- if (
218- context . files . find ( targetFile => targetFile . uid === file . uid ) &&
219- context . files . find ( targetFile => targetFile . uid === file . uid ) . folderPath ) {
220- setPreviewFileFolderPath (
221- context . files . find ( targetFile => targetFile . uid === file . uid )
222- . folderPath
223- )
296+ const targetFile = filesByUid . get ( file . uid )
297+ if ( targetFile ?. folderPath ) {
298+ setPreviewFileFolderPath ( targetFile . folderPath )
224299 } else {
225300 const originPath =
226301 file ?. originFileObj ?. path ||
@@ -231,22 +306,12 @@ export function Dragger () {
231306 }
232307 }
233308
234- // Solved the "clear the cache" button for image loading is not reachable when the image preview files are loaded.
235309 const listItemStyle = {
236310 display : 'inline-block' ,
237311 width : '185px' ,
238312 height : 'auto' ,
239313 verticalAlign : 'top'
240314 }
241- useEffect ( ( ) => {
242- // Get all elements with the class name "ant-upload-list-item-container"
243- const uploadListItemContainers = document . querySelectorAll ( '.ant-upload-list-item-container' )
244-
245- // Apply styles to each element
246- uploadListItemContainers . forEach ( ( element ) => {
247- Object . assign ( element . style , listItemStyle )
248- } )
249- } )
250315
251316 // when click or drag file to this area to upload, below function will be deployed.
252317 const handleBeforeUpload = ( file ) => {
@@ -262,10 +327,17 @@ export function Dragger () {
262327 } )
263328 } else {
264329 file . thumbUrl = URL . createObjectURL ( file )
330+ objectUrlMapRef . current . set ( file . uid , file . thumbUrl )
265331 }
266332 return true // Allow the upload
267333 }
268334
335+ useEffect ( ( ) => {
336+ return ( ) => {
337+ revokeAllObjectUrls ( )
338+ }
339+ } , [ revokeAllObjectUrls ] )
340+
269341 return (
270342 < >
271343 < Upload . Dragger
0 commit comments