@@ -92,6 +92,7 @@ export default function Uploader(props: Props) {
9292 ) . current
9393
9494 const uploadRef = useRef < Subscription | null > ( null )
95+ const uploadingDocumentId = useRef < string | null > ( null )
9596 const [ state , dispatch ] = useReducer (
9697 ( prev : State , action : UploaderStateAction ) => {
9798 switch ( action . action ) {
@@ -121,11 +122,13 @@ export default function Uploader(props: Props) {
121122 // Clear upload observable on completion
122123 uploadRef . current ?. unsubscribe ( )
123124 uploadRef . current = null
125+ uploadingDocumentId . current = null
124126 return INITIAL_STATE
125127 case 'error' :
126128 // Clear upload observable on error
127129 uploadRef . current ?. unsubscribe ( )
128130 uploadRef . current = null
131+ uploadingDocumentId . current = null
129132 return Object . assign ( { } , INITIAL_STATE , { error : action . error } )
130133 default :
131134 return prev
@@ -139,13 +142,38 @@ export default function Uploader(props: Props) {
139142 )
140143
141144 // Make sure we close out the upload observer on dismount
145+ // and cleanup orphaned documents if upload was in progress
142146 useEffect ( ( ) => {
143- return ( ) => {
147+ const cleanup = ( ) => {
148+ // Cancel subscription
144149 if ( uploadRef . current && ! uploadRef . current . closed ) {
145150 uploadRef . current . unsubscribe ( )
146151 }
152+
153+ // Delete orphaned document if upload was in progress and document is different from the saved asset
154+ if ( uploadingDocumentId . current && props . asset ?. _id !== uploadingDocumentId . current ) {
155+ const docId = uploadingDocumentId . current
156+ uploadingDocumentId . current = null
157+
158+ props . client . delete ( docId ) . catch ( ( err ) => {
159+ console . warn ( 'Failed to cleanup orphaned upload document:' , err )
160+ } )
161+ }
162+ }
163+
164+ const handleBeforeUnload = ( ) => {
165+ cleanup ( )
147166 }
148- } , [ ] )
167+
168+ window . addEventListener ( 'beforeunload' , handleBeforeUnload )
169+ window . addEventListener ( 'pagehide' , handleBeforeUnload )
170+
171+ return ( ) => {
172+ window . removeEventListener ( 'beforeunload' , handleBeforeUnload )
173+ window . removeEventListener ( 'pagehide' , handleBeforeUnload )
174+ cleanup ( )
175+ }
176+ } , [ props . client , props . asset ?. _id ] )
149177
150178 /* -------------------------------------------------------------------------- */
151179 /* Uploading */
@@ -183,8 +211,9 @@ export default function Uploader(props: Props) {
183211 takeUntil (
184212 cancelUploadButton . observable . pipe (
185213 tap ( ( ) => {
186- if ( state . uploadStatus ?. uuid ) {
187- props . client . delete ( state . uploadStatus . uuid )
214+ if ( uploadingDocumentId . current ) {
215+ props . client . delete ( uploadingDocumentId . current )
216+ uploadingDocumentId . current = null
188217 }
189218 } )
190219 )
@@ -196,6 +225,10 @@ export default function Uploader(props: Props) {
196225 next : ( event ) => {
197226 switch ( event . type ) {
198227 case 'uuid' :
228+ // Track the document ID for cleanup on unmount
229+ uploadingDocumentId . current = event . uuid
230+ dispatch ( { action : 'progressInfo' , ...event } )
231+ break
199232 case 'file' :
200233 case 'url' :
201234 dispatch ( { action : 'progressInfo' , ...event } )
@@ -205,6 +238,7 @@ export default function Uploader(props: Props) {
205238 break
206239 case 'success' :
207240 dispatch ( { action : 'progress' , percent : 100 } )
241+ uploadingDocumentId . current = null
208242 props . onChange (
209243 PatchEvent . from ( [
210244 setIfMissing ( { asset : { } } ) ,
0 commit comments