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 from 'react';
|
|
|
|
|
import { RefreshCw, Clock } from 'lucide-react';
|
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
|
import { SectionCard, fmt } from './dataShared';
|
|
|
|
|
|
2026-05-30 21:52:02 -05:00
|
|
|
export default function ImportHistorySection({ history, loading, onRefresh, 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
|
|
|
if (loading) {
|
|
|
|
|
return (
|
2026-05-30 21:52:02 -05:00
|
|
|
<SectionCard title="Import History" {...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
|
|
|
<div className="px-6 py-6 text-sm text-muted-foreground">Loading…</div>
|
|
|
|
|
</SectionCard>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rows = history ?? [];
|
|
|
|
|
|
|
|
|
|
return (
|
2026-05-30 21:52:02 -05:00
|
|
|
<SectionCard title="Import History" {...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
|
|
|
<div className="px-6 py-4 flex items-center justify-between">
|
|
|
|
|
<p className="text-xs text-muted-foreground">
|
|
|
|
|
{rows.length === 0 ? 'No imports yet.' : `${rows.length} import${rows.length === 1 ? '' : 's'}`}
|
|
|
|
|
</p>
|
|
|
|
|
<Button size="sm" variant="ghost" onClick={onRefresh} className="h-7 text-xs gap-1.5">
|
|
|
|
|
<RefreshCw className="h-3 w-3" />Refresh
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
{rows.length > 0 && (
|
|
|
|
|
<div className="overflow-x-auto">
|
|
|
|
|
<table className="w-full text-xs">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr className="border-b border-border/50 text-muted-foreground">
|
|
|
|
|
{['Date','File','Sheet','Parsed','Created','Updated','Skipped','Errors'].map(h => (
|
|
|
|
|
<th key={h} className="px-4 py-2 text-left font-medium whitespace-nowrap">{h}</th>
|
|
|
|
|
))}
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody className="divide-y divide-border/30">
|
|
|
|
|
{rows.map(r => (
|
|
|
|
|
<tr key={r.id} className="hover:bg-muted/20 transition-colors">
|
|
|
|
|
<td className="px-4 py-2 whitespace-nowrap text-muted-foreground">
|
|
|
|
|
<span className="flex items-center gap-1"><Clock className="h-3 w-3" />{fmt(r.imported_at)}</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-4 py-2 text-muted-foreground">{r.source_filename || '—'}</td>
|
|
|
|
|
<td className="px-4 py-2 text-muted-foreground">{r.sheet_name || '—'}</td>
|
|
|
|
|
<td className="px-4 py-2 tabular-nums">{r.rows_parsed}</td>
|
|
|
|
|
<td className="px-4 py-2 tabular-nums text-emerald-600">{r.rows_created}</td>
|
|
|
|
|
<td className="px-4 py-2 tabular-nums text-blue-600">{r.rows_updated}</td>
|
|
|
|
|
<td className="px-4 py-2 tabular-nums text-muted-foreground">{r.rows_skipped}</td>
|
|
|
|
|
<td className="px-4 py-2 tabular-nums text-red-500">{r.rows_errored}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</SectionCard>
|
|
|
|
|
);
|
|
|
|
|
}
|