import { useState, useRef } from 'react'; import { toast } from 'sonner'; import { api } from '@/api.js'; import { cn, fmt, fmtDate } from '@/lib/utils'; import { Input } from '@/components/ui/input'; // `threshold` = actual_amount ?? expected_amount for this bill/month export function EditableCell({ row, field, threshold, defaultPaymentDate, refresh }) { const [editing, setEditing] = useState(false); const [value, setValue] = useState(''); const inputRef = useRef(null); const displayVal = field === 'amount' ? (row.total_paid > 0 ? fmt(row.total_paid) : '—') : (row.last_paid_date ? fmtDate(row.last_paid_date) : '—'); const isEmpty = field === 'amount' ? row.total_paid <= 0 : !row.last_paid_date; // Mismatch when paid amount differs from the effective threshold for this month const mismatch = field === 'amount' && row.total_paid > 0 && row.total_paid !== threshold; function startEdit() { if (editing) return; setValue(field === 'amount' ? (row.total_paid > 0 ? String(row.total_paid) : '') : (row.last_paid_date || '')); setEditing(true); setTimeout(() => { inputRef.current?.focus(); inputRef.current?.select(); }, 0); } async function commit() { setEditing(false); const val = value.trim(); if (!val) return; try { if (row.payments && row.payments.length > 0) { const update = {}; if (field === 'amount') update.amount = parseFloat(val); if (field === 'date') update.paid_date = val; await api.updatePayment(row.payments[0].id, update); } else { await api.createPayment({ bill_id: row.id, amount: field === 'amount' ? parseFloat(val) : threshold, paid_date: field === 'date' ? val : defaultPaymentDate, }); } toast.success('Saved'); refresh(); } catch (err) { toast.error(err.message); } } function onKeyDown(e) { if (e.key === 'Enter') inputRef.current?.blur(); if (e.key === 'Escape') { setValue(''); setEditing(false); } } if (editing) { return ( setValue(e.target.value)} onBlur={commit} onKeyDown={onKeyDown} className="h-7 w-28 text-right font-mono text-sm bg-background/80 border-border/60" /> ); } return ( {displayVal} ); }