Files
payload/packages/ui/src/forms/Form/mergeServerFormState.ts
Jessica Chowdhury 7cccca8194 chore(alpha): update fields-relationship e2e tests (#5553)
* fix: handles filter options in form state merge

* chore: fix and reintegrate fields-relationship e2e tests

* chore: update withMergedProps function for e2e tests
2024-04-03 16:11:19 +01:00

74 lines
2.3 KiB
TypeScript

import type { FormState } from 'payload/types'
import deepEquals from 'deep-equal'
import { mergeErrorPaths } from './mergeErrorPaths.js'
const serverPropsToAccept = ['passesCondition', 'valid', 'errorMessage']
/**
* Merges certain properties from the server state into the client state. These do not include values,
* as we do not want to update them on the client like that, which would cause flickering.
*
* We want to use this to update the error state, and other properties that are not user input, as the error state
* is the thing we want to keep in sync with the server (where it's calculated) on the client.
*/
export const mergeServerFormState = (
existingState: FormState,
incomingState: FormState,
): { changed: boolean; newState: FormState } => {
let changed = false
const newState = {}
if (existingState) {
Object.entries(existingState).forEach(([path, newFieldState]) => {
if (!incomingState[path]) return
/**
* Handle error paths
*/
const errorPathsResult = mergeErrorPaths(
newFieldState.errorPaths,
incomingState[path].errorPaths as unknown as string[],
)
if (errorPathsResult.result) {
if (errorPathsResult.changed) {
changed = errorPathsResult.changed
}
newFieldState.errorPaths = errorPathsResult.result
}
/**
* Handle filterOptions
*/
if (incomingState[path]?.filterOptions || newFieldState.filterOptions) {
if (!deepEquals(incomingState[path]?.filterOptions, newFieldState.filterOptions)) {
changed = true
newFieldState.filterOptions = incomingState[path].filterOptions
}
}
/**
* Handle the rest which is in serverPropsToAccept
*/
serverPropsToAccept.forEach((prop) => {
if (incomingState[path]?.[prop] !== newFieldState[prop]) {
changed = true
if (!(prop in incomingState[path])) {
delete newFieldState[prop]
} else {
newFieldState[prop] = incomingState[path][prop]
}
}
})
// Conditions don't work if we don't memcopy the new state, as the object references would otherwise be the same
newState[path] = { ...newFieldState }
})
}
return { changed, newState }
}