refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
import { toast } from 'sonner';
|
2026-07-03 15:15:36 -05:00
|
|
|
import { Database, Download, FileSpreadsheet, FileJson, AlertTriangle, CheckCircle2, XCircle, Loader2 } from 'lucide-react';
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
import { Button } from '@/components/ui/button';
|
2026-07-03 15:15:36 -05:00
|
|
|
import { Input } from '@/components/ui/input';
|
|
|
|
|
import { Label } from '@/components/ui/label';
|
|
|
|
|
import { cn } from '@/lib/utils';
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
import { SectionCard } from './dataShared';
|
|
|
|
|
|
2026-07-03 15:15:36 -05:00
|
|
|
// Shared blob download: works whether or not the response sets Content-Disposition
|
|
|
|
|
// (the JSON payments export doesn't), falling back to the given name.
|
|
|
|
|
async function downloadFile(endpoint, fallbackName) {
|
|
|
|
|
const res = await fetch(endpoint, { credentials: 'include' });
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
let data = {};
|
|
|
|
|
try { data = await res.json(); } catch {}
|
|
|
|
|
throw new Error(data.message || data.error || `HTTP ${res.status}`);
|
|
|
|
|
}
|
|
|
|
|
const disposition = res.headers.get('Content-Disposition');
|
|
|
|
|
const match = disposition?.match(/filename="?([^"]+)"?/i);
|
|
|
|
|
const name = match ? match[1] : fallbackName;
|
|
|
|
|
const blob = await res.blob();
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
a.href = url; a.download = name; a.click();
|
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|
}
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
|
|
|
|
|
function ExportCard({ icon: Icon, title, description, filename, endpoint }) {
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const handleDownload = async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
2026-07-03 15:15:36 -05:00
|
|
|
await downloadFile(endpoint, filename);
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
toast.success(`${title} downloaded.`);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
toast.error(err.message || 'Download failed.');
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return (
|
2026-07-03 15:15:36 -05:00
|
|
|
<div className="flex items-start justify-between gap-6 px-6 py-5">
|
|
|
|
|
<div className="flex min-w-0 flex-1 items-start gap-4">
|
|
|
|
|
<div className="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
<Icon className="h-5 w-5 text-primary" />
|
|
|
|
|
</div>
|
2026-07-03 15:15:36 -05:00
|
|
|
<div className="min-w-0 flex-1">
|
|
|
|
|
<p className="mb-0.5 text-sm font-medium">{title}</p>
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
<p className="text-xs text-muted-foreground">{description}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="shrink-0 pt-0.5">
|
2026-07-03 15:15:36 -05:00
|
|
|
<Button size="sm" variant="outline" disabled={loading} onClick={handleDownload}>
|
|
|
|
|
{loading ? <><Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />Downloading…</>
|
|
|
|
|
: <><Download className="mr-1.5 h-3.5 w-3.5" />Download</>}
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:15:36 -05:00
|
|
|
// Filtered payments export: current year by default, or a custom date range, as CSV or JSON.
|
|
|
|
|
function PaymentsExport() {
|
|
|
|
|
const [from, setFrom] = useState('');
|
|
|
|
|
const [to, setTo] = useState('');
|
|
|
|
|
const [format, setFormat] = useState('csv');
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
|
|
|
|
const handle = async () => {
|
|
|
|
|
if ((from && !to) || (!from && to)) { toast.error('Enter both From and To dates, or leave both empty.'); return; }
|
|
|
|
|
if (from && to && from > to) { toast.error('“From” must be on or before “To”.'); return; }
|
|
|
|
|
const params = new URLSearchParams({ format });
|
|
|
|
|
if (from && to) { params.set('from', from); params.set('to', to); }
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
|
|
|
|
await downloadFile(`/api/export?${params.toString()}`, `bills.${format === 'json' ? 'json' : 'csv'}`);
|
|
|
|
|
toast.success('Payments exported.');
|
|
|
|
|
} catch (err) {
|
|
|
|
|
toast.error(err.message || 'Export failed.');
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="px-6 py-5">
|
|
|
|
|
<div className="rounded-lg border border-border/60 bg-muted/25 p-4">
|
|
|
|
|
<p className="text-sm font-medium">Payments export</p>
|
|
|
|
|
<p className="mt-0.5 text-xs text-muted-foreground">Just your payment records — filter by date and choose a format. Leave dates empty for the current year.</p>
|
|
|
|
|
<div className="mt-3 flex flex-wrap items-end gap-3">
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="pe-from" className="text-xs">From</Label>
|
|
|
|
|
<Input id="pe-from" type="date" value={from} onChange={e => setFrom(e.target.value)} className="mt-1 h-9 w-[9.5rem]" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<Label htmlFor="pe-to" className="text-xs">To</Label>
|
|
|
|
|
<Input id="pe-to" type="date" value={to} onChange={e => setTo(e.target.value)} className="mt-1 h-9 w-[9.5rem]" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<span className="block text-xs text-muted-foreground">Format</span>
|
|
|
|
|
<div className="mt-1 inline-flex rounded-lg border border-border/60 p-0.5" role="group" aria-label="Export format">
|
|
|
|
|
{['csv', 'json'].map(f => (
|
|
|
|
|
<button
|
|
|
|
|
key={f}
|
|
|
|
|
type="button"
|
|
|
|
|
aria-pressed={format === f}
|
|
|
|
|
onClick={() => setFormat(f)}
|
|
|
|
|
className={cn('rounded-md px-2.5 py-1 text-xs font-medium transition-colors',
|
|
|
|
|
format === f ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground')}
|
|
|
|
|
>
|
|
|
|
|
{f.toUpperCase()}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<Button size="sm" className="h-9 gap-1.5" disabled={loading} onClick={handle}>
|
|
|
|
|
{loading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Download className="h-3.5 w-3.5" />}
|
|
|
|
|
Export
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-30 21:52:02 -05:00
|
|
|
export default function DownloadMyDataSection({ cardProps = {} }) {
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
return (
|
|
|
|
|
<SectionCard
|
|
|
|
|
title="Download My Data"
|
|
|
|
|
subtitle="Export your bill tracker data for your own records. These exports include only your data — not a full system backup."
|
2026-05-30 21:52:02 -05:00
|
|
|
{...cardProps}
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
>
|
2026-07-03 15:15:36 -05:00
|
|
|
<ExportCard icon={Database} title="SQLite backup"
|
|
|
|
|
description="A portable SQLite database with all of your bill tracker data — the format used to restore a backup."
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
filename="bill-tracker-user-export.sqlite" endpoint="/api/export/user-db" />
|
2026-07-03 15:15:36 -05:00
|
|
|
<ExportCard icon={FileSpreadsheet} title="Excel databook"
|
|
|
|
|
description="An Excel workbook with sheets for bills, payments, categories, monthly state, and summary data."
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
filename="bill-tracker-databook.xlsx" endpoint="/api/export/user-excel" />
|
2026-07-03 15:15:36 -05:00
|
|
|
<ExportCard icon={FileJson} title="JSON export"
|
|
|
|
|
description="Your full data as portable JSON — handy for scripting, backups, or moving between tools."
|
|
|
|
|
filename="bill-tracker-user-export.json" endpoint="/api/export/user-json" />
|
|
|
|
|
<PaymentsExport />
|
|
|
|
|
<div className="mx-6 mt-2 flex items-start gap-2.5 rounded-md border border-amber-200 bg-amber-50 px-6 py-3 dark:border-amber-800/40 dark:bg-amber-950/30">
|
|
|
|
|
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-amber-600 dark:text-amber-400" />
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
<p className="text-xs text-amber-700 dark:text-amber-300">Exports may contain sensitive account metadata (website URLs, usernames, account info). Store exported files securely and avoid sharing them unencrypted.</p>
|
|
|
|
|
</div>
|
2026-07-03 15:15:36 -05:00
|
|
|
<div className="grid grid-cols-1 gap-3 px-6 py-5 sm:grid-cols-2">
|
|
|
|
|
<div className="rounded-lg border border-border/60 bg-muted/40 p-4">
|
|
|
|
|
<p className="mb-2.5 text-[10px] font-bold uppercase tracking-widest text-muted-foreground">What's included</p>
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
<ul className="space-y-1.5">
|
|
|
|
|
{['Bills','Payments','Categories','Monthly bill state','Monthly starting amounts','History ranges','Notes','Export metadata'].map(i => (
|
|
|
|
|
<li key={i} className="flex items-center gap-2 text-xs text-foreground/80">
|
2026-07-03 15:15:36 -05:00
|
|
|
<CheckCircle2 className="h-3.5 w-3.5 shrink-0 text-emerald-500" />{i}
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
2026-07-03 15:15:36 -05:00
|
|
|
<div className="rounded-lg border border-border/60 bg-muted/40 p-4">
|
|
|
|
|
<p className="mb-2.5 text-[10px] font-bold uppercase tracking-widest text-muted-foreground">What's not included</p>
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
<ul className="space-y-1.5">
|
|
|
|
|
{['Passwords','Sessions','Admin settings','Server configuration',"Other users' data",'Full system backup files'].map(i => (
|
|
|
|
|
<li key={i} className="flex items-center gap-2 text-xs text-muted-foreground">
|
2026-07-03 15:15:36 -05:00
|
|
|
<XCircle className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />{i}
|
refactor: component splits, PWA support, CommandPalette
Component Splits:
- AdminPage.jsx: 1,906 -> 82 lines (logic moved to client/components/admin/ — 9 files)
- DataPage.jsx: 3,132 -> 60 lines (logic moved to client/components/data/ — 8 files)
- TrackerPage.jsx: 2,566 -> 2,132 lines (MonthlyStateDialog, StartingAmountsEditDialog, PaymentModal)
PWA:
- vite-plugin-pwa installed with NetworkFirst caching for API routes
- Square PWA icons (192x192, 512x512, apple-touch-icon)
- theme-color, apple meta tags, touch icon in index.html
- Build generates dist/sw.js + Workbox runtime
CommandPalette:
- Navigation commands, Add bill action, month jumps
- Grouped results with empty/filtered states
2026-05-28 20:53:22 -05:00
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</SectionCard>
|
|
|
|
|
);
|
|
|
|
|
}
|