Toutes les offres
Fichier : apps/web/src/pages/Contribute/components/tabs/AllOffers.tsx
Features
| Feature | Statut |
|---|---|
| Mode lecture/edition | FAIT |
| Filtre par fournisseur | FAIT |
| Filtre par type d'offre | FAIT |
| Regroupement par nom d'offre | FAIT |
| Edition du nom d'offre | FAIT |
| Edition inline des offres | FAIT |
| Suppression de puissance | FAIT |
| Ajout de puissance | FAIT |
| Creation nouveau groupe | FAIT |
| Recapitulatif avant soumission | FAIT |
| Soumission des modifications | FAIT |
| Creation nouveau fournisseur | FAIT |
| Suppression de fournisseur | FAIT |
| Ajout nouvelle offre | FAIT |
| Gestion date par offre | FAIT |
| Toggle historique des tarifs | FAIT |
| Duplication des tarifs | FAIT |
| Warning perte de modifications | FAIT |
| Mode IA (import JSON) | FAIT |
Details implementation
Mode lecture/edition (FAIT)
- Mode lecture (par defaut) : Affichage simple des offres en lecture seule
- Mode edition : Permet de modifier les tarifs, supprimer et ajouter des puissances
- Bouton "Proposer des modifications" en haut a droite pour passer en mode edition
- Bouton "Mode lecture" pour revenir au mode lecture (reset toutes les modifications)
- Encadre d'information en mode edition rappelant :
- Selectionner un fournisseur et un type d'offre
- Chaque soumission concerne un seul fournisseur/type a la fois
UI :
- Bouton mode lecture :
bg-gray-100 dark:bg-gray-700 - Bouton mode edition :
bg-primary-600 text-white - Encadre info :
bg-blue-50 dark:bg-blue-900/20 border-blue-200
Filtre par fournisseur (FAIT)
- Boutons pour selectionner un fournisseur
- EDF affiche en premier par defaut
- Compteur d'offres par fournisseur
Filtre par type d'offre (FAIT)
- Boutons dynamiques selon le fournisseur selectionne
- Types supportes : BASE, HC_HP, TEMPO, EJP, ZEN_FLEX, ZEN_WEEK_END, SEASONAL
- Reset automatique quand on change de fournisseur
Regroupement par nom d'offre (FAIT)
Les offres sont regroupees par nom "clean" (sans la puissance et le type d'offre).
Exemple : Pour Alpiq avec des offres "Stable 6 kVA", "Stable 9 kVA", "Stable 12 kVA", toutes ces offres sont regroupees sous un seul en-tete "Stable".
Fonctionnement :
- Extraction du nom "clean" via
getCleanOfferName()qui retire :- La puissance (ex: "6 kVA", "9kVA")
- Le type d'offre (ex: "BASE", "HC_HP", "TEMPO")
- Les tirets et espaces superflus
- Tri des groupes par ordre alphabetique
- Tri des offres dans chaque groupe par puissance croissante
- Affichage d'un en-tete par groupe avec le nombre de puissances
UI :
- En-tete de groupe : bordure basse
border-b border-gray-200 - Nombre de puissances :
text-xs text-gray-500
Edition du nom d'offre (FAIT)
En mode edition, l'en-tete de chaque groupe d'offres devient editable.
Fonctionnement :
- En mode lecture : affichage simple du nom du groupe
- En mode edition : champ input text remplace le titre
- Highlight ambre quand le nom est modifie
- Badge "Nom modifie" affiche a cote du champ
State :
const [editedOfferNames, setEditedOfferNames] = useState<
Record<string, string>
>({});
UI :
- Input en mode edition :
border-2 rounded-lgavec focus ring - Bordure ambre si modifie :
border-amber-400 dark:border-amber-600 - Badge :
text-xs text-amber-600 bg-amber-100
Note : Cette fonctionnalite permet de proposer un renommage du nom commercial de l'offre (ex: "Stable" → "Fixe Vert").
Creation nouveau groupe (FAIT)
Permet de proposer la creation d'un nouveau groupe d'offres (nouveau nom commercial) pour un fournisseur/type d'offre existant.
Exemple : Pour Alpiq qui a deja "Stable", on peut proposer un nouveau groupe "Vert Fixe" avec ses propres puissances et tarifs.
Fonctionnement :
- Bouton "Creer un nouveau groupe d'offres" en bas de la liste (fond bleu)
- Clic cree un nouveau groupe avec un champ nom et une puissance vide
- Possibilite d'ajouter plusieurs puissances a chaque groupe
- Possibilite de creer plusieurs groupes en une seule soumission
- Bouton X pour supprimer un groupe entier
Formulaire par groupe :
- Champ texte pour le nom du groupe (ex: "Vert Fixe", "Eco Plus")
- Liste des puissances avec tarifs selon le type d'offre
- Bouton pour ajouter une puissance au groupe
- Bouton X pour supprimer le groupe
State :
const [newGroups, setNewGroups] = useState<
Array<{
name: string;
powers: Array<{
power: number;
fields: Record<string, string>;
}>;
}>
>([]);
UI :
- Conteneur groupe :
bg-green-50 border-2 border-dashed border-green-400 - En-tete : bordure basse
border-green-300 - Badge :
text-xs text-green-600 bg-green-100"Nouveau groupe" - Bouton creer :
bg-blue-50 border-dashed border-blue-300avec iconesPackage+Plus
Soumission :
- Type de contribution :
NEW_OFFER - Une contribution par puissance dans le groupe
existing_provider_id: ID du fournisseur selectionneoffer_name:{nom_groupe} - {puissance} kVA(format d'envoi, inchangé) ; le serveur ne garde que le nom commercial (clean_offer_name, MED-22), la puissance étant danspower_kva- Description : "Creation d'un nouveau groupe d'offres..."
Recap :
Dans le recapitulatif, les nouveaux groupes sont affiches dans une section bleue avec :
- Le nom du groupe
- La liste des puissances avec leurs tarifs
Edition inline des offres (FAIT)
- Champs input type="number" avec step="0.0001"
- Highlight jaune/ambre quand une valeur est modifiee
- Badge "Modifie" sur l'offre
- Champs selon le type d'offre :
- BASE : Abonnement, Prix Base
- HC_HP : Abonnement, HC, HP
- TEMPO : Abonnement, Bleu HC/HP, Blanc HC/HP, Rouge HC/HP
- EJP : Abonnement, Normal, Pointe
- ZEN_FLEX : Abonnement, Eco HC/HP, Sobriete HC/HP
- ZEN_WEEK_END : Abonnement, HC, HP, Week-end HC/HP
- SEASONAL : Abonnement, Hiver HC/HP, Ete HC/HP
Suppression de puissance (FAIT)
Permet de proposer la suppression d'une puissance existante pour un fournisseur/type d'offre.
- Icone corbeille rouge sur chaque ligne d'offre
- Clic sur la corbeille marque la puissance pour suppression
- Ligne devient rouge avec opacite reduite et texte barre
- Badge "A supprimer" affiche sur la ligne
- Icone annulation (Undo) pour annuler la suppression
- Reset automatique quand on change de fournisseur ou type d'offre
UI :
- Bouton corbeille :
text-red-500 dark:text-red-400 - Ligne marquee :
border-red-400 bg-red-50 opacity-60 - Badge :
text-red-600 bg-red-100
Soumission :
- Type de contribution :
UPDATE_OFFER - Nom de l'offre prefixe avec
[SUPPRESSION] - Description : "Demande de suppression de la puissance X kVA pour Fournisseur (Type)"
Backend (approbation) :
Quand l'admin approuve une contribution de suppression :
- Le backend detecte le prefixe
[SUPPRESSION]dansoffer_name - Recherche l'offre par
provider_id,offer_typeetpower_kva - Supprime l'offre de la base de donnees
Ajout de puissance (FAIT)
Permet de proposer l'ajout de plusieurs nouvelles puissances pour un fournisseur/type d'offre existant.
Fonctionnement :
- Bouton "Ajouter une puissance" en bas de la liste des offres
- Chaque clic ajoute une nouvelle ligne verte au-dessus du bouton
- Possibilite d'ajouter plusieurs puissances en une seule soumission
- Chaque ligne contient :
- Champ de saisie pour la puissance (kVA) - input number
- Champs de tarification selon le type d'offre
- Bouton X pour supprimer cette ligne
- Badge "Nouveau" sur chaque ligne ajoutee
- Reset automatique quand on change de fournisseur ou type d'offre
Champs de tarification selon le type d'offre :
- BASE : Abonnement (€/mois), Base (€/kWh)
- HC_HP : Abonnement (€/mois), HC (€/kWh), HP (€/kWh)
- TEMPO : Abonnement uniquement (tarifs specifiques apres validation)
- Autres types : Abonnement uniquement (tarifs specifiques apres validation)
UI :
- Conteneur :
bg-green-50 dark:bg-green-900/20 - Bordure :
border-dashed border-green-300(vide) ouborder-green-400(avec donnees) - Icone + :
text-green-600 dark:text-green-400 - Champs : bordure verte
border-green-300 dark:border-green-600
Soumission :
- Type de contribution :
NEW_OFFER existing_provider_id: ID du fournisseur selectionnepower_kva: puissance saisiepricing_data: tarifs saisis (subscription_price, base_price, hc_price, hp_price)- Description : "Ajout de la puissance X kVA pour Fournisseur (Type)"
Recapitulatif avant soumission (FAIT)
- Section recapitulative affichee quand des modifications existent
- Affiche les modifications de tarifs avec ancienne/nouvelle valeur
- Affiche les modifications de puissances dans une section dediee :
- Suppressions en rouge avec icone corbeille
- Ajouts en vert avec icone + et details des tarifs saisis (supporte plusieurs ajouts)
- Affiche les nouveaux groupes d'offres dans une section bleue
- Champ lien vers la fiche tarifaire officielle :
- Obligatoire pour les utilisateurs standards
- Optionnel pour les admins/moderateurs
- Boutons "Annuler les modifications" et "Envoyer les contributions"
Recap ajout de puissance :
Le recapitulatif affiche les informations completes :
- Puissance en kVA
- Abonnement en €/mois (si renseigne)
- Tarif Base en €/kWh (si renseigne)
- Tarif HC en €/kWh (si renseigne, couleur bleue)
- Tarif HP en €/kWh (si renseigne, couleur rouge)
Soumission des modifications (FAIT)
- Types de contribution :
UPDATE_OFFER: modification de tarifs existants ou demande de suppressionNEW_OFFER: ajout d'une nouvelle puissance (une contribution par puissance ajoutee)
- Toast de succes/erreur apres soumission
- Invalidation du cache
my-contributions - Reset des modifications apres succes (editedOffers, priceSheetUrl, powersToRemove, newPowersData, newGroups)
State management
// Mode lecture (false) ou edition (true)
const [isEditMode, setIsEditMode] = useState(false);
// Editions de tarifs existants
const [editedOffers, setEditedOffers] = useState<
Record<string, Record<string, string>>
>({});
// Puissances a supprimer
const [powersToRemove, setPowersToRemove] = useState<number[]>([]);
// Nouvelles puissances a ajouter avec leurs tarifs (supporte plusieurs ajouts)
const [newPowersData, setNewPowersData] = useState<
Array<{
power: number;
fields: Record<string, string>;
}>
>([]);
// URL de la fiche tarifaire (obligatoire sauf admin/moderateur)
const [priceSheetUrl, setPriceSheetUrl] = useState("");
// Creation nouveau fournisseur (formulaire inline)
const [isAddingProvider, setIsAddingProvider] = useState(false);
const [newProviderName, setNewProviderName] = useState("");
const [newProviderOfferType, setNewProviderOfferType] = useState("");
// Fournisseurs a supprimer
const [providersToRemove, setProvidersToRemove] = useState<string[]>([]);
// Ajout nouvelle offre a un fournisseur existant
const [isAddingOffer, setIsAddingOffer] = useState(false);
const [newOfferType, setNewOfferType] = useState("");
// Edition des noms d'offres (cle = nom original clean, valeur = nouveau nom)
const [editedOfferNames, setEditedOfferNames] = useState<
Record<string, string>
>({});
Computed values (useMemo)
// Regroupement des offres par nom "clean"
const groupedOffers = useMemo(() => {
const groups: Record<string, typeof providerOffers> = {};
for (const offer of providerOffers) {
const cleanName = getCleanOfferName(offer.name);
if (!groups[cleanName]) groups[cleanName] = [];
groups[cleanName].push(offer);
}
// Tri par puissance dans chaque groupe
for (const groupName of Object.keys(groups)) {
groups[groupName].sort((a, b) => powerA - powerB);
}
return groups;
}, [providerOffers]);
// Liste des noms de groupes tries alphabetiquement
const groupNames = useMemo(() => {
return Object.keys(groupedOffers).sort((a, b) => a.localeCompare(b));
}, [groupedOffers]);
API utilisee
energyApi.getProviders(): liste des fournisseursenergyApi.getOffers(): liste des offresenergyApi.submitContribution(): soumission d'une contribution
Creation d'un nouveau fournisseur (FAIT)
Permet de proposer l'ajout d'un nouveau fournisseur d'energie directement depuis l'onglet "Toutes les offres".
Fonctionnement :
- Bouton
+pleine largeur en bas de la liste des fournisseurs (visible uniquement en mode edition) - Style bordure pointillee pour indiquer une action d'ajout
- Clic transforme le bouton en formulaire inline (pas de modal)
Formulaire inline :
- Champ texte pour le nom du fournisseur (obligatoire)
- Dropdown pour selectionner le type d'offre parmi tous les types existants
- Section d'ajout de puissances (meme interface que l'ajout pour fournisseurs existants)
- Bouton X pour annuler et revenir au bouton
+
Comportement :
- Quand on clique sur
+, toutes les puissances existantes se vident - On peut ajouter une ou plusieurs puissances avec leurs tarifs
- Les types d'offres disponibles sont extraits de toutes les offres existantes
UI :
- Bouton :
border-dashed border-primary-300avec iconePlus, pleine largeur - Formulaire : fond vert clair
bg-green-50 dark:bg-green-900/20 - Champ nom : bordure verte
border-green-300 - Dropdown type : meme style que les autres selects
Soumission :
- Type de contribution :
NEW_PROVIDER - Inclut le nom du fournisseur, type d'offre, et variantes de puissance
- Invalide les caches
my-contributionsetenergy-providers - Toast de succes/erreur
- Reset du formulaire apres succes
Suppression de fournisseur (FAIT)
Permet de proposer la suppression d'un fournisseur existant.
Fonctionnement :
- En mode edition, survol d'un bouton fournisseur affiche une icone corbeille
- Clic sur la corbeille marque le fournisseur pour suppression
- Le bouton devient rouge avec texte barre
- Badge "A supprimer" affiche sur le bouton
- Clic sur l'icone Undo annule la suppression
UI :
- Icone corbeille :
text-red-400au survol - Bouton marque :
bg-red-100 dark:bg-red-900/30 border-red-400 - Texte :
line-through text-red-600 - Badge :
bg-red-100 text-red-600
Soumission :
- Type de contribution :
UPDATE_OFFER - Nom de l'offre prefixe avec
[SUPPRESSION_FOURNISSEUR] - Description : "Demande de suppression du fournisseur NomFournisseur"
Backend (approbation) :
Quand l'admin approuve une contribution de suppression de fournisseur :
- Le backend detecte le prefixe
[SUPPRESSION_FOURNISSEUR]dansoffer_name - Recherche le fournisseur par son nom
- Supprime le fournisseur et toutes ses offres de la base de donnees
Ajout nouvelle offre (FAIT)
Permet de proposer l'ajout d'un nouveau type d'offre pour un fournisseur existant.
Fonctionnement :
- Bouton "Proposer une nouvelle offre" en bas des types d'offres (visible uniquement en mode edition)
- Visible uniquement si le fournisseur n'a pas deja tous les types d'offres
- Clic affiche un formulaire inline avec selection du type d'offre
Formulaire inline :
- Dropdown pour selectionner le type d'offre parmi les types non utilises
- Section d'ajout de puissances (meme interface que pour les autres modes)
- Bouton X pour annuler
Types d'offres predefinis :
- BASE, HC_HP, TEMPO, EJP, ZEN_FLEX, ZEN_WEEK_END, ZEN_WEEK_END_HP_HC, SEASONAL, BASE_WEEKEND, HC_NUIT_WEEKEND, HC_WEEKEND
UI :
- Bouton :
border-dashed border-primary-300avec iconesPackage+Plus - Formulaire : fond vert clair
bg-green-50 dark:bg-green-900/20 - Dropdown : bordure verte
border-green-300
Soumission :
- Type de contribution :
NEW_OFFER existing_provider_id: ID du fournisseur selectionne- Inclut le type d'offre et les variantes de puissance
- Invalide les caches
my-contributions,energy-providersetenergy-offers - Toast de succes/erreur
- Reset du formulaire apres succes
Gestion de date par offre (FAIT)
Chaque groupe d'offres (meme nom commercial) possede une date de validite qui permet de gerer l'historique des tarifs.
Regles metier
| Regle | Description |
|---|---|
| Identite d'offre | provider_id + offer_type (meme fournisseur + type = meme offre) |
| Desactivation | Automatique a l'approbation d'une nouvelle contribution |
| Historique | Les anciennes offres sont desactivees (valid_to defini), jamais supprimees |
| Niveau de date | Par groupe d'offres (nom commercial), pas par puissance |
Fonctionnement
- Formulaire de contribution : Champ "Date de mise en service" (DatePicker) avec date du jour par defaut
- Approbation : Quand une contribution est approuvee, les offres existantes du meme fournisseur/type sont automatiquement desactivees (
valid_to= date de la nouvelle offre) - Affichage : Badge avec la date de validite dans l'en-tete du groupe d'offres (a cote du compteur de puissances)
- Toggle historique : Checkbox pour afficher les tarifs expires dans la liste
UI
Badge date : Affiche a droite de l'en-tete du groupe, style prominent
┌──────────────────────────────────────────────────────────────────────────┐
│ Tarif Bleu 9 puissance(s) [ Depuis le 01/01/2026 ]│
├──────────────────────────────────────────────────────────────────────────┤
│ 3 kVA Abo. [11,73] €/mois Base [0,1952] €/kWh │
│ 6 kVA Abo. [15,47] €/mois Base [0,1952] €/kWh │
│ ... │
└──────────────────────────────────────────────────────────────────────────┘
Style actif (offre en vigueur) : fond bleu/primary
<span className="text-sm font-medium px-3 py-1 rounded-lg text-primary-700 bg-primary-100 border border-primary-300">
Depuis le {date}
</span>
Style expire (offre avec valid_to) : fond ambre
<span className="text-sm font-medium px-3 py-1 rounded-lg text-amber-700 bg-amber-100 border border-amber-300">
Expire le {date}
</span>
Toggle historique : Checkbox dans la section des filtres
<label className="flex items-center gap-2 cursor-pointer">
<input type="checkbox" checked={showHistory} onChange={...} />
<span>Afficher l'historique des tarifs</span>
</label>
Duplication des tarifs (FAIT)
Permet de copier tous les champs tarifaires (abonnement + prix kWh) d'une ligne de puissance vers la ligne suivante ou toutes les autres lignes du meme groupe.
Fonctionnement :
- Icone
CopyDown(lucide-react) placee a cote de l'icone corbeille dans la colonne d'actions - Visible uniquement en mode edition
- Clic ouvre un menu contextuel avec deux options :
- "Dupliquer vers la ligne suivante" : copie vers la puissance immediatement inferieure
- "Dupliquer vers toutes les lignes" : copie vers toutes les autres puissances du groupe
- Les valeurs dupliquees sont marquees comme "modifiees" (highlight ambre)
- Le bouton "ligne suivante" est desactive sur la derniere ligne du groupe
- Le bouton "toutes les lignes" est desactive si le groupe n'a qu'une seule puissance
- Toast de confirmation apres duplication
Champs copies selon le type d'offre :
- Toujours :
subscription_price(abonnement) - BASE :
base_price - BASE_WEEKEND :
base_price,base_price_weekend - HC_HP / HC_NUIT_WEEKEND / HC_WEEKEND :
hc_price,hp_price - TEMPO :
tempo_blue_hc,tempo_blue_hp,tempo_white_hc,tempo_white_hp,tempo_red_hc,tempo_red_hp - EJP :
ejp_normal,ejp_peak - ZEN_FLEX / SEASONAL :
hc_price_summer,hp_price_summer,hc_price_winter,hp_price_winter - ZEN_WEEK_END :
base_price,base_price_weekend - ZEN_WEEK_END_HP_HC :
hc_price,hp_price,hc_price_weekend,hp_price_weekend
UI :
- Bouton :
text-primary-500 dark:text-primary-400 hover:bg-primary-50 - Menu dropdown :
bg-white dark:bg-gray-800 border shadow-lg rounded-lg z-50 w-64 - Fermeture au clic exterieur (useEffect sur document click)
Warning perte de modifications (FAIT)
Quand l'utilisateur a des modifications en cours (tarifs edites, puissances ajoutees/supprimees, groupes crees, noms renommes) et clique sur une action qui ferait perdre ces modifications, une modale de confirmation s'affiche.
Actions protegees :
- Clic "Mode lecture" (quitter le mode edition)
- Clic sur un autre fournisseur
- Clic sur un autre type d'offre
Fonctionnement :
- Fonction
confirmOrExecute(action)verifiehasAnyModifications - Si pas de modification en cours : action executee directement sans confirmation
- Si modifications en cours : affiche une modale avec le nombre de modifications et un avertissement
- 3 boutons dans la modale :
- Annuler : ferme la modale, modifications preservees
- Soumettre : ferme la modale et ouvre le recap de soumission (
showRecapModal) - Continuer sans soumettre : l'action est executee (modifications perdues)
- Clic sur le backdrop : equivalent a "Annuler"
State :
const [confirmDialog, setConfirmDialog] = useState<{
title: string
message: string
onConfirm: () => void
onSubmit: () => void
} | null>(null)
UI :
- Style identique a
Admin/Offers.tsx(pattern inline state) - Titre :
text-xl font-bold text-orange-600(type warning) - Message : inclut le nombre de modifications et un conseil de soumission
- Backdrop :
bg-black/50ferme la modale au clic - Bouton "Annuler" :
bg-gray-100 dark:bg-gray-700 - Bouton "Soumettre" :
bg-primary-600 hover:bg-primary-700 text-whiteavec iconeSend - Bouton "Continuer sans soumettre" :
bg-orange-600 hover:bg-orange-700 text-white
Mode IA - Import JSON (FAIT)
Permet d'importer les tarifs d'un fournisseur via un JSON genere par une IA externe.
Prerequis : Mode edition actif + fournisseur selectionne.
Flux :
- L'utilisateur clique sur "Mode IA" dans la barre d'outils
- Un panneau s'ouvre avec un prompt pre-genere contenant le nom du fournisseur et tous les types d'offres
- L'utilisateur copie le prompt, le colle dans son IA preferee
- L'IA genere un JSON multi-offres
- L'utilisateur colle le JSON et clique "Importer"
- Les donnees sont validees et injectees dans les champs d'edition
Format JSON multi-offres :
{
"offers": [
{
"offer_name": "Nom de l'offre",
"offer_type": "BASE",
"valid_from": "2025-02-01",
"warning": "optionnel",
"deprecated": false,
"power_variants": [
{
"power_kva": 6,
"subscription_price": 12.34,
"base_price": 0.2516
}
]
}
]
}
Le champ deprecated: true permet a l'IA de signaler des offres qui n'existent plus chez le fournisseur. Ces offres sont affichees en orange dans le panneau de resultat et proposees a la suppression dans le recapitulatif.
Logique d'import (importAIJson) :
- Nettoyage automatique des blocs markdown (
```json ... ```) - Validation du type d'offre (doit etre un type connu)
- Pour chaque variante de puissance :
- Si match par
power_kvadans les offres existantes du fournisseur : injection danseditedOffers - Si pas de match : ajout dans
newPowersData
- Si match par
- Offres avec
deprecated: true: stockees dansdeprecatedOfferset proposees a la suppression - Rapport detaille par offre (matched, added, deprecated, warnings)
- Si import multi-types : passage automatique du filtre en "all"
Detection d'offres obsoletes :
Le prompt demande a l'IA de comparer les offres trouvees avec celles existantes. Si une offre n'existe plus, l'IA la retourne avec deprecated: true. Ces offres sont :
- Affichees en orange dans le resultat d'import ("obsolete - suppression proposee")
- Stockees dans le state
deprecatedOffers - Affichees dans le recapitulatif avant soumission (section orange avec icone Trash2)
- Soumises comme demande de suppression via l'endpoint batch
Conseils source de donnees :
Un encadre amber est affiche entre le prompt et la zone de saisie JSON avec des conseils :
- Page HTML ou lien web : source la plus fiable
- Image (capture d'ecran) : bonne alternative
- PDF : difficile a lire pour les IA (colonnes melangees, tableaux mal interpretes)
- Rappel : toujours verifier les tarifs avant de soumettre
States :
const [showAIMode, setShowAIMode] = useState(false)
const [aiJsonInput, setAiJsonInput] = useState('')
const [aiImportResult, setAiImportResult] = useState<{
success: boolean
message: string
details?: Array<{
offer_type: string
offer_name: string
matched: number
added: number
deprecated?: boolean
warning?: string
}>
} | null>(null)
const [deprecatedOffers, setDeprecatedOffers] = useState<Array<{
offer_type: string
offer_name: string
offer_ids: string[]
warning: string
}>>([])
UI :
- Bouton "Mode IA" :
bg-purple-50 dark:bg-purple-900/30 text-purple-700(inactif) /bg-purple-600 text-white(actif) - Panneau :
border-purple-200 dark:border-purple-700avec header violet - Prompt :
<pre>avec bouton "Copier" en overlay - Textarea : pour coller le JSON
- Resultat : vert si succes, rouge si erreur, avec details par offre et warnings amber
- Reset automatique au changement de fournisseur
Flux utilisateur
- Consulter les offres en mode lecture (par defaut)
- Cliquer sur "Proposer des modifications" pour passer en mode edition
- Selectionner un fournisseur (boutons) ou :
- Cliquer sur le bouton
+en bas pour ajouter un nouveau fournisseur - Survoler un fournisseur et cliquer sur la corbeille pour proposer sa suppression
- Cliquer sur le bouton
- Selectionner un type d'offre (boutons) ou :
- Cliquer sur "Proposer une nouvelle offre" pour ajouter un nouveau type d'offre au fournisseur
- Effectuer les modifications souhaitees :
- Manuellement : Modifier les tarifs existants (champs inline)
- Duplication : Dupliquer les tarifs d'une ligne vers la suivante ou toutes les lignes
- Mode IA : Cliquer "Mode IA", copier le prompt, coller le JSON genere par l'IA
- Marquer des puissances pour suppression (icone corbeille)
- Ajouter une ou plusieurs puissances (bouton "Ajouter une puissance")
- Renseigner le lien vers la fiche tarifaire officielle (optionnel pour admin/moderateur)
- Cliquer sur "Envoyer les contributions"
- Les contributions sont soumises en batch et apparaissent dans "Mes contributions"
Soumission batch
Les contributions sont envoyees en un seul appel API (POST /energy/contribute/batch) au lieu d'un appel par modification. Cela permet :
- Une seule notification Slack regroupant toutes les modifications par type (mises a jour, nouvelles offres, suppressions)
- Un seul email aux administrateurs avec un tableau recapitulatif
- Une seule transaction base de donnees pour l'ensemble du lot
- Un rapport avec le nombre de contributions creees et les eventuelles erreurs
Endpoint batch :
POST /energy/contribute/batch
Body: { "contributions": [...], "price_sheet_url": "..." }
Response: { "created": 96, "errors": 0, "error_details": [], "message": "..." }
Types de contributions dans le batch :
- Modifications de tarifs existants (match par
existing_offer_id) - Nouvelles puissances (
power_variantssansexisting_offer_id) - Suppressions de fournisseurs (
offer_namecontient[SUPPRESSION FOURNISSEUR]) - Offres obsoletes (
offer_namecontient[SUPPRESSION],power_kva: 0)