Compare commits

...
Author SHA1 Message Date
renovate Bot f2e7444d88 chore(frontend): update template to v0.8.0, conflicts left 2026-10-20 05:00:35 +00:00
hh 65d83ddec7 fix(period): [ and ] after month or year to date step by whole months or years
Month to date went back to 13-30 Sept because a partial range was moved
by its length; a range that starts a month, quarter, half or year now
steps by that unit.
2026-10-18 17:26:58 +00:00
hh 54a51752ac fix(subscriptions): card and never-paid wait for the payments instead of guessing while they load 2026-10-18 17:19:43 +00:00
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
7 changed files with 32 additions and 18 deletions

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
_commit: v0.7.0
_commit: v0.8.0
_src_path: https://git.kotikot.com/templates/frontend-svelte.git
install_deps: true
layout: root
+4 -5
View File
@@ -7,20 +7,19 @@
"!.svelte-kit",
"!build",
"!.mcp.json",
<<<<<<< before updating
"!.impeccable",
"!src/lib/components/ui",
"!src/routes/claddcn.css",
"!!src/lib/api/schema.d.ts",
"!api"
=======
"!src/lib/components/ui"
>>>>>>> after updating
]
},
"javascript": { "globals": ["Bun"] },
"overrides": [
{
"includes": ["src/lib/components/ui/**"],
"linter": { "enabled": false },
"assist": { "enabled": false }
},
{
"includes": ["src/lib/utils.ts"],
"linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } }
+4
View File
@@ -40,9 +40,13 @@
"d3-scale": "^4.0.2",
"d3-shape": "^3.2.0",
"mode-watcher": "^1.1.0",
<<<<<<< before updating
"openapi-fetch": "^0.17.0",
"openapi-typescript": "^7.13.0",
"shadcn-svelte": "^1.3.0",
=======
"shadcn-svelte": "^1.7.0",
>>>>>>> after updating
"svelte": "^5.57.1",
"svelte-check": "^4.7.6",
"svelte-sonner": "^1.1.0",
+16 -5
View File
@@ -118,12 +118,23 @@ export function periodOf(value: string, view: ViewRange): Range {
}
}
const UNITS: ViewRange[] = ["1M", "3M", "6M", "1Y"];
function unitOf(range: Range, view: ViewRange): ViewRange | null {
const units = isDynamic(view) ? UNITS : [view, ...UNITS];
return (
units.find((unit) => {
const aligned = periodOf(range.start, unit);
return aligned.start === range.start && range.end <= aligned.end;
}) ?? null
);
}
export function shiftPeriod(range: Range, view: ViewRange, dir: 1 | -1): Range {
const fixed = isDynamic(view) ? "1M" : view;
const aligned = periodOf(range.start, fixed);
if (aligned.start === range.start && aligned.end === range.end) {
const anchor = dir === 1 ? addDays(range.end, 1) : addDays(range.start, -1);
return periodOf(anchor, fixed);
const unit = unitOf(range, view);
if (unit) {
const anchor = dir === 1 ? periodOf(range.start, unit).end : range.start;
return periodOf(addDays(anchor, dir), unit);
}
const days = daysBetween(range.start, range.end) + 1;
return {
+2
View File
@@ -28,10 +28,12 @@ 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);
+1 -5
View File
@@ -208,11 +208,7 @@ function occurrences(bill: Bill, day: string) {
return (bill.pay_dates ?? [])
.map((raw) => raw.slice(0, 10))
.filter((date) => !end || date <= end)
.filter(
(date) =>
date < day ||
!paid.some((p) => p <= date && daysBetween(p, date) < early)
)
.filter((date) => !paid.some((p) => Math.abs(daysBetween(p, date)) < early))
.map((date) => ({ date: date < day ? day : date, overdue: date < day }));
}
+4 -2
View File
@@ -491,7 +491,9 @@
{@const ends = bill.end_date?.slice(0, 10)}
{@const last = lastOf(item)}
{@const who = payer(item)}
{@const stale = staleSince(bill, last, day)}
{@const stale = paid.isSuccess
? staleSince(bill, last, day)
: null}
{@const extra = found.get(item.id) ?? []}
{@const armedHere = arm.key?.endsWith(`:${item.id}`)}
<tr
@@ -567,7 +569,7 @@
billIds={manualCards.picking.ids}
cards={cardList}
/>
{:else if bill.active}
{:else if bill.active && paid.isSuccess}
{#if who.card}
<span class="text-cladd-fg-soft"
>{who.card.name}</span