fix(tracker): payment progress tracking fixes

This commit is contained in:
null 2026-06-07 16:44:40 -05:00
parent 13e41aec74
commit 34fcbb0d92
3 changed files with 23 additions and 20 deletions

View File

@ -1,7 +1,7 @@
import { cn, fmt } from '@/lib/utils';
import { paymentSummary } from '@/lib/trackerUtils';
export function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, compact = false }) {
export function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, compact = false, className }) {
const summary = paymentSummary(row, threshold);
const barTone = summary.remaining === 0
? 'bg-emerald-500'
@ -19,7 +19,7 @@ export function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, comp
const showQuickFix = onMarkFullAmount && summary.partial && summary.paid > 0;
return (
<div>
<div className={cn('w-full', className)}>
<button
type="button"
onClick={onOpen}

View File

@ -219,10 +219,12 @@ export function TrackerBucket({ label, rows, year, month, refresh, onEditBill, l
<SortableHead sortKey="due" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%]">Due</SortableHead>
<SortableHead sortKey="expected" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%] text-right">Expected</SortableHead>
<SortableHead sortKey="previous" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%] text-right">Last Month</SortableHead>
<SortableHead sortKey="paid" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%] text-right">Paid</SortableHead>
<SortableHead sortKey="paid" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%] text-center">Paid</SortableHead>
<SortableHead sortKey="paid_date" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[10%]">Paid Date</SortableHead>
<SortableHead sortKey="status" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[9%]">Status</SortableHead>
<TableHead className="w-[10%] py-2.5" />
<SortableHead sortKey="status" activeSortKey={sortKey} sortDir={sortDir} onSort={onSort} className="w-[9%] text-center">Status</SortableHead>
<TableHead className="w-[10%] py-2.5 text-center text-xs font-medium uppercase tracking-wider text-muted-foreground">
Action
</TableHead>
<TableHead className="w-[23%] py-2.5 text-xs font-medium uppercase tracking-wider text-muted-foreground border-l border-border/80 pl-4">
Notes
</TableHead>
@ -241,11 +243,11 @@ export function TrackerBucket({ label, rows, year, month, refresh, onEditBill, l
<TableCell className="w-[10%] py-3"><div className="h-3 w-20 rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3 text-right"><div className="h-3 w-20 ml-auto rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3 text-right"><div className="h-3 w-20 ml-auto rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3"><div className="h-7 w-24 ml-auto rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3"><div className="mx-auto h-7 w-24 rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3"><div className="h-7 w-24 rounded-md bg-muted" /></TableCell>
<TableCell className="w-[9%] py-3"><div className="h-5 w-20 rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3 text-right">
<div className="flex items-center justify-end gap-1">
<TableCell className="w-[9%] py-3"><div className="mx-auto h-5 w-20 rounded-md bg-muted" /></TableCell>
<TableCell className="w-[10%] py-3 text-center">
<div className="flex items-center justify-center gap-1">
<div className="h-7 w-20 rounded-md bg-muted" />
<div className="h-7 w-7 rounded-md bg-muted" />
</div>

View File

@ -306,7 +306,7 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
>
{/* Bill name + category + monthly notes (if set) */}
<TableCell className="w-[18%] py-3">
<div className="flex items-center gap-2.5">
<div className="flex min-w-0 items-center gap-2.5">
<div className="flex shrink-0 items-center gap-0.5">
<GripVertical
className={cn(
@ -339,15 +339,15 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
</button>
</div>
</div>
<div>
<div className="flex items-center gap-1">
<div className="min-w-0">
<div className="flex min-w-0 items-center gap-1.5">
{row.website ? (
<a
href={row.website}
target="_blank"
rel="noreferrer"
className={cn(
'text-[15px] font-semibold leading-tight text-foreground transition-colors',
'min-w-0 truncate text-base font-bold leading-tight text-foreground transition-colors',
'hover:underline decoration-muted-foreground/50 underline-offset-2',
isSkipped && 'line-through',
)}
@ -355,7 +355,7 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
{row.name}
</a>
) : (
<span className={cn('text-[15px] font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
<span className={cn('min-w-0 truncate text-base font-bold leading-tight text-foreground', isSkipped && 'line-through')}>
{row.name}
</span>
)}
@ -427,7 +427,7 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
</TooltipProvider>
<Button
size="icon" variant="ghost"
className="h-7 w-7 opacity-100 transition-opacity text-muted-foreground hover:text-foreground hover:bg-accent lg:opacity-0 lg:group-hover:opacity-100"
className="h-7 w-7 shrink-0 opacity-100 transition-opacity text-muted-foreground hover:text-foreground hover:bg-accent lg:opacity-0 lg:group-hover:opacity-100"
title="Edit bill"
onClick={() => onEditBill?.(row)}
>
@ -435,7 +435,7 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
</Button>
</div>
{row.category_name && (
<p className="mt-0.5 text-xs text-muted-foreground/85">{row.category_name}</p>
<p className="mt-1 truncate text-[11px] font-medium leading-none text-muted-foreground/75">{row.category_name}</p>
)}
{/* Monthly notes shown inline under the bill name */}
{row.monthly_notes && (
@ -555,10 +555,11 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
</TableCell>
{/* Amount paid — mismatch now compares against threshold */}
<TableCell className="w-[10%] py-3 text-right">
<TableCell className="w-[10%] py-3 text-center">
<PaymentProgress
row={row}
threshold={threshold}
className="mx-auto max-w-[7.5rem]"
onOpen={() => setPaymentLedgerOpen(true)}
onMarkFullAmount={!isSkipped ? handleMarkFullAmount : undefined}
/>
@ -579,7 +580,7 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
{/* Status — uses effectiveStatus (accounts for skipped + threshold) */}
<TableCell className="w-[9%] py-3">
<div className="flex flex-col items-start gap-1">
<div className="flex flex-col items-center gap-1">
<StatusBadge
status={effectiveStatus}
clickable
@ -601,8 +602,8 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
</TableCell>
{/* Actions */}
<TableCell className="w-[10%] py-3 text-right">
<div className="flex items-center justify-end gap-1">
<TableCell className="w-[10%] py-3 text-center">
<div className="flex items-center justify-center gap-1">
{showUpdateNudge ? (
<div className="flex items-center gap-1 animate-in fade-in slide-in-from-right-1 duration-200">
<span className="text-[10px] text-muted-foreground">Update default?</span>