fix(tracker): pin-Due sort uses reconciled status; add filtered-empty state
- Pin-upcoming sort ranked on raw row.status, so a bill paid-by-threshold but still carrying a stale 'late'/'missed' status was pinned to the top. Rank on rowEffectiveStatus (same source the overdue filter uses) so it sorts to the bottom instead. - Filtering to zero results showed a blank content area (rows.length checks the unfiltered list). Add a "No bills match your filters" state with a Clear-filters action. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ef566b12f0
commit
db1be4b0bd
|
|
@ -622,8 +622,11 @@ export default function TrackerPage() {
|
|||
? sortTrackerRows(filteredRows, sortKey, sortDir)
|
||||
: pinUpcoming
|
||||
? [...filteredRows].sort((a, b) => {
|
||||
const ua = URGENCY_ORDER[a.status] ?? 99;
|
||||
const ub = URGENCY_ORDER[b.status] ?? 99;
|
||||
// Rank on the reconciled status (same source the overdue filter uses),
|
||||
// so a bill that's paid-by-threshold but still carries a stale raw
|
||||
// 'late'/'missed' status sorts to the bottom instead of being pinned up.
|
||||
const ua = URGENCY_ORDER[rowEffectiveStatus(a)] ?? 99;
|
||||
const ub = URGENCY_ORDER[rowEffectiveStatus(b)] ?? 99;
|
||||
if (ua !== ub) return ua - ub;
|
||||
return (a.due_day ?? 99) - (b.due_day ?? 99);
|
||||
})
|
||||
|
|
@ -1060,6 +1063,23 @@ export default function TrackerPage() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* ── Filtered-to-empty state — bills exist this month but none match the active filters/search ── */}
|
||||
{!isError && !loading && rows.length > 0 && first.length === 0 && second.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center py-20 text-center rounded-xl border border-border bg-muted/20">
|
||||
<div className="h-10 w-10 rounded-full bg-muted flex items-center justify-center mb-3">
|
||||
<Search className="h-5 w-5 text-muted-foreground" />
|
||||
</div>
|
||||
<p className="text-sm font-medium text-foreground">No bills match your filters</p>
|
||||
<p className="mt-1 text-xs text-muted-foreground">{rows.length} bill{rows.length === 1 ? '' : 's'} this month are hidden by the current search or filters.</p>
|
||||
{hasFilters && (
|
||||
<Button size="sm" variant="outline" onClick={resetFilters} className="mt-4 gap-1.5 text-xs">
|
||||
<RefreshCw className="h-3 w-3" />
|
||||
Clear filters
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isError && (first.length > 0 || second.length > 0) && (
|
||||
<div className="space-y-5">
|
||||
{first.length > 0 && <Bucket label="1st – 14th" rows={first} year={year} month={month} refresh={invalidateData} onEditBill={handleOpenEditBill} loading={loading} reorderEnabled={reorderEnabled} movingBillId={movingBillId} sortKey={sortKey} sortDir={sortDir} onSort={handleSortHeader} onReorderRows={(next) => handleReorderBucket('1st', next)} driftedIds={driftedIds} visibleColumns={visibleTableColumns} />}
|
||||
|
|
|
|||
Loading…
Reference in New Issue