From 938a567cce0c7a22412b172563a961f9622e9f42 Mon Sep 17 00:00:00 2001 From: Manus Date: Wed, 3 Jun 2026 14:48:16 +0000 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Ajout=20du=20champ=20anneeDefaut?= =?UTF-8?q?=20dans=20ParametresContext=20(avec=20persistance=20localStorag?= =?UTF-8?q?e).=20Nouvelle=20section=20"Ann=C3=A9e=20d'ouverture=20par=20d?= =?UTF-8?q?=C3=A9faut"=20dans=20la=20page=20Param=C3=A8tres=20avec=20s?= =?UTF-8?q?=C3=A9lecteur=20de=20boutons=20(2025-2030).=20AnneeContext=20mi?= =?UTF-8?q?s=20=C3=A0=20jour=20pour=20utiliser=20cette=20valeur=20au=20pre?= =?UTF-8?q?mier=20lancement=20(quand=20aucune=20session=20n'est=20m=C3=A9m?= =?UTF-8?q?oris=C3=A9e).=20La=20page=20Param=C3=A8tres=20reste=20accessibl?= =?UTF-8?q?e=20via=20l'ic=C3=B4ne=20engrenage=20en=20bas=20de=20la=20sideb?= =?UTF-8?q?ar.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/contexts/AnneeContext.tsx | 23 +++++++++++- client/src/contexts/ParametresContext.tsx | 3 ++ client/src/pages/Parametres.tsx | 46 ++++++++++++++++++++++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/client/src/contexts/AnneeContext.tsx b/client/src/contexts/AnneeContext.tsx index 3c4bebd..99457da 100644 --- a/client/src/contexts/AnneeContext.tsx +++ b/client/src/contexts/AnneeContext.tsx @@ -6,6 +6,21 @@ import { createContext, useContext, useState, ReactNode } from 'react'; export const ANNEES_DISPONIBLES = [2025, 2026, 2027, 2028, 2029, 2030]; export const ANNEE_DEFAUT = 2027; +const PARAMETRES_STORAGE_KEY = 'itinova_budget_parametres'; + +function getAnneeDefautFromParametres(): number { + try { + const raw = localStorage.getItem(PARAMETRES_STORAGE_KEY); + if (raw) { + const parsed = JSON.parse(raw); + if (typeof parsed.anneeDefaut === 'number' && ANNEES_DISPONIBLES.includes(parsed.anneeDefaut)) { + return parsed.anneeDefaut; + } + } + } catch { /* ignore */ } + return ANNEE_DEFAUT; +} + interface AnneeContextType { annee: number; setAnnee: (a: number) => void; @@ -20,8 +35,12 @@ export function AnneeProvider({ children }: { children: ReactNode }) { const [annee, setAnneeState] = useState(() => { try { const stored = localStorage.getItem('itinova_annee_selectionnee'); - const parsed = stored ? parseInt(stored, 10) : ANNEE_DEFAUT; - return ANNEES_DISPONIBLES.includes(parsed) ? parsed : ANNEE_DEFAUT; + if (stored) { + const parsed = parseInt(stored, 10); + if (ANNEES_DISPONIBLES.includes(parsed)) return parsed; + } + // Pas de session mémorisée → utiliser l'année par défaut des paramètres + return getAnneeDefautFromParametres(); } catch { return ANNEE_DEFAUT; } }); diff --git a/client/src/contexts/ParametresContext.tsx b/client/src/contexts/ParametresContext.tsx index 017decf..d9f126a 100644 --- a/client/src/contexts/ParametresContext.tsx +++ b/client/src/contexts/ParametresContext.tsx @@ -8,6 +8,7 @@ export interface Parametres { seuilPortablesAns: number; coutFixe: number; coutPortable: number; + anneeDefaut: number; } const DEFAULTS: Parametres = { @@ -15,6 +16,7 @@ const DEFAULTS: Parametres = { seuilPortablesAns: 4, coutFixe: 450, coutPortable: 1000, + anneeDefaut: 2027, }; const STORAGE_KEY = 'itinova_budget_parametres'; @@ -29,6 +31,7 @@ function loadFromStorage(): Parametres { seuilPortablesAns: typeof parsed.seuilPortablesAns === 'number' ? parsed.seuilPortablesAns : DEFAULTS.seuilPortablesAns, coutFixe: typeof parsed.coutFixe === 'number' ? parsed.coutFixe : DEFAULTS.coutFixe, coutPortable: typeof parsed.coutPortable === 'number' ? parsed.coutPortable : DEFAULTS.coutPortable, + anneeDefaut: typeof parsed.anneeDefaut === 'number' ? parsed.anneeDefaut : DEFAULTS.anneeDefaut, }; } catch { return DEFAULTS; diff --git a/client/src/pages/Parametres.tsx b/client/src/pages/Parametres.tsx index a66b8df..8814595 100644 --- a/client/src/pages/Parametres.tsx +++ b/client/src/pages/Parametres.tsx @@ -14,7 +14,9 @@ import { ChevronLeft, Info, BarChart3, + Calendar, } from 'lucide-react'; +import { ANNEES_DISPONIBLES } from '../contexts/AnneeContext'; import { AppSidebar } from '../components/AppSidebar'; import { useParametres, PARAMETRES_DEFAULTS } from '../contexts/ParametresContext'; import { formatEuros } from '../lib/format'; @@ -25,6 +27,7 @@ interface FieldState { seuilPortablesAns: number; coutFixe: number; coutPortable: number; + anneeDefaut: number; } function SliderInput({ @@ -123,7 +126,8 @@ export default function Parametres() { draft.seuilFixesAns !== parametres.seuilFixesAns || draft.seuilPortablesAns !== parametres.seuilPortablesAns || draft.coutFixe !== parametres.coutFixe || - draft.coutPortable !== parametres.coutPortable; + draft.coutPortable !== parametres.coutPortable || + draft.anneeDefaut !== parametres.anneeDefaut; const handleSave = () => { setParametres(draft); @@ -300,6 +304,45 @@ export default function Parametres() { /> + {/* Section année par défaut */} +
+
+ +

+ Année d'ouverture par défaut +

+
+

+ L'année sélectionnée au démarrage de l'application lorsqu'aucune session précédente n'est mémorisée. +

+
+
+
+ +
+
+

Année par défaut

+

Exercice ouvert au premier lancement

+
+
+ {ANNEES_DISPONIBLES.map(a => ( + + ))} +
+
+
+
+ {/* Aperçu de l'impact */}
@@ -314,6 +357,7 @@ export default function Parametres() { { label: 'Seuil PC Portables', value: `${draft.seuilPortablesAns} ans`, changed: draft.seuilPortablesAns !== parametres.seuilPortablesAns }, { label: 'Coût fixe unitaire', value: formatEuros(draft.coutFixe), changed: draft.coutFixe !== parametres.coutFixe }, { label: 'Coût portable unitaire', value: formatEuros(draft.coutPortable), changed: draft.coutPortable !== parametres.coutPortable }, + { label: 'Année par défaut', value: `${draft.anneeDefaut}`, changed: draft.anneeDefaut !== parametres.anneeDefaut }, ].map((item) => (