BillTracker/client/pages/AdminPage.tsx

100 lines
3.3 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '@/api';
import { errMessage } from '@/lib/utils';
import AppNavigation from '@/components/layout/Sidebar';
import OnboardingWizard from '@/components/admin/OnboardingWizard';
import EmailNotifCard from '@/components/admin/EmailNotifCard';
import BankSyncAdminCard from '@/components/admin/BankSyncAdminCard';
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';
import type { User } from '@/hooks/useAuth';
export default function AdminPage() {
const navigate = useNavigate();
const [me, setMe] = useState<User | null>(null);
const [hasUsers, setHasUsers] = useState<boolean | null>(null);
const [loadError, setLoadError] = useState('');
const [users, setUsers] = useState<unknown[]>([]);
const [authMode, setAuthMode] = useState('multi');
const loadMe = useCallback(async () => {
try {
const d = await api.me() as { user?: User };
setMe(d.user ?? null);
} catch {
navigate('/login', { replace: true });
}
}, [navigate]);
const loadUsers = useCallback(async () => {
try {
const d = await api.adminUsers() as { users?: unknown[] } | unknown[];
setUsers(Array.isArray(d) ? d : (d.users || []));
} catch { /* ignore */ }
}, []);
const loadHasUsers = useCallback(async () => {
try {
const d = await api.hasUsers() as { has_users?: boolean };
setHasUsers(!!d.has_users);
if (d.has_users) loadUsers();
} catch (err) {
setLoadError(errMessage(err, 'Failed to load admin page'));
setHasUsers(false);
}
}, [loadUsers]);
useEffect(() => {
loadMe();
loadHasUsers();
}, [loadMe, loadHasUsers]);
const handleOnboardingComplete = () => {
setHasUsers(true);
loadUsers();
};
if (hasUsers === null && !loadError) {
return (
<div className="flex items-center justify-center min-h-screen text-muted-foreground text-sm">
Loading
</div>
);
}
if (loadError) {
return (
<div className="flex items-center justify-center min-h-screen text-destructive text-sm">
{loadError}
</div>
);
}
return (
<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">
<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 />
<BankSyncAdminCard />
<BackupManagementCard />
<CleanupPanel />
<LoginModeCard users={users} onModeChange={setAuthMode} />
{authMode !== 'single' && <AuthMethodsCard />}
<AddUserCard onCreated={loadUsers} />
<UsersTable users={users} onRefresh={loadUsers} currentUser={me} />
</main>
)}
</div>
);
}