Files
firefly-ui/src/lib/subscriptions/queries.ts
T
hh 9c15b81409 fix(subscriptions): a payment made around a past due date counts as paid, runway refetches on focus
A bill paid a day before its due date showed as overdue in the runway
because past due dates were never matched against payments; now any
payment within a third of the cycle around the date settles it. The
runway's bills and payments refetch when the tab gets focus, so entries
the bot made meanwhile show up.
2026-10-18 17:02:12 +00:00

49 lines
1.6 KiB
TypeScript

import { api } from "#lib/api/client.js";
import { all } from "#lib/api/lists.js";
import type { Bill, Item, Page, TransactionGroup } from "#lib/api/types.js";
import { addDays } from "#lib/dates.js";
import { toPayments } from "./runway.js";
const SEARCH_LIMIT = 500;
const UNLINKED_DAYS = 92;
async function search(query: string): Promise<Item<TransactionGroup>[]> {
const read = (page: number) =>
api<Page<TransactionGroup>>("/v1/search/transactions", {
query: { limit: SEARCH_LIMIT, page, query },
});
const first = await read(1);
const pages = first.meta.pagination?.total_pages ?? 1;
const rest = await Promise.all(
Array.from({ length: Math.max(0, pages - 1) }, (_, i) => read(i + 2))
);
const seen = new Map<string, Item<TransactionGroup>>();
for (const group of [first, ...rest].flatMap((page) => page.data)) {
seen.set(group.id, group);
}
return [...seen.values()];
}
export const runwayQueries = {
bills: (start: string, end: string) => ({
queryFn: () => all<Bill>("/v1/bills", { end, start }),
queryKey: ["subscriptions", "runway", start, end],
refetchOnWindowFocus: true,
}),
paid: () => ({
queryFn: async () => toPayments(await search("has_any_bill:true")),
queryKey: ["subscriptions", "payments"],
refetchOnWindowFocus: true,
}),
unlinked: (day: string) => {
const after = addDays(day, -UNLINKED_DAYS);
return {
queryFn: async () =>
toPayments(
await search(`has_no_bill:true type:withdrawal date_after:${after}`)
).filter((payment) => !payment.billId),
queryKey: ["subscriptions", "unlinked", after],
};
},
};