62 lines
2.3 KiB
React
62 lines
2.3 KiB
React
|
|
import { cn, fmt } from '@/lib/utils';
|
|||
|
|
import { paymentSummary } from '@/lib/trackerUtils';
|
|||
|
|
|
|||
|
|
export function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, compact = false }) {
|
|||
|
|
const summary = paymentSummary(row, threshold);
|
|||
|
|
const barTone = summary.remaining === 0
|
|||
|
|
? 'bg-emerald-500'
|
|||
|
|
: summary.paid > 0
|
|||
|
|
? 'bg-amber-500'
|
|||
|
|
: 'bg-muted-foreground/40';
|
|||
|
|
|
|||
|
|
const amountLabel = (() => {
|
|||
|
|
if (summary.paid === 0) return '—';
|
|||
|
|
if (summary.overpaid > 0) return `${fmt(summary.paidTowardDue)} · overpaid`;
|
|||
|
|
if (summary.remaining > 0) return `${fmt(summary.paidTowardDue)} paid`;
|
|||
|
|
return fmt(summary.paidTowardDue);
|
|||
|
|
})();
|
|||
|
|
|
|||
|
|
const showQuickFix = onMarkFullAmount && summary.partial && summary.paid > 0;
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div>
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
onClick={onOpen}
|
|||
|
|
className={cn(
|
|||
|
|
'w-full rounded-md text-left transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
|||
|
|
compact ? 'p-2' : 'px-2 py-1.5',
|
|||
|
|
)}
|
|||
|
|
title="View payment history"
|
|||
|
|
>
|
|||
|
|
<div className="flex items-center justify-between gap-2 text-xs">
|
|||
|
|
<span className={cn('tracker-number text-[13px] font-semibold', summary.paid > 0 ? 'text-emerald-300' : 'text-muted-foreground/85')}>
|
|||
|
|
{amountLabel}
|
|||
|
|
</span>
|
|||
|
|
{summary.count > 1 && (
|
|||
|
|
<span className="shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|||
|
|
{summary.count}×
|
|||
|
|
</span>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
<div className="mt-1.5 h-1.5 overflow-hidden rounded-full bg-muted">
|
|||
|
|
<div
|
|||
|
|
className={cn('h-full rounded-full transition-all', barTone)}
|
|||
|
|
style={{ width: `${summary.percent}%` }}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</button>
|
|||
|
|
{showQuickFix && (
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
onClick={onMarkFullAmount}
|
|||
|
|
className="mt-0.5 w-full rounded px-2 py-0.5 text-left text-[10px] text-muted-foreground/60 transition-colors hover:bg-accent/50 hover:text-foreground"
|
|||
|
|
title={`Set ${fmt(summary.paidTowardDue)} as the full amount due this month`}
|
|||
|
|
>
|
|||
|
|
✓ {fmt(summary.paidTowardDue)} is the full amount
|
|||
|
|
</button>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|