2026-05-09 13:03:36 -05:00
|
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
2026-05-03 19:51:57 -05:00
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
import { api } from '@/api';
|
|
|
|
|
import AppNavigation from '@/components/layout/Sidebar';
|
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 OnboardingWizard from '@/components/admin/OnboardingWizard';
|
|
|
|
|
import EmailNotifCard from '@/components/admin/EmailNotifCard';
|
2026-05-28 22:06:15 -05:00
|
|
|
import BankSyncAdminCard from '@/components/admin/BankSyncAdminCard';
|
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 LoginModeCard from '@/components/admin/LoginModeCard';
|
|
|
|
|
import AuthMethodsCard from '@/components/admin/AuthMethodsCard';
|
|
|
|
|
import UsersTable from '@/components/admin/UsersTable';
|
|
|
|
|
import AddUserCard from '@/components/admin/AddUserCard';
|
|
|
|
|
import BackupManagementCard from '@/components/admin/BackupManagementCard';
|
|
|
|
|
import CleanupPanel from '@/components/admin/CleanupPanel';
|
2026-05-03 19:51:57 -05:00
|
|
|
|
|
|
|
|
export default function AdminPage() {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
const [me, setMe] = useState(null);
|
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
|
|
|
const [hasUsers, setHasUsers] = useState(null);
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
const [loadError, setLoadError] = useState('');
|
2026-05-03 19:51:57 -05:00
|
|
|
const [users, setUsers] = useState([]);
|
2026-06-04 03:53:38 -05:00
|
|
|
const [authMode, setAuthMode] = useState('multi');
|
2026-05-03 19:51:57 -05:00
|
|
|
|
|
|
|
|
const loadMe = useCallback(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const d = await api.me();
|
|
|
|
|
setMe(d.user);
|
|
|
|
|
} catch {
|
|
|
|
|
navigate('/login', { replace: true });
|
|
|
|
|
}
|
|
|
|
|
}, [navigate]);
|
|
|
|
|
|
|
|
|
|
const loadUsers = useCallback(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const d = await api.adminUsers();
|
|
|
|
|
setUsers(d.users || d);
|
|
|
|
|
} catch {}
|
|
|
|
|
}, []);
|
|
|
|
|
|
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
|
|
|
const loadHasUsers = useCallback(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const d = await api.hasUsers();
|
|
|
|
|
setHasUsers(d.has_users);
|
|
|
|
|
if (d.has_users) loadUsers();
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
} catch (err) {
|
|
|
|
|
setLoadError(err.message || 'Failed to load admin page');
|
|
|
|
|
setHasUsers(false);
|
|
|
|
|
}
|
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
|
|
|
}, [loadUsers]);
|
|
|
|
|
|
2026-05-03 19:51:57 -05:00
|
|
|
useEffect(() => {
|
|
|
|
|
loadMe();
|
|
|
|
|
loadHasUsers();
|
|
|
|
|
}, [loadMe, loadHasUsers]);
|
|
|
|
|
|
|
|
|
|
const handleOnboardingComplete = () => {
|
|
|
|
|
setHasUsers(true);
|
|
|
|
|
loadUsers();
|
|
|
|
|
};
|
|
|
|
|
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
if (hasUsers === null && !loadError) {
|
2026-05-03 19:51:57 -05:00
|
|
|
return (
|
|
|
|
|
<div className="flex items-center justify-center min-h-screen text-muted-foreground text-sm">
|
|
|
|
|
Loading…
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
if (loadError) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center justify-center min-h-screen text-destructive text-sm">
|
|
|
|
|
{loadError}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 19:51:57 -05:00
|
|
|
return (
|
2026-05-15 22:45:38 -05:00
|
|
|
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,oklch(var(--primary)/0.06),transparent_34rem),linear-gradient(180deg,oklch(var(--background)),oklch(var(--muted)/0.18))] text-foreground">
|
2026-05-03 19:51:57 -05:00
|
|
|
<AppNavigation adminMode />
|
|
|
|
|
|
|
|
|
|
{!hasUsers ? (
|
|
|
|
|
<OnboardingWizard onComplete={handleOnboardingComplete} />
|
|
|
|
|
) : (
|
|
|
|
|
<main className="mx-auto max-w-5xl px-4 py-6 sm:px-6 lg:px-8 lg:py-8 space-y-6">
|
|
|
|
|
<EmailNotifCard />
|
2026-05-28 22:06:15 -05:00
|
|
|
<BankSyncAdminCard />
|
2026-05-03 19:51:57 -05:00
|
|
|
<BackupManagementCard />
|
|
|
|
|
<CleanupPanel />
|
2026-06-04 03:53:38 -05:00
|
|
|
<LoginModeCard users={users} onModeChange={setAuthMode} />
|
|
|
|
|
{authMode !== 'single' && <AuthMethodsCard />}
|
2026-05-03 19:51:57 -05:00
|
|
|
<AddUserCard onCreated={loadUsers} />
|
|
|
|
|
<UsersTable users={users} onRefresh={loadUsers} currentUser={me} />
|
|
|
|
|
</main>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|