diff --git a/backend/internal/auth/jwt.go b/backend/internal/auth/jwt.go index c369266..0ff45bb 100644 --- a/backend/internal/auth/jwt.go +++ b/backend/internal/auth/jwt.go @@ -20,7 +20,7 @@ func GenerateToken(userID, email, role, secret string) (string, error) { Email: email, Role: role, RegisteredClaims: jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 02c1290..0aab391 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -14,6 +14,12 @@ async function request(path: string, options: RequestInit = {}): Promise { ...options.headers, }, }) + if (res.status === 401) { + localStorage.removeItem('token') + localStorage.removeItem('user') + window.location.href = '/login' + throw new Error('Session expirée') + } if (!res.ok) { const err = await res.json().catch(() => ({ error: res.statusText })) throw new Error(err.error || res.statusText) diff --git a/frontend/src/index.css b/frontend/src/index.css index 55912cb..9a753d6 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -37,3 +37,8 @@ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { @apply bg-muted; } ::-webkit-scrollbar-thumb { @apply bg-border rounded-full; } + +@layer utilities { + .scrollbar-none { scrollbar-width: none; } + .scrollbar-none::-webkit-scrollbar { display: none; } +} diff --git a/frontend/src/pages/admin/AdminLayout.tsx b/frontend/src/pages/admin/AdminLayout.tsx index 6bf87b2..eae71c0 100644 --- a/frontend/src/pages/admin/AdminLayout.tsx +++ b/frontend/src/pages/admin/AdminLayout.tsx @@ -1,12 +1,47 @@ -import { Outlet, Navigate } from 'react-router-dom' +import { NavLink, Outlet, Navigate } from 'react-router-dom' +import { Cpu, Key, Database, ClipboardList, Users, CalendarDays, Settings } from 'lucide-react' import { useAuth } from '@/lib/auth' +import { cn } from '@/lib/cn' + +const adminItems = [ + { to: '/admin/ai', icon: Cpu, label: 'Fournisseurs IA' }, + { to: '/admin/credentials', icon: Key, label: 'Identifiants' }, + { to: '/admin/sources', icon: Database, label: 'Sources' }, + { to: '/admin/jobs', icon: ClipboardList,label: 'Jobs' }, + { to: '/admin/users', icon: Users, label: 'Utilisateurs' }, + { to: '/admin/schedule', icon: CalendarDays, label: 'Planning' }, + { to: '/admin/settings', icon: Settings, label: 'Paramètres' }, +] export function AdminLayout() { const { isAdmin } = useAuth() if (!isAdmin) return return ( -
- +
+ {/* Mobile sub-nav — scrollable horizontal tabs */} + + +
+ +
) } diff --git a/frontend/src/pages/admin/Sources.tsx b/frontend/src/pages/admin/Sources.tsx index 95fcbce..82c0208 100644 --- a/frontend/src/pages/admin/Sources.tsx +++ b/frontend/src/pages/admin/Sources.tsx @@ -34,12 +34,12 @@ export function Sources() {
{sources.map(s => ( - +
{s.name} ({s.type})
-
+
{s.enabled ? 'Activée' : 'Désactivée'}