feat: Permettre au super admin de se connecter et accéder à son dashboard
Le super admin (table super_admins, master DB) ne pouvait pas se connecter via /api/login car ce firewall n'utilisait que le provider tenant. De même, le JWT n'était pas enrichi pour les super admins, l'endpoint /api/me/roles les rejetait, et le frontend redirigeait systématiquement vers /dashboard. Un chain provider (super_admin + tenant) résout l'authentification, le JwtPayloadEnricher et MyRolesProvider gèrent désormais les deux types d'utilisateurs, et le frontend redirige selon le rôle après login.
This commit is contained in:
157
frontend/src/routes/super-admin/+layout.svelte
Normal file
157
frontend/src/routes/super-admin/+layout.svelte
Normal file
@@ -0,0 +1,157 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { isAuthenticated, refreshToken } from '$lib/auth/auth.svelte';
|
||||
import { fetchRoles, getActiveRole } from '$lib/features/roles/roleContext.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let hasAccess = $derived(isAuthenticated() && getActiveRole() === 'ROLE_SUPER_ADMIN');
|
||||
|
||||
$effect(() => {
|
||||
untrack(async () => {
|
||||
if (!isAuthenticated()) {
|
||||
const refreshed = await refreshToken();
|
||||
if (!refreshed) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
}
|
||||
await fetchRoles();
|
||||
});
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const role = getActiveRole();
|
||||
if (role !== null && role !== 'ROLE_SUPER_ADMIN') {
|
||||
goto('/dashboard');
|
||||
}
|
||||
});
|
||||
|
||||
const isEstablishmentsActive = $derived($page.url.pathname.startsWith('/super-admin/establishments'));
|
||||
const isDashboardActive = $derived(
|
||||
$page.url.pathname === '/super-admin' || $page.url.pathname === '/super-admin/dashboard'
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if hasAccess}
|
||||
<div class="super-admin-layout">
|
||||
<header class="sa-header">
|
||||
<div class="sa-header-inner">
|
||||
<div class="sa-brand">
|
||||
<span class="sa-logo">SA</span>
|
||||
<h1>Classeo Super Admin</h1>
|
||||
</div>
|
||||
<nav class="sa-nav">
|
||||
<a
|
||||
href="/super-admin/dashboard"
|
||||
class="sa-nav-link"
|
||||
class:active={isDashboardActive}
|
||||
>
|
||||
Dashboard
|
||||
</a>
|
||||
<a
|
||||
href="/super-admin/establishments"
|
||||
class="sa-nav-link"
|
||||
class:active={isEstablishmentsActive}
|
||||
>
|
||||
Établissements
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="sa-main">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="sa-loading">
|
||||
<p>Vérification des accès...</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.super-admin-layout {
|
||||
min-height: 100vh;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.sa-header {
|
||||
background: #1a1a2e;
|
||||
color: white;
|
||||
padding: 0 1.5rem;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sa-header-inner {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.sa-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.sa-logo {
|
||||
background: #e94560;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sa-brand h1 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sa-nav {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.sa-nav-link {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.sa-nav-link:hover {
|
||||
color: white;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.sa-nav-link.active {
|
||||
color: white;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.sa-main {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
.sa-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user