feat: make MH Paid column inline-editable
Add PATCH /api/payments/:id/mh-paid-amount for direct value updates. Clicking the MH Paid cell opens an input; Enter/blur saves and refreshes, Escape cancels. Dash placeholder is also clickable to enter a value. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,8 @@ export default function PaymentsRecentTable({
|
||||
const [selectedPaymentId, setSelectedPaymentId] = useState<number | null>(null);
|
||||
const [checkedPaymentIds, setCheckedPaymentIds] = useState<Set<number>>(new Set());
|
||||
const [isMhChecking, setIsMhChecking] = useState(false);
|
||||
const [editingMhPaidId, setEditingMhPaidId] = useState<number | null>(null);
|
||||
const [editingMhPaidValue, setEditingMhPaidValue] = useState<string>("");
|
||||
|
||||
const [isRevertOpen, setIsRevertOpen] = useState(false);
|
||||
const [revertPaymentId, setRevertPaymentId] = useState<number | null>(null);
|
||||
@@ -741,12 +743,60 @@ export default function PaymentsRecentTable({
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
{payment.mhPaidAmount != null ? (
|
||||
<span className="text-sm font-medium text-green-700">
|
||||
${Number(payment.mhPaidAmount).toFixed(2)}
|
||||
</span>
|
||||
{editingMhPaidId === payment.id ? (
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
autoFocus
|
||||
className="w-24 border border-blue-400 rounded px-1 py-0.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-300"
|
||||
value={editingMhPaidValue}
|
||||
onChange={(e) => setEditingMhPaidValue(e.target.value)}
|
||||
onKeyDown={async (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.currentTarget.blur();
|
||||
} else if (e.key === "Escape") {
|
||||
setEditingMhPaidId(null);
|
||||
}
|
||||
}}
|
||||
onBlur={async () => {
|
||||
const val = parseFloat(editingMhPaidValue);
|
||||
if (!isNaN(val) && val >= 0) {
|
||||
try {
|
||||
const res = await apiRequest(
|
||||
"PATCH",
|
||||
`/api/payments/${payment.id}/mh-paid-amount`,
|
||||
{ mhPaidAmount: val }
|
||||
);
|
||||
if (res.ok) {
|
||||
await queryClient.invalidateQueries({ queryKey: QK_PAYMENTS_RECENT_BASE });
|
||||
} else {
|
||||
toast({ title: "Error", description: "Failed to save MH paid amount.", variant: "destructive" });
|
||||
}
|
||||
} catch {
|
||||
toast({ title: "Error", description: "Failed to save MH paid amount.", variant: "destructive" });
|
||||
}
|
||||
}
|
||||
setEditingMhPaidId(null);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-xs text-gray-400">—</span>
|
||||
<span
|
||||
className="text-sm font-medium text-green-700 cursor-pointer hover:underline hover:text-green-900"
|
||||
title="Click to edit"
|
||||
onClick={() => {
|
||||
setEditingMhPaidId(payment.id);
|
||||
setEditingMhPaidValue(
|
||||
payment.mhPaidAmount != null
|
||||
? Number(payment.mhPaidAmount).toFixed(2)
|
||||
: "0.00"
|
||||
);
|
||||
}}
|
||||
>
|
||||
{payment.mhPaidAmount != null
|
||||
? `$${Number(payment.mhPaidAmount).toFixed(2)}`
|
||||
: <span className="text-gray-400 font-normal">—</span>}
|
||||
</span>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user