Skip to content

Commit 12b3ffb

Browse files
authored
Merge pull request #109 from pitzzahh/patch/table-date-filter
fix: history data table date filter
2 parents 380107f + 63d471b commit 12b3ffb

File tree

7 files changed

+368
-242
lines changed

7 files changed

+368
-242
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
},
4848
"devDependencies": {
4949
"@lucide/svelte": "^0.575.0",
50-
"@number-flow/svelte": "^0.3.11",
50+
"@number-flow/svelte": "^0.3.13",
5151
"@prettier/plugin-oxc": "^0.1.3",
5252
"@svelte-put/qr": "^2.1.1",
5353
"@sveltejs/adapter-node": "^5.5.3",
@@ -67,12 +67,12 @@
6767
"drizzle-kit": "^1.0.0-beta.15-859cf75",
6868
"drizzle-orm": "^1.0.0-beta.15-859cf75",
6969
"layerchart": "2.0.0-next.46",
70-
"oxlint": "^1.49.0",
70+
"oxlint": "^1.50.0",
7171
"phosphor-svelte": "^3.1.0",
7272
"prettier": "^3.8.1",
7373
"prettier-plugin-svelte": "^3.5.0",
7474
"prettier-plugin-tailwindcss": "^0.7.2",
75-
"svelte": "^5.53.2",
75+
"svelte": "^5.53.3",
7676
"svelte-check": "^4.4.3",
7777
"svelte-render-scan": "^1.1.0",
7878
"svelte-sonner": "^1.0.7",

pnpm-lock.yaml

Lines changed: 189 additions & 189 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/utils/format.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,28 @@ export const parseCalendarDate = (dateStr: string): Date => {
3131
};
3232

3333
export const formatDate = (
34-
date: Date,
34+
dateInput: Date | string | number,
3535
options: { format?: DateFormat; locale?: string } = {}
3636
): string => {
3737
const { format = DateFormat.DateOnly, locale = "en-PH" } = options;
3838

39+
// Normalize input into a Date instance.
40+
let date: Date;
41+
if (typeof dateInput === "string") {
42+
// If it's a calendar date string YYYY-MM-DD, parse as UTC to avoid TZ shifts.
43+
if (/^\d{4}-\d{2}-\d{2}$/.test(dateInput)) {
44+
date = parseCalendarDate(dateInput);
45+
} else {
46+
date = new Date(dateInput);
47+
}
48+
} else {
49+
// number (ms since epoch) or Date
50+
date = new Date(dateInput as any);
51+
}
52+
53+
// If invalid date, return empty string so callers don't throw.
54+
if (Number.isNaN(date.getTime())) return "";
55+
3956
let intlOptions: Intl.DateTimeFormatOptions;
4057

4158
switch (format) {

src/lib/utils/mapper/billing-info.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,9 @@ export function billingInfoToTableView(original: BillingInfo): BillingInfoTableV
4141
export function extendedBillingInfoToTableView(
4242
original: ExtendedBillingInfo
4343
): ExtendedBillingInfoTableView {
44-
// Extract calendar date components and store as YYYY-MM-DD string
45-
const dateObj = new Date(original.date);
46-
const year = dateObj.getFullYear();
47-
const month = String(dateObj.getMonth() + 1).padStart(2, "0");
48-
const day = String(dateObj.getDate()).padStart(2, "0");
49-
5044
return {
5145
...original,
52-
date: `${year}-${month}-${day}`,
46+
date: formatDate(original.date),
5347
createdAt: formatDate(new Date(original.createdAt), {
5448
format: DateFormat.DateTime,
5549
}),

src/routes/(components)/landing-footer.svelte

Lines changed: 149 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,149 @@
55
</script>
66

77
<script lang="ts">
8+
import { gsap } from "gsap";
89
import Logo from "$/components/logo.svelte";
910
import { site } from "$/site";
1011
import { ChartLine, Users, Shield, Download } from "$lib/assets/icons";
1112
import { LANDING_NAV_ITEMS, handleLandingNavClick } from ".";
1213
1314
let { user }: LandingFooterProps = $props();
15+
16+
// ─── Canvas grid drawing ───────────────────────────────────────────────────
17+
function initCanvas(canvas: HTMLCanvasElement) {
18+
const ctx = canvas.getContext("2d")!;
19+
let animId: number;
20+
let t = 0;
21+
22+
function resize() {
23+
canvas.width = canvas.offsetWidth;
24+
canvas.height = canvas.offsetHeight;
25+
}
26+
27+
function drawGrid() {
28+
const { width, height } = canvas;
29+
ctx.clearRect(0, 0, width, height);
30+
31+
const cols = 24;
32+
const rows = 10;
33+
const cellW = width / cols;
34+
const cellH = height / rows;
35+
36+
for (let r = 0; r <= rows; r++) {
37+
for (let c = 0; c <= cols; c++) {
38+
const x = c * cellW;
39+
const y = r * cellH;
40+
41+
const wave = Math.sin(t * 0.04 + c * 0.4 + r * 0.6) * 0.5 + 0.5;
42+
const alpha = wave * 0.35 + 0.05;
43+
44+
ctx.beginPath();
45+
ctx.arc(x, y, 1.2, 0, Math.PI * 2);
46+
ctx.fillStyle = `rgba(56, 189, 248, ${alpha})`;
47+
ctx.fill();
48+
49+
if (c < cols) {
50+
const lineAlpha = wave * 0.12 + 0.03;
51+
ctx.beginPath();
52+
ctx.moveTo(x, y);
53+
ctx.lineTo(x + cellW, y);
54+
ctx.strokeStyle = `rgba(56, 189, 248, ${lineAlpha})`;
55+
ctx.lineWidth = 0.5;
56+
ctx.stroke();
57+
}
58+
59+
if (r < rows) {
60+
const lineAlpha = wave * 0.12 + 0.03;
61+
ctx.beginPath();
62+
ctx.moveTo(x, y);
63+
ctx.lineTo(x, y + cellH);
64+
ctx.strokeStyle = `rgba(56, 189, 248, ${lineAlpha})`;
65+
ctx.lineWidth = 0.5;
66+
ctx.stroke();
67+
}
68+
}
69+
}
70+
71+
if (Math.random() < 0.04) {
72+
const sx = Math.floor(Math.random() * (cols + 1)) * cellW;
73+
const sy = Math.floor(Math.random() * (rows + 1)) * cellH;
74+
const sparkAlpha = 0.6 + Math.random() * 0.4;
75+
ctx.beginPath();
76+
ctx.arc(sx, sy, 2.5 + Math.random() * 2, 0, Math.PI * 2);
77+
ctx.fillStyle = `rgba(186, 230, 253, ${sparkAlpha})`;
78+
ctx.shadowBlur = 8;
79+
ctx.shadowColor = "rgba(56, 189, 248, 0.8)";
80+
ctx.fill();
81+
ctx.shadowBlur = 0;
82+
}
83+
84+
t++;
85+
animId = requestAnimationFrame(drawGrid);
86+
}
87+
88+
const ro = new ResizeObserver(() => resize());
89+
ro.observe(canvas);
90+
resize();
91+
drawGrid();
92+
93+
return () => {
94+
cancelAnimationFrame(animId);
95+
ro.disconnect();
96+
};
97+
}
98+
99+
// ─── GSAP entrance animations ─────────────────────────────────────────────
100+
function initAnimations(footer: HTMLElement) {
101+
gsap.fromTo(
102+
footer.querySelectorAll(".footer-col"),
103+
{ opacity: 0, y: 24 },
104+
{ opacity: 1, y: 0, duration: 0.6, stagger: 0.1, ease: "power3.out", delay: 0.1 }
105+
);
106+
107+
gsap.fromTo(
108+
footer.querySelectorAll(".footer-bottom > *"),
109+
{ opacity: 0, y: 12 },
110+
{ opacity: 1, y: 0, duration: 0.5, stagger: 0.08, ease: "power2.out", delay: 0.5 }
111+
);
112+
}
113+
114+
// ─── attach action ─────────────────────────────────────────────────────────
115+
function footerAttach(footer: HTMLElement) {
116+
const canvas = footer.querySelector<HTMLCanvasElement>("canvas.grid-canvas")!;
117+
const cleanupCanvas = initCanvas(canvas);
118+
initAnimations(footer);
119+
return { destroy: cleanupCanvas };
120+
}
14121
</script>
15122

16-
<footer class="relative z-10 border-t border-border/50 bg-muted/30 py-16">
17-
<div class="container mx-auto px-4">
123+
<footer use:footerAttach class="relative z-10 overflow-hidden border-t border-border bg-background">
124+
<!-- Electric grid canvas background -->
125+
<canvas class="grid-canvas pointer-events-none absolute inset-0 h-full w-full" aria-hidden="true"
126+
></canvas>
127+
128+
<div class="relative z-10 container mx-auto px-4 py-16">
18129
<div class="grid gap-12 md:grid-cols-2 lg:grid-cols-4">
19130
<!-- Brand Column -->
20-
<div class="space-y-4">
131+
<div class="footer-col space-y-4">
21132
<Logo variant="ghost" class="px-0 md:pl-0!" viewTransitionName="logo-footer" />
22-
<p class="text-sm text-muted-foreground">
133+
<p class="text-sm leading-relaxed text-muted-foreground">
23134
{site.description}
24135
</p>
25-
<p class="text-sm text-muted-foreground">
136+
<p class="text-sm leading-relaxed text-muted-foreground">
26137
Software-focused tracking and billing for practical expense allocation.
27138
</p>
28139
</div>
29140

30141
<!-- Navigation Links -->
31-
<div class="space-y-4">
32-
<h3 class="text-sm font-semibold tracking-wider text-foreground uppercase">Navigation</h3>
142+
<div class="footer-col space-y-4">
143+
<h3 class="text-sm font-semibold">Navigation</h3>
33144
<ul class="space-y-3">
34145
{#each LANDING_NAV_ITEMS as item}
35146
<li>
36147
<a
37148
href={item.href}
38149
onclick={(e) => handleLandingNavClick(e, item.href)}
39-
class="text-sm text-muted-foreground transition-colors hover:text-primary"
150+
class="text-sm text-muted-foreground transition-colors hover:text-foreground"
40151
>
41152
{item.label}
42153
</a>
@@ -45,70 +156,70 @@
45156
</ul>
46157
</div>
47158

48-
<!-- Features Highlight -->
49-
<div class="space-y-4">
50-
<h3 class="text-sm font-semibold tracking-wider text-foreground uppercase">Features</h3>
159+
<!-- Features -->
160+
<div class="footer-col space-y-4">
161+
<h3 class="text-sm font-semibold">Features</h3>
51162
<ul class="space-y-3">
52163
<li class="flex items-center gap-2 text-sm text-muted-foreground">
53-
<ChartLine class="h-4 w-4 text-primary" />
164+
<ChartLine class="h-4 w-4 shrink-0" />
54165
<span>Billing Summaries</span>
55166
</li>
56167
<li class="flex items-center gap-2 text-sm text-muted-foreground">
57-
<Users class="h-4 w-4 text-primary" />
168+
<Users class="h-4 w-4 shrink-0" />
58169
<span>User Accounts</span>
59170
</li>
60171
<li class="flex items-center gap-2 text-sm text-muted-foreground">
61-
<Shield class="h-4 w-4 text-primary" />
172+
<Shield class="h-4 w-4 shrink-0" />
62173
<span>Input Validation</span>
63174
</li>
64175
<li class="flex items-center gap-2 text-sm text-muted-foreground">
65-
<Download class="h-4 w-4 text-primary" />
66-
<span>Import & Export</span>
176+
<Download class="h-4 w-4 shrink-0" />
177+
<span>Import &amp; Export</span>
67178
</li>
68179
</ul>
69180
</div>
70181

71182
<!-- Use Cases -->
72-
<div class="space-y-4">
73-
<h3 class="text-sm font-semibold tracking-wider text-foreground uppercase">Built For</h3>
183+
<div class="footer-col space-y-4">
184+
<h3 class="text-sm font-semibold">Built For</h3>
74185
<ul class="space-y-3">
75-
<li class="text-sm text-muted-foreground">Multi-Tenant Buildings</li>
76-
<li class="text-sm text-muted-foreground">Homeowners with Rentals</li>
77-
<li class="text-sm text-muted-foreground">Property Managers</li>
186+
{#each ["Multi-Tenant Buildings", "Homeowners with Rentals", "Property Managers"] as item}
187+
<li class="text-sm text-muted-foreground">{item}</li>
188+
{/each}
78189
</ul>
79190
</div>
80191
</div>
81192

82-
<!-- Divider -->
83-
<div class="my-10 h-px bg-border/50"></div>
193+
<div class="my-10 border-t border-border"></div>
84194

85195
<!-- Bottom Row -->
86-
<div class="flex flex-col items-center justify-between gap-4 md:flex-row">
87-
<p class="text-sm text-muted-foreground">
196+
<div class="footer-bottom flex flex-col items-center justify-between gap-4 md:flex-row">
197+
<p class="text-xs text-muted-foreground">
88198
&copy; {new Date().getFullYear()}
89-
{site.name}. All rights reserved.
199+
<span class="font-medium text-foreground">{site.name}</span>. All rights reserved.
90200
</p>
201+
91202
<div class="flex items-center gap-6">
92203
{#if user}
93204
<a
94205
data-sveltekit-reload
95206
href="/dashboard"
96-
class="text-sm text-muted-foreground transition-colors hover:text-primary"
207+
class="text-xs text-muted-foreground transition-colors hover:text-foreground"
97208
>
98-
Go to Dashboard
209+
Dashboard
99210
</a>
100211
{:else}
101212
<a
102213
data-sveltekit-reload
103214
href="/auth?act=login"
104-
class="text-sm text-muted-foreground transition-colors hover:text-primary"
215+
class="text-xs text-muted-foreground transition-colors hover:text-foreground"
105216
>
106217
Sign In
107218
</a>
108219
<a
109220
data-sveltekit-reload
110221
href="/auth?act=register"
111-
class="text-sm text-muted-foreground transition-colors hover:text-primary"
222+
class="text-xs text-muted-foreground transition-colors hover:text-foreground"
112223
>
113224
Get Started
114225
</a>
@@ -117,3 +228,11 @@
117228
</div>
118229
</div>
119230
</footer>
231+
232+
<style>
233+
/* GSAP animates these in — start hidden */
234+
.footer-col,
235+
.footer-bottom > * {
236+
opacity: 0;
237+
}
238+
</style>

src/routes/history/(components)/history-data-table-row-actions.svelte

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import { Loader, Trash2, View, Pencil, Ticket } from "$/assets/icons";
1616
import { Table, TableBody, TableCell, TableRow } from "$lib/components/ui/table";
1717
import { BillingInfoForm, SubPaymentsButton } from ".";
18-
import { formatDate, formatNumber, parseCalendarDate } from "$/utils/format";
18+
import { formatNumber } from "$/utils/format";
1919
import type { Row } from "@tanstack/table-core";
2020
import Button from "$/components/ui/button/button.svelte";
2121
import * as Dialog from "$/components/ui/dialog";
@@ -57,7 +57,7 @@
5757
},
5858
{
5959
label: "Date",
60-
value: formatDate(parseCalendarDate(row.original.date)),
60+
value: row.original.date,
6161
class: "font-mono",
6262
},
6363
{
@@ -88,7 +88,7 @@
8888
]);
8989
9090
async function handle_remove_billing_info() {
91-
if (delete_confirm_value !== formatDate(parseCalendarDate(row.original.date))) {
91+
if (delete_confirm_value !== row.original.date) {
9292
return showInspectorWarning();
9393
}
9494
app_state = "processing";
@@ -167,9 +167,7 @@
167167
</Dialog.Title>
168168
<Dialog.Description class="mt-2 text-lg text-muted-foreground">
169169
Comprehensive billing information for
170-
<span class="font-mono text-primary"
171-
>{formatDate(parseCalendarDate(row.original.date))}</span
172-
>
170+
<span class="font-mono text-primary">{row.original.date}</span>
173171
</Dialog.Description>
174172
</Dialog.Header>
175173
<ScrollArea class="max-h-[60vh] pr-2.5">
@@ -208,7 +206,7 @@
208206
{/if}
209207

210208
{#if active_dialog_content === "remove"}
211-
{@const currentDate = formatDate(parseCalendarDate(row.original.date))}
209+
{@const currentDate = row.original.date}
212210
<Dialog.Content>
213211
<Dialog.Header>
214212
<Dialog.Title>Remove Billing Info Record</Dialog.Title>
@@ -259,9 +257,7 @@
259257
<Sheet.Portal>
260258
<Sheet.Content class="w-full gap-1 md:min-w-[60%]" side="left">
261259
<Sheet.Header class="border-b">
262-
<Sheet.Title
263-
>Edit billing info of {formatDate(parseCalendarDate(row.original.date))}</Sheet.Title
264-
>
260+
<Sheet.Title>Edit billing info of {row.original.date}</Sheet.Title>
265261
<Sheet.Description>
266262
Update the billing info details for billing info with id
267263
<span class="font-mono text-primary">

0 commit comments

Comments
 (0)