PriceGhost/frontend/src/App.tsx
clucraft a6928a0c17 Add refresh controls and notification support
- Add refresh button to product list items with spinning animation
- Add editable refresh interval dropdown on product detail page
- Add user profile dropdown with settings link in navbar
- Create Settings page for Telegram and Discord configuration
- Add per-product notification options (price drop threshold, back in stock)
- Integrate notifications into scheduler for automatic alerts
- Add notification service supporting Telegram Bot API and Discord webhooks

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

128 lines
2.7 KiB
TypeScript

import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { AuthProvider, useAuth } from './context/AuthContext';
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>
<AppRoutes />
</AuthProvider>
</BrowserRouter>
</ThemeInitializer>
);
}