Spaces:
Sleeping
Sleeping
| import { Switch, Route, Router as WouterRouter, useLocation, Redirect } from "wouter"; | |
| import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | |
| import { Toaster } from "@/components/ui/toaster"; | |
| import { TooltipProvider } from "@/components/ui/tooltip"; | |
| import { AuthProvider, useAuth } from "./context/auth-context"; | |
| import { setAuthTokenGetter } from "@workspace/api-client-react"; | |
| import React, { useEffect, Suspense } from "react"; | |
| import { useToast } from "./hooks/use-toast"; | |
| import { AppLayout } from "./components/layout"; | |
| import LoginPage from "./pages/login"; | |
| const Dashboard = React.lazy(() => import("./pages/dashboard")); | |
| const TasksList = React.lazy(() => import("./pages/tasks")); | |
| const TaskDetail = React.lazy(() => import("./pages/task-detail")); | |
| const TaskNew = React.lazy(() => import("./pages/task-new")); | |
| const Teams = React.lazy(() => import("./pages/teams")); | |
| const Notifications = React.lazy(() => import("./pages/notifications")); | |
| const Users = React.lazy(() => import("./pages/users")); | |
| const Clients = React.lazy(() => import("./pages/clients")); | |
| const ClientDetail = React.lazy(() => import("./pages/client-detail")); | |
| const Admin = React.lazy(() => import("./pages/admin")); | |
| import NotFound from "@/pages/not-found"; | |
| import AccessDenied from "./pages/access-denied"; | |
| const queryClient = new QueryClient({ | |
| defaultOptions: { | |
| queries: { | |
| retry: (failureCount, error: any) => { | |
| // Do not retry on 401 or 403 | |
| if (error?.status === 401 || error?.status === 403) return false; | |
| return failureCount < 2; | |
| }, | |
| refetchOnWindowFocus: false, | |
| }, | |
| }, | |
| }); | |
| function ProtectedRoutes() { | |
| const { user, token, logout, isLoading } = useAuth(); | |
| const [location, setLocation] = useLocation(); | |
| const { toast } = useToast(); | |
| // Set the API client token getter | |
| useEffect(() => { | |
| setAuthTokenGetter(() => token); | |
| }, [token]); | |
| // Global 401/403 handler (simple version) | |
| // Real implementation might need a custom hook or interceptor | |
| // but we can catch some states here. | |
| if (isLoading) { | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center bg-slate-50"> | |
| <div className="text-center"> | |
| <div className="animate-spin text-4xl mb-3">⚙️</div> | |
| <p className="text-slate-500 text-sm">جارٍ التحميل…</p> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| if (!user) return <Redirect to="/login" />; | |
| const role = user.role; | |
| // Admin-only routes | |
| if ((location === "/admin" || location === "/teams") && role !== "admin") { | |
| return ( | |
| <AppLayout> | |
| <AccessDenied /> | |
| </AppLayout> | |
| ); | |
| } | |
| // Member-only restricted routes | |
| if (role === "member" && (location === "/users" || location.startsWith("/clients"))) { | |
| return ( | |
| <AppLayout> | |
| <AccessDenied /> | |
| </AppLayout> | |
| ); | |
| } | |
| // Handle head_of_team and team_lead route exceptions if any | |
| // (Currently they can see most things except Admin) | |
| return ( | |
| <AppLayout> | |
| <Suspense fallback={ | |
| <div className="flex h-[50vh] items-center justify-center"> | |
| <div className="text-center"> | |
| <div className="animate-spin text-4xl mb-3">⚙️</div> | |
| <p className="text-slate-500 text-sm">جارٍ تحميل الصفحة…</p> | |
| </div> | |
| </div> | |
| }> | |
| <Switch> | |
| <Route path="/" component={Dashboard} /> | |
| <Route path="/tasks/new" component={TaskNew} /> | |
| <Route path="/tasks/:id" component={TaskDetail} /> | |
| <Route path="/tasks" component={TasksList} /> | |
| <Route path="/teams" component={Teams} /> | |
| <Route path="/notifications" component={Notifications} /> | |
| <Route path="/users" component={Users} /> | |
| <Route path="/clients/:id" component={ClientDetail} /> | |
| <Route path="/clients" component={Clients} /> | |
| <Route path="/admin" component={Admin} /> | |
| <Route component={NotFound} /> | |
| </Switch> | |
| </Suspense> | |
| </AppLayout> | |
| ); | |
| } | |
| function AppRoutes() { | |
| return ( | |
| <Switch> | |
| <Route path="/login" component={LoginPage} /> | |
| <Route component={ProtectedRoutes} /> | |
| </Switch> | |
| ); | |
| } | |
| function App() { | |
| return ( | |
| <QueryClientProvider client={queryClient}> | |
| <TooltipProvider> | |
| <WouterRouter base={import.meta.env.BASE_URL.replace(/\/$/, "")}> | |
| <AuthProvider> | |
| <AppRoutes /> | |
| </AuthProvider> | |
| </WouterRouter> | |
| <Toaster /> | |
| </TooltipProvider> | |
| </QueryClientProvider> | |
| ); | |
| } | |
| export default App; | |