mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-05-04 21:32:40 +02:00
- 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>
128 lines
2.7 KiB
TypeScript
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>
|
|
);
|
|
}
|