refactor: corriger formulaire organisation et supprimer alias morts

Formulaire organisation-form.xhtml:
- Fix binding numeroRegistre→numeroEnregistrement (bug silencieux)
- Fix réseaux sociaux: JSON brut→format lisible un par ligne
- Fix tooltips: "Côte d'Ivoire"→générique multi-pays

OrganisationsBean:
- Villes: 20 CI→70+ villes UEMOA/CEMAC/Maroc
- Régions: 19 CI→60+ régions multi-pays

nouvelle.xhtml:
- Supprimer bouton "Enregistrer" doublon dans le header

detail.xhtml:
- numeroRegistre→numeroEnregistrement
- nomOrganisationParente→organisationParenteNom
- typeLibelle→typeOrganisationLibelle

OrganisationDetailBean:
- getTypeLibelle()→getTypeOrganisationLibelle()
This commit is contained in:
dahoud
2026-04-17 20:01:02 +00:00
parent 634cc5e30d
commit cbdd5571f9
5 changed files with 70 additions and 52 deletions

View File

@@ -321,13 +321,10 @@ public class OrganisationDetailBean implements Serializable {
} }
/** /**
* Alias pour la vue (detail.xhtml) : libellé du type d'organisation. * Libellé du type d'organisation pour la vue.
* Délègue à typeLibelle du DTO si présent, sinon typeOrganisationLibelle.
*/ */
public String getTypeLibelle() { public String getTypeOrganisationLibelle() {
if (organisation == null) return ""; if (organisation == null) return "";
String libelle = organisation.getTypeLibelle();
if (libelle != null && !libelle.isBlank()) return libelle;
return organisation.getTypeOrganisationLibelle() != null ? organisation.getTypeOrganisationLibelle() : ""; return organisation.getTypeOrganisationLibelle() != null ? organisation.getTypeOrganisationLibelle() : "";
} }

View File

