diff --git a/src_generic/components/fields/FormField.tsx b/src_generic/components/fields/FormField.tsx new file mode 100644 index 0000000..81390ec --- /dev/null +++ b/src_generic/components/fields/FormField.tsx @@ -0,0 +1,224 @@ +import * as React from 'react'; +import { + TextField, + FormControl, + InputLabel, + Select, + MenuItem, + FormControlLabel, + Checkbox, + Typography, + Box, + Divider, +} from '@mui/material'; +import { ResourceField } from '../../types/config'; +import ImageUploadField from './ImageUploadField'; + +interface FormFieldProps { + name: string; + field: ResourceField; + value: any; + onChange: (val: any) => void; + disabled?: boolean; + uploadFile: (file: File) => Promise; + uploading: boolean; + baseUrl: string; + relationDataMap?: Record; // Map of relation name to data array +} + +export default function FormField({ + name, + field, + value, + onChange, + disabled, + uploadFile, + uploading, + baseUrl, + relationDataMap = {}, +}: FormFieldProps) { + const label = field.label; + + // 1. Recursive Rendering for Objects (Not Relations) + if (field.type === 'object' && field.schema && !field.relation) { + return ( + + + {label} + + + {Object.entries(field.schema).map(([subKey, subField]) => ( + { + const updated = { ...(value || {}), [subKey]: newVal }; + onChange(updated); + }} + disabled={disabled} + uploadFile={uploadFile} + uploading={uploading} + baseUrl={baseUrl} + relationDataMap={relationDataMap} + /> + ))} + + + ); + } + + // 2. Relation Handling (Select / Multi-Select) + if (field.relation && relationDataMap[field.relation]) { + const relationData = relationDataMap[field.relation]; + const isArrayRelation = field.type === 'array'; + + // Determine how to display the related item + const getOptionLabel = (option: any) => { + if (!option) return ""; + if (field.displayField && option[field.displayField]) return option[field.displayField]; + // Standard naming fields + return option.name || option.title || option.label || option.id || JSON.stringify(option); + }; + + const getOptionValue = (option: any) => { + // Return the whole object to maintain identity + return option; + }; + + return ( + + {label} + + + ); + } + + // 3. Image Handling + if (field.type === 'image') { + return ( + { + const url = await uploadFile(file); + if (url) onChange(url); + }} + uploading={uploading} + baseUrl={baseUrl} + disabled={disabled} + /> + ); + } + + // 4. Boolean Handling + if (field.type === 'boolean') { + return ( + onChange(e.target.checked)} + disabled={disabled} + /> + } + label={label} + /> + ); + } + + // 5. Enum Handling + if (field.type === 'enum' && field.options) { + return ( + + {label} + + + ); + } + + // 6. Common Text Fields + if (field.type === 'datetime' || field.type === 'date') { + return ( + onChange(e.target.value)} + disabled={disabled} + required={field.required} + /> + ); + } + + if (field.type === 'markdown' || field.type === 'string') { + return ( + onChange(e.target.value)} + disabled={disabled} + required={field.required} + /> + ); + } + + if (field.type === 'number') { + return ( + onChange(e.target.value === '' ? '' : Number(e.target.value))} + disabled={disabled} + required={field.required} + /> + ); + } + + return ( + + ); +}