131 lines
4.1 KiB
TypeScript
131 lines
4.1 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { AuthProvider, useAuth } from './context/AuthContext';
|
|
import Dashboard from './pages/Dashboard';
|
|
import Login from './pages/Login';
|
|
import Register from './pages/Register';
|
|
import CreateRecipe from './pages/CreateRecipe';
|
|
import EditRecipe from './pages/EditRecipe';
|
|
import './App.css';
|
|
|
|
// Protected Route component
|
|
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { user, loading } = useAuth();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="loading-container">
|
|
<div className="loading-spinner"></div>
|
|
<p>Loading...</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return user ? <>{children}</> : <Navigate to="/login" />;
|
|
};
|
|
|
|
// Public Route component (redirect to dashboard if already logged in)
|
|
const PublicRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const { user, loading } = useAuth();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="loading-container">
|
|
<div className="loading-spinner"></div>
|
|
<p>Loading...</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return user ? <Navigate to="/" /> : <>{children}</>;
|
|
};
|
|
|
|
function App() {
|
|
useEffect(() => {
|
|
// Update document title
|
|
document.title = 'Scoffer - Recipe Management';
|
|
|
|
// Create and set favicon
|
|
const favicon = document.querySelector("link[rel*='icon']") as HTMLLinkElement || document.createElement('link');
|
|
favicon.type = 'image/svg+xml';
|
|
favicon.rel = 'shortcut icon';
|
|
favicon.href = 'data:image/svg+xml;base64,' + btoa(`
|
|
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
<circle cx="16" cy="16" r="15" fill="#FF6B35"/>
|
|
<path d="M8 12 Q8 9 10 9 Q12 7 16 7 Q20 7 22 9 Q24 9 24 12 L24 15 Q24 16 23 16 L9 16 Q8 16 8 15 Z" fill="white"/>
|
|
<rect x="9" y="15" width="14" height="4" fill="white" rx="1"/>
|
|
<g transform="translate(6, 20)">
|
|
<rect x="2" y="0" width="0.5" height="6" fill="white"/>
|
|
<rect x="1.5" y="0" width="0.5" height="4" fill="white"/>
|
|
<rect x="2.5" y="0" width="0.5" height="4" fill="white"/>
|
|
<rect x="1.2" y="6" width="2.1" height="2" fill="white" rx="0.3"/>
|
|
</g>
|
|
<g transform="translate(22, 20)">
|
|
<rect x="0" y="0" width="2" height="0.8" fill="white"/>
|
|
<rect x="0.7" y="0.8" width="0.6" height="5.5" fill="white"/>
|
|
<rect x="0.3" y="6.3" width="1.4" height="2" fill="white" rx="0.3"/>
|
|
</g>
|
|
<ellipse cx="16" cy="23" rx="5" ry="2" fill="white" opacity="0.9"/>
|
|
<circle cx="14" cy="22.5" r="0.8" fill="#4CAF50"/>
|
|
<circle cx="18" cy="22.5" r="0.8" fill="#FFC107"/>
|
|
<circle cx="16" cy="21.5" r="0.6" fill="#FF5722"/>
|
|
</svg>
|
|
`);
|
|
document.getElementsByTagName('head')[0].appendChild(favicon);
|
|
}, []);
|
|
|
|
return (
|
|
<AuthProvider>
|
|
<Router>
|
|
<div className="App">
|
|
<Routes>
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<ProtectedRoute>
|
|
<Dashboard />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/login"
|
|
element={
|
|
<PublicRoute>
|
|
<Login />
|
|
</PublicRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/register"
|
|
element={
|
|
<PublicRoute>
|
|
<Register />
|
|
</PublicRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/create-recipe"
|
|
element={
|
|
<ProtectedRoute>
|
|
<CreateRecipe />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/edit-recipe/:id"
|
|
element={
|
|
<ProtectedRoute>
|
|
<EditRecipe />
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
<Route path="*" element={<Navigate to="/" />} />
|
|
</Routes>
|
|
</div>
|
|
</Router>
|
|
</AuthProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|