@@ -552,14 +552,42 @@ public class OrganisationsBean implements Serializable {
} }
/** /**
* Autocomplétion pour les villes de Côte d'Ivoire. * Autocomplétion pour les principales villes d'Afrique de l'Ouest et Centrale.
*/ */
public List<String> completerVilles(String query) { public List<String> completerVilles(String query) {
List<String> villes = List.of( List<String> villes = List.of(
// Côte d'Ivoire
"Abidjan", "Bouaké", "Daloa", "Korhogo", "San-Pédro", "Abidjan", "Bouaké", "Daloa", "Korhogo", "San-Pédro",
"Yamoussoukro", "Man", "Divo", "Gagnoa", "Abengourou", "Yamoussoukro", "Man", "Divo", "Gagnoa", "Abengourou",
"Grand-Bassam", "Bingerville", "Anyama", "Agboville", "Grand-Bassam", "Bingerville",
"Dabou", "Adzopé", "Bouaflé", "Issia", "Sinfra", "Vavoua"); // Sénégal
"Dakar", "Thiès", "Saint-Louis", "Kaolack", "Ziguinchor",
"Rufisque", "Touba", "Mbour", "Diourbel", "Tambacounda",
// Mali
"Bamako", "Sikasso", "Mopti", "Koutiala", "Ségou",
"Kayes", "Gao", "Tombouctou",
// Burkina Faso
"Ouagadougou", "Bobo-Dioulasso", "Koudougou", "Banfora",
"Ouahigouya", "Kaya",
// Guinée
"Conakry", "Kankan", "Kindia", "Nzérékoré", "Labé",
// Togo
"Lomé", "Sokodé", "Kara", "Kpalimé", "Atakpamé",
// Bénin
"Cotonou", "Porto-Novo", "Parakou", "Abomey-Calavi", "Bohicon",
// Niger
"Niamey", "Zinder", "Maradi", "Agadez", "Tahoua",
// Cameroun
"Douala", "Yaoundé", "Bafoussam", "Garoua", "Maroua",
// Gabon
"Libreville", "Port-Gentil", "Franceville",
// Congo
"Brazzaville", "Pointe-Noire",
// RD Congo
"Kinshasa", "Lubumbashi", "Mbuji-Mayi", "Kisangani",
// Maroc
"Casablanca", "Rabat", "Marrakech", "Fès", "Tanger", "Agadir"
);
if (query == null || query.trim().isEmpty()) { if (query == null || query.trim().isEmpty()) {
return villes; return villes;
} }
@@ -570,14 +598,32 @@ public class OrganisationsBean implements Serializable {
} }
/** /**
* Autocomplétion pour les régions de Côte d'Ivoire. * Autocomplétion pour les régions d'Afrique de l'Ouest et Centrale.
*/ */
public List<String> completerRegions(String query) { public List<String> completerRegions(String query) {
List<String> regions = List.of( List<String> regions = List.of(
// Côte d'Ivoire
"Lagunes", "Haut-Sassandra", "Savanes", "Vallée du Bandama", "Lagunes", "Haut-Sassandra", "Savanes", "Vallée du Bandama",
"Moyen-Comoé", "Worodougou", "Sud-Comoé", "Marahoué", "Gbêkê", "Nawa", "Tonkpi", "Poro", "Sud-Comoé",
"Sud-Bandama", "Gbêkê", "Nawa", "Gbôklé", "Cavally", // Sénégal
"Guémon", "Tonkpi", "Bagoué", "Poro", "Tchologo", "Béré"); "Dakar", "Thiès", "Diourbel", "Saint-Louis", "Ziguinchor",
"Kaolack", "Fatick", "Louga", "Matam", "Tambacounda",
// Mali
"Bamako", "Sikasso", "Mopti", "Ségou", "Kayes", "Koulikoro",
// Burkina Faso
"Centre", "Hauts-Bassins", "Boucle du Mouhoun", "Sahel",
// Guinée
"Conakry", "Kindia", "Nzérékoré", "Kankan", "Faranah",
// Togo
"Maritime", "Plateaux", "Centrale", "Kara", "Savanes",
// Bénin
"Littoral", "Atlantique", "Ouémé", "Borgou", "Zou",
// Cameroun
"Centre", "Littoral", "Ouest", "Nord", "Extrême-Nord",
// Maroc
"Casablanca-Settat", "Rabat-Salé-Kénitra", "Marrakech-Safi",
"Fès-Meknès", "Tanger-Tétouan-Al Hoceïma"
);
if (query == null || query.trim().isEmpty()) { if (query == null || query.trim().isEmpty()) {
return regions; return regions;
} }

View File

@@ -61,7 +61,7 @@
<h:outputText value="#{organisationDetailBean.organisation.nomCourt}" /> <h:outputText value="#{organisationDetailBean.organisation.nomCourt}" />
</span> </span>
</h:panelGroup> </h:panelGroup>
<p:tag value="#{organisationDetailBean.typeLibelle}" severity="info" <p:tag value="#{organisationDetailBean.typeOrganisationLibelle}" severity="info"
icon="pi pi-tag" styleClass="text-xs" /> icon="pi pi-tag" styleClass="text-xs" />
<p:tag value="#{organisationDetailBean.statutLibelle}" <p:tag value="#{organisationDetailBean.statutLibelle}"
severity="#{organisationDetailBean.statutSeverity}" styleClass="text-xs" /> severity="#{organisationDetailBean.statutSeverity}" styleClass="text-xs" />
@@ -210,11 +210,11 @@
</ui:include> </ui:include>
<ui:include src="/templates/components/forms/detail-field.xhtml"> <ui:include src="/templates/components/forms/detail-field.xhtml">
<ui:param name="label" value="Type d'organisation" /> <ui:param name="label" value="Type d'organisation" />
<ui:param name="value" value="#{organisationDetailBean.typeLibelle}" /> <ui:param name="value" value="#{organisationDetailBean.typeOrganisationLibelle}" />
</ui:include> </ui:include>
<ui:include src="/templates/components/forms/detail-field.xhtml"> <ui:include src="/templates/components/forms/detail-field.xhtml">
<ui:param name="label" value="N° d'enregistrement" /> <ui:param name="label" value="N° d'enregistrement" />
<ui:param name="value" value="#{organisationDetailBean.organisation.numeroRegistre}" /> <ui:param name="value" value="#{organisationDetailBean.organisation.numeroEnregistrement}" />
</ui:include> </ui:include>
<ui:include src="/templates/components/forms/detail-field.xhtml"> <ui:include src="/templates/components/forms/detail-field.xhtml">
<ui:param name="label" value="Date de fondation" /> <ui:param name="label" value="Date de fondation" />
@@ -606,7 +606,7 @@
</div> </div>
<p:divider styleClass="mb-3" /> <p:divider styleClass="mb-3" />
<h:panelGroup rendered="#{not empty organisationDetailBean.organisation.nomOrganisationParente}"> <h:panelGroup rendered="#{not empty organisationDetailBean.organisation.organisationParenteNom}">
<div class="border-round-lg p-3 mb-4 flex align-items-center gap-3" <div class="border-round-lg p-3 mb-4 flex align-items-center gap-3"
style="background:var(--cyan-50);border:1px solid var(--cyan-100);"> style="background:var(--cyan-50);border:1px solid var(--cyan-100);">
<i class="pi pi-arrow-up text-cyan-600" /> <i class="pi pi-arrow-up text-cyan-600" />
@@ -615,7 +615,7 @@
Rattachée à Rattachée à
</div> </div>
<div style="font-weight:700;color:var(--text-color);"> <div style="font-weight:700;color:var(--text-color);">
<h:link value="#{organisationDetailBean.organisation.nomOrganisationParente}" <h:link value="#{organisationDetailBean.organisation.organisationParenteNom}"
outcome="/pages/secure/organisation/detail" outcome="/pages/secure/organisation/detail"
styleClass="text-cyan-700 font-bold no-underline hover:underline"> styleClass="text-cyan-700 font-bold no-underline hover:underline">
<f:param name="id" value="#{organisationDetailBean.organisation.organisationParenteId}" /> <f:param name="id" value="#{organisationDetailBean.organisation.organisationParenteId}" />
@@ -624,7 +624,7 @@
</div> </div>
</div> </div>
</h:panelGroup> </h:panelGroup>
<h:panelGroup rendered="#{empty organisationDetailBean.organisation.nomOrganisationParente}"> <h:panelGroup rendered="#{empty organisationDetailBean.organisation.organisationParenteNom}">
<div class="mb-4"> <div class="mb-4">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--text-color-secondary);opacity:.7;margin-bottom:.35rem;"> <div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--text-color-secondary);opacity:.7;margin-bottom:.35rem;">
Organisation parente Organisation parente

View File

@@ -13,55 +13,34 @@
<h:form id="formNouvelleOrganisation"> <h:form id="formNouvelleOrganisation">
<!-- En-tête avec titre et actions (DRY/WOU: card-header) --> <!-- En-tête -->
<ui:decorate template="/templates/components/cards/card-header.xhtml"> <ui:decorate template="/templates/components/cards/card-header.xhtml">
<ui:param name="title" value="Nouvelle Organisation" /> <ui:param name="title" value="Nouvelle Organisation" />
<ui:param name="subtitle" value="Créez une nouvelle organisation en renseignant les informations essentielles." /> <ui:param name="subtitle" value="Renseignez les informations de la nouvelle organisation. Les champs obligatoires sont marqués d'un astérisque." />
<ui:param name="icon" value="pi pi-building" /> <ui:param name="icon" value="pi pi-building" />
<ui:param name="styleClass" value="mb-3" /> <ui:param name="styleClass" value="mb-3" />
<ui:define name="actions"> <ui:define name="actions">
<!-- Bouton Enregistrer (MethodExpression direct) -->
<p:commandButton value="Enregistrer"
icon="pi pi-save"
action="#{organisationsBean.creerOrganisation}"
update="formNouvelleOrganisation messages"
styleClass="p-button-success p-button-lg"
validateClient="true">
<p:confirm header="Confirmation"
message="Voulez-vous créer cette organisation ?"
icon="pi pi-question-circle"/>
</p:commandButton>
<!-- DRY/WOU: button-secondary pour Annuler -->
<ui:include src="/templates/components/buttons/button-secondary.xhtml"> <ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Annuler"/> <ui:param name="value" value="Annuler"/>
<ui:param name="icon" value="pi pi-times"/> <ui:param name="icon" value="pi pi-times"/>
<ui:param name="outcome" value="/pages/secure/organisation/liste"/> <ui:param name="outcome" value="/pages/secure/organisation/liste"/>
</ui:include> </ui:include>
</ui:define> </ui:define>
<ui:define name="info">
<p class="text-500 text-sm m-0">
<i class="pi pi-asterisk text-red-500 mr-1" style="font-size: 0.5rem;"/>
Les champs marqués d'un astérisque sont obligatoires
</p>
</ui:define>
</ui:decorate> </ui:decorate>
<!-- Messages globaux --> <!-- Messages globaux -->
<p:messages id="messages" showDetail="true" closable="true" styleClass="mb-3"/> <p:messages id="messages" showDetail="true" closable="true" styleClass="mb-3"/>
<!-- Formulaire (DRY/WOU: card-simple) --> <!-- Formulaire complet -->
<ui:decorate template="/templates/components/cards/card-simple.xhtml"> <ui:decorate template="/templates/components/cards/card-simple.xhtml">
<ui:param name="styleClass" value="shadow-2" /> <ui:param name="styleClass" value="shadow-2" />
<ui:define name="content"> <ui:define name="content">
<!-- DRY/WOU: organisation-form.xhtml include réutilisable -->
<ui:include src="/ui/includes/organisation-form.xhtml"> <ui:include src="/ui/includes/organisation-form.xhtml">
<ui:param name="model" value="#{organisationsBean.nouvelleOrganisation}" /> <ui:param name="model" value="#{organisationsBean.nouvelleOrganisation}" />
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" /> <ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
<ui:param name="completionBean" value="#{organisationsBean}" /> <ui:param name="completionBean" value="#{organisationsBean}" />
</ui:include> </ui:include>
<!-- Actions du formulaire (bas de page) -->
<p:divider styleClass="mt-5"/> <p:divider styleClass="mt-5"/>
<div class="flex justify-content-between align-items-center flex-column md:flex-row gap-3 mt-4"> <div class="flex justify-content-between align-items-center flex-column md:flex-row gap-3 mt-4">
@@ -70,7 +49,6 @@
Toutes les données sont sécurisées et conformes Toutes les données sont sécurisées et conformes
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<!-- Bouton Réinitialiser avec confirmation -->
<p:commandButton value="Réinitialiser" <p:commandButton value="Réinitialiser"
icon="pi pi-refresh" icon="pi pi-refresh"
action="#{organisationsBean.preparerNouvelleOrganisation}" action="#{organisationsBean.preparerNouvelleOrganisation}"
@@ -82,14 +60,12 @@
icon="pi pi-exclamation-triangle"/> icon="pi pi-exclamation-triangle"/>
</p:commandButton> </p:commandButton>
<!-- DRY/WOU: button-secondary pour Annuler -->
<ui:include src="/templates/components/buttons/button-secondary.xhtml"> <ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Annuler"/> <ui:param name="value" value="Annuler"/>
<ui:param name="icon" value="pi pi-times"/> <ui:param name="icon" value="pi pi-times"/>
<ui:param name="outcome" value="/pages/secure/organisation/liste"/> <ui:param name="outcome" value="/pages/secure/organisation/liste"/>
</ui:include> </ui:include>
<!-- Bouton Créer l'organisation (MethodExpression direct) -->
<p:commandButton value="Créer l'organisation" <p:commandButton value="Créer l'organisation"
icon="pi pi-check" icon="pi pi-check"
action="#{organisationsBean.creerOrganisation}" action="#{organisationsBean.creerOrganisation}"
@@ -105,7 +81,6 @@
</ui:define> </ui:define>
</ui:decorate> </ui:decorate>
<!-- Dialog de confirmation global (DRY/WOU: confirm-dialog) -->
<ui:include src="/templates/components/dialogs/confirm-dialog.xhtml" /> <ui:include src="/templates/components/dialogs/confirm-dialog.xhtml" />
</h:form> </h:form>

View File

@@ -103,7 +103,7 @@
<div class="field col-12 md:col-6"> <div class="field col-12 md:col-6">
<p:outputLabel for="numEnreg" value="N° d'enregistrement / RCCM" styleClass="font-semibold" /> <p:outputLabel for="numEnreg" value="N° d'enregistrement / RCCM" styleClass="font-semibold" />
<p:inputText id="numEnreg" <p:inputText id="numEnreg"
value="#{model.numeroRegistre}" value="#{model.numeroEnregistrement}"
maxlength="100" maxlength="100"
placeholder="Ex: CI-ABJ-01-2024-B12-12345"> placeholder="Ex: CI-ABJ-01-2024-B12-12345">
<f:validateLength maximum="100" /> <f:validateLength maximum="100" />
@@ -239,13 +239,13 @@
value="#{model.reseauxSociaux}" value="#{model.reseauxSociaux}"
rows="3" rows="3"
maxlength="1000" maxlength="1000"
placeholder='{"facebook":"@page_officielle", "twitter":"@compte", "linkedin":"entreprise/nom", "instagram":"@profil"}' placeholder="Facebook: @page_officielle&#10;LinkedIn: entreprise/nom&#10;Instagram: @profil&#10;Twitter/X: @compte"
autoResize="false"> autoResize="false">
<f:validateLength maximum="1000" /> <f:validateLength maximum="1000" />
</p:inputTextarea> </p:inputTextarea>
<small class="text-500"> <small class="text-500">
<i class="pi pi-share-alt mr-1"/> <i class="pi pi-share-alt mr-1"/>
Format JSON recommandé - Maximum 1000 caractères Un réseau par ligne (ex: Facebook: @mapage) — Maximum 1000 caractères
</small> </small>
</div> </div>
</div> </div>
@@ -299,7 +299,7 @@
maxlength="100"> maxlength="100">
<f:validateLength maximum="100" /> <f:validateLength maximum="100" />
</p:autoComplete> </p:autoComplete>
<p:tooltip for="ville" value="Commencez à taper pour voir les suggestions de villes de Côte d'Ivoire" position="top"/> <p:tooltip for="ville" value="Commencez à taper pour voir les suggestions de villes" position="top"/>
<small class="text-500"> <small class="text-500">
<i class="pi pi-building mr-1"/> <i class="pi pi-building mr-1"/>
Ville du siège social Ville du siège social
@@ -336,7 +336,7 @@
maxlength="100"> maxlength="100">
<f:validateLength maximum="100" /> <f:validateLength maximum="100" />
</p:autoComplete> </p:autoComplete>
<p:tooltip for="region" value="Commencez à taper pour voir les suggestions de régions de Côte d'Ivoire" position="top"/> <p:tooltip for="region" value="Commencez à taper pour voir les suggestions de régions" position="top"/>
<small class="text-500"> <small class="text-500">
<i class="pi pi-map mr-1"/> <i class="pi pi-map mr-1"/>
Région administrative Région administrative
@@ -514,7 +514,7 @@
<h:outputText value="#{org.nom}" styleClass="font-semibold"/> <h:outputText value="#{org.nom}" styleClass="font-semibold"/>
</p:column> </p:column>
<p:column headerText="Type" style="width:40%"> <p:column headerText="Type" style="width:40%">
<h:outputText value="#{org.typeLibelle}" styleClass="text-500" /> <h:outputText value="#{org.typeOrganisationLibelle}" styleClass="text-500" />
</p:column> </p:column>
</p:autoComplete> </p:autoComplete>
<p:message for="orgParente" /> <p:message for="orgParente" />