diff --git a/pom.xml b/pom.xml index 23eb425..c782337 100644 --- a/pom.xml +++ b/pom.xml @@ -19,9 +19,6 @@ 3.6.0 - 13.0.0 - 5.0.0 - 4.0.1 @@ -65,20 +62,10 @@ quarkus-qute - + - org.primefaces - primefaces - ${primefaces.version} - jakarta - - - - - org.primefaces.themes - freya - ${freya.version} - jakarta + io.quarkus + quarkus-resteasy-reactive-qute diff --git a/src/main/java/com/gbcm/client/beans/GuestPreferences.java b/src/main/java/com/gbcm/client/beans/GuestPreferences.java deleted file mode 100644 index 0fa50e3..0000000 --- a/src/main/java/com/gbcm/client/beans/GuestPreferences.java +++ /dev/null @@ -1,226 +0,0 @@ -package com.gbcm.client.beans; - -import jakarta.enterprise.context.SessionScoped; -import jakarta.inject.Named; -import java.io.Serializable; - -/** - * Bean pour les préférences d'affichage du template Freya - * Compatible avec le template Freya 5.0.0 original - * - * @author GBCM Team - * @version 1.0.0 - * @since 2025-01-01 - */ -@Named("guestPreferences") -@SessionScoped -public class GuestPreferences implements Serializable { - - private String layout = "layout-light"; - private String menuTheme = "light"; - private String topbarTheme = "light"; - private String menuMode = "static"; - private String inputStyleClass = ""; - private boolean lightLogo = false; - - /** - * Récupère le layout CSS (light/dark) - * - * @return Nom du fichier CSS de layout - */ - public String getLayout() { - return layout; - } - - /** - * Définit le layout CSS - * - * @param layout Nom du layout (layout-light ou layout-dark) - */ - public void setLayout(String layout) { - this.layout = layout; - // Ajuster le logo selon le thème - this.lightLogo = "layout-dark".equals(layout); - } - - /** - * Récupère le thème du menu - * - * @return Thème du menu (light/dark) - */ - public String getMenuTheme() { - return menuTheme; - } - - /** - * Définit le thème du menu - * - * @param menuTheme Thème du menu - */ - public void setMenuTheme(String menuTheme) { - this.menuTheme = menuTheme; - } - - /** - * Récupère le thème de la topbar - * - * @return Thème de la topbar (light/dark) - */ - public String getTopbarTheme() { - return topbarTheme; - } - - /** - * Définit le thème de la topbar - * - * @param topbarTheme Thème de la topbar - */ - public void setTopbarTheme(String topbarTheme) { - this.topbarTheme = topbarTheme; - } - - /** - * Récupère le mode du menu - * - * @return Mode du menu (static/overlay/horizontal) - */ - public String getMenuMode() { - return menuMode; - } - - /** - * Définit le mode du menu - * - * @param menuMode Mode du menu - */ - public void setMenuMode(String menuMode) { - this.menuMode = menuMode; - } - - /** - * Récupère la classe CSS pour le style des inputs - * - * @return Classe CSS - */ - public String getInputStyleClass() { - return inputStyleClass; - } - - /** - * Définit la classe CSS pour le style des inputs - * - * @param inputStyleClass Classe CSS - */ - public void setInputStyleClass(String inputStyleClass) { - this.inputStyleClass = inputStyleClass; - } - - /** - * Indique si le logo light doit être utilisé - * - * @return true pour le logo light - */ - public boolean isLightLogo() { - return lightLogo; - } - - /** - * Définit l'utilisation du logo light - * - * @param lightLogo true pour utiliser le logo light - */ - public void setLightLogo(boolean lightLogo) { - this.lightLogo = lightLogo; - } - - /** - * Bascule vers le thème sombre - */ - public void switchToDark() { - setLayout("layout-dark"); - setMenuTheme("dark"); - setTopbarTheme("dark"); - } - - /** - * Bascule vers le thème clair - */ - public void switchToLight() { - setLayout("layout-light"); - setMenuTheme("light"); - setTopbarTheme("light"); - } - - /** - * Vérifie si le thème sombre est actif - * - * @return true si thème sombre - */ - public boolean isDarkTheme() { - return "layout-dark".equals(layout); - } - - /** - * Vérifie si le thème clair est actif - * - * @return true si thème clair - */ - public boolean isLightTheme() { - return "layout-light".equals(layout); - } - - /** - * Récupère la classe CSS complète pour le body - * - * @return Classes CSS combinées - */ - public String getBodyStyleClass() { - StringBuilder sb = new StringBuilder(); - sb.append(inputStyleClass); - if (isDarkTheme()) { - sb.append(" dark-theme"); - } - return sb.toString().trim(); - } - - /** - * Récupère l'icône pour le bouton de basculement de thème - * - * @return Classe d'icône - */ - public String getThemeToggleIcon() { - return isDarkTheme() ? "pi pi-sun" : "pi pi-moon"; - } - - /** - * Récupère le texte pour le bouton de basculement de thème - * - * @return Texte du bouton - */ - public String getThemeToggleText() { - return isDarkTheme() ? "Mode Clair" : "Mode Sombre"; - } - - /** - * Bascule entre les thèmes clair et sombre - */ - public void toggleTheme() { - if (isDarkTheme()) { - switchToLight(); - } else { - switchToDark(); - } - } - - /** - * Réinitialise les préférences aux valeurs par défaut - */ - public void resetToDefaults() { - layout = "layout-light"; - menuTheme = "light"; - topbarTheme = "light"; - menuMode = "static"; - inputStyleClass = ""; - lightLogo = false; - } -} diff --git a/src/main/java/com/gbcm/client/beans/NavigationBean.java b/src/main/java/com/gbcm/client/beans/NavigationBean.java deleted file mode 100644 index 0314f1a..0000000 --- a/src/main/java/com/gbcm/client/beans/NavigationBean.java +++ /dev/null @@ -1,272 +0,0 @@ -package com.gbcm.client.beans; - -import com.gbcm.client.beans.auth.AuthBean; -import jakarta.enterprise.context.SessionScoped; -import jakarta.faces.context.FacesContext; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.Serializable; - -/** - * Bean JSF pour la gestion de la navigation dans l'interface GBCM - * - * @author GBCM Team - * @version 1.0.0 - * @since 2025-01-01 - */ -@Named("navigationBean") -@SessionScoped -public class NavigationBean implements Serializable { - - private static final Logger logger = LoggerFactory.getLogger(NavigationBean.class); - - @Inject - AuthBean authBean; - - private String currentPage = "dashboard"; - - /** - * Navigation vers le dashboard - * - * @return Outcome de navigation - */ - public String goToDashboard() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "dashboard"; - logger.debug("Navigation vers le dashboard"); - return "/pages/dashboard?faces-redirect=true"; - } - - /** - * Navigation vers la gestion des utilisateurs - * - * @return Outcome de navigation - */ - public String goToUsers() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - if (!authBean.isAdmin() && !authBean.isManager()) { - logger.warn("Accès refusé à la gestion des utilisateurs pour: {}", authBean.getUsername()); - return "/pages/access-denied?faces-redirect=true"; - } - - currentPage = "users"; - logger.debug("Navigation vers la gestion des utilisateurs"); - return "/pages/users?faces-redirect=true"; - } - - /** - * Navigation vers la gestion des clients - * - * @return Outcome de navigation - */ - public String goToClients() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "clients"; - logger.debug("Navigation vers la gestion des clients"); - return "/pages/clients?faces-redirect=true"; - } - - /** - * Navigation vers la gestion des coaches - * - * @return Outcome de navigation - */ - public String goToCoaches() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "coaches"; - logger.debug("Navigation vers la gestion des coaches"); - return "/pages/coaches?faces-redirect=true"; - } - - /** - * Navigation vers la gestion des ateliers - * - * @return Outcome de navigation - */ - public String goToWorkshops() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "workshops"; - logger.debug("Navigation vers la gestion des ateliers"); - return "/pages/workshops?faces-redirect=true"; - } - - /** - * Navigation vers les sessions de coaching - * - * @return Outcome de navigation - */ - public String goToSessions() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "sessions"; - logger.debug("Navigation vers les sessions de coaching"); - return "/pages/sessions?faces-redirect=true"; - } - - /** - * Navigation vers le profil utilisateur - * - * @return Outcome de navigation - */ - public String goToProfile() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - currentPage = "profile"; - logger.debug("Navigation vers le profil utilisateur"); - return "/pages/profile?faces-redirect=true"; - } - - /** - * Navigation vers les paramètres (admin seulement) - * - * @return Outcome de navigation - */ - public String goToSettings() { - if (!authBean.isAuthenticated()) { - return authBean.login(); - } - - if (!authBean.isAdmin()) { - logger.warn("Accès refusé aux paramètres pour: {}", authBean.getUsername()); - return "/pages/access-denied?faces-redirect=true"; - } - - currentPage = "settings"; - logger.debug("Navigation vers les paramètres"); - return "/pages/settings?faces-redirect=true"; - } - - /** - * Vérifie si une page est active - * - * @param page Nom de la page - * @return true si la page est active - */ - public boolean isPageActive(String page) { - return page.equals(currentPage); - } - - /** - * Récupère la classe CSS pour un élément de menu - * - * @param page Nom de la page - * @return Classe CSS - */ - public String getMenuItemClass(String page) { - return isPageActive(page) ? "ui-state-active" : ""; - } - - /** - * Récupère le titre de la page courante - * - * @return Titre de la page - */ - public String getPageTitle() { - switch (currentPage) { - case "dashboard": - return "Tableau de Bord"; - case "users": - return "Gestion des Utilisateurs"; - case "clients": - return "Gestion des Clients"; - case "coaches": - return "Gestion des Coaches"; - case "workshops": - return "Gestion des Ateliers"; - case "sessions": - return "Sessions de Coaching"; - case "profile": - return "Mon Profil"; - case "settings": - return "Paramètres"; - default: - return "GBCM"; - } - } - - /** - * Récupère l'icône de la page courante - * - * @return Classe d'icône FontAwesome - */ - public String getPageIcon() { - switch (currentPage) { - case "dashboard": - return "pi pi-chart-line"; - case "users": - return "pi pi-users"; - case "clients": - return "pi pi-briefcase"; - case "coaches": - return "pi pi-user-plus"; - case "workshops": - return "pi pi-calendar"; - case "sessions": - return "pi pi-comments"; - case "profile": - return "pi pi-user"; - case "settings": - return "pi pi-cog"; - default: - return "pi pi-home"; - } - } - - /** - * Vérifie si l'utilisateur peut accéder à une page - * - * @param page Nom de la page - * @return true si l'accès est autorisé - */ - public boolean canAccessPage(String page) { - if (!authBean.isAuthenticated()) { - return false; - } - - switch (page) { - case "users": - case "settings": - return authBean.isAdmin() || authBean.isManager(); - case "dashboard": - case "clients": - case "coaches": - case "workshops": - case "sessions": - case "profile": - return true; - default: - return false; - } - } - - // Getters et Setters - public String getCurrentPage() { - return currentPage; - } - - public void setCurrentPage(String currentPage) { - this.currentPage = currentPage; - } -} diff --git a/src/main/java/com/gbcm/client/beans/auth/AuthBean.java b/src/main/java/com/gbcm/client/beans/auth/AuthBean.java deleted file mode 100644 index aa8e668..0000000 --- a/src/main/java/com/gbcm/client/beans/auth/AuthBean.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.gbcm.client.beans.auth; - -import io.quarkus.oidc.IdToken; -import io.quarkus.oidc.OidcSession; -import io.quarkus.security.identity.SecurityIdentity; -import jakarta.enterprise.context.SessionScoped; -import jakarta.faces.application.FacesMessage; -import jakarta.faces.context.FacesContext; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import org.eclipse.microprofile.jwt.JsonWebToken; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.Serializable; -import java.util.Set; - -/** - * Bean JSF pour la gestion de l'authentification OIDC avec Keycloak - * - * @author GBCM Team - * @version 1.0.0 - * @since 2025-01-01 - */ -@Named("authBean") -@SessionScoped -public class AuthBean implements Serializable { - - private static final Logger logger = LoggerFactory.getLogger(AuthBean.class); - - @Inject - SecurityIdentity securityIdentity; - - @Inject - OidcSession oidcSession; - - @Inject - @IdToken - JsonWebToken idToken; - - /** - * Vérifie si l'utilisateur est authentifié - * - * @return true si authentifié - */ - public boolean isAuthenticated() { - boolean authenticated = securityIdentity != null && !securityIdentity.isAnonymous(); - logger.debug("Vérification authentification: {}", authenticated); - return authenticated; - } - - /** - * Récupère le nom de l'utilisateur connecté - * - * @return Nom d'utilisateur ou null - */ - public String getUsername() { - if (isAuthenticated()) { - String username = securityIdentity.getPrincipal().getName(); - logger.debug("Nom d'utilisateur: {}", username); - return username; - } - return null; - } - - /** - * Récupère l'email de l'utilisateur connecté - * - * @return Email ou null - */ - public String getEmail() { - if (isAuthenticated() && idToken != null) { - String email = idToken.getClaim("email"); - logger.debug("Email utilisateur: {}", email); - return email; - } - return getUsername(); // Fallback sur le username - } - - /** - * Récupère le nom complet de l'utilisateur - * - * @return Nom complet ou null - */ - public String getFullName() { - if (isAuthenticated() && idToken != null) { - String firstName = idToken.getClaim("given_name"); - String lastName = idToken.getClaim("family_name"); - - if (firstName != null && lastName != null) { - return firstName + " " + lastName; - } else if (firstName != null) { - return firstName; - } else if (lastName != null) { - return lastName; - } - } - return getUsername(); // Fallback sur le username - } - - /** - * Récupère les rôles de l'utilisateur - * - * @return Set des rôles - */ - public Set getRoles() { - if (isAuthenticated()) { - Set roles = securityIdentity.getRoles(); - logger.debug("Rôles utilisateur: {}", roles); - return roles; - } - return Set.of(); - } - - /** - * Vérifie si l'utilisateur a un rôle spécifique - * - * @param role Rôle à vérifier - * @return true si l'utilisateur a le rôle - */ - public boolean hasRole(String role) { - boolean hasRole = isAuthenticated() && securityIdentity.hasRole(role); - logger.debug("Vérification rôle '{}': {}", role, hasRole); - return hasRole; - } - - /** - * Vérifie si l'utilisateur est administrateur - * - * @return true si admin - */ - public boolean isAdmin() { - return hasRole("ADMIN"); - } - - /** - * Vérifie si l'utilisateur est manager - * - * @return true si manager - */ - public boolean isManager() { - return hasRole("MANAGER"); - } - - /** - * Vérifie si l'utilisateur est coach - * - * @return true si coach - */ - public boolean isCoach() { - return hasRole("COACH"); - } - - /** - * Vérifie si l'utilisateur est client - * - * @return true si client - */ - public boolean isClient() { - return hasRole("CLIENT"); - } - - /** - * Vérifie si l'utilisateur est prospect - * - * @return true si prospect - */ - public boolean isProspect() { - return hasRole("PROSPECT"); - } - - /** - * Initie la connexion OIDC - * - * @return Navigation vers la page de login Keycloak - */ - public String login() { - logger.info("Initiation de la connexion OIDC"); - // Quarkus OIDC redirigera automatiquement vers Keycloak - return "/gbcm/login?faces-redirect=true"; - } - - /** - * Déconnexion OIDC - * - * @return Navigation vers la page d'accueil - */ - public String logout() { - try { - logger.info("Déconnexion OIDC pour l'utilisateur: {}", getUsername()); - - if (oidcSession != null) { - oidcSession.logout().await().indefinitely(); - } - - // Invalider la session JSF - FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); - - // Message de confirmation - FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Déconnexion réussie", - "Vous avez été déconnecté avec succès.")); - - logger.info("Déconnexion OIDC terminée"); - return "/index?faces-redirect=true"; - - } catch (Exception e) { - logger.error("Erreur lors de la déconnexion OIDC", e); - FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur de déconnexion", - "Une erreur s'est produite lors de la déconnexion.")); - return null; - } - } - - /** - * Récupère l'URL de déconnexion Keycloak - * - * @return URL de déconnexion - */ - public String getLogoutUrl() { - return "http://localhost:8180/realms/gbcm-llc/protocol/openid-connect/logout" + - "?redirect_uri=http://localhost:8081/gbcm/"; - } - - /** - * Récupère des informations sur le token ID - * - * @return Informations du token ou message d'erreur - */ - public String getTokenInfo() { - if (idToken != null) { - return "Token émis par: " + idToken.getIssuer() + - ", Expire à: " + idToken.getExpirationTime(); - } - return "Aucun token ID disponible"; - } -} diff --git a/src/main/java/com/gbcm/client/resources/HomeController.java b/src/main/java/com/gbcm/client/resources/HomeController.java new file mode 100644 index 0000000..fc8fff0 --- /dev/null +++ b/src/main/java/com/gbcm/client/resources/HomeController.java @@ -0,0 +1,76 @@ +package com.gbcm.client.resources; + +import io.quarkus.qute.Template; +import io.quarkus.qute.TemplateInstance; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.oidc.OidcSession; +import io.quarkus.oidc.IdToken; +import org.eclipse.microprofile.jwt.JsonWebToken; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/") +public class HomeController { + + @Inject + Template index; + + @Inject + SecurityIdentity securityIdentity; + + @Inject + OidcSession oidcSession; + + @Inject + @IdToken + JsonWebToken idToken; + + @GET + @Produces(MediaType.TEXT_HTML) + public TemplateInstance index() { + return index + .data("user", getCurrentUser()) + .data("authenticated", isAuthenticated()) + .data("title", "Accueil - GBCM"); + } + + @GET + @Path("/index") + @Produces(MediaType.TEXT_HTML) + public TemplateInstance indexPage() { + return index(); + } + + private boolean isAuthenticated() { + return securityIdentity != null && !securityIdentity.isAnonymous(); + } + + private UserInfo getCurrentUser() { + if (!isAuthenticated()) { + return new UserInfo("Invité", "guest@example.com", "GUEST"); + } + + String username = securityIdentity.getPrincipal().getName(); + String email = idToken != null ? idToken.getClaim("email") : username; + String role = securityIdentity.getRoles().isEmpty() ? "USER" : + securityIdentity.getRoles().iterator().next(); + + return new UserInfo(username, email, role); + } + + public static class UserInfo { + public final String name; + public final String email; + public final String role; + + public UserInfo(String name, String email, String role) { + this.name = name; + this.email = email; + this.role = role; + } + } +} diff --git a/src/main/java/com/gbcm/client/resources/PageController.java b/src/main/java/com/gbcm/client/resources/PageController.java new file mode 100644 index 0000000..2202044 --- /dev/null +++ b/src/main/java/com/gbcm/client/resources/PageController.java @@ -0,0 +1,111 @@ +package com.gbcm.client.resources; + +import io.quarkus.qute.Template; +import io.quarkus.qute.TemplateInstance; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.oidc.OidcSession; +import io.quarkus.oidc.IdToken; +import org.eclipse.microprofile.jwt.JsonWebToken; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/pages") +public class PageController { + + @Inject + Template dashboard; + + @Inject + Template clients; + + @Inject + Template profile; + + @Inject + SecurityIdentity securityIdentity; + + @Inject + OidcSession oidcSession; + + @Inject + @IdToken + JsonWebToken idToken; + + @GET + @Path("/dashboard") + @Produces(MediaType.TEXT_HTML) + public TemplateInstance dashboard() { + return dashboard + .data("user", getCurrentUser()) + .data("authenticated", isAuthenticated()) + .data("title", "Tableau de Bord - GBCM"); + } + + @GET + @Path("/clients") + @Produces(MediaType.TEXT_HTML) + public TemplateInstance clients() { + return clients + .data("user", getCurrentUser()) + .data("authenticated", isAuthenticated()) + .data("title", "Gestion des Clients - GBCM"); + } + + @GET + @Path("/profile") + @Produces(MediaType.TEXT_HTML) + public TemplateInstance profile() { + return profile + .data("user", getCurrentUser()) + .data("authenticated", isAuthenticated()) + .data("title", "Profil Utilisateur - GBCM") + .data("tokenInfo", getTokenInfo()); + } + + private boolean isAuthenticated() { + return securityIdentity != null && !securityIdentity.isAnonymous(); + } + + private UserInfo getCurrentUser() { + if (!isAuthenticated()) { + return new UserInfo("Invité", "guest@example.com", "GUEST"); + } + + String username = securityIdentity.getPrincipal().getName(); + String email = idToken != null ? idToken.getClaim("email") : username; + String role = securityIdentity.getRoles().isEmpty() ? "USER" : + securityIdentity.getRoles().iterator().next(); + + return new UserInfo(username, email, role); + } + + private String getTokenInfo() { + if (idToken == null) { + return "Aucun token disponible"; + } + + StringBuilder info = new StringBuilder(); + info.append("Issuer: ").append(idToken.getIssuer()).append("\n"); + info.append("Subject: ").append(idToken.getSubject()).append("\n"); + info.append("Expiration: ").append(idToken.getExpirationTime()).append("\n"); + info.append("Issued At: ").append(idToken.getIssuedAtTime()).append("\n"); + + return info.toString(); + } + + public static class UserInfo { + public final String name; + public final String email; + public final String role; + + public UserInfo(String name, String email, String role) { + this.name = name; + this.email = email; + this.role = role; + } + } +} diff --git a/src/main/java/com/gbcm/client/web/HomeController.java b/src/main/java/com/gbcm/client/web/HomeController.java deleted file mode 100644 index 89ea235..0000000 --- a/src/main/java/com/gbcm/client/web/HomeController.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gbcm.client.web; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import io.quarkus.qute.Template; -import io.quarkus.qute.TemplateInstance; -import jakarta.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Contrôleur principal pour l'interface web GBCM - * - * @author GBCM Team - * @version 1.0.0 - * @since 2025-01-01 - */ -@Path("/") -public class HomeController { - - private static final Logger logger = LoggerFactory.getLogger(HomeController.class); - - @Inject - Template index; - - @GET - @Produces(MediaType.TEXT_HTML) - public TemplateInstance home() { - logger.info("Accès à la page d'accueil GBCM"); - return index.data("title", "GBCM - Global Business Consulting & Management") - .data("message", "Bienvenue dans l'interface web GBCM"); - } - - @GET - @Path("/health") - @Produces(MediaType.APPLICATION_JSON) - public String health() { - return "{\"status\":\"UP\",\"service\":\"gbcm-client-web\"}"; - } -} diff --git a/src/main/resources/templates/clients.html b/src/main/resources/templates/clients.html new file mode 100644 index 0000000..35c7fc2 --- /dev/null +++ b/src/main/resources/templates/clients.html @@ -0,0 +1,329 @@ + + + + + + {title} + + + + + +
+
+ + + + +
+
+

Gestion des Clients

+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
156
+

Clients Actifs

+
+
+
+
+
+
+
23
+

Nouveaux ce mois

+
+
+
+
+
+
+
12
+

Prospects

+
+
+
+
+
+
+
€2.4M
+

Chiffre d'affaires

+
+
+
+
+ + +
+
+
Liste des Clients
+
+
+
+ +
+
+
+
+
+
+ TC +
+
+
TechCorp Solutions
+ Technologie +
+
+ Actif +
+

+ Société de développement logiciel spécialisée dans les solutions cloud. +

+
+
+ Projets +
8
+
+
+ CA +
€450K
+
+
+ Depuis +
2022
+
+
+
+ + + +
+
+
+
+ + +
+
+
+
+
+
+ GT +
+
+
GlobalTech Inc.
+ Finance +
+
+ Actif +
+

+ Entreprise fintech proposant des solutions de paiement innovantes. +

+
+
+ Projets +
12
+
+
+ CA +
€780K
+
+
+ Depuis +
2021
+
+
+
+ + + +
+
+
+
+ + +
+
+
+
+
+
+ RS +
+
+
RetailSmart
+ Commerce +
+
+ Prospect +
+

+ Chaîne de magasins cherchant à digitaliser ses processus. +

+
+
+ Projets +
2
+
+
+ CA +
€120K
+
+
+ Depuis +
2024
+
+
+
+ + + +
+
+
+
+
+ + + +
+
+
+
+
+ + + + diff --git a/src/main/resources/templates/dashboard.html b/src/main/resources/templates/dashboard.html new file mode 100644 index 0000000..88c0a13 --- /dev/null +++ b/src/main/resources/templates/dashboard.html @@ -0,0 +1,252 @@ + + + + + + {title} + + + + + +
+
+ + + + +
+
+

Tableau de Bord

+
+
+ +
+
+
+ + +
+
+
+
+
+
+
Clients Actifs
+ 156 +
+
+
+ +
+
+
+

+ 3.48% + Depuis le mois dernier +

+
+
+
+
+
+
+
+
+
Revenus
+ €2.4M +
+
+
+ +
+
+
+

+ 5.4% + Depuis le mois dernier +

+
+
+
+
+
+
+
+
+
Projets
+ 49 +
+
+
+ +
+
+
+

+ 1.10% + Depuis le mois dernier +

+
+
+
+
+
+
+
+
+
Satisfaction
+ 94% +
+
+
+ +
+
+
+

+ 12% + Depuis le mois dernier +

+
+
+
+
+ + +
+
+
+
+
Activité Récente
+
+
+
+
+
+
+
Nouveau client ajouté
+

TechCorp Solutions a été ajouté comme nouveau client.

+ Il y a 2 heures +
+
+
+
+
+
Projet terminé
+

Le projet "Migration Cloud" a été terminé avec succès.

+ Il y a 5 heures +
+
+
+
+
+
Réunion programmée
+

Réunion avec GlobalTech prévue pour demain à 14h.

+ Il y a 1 jour +
+
+
+
+
+
+
+
+
+
Actions Rapides
+
+
+
+ + + + +
+
+
+
+
+
+
+
+ + + + diff --git a/src/main/resources/templates/profile.html b/src/main/resources/templates/profile.html new file mode 100644 index 0000000..4fe9532 --- /dev/null +++ b/src/main/resources/templates/profile.html @@ -0,0 +1,298 @@ + + + + + + {title} + + + + + +
+
+ + + + +
+
+

Profil Utilisateur

+
+
+ + +
+
+
+ +
+ +
+
+
+
+ +
+
{user.name}
+

{user.email}

+ {user.role} + +
+ +
+
+
156
+ Clients +
+
+
49
+ Projets +
+
+
12
+ Tâches +
+
+
+
+ + +
+
+
Actions Rapides
+
+
+
+ + + + +
+
+
+
+ + +
+ +
+
+
Informations Personnelles
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+ + + {#if authenticated} +
+
+
Informations d'Authentification
+
+
+
+
+
Statut de connexion
+ + + Connecté + +
+
+
Dernière connexion
+

Aujourd'hui à 14:30

+
+
+ +
+ +
+
+ + Informations du Token OIDC +
+
{tokenInfo}
+
+
+
+ {/if} + + +
+
+
Activité Récente
+
+
+
+
+
+
+ +
+
+
+
Connexion réussie
+

Connexion depuis l'adresse IP 192.168.1.100

+ Il y a 2 heures +
+
+ +
+
+
+ +
+
+
+
Profil mis à jour
+

Modification des informations de contact

+ Il y a 1 jour +
+
+ +
+
+
+ +
+
+
+
Rapport généré
+

Rapport mensuel des activités clients

+ Il y a 3 jours +
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/src/main/webapp/WEB-INF/faces-config.xml b/src/main/webapp/WEB-INF/faces-config.xml deleted file mode 100644 index 4201bf5..0000000 --- a/src/main/webapp/WEB-INF/faces-config.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - messages - - fr - fr - en - - - - - * - - dashboard - /pages/dashboard.xhtml - - - - profile - /pages/profile.xhtml - - - - clients - /pages/clients.xhtml - - - - home - /index.xhtml - - - - - - diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index db61510..0000000 --- a/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - GBCM Client Application - Interface web GBCM pour la gestion des services de consulting - - - - jakarta.faces.PROJECT_STAGE - Development - - - - jakarta.faces.STATE_SAVING_METHOD - server - - - - jakarta.faces.FACELETS_SKIP_COMMENTS - true - - - - - primefaces.THEME - freya - - - - primefaces.FONT_AWESOME - true - - - - primefaces.CLIENT_SIDE_VALIDATION - true - - - - - Faces Servlet - jakarta.faces.webapp.FacesServlet - 1 - - - - Faces Servlet - *.xhtml - - - - - - - - index.xhtml - - - - - 404 - /pages/error/404.xhtml - - - - 500 - /pages/error/500.xhtml - - -