Files
network-app-web/src/App.tsx
Hammer 7a956aebec
Some checks failed
CI/CD / test (push) Failing after 21s
CI/CD / deploy (push) Has been skipped
feat: production hardening UI - tags page, onboarding wizard, pagination
- Tags management page: grid cards, rename/delete/merge modals, color-coded
- Onboarding wizard: 4-step full-screen flow for new users (welcome, client, style, tour)
- Client list pagination: page controls, page size selector, URL query params
- Pipeline view unaffected (shows all clients)
- Tags added to sidebar navigation
- All components support dark mode
2026-01-30 01:37:40 +00:00

92 lines
4.5 KiB
TypeScript

import { useEffect, lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { useAuthStore } from '@/stores/auth';
import Layout from '@/components/Layout';
import { PageLoader } from '@/components/LoadingSpinner';
import ErrorBoundary from '@/components/ErrorBoundary';
import { ToastContainer, toast } from '@/components/Toast';
import { api } from '@/lib/api';
const LoginPage = lazy(() => import('@/pages/LoginPage'));
const DashboardPage = lazy(() => import('@/pages/DashboardPage'));
const ClientsPage = lazy(() => import('@/pages/ClientsPage'));
const ClientDetailPage = lazy(() => import('@/pages/ClientDetailPage'));
const EventsPage = lazy(() => import('@/pages/EventsPage'));
const EmailsPage = lazy(() => import('@/pages/EmailsPage'));
const SettingsPage = lazy(() => import('@/pages/SettingsPage'));
const AdminPage = lazy(() => import('@/pages/AdminPage'));
const NetworkPage = lazy(() => import('@/pages/NetworkPage'));
const ReportsPage = lazy(() => import('@/pages/ReportsPage'));
const TemplatesPage = lazy(() => import('@/pages/TemplatesPage'));
const SegmentsPage = lazy(() => import('@/pages/SegmentsPage'));
const InvitePage = lazy(() => import('@/pages/InvitePage'));
const ForgotPasswordPage = lazy(() => import('@/pages/ForgotPasswordPage'));
const ResetPasswordPage = lazy(() => import('@/pages/ResetPasswordPage'));
const AuditLogPage = lazy(() => import('@/pages/AuditLogPage'));
const TagsPage = lazy(() => import('@/pages/TagsPage'));
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuthStore();
if (isLoading) return <PageLoader />;
if (!isAuthenticated) return <Navigate to="/login" replace />;
return <>{children}</>;
}
// Setup global API error interceptor
api.setErrorHandler((status, message) => {
if (status === 401) {
toast.error('Session expired. Please log in again.');
} else if (status === 403) {
toast.error('Access denied: ' + message);
} else if (status >= 500) {
toast.error('Server error: ' + message);
}
});
function PageErrorBoundary({ children }: { children: React.ReactNode }) {
return <ErrorBoundary>{children}</ErrorBoundary>;
}
export default function App() {
const { checkSession, isAuthenticated } = useAuthStore();
useEffect(() => {
checkSession();
}, [checkSession]);
return (
<BrowserRouter>
<Suspense fallback={<PageLoader />}>
<Routes>
<Route path="/login" element={
isAuthenticated ? <Navigate to="/" replace /> : <PageErrorBoundary><LoginPage /></PageErrorBoundary>
} />
<Route path="/invite/:token" element={<PageErrorBoundary><InvitePage /></PageErrorBoundary>} />
<Route path="/forgot-password" element={<PageErrorBoundary><ForgotPasswordPage /></PageErrorBoundary>} />
<Route path="/reset-password/:token" element={<PageErrorBoundary><ResetPasswordPage /></PageErrorBoundary>} />
<Route path="/" element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}>
<Route index element={<PageErrorBoundary><DashboardPage /></PageErrorBoundary>} />
<Route path="clients" element={<PageErrorBoundary><ClientsPage /></PageErrorBoundary>} />
<Route path="clients/:id" element={<PageErrorBoundary><ClientDetailPage /></PageErrorBoundary>} />
<Route path="events" element={<PageErrorBoundary><EventsPage /></PageErrorBoundary>} />
<Route path="emails" element={<PageErrorBoundary><EmailsPage /></PageErrorBoundary>} />
<Route path="network" element={<PageErrorBoundary><NetworkPage /></PageErrorBoundary>} />
<Route path="reports" element={<PageErrorBoundary><ReportsPage /></PageErrorBoundary>} />
<Route path="templates" element={<PageErrorBoundary><TemplatesPage /></PageErrorBoundary>} />
<Route path="tags" element={<PageErrorBoundary><TagsPage /></PageErrorBoundary>} />
<Route path="segments" element={<PageErrorBoundary><SegmentsPage /></PageErrorBoundary>} />
<Route path="settings" element={<PageErrorBoundary><SettingsPage /></PageErrorBoundary>} />
<Route path="admin" element={<PageErrorBoundary><AdminPage /></PageErrorBoundary>} />
<Route path="audit-log" element={<PageErrorBoundary><AuditLogPage /></PageErrorBoundary>} />
</Route>
</Routes>
</Suspense>
<ToastContainer />
</BrowserRouter>
);
}