File tree Expand file tree Collapse file tree
src/modules/Builder/features/SaveAndPublish Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -319,9 +319,19 @@ export const useSaveAndPublishSetup = (): SaveAndPublishSetup => {
319319 // `isDirty` is a structural deep-compare of the form values against the form defaults,
320320 // so empty arrays that field arrays (e.g. `responseValues.rows`) inject into the form
321321 // values on mount — but never into the defaults — make `isDirty` permanently `true`
322- // even with no real changes. `dirtyFields` stays empty in that case, so it accurately
323- // reflects whether there are unsaved user changes worth prompting about.
324- const hasFormChanges = ! ! Object . keys ( dirtyFields ?? { } ) . length ;
322+ // even with no real changes.
323+ //
324+ // A shallow `Object.keys(dirtyFields).length` check is also insufficient: after a
325+ // useFieldArray append+remove round-trip, RHF leaves stale array-shaped entries in
326+ // `dirtyFields` (e.g. `{ activities: [{ name: false, … }] }`) even though every leaf
327+ // is `false`. Recursively scanning for any `true` leaf is the correct signal.
328+ const hasTrueDirtyField = ( val : unknown ) : boolean => {
329+ if ( val === true ) return true ;
330+ if ( ! val || typeof val !== 'object' ) return false ;
331+
332+ return Object . values ( val ) . some ( hasTrueDirtyField ) ;
333+ } ;
334+ const hasFormChanges = hasTrueDirtyField ( dirtyFields ) ;
325335 const {
326336 cancelNavigation : onCancelNavigation ,
327337 confirmNavigation,
You can’t perform that action at this time.
0 commit comments