diff --git a/app/(dashboard)/transactions/page.tsx b/app/(dashboard)/transactions/page.tsx index 7e38c0f5..21855669 100644 --- a/app/(dashboard)/transactions/page.tsx +++ b/app/(dashboard)/transactions/page.tsx @@ -22,6 +22,7 @@ import BankSyncStatusChip from '@/components/transactions/BankSyncStatusChip' import { ContextPicker, type ContextPickerItem } from '@/components/common/ContextPicker' import { AttnLine } from '@/components/ui/attn-line' import BankSyncNowButton from '@/components/transactions/BankSyncNowButton' +import BankSyncSinceLastVisit from '@/components/transactions/BankSyncSinceLastVisit' import TransactionInboxCard from '@/components/transactions/TransactionInboxCard' import TransactionHistoryList from '@/components/transactions/TransactionHistoryList' import InboxZeroState from '@/components/transactions/InboxZeroState' @@ -2663,6 +2664,7 @@ export default function TransactionsPage() { )} + { + .then(({ count: rowCount, error }) => { if (cancelled) return + // A failed query must not advance the marker: that would silently + // swallow the notification for rows that DID arrive in the window. + if (error) return if (rowCount && rowCount > 0) { setCount(rowCount) } else { diff --git a/extensions/general/enable-banking/components/BankSyncProgressDialog.tsx b/extensions/general/enable-banking/components/BankSyncProgressDialog.tsx index 8c7bded6..4d391752 100644 --- a/extensions/general/enable-banking/components/BankSyncProgressDialog.tsx +++ b/extensions/general/enable-banking/components/BankSyncProgressDialog.tsx @@ -83,6 +83,34 @@ export function BankSyncProgressDialog({ // grace period the user may background the (still-running) sync. const blockClose = state.kind === 'syncing' && !overGrace + // The payoff: once the first sync lands, name the work now waiting so the + // moment points onward instead of stranding the user on the settings panel. + // Same authenticated endpoint the dashboard pane refetches; best-effort. + const [workCounts, setWorkCounts] = useState<{ book: number; matches: number } | null>(null) + useEffect(() => { + if (!open || state.kind !== 'done' || state.summary.imported === 0) { + // A later sync must not inherit the previous run's numbers. + setWorkCounts(null) + return + } + let cancelled = false + fetch('/api/worklist/counts') + .then((res) => (res.ok ? res.json() : null)) + .then((json: { data?: { counts?: Record } } | null) => { + if (cancelled || !json?.data?.counts) return + setWorkCounts({ + book: json.data.counts.book_transaction ?? 0, + matches: json.data.counts.suggested_match ?? 0, + }) + }) + .catch(() => { + // The CTA degrades to a plain link; the numbers are a nicety. + }) + return () => { + cancelled = true + } + }, [open, state]) + return ( + )} {state.kind === 'failed' && ( @@ -162,22 +190,47 @@ export function BankSyncProgressDialog({ )} - + {state.kind === 'done' && state.summary.imported > 0 ? ( + <> + + + + ) : ( + + )} ) } -function DoneBody({ summary }: { summary: SyncProgressSummary }) { +function DoneBody({ + summary, + workCounts, +}: { + summary: SyncProgressSummary + workCounts: { book: number; matches: number } | null +}) { const requestedDays = daysBetween(summary.requested_from) const returnedDays = summary.returned_min_date && summary.returned_max_date @@ -199,6 +252,12 @@ function DoneBody({ summary }: { summary: SyncProgressSummary }) { Datum: {summary.returned_min_date} → {summary.returned_max_date}

)} + {workCounts && workCounts.book > 0 && ( +

+ {workCounts.book} att bokföra + {workCounts.matches > 0 && <> · {workCounts.matches} matchar fakturor} +

+ )}