diff --git a/client/src/App.tsx b/client/src/App.tsx index 3d20637..6950c14 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -10,12 +10,14 @@ import { ThemeProvider } from "./contexts/ThemeContext"; import { ParametresProvider } from "./contexts/ParametresContext"; import Home from "./pages/Home"; import Parametres from "./pages/Parametres"; +import Budget2027 from "./pages/Budget2027"; function Router() { return ( + diff --git a/client/src/data_bp2027.json b/client/src/data_bp2027.json new file mode 100644 index 0000000..9a66852 --- /dev/null +++ b/client/src/data_bp2027.json @@ -0,0 +1,847 @@ +{ + "meta": { + "titre": "BP2027 - Prévisionnel 2027 CAPEX DSI", + "nb_etablissements": 55, + "colonnes": { + "renouvellement_2025": "Parc informatique — Enveloppe Renouvellement 2025 (Source : ITINOVA Siège)", + "renouvellement_2026": "Parc informatique — Enveloppe Renouvellement 2026 (Source : ITINOVA Siège)", + "renouvellement_2027": "Parc informatique — Renouvellement 2027 (calculé par vétusté)", + "machines_supplementaires": "Parc informatique — Acquisition machines supplémentaires", + "appel_malade": "Système Appel Malade / Anti Fugue", + "telephonie": "Installation téléphonique", + "wifi": "Réseau WiFi", + "video_surveillance": "Vidéo Surveillance", + "copieurs": "Copieurs", + "visio": "Équipement Visio Conférence", + "autres": "Autres investissements SI", + "commentaires": "Commentaires" + } + }, + "etablissements": [ + { + "code": "1001BPT", + "nom": "FAM ST JOSEPH", + "renouvellement_2025": 0, + "renouvellement_2026": 7141, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1001GRF", + "nom": "EAM / EANM CORBONOD", + "renouvellement_2025": 0, + "renouvellement_2026": 8966, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1001VAR", + "nom": "ITEP / SESSAD CHATEAU DE VAREY", + "renouvellement_2025": 0, + "renouvellement_2026": 13219, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1015CHA", + "nom": "MECS CHANTECLAIR", + "renouvellement_2025": 0, + "renouvellement_2026": 6027, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1031MER", + "nom": "MECS MERLY", + "renouvellement_2025": 0, + "renouvellement_2026": 14184, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1038MBN", + "nom": "ITEP / SESSAD MONTBERNIER", + "renouvellement_2025": 0, + "renouvellement_2026": 17945, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1038RAC", + "nom": "MECS L'ETOILE DU RACHAIS", + "renouvellement_2025": 0, + "renouvellement_2026": 9157, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1042CLA", + "nom": "MECS LA CLAIRIERE", + "renouvellement_2025": 0, + "renouvellement_2026": 7059, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1063CRD", + "nom": "CRDV", + "renouvellement_2025": 0, + "renouvellement_2026": 22000, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069BOU", + "nom": "IME JEAN BOURJADE", + "renouvellement_2025": 0, + "renouvellement_2026": 12835, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069CJO", + "nom": "ITEP SESSAD CLAIR'JOIE", + "renouvellement_2025": 0, + "renouvellement_2026": 16000, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069GOR", + "nom": "CEM HENRY GORMAND", + "renouvellement_2025": 0, + "renouvellement_2026": 26272, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069IVP", + "nom": "IMP INSTITUT ST VINCENT DE PAUL", + "renouvellement_2025": 0, + "renouvellement_2026": 12850, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069POR", + "nom": "MECS LE PORT", + "renouvellement_2025": 0, + "renouvellement_2026": 5693, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1069SEG", + "nom": "IME EDOUARD SEGUIN", + "renouvellement_2025": 0, + "renouvellement_2026": 6758, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083ADV", + "nom": "CHRS LES ADRETS DU VAR", + "renouvellement_2025": 0, + "renouvellement_2026": 11550, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083MAS", + "nom": "IME MASYLVA", + "renouvellement_2025": 0, + "renouvellement_2026": 1900, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083MIC", + "nom": "ESAT LES MIMOSAS BC", + "renouvellement_2025": 0, + "renouvellement_2026": 0, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083MIS", + "nom": "ESAT LES MIMOSAS BS", + "renouvellement_2025": 0, + "renouvellement_2026": 1900, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083QVT", + "nom": "SIAO 115 TOULON", + "renouvellement_2025": 0, + "renouvellement_2026": 5700, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083SAV", + "nom": "SAVS LES MIMOSAS", + "renouvellement_2025": 0, + "renouvellement_2026": 0, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1083SYL", + "nom": "IME SYLVABELLE", + "renouvellement_2025": 0, + "renouvellement_2026": 9250, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1084CAC", + "nom": "ESAT LES ATELIERS CHAUD D'ABRIEU BC", + "renouvellement_2025": 0, + "renouvellement_2026": 0, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1084CAS", + "nom": "ESAT LES ATELIERS CHAUD D'ABRIEU BS", + "renouvellement_2025": 0, + "renouvellement_2026": 3500, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1084RAM", + "nom": "FOYER DE VIE LA RAMADE", + "renouvellement_2025": 0, + "renouvellement_2026": 1500, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1084ROU", + "nom": "FOYER D'HEBERGEMENT LA ROUVILLIERE", + "renouvellement_2025": 0, + "renouvellement_2026": 1000, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "1084SLM", + "nom": "SAVS LA MERCI-SAVA84", + "renouvellement_2025": 0, + "renouvellement_2026": 500, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2001AJB", + "nom": "ACCUEUIL DE JOUR BON REPOS", + "renouvellement_2025": 0, + "renouvellement_2026": 0, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2001BRP", + "nom": "EHPAD BON REPOS", + "renouvellement_2025": 0, + "renouvellement_2026": 3263, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2001GRE", + "nom": "EHPAD LE CLOS DE GREX", + "renouvellement_2025": 0, + "renouvellement_2026": 8967, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2001MUS", + "nom": "EHPAD ST VINCENT DE PAUL BELLEGARDE", + "renouvellement_2025": 0, + "renouvellement_2026": 8303, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2001ROS", + "nom": "EHPAD SOEUR ROSALIE", + "renouvellement_2025": 0, + "renouvellement_2026": 5924, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2003BBN", + "nom": "EHPAD ST JOSEPH", + "renouvellement_2025": 0, + "renouvellement_2026": 4992, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2011MON", + "nom": "EHPAD ST VINCENT DE PAUL MONTOLIEU", + "renouvellement_2025": 0, + "renouvellement_2026": 6006, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2013ANG", + "nom": "SSR L'ANGELUS", + "renouvellement_2025": 0, + "renouvellement_2026": 10570, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2021BEA", + "nom": "EHPAD ST VINCENT DE PAUL VIGNOLES", + "renouvellement_2025": 0, + "renouvellement_2026": 5108, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2021MOU", + "nom": "EHPAD LES LOGIS DU PARC MOUSSIER", + "renouvellement_2025": 0, + "renouvellement_2026": 4728, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2026STA", + "nom": "EHPAD SAINTE ANNE", + "renouvellement_2025": 0, + "renouvellement_2026": 6190, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2026STM", + "nom": "EHPAD SAINTE MARTHE", + "renouvellement_2025": 0, + "renouvellement_2026": 5341, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2032RSR", + "nom": "EHPAD LA ROSERAIE", + "renouvellement_2025": 0, + "renouvellement_2026": 5589, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2038ROC", + "nom": "EHPAD NOTRE DAME DES ROCHES", + "renouvellement_2025": 0, + "renouvellement_2026": 8053, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2042PRO", + "nom": "EHPAD LA PROVIDENCE", + "renouvellement_2025": 0, + "renouvellement_2026": 17079, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2063ABV", + "nom": "SSR AUVERGNE BASSE VISION", + "renouvellement_2025": 0, + "renouvellement_2026": 2031, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2063VSJ", + "nom": "EHPAD LA VILLA SAINT JEAN", + "renouvellement_2025": 0, + "renouvellement_2026": 5324, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2064CON", + "nom": "SSR VILLA CONCHA BERRI", + "renouvellement_2025": 0, + "renouvellement_2026": 14267, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2064CSH", + "nom": "CSI HENDAYE", + "renouvellement_2025": 0, + "renouvellement_2026": 0, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2069MAU", + "nom": "EHPAD RESIDENCE CARDINAL MAURIN", + "renouvellement_2025": 0, + "renouvellement_2026": 7455, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2069PET", + "nom": "EHPAD DOROTHEE PETIT", + "renouvellement_2025": 0, + "renouvellement_2026": 5406, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2069SAL", + "nom": "EHPAD NOTRE DAME DE LA SALETTE", + "renouvellement_2025": 0, + "renouvellement_2026": 9206, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2069THE", + "nom": "EHPAD LOUISE THERESE", + "renouvellement_2025": 0, + "renouvellement_2026": 4111, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2073NDM", + "nom": "EHPAD FOYER NOTRE-DAME", + "renouvellement_2025": 0, + "renouvellement_2026": 7507, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2074MAR", + "nom": "SSR LA MARTERAYE", + "renouvellement_2025": 0, + "renouvellement_2026": 22573, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2081ANC", + "nom": "EHPAD LOUISE ANCEAU", + "renouvellement_2025": 0, + "renouvellement_2026": 5776, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2081BLA", + "nom": "EHPAD SAINT VINCENT DE PAUL BLAN", + "renouvellement_2025": 0, + "renouvellement_2026": 5806, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + }, + { + "code": "2083SCL", + "nom": "EHPAD SAINTE CATHERINE LABOURE", + "renouvellement_2025": 0, + "renouvellement_2026": 7368, + "machines_supplementaires": 0, + "appel_malade": 0, + "telephonie": 0, + "wifi": 0, + "video_surveillance": 0, + "copieurs": 0, + "visio": 0, + "autres": 0, + "commentaires": "" + } + ] +} \ No newline at end of file diff --git a/client/src/pages/Budget2027.tsx b/client/src/pages/Budget2027.tsx new file mode 100644 index 0000000..400f50c --- /dev/null +++ b/client/src/pages/Budget2027.tsx @@ -0,0 +1,596 @@ +// Budget2027.tsx — Page de construction du budget CAPEX DSI 2027 +// Design: Corporate Modernism — Itinova Budget SI 2027 +// Chaque directeur sélectionne son établissement et remplit les champs optionnels. +// Le renouvellement 2027 est pré-rempli depuis les données de vétusté. + +import { useState, useMemo, useEffect } from 'react'; +import { useLocation } from 'wouter'; +import { + Building2, + BarChart3, + Settings, + ChevronDown, + Monitor, + PlusCircle, + Bell, + Phone, + Wifi, + Camera, + Printer, + Video, + Package, + Info, + CheckCircle, + FileText, + RotateCcw, + TrendingUp, + AlertCircle, +} from 'lucide-react'; +import bp2027Raw from '../data_bp2027.json'; +import budgetRaw from '../data_budget.json'; +import { useParametres } from '../contexts/ParametresContext'; +import { formatEuros } from '../lib/format'; +import type { BP2027Data, EtablissementBP, BudgetFormValues } from '../types/bp2027'; +import type { BudgetData } from '../types/budget'; + +const bp2027Data = bp2027Raw as BP2027Data; +const budgetData = budgetRaw as BudgetData; + +const STORAGE_KEY = 'itinova_budget2027_saisies'; + +// Icônes par clé de champ +const ICON_MAP: Record = { + renouvellement_2027: Monitor, + machines_supplementaires: PlusCircle, + appel_malade: Bell, + telephonie: Phone, + wifi: Wifi, + video_surveillance: Camera, + copieurs: Printer, + visio: Video, + autres: Package, +}; + +// Couleurs par champ +const COLOR_MAP: Record = { + renouvellement_2027: 'blue', + machines_supplementaires: 'indigo', + appel_malade: 'red', + telephonie: 'green', + wifi: 'cyan', + video_surveillance: 'orange', + copieurs: 'purple', + visio: 'teal', + autres: 'slate', +}; + +const COLOR_CLASSES: Record = { + blue: { bg: 'bg-blue-600', text: 'text-blue-700', border: 'border-blue-200', light: 'bg-blue-50' }, + indigo: { bg: 'bg-indigo-600', text: 'text-indigo-700', border: 'border-indigo-200', light: 'bg-indigo-50' }, + red: { bg: 'bg-red-500', text: 'text-red-700', border: 'border-red-200', light: 'bg-red-50' }, + green: { bg: 'bg-emerald-600',text: 'text-emerald-700',border: 'border-emerald-200',light: 'bg-emerald-50' }, + cyan: { bg: 'bg-cyan-600', text: 'text-cyan-700', border: 'border-cyan-200', light: 'bg-cyan-50' }, + orange: { bg: 'bg-orange-500', text: 'text-orange-700', border: 'border-orange-200', light: 'bg-orange-50' }, + purple: { bg: 'bg-purple-600', text: 'text-purple-700', border: 'border-purple-200', light: 'bg-purple-50' }, + teal: { bg: 'bg-teal-600', text: 'text-teal-700', border: 'border-teal-200', light: 'bg-teal-50' }, + slate: { bg: 'bg-slate-500', text: 'text-slate-700', border: 'border-slate-200', light: 'bg-slate-50' }, +}; + +const CHAMPS: { key: keyof BudgetFormValues; label: string; description: string }[] = [ + { key: 'renouvellement_2027', label: 'Renouvellement parc informatique', description: 'Pré-rempli depuis le calcul de vétusté — modifiable' }, + { key: 'machines_supplementaires', label: 'Acquisition machines supplémentaires', description: 'Nouveaux postes hors renouvellement' }, + { key: 'appel_malade', label: 'Système Appel Malade / Anti Fugue', description: 'Équipements d\'appel et de sécurité' }, + { key: 'telephonie', label: 'Installation téléphonique', description: 'Infrastructure téléphonique fixe et mobile' }, + { key: 'wifi', label: 'Réseau WiFi', description: 'Infrastructure réseau sans fil' }, + { key: 'video_surveillance', label: 'Vidéo Surveillance', description: 'Caméras et système de surveillance' }, + { key: 'copieurs', label: 'Copieurs', description: 'Imprimantes et copieurs multifonctions' }, + { key: 'visio', label: 'Équipement Visio Conférence', description: 'Matériel de visioconférence' }, + { key: 'autres', label: 'Autres investissements SI', description: 'Tout autre investissement informatique' }, +]; + +function loadSaisies(): Record> { + try { + const raw = localStorage.getItem(STORAGE_KEY); + return raw ? JSON.parse(raw) : {}; + } catch { return {}; } +} + +function saveSaisies(data: Record>) { + try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch {} +} + +function getDefaultValues(etabCode: string, renouvellement2027: number): BudgetFormValues { + return { + renouvellement_2027: renouvellement2027, + machines_supplementaires: 0, + appel_malade: 0, + telephonie: 0, + wifi: 0, + video_surveillance: 0, + copieurs: 0, + visio: 0, + autres: 0, + commentaires: '', + }; +} + +// Calcule le budget de renouvellement 2027 depuis les données de vétusté +function getBudgetRenouvellement2027(code: string, parametres: { coutFixe: number; coutPortable: number; seuilFixesAns: number; seuilPortablesAns: number }): number { + const etab = budgetData.etablissements.find(e => e.code === code); + if (!etab) return 0; + const nbFixesR = (etab.fixes ?? []).filter(f => f.age_ans !== null && f.age_ans >= parametres.seuilFixesAns).length; + const nbPortablesR = (etab.portables ?? []).filter(p => p.age_ans !== null && p.age_ans >= parametres.seuilPortablesAns).length; + return nbFixesR * parametres.coutFixe + nbPortablesR * parametres.coutPortable; +} + +function CurrencyInput({ + value, + onChange, + placeholder = '0', + disabled = false, +}: { + value: number; + onChange: (v: number) => void; + placeholder?: string; + disabled?: boolean; +}) { + const [raw, setRaw] = useState(value === 0 ? '' : String(value)); + + useEffect(() => { + setRaw(value === 0 ? '' : String(value)); + }, [value]); + + return ( +
+ { + setRaw(e.target.value); + const v = parseFloat(e.target.value); + onChange(isNaN(v) || v < 0 ? 0 : Math.round(v)); + }} + onBlur={() => setRaw(value === 0 ? '' : String(value))} + className={`w-full pl-8 pr-12 py-2.5 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary tabular-nums transition-colors ${ + disabled ? 'bg-muted/50 text-muted-foreground cursor-not-allowed' : 'bg-background' + }`} + /> + + TTC +
+ ); +} + +export default function Budget2027() { + const [, navigate] = useLocation(); + const { parametres } = useParametres(); + const [selectedCode, setSelectedCode] = useState(''); + const [saisies, setSaisies] = useState>>(loadSaisies); + const [saved, setSaved] = useState(false); + const [searchEtab, setSearchEtab] = useState(''); + const [dropdownOpen, setDropdownOpen] = useState(false); + + // Établissement sélectionné (depuis BP2027) + const selectedBP = useMemo( + () => bp2027Data.etablissements.find(e => e.code === selectedCode) ?? null, + [selectedCode] + ); + + // Budget renouvellement 2027 calculé par vétusté + const renouvellement2027Calcule = useMemo( + () => selectedCode ? getBudgetRenouvellement2027(selectedCode, parametres) : 0, + [selectedCode, parametres] + ); + + // Valeurs du formulaire pour l'établissement sélectionné + const formValues = useMemo(() => { + const defaults = getDefaultValues(selectedCode, renouvellement2027Calcule); + const saved = saisies[selectedCode] ?? {}; + return { + ...defaults, + ...saved, + // Si pas encore saisi, on prend le calculé + renouvellement_2027: saved.renouvellement_2027 !== undefined ? saved.renouvellement_2027 : renouvellement2027Calcule, + }; + }, [selectedCode, saisies, renouvellement2027Calcule]); + + // Total BP 2027 + const totalBP2027 = useMemo(() => { + const v = formValues; + return ( + v.renouvellement_2027 + + v.machines_supplementaires + + v.appel_malade + + v.telephonie + + v.wifi + + v.video_surveillance + + v.copieurs + + v.visio + + v.autres + ); + }, [formValues]); + + const updateField = (key: keyof BudgetFormValues, value: number | string) => { + setSaisies(prev => { + const next = { + ...prev, + [selectedCode]: { + ...(prev[selectedCode] ?? {}), + [key]: value, + }, + }; + saveSaisies(next); + return next; + }); + setSaved(false); + }; + + const handleSave = () => { + saveSaisies(saisies); + setSaved(true); + setTimeout(() => setSaved(false), 2500); + }; + + const handleReset = () => { + setSaisies(prev => { + const next = { ...prev }; + delete next[selectedCode]; + saveSaisies(next); + return next; + }); + }; + + // Établissements filtrés pour le dropdown + const etabsFiltres = useMemo(() => { + const q = searchEtab.toLowerCase(); + return bp2027Data.etablissements.filter( + e => e.nom.toLowerCase().includes(q) || e.code.toLowerCase().includes(q) + ); + }, [searchEtab]); + + // Nb d'établissements avec saisie + const nbSaisies = Object.keys(saisies).length; + + return ( +
+ {/* Sidebar */} + + + {/* Contenu principal */} +
+ {/* En-tête */} +
+
+
+

+ Construction Budget 2027 +

+

+ Campagne budgétaire CAPEX DSI — Prévisionnel 2027 +

+
+ {selectedCode && ( +
+ + +
+ )} +
+
+ +
+ + {/* Sélection établissement */} +
+
+ +

+ Sélection de l'établissement +

+
+ +
+ + + {dropdownOpen && ( +
+
+ setSearchEtab(e.target.value)} + className="w-full px-3 py-2 text-sm border border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/30" + autoFocus + /> +
+
+ {etabsFiltres.length === 0 ? ( +

Aucun résultat

+ ) : ( + etabsFiltres.map(e => ( + + )) + )} +
+
+ )} +
+
+ + {/* Formulaire (visible uniquement si établissement sélectionné) */} + {!selectedCode && ( +
+
+ +
+

+ Sélectionnez un établissement +

+

+ Choisissez votre établissement dans la liste ci-dessus pour accéder au formulaire de construction budgétaire. +

+
+ )} + + {selectedCode && selectedBP && ( + <> + {/* Données informatives 2025/2026 */} +
+
+ +
+

+ Données historiques — à titre informatif +

+

+ Enveloppes de renouvellement allouées par le Siège Itinova (non modifiables) +

+
+
+
+
+

Renouvellement 2025

+

+ {selectedBP.renouvellement_2025 > 0 ? formatEuros(selectedBP.renouvellement_2025) : '—'} +

+

Enveloppe Siège

+
+
+

Renouvellement 2026

+

+ {selectedBP.renouvellement_2026 > 0 ? formatEuros(selectedBP.renouvellement_2026) : '—'} +

+

Enveloppe Siège

+
+
+
+ + {/* Formulaire de saisie */} +
+
+ +

+ Budget prévisionnel 2027 — Saisie directeur +

+ (tous les champs sont optionnels) +
+ + {CHAMPS.map(champ => { + const Icon = ICON_MAP[champ.key] ?? Package; + const color = COLOR_MAP[champ.key] ?? 'slate'; + const cls = COLOR_CLASSES[color]; + const isRenouvellement = champ.key === 'renouvellement_2027'; + const val = formValues[champ.key]; + const numVal = typeof val === 'number' ? val : 0; + + return ( +
0 ? `${cls.border} ${cls.light}` : 'border-border' + }`} + > +
+
+ +
+
+
+

{champ.label}

+ {isRenouvellement && ( + + Pré-rempli + + )} +
+

{champ.description}

+ {isRenouvellement && renouvellement2027Calcule > 0 && ( +
+ +

+ Proposé par vétusté : {formatEuros(renouvellement2027Calcule)} + {formValues.renouvellement_2027 !== renouvellement2027Calcule && ( + (modifié) + )} +

+
+ )} + updateField(champ.key, v)} + /> +
+ {numVal > 0 && ( +
+ + {formatEuros(numVal)} + +
+ )} +
+
+ ); + })} + + {/* Commentaires */} +
+
+ +

Commentaires

+ (optionnel) +
+