import type { Component } from 'solid-js'; import { Show, createMemo } from 'solid-js'; import { Trash2, Calculator, EyeOff } from 'lucide-solid'; import NumericInput from './ui/NumericInput'; import type { Modifier } from '../types'; import { ModifierRegistry } from '../utils/modifier-registry'; import { CUSTOM_CALC_DEFAULT_EXPRESSION, getComputedModifierStatus, isComputedFieldModifier, isCustomCalculationModifier, isPrevailingWageModifier, TARGET_FIELD_LABELS } from '../utils/pricing'; interface ModifierRowProps { modifier: Modifier; calculatedValue: number; onUpdate: (id: string, updates: Partial) => void; onDelete: (id: string) => void; } const ModifierRow: Component = (props) => { const module = () => ModifierRegistry.getModule(props.modifier.moduleId, props.modifier); const computedStatus = createMemo(() => getComputedModifierStatus(props.modifier)); const isPrevailing = () => isPrevailingWageModifier(props.modifier); const isCustom = () => isCustomCalculationModifier(props.modifier); const isComputed = () => isComputedFieldModifier(props.modifier); const formatNumber = (num: number) => { return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }; if (isPrevailing()) { return (
props.onUpdate(props.modifier.id, { name: e.currentTarget.value })} class="bg-transparent border-none outline-none text-sm font-semibold text-foreground focus:ring-0 py-0.5 w-48" placeholder="Modifier Name" /> Unit Price
Base Rate
props.onUpdate(props.modifier.id, { targetField: 'unitPrice', parameters: { ...computedStatus().parameters, baseRate: val } })} class="w-full rounded-xl border border-border/60 bg-muted/30 px-3 py-2 text-right text-xs font-bold text-foreground outline-none transition-all focus:border-primary focus:bg-background" />
Prevailing
props.onUpdate(props.modifier.id, { targetField: 'unitPrice', parameters: { ...computedStatus().parameters, prevailingRate: val } })} class="w-full rounded-xl border border-border/60 bg-muted/30 px-3 py-2 text-right text-xs font-bold text-foreground outline-none transition-all focus:border-primary focus:bg-background" />
Multiplier {computedStatus().multiplier?.toFixed(4)}x
{computedStatus().error}
); } if (isCustom()) { return (
props.onUpdate(props.modifier.id, { name: e.currentTarget.value })} class="bg-transparent border-none outline-none text-sm font-semibold text-foreground focus:ring-0 py-0.5 w-48" placeholder="Modifier Name" />
Math Inputs: price, quantity, subtotal
props.onUpdate(props.modifier.id, { expression: e.currentTarget.value })} class="w-full rounded-xl border border-border/60 bg-muted/30 px-3 py-2 text-xs font-mono text-foreground outline-none transition-all focus:border-primary focus:bg-background" placeholder={CUSTOM_CALC_DEFAULT_EXPRESSION} />
{computedStatus().error}} > Output updates {TARGET_FIELD_LABELS[computedStatus().targetField].toLowerCase()}
Base inputs stay editable
); } if (isComputed()) { return (
props.onUpdate(props.modifier.id, { name: e.currentTarget.value })} class="bg-transparent border-none outline-none text-sm font-semibold text-foreground focus:ring-0 py-0.5 w-48" placeholder="Modifier Name" /> Legacy Modifier
{computedStatus().error}} > Existing computed modifier remains supported
); } return (
props.onUpdate(props.modifier.id, { name: e.currentTarget.value })} class="bg-transparent border-none outline-none text-sm font-medium text-muted-foreground focus:text-foreground focus:ring-0 py-0.5 w-48" placeholder="Modifier Name" />
props.onUpdate(props.modifier.id, { value: val })} class="w-20 text-right text-sm border-b border-dashed border-border focus:border-primary outline-none bg-transparent text-primary font-medium" placeholder={props.modifier.moduleId === 'man-hours' ? 'Factor' : '0.00'} /> {props.modifier.moduleId === 'man-hours' ? 'factor' : props.modifier.unitLabel}
{props.modifier.moduleId === 'man-hours' ? '' : '$'}{formatNumber(props.calculatedValue)} {props.modifier.moduleId === 'man-hours' ? ' hrs' : ''}
); }; export default ModifierRow;