import { Field as FieldSchema } from '../../../../fields/config/types'; import { Fields, Field, Data } from './types'; const buildValidationPromise = async (fieldState: Field, field: FieldSchema) => { const validatedFieldState = fieldState; validatedFieldState.valid = typeof field.validate === 'function' ? await field.validate(fieldState.value, field) : true; if (typeof validatedFieldState.valid === 'string') { validatedFieldState.errorMessage = validatedFieldState.valid; validatedFieldState.valid = false; } }; const buildStateFromSchema = async (fieldSchema: FieldSchema[], fullData: Data = {}): Promise => { if (fieldSchema) { const validationPromises = []; const structureFieldState = (field, data = {}) => { const value = typeof data?.[field.name] !== 'undefined' ? data[field.name] : field.defaultValue; const fieldState = { value, initialValue: value, valid: true, }; validationPromises.push(buildValidationPromise(fieldState, field)); return fieldState; }; const iterateFields = (fields: FieldSchema[], data: Data, path = '') => fields.reduce((state, field) => { let initialData = data; if (field.name && field.defaultValue && typeof initialData?.[field.name] === 'undefined') { initialData = { [field.name]: field.defaultValue }; } if (field.name) { if (field.type === 'relationship' && initialData?.[field.name] === null) { initialData[field.name] = 'null'; } if (field.type === 'array' || field.type === 'blocks') { if (Array.isArray(initialData?.[field.name])) { const rows = initialData[field.name] as Data[]; if (field.type === 'array') { return { ...state, ...rows.reduce((rowState, row, i) => ({ ...rowState, ...iterateFields(field.fields, row, `${path}${field.name}.${i}.`), }), {}), }; } if (field.type === 'blocks') { return { ...state, ...rows.reduce((rowState, row, i) => { const block = field.blocks.find((blockType) => blockType.slug === row.blockType); const rowPath = `${path}${field.name}.${i}.`; return { ...rowState, [`${rowPath}blockType`]: { value: row.blockType, initialValue: row.blockType, valid: true, }, [`${rowPath}blockName`]: { value: row.blockName, initialValue: row.blockName, valid: true, }, ...(block?.fields ? iterateFields(block.fields, row, rowPath) : {}), }; }, {}), }; } } return state; } // Handle non-array-based nested fields (group, etc) if (Array.isArray(field.fields)) { return { ...state, ...iterateFields(field.fields, initialData?.[field.name], `${path}${field.name}.`), }; } return { ...state, [`${path}${field.name}`]: structureFieldState(field, data), }; } // Handle field types that do not use names (row, etc) if (field.fields) { return { ...state, ...iterateFields(field.fields, data, path), }; } // Handle normal fields return { ...state, [`${path}${field.name}`]: structureFieldState(field, data), }; }, {}); const resultingState = iterateFields(fieldSchema, fullData); await Promise.all(validationPromises); return resultingState; } return {}; }; export default buildStateFromSchema;