import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { type Condition, type ConditionGroup, createEmptyCondition, createEmptyGroup, FIELD_CONFIG, OPERATOR_LABELS, type RuleStructure, } from '@/lib/rule-builder-utils'; import { ChevronDown, Plus, Trash2, X } from 'lucide-react'; import { useEffect, useState } from 'react'; interface RuleBuilderProps { value: RuleStructure; onChange: (value: RuleStructure) => void; error?: string; } export function RuleBuilder({ value, onChange, error }: RuleBuilderProps) { const [structure, setStructure] = useState(value); useEffect(() => { setStructure(value); }, [value]); const handleStructureChange = (newStructure: RuleStructure) => { setStructure(newStructure); onChange(newStructure); }; const addGroup = () => { handleStructureChange({ ...structure, groups: [...structure.groups, createEmptyGroup()], }); }; const removeGroup = (groupId: string) => { if (structure.groups.length === 1) { return; } handleStructureChange({ ...structure, groups: structure.groups.filter((g) => g.id !== groupId), }); }; const updateGroup = (groupId: string, updatedGroup: ConditionGroup) => { handleStructureChange({ ...structure, groups: structure.groups.map((g) => g.id === groupId ? updatedGroup : g, ), }); }; const toggleGroupOperator = () => { handleStructureChange({ ...structure, groupOperator: structure.groupOperator === 'and' ? 'or' : 'and', }); }; return (
{structure.groups.length > 1 && ( )}
{structure.groups.map((group) => (
{group.conditions.length > 1 && ( <> )}
{structure.groups.length > 1 && ( )}
{group.conditions.map((condition) => (
{ updateGroup(group.id, { ...group, conditions: group.conditions.map( (c) => c.id === condition.id ? updatedCondition : c, ), }); }} onRemove={() => { if ( group.conditions .length === 1 ) { return; } updateGroup(group.id, { ...group, conditions: group.conditions.filter( (c) => c.id !== condition.id, ), }); }} canRemove={ group.conditions.length > 1 } />
), )}
))}
{error &&

{error}

}
); } interface ConditionRowProps { condition: Condition; onChange: (condition: Condition) => void; onRemove: () => void; canRemove: boolean; } function ConditionRow({ condition, onChange, onRemove, canRemove, }: ConditionRowProps) { const fieldConfig = FIELD_CONFIG[condition.field]; const availableOperators = fieldConfig?.operators || []; const handleFieldChange = (field: string) => { const newFieldConfig = FIELD_CONFIG[field]; const newOperator = newFieldConfig.operators[0]; onChange({ ...condition, field, operator: newOperator, value: '', }); }; const handleOperatorChange = (operator: string) => { onChange({ ...condition, operator: operator as Condition['operator'], value: operator === 'is_empty' || operator === 'is_not_empty' ? '' : condition.value, }); }; const showValueInput = condition.operator !== 'is_empty' && condition.operator !== 'is_not_empty'; const inputType = fieldConfig?.type === 'number' ? 'number' : fieldConfig?.type === 'date' ? 'date' : 'text'; return (
{showValueInput && ( onChange({ ...condition, value: e.target.value }) } placeholder="Value" className="flex-1" step={inputType === 'number' ? 'any' : undefined} /> )} {!showValueInput &&
}
); }