Quatre écrans manquaient faute de spécification. Les captures du produit audité les fournissent : identité de l'entreprise, comportement des plannings, droits ouverts aux salariés, décompte de paie. Les préférences sont trois blocs typés, pas un sac de clés-valeurs. Ce n'est pas de la rigueur gratuite : `smoothOvertimeMonthly` change le calcul des heures supplémentaires, et un JSON libre rendrait indétectable une clé mal orthographiée — le réglage paraîtrait actif sans l'être. Chaque formulaire déclare les clés qu'il gouverne. Une case décochée n'arrive pas dans le FormData ; sans cette déclaration, enregistrer « Plannings » remettrait à faux tout « Droits », un formulaire partiel effaçant ce qu'il n'affiche pas. Trois réglages portent un avertissement en évidence parce qu'ils déplacent des heures et non des pixels. Le lissage mensuel des heures supplémentaires suppose un accord d'aménagement du temps de travail : le décompte hebdomadaire est le principe, et sans accord l'aménagement est inopposable. Les pauses rémunérées et l'inclusion des repos dans les heures normales changent la répartition entre heures normales et majorées. Un interrupteur qui coûte de l'argent ne doit pas se présenter comme un réglage d'affichage. La ligne de préférences est créée à la demande : son absence vaut « tous les défauts ». Semer une ligne à l'installation obligerait à migrer chaque compte au premier réglage ajouté. L'adresse va sur le compte et non sur l'établissement : le siège porte l'identité juridique et figure au registre du personnel, là où l'établissement porte le SIRET, le fuseau effectif et les plannings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
'use client';
|
||
|
||
import { useActionState } from 'react';
|
||
|
||
import { Field, FormError, SubmitButton } from '@/components/ui/Form';
|
||
import { PersistentForm } from '@/components/ui/PersistentForm';
|
||
import {
|
||
saveAccountIdentityAction,
|
||
type AccountIdentity,
|
||
type ActionState,
|
||
} from '@/server/settings/account';
|
||
|
||
const empty: ActionState = {};
|
||
|
||
export function AccountIdentityForm({
|
||
account,
|
||
}: {
|
||
account: AccountIdentity;
|
||
}) {
|
||
const [state, action] = useActionState(saveAccountIdentityAction, empty);
|
||
|
||
return (
|
||
<PersistentForm action={action} className="flex flex-col gap-3 p-4">
|
||
<Field
|
||
label="Raison sociale"
|
||
name="name"
|
||
defaultValue={account.name}
|
||
required
|
||
maxLength={200}
|
||
/>
|
||
|
||
<div className="flex flex-wrap gap-3">
|
||
<Field
|
||
label="SIREN"
|
||
name="siren"
|
||
defaultValue={account.siren ?? ''}
|
||
inputMode="numeric"
|
||
placeholder="9 chiffres"
|
||
hint="Identifie l’entreprise. Le SIRET, propre à chaque établissement, se saisit sur l’établissement."
|
||
/>
|
||
<Field
|
||
label="Code APE"
|
||
name="apeCode"
|
||
defaultValue={account.apeCode ?? ''}
|
||
placeholder="4759B"
|
||
/>
|
||
</div>
|
||
|
||
<Field
|
||
label="Adresse du siège"
|
||
name="addressLine"
|
||
defaultValue={account.addressLine ?? ''}
|
||
maxLength={200}
|
||
hint="Figure sur les documents édités et au registre unique du personnel."
|
||
/>
|
||
|
||
<div className="flex flex-wrap gap-3">
|
||
<Field
|
||
label="Code postal"
|
||
name="postalCode"
|
||
defaultValue={account.postalCode ?? ''}
|
||
inputMode="numeric"
|
||
/>
|
||
<Field
|
||
label="Ville"
|
||
name="city"
|
||
defaultValue={account.city ?? ''}
|
||
maxLength={120}
|
||
/>
|
||
</div>
|
||
|
||
<Field
|
||
label="Fuseau horaire"
|
||
name="timezone"
|
||
defaultValue={account.timezone}
|
||
required
|
||
hint="Défaut du compte. Un établissement dans un autre fuseau porte le sien."
|
||
/>
|
||
|
||
<FormError>{state.error}</FormError>
|
||
|
||
<div className="flex items-center gap-3">
|
||
<SubmitButton>Enregistrer</SubmitButton>
|
||
{state.ok ? (
|
||
<span className="text-xs text-ok-soft-ink">Compte enregistré.</span>
|
||
) : null}
|
||
</div>
|
||
</PersistentForm>
|
||
);
|
||
}
|