UNPKG

magner

Version:

Universal admin panel magnetic to any backend

135 lines (118 loc) 4.54 kB
import type { GenericComponent } from 'lib/types/form'; import type { FormLayout, GenericFormLayout } from 'lib/types/form/layout'; export type SupportedDataTypes = 'string'|'number'|'array'|'object'|'date'|'boolean'; export type DataTypeInitials = '' | null | [] | {} | false; /** * If there is a field which operates a data not of a string type, it is recommended to * set the 'dataType' field to help the form working with the data. */ export const dataTypeToInitial = (dataType: SupportedDataTypes): DataTypeInitials => { switch (dataType) { case 'string': return ''; case 'number': return null; case 'boolean': return false; case 'array': return []; case 'object': return {}; case 'date': return null; default: return ''; } }; /** Function extracts all fields from the nested layout recursively */ export const collectFieldsFromLayout = ( layout: GenericFormLayout<any> | GenericFormLayout<any>[], ): GenericComponent<any>[] => { const fields: GenericComponent<any>[] = []; if (Array.isArray(layout)) { fields.push(...layout.map((singleLayout) => collectFieldsFromLayout(singleLayout)).flat()); } else if (layout.layout) { fields.push(...collectFieldsFromLayout(layout.layout)); } else if (layout.fields) { fields.push(...layout.fields); } return fields; }; export const parseUrl = (query: { data?: string }) => { try { return JSON.parse(decodeURI(query?.data || '')); } catch (_) { return null; } }; /** Extract all generic components (fields) from layout */ export const layoutToFields = (layout: FormLayout<any>): GenericComponent<Record<string, unknown>>[] => { let fields: GenericComponent<any>[]; if (Array.isArray(layout)) { fields = layout; } else { fields = collectFieldsFromLayout(layout); } return fields; }; /** * Creates an object with initial values for each field of a form. * This object is used when the form triggers the 'submit' event. */ export const fieldsToModels = ( fields: GenericComponent<Record<string, any>>[], initialData?: Record<string, any>, ): Record<string, DataTypeInitials> => fields .reduce((accum, currentValue) => { // In case of FormCollection, get all fields in the collection, and assign initial values // for each form in the collection as an object if (currentValue.type === 'collection') { const initialCollection = initialData?.[currentValue.name] || []; const collectionLen = initialCollection.length ?? (currentValue.props.showFirst ? 1 : 0); const collectionFields = collectFieldsFromLayout(currentValue.layout as unknown as GenericFormLayout<any>); accum[currentValue.name] = (new Array(collectionLen).fill(0)) .map((_, index) => fieldsToModels( collectionFields, (initialCollection?.[index] || {}) as Record<string, unknown>, )); return accum; } accum[currentValue.name] = initialData?.[currentValue.name] ?? dataTypeToInitial(currentValue.dataType || 'string'); return accum; }, {} as Record<string, DataTypeInitials>); export const initialDifference = (form: Record<string, any>, initialData: Record<string, any>) => Object .entries(form) .reduce((accum, entry) => { // eslint-disable-next-line no-prototype-builtins if (!initialData?.hasOwnProperty(entry[0])) return accum; const initial = initialData[entry[0]]; const current = entry[1]; if (typeof current !== 'object' && initial !== current) { accum[entry[0]] = current; return accum; } if (Array.isArray(current)) { const hasDifference = current.some((currentNestedVal, i) => { const initialNestedVal = initial?.[i]; if (currentNestedVal !== initialNestedVal) return true; if (typeof currentNestedVal === 'object' && typeof initialNestedVal === 'object') { const nestedDifference = initialDifference(currentNestedVal, initialNestedVal); return !!Object.keys(nestedDifference).length; } return false; }); if (hasDifference || current?.length !== initial?.length) { accum[entry[0]] = current; return accum; } } if (typeof current === 'object' && current instanceof Date) { accum[entry[0]] = current; } // Example [](initial) => null(current) if (Array.isArray(initial) && !Array.isArray(current)) { accum[entry[0]] = current; } return accum; }, {} as Record<string, DataTypeInitials>);