From 70060af4bf696a523e3f20c60a7efe3f7fc1d401 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 19:51:12 +0000 Subject: [PATCH 1/3] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 66 ++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 03238a7..2bf6e92 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -27,6 +27,26 @@ export const Route = createFileRoute("/invoices/")({ type UnbilledStatus = "unbilled" | "marked" | "all"; const PAGE_SIZE = 100; +const UNBILLED_PAGE_SIZE = 1000; + +async function fetchAllPages( + loader: (from: number, to: number) => Promise<{ data: T[] | null; error: { message: string } | null }>, +) { + const rows: T[] = []; + let from = 0; + + while (true) { + const to = from + UNBILLED_PAGE_SIZE - 1; + const { data, error } = await loader(from, to); + if (error) throw new Error(error.message); + const batch = data ?? []; + rows.push(...batch); + if (batch.length < UNBILLED_PAGE_SIZE) break; + from += UNBILLED_PAGE_SIZE; + } + + return rows; +} function InvoicesIndex() { const navigate = useNavigate(); @@ -94,23 +114,35 @@ function InvoicesIndex() { }, [q]); const loadUnbilled = async () => { - const [{ data: t }, { data: e }] = await Promise.all([ - supabase - .from("time_entries") - .select("id, work_date, description, hours, hourly_rate, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!time_entries_user_id_fkey(id, full_name, email)") - .eq("billable", true) - .order("work_date", { ascending: false }) - .limit(2000), - supabase - .from("expenses") - .select("id, expense_date, description, amount, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!expenses_user_id_fkey(id, full_name, email)") - .eq("billable", true) - .order("expense_date", { ascending: false }) - .limit(2000), - ]); - setTime(t ?? []); - setExpenses(e ?? []); - setTabsLoaded(true); + try { + setTabsLoaded(false); + const [t, e] = await Promise.all([ + fetchAllPages((from, to) => + supabase + .from("time_entries") + .select("id, work_date, description, hours, hourly_rate, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!time_entries_user_id_fkey(id, full_name, email)") + .eq("billable", true) + .order("work_date", { ascending: false }) + .range(from, to), + ), + fetchAllPages((from, to) => + supabase + .from("expenses") + .select("id, expense_date, description, amount, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!expenses_user_id_fkey(id, full_name, email)") + .eq("billable", true) + .order("expense_date", { ascending: false }) + .range(from, to), + ), + ]); + setTime(t); + setExpenses(e); + } catch (error: any) { + toast.error(error?.message ?? "Could not load unbilled items"); + setTime([]); + setExpenses([]); + } finally { + setTabsLoaded(true); + } }; useEffect(() => { loadUnbilled(); }, []); From 59186b2b217b6d2e8199ec4d7803f7974ecfdd13 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 19:51:44 +0000 Subject: [PATCH 2/3] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/invoices.index.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/routes/invoices.index.tsx b/src/routes/invoices.index.tsx index 2bf6e92..de93113 100644 --- a/src/routes/invoices.index.tsx +++ b/src/routes/invoices.index.tsx @@ -117,22 +117,24 @@ function InvoicesIndex() { try { setTabsLoaded(false); const [t, e] = await Promise.all([ - fetchAllPages((from, to) => - supabase + fetchAllPages(async (from, to) => { + const result = await supabase .from("time_entries") .select("id, work_date, description, hours, hourly_rate, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!time_entries_user_id_fkey(id, full_name, email)") .eq("billable", true) .order("work_date", { ascending: false }) - .range(from, to), - ), - fetchAllPages((from, to) => - supabase + .range(from, to); + return { data: result.data, error: result.error ? { message: result.error.message } : null }; + }), + fetchAllPages(async (from, to) => { + const result = await supabase .from("expenses") .select("id, expense_date, description, amount, billable, user_id, invoice_id, case_id, case:cases(id, case_number, title, client_id, client:clients(id, name)), profile:profiles!expenses_user_id_fkey(id, full_name, email)") .eq("billable", true) .order("expense_date", { ascending: false }) - .range(from, to), - ), + .range(from, to); + return { data: result.data, error: result.error ? { message: result.error.message } : null }; + }), ]); setTime(t); setExpenses(e); From 8f4b7a72332a4e7d321becae0646ee4dd8931871 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 19:52:44 +0000 Subject: [PATCH 3/3] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routeTree.gen.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 94db69b..2c230ca 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -1046,3 +1046,12 @@ 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> + } +}