'use client'; import { useState } from 'react'; import { Plus, Minus, ChevronDown, ChevronRight } from 'lucide-react'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Card } from './ui/card'; export interface SchemaField { id: string; name: string; type: 'field' | 'group'; description: string; fields?: SchemaField[]; } const defaultSchema: SchemaField[] = [ { id: '1', name: 'company', type: 'field', description: 'name of company' }, { id: '2', name: 'address', type: 'field', description: 'address of company' }, { id: '3', name: 'total_sum', type: 'field', description: 'total amount we purchased' }, { id: '4', name: 'items', type: 'group', description: 'list of items purchased', fields: [ { id: '4.1', name: 'item', type: 'field', description: 'name of item' }, { id: '4.2', name: 'unit_price', type: 'field', description: 'unit price of item' }, { id: '4.3', name: 'quantity', type: 'field', description: 'quantity we purchased' }, { id: '4.4', name: 'sum', type: 'field', description: 'total amount we purchased' } ] } ]; interface SchemaDefinitionProps { onSchemaChange: (schema: SchemaField[]) => void; } export function SchemaDefinition({ onSchemaChange }: SchemaDefinitionProps) { const [schema, setSchema] = useState<SchemaField[]>(defaultSchema); const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set(['4'])); const toggleGroup = (id: string) => { setExpandedGroups(prev => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); }; const addField = (parentId?: string) => { const newField: SchemaField = { id: Date.now().toString(), name: '', type: 'field', description: '' }; if (parentId) { setSchema(prev => { const updateFields = (fields: SchemaField[]): SchemaField[] => { return fields.map(field => { if (field.id === parentId) { return { ...field, fields: [...(field.fields || []), newField] }; } if (field.fields) { return { ...field, fields: updateFields(field.fields) }; } return field; }); }; return updateFields(prev); }); } else { setSchema(prev => [...prev, newField]); } }; const addGroup = (parentId?: string) => { const newGroup: SchemaField = { id: Date.now().toString(), name: '', type: 'group', description: '', fields: [] }; if (parentId) { setSchema(prev => { const updateFields = (fields: SchemaField[]): SchemaField[] => { return fields.map(field => { if (field.id === parentId) { return { ...field, fields: [...(field.fields || []), newGroup] }; } if (field.fields) { return { ...field, fields: updateFields(field.fields) }; } return field; }); }; return updateFields(prev); }); } else { setSchema(prev => [...prev, newGroup]); } setExpandedGroups(prev => new Set([...prev, newGroup.id])); }; const removeField = (id: string) => { const removeFieldFromArray = (fields: SchemaField[]): SchemaField[] => { return fields.filter(field => { if (field.id === id) return false; if (field.fields) { field.fields = removeFieldFromArray(field.fields); } return true; }); }; setSchema(prev => removeFieldFromArray(prev)); }; const updateField = (id: string, updates: Partial<SchemaField>) => { const updateFieldInArray = (fields: SchemaField[]): SchemaField[] => { return fields.map(field => { if (field.id === id) { return { ...field, ...updates }; } if (field.fields) { return { ...field, fields: updateFieldInArray(field.fields) }; } return field; }); }; const updatedSchema = updateFieldInArray(schema); setSchema(updatedSchema); onSchemaChange(updatedSchema); }; const renderField = (field: SchemaField, depth = 0) => { const isExpanded = expandedGroups.has(field.id); return ( <div key={field.id} className="space-y-2" style={{ marginLeft: `${depth * 20}px` }}> <Card className="p-4"> <div className="flex items-center space-x-2"> {field.type === 'group' && ( <Button variant="ghost" size="icon" onClick={() => toggleGroup(field.id)} > {isExpanded ? ( <ChevronDown className="h-4 w-4" /> ) : ( <ChevronRight className="h-4 w-4" /> )} </Button> )} <Input placeholder="Field name" value={field.name} onChange={(e) => updateField(field.id, { name: e.target.value })} className="flex-1" /> <Input placeholder="Description" value={field.description} onChange={(e) => updateField(field.id, { description: e.target.value })} className="flex-1" /> <Button variant="destructive" size="icon" onClick={() => removeField(field.id)} > <Minus className="h-4 w-4" /> </Button> </div> </Card> {field.type === 'group' && isExpanded && ( <div className="space-y-2"> {field.fields?.map(subField => renderField(subField, depth + 1))} <div className="flex space-x-2" style={{ marginLeft: `${(depth + 1) * 20}px` }}> <Button variant="outline" size="sm" onClick={() => addField(field.id)} > <Plus className="h-4 w-4 mr-2" /> Add Field </Button> <Button variant="outline" size="sm" onClick={() => addGroup(field.id)} > <Plus className="h-4 w-4 mr-2" /> Add Group </Button> </div> </div> )} </div> ); }; return ( <div className="space-y-4"> <div className="flex justify-between items-center"> <h2 className="text-lg font-semibold">Schema Definition</h2> <div className="space-x-2"> <Button variant="outline" onClick={() => addField()}> <Plus className="h-4 w-4 mr-2" /> Add Field </Button> <Button variant="outline" onClick={() => addGroup()}> <Plus className="h-4 w-4 mr-2" /> Add Group </Button> </div> </div> <div className="space-y-2"> {schema.map(field => renderField(field))} </div> </div> ); }