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