'use client' import React, { useState } from 'react' import type { ConditionNode, FieldCatalogEntry, ComparisonOperator } from '@/types' interface Props { node: ConditionNode fieldCatalog: FieldCatalogEntry[] onChange: (node: ConditionNode) => void onDelete: () => void readOnly?: boolean } const OPERATORS: { value: ComparisonOperator; label: string; showValue: 'single' | 'double' | 'none' | 'multi' }[] = [ { value: 'EQUALS', label: '= Equals', showValue: 'single' }, { value: 'NOT_EQUALS', label: '≠ Not Equals', showValue: 'single' }, { value: 'GREATER_THAN', label: '> Greater Than', showValue: 'single' }, { value: 'GREATER_THAN_OR_EQUAL', label: '≥ Greater Than or Equal', showValue: 'single' }, { value: 'LESS_THAN', label: '< Less Than', showValue: 'single' }, { value: 'LESS_THAN_OR_EQUAL', label: '≤ Less Than or Equal', showValue: 'single' }, { value: 'BETWEEN', label: '↔ Between', showValue: 'double' }, { value: 'IN', label: '∈ In (comma separated)', showValue: 'single' }, { value: 'NOT_IN', label: '∉ Not In', showValue: 'single' }, { value: 'CONTAINS', label: '⊆ Contains', showValue: 'single' }, { value: 'IS_NULL', label: '∅ Is Empty/Null', showValue: 'none' }, { value: 'IS_NOT_NULL', label: '• Is Not Null', showValue: 'none' }, { value: 'IS_TRUE', label: '✓ Is True', showValue: 'none' }, { value: 'IS_FALSE', label: '✗ Is False', showValue: 'none' }, { value: 'REGEX', label: '⚙ Matches Regex', showValue: 'single' }, ] const FIELD_CATEGORIES = ['BUREAU', 'INCOME', 'PERSONAL', 'EMPLOYMENT', 'VEHICLE', 'FI', 'LOAN', 'RATIOS', 'FRAUD', 'GST', 'ITR', 'KYC'] export function ConditionNodeEditor({ node, fieldCatalog, onChange, onDelete, readOnly }: Props) { const [showFieldSearch, setShowFieldSearch] = useState(false) const [fieldSearch, setFieldSearch] = useState('') const selectedOp = OPERATORS.find((o) => o.value === node.operator) const selectedField = fieldCatalog.find((f) => f.fieldPath === node.field) const filteredFields = fieldCatalog.filter( (f) => !fieldSearch || f.fieldPath.toLowerCase().includes(fieldSearch.toLowerCase()) || f.displayName.toLowerCase().includes(fieldSearch.toLowerCase()) ) const groupedFields = FIELD_CATEGORIES.reduce>((acc, cat) => { const fields = filteredFields.filter((f) => f.category === cat) if (fields.length > 0) acc[cat] = fields return acc }, {}) return (
{/* Field Selector */}
{showFieldSearch && !readOnly && (
setFieldSearch(e.target.value)} placeholder="Search fields..." className="w-full text-sm px-2 py-1.5 border border-gray-200 rounded-lg focus:outline-none focus:border-blue-400" />
{Object.entries(groupedFields).map(([cat, fields]) => (
{cat}
{fields.map((f) => ( ))}
))}
)}
{/* Operator Selector */} {/* Value Input(s) */} {selectedOp?.showValue === 'single' && ( onChange({ ...node, value: v })} placeholder="Value" /> )} {selectedOp?.showValue === 'double' && ( <> onChange({ ...node, value: v })} placeholder="From" /> and onChange({ ...node, value2: v })} placeholder="To" /> )} {/* Field badge */} {node.field && ( {node.field} )}
) } function ValueInput({ value, fieldType, onChange, placeholder, readOnly, }: { value: string fieldType?: string onChange: (v: string) => void placeholder: string readOnly?: boolean }) { if (fieldType === 'BOOLEAN') { return ( ) } return ( onChange(e.target.value)} placeholder={placeholder} className="text-sm border border-gray-200 rounded-lg px-2 py-1.5 bg-gray-50 focus:outline-none focus:border-blue-500 w-32" /> ) }