feat: Paralléliser les appels API de la page devoirs
Some checks failed
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

La page devoirs enchaînait séquentiellement les appels classes, subjects,
assignments et homework, produisant un waterfall de ~2.5s. En les lançant
dans un seul Promise.all, le temps de chargement correspond désormais au
plus lent des appels (~600ms) au lieu de leur somme.

Pour résoudre la dépendance de assignments sur le userId (nécessaire dans
l'URL), un nouveau helper getAuthenticatedUserId() encapsule le mécanisme
de token refresh côté module auth, évitant aux pages d'importer
refreshToken directement.

Chaque branche side-effect (loadAssignments, loadHomeworks) gère ses
erreurs via .catch() local pour éviter l'état partiel si l'une échoue
pendant que les autres réussissent.
This commit is contained in:
2026-03-16 22:36:50 +01:00
parent 68179a929f
commit a708af3a8f
4 changed files with 124 additions and 30 deletions

View File

@@ -2,7 +2,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { getApiBaseUrl } from '$lib/api/config';
import { authenticatedFetch, getCurrentUserId } from '$lib/auth';
import { authenticatedFetch, getAuthenticatedUserId } from '$lib/auth';
import Pagination from '$lib/components/molecules/Pagination/Pagination.svelte';
import SearchInput from '$lib/components/molecules/SearchInput/SearchInput.svelte';
import { untrack } from 'svelte';
@@ -121,15 +121,35 @@
return [];
}
async function loadAssignments() {
const userId = await getAuthenticatedUserId();
if (!userId) return;
const apiUrl = getApiBaseUrl();
const res = await authenticatedFetch(`${apiUrl}/teachers/${userId}/assignments`);
if (!res.ok) throw new Error('Erreur lors du chargement des affectations');
const data = await res.json();
assignments = extractCollection<TeacherAssignment>(data);
}
async function loadAll() {
try {
isLoading = true;
error = null;
const apiUrl = getApiBaseUrl();
// classesRes/subjectsRes are used below; loadAssignments & loadHomeworks
// apply side-effects internally and their results are intentionally ignored
const [classesRes, subjectsRes] = await Promise.all([
authenticatedFetch(`${apiUrl}/classes?itemsPerPage=100`),
authenticatedFetch(`${apiUrl}/subjects?itemsPerPage=100`),
loadAssignments().catch((e) => {
error = e instanceof Error ? e.message : 'Erreur lors du chargement des affectations';
}),
loadHomeworks().catch((e) => {
homeworks = [];
totalItems = 0;
error = e instanceof Error ? e.message : 'Erreur inconnue';
}),
]);
if (!classesRes.ok) throw new Error('Erreur lors du chargement des classes');
@@ -142,19 +162,6 @@
classes = extractCollection<SchoolClass>(classesData);
subjects = extractCollection<Subject>(subjectsData);
// getCurrentUserId() must be called AFTER authenticatedFetch,
// which triggers token refresh and sets currentUserId in memory
const userId = getCurrentUserId();
if (userId) {
const assignmentsRes = await authenticatedFetch(`${apiUrl}/teachers/${userId}/assignments`);
if (assignmentsRes.ok) {
const assignmentsData = await assignmentsRes.json();
assignments = extractCollection<TeacherAssignment>(assignmentsData);
}
}
await loadHomeworks();
} catch (e) {
error = e instanceof Error ? e.message : 'Erreur inconnue';
} finally {
@@ -884,8 +891,8 @@
{#if availableTargetClasses.length === 0}
<p class="empty-target-classes">Aucune autre classe disponible pour cette matière.</p>
{:else}
<div class="form-group">
<label>Classes cibles *</label>
<div class="form-group" role="group" aria-label="Classes cibles">
<span class="field-label">Classes cibles *</span>
<div class="checkbox-list">
{#each availableTargetClasses as cls (cls.id)}
{@const validationResult = duplicateValidationResults.find((r) => r.classId === cls.id)}
@@ -1279,7 +1286,8 @@
margin-bottom: 1.25rem;
}
.form-group label {
.form-group label,
.field-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;