From e7a278561f0412c776fc4682d89ee60b87829f82 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:04:22 +0000 Subject: [PATCH 1/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routeTree.gen.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 2c230ca..94db69b 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -1046,12 +1046,3 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() - -import type { getRouter } from './router.tsx' -import type { createStart } from '@tanstack/react-start' -declare module '@tanstack/react-start' { - interface Register { - ssr: true - router: Awaited> - } -} From bf7b631c1fce4289660b93c16152c56711b7738d Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:04:30 +0000 Subject: [PATCH 2/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 79c5630..1dcf0ff 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -67,6 +67,9 @@ function InvoicesIndex() { const [selectedExp, setSelectedExp] = useState>(new Set()); const [selectedInvoices, setSelectedInvoices] = useState>(new Set()); const [working, setWorking] = useState(false); + const [timePage, setTimePage] = useState(0); + const [expPage, setExpPage] = useState(0); + const TAB_PAGE_SIZE = 200; // Map of placeholder invoice id -> true (placeholder = MARKED-INVOICED-* or IMPORT-PREBILLED-*) const [placeholderIds, setPlaceholderIds] = useState>(new Set()); From 475595647dd3adf0030e3be40dc1c2825703d2c4 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:04:41 +0000 Subject: [PATCH 3/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 1dcf0ff..882cd5c 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -210,6 +210,21 @@ function InvoicesIndex() { [visibleExp], ); + // Reset to page 0 when filter or underlying data changes + useEffect(() => { setTimePage(0); }, [timeFilter, time.length]); + useEffect(() => { setExpPage(0); }, [expFilter, expenses.length]); + + const timeTotalPages = Math.max(1, Math.ceil(visibleTime.length / TAB_PAGE_SIZE)); + const expTotalPages = Math.max(1, Math.ceil(visibleExp.length / TAB_PAGE_SIZE)); + const pagedTime = useMemo( + () => visibleTime.slice(timePage * TAB_PAGE_SIZE, (timePage + 1) * TAB_PAGE_SIZE), + [visibleTime, timePage], + ); + const pagedExp = useMemo( + () => visibleExp.slice(expPage * TAB_PAGE_SIZE, (expPage + 1) * TAB_PAGE_SIZE), + [visibleExp, expPage], + ); + const toggleSel = (set: Set, id: string) => { const next = new Set(set); if (next.has(id)) next.delete(id); else next.add(id); From 5544a43da17b08e5a6428100d5e5642300a60d30 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:04:50 +0000 Subject: [PATCH 4/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 882cd5c..695aca0 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -473,8 +473,13 @@ function InvoicesIndex() { 0 && selectedTime.size === visibleTime.length} - onCheckedChange={(c) => setSelectedTime(c ? new Set(visibleTime.map((t) => t.id)) : new Set())} + checked={pagedTime.length > 0 && pagedTime.every((t) => selectedTime.has(t.id))} + onCheckedChange={(c) => setSelectedTime((prev) => { + const next = new Set(prev); + if (c) pagedTime.forEach((t) => next.add(t.id)); + else pagedTime.forEach((t) => next.delete(t.id)); + return next; + })} /> Date From c025689b26a3f67031b399c9df26c27ac84b3a2d Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:05:21 +0000 Subject: [PATCH 5/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 695aca0..960b28c 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -500,7 +500,7 @@ function InvoicesIndex() { No matching time entries. )} - {visibleTime.map((t) => { + {pagedTime.map((t) => { const amount = Number(t.hours) * Number(t.hourly_rate); const marked = isPlaceholder(t.invoice_id); return ( @@ -545,6 +545,18 @@ function InvoicesIndex() { + {visibleTime.length > TAB_PAGE_SIZE && ( +
+ + Showing {timePage * TAB_PAGE_SIZE + 1}–{Math.min((timePage + 1) * TAB_PAGE_SIZE, visibleTime.length)} of {visibleTime.length} + +
+ + Page {timePage + 1} of {timeTotalPages} + +
+
+ )} From 6bea44ae14fda1957c9f0c0a77494e09f5ff183a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:05:33 +0000 Subject: [PATCH 6/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 960b28c..30f3653 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -579,8 +579,13 @@ function InvoicesIndex() { 0 && selectedExp.size === visibleExp.length} - onCheckedChange={(c) => setSelectedExp(c ? new Set(visibleExp.map((e) => e.id)) : new Set())} + checked={pagedExp.length > 0 && pagedExp.every((e) => selectedExp.has(e.id))} + onCheckedChange={(c) => setSelectedExp((prev) => { + const next = new Set(prev); + if (c) pagedExp.forEach((e) => next.add(e.id)); + else pagedExp.forEach((e) => next.delete(e.id)); + return next; + })} /> Date From 64cff0f33b68bfa6168337f7df0060e632265a47 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:05:48 +0000 Subject: [PATCH 7/7] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 30f3653..95d3718 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -604,7 +604,7 @@ function InvoicesIndex() { No matching expenses. )} - {visibleExp.map((e) => { + {pagedExp.map((e) => { const marked = isPlaceholder(e.invoice_id); return ( @@ -646,6 +646,18 @@ function InvoicesIndex() { + {visibleExp.length > TAB_PAGE_SIZE && ( +
+ + Showing {expPage * TAB_PAGE_SIZE + 1}–{Math.min((expPage + 1) * TAB_PAGE_SIZE, visibleExp.length)} of {visibleExp.length} + +
+ + Page {expPage + 1} of {expTotalPages} + +
+
+ )}