refactor: replace status dropdown with computed status badge

Status is now derived from the numbers — no manual switching needed:
- Balance = 0 → Paid in Full (teal)
- Balance > 0, Collected > 0 → Partially Paid (blue)
- Balance > 0, Collected = 0 → Pending (red)

VOID/DENIED/OVERPAID still show from DB as manual decisions.
Removed Revert Full Due button (tied to old status system).
Void button now shows for all non-VOID, non-DENIED payments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-06 21:46:25 -04:00
parent 49415bcfc4
commit c4ce5dd23d

View File

@@ -718,61 +718,33 @@ export default function PaymentsRecentTable({
<TableCell>
<div className="flex items-center gap-2">
{(() => {
const { label, color, icon } = getStatusInfo(
payment.status
);
const switchableStatuses: PaymentStatus[] = [
"PENDING",
"PARTIALLY_PAID",
"PAID",
];
const isSwitchable = switchableStatuses.includes(
payment.status as PaymentStatus
);
if (isSwitchable) {
// VOID and DENIED are manual decisions — show as-is
if (payment.status === "VOID" || payment.status === "DENIED" || payment.status === "OVERPAID") {
const { label, color, icon } = getStatusInfo(payment.status);
return (
<select
value={payment.status ?? ""}
onChange={(e) => {
const val = e.target.value as PaymentStatus;
if (val === "PAID") {
handlePayAbsoluteFullDue(payment.id);
} else if (payment.status === "PAID") {
// revert the full payment amount, then set the new status
fullPaymentMutation.mutate(
{ paymentId: payment.id, type: "revert" },
{
onSuccess: () => {
updatePaymentStatusMutation.mutate({
paymentId: payment.id,
status: val,
});
},
}
);
} else {
updatePaymentStatusMutation.mutate({
paymentId: payment.id,
status: val,
});
}
}}
className={`px-2 py-1 text-xs font-medium rounded-full border-0 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-teal-400 ${color}`}
>
<option value="PENDING">Pending</option>
<option value="PARTIALLY_PAID">Partially Paid</option>
<option value="PAID">Paid in Full</option>
</select>
);
}
return (
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${color}`}
>
<span className="flex items-center">
{icon}
{label}
<span className={`px-2 py-1 text-xs font-medium rounded-full ${color}`}>
<span className="flex items-center">{icon}{label}</span>
</span>
);
}
// Compute status from numbers
if (totalDue === 0) {
return (
<span className="px-2 py-1 text-xs font-medium rounded-full bg-teal-100 text-teal-800">
<span className="flex items-center"><CheckCircle className="h-3 w-3 mr-1" />Paid in Full</span>
</span>
);
}
if (totalCollected > 0) {
return (
<span className="px-2 py-1 text-xs font-medium rounded-full bg-blue-100 text-blue-800">
<span className="flex items-center"><DollarSign className="h-3 w-3 mr-1" />Partially Paid</span>
</span>
);
}
return (
<span className="px-2 py-1 text-xs font-medium rounded-full bg-red-100 text-red-800">
<span className="flex items-center"><Clock className="h-3 w-3 mr-1" />Pending</span>
</span>
);
})()}
@@ -977,9 +949,9 @@ export default function PaymentsRecentTable({
</Button>
)}
{/* When NOT PAID and NOT VOID → Void */}
{payment.status !== "PAID" &&
payment.status !== "VOID" && (
{/* Show Void unless already voided or denied */}
{payment.status !== "VOID" &&
payment.status !== "DENIED" && (
<Button
variant="outline"
size="sm"
@@ -992,20 +964,6 @@ export default function PaymentsRecentTable({
</Button>
)}
{/* When PAID → Revert */}
{payment.status === "PAID" && (
<Button
variant="outline"
size="sm"
onClick={() => {
setRevertPaymentId(payment.id);
setIsRevertOpen(true);
}}
>
Revert Full Due
</Button>
)}
{/* When VOID → Unvoid */}
{payment.status === "VOID" && (
<Button