Checkpoint: 1) createSolution retourne maintenant l'insertId (number) au lieu du ResultSetHeader brut → solutionId n'est plus NaN. 2) La charte CGU est désormais affichée à chaque nouvelle session navigateur (sessionStorage) et non plus uniquement à la première connexion.

This commit is contained in:
Manus
2026-04-16 11:51:20 -04:00
parent 19852d0907
commit b86977eae4
5 changed files with 20 additions and 6 deletions

View File

@@ -9,7 +9,11 @@ interface CguModalProps {
export default function CguModal({ onAccepted }: CguModalProps) { export default function CguModal({ onAccepted }: CguModalProps) {
const [checked, setChecked] = useState(false); const [checked, setChecked] = useState(false);
const acceptMutation = trpc.cgu.accept.useMutation({ const acceptMutation = trpc.cgu.accept.useMutation({
onSuccess: () => onAccepted(), onSuccess: () => {
// Marquer l'acceptation pour cette session (réinitialisé à chaque fermeture de navigateur)
sessionStorage.setItem("sonum_cgu_accepted", "1");
onAccepted();
},
}); });
return ( return (

View File

@@ -68,7 +68,7 @@ export default function RattacherSolutionModal({ etablissementId, etablissementN
} }
const sol = await createSolutionMutation.mutateAsync({ nom: newSolutionNom, editeurId }); const sol = await createSolutionMutation.mutateAsync({ nom: newSolutionNom, editeurId });
const editeurNom = editeursQuery.data?.find(e => e.id === editeurId)?.nom ?? newEditeurNom; const editeurNom = editeursQuery.data?.find(e => e.id === editeurId)?.nom ?? newEditeurNom;
setSelectedSolution({ id: Number(sol), nom: newSolutionNom, editeurNom }); setSelectedSolution({ id: sol as number, nom: newSolutionNom, editeurNom });
setStep(2); setStep(2);
}; };

View File

@@ -46,10 +46,15 @@ export default function Home() {
}; };
const cguQuery = trpc.cgu.status.useQuery(undefined, { enabled: isAuthenticated }); const cguQuery = trpc.cgu.status.useQuery(undefined, { enabled: isAuthenticated });
// La CGU doit être acceptée à chaque nouvelle session (sessionStorage vidé à la fermeture du navigateur)
const [sessionCguAccepted, setSessionCguAccepted] = useState(() =>
typeof window !== "undefined" && sessionStorage.getItem("sonum_cgu_accepted") === "1"
);
const blocsQuery = trpc.referentiel.blocsFonctionnels.useQuery(); const blocsQuery = trpc.referentiel.blocsFonctionnels.useQuery();
const editeursQuery = trpc.referentiel.editeurs.useQuery(); const editeursQuery = trpc.referentiel.editeurs.useQuery();
const solutionsQuery = trpc.referentiel.solutions.useQuery({ search: searchText.length >= 2 ? searchText : undefined }); const solutionsQuery = trpc.referentiel.solutions.useQuery({ search: searchText.length >= 2 ? searchText : undefined });
const searchQuery = trpc.etablissements.search.useQuery(filters, { enabled: isAuthenticated && (cguQuery.data?.accepted ?? false) }); const cguFullyAccepted = sessionCguAccepted && (cguQuery.data?.accepted ?? false);
const searchQuery = trpc.etablissements.search.useQuery(filters, { enabled: isAuthenticated && cguFullyAccepted });
const tracabiliteUtils = trpc.useUtils(); const tracabiliteUtils = trpc.useUtils();
const recordConsultation = trpc.tracabilite.enregistrerConsultation.useMutation(); const recordConsultation = trpc.tracabilite.enregistrerConsultation.useMutation();
@@ -95,10 +100,10 @@ export default function Home() {
); );
} }
if (!cguQuery.data?.accepted) { if (!cguFullyAccepted) {
return ( return (
<SonumLayout> <SonumLayout>
<CguModal onAccepted={() => cguQuery.refetch()} /> <CguModal onAccepted={() => { setSessionCguAccepted(true); cguQuery.refetch(); }} />
</SonumLayout> </SonumLayout>
); );
} }

View File

@@ -138,7 +138,9 @@ export async function createSolution(nom: string, editeurId: number, blocFonctio
const db = await getDb(); const db = await getDb();
if (!db) return null; if (!db) return null;
const result = await db.insert(solutions).values({ nom, editeurId, blocFonctionnelId: blocFonctionnelId ?? null, estValide }); const result = await db.insert(solutions).values({ nom, editeurId, blocFonctionnelId: blocFonctionnelId ?? null, estValide });
return result[0]; // result[0] est un ResultSetHeader MySQL, on retourne l'insertId directement
const insertId = (result[0] as any).insertId as number;
return insertId;
} }
// ─── Établissements ─────────────────────────────────────────────────────────── // ─── Établissements ───────────────────────────────────────────────────────────

View File

@@ -108,8 +108,11 @@ export const appRouter = router({
return { success: true }; return { success: true };
}), }),
status: protectedProcedure.query(({ ctx }) => ({ status: protectedProcedure.query(({ ctx }) => ({
// La CGU doit être acceptée à chaque session (pas seulement la première fois)
// On retourne toujours les données réelles mais le frontend gère la session
accepted: ctx.user.cguAccepted, accepted: ctx.user.cguAccepted,
acceptedAt: ctx.user.cguAcceptedAt, acceptedAt: ctx.user.cguAcceptedAt,
userId: ctx.user.id,
})), })),
}), }),