Checkpoint: OPEX DSI : ajout d'un écran vide dédié pour les années sans données, avec bouton "Créer depuis N-1" (copie toutes les lignes de l'année précédente avec confirmation AlertDialog) et bouton "Ajouter une ligne manuellement". La fonction handleCreateFromN1 clone les lignes N-1 avec budget_n1 = montant N-1 pour que les tendances soient calculables dès la création.
This commit is contained in:
@@ -454,6 +454,32 @@ export default function DsiOpex() {
|
||||
toast.info('Montants réinitialisés', { description: 'Les valeurs ont été restaurées depuis les données sources.' });
|
||||
}, [isValidated, annee]);
|
||||
|
||||
// Créer depuis l'année précédente (N-1)
|
||||
const handleCreateFromN1 = useCallback(() => {
|
||||
const anneeN1 = annee - 1;
|
||||
const stateN1 = loadOpexState(anneeN1);
|
||||
if (stateN1.lignes.length === 0) {
|
||||
toast.error(`Aucune donnée disponible pour ${anneeN1}`, {
|
||||
description: `Veuillez d'abord créer ou importer l'OPEX ${anneeN1}.`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Cloner les lignes de N-1 en mettant budget_n1 = montant N-1 et montant = montant N-1
|
||||
const lignesClonees: LigneOpex[] = stateN1.lignes.map(l => ({
|
||||
...l,
|
||||
id: l.isCustom ? genId() : l.id,
|
||||
budget_n1: l.montant,
|
||||
montant: l.montant,
|
||||
}));
|
||||
const newState: OpexAnneeState = { lignes: lignesClonees, validated: false, savedAt: new Date().toISOString() };
|
||||
setOpexState(newState);
|
||||
saveOpexState(annee, newState);
|
||||
setIsDirty(false);
|
||||
toast.success(`OPEX ${annee} créé depuis ${anneeN1}`, {
|
||||
description: `${lignesClonees.length} postes de charges copiés. Vous pouvez maintenant les modifier.`,
|
||||
});
|
||||
}, [annee]);
|
||||
|
||||
// Valider définitivement
|
||||
const handleValidate = useCallback(() => {
|
||||
const newState: OpexAnneeState = {
|
||||
@@ -822,8 +848,54 @@ export default function DsiOpex() {
|
||||
{/* Contenu principal */}
|
||||
<div className="flex-1 overflow-auto px-6 py-4">
|
||||
|
||||
{/* === ÉTAT VIDE : année sans données === */}
|
||||
{opexState.lignes.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center py-24 text-center">
|
||||
<div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mb-4">
|
||||
<BarChart3 className="w-8 h-8 text-muted-foreground" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-foreground mb-1" style={{ fontFamily: 'Sora, sans-serif' }}>
|
||||
Aucune donnée pour {annee}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground mb-6 max-w-sm">
|
||||
L'OPEX {annee} n'a pas encore été créé. Vous pouvez le créer en copiant les charges de {annee - 1} ou en ajoutant les lignes manuellement.
|
||||
</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button className="flex items-center gap-2 px-5 py-2.5 rounded-lg bg-primary text-primary-foreground font-medium text-sm hover:bg-primary/90 transition-all shadow-sm">
|
||||
<Plus className="w-4 h-4" />
|
||||
Créer depuis {annee - 1}
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Créer l'OPEX {annee} depuis {annee - 1} ?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Tous les postes de charges de {annee - 1} seront copiés comme base de travail pour {annee}. Les montants seront identiques et modifiables.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Annuler</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleCreateFromN1} className="bg-primary hover:bg-primary/90">
|
||||
Confirmer
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<button
|
||||
onClick={() => { setDialogMode('add'); setEditingLigne(null); }}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-lg border border-border bg-card font-medium text-sm hover:bg-muted transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Ajouter une ligne manuellement
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* === VUE PAR POSTE === */}
|
||||
{viewMode === 'postes' && (
|
||||
{viewMode === 'postes' && opexState.lignes.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
{selectedCategorie !== 'Toutes' && (
|
||||
<div className="flex items-center justify-between mb-3 px-1">
|
||||
|
||||
Reference in New Issue
Block a user