Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-04-19 19:51:12 +00:00
co-authored by renee-png
parent a155a40c0d
commit 70060af4bf
+49 -17
View File
@@ -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<T>(
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<any>((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<any>((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(); }, []);