11'use client'
22
3+ import type { FieldType } from '@payloadcms/ui'
34import type { RelationshipFieldClientProps } from 'payload'
45
56import {
7+ FieldContext ,
8+ FieldPathContext ,
69 Pill ,
710 RelationshipField ,
811 useDocumentInfo ,
@@ -13,6 +16,8 @@ import {
1316} from '@payloadcms/ui'
1417import React from 'react'
1518
19+ import type { TenantValue } from '../../types.js'
20+
1621import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
1722import {
1823 AssignTenantFieldModal ,
@@ -29,77 +34,84 @@ type Props = {
2934
3035export const TenantField = ( { debug, unique, ...fieldArgs } : Props ) => {
3136 const { entityType, options, selectedTenantID, setEntityType, setTenant } = useTenantSelection ( )
32- const { setValue , showError , value } = useField < ( number | string ) [ ] | ( number | string ) > ( )
33- const modified = useFormModified ( )
34- const { isValid : isFormValid , setModified } = useForm ( )
37+ const tenantField = useField < TenantValue > ( )
38+ const { setValue , showError , value } = tenantField
39+ const { isValid : isFormValid } = useForm ( )
3540 const { id : docID , collectionSlug } = useDocumentInfo ( )
3641 const { isModalOpen, openModal } = useModal ( )
3742 const isEditManyModalOpen = collectionSlug
3843 ? isModalOpen ( `edit-${ collectionSlug } ` ) || isModalOpen ( `edit-${ collectionSlug } -bulk-uploads` )
3944 : false
40- const isConfirmingRef = React . useRef < boolean > ( false )
41- const prevModified = React . useRef ( modified )
42- const prevValue = React . useRef < typeof value > ( value )
45+ const [ modalValue , setModalValue ] = React . useState < TenantValue | undefined > ( value )
46+ const localTenantField = React . useMemo < FieldType < TenantValue > > (
47+ ( ) => ( {
48+ ...tenantField ,
49+ initialValue : modalValue ,
50+ setValue : ( nextValue ) => {
51+ setModalValue ( nextValue as TenantValue | undefined )
52+ } ,
53+ value : modalValue as TenantValue ,
54+ } ) ,
55+ [ modalValue , tenantField ] ,
56+ )
4357 const showField =
4458 ( options . length > 1 && ! fieldArgs . field . admin ?. hidden && ! fieldArgs . field . hidden ) || debug
4559
46- const onConfirm = React . useCallback ( ( ) => {
47- isConfirmingRef . current = true
48- } , [ ] )
49-
50- const afterModalOpen = React . useCallback ( ( ) => {
51- prevModified . current = modified
52- prevValue . current = value
53- } , [ modified , value ] )
54-
55- const afterModalClose = React . useCallback ( ( ) => {
56- let didChange = true
57- if ( isConfirmingRef . current ) {
58- // did the values actually change?
59- if ( fieldArgs . field . hasMany ) {
60- const prev = ( prevValue . current || [ ] ) as ( number | string ) [ ]
61- const newValue = ( value || [ ] ) as ( number | string ) [ ]
62- if ( prev . length !== newValue . length ) {
63- didChange = true
64- } else {
65- const allMatch = newValue . every ( ( val ) => prev . includes ( val ) )
66- if ( allMatch ) {
67- didChange = false
68- }
69- }
70- } else if ( value === prevValue . current ) {
71- didChange = false
60+ function getTenantIDToSelect ( {
61+ selectedTenantID,
62+ value,
63+ } : {
64+ selectedTenantID : number | string | undefined
65+ value : TenantValue | undefined
66+ } ) : number | string | undefined {
67+ if ( Array . isArray ( value ) ) {
68+ if ( ! value . length ) {
69+ return undefined
7270 }
7371
74- if ( didChange ) {
75- prevModified . current = true
76- prevValue . current = value
72+ if ( ! selectedTenantID || ! value . includes ( selectedTenantID ) ) {
73+ return value [ 0 ]
7774 }
75+
76+ return undefined
7877 }
7978
80- setValue ( prevValue . current , true )
81- setModified ( prevModified . current )
79+ if ( value && selectedTenantID !== value ) {
80+ return value
81+ }
82+
83+ return undefined
84+ }
85+
86+ const syncTenantSelectionFromValue = React . useCallback (
87+ ( tenantValue : TenantValue | undefined ) => {
88+ const tenantID = getTenantIDToSelect ( { selectedTenantID, value : tenantValue } )
89+
90+ if ( tenantID ) {
91+ setTenant ( { id : tenantID , refresh : false } )
92+ }
93+ } ,
94+ [ selectedTenantID , setTenant ] ,
95+ )
96+
97+ const onConfirm = React . useCallback ( ( ) => {
98+ if ( hasTenantValueChanged ( { hasMany : fieldArgs . field . hasMany , modalValue, value } ) ) {
99+ setValue ( modalValue )
100+ syncTenantSelectionFromValue ( modalValue )
101+ }
102+ } , [ fieldArgs . field . hasMany , modalValue , setValue , syncTenantSelectionFromValue , value ] )
82103
83- isConfirmingRef . current = false
84- } , [ setValue , setModified , value , fieldArgs . field . hasMany ] )
104+ const afterModalOpen = React . useCallback ( ( ) => {
105+ setModalValue ( value )
106+ } , [ value ] )
85107
86108 React . useEffect ( ( ) => {
87109 if ( ! entityType ) {
88110 setEntityType ( unique ? 'global' : 'document' )
89111 } else {
90112 // unique documents are controlled from the global TenantSelector
91- if ( ! unique && value ) {
92- if ( Array . isArray ( value ) ) {
93- if ( value . length ) {
94- if ( ! selectedTenantID ) {
95- setTenant ( { id : value [ 0 ] , refresh : false } )
96- } else if ( ! value . includes ( selectedTenantID ) ) {
97- setTenant ( { id : value [ 0 ] , refresh : false } )
98- }
99- }
100- } else if ( selectedTenantID !== value ) {
101- setTenant ( { id : value , refresh : false } )
102- }
113+ if ( ! unique ) {
114+ syncTenantSelectionFromValue ( value )
103115 }
104116 }
105117
@@ -108,7 +120,7 @@ export const TenantField = ({ debug, unique, ...fieldArgs }: Props) => {
108120 setEntityType ( undefined )
109121 }
110122 }
111- } , [ unique , options , selectedTenantID , setTenant , value , setEntityType , entityType ] )
123+ } , [ entityType , setEntityType , syncTenantSelectionFromValue , unique , value ] )
112124
113125 React . useEffect ( ( ) => {
114126 if ( unique || debug || isEditManyModalOpen ) {
@@ -138,12 +150,12 @@ export const TenantField = ({ debug, unique, ...fieldArgs }: Props) => {
138150 if ( ! unique ) {
139151 /** Editing a non-global tenant document */
140152 return (
141- < AssignTenantFieldModal
142- afterModalClose = { afterModalClose }
143- afterModalOpen = { afterModalOpen }
144- onConfirm = { onConfirm }
145- >
146- < TenantRelationshipField fieldArgs = { fieldArgs } unique = { unique } / >
153+ < AssignTenantFieldModal afterModalOpen = { afterModalOpen } onConfirm = { onConfirm } >
154+ < FieldPathContext value = { tenantField . path } >
155+ < FieldContext value = { localTenantField } >
156+ < TenantRelationshipField fieldArgs = { fieldArgs } unique = { unique } />
157+ </ FieldContext >
158+ </ FieldPathContext >
147159 </ AssignTenantFieldModal >
148160 )
149161 }
@@ -154,6 +166,28 @@ export const TenantField = ({ debug, unique, ...fieldArgs }: Props) => {
154166 return null
155167}
156168
169+ const hasTenantValueChanged = ( {
170+ hasMany,
171+ modalValue,
172+ value,
173+ } : {
174+ hasMany ?: boolean
175+ modalValue : TenantValue | undefined
176+ value : TenantValue | undefined
177+ } ) : boolean => {
178+ if ( hasMany ) {
179+ const currentValue = ( value || [ ] ) as ( number | string ) [ ]
180+ const nextValue = ( modalValue || [ ] ) as ( number | string ) [ ]
181+
182+ return (
183+ currentValue . length !== nextValue . length ||
184+ nextValue . some ( ( nextValueItem ) => ! currentValue . includes ( nextValueItem ) )
185+ )
186+ }
187+
188+ return value !== modalValue
189+ }
190+
157191const TenantRelationshipField : React . FC < {
158192 debug ?: boolean
159193 fieldArgs : RelationshipFieldClientProps
0 commit comments