Files
planflow/src/app/(app)/equipe/[id]/documents/page.tsx
T
MichaelandClaude Opus 5 c6abbaadc5 Faire de la fiche salarié un dossier à onglets, et le rendre saisissable
La fiche empilait tout sur une page, en lecture seule. Le dossier personnel
existait pourtant en base — date et lieu de naissance, nationalité, adresse,
contact d'urgence, NIR et IBAN chiffrés — sans qu'aucun écran ne l'écrive :
un salarié créé restait un dossier vide que rien ne permettait de remplir.

Cinq onglets, cinq routes : une fiche s'envoie par lien et se rouvre au même
endroit. Le bandeau porte ce qui ne change pas d'un onglet à l'autre, et le
gabarit le tient une fois pour toutes.

Deux points d'écriture et non un seul. L'état civil et les coordonnées
demandent `members.edit` ; le NIR, l'IBAN et le BIC exigent en plus de
pouvoir les lire. Fondus dans un même formulaire, un profil habilité à
modifier mais pas à lire aurait renvoyé des champs vides — et effacé ce qui
ne lui avait jamais été montré. Le journal retient qu'ils ont été renseignés,
jamais leur valeur.

Les parcours qui déposaient une pièce ou ouvraient un accès passent
désormais par l'onglet qui les porte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 11:20:18 +02:00

60 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { notFound } from 'next/navigation';
import { DocumentsPanel } from '@/app/(app)/equipe/[id]/DocumentsPanel';
import { InvitationPanel } from '@/app/(app)/equipe/[id]/InvitationPanel';
import { Badge } from '@/components/ui/Badge';
import { Card, CardHeader, EmptyState } from '@/components/ui/Card';
import { listDocuments } from '@/server/documents/queries';
import { getEmployee } from '@/server/employees/queries';
export const dynamic = 'force-dynamic';
export default async function DocumentsTab({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const employee = await getEmployee(id);
if (!employee) notFound();
// `members.documents.view` peut manquer là où `members.view` est accordée :
// la section disparaît alors, plutôt que d'échouer sur toute la page.
const documents = await listDocuments(id).catch(() => null);
return (
<div className="flex flex-col gap-5">
{documents ? (
<Card>
<CardHeader
title="Pièces du dossier"
badge={<Badge tone="neutral">{documents.documents.length}</Badge>}
/>
<DocumentsPanel
membershipId={employee.id}
documents={documents.documents}
canManage={documents.canManage}
/>
</Card>
) : (
<EmptyState
title="Documents non consultables"
description="Votre rôle ne donne pas accès aux pièces du dossier."
/>
)}
{employee.canInvite ? (
<Card>
<CardHeader title="Accès à l’application" />
<InvitationPanel
membershipId={employee.id}
defaultEmail={employee.email ?? employee.profile?.personalEmail ?? ''}
hasAccount={employee.hasAccount}
invitation={employee.invitation}
/>
</Card>
) : null}
</div>
);
}