Emplois, étiquettes et types d'absence vivaient en base sans écran : le seed les posait, et rien ne permettait ensuite d'en ajouter un. Ils s'éditent désormais depuis les réglages. Trois choix portent la conformité plutôt que le confort : - Archiver, jamais supprimer. Un emploi figure au registre du personnel, une étiquette colore des semaines closes, un type d'absence justifie des écritures de compteur. Supprimer l'un des trois rendrait illisible un dossier dont la conservation court encore. - Le code Silae manquant est signalé. Un type sans code fait échouer l'export de la période ; l'écran le dit avant l'échéance de paie plutôt qu'après. - La convention se réédite, elle ne se modifie pas. Chaque enregistrement crée une version datée : une paie de mars doit rester reproductible après un changement de seuil en juin. L'origine de chaque valeur — ordre public, convention, accord d'entreprise — est affichée, parce que les trois ne se corrigent pas de la même main. Les mutations de types d'absence passent par settings.agreement.manage : le catalogue §5 ne déclare pas de code dédié, et ces drapeaux relèvent du paramétrage légal. Inventer une capacité aurait créé un droit sans rien protéger de neuf. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
104 lines
3.4 KiB
TypeScript
104 lines
3.4 KiB
TypeScript
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||
import { Badge } from '@/components/ui/Badge';
|
||
import { Button } from '@/components/ui/Button';
|
||
import { Card, CardHeader, EmptyState } from '@/components/ui/Card';
|
||
import {
|
||
AddJobTitleForm,
|
||
RenameJobTitleForm,
|
||
} from '@/app/(app)/reglages/emplois/JobTitleForms';
|
||
import {
|
||
archiveJobTitleAction,
|
||
listJobTitles,
|
||
} from '@/server/settings/job-titles';
|
||
|
||
export const metadata = { title: 'Emplois · PlanFlow' };
|
||
export const dynamic = 'force-dynamic';
|
||
|
||
export default async function EmploisPage({
|
||
searchParams,
|
||
}: {
|
||
searchParams: Promise<{ archives?: string }>;
|
||
}) {
|
||
const { archives } = await searchParams;
|
||
const showArchived = archives === '1';
|
||
const titles = await listJobTitles(showArchived);
|
||
const active = titles.filter((title) => title.archivedAt === null);
|
||
|
||
return (
|
||
<PageBody>
|
||
<PageHeader
|
||
title="Emplois"
|
||
subtitle={`${active.length} emploi${active.length > 1 ? 's' : ''} en vigueur`}
|
||
/>
|
||
|
||
<Card>
|
||
<CardHeader
|
||
title="Référentiel"
|
||
badge={
|
||
<Badge tone="neutral">
|
||
{titles.length} affiché{titles.length > 1 ? 's' : ''}
|
||
</Badge>
|
||
}
|
||
action={
|
||
<a
|
||
href={showArchived ? '/reglages/emplois' : '/reglages/emplois?archives=1'}
|
||
className="text-xs text-ink-2 underline underline-offset-2 hover:text-ink-1"
|
||
>
|
||
{showArchived ? 'Masquer les archivés' : 'Voir les archivés'}
|
||
</a>
|
||
}
|
||
/>
|
||
|
||
{titles.length === 0 ? (
|
||
<EmptyState
|
||
title="Aucun emploi"
|
||
description="Un contrat porte une qualification ; créez d’abord les emplois de l’organisation."
|
||
/>
|
||
) : (
|
||
<ul className="divide-y divide-line-1">
|
||
{titles.map((title) => (
|
||
<li
|
||
key={title.id}
|
||
className="flex flex-wrap items-end gap-3 px-4 py-3"
|
||
>
|
||
<RenameJobTitleForm id={title.id} name={title.name} />
|
||
|
||
<div className="flex items-center gap-2">
|
||
<Badge tone="neutral">
|
||
{title.contractCount} contrat
|
||
{title.contractCount > 1 ? 's' : ''}
|
||
</Badge>
|
||
{title.archivedAt ? <Badge tone="warn">Archivé</Badge> : null}
|
||
</div>
|
||
|
||
<form action={archiveJobTitleAction}>
|
||
<input type="hidden" name="id" value={title.id} />
|
||
{title.archivedAt ? (
|
||
<input type="hidden" name="restore" value="1" />
|
||
) : null}
|
||
<Button size="sm" variant="ghost" type="submit">
|
||
{title.archivedAt ? 'Rétablir' : 'Archiver'}
|
||
</Button>
|
||
</form>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
)}
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader title="Nouvel emploi" />
|
||
<div className="p-4">
|
||
<AddJobTitleForm />
|
||
</div>
|
||
</Card>
|
||
|
||
<p className="max-w-[70ch] text-xs leading-[var(--lh-prose)] text-ink-3">
|
||
Un emploi porté par un contrat est archivé, jamais supprimé : le registre
|
||
unique du personnel doit rester lisible pendant toute la durée de
|
||
conservation, y compris pour un salarié parti.
|
||
</p>
|
||
</PageBody>
|
||
);
|
||
}
|