- Pridaná kompletná správa používateľov (CRUD, reset hesla, zmena roly) pre ROOT/ADMIN - Backend: POST /users endpoint, createUser controller, validácia - Frontend: UserManagement, UserForm, PasswordResetModal komponenty - Settings prístupné pre ROOT aj ADMIN (AdminRoute) - Notifikačný systém s snooze funkcionalitou - Aktualizácia HELPDESK_INIT_V2.md dokumentácie Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { Toaster } from 'react-hot-toast';
|
|
import { useEffect } from 'react';
|
|
|
|
import { useAuthStore } from '@/store/authStore';
|
|
import { useConfigStore } from '@/store/configStore';
|
|
import { MainLayout } from '@/components/layout';
|
|
import { LoadingOverlay } from '@/components/ui';
|
|
|
|
import { Login } from '@/pages/Login';
|
|
import { Dashboard } from '@/pages/Dashboard';
|
|
import { CustomersList } from '@/pages/customers';
|
|
import { ProjectsList } from '@/pages/projects';
|
|
import { TasksList } from '@/pages/tasks';
|
|
import { EquipmentList } from '@/pages/equipment';
|
|
import { RMAList } from '@/pages/rma';
|
|
import { SettingsDashboard } from '@/pages/settings';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
const { isAuthenticated, user, isLoading, fetchProfile } = useAuthStore();
|
|
const { fetchConfig, isLoaded: configLoaded } = useConfigStore();
|
|
|
|
useEffect(() => {
|
|
// Only fetch profile if we have a token but no user data
|
|
const token = localStorage.getItem('accessToken');
|
|
if (token && !user) {
|
|
fetchProfile();
|
|
}
|
|
}, [user, fetchProfile]);
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated && !configLoaded) {
|
|
fetchConfig();
|
|
}
|
|
}, [isAuthenticated, configLoaded, fetchConfig]);
|
|
|
|
// Show loading only when we're actively fetching
|
|
if (isLoading && !user) {
|
|
return <LoadingOverlay message="Načítavam..." />;
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
return <Navigate to="/login" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|
|
function AdminRoute({ children }: { children: React.ReactNode }) {
|
|
const { user } = useAuthStore();
|
|
|
|
if (user?.role.code !== 'ROOT' && user?.role.code !== 'ADMIN') {
|
|
return <Navigate to="/" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|
|
function AppRoutes() {
|
|
const { isAuthenticated } = useAuthStore();
|
|
|
|
return (
|
|
<Routes>
|
|
<Route
|
|
path="/login"
|
|
element={isAuthenticated ? <Navigate to="/" replace /> : <Login />}
|
|
/>
|
|
<Route
|
|
element={
|
|
<ProtectedRoute>
|
|
<MainLayout />
|
|
</ProtectedRoute>
|
|
}
|
|
>
|
|
<Route path="/" element={<Dashboard />} />
|
|
<Route path="/customers" element={<CustomersList />} />
|
|
<Route path="/projects" element={<ProjectsList />} />
|
|
<Route path="/tasks" element={<TasksList />} />
|
|
<Route path="/equipment" element={<EquipmentList />} />
|
|
<Route path="/rma" element={<RMAList />} />
|
|
<Route
|
|
path="/settings"
|
|
element={
|
|
<AdminRoute>
|
|
<SettingsDashboard />
|
|
</AdminRoute>
|
|
}
|
|
/>
|
|
</Route>
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
export function App() {
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<BrowserRouter>
|
|
<AppRoutes />
|
|
<Toaster
|
|
position="top-right"
|
|
toastOptions={{
|
|
duration: 3000,
|
|
style: {
|
|
background: '#fff',
|
|
color: '#0f172a',
|
|
border: '1px solid #e2e8f0',
|
|
},
|
|
}}
|
|
/>
|
|
</BrowserRouter>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|