import { Button } from '@workspace/ui/components/button'; import { Label } from '@workspace/ui/components/label'; import { Switch } from '@workspace/ui/components/switch'; import { Combobox } from '@workspace/ui/custom-components/combobox'; import { EnhancedInput, EnhancedInputProps } from '@workspace/ui/custom-components/enhanced-input'; import { cn } from '@workspace/ui/lib/utils'; import { CircleMinusIcon, CirclePlusIcon } from 'lucide-react'; import { useEffect, useState } from 'react'; interface FieldConfig extends Omit { name: string; type: 'text' | 'number' | 'select' | 'time' | 'boolean'; options?: { label: string; value: string }[]; internal?: boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any calculateValue?: (value: Record) => any; } interface ObjectInputProps { value: T; onChange: (value: T) => void; fields: FieldConfig[]; className?: string; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export function ObjectInput>({ value, onChange, fields, className, }: ObjectInputProps) { const [internalState, setInternalState] = useState(value); useEffect(() => { let updatedState = { ...internalState, ...value }; fields.forEach((field) => { if (field.calculateValue) { updatedState = field.calculateValue(updatedState); } }); setInternalState(updatedState); }, [value, fields]); const updateField = (key: keyof T, fieldValue: string | number | boolean) => { let updatedInternalState = { ...internalState, [key]: fieldValue }; fields.forEach((field) => { if (field.calculateValue && field.name === key) { const newValue = field.calculateValue(updatedInternalState); updatedInternalState = newValue; } }); setInternalState(updatedInternalState); const filteredValue = Object.keys(updatedInternalState).reduce((acc, fieldKey) => { const field = fields.find((f) => f.name === fieldKey); if (field && !field.internal) { acc[fieldKey as keyof T] = updatedInternalState[fieldKey as keyof T]; } return acc; }, {} as T); onChange(filteredValue); }; const renderField = (field: FieldConfig) => { switch (field.type) { case 'select': return ( field.options && ( placeholder={field.placeholder} options={field.options} value={internalState[field.name]} onChange={(fieldValue) => updateField(field.name, fieldValue)} /> ) ); case 'boolean': return (
updateField(field.name, fieldValue)} /> {field.placeholder && }
); default: return ( updateField(field.name, fieldValue)} {...field} /> ); } }; return (
{fields.map((field) => (
{renderField(field)}
))}
); } interface ArrayInputProps { value?: T[]; onChange: (value: T[]) => void; fields: FieldConfig[]; isReverse?: boolean; className?: string; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export function ArrayInput>({ value = [], onChange, fields, isReverse = false, className, }: ArrayInputProps) { const initializeDefaultItem = (): T => fields.reduce((acc, field) => { acc[field.name as keyof T] = undefined as T[keyof T]; return acc; }, {} as T); const [displayItems, setDisplayItems] = useState(() => { return value.length > 0 ? value : [initializeDefaultItem()]; }); const isItemModified = (item: T): boolean => fields.some((field) => { const val = item[field.name]; return val !== undefined && val !== null && val !== ''; }); const handleItemChange = (index: number, updatedItem: T) => { const newDisplayItems = [...displayItems]; newDisplayItems[index] = updatedItem; setDisplayItems(newDisplayItems); const modifiedItems = newDisplayItems.filter(isItemModified); onChange(modifiedItems); }; const createField = () => { if (isReverse) { setDisplayItems([initializeDefaultItem(), ...displayItems]); } else { setDisplayItems([...displayItems, initializeDefaultItem()]); } }; const deleteField = (index: number) => { const newDisplayItems = displayItems.filter((_, i) => i !== index); setDisplayItems(newDisplayItems); const modifiedItems = newDisplayItems.filter(isItemModified); onChange(modifiedItems); }; useEffect(() => { if (value.length > 0) { setDisplayItems(value); } }, [value]); return (
{displayItems.map((item, index) => (
handleItemChange(index, updatedItem)} fields={fields} className={className} />
{displayItems.length > 1 && ( )} {(isReverse ? index === 0 : index === displayItems.length - 1) && ( )}
))}
); }