'use client'
/**
* Strukturierter Editor fuer JSONB-Conditions:
* { kind: 'all'|'any', clauses: [{field, op, value}] }
*
* Wird im RuleEditor verwendet. Reine Praesentations-Komponente — Parent
* verwaltet State.
*/
import type {
ClauseOperator, RuleClause, RuleCondition,
} from '../_types'
import { OPERATOR_LABELS, PROFILE_FIELDS } from '../_types'
interface Props {
value: RuleCondition
onChange: (next: RuleCondition) => void
readOnly?: boolean
}
export default function ConditionBuilder({ value, onChange, readOnly }: Props) {
const setKind = (kind: 'all' | 'any') => onChange({ ...value, kind })
const setClause = (idx: number, clause: RuleClause) => {
const next = [...value.clauses]
next[idx] = clause
onChange({ ...value, clauses: next })
}
const addClause = () =>
onChange({
...value,
clauses: [
...value.clauses,
{ field: PROFILE_FIELDS[0].key, op: 'eq', value: '' },
],
})
const removeClause = (idx: number) =>
onChange({ ...value, clauses: value.clauses.filter((_, i) => i !== idx) })
return (
Bedingung:
{value.clauses.length === 0 && (
Keine Klauseln — Regel gilt für jedes Profil.
)}
{value.clauses.map((clause, idx) => (
-
setClause(idx, c)}
readOnly={!!readOnly}
/>
{!readOnly && (
)}
))}
{!readOnly && (
)}
)
}
function ClauseRow({
clause, onChange, readOnly,
}: {
clause: RuleClause
onChange: (c: RuleClause) => void
readOnly: boolean
}) {
const field = PROFILE_FIELDS.find((f) => f.key === clause.field) || PROFILE_FIELDS[0]
const operators: ClauseOperator[] =
field.type === 'enum'
? ['eq', 'neq', 'in', 'not_in', 'exists', 'truthy', 'falsy']
: field.type === 'boolean'
? ['truthy', 'falsy', 'eq', 'neq']
: field.type === 'number'
? ['eq', 'neq', 'gt', 'gte', 'lt', 'lte']
: ['eq', 'neq', 'in', 'not_in', 'exists']
const requiresValue = !['exists', 'truthy', 'falsy'].includes(clause.op)
const multiValue = clause.op === 'in' || clause.op === 'not_in'
return (
{requiresValue && (
onChange({ ...clause, value: v })}
readOnly={readOnly}
/>
)}
)
}
function ValueInput({
field, multi, value, onChange, readOnly,
}: {
field: typeof PROFILE_FIELDS[number]
multi: boolean
value: unknown
onChange: (v: unknown) => void
readOnly: boolean
}) {
if (field.type === 'enum' && field.options) {
if (multi) {
const selected = Array.isArray(value) ? (value as string[]) : []
return (
)
}
return (
)
}
if (field.type === 'number') {
return (
onChange(Number(e.target.value))}
/>
)
}
if (field.type === 'boolean') {
return (
)
}
return (
onChange(e.target.value)}
/>
)
}