PriceGhost/frontend/src/App.tsx
clucraft cfca33b4ea Add toast notifications for user feedback
- Created ToastContext with showToast hook
- Toast notifications appear in bottom-right, auto-dismiss after 3s
- Added success/error toasts for:
  - Saving notification settings
  - Refreshing prices
  - Updating check interval
  - Deleting products
- Replaced alert() calls with toast notifications

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:35:28 -05:00

131 lines
2.8 KiB
TypeScript

import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { AuthProvider, useAuth } from './context/AuthContext';
import { ToastProvider } from './context/ToastContext';
import Login from './pages/Login';
import Register from './pages/Register';
import Dashboard from './pages/Dashboard';
import ProductDetail from './pages/ProductDetail';
import Settings from './pages/Settings';
function ThemeInitializer({ children }: { children: React.ReactNode }) {
useEffect(() => {
const saved = localStorage.getItem('theme');
if (saved) {
document.documentElement.setAttribute('data-theme', saved);
}
}, []);
return <>{children}</>;
}
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth();
if (isLoading) {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
}}
>
<span className="spinner" style={{ width: '3rem', height: '3rem' }} />
</div>
);
}
if (!user) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
function PublicRoute({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth();
if (isLoading) {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
}}
>
<span className="spinner" style={{ width: '3rem', height: '3rem' }} />
</div>
);
}
if (user) {
return <Navigate to="/" replace />;
}
return <>{children}</>;
}
function AppRoutes() {
return (
<Routes>
<Route
path="/login"
element={
<PublicRoute>
<Login />
</PublicRoute>
}
/>
<Route
path="/register"
element={
<PublicRoute>
<Register />
</PublicRoute>
}
/>
<Route
path="/"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
<Route
path="/product/:id"
element={
<ProtectedRoute>
<ProductDetail />
</ProtectedRoute>
}
/>
<Route
path="/settings"
element={
<ProtectedRoute>
<Settings />
</ProtectedRoute>
}
/>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
}
export default function App() {
return (
<ThemeInitializer>
<BrowserRouter>
<AuthProvider>
<ToastProvider>
<AppRoutes />
</ToastProvider>
</AuthProvider>
</BrowserRouter>
</ThemeInitializer>
);
}