feat: Dashboard placeholder avec preview Score Sérénité

Permet aux parents de visualiser une démo du Score Sérénité dès leur
première connexion, avant même que les données réelles soient disponibles.
Les autres rôles (enseignant, élève, admin) ont également leur dashboard
adapté avec des sections placeholder.

La landing page redirige automatiquement vers /dashboard si l'utilisateur
est déjà authentifié, offrant un accès direct au tableau de bord.
This commit is contained in:
2026-02-04 18:34:08 +01:00
parent d3c6773be5
commit b45ef735db
26 changed files with 3096 additions and 76 deletions

View File

@@ -0,0 +1,330 @@
<script lang="ts">
import type { DemoData } from '$types';
import DashboardSection from '$lib/components/molecules/DashboardSection.svelte';
import SkeletonList from '$lib/components/atoms/Skeleton/SkeletonList.svelte';
let {
demoData,
isLoading = false,
hasRealData = false,
isMinor = true
}: {
demoData: DemoData;
isLoading?: boolean;
hasRealData?: boolean;
isMinor?: boolean;
} = $props();
</script>
<div class="dashboard-student">
<header class="dashboard-header">
<h1>Mon espace</h1>
<p class="dashboard-subtitle">
{#if isMinor}
Bienvenue ! Voici ton tableau de bord.
{:else}
Bienvenue ! Voici votre tableau de bord.
{/if}
</p>
</header>
{#if !hasRealData}
<div class="info-banner">
<span class="info-icon">📚</span>
<p>
{#if isMinor}
Ton emploi du temps, tes notes et tes devoirs apparaîtront ici bientôt !
{:else}
Votre emploi du temps, vos notes et vos devoirs apparaîtront ici bientôt !
{/if}
</p>
</div>
{/if}
<div class="dashboard-grid">
<!-- EDT Section -->
<DashboardSection
title="Mon emploi du temps"
subtitle={hasRealData ? "Aujourd'hui" : undefined}
isPlaceholder={!hasRealData}
placeholderMessage={isMinor ? "Ton emploi du temps sera bientôt disponible" : "Votre emploi du temps sera bientôt disponible"}
>
{#if hasRealData}
{#if isLoading}
<SkeletonList items={4} message="Chargement de l'emploi du temps..." />
{:else}
<ul class="schedule-list">
{#each demoData.schedule.today as item}
<li class="schedule-item">
<span class="schedule-time">{item.time}</span>
<span class="schedule-subject">{item.subject}</span>
<span class="schedule-room">Salle {item.room}</span>
</li>
{/each}
</ul>
{/if}
{/if}
</DashboardSection>
<!-- Notes Section -->
<DashboardSection
title="Mes notes"
subtitle={hasRealData ? "Dernières notes" : undefined}
isPlaceholder={!hasRealData}
placeholderMessage={isMinor ? "Tes notes apparaîtront ici" : "Vos notes apparaîtront ici"}
>
{#if hasRealData}
{#if isLoading}
<SkeletonList items={3} message="Chargement des notes..." />
{:else}
<ul class="grades-list">
{#each demoData.grades.recent as grade}
<li class="grade-item">
<div class="grade-header">
<span class="grade-subject">{grade.subject}</span>
<span class="grade-value">{grade.value}/{grade.max}</span>
</div>
<span class="grade-eval">{grade.evaluation}</span>
</li>
{/each}
</ul>
{/if}
{/if}
</DashboardSection>
<!-- Devoirs Section -->
<DashboardSection
title="Mes devoirs"
subtitle={hasRealData ? "À faire" : undefined}
isPlaceholder={!hasRealData}
placeholderMessage={isMinor ? "Tes devoirs s'afficheront ici" : "Vos devoirs s'afficheront ici"}
>
{#if hasRealData}
{#if isLoading}
<SkeletonList items={3} message="Chargement des devoirs..." />
{:else}
<ul class="homework-list">
{#each demoData.homework.upcoming as homework}
<li class="homework-item" class:done={homework.status === 'done'}>
<div class="homework-header">
<span class="homework-subject">{homework.subject}</span>
{#if homework.status === 'done'}
<span class="homework-badge done">Fait ✓</span>
{:else if homework.status === 'late'}
<span class="homework-badge late">En retard</span>
{/if}
</div>
<span class="homework-title">{homework.title}</span>
<span class="homework-due">Pour le {homework.dueDate}</span>
</li>
{/each}
</ul>
{/if}
{/if}
</DashboardSection>
</div>
</div>
<style>
.dashboard-student {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.dashboard-header {
margin-bottom: 0.5rem;
}
.dashboard-header h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 700;
color: #1f2937;
}
.dashboard-subtitle {
margin: 0.25rem 0 0;
color: #6b7280;
}
.info-banner {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 1.25rem;
background: #eff6ff;
border: 1px solid #bfdbfe;
border-radius: 0.75rem;
color: #1e40af;
}
.info-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.info-banner p {
margin: 0;
font-size: 0.875rem;
}
.dashboard-grid {
display: grid;
gap: 1.5rem;
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.dashboard-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.dashboard-grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Schedule List */
.schedule-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.schedule-item {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 0.75rem;
padding: 0.75rem;
background: #f9fafb;
border-radius: 0.5rem;
align-items: center;
}
.schedule-time {
font-weight: 600;
color: #3b82f6;
font-size: 0.875rem;
min-width: 3rem;
}
.schedule-subject {
font-weight: 500;
color: #1f2937;
}
.schedule-room {
font-size: 0.75rem;
color: #6b7280;
}
/* Grades List */
.grades-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.grade-item {
padding: 0.75rem;
background: #f9fafb;
border-radius: 0.5rem;
}
.grade-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.25rem;
}
.grade-subject {
font-weight: 500;
color: #1f2937;
}
.grade-value {
font-weight: 700;
color: #22c55e;
font-size: 1.125rem;
}
.grade-eval {
font-size: 0.875rem;
color: #6b7280;
}
/* Homework List */
.homework-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.homework-item {
padding: 0.75rem;
background: #f9fafb;
border-radius: 0.5rem;
border-left: 3px solid #3b82f6;
}
.homework-item.done {
border-left-color: #22c55e;
opacity: 0.7;
}
.homework-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.25rem;
}
.homework-subject {
font-size: 0.75rem;
font-weight: 600;
color: #3b82f6;
text-transform: uppercase;
}
.homework-badge {
font-size: 0.625rem;
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-weight: 500;
}
.homework-badge.done {
background: #dcfce7;
color: #166534;
}
.homework-badge.late {
background: #fee2e2;
color: #991b1b;
}
.homework-title {
display: block;
font-weight: 500;
color: #1f2937;
margin-bottom: 0.25rem;
}
.homework-due {
font-size: 0.875rem;
color: #6b7280;
}
</style>