@@ -33,6 +33,7 @@ import { FieldLabel } from '../../fields/FieldLabel/index.js'
3333import { useAuth } from '../../providers/Auth/index.js'
3434import { useLocale } from '../../providers/Locale/index.js'
3535import { useTranslation } from '../../providers/Translation/index.js'
36+ import { normalizeRelationshipValue } from '../../utilities/normalizeRelationshipValue.js'
3637import { fieldBaseClass } from '../shared/index.js'
3738import { UploadComponentHasMany } from './HasMany/index.js'
3839import { UploadComponentHasOne } from './HasOne/index.js'
@@ -249,7 +250,14 @@ export function UploadInput(props: UploadInputProps) {
249250 if ( ! grouped [ relationTo ] ) {
250251 grouped [ relationTo ] = [ ]
251252 }
252- grouped [ relationTo ] . push ( value )
253+ // Ensure we extract the actual ID value, not an object
254+ let idValue : number | string = value
255+
256+ if ( value && typeof value === 'object' && 'value' in ( value as any ) ) {
257+ idValue = ( value as any ) . value
258+ }
259+
260+ grouped [ relationTo ] . push ( idValue )
253261 } )
254262
255263 // 2. Fetch per collection
@@ -315,6 +323,11 @@ export function UploadInput(props: UploadInputProps) {
315323 [ serverURL , api , code , i18n . language , t ] ,
316324 )
317325
326+ const normalizeValue = useCallback (
327+ ( value : any ) : any => normalizeRelationshipValue ( value , relationTo ) ,
328+ [ relationTo ] ,
329+ )
330+
318331 const onUploadSuccess : BulkUploadContext [ 'onSuccess' ] = useCallback (
319332 ( uploadedForms ) => {
320333 const isPoly = Array . isArray ( relationTo )
@@ -323,7 +336,9 @@ export function UploadInput(props: UploadInputProps) {
323336 const newValues = uploadedForms . map ( ( form ) =>
324337 isPoly ? { relationTo : form . collectionSlug , value : form . doc . id } : form . doc . id ,
325338 )
326- const mergedValue = [ ...( Array . isArray ( value ) ? value : [ ] ) , ...newValues ]
339+ // Normalize existing values before merging
340+ const normalizedExisting = Array . isArray ( value ) ? value . map ( normalizeValue ) : [ ]
341+ const mergedValue = [ ...normalizedExisting , ...newValues ]
327342 onChange ( mergedValue )
328343 setPopulatedDocs ( ( currentDocs ) => [
329344 ...( currentDocs || [ ] ) ,
@@ -346,7 +361,7 @@ export function UploadInput(props: UploadInputProps) {
346361 ] )
347362 }
348363 } ,
349- [ value , onChange , hasMany , relationTo ] ,
364+ [ value , onChange , hasMany , relationTo , normalizeValue ] ,
350365 )
351366
352367 const onLocalFileSelection = React . useCallback (
@@ -405,6 +420,7 @@ export function UploadInput(props: UploadInputProps) {
405420 relationTo : activeRelationTo ,
406421 value : id ,
407422 } ) )
423+
408424 const loadedDocs = await populateDocs ( itemsToLoad )
409425 if ( loadedDocs ) {
410426 setPopulatedDocs ( ( currentDocs ) => [ ...( currentDocs || [ ] ) , ...loadedDocs ] )
@@ -413,10 +429,12 @@ export function UploadInput(props: UploadInputProps) {
413429 const newValues = selectedDocIDs . map ( ( id ) =>
414430 isPoly ? { relationTo : activeRelationTo , value : id } : id ,
415431 )
416- onChange ( [ ...( Array . isArray ( value ) ? value : [ ] ) , ...newValues ] )
432+ // Normalize existing values before merging
433+ const normalizedExisting = Array . isArray ( value ) ? value . map ( normalizeValue ) : [ ]
434+ onChange ( [ ...normalizedExisting , ...newValues ] )
417435 closeListDrawer ( )
418436 } ,
419- [ activeRelationTo , closeListDrawer , onChange , populateDocs , value , relationTo ] ,
437+ [ activeRelationTo , closeListDrawer , onChange , populateDocs , value , relationTo , normalizeValue ] ,
420438 )
421439
422440 const onDocCreate = React . useCallback (
@@ -456,18 +474,19 @@ export function UploadInput(props: UploadInputProps) {
456474 return currentDocs
457475 } )
458476
459- const newValue = isPoly ? { relationTo : collectionSlug , value : doc . id } : doc . id
460-
461477 if ( hasMany ) {
462- const valueToUse = [ ...( Array . isArray ( value ) ? value : [ ] ) , newValue ]
478+ const newValue = isPoly ? { relationTo : collectionSlug , value : doc . id } : doc . id
479+ // Normalize existing values before merging
480+ const normalizedExisting = Array . isArray ( value ) ? value . map ( normalizeValue ) : [ ]
481+ const valueToUse = [ ...normalizedExisting , newValue ]
463482 onChange ( valueToUse )
464483 } else {
465484 const valueToUse = isPoly ? { relationTo : collectionSlug , value : doc . id } : doc . id
466485 onChange ( valueToUse )
467486 }
468487 closeListDrawer ( )
469488 } ,
470- [ closeListDrawer , hasMany , populateDocs , onChange , value , relationTo ] ,
489+ [ closeListDrawer , hasMany , populateDocs , onChange , value , relationTo , normalizeValue ] ,
471490 )
472491
473492 const reloadDoc = React . useCallback < ReloadDoc > (
@@ -534,7 +553,7 @@ export function UploadInput(props: UploadInputProps) {
534553 useEffect ( ( ) => {
535554 async function loadInitialDocs ( ) {
536555 if ( value ) {
537- let itemsToLoad : ValueWithRelation [ ]
556+ let itemsToLoad : ValueWithRelation [ ] = [ ]
538557 if (
539558 Array . isArray ( relationTo ) &&
540559 ( ( typeof value === 'object' && 'relationTo' in value ) ||
@@ -545,29 +564,55 @@ export function UploadInput(props: UploadInputProps) {
545564 ) {
546565 // For poly uploads, value should already be in the format { relationTo, value }
547566 const values = Array . isArray ( value ) ? value : [ value ]
548- itemsToLoad = values . filter (
549- ( v ) : v is ValueWithRelation => typeof v === 'object' && 'relationTo' in v ,
550- )
567+ itemsToLoad = values
568+ . filter ( ( v ) : v is ValueWithRelation => typeof v === 'object' && 'relationTo' in v )
569+ . map ( ( v ) => {
570+ // Ensure the value property is a simple ID, not nested
571+ let idValue : any = v . value
572+ while (
573+ idValue &&
574+ typeof idValue === 'object' &&
575+ idValue !== null &&
576+ 'value' in idValue
577+ ) {
578+ idValue = idValue . value
579+ }
580+ return {
581+ relationTo : v . relationTo ,
582+ value : idValue as number | string ,
583+ }
584+ } )
551585 } else {
552586 // This check is here to satisfy TypeScript that relationTo is a string
553587 if ( ! Array . isArray ( relationTo ) ) {
554588 // For single collection uploads, we need to wrap the IDs
555589 const ids = Array . isArray ( value ) ? value : [ value ]
556590 itemsToLoad = ids . map ( ( id ) : ValueWithRelation => {
557- const idValue = typeof id === 'object' && 'value' in id ? id . value : id
591+ // Extract the actual ID, handling nested objects
592+ let idValue : any = id
593+ while (
594+ idValue &&
595+ typeof idValue === 'object' &&
596+ idValue !== null &&
597+ 'value' in idValue
598+ ) {
599+ idValue = idValue . value
600+ }
558601 return {
559602 relationTo,
560- value : idValue ,
603+ value : idValue as number | string ,
561604 }
562605 } )
563606 }
564607 }
565608
566- const loadedDocs = await populateDocs ( itemsToLoad )
609+ if ( itemsToLoad . length > 0 ) {
610+ const loadedDocs = await populateDocs ( itemsToLoad )
567611
568- if ( loadedDocs ) {
569- setPopulatedDocs ( loadedDocs )
570- loadedValueRef . current = value
612+ if ( loadedDocs ) {
613+ setPopulatedDocs ( loadedDocs )
614+ loadedValueRef . current = value
615+ }
571616 }
572617 } else {
573618 // Clear populated docs when value is cleared
0 commit comments