fix: bank tracking pending deduction corrected, projected month-end balance, settings loading fix

This commit is contained in:
null 2026-06-04 01:36:07 -05:00
parent ccdd16a626
commit 48f5577031
3 changed files with 37 additions and 1 deletions

View File

@ -28,6 +28,12 @@
- **Pin Due — urgent bills float to top of tracker** — A "Pin Due" toggle button in the TrackerPage header sorts overdue and due-soon bills to the top of each bucket when enabled. Priority order: `missed``late``due_soon``upcoming` → everything else; ties broken by `due_day`. The sort runs after filtering but before the bucket split, so each half-month bucket is sorted independently. The button uses `variant="default"` (solid) when active and `variant="outline"` when off so the current mode is always visible. Preference persists across sessions via `localStorage` under `tracker_pin_upcoming`. Drag reorder is automatically disabled while the toggle is on (`reorderEnabled` now also requires `!pinUpcoming`) since the two modes conflict.
- **Bank tracking pending deduction corrected — no double-counting** — The pending payments window was subtracting all recent payments regardless of source, including bank-synced ones (`payment_source = 'provider_sync'`). Since the live bank balance already reflects those outgoing transactions, subtracting them again produced a balance ~$2k lower than reality. Fixed in both `trackerService.js` and `summary.js` by adding `AND (p.payment_source IS NULL OR p.payment_source != 'provider_sync')` to the pending query. Only manually-entered payments and transaction-matched payments are now counted as pending — those are payments the user recorded in the tracker before the bank has seen them. The `pending_cleared` badge on tracker rows was given the same fix. Additionally, `b.name` was missing from the `SELECT` in `getOverdueCount`, causing the tooltip to show `null` names — corrected.
- **Bank tracking: projected month-end balance added** — The CalendarPage Monthly Money Map (bank mode) now shows a dedicated "Projected Month-End Balance" row below the four metrics. It displays the full equation inline — `$5,461 bank $1,737 pending $3,696 remaining bills` — so the source of the number is always visible. The row uses a green/red border depending on whether the projection is positive or negative. The TrackerPage Starting card hint also updated from `account_name · live balance` to `account_name · projected $X after bills` so the projection is visible without navigating to Calendar.
- **Bank tracking settings and account picker fixed** — The `loadBankTracking` function in `BankSyncSection` called `api.getSettings()` but the API method is `api.settings()`. The wrong name threw `TypeError: api.getSettings is not a function`, silently caught by the outer `catch {}`, so neither the toggle state nor the account list ever loaded. Renamed to `api.settings()`. All 19 financial accounts now appear in the picker and the enabled/account/pending-days settings persist correctly across page loads.
- **Overdue badge: "due today" no longer counts as overdue + tooltip added**`getOverdueCount` changed `dueDate > todayStr` to `dueDate >= todayStr` so bills due today are not counted as past due — only bills strictly in the past trigger the badge. The function now also returns `names: [...]` alongside the count. Both the sidebar `TrackerMenu` (desktop) and `NavPill` (mobile) wrap the badge in a `<Tooltip>` that shows "2 past due · Discord Nitro · Camry" on hover, so the number is immediately explained without navigating anywhere. Up to 5 names are shown with a "+N more" overflow line.
- **Column labels larger and lighter in tracker table**`TableHead` elements in `TrackerBucket` changed from `text-[10px] font-semibold tracking-widest` to `text-xs font-medium tracking-wider`. Size increased from 10 px to 12 px for readability; weight dropped from semibold to medium so the labels don't visually compete with the bold bill name text in each row.

View File

@ -168,6 +168,32 @@ function MoneyMap({ summaryData, loading }) {
</div>
)}
{bankMode && (
<div className={cn(
'flex items-center justify-between gap-3 rounded-xl border px-4 py-3',
Number(bt.remaining || 0) >= 0
? 'border-emerald-500/25 bg-emerald-500/5'
: 'border-destructive/25 bg-destructive/5',
)}>
<div className="space-y-0.5">
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
Projected Month-End Balance
</p>
<p className="text-[11px] text-muted-foreground/70">
{fmt(bt.balance || 0)} bank
{Number(bt.pending_payments || 0) > 0 && ` ${fmt(bt.pending_payments)} pending`}
{` ${fmt(bt.unpaid_this_month || 0)} remaining bills`}
</p>
</div>
<p className={cn(
'tracker-number text-2xl font-bold tabular-nums shrink-0',
Number(bt.remaining || 0) >= 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-destructive',
)}>
{Number(bt.remaining || 0) < 0 ? '' : ''}{fmt(Math.abs(Number(bt.remaining || 0)))}
</p>
</div>
)}
{bankMode && bt.last_updated && (
<p className="text-xs text-muted-foreground">
Balance last updated: {new Date(bt.last_updated).toLocaleString()}

View File

@ -489,7 +489,11 @@ export default function TrackerPage() {
type="starting"
value={summary.total_starting}
hint={(() => {
if (bankTracking?.enabled) return `${bankTracking.account_name} · live balance`;
if (bankTracking?.enabled) {
const proj = Number(bankTracking.remaining ?? 0);
const sign = proj < 0 ? '' : '';
return `${bankTracking.account_name} · projected ${sign}${fmt(Math.abs(proj))} after bills`;
}
if (!summary.has_starting_amounts) return 'Set monthly starting cash';
if (cashflow?.has_data && cashflow.period_projected !== undefined) {
const proj = Number(cashflow.period_projected);