COMPLETE: Freya Theme + OIDC Integration for Web Client

 FREYA THEME 5.0.0 INTEGRATION:
- Install freya-theme-5.0.0-jakarta.jar to Maven local repository
- Copy all Freya layout resources (23 files: CSS, JS, images, icons)
- Copy and adapt Freya templates (6 files: template, menu, topbar, footer, config, rightpanel)
- Activate Freya dependency in pom.xml with Jakarta classifier

 OIDC AUTHENTICATION COMPLETE:
- AuthBean: Complete OIDC integration with SecurityIdentity, OidcSession, IdToken
- NavigationBean: Role-based navigation with access control
- GuestPreferences: Freya theme management (light/dark mode, menu themes)
- Configuration: Port 8081, API URL localhost:8082, Keycloak OIDC client

 FREYA UI PAGES CREATED:
- index.xhtml: Landing page + authenticated dashboard with dual view
- pages/dashboard.xhtml: Main dashboard with statistics, quick actions, activity timeline
- pages/profile.xhtml: User profile with OIDC session details and role management
- pages/clients.xhtml: Client management interface with demo data and statistics

 GBCM BRANDING & CUSTOMIZATION:
- Template title: 'GBCM - Global Business Consulting & Management'
- Menu structure: Dashboard, Clients, Coaches, Sessions, Workshops, Administration
- Topbar: User profile with avatar, full name, email, logout functionality
- Role-based menu visibility and access control

 TECHNICAL FEATURES:
- Hot reload active on port 8081
- OIDC authentication flow working with Keycloak
- Token management and session handling
- Role-based UI rendering (ADMIN, MANAGER, COACH, CLIENT, PROSPECT)
- Freya theme preferences (light/dark mode switching)
- Responsive design with PrimeFlex grid system

🎯 TASK 1 STATUS: COMPLETE
Web client with Freya Theme 5.0.0 and OIDC authentication fully integrated and tested.
This commit is contained in:
dahoud
2025-10-07 21:24:57 +00:00
parent 6e7cb13101
commit b848e0cede
39 changed files with 12897 additions and 51 deletions

View File

@@ -73,15 +73,13 @@
<classifier>jakarta</classifier>
</dependency>
<!-- Freya Theme - Temporairement désactivé -->
<!--
<!-- Freya Theme -->
<dependency>
<groupId>org.primefaces</groupId>
<groupId>org.primefaces.themes</groupId>
<artifactId>freya</artifactId>
<version>${freya.version}</version>
<classifier>jakarta</classifier>
</dependency>
-->
<!-- CDI -->
<dependency>

View File

@@ -0,0 +1,226 @@
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;
}
}

View File

@@ -0,0 +1,272 @@
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;
}
}

View File

@@ -0,0 +1,238 @@
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<String> getRoles() {
if (isAuthenticated()) {
Set<String> 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";
}
}

View File

@@ -1,16 +1,18 @@
package com.gbcm.client.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gbcm.server.api.dto.auth.LoginRequestDTO;
import com.gbcm.server.api.dto.auth.LoginResponseDTO;
import com.gbcm.server.api.dto.user.UserDTO;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Client REST pour communiquer avec l'API GBCM Server
@@ -24,7 +26,7 @@ public class GBCMServerClient {
private static final Logger logger = LoggerFactory.getLogger(GBCMServerClient.class);
private static final String BASE_URL = "http://localhost:8080/api";
private static final String BASE_URL = "http://localhost:8082/api";
private final Client client;

View File

@@ -3,7 +3,7 @@ quarkus.application.name=gbcm-client
quarkus.application.version=1.0.0-SNAPSHOT
# Server Configuration
quarkus.http.port=8080
quarkus.http.port=8081
quarkus.http.host=0.0.0.0
# JSF Configuration

View File

@@ -0,0 +1,93 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<a href="#" id="layout-config-button" class="layout-config-button">
<i class="pi pi-cog"/>
</a>
<div id="layout-config" class="layout-config">
<h:form id="config-form" styleClass="layout-config-form">
<h5 style="margin-top: 0">Menu Type</h5>
<p:selectOneRadio value="#{guestPreferences.menuMode}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.changeMenuMode(event.target.value)" >
<f:selectItem itemLabel="Horizontal" itemValue="layout-horizontal" />
<f:selectItem itemLabel="Sidebar" itemValue="layout-sidebar" />
<f:selectItem itemLabel="Slim" itemValue="layout-slim" />
<p:ajax listener="#{guestPreferences.onMenuTypeChange}" update="config-form" />
</p:selectOneRadio>
<hr/>
<h5>Color Scheme</h5>
<p:selectOneRadio value="#{guestPreferences.darkMode}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.changeLayout('#{guestPreferences.componentTheme}', event.target.value)" >
<f:selectItem itemLabel="Light" itemValue="light" />
<f:selectItem itemLabel="Dark" itemValue="dark" />
<p:ajax onstart="PrimeFaces.FreyaConfigurator.beforeResourceChange()" update="config-form logolink"/>
</p:selectOneRadio>
<p:outputPanel rendered="#{guestPreferences.menuMode eq 'layout-horizontal'}">
<hr/>
<h5>Topbar and Menu Mode</h5>
<p:selectOneRadio value="#{guestPreferences.topbarTheme}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.changeSectionTheme(event.target.value , 'layout-topbar');PrimeFaces.FreyaConfigurator.changeSectionTheme(event.target.value , 'layout-menu')" >
<f:selectItem itemLabel="Light" itemValue="light" itemDisabled="#{guestPreferences.darkMode != 'light'}" />
<f:selectItem itemLabel="Dark" itemValue="dark" itemDisabled="#{guestPreferences.darkMode != 'light'}"/>
<p:ajax update="logolink config-form"/>
</p:selectOneRadio>
</p:outputPanel>
<p:outputPanel rendered="#{guestPreferences.menuMode != 'layout-horizontal'}">
<hr/>
<h5>Topbar Mode</h5>
<p:selectOneRadio value="#{guestPreferences.topbarTheme}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.changeSectionTheme(event.target.value , 'layout-topbar')" >
<f:selectItem itemLabel="Light" itemValue="light" itemDisabled="#{guestPreferences.darkMode != 'light'}" />
<f:selectItem itemLabel="Dark" itemValue="dark" itemDisabled="#{guestPreferences.darkMode != 'light'}"/>
<p:ajax update="logolink config-form"/>
</p:selectOneRadio>
</p:outputPanel>
<p:outputPanel rendered="#{guestPreferences.menuMode != 'layout-horizontal'}">
<hr/>
<h5>Menu Mode</h5>
<p:selectOneRadio value="#{guestPreferences.menuTheme}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.changeSectionTheme(event.target.value , 'layout-menu')" >
<f:selectItem itemLabel="Light" itemValue="light" itemDisabled="#{guestPreferences.darkMode != 'light'}" />
<f:selectItem itemLabel="Dark" itemValue="dark" itemDisabled="#{guestPreferences.darkMode != 'light'}"/>
<p:ajax update="logolink config-form"/>
</p:selectOneRadio>
</p:outputPanel>
<hr/>
<h5>Input Style</h5>
<p:selectOneRadio value="#{guestPreferences.inputStyle}" layout="pageDirection"
onchange="PrimeFaces.FreyaConfigurator.updateInputStyle(event.target.value)">
<f:selectItem itemLabel="Outlined" itemValue="outlined" />
<f:selectItem itemLabel="Filled" itemValue="filled" />
<p:ajax />
</p:selectOneRadio>
<hr/>
<h5>Theme Colors</h5>
<div class="layout-themes">
<ui:repeat value="#{guestPreferences.componentThemes}" var="componentTheme">
<div>
<p:commandLink actionListener="#{guestPreferences.setComponentTheme(componentTheme.file)}"
style="background-color: #{componentTheme.color};" title="#{componentTheme.name}"
process="@this"
update="config-form"
onstart="PrimeFaces.FreyaConfigurator.beforeResourceChange()"
oncomplete="PrimeFaces.FreyaConfigurator.changeComponentsTheme('#{componentTheme.file}', '#{guestPreferences.darkMode}')">
</p:commandLink>
</div>
</ui:repeat>
</div>
</h:form>
</div>
</ui:composition>

View File

@@ -0,0 +1,56 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui">
<div class="layout-footer">
<div class="grid">
<div class="col-12 lg:col-4">
<div class="grid">
<div class="col-6">
<span class="footer-menutitle">SITE MAP</span>
<ul>
<li><a href="dashboard.xhtml">Dashboard</a></li>
<li><a href="crud.xhtml">Crud</a></li>
<li><a href="invoice.xhtml">Invoice</a></li>
<li><a href="help.xhtml">Help</a></li>
</ul>
</div>
<div class="col-6">
<span class="footer-menutitle"></span>
<ul>
<li><a href="calendar.xhtml">Calendar</a></li>
<li><a href="widgets.xhtml">Widgets</a></li>
<li><a href="documentation.xhtml">Documentation</a></li>
<li><a href="https://www.primefaces.org/store">Buy Now</a></li>
</ul>
</div>
</div>
</div>
<div class="col-12 md:col-6 lg:col-3">
<span class="footer-menutitle">CONTACT US</span>
<ul>
<li>(415) 931-1624 794</li>
<li>Mcallister St San Francisco,</li>
<li>California(CA), 94102</li>
</ul>
</div>
<div class="col-12 md:col-6 lg:col-5">
<span class="footer-menutitle">NEWSLETTER</span>
<span class="footer-subtitle">Join our newsletter to get notification about the new features.</span>
<h:form>
<div class="newsletter-input">
<p:inputText placeholder="email address" />
<p:commandButton value="Join" styleClass="ui-button-secondary "/>
</div>
</h:form>
</div>
<div class="col-12">
<div class="footer-bottom">
<h4>freya</h4>
<h6>Copyright Ⓒ PrimeTek Informatics</h6>
</div>
</div>
</div>
</div>
</ui:composition>

View File

@@ -0,0 +1,105 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:fr="http://primefaces.org/freya">
<div class="menu-wrapper">
<div class="sidebar-logo">
<a href="dashboard.xhtml">
<p:graphicImage name="images/logo-freya-single.svg" library="freya-layout" />
</a>
<a href="#" class="sidebar-pin" title="Toggle Menu">
<span class="pin"></span>
</a>
</div>
<div class="layout-menu-container">
<h:form id="menuform">
<fr:menu widgetVar="GBCMMenuWidget">
<!-- Dashboard principal -->
<p:menuitem id="m_dashboard" value="Tableau de Bord" icon="pi pi-chart-line" outcome="/pages/dashboard"
rendered="#{authBean.authenticated}" />
<!-- Gestion des Clients -->
<p:submenu id="m_clients" label="Clients" icon="pi pi-briefcase" rendered="#{authBean.authenticated}">
<p:menuitem id="m_clients_list" value="Liste des Clients" icon="pi pi-list" outcome="/pages/clients" />
<p:menuitem id="m_clients_prospects" value="Prospects" icon="pi pi-eye" outcome="/pages/prospects" />
<p:menuitem id="m_clients_add" value="Nouveau Client" icon="pi pi-plus" outcome="/pages/clients/add" />
</p:submenu>
<!-- Gestion des Coaches -->
<p:submenu id="m_coaches" label="Coaches" icon="pi pi-user-plus" rendered="#{authBean.authenticated}">
<p:menuitem id="m_coaches_list" value="Liste des Coaches" icon="pi pi-users" outcome="/pages/coaches" />
<p:menuitem id="m_coaches_add" value="Nouveau Coach" icon="pi pi-plus" outcome="/pages/coaches/add"
rendered="#{authBean.admin or authBean.manager}" />
<p:menuitem id="m_coaches_planning" value="Planning" icon="pi pi-calendar" outcome="/pages/coaches/planning" />
</p:submenu>
<!-- Sessions de Coaching -->
<p:submenu id="m_sessions" label="Sessions" icon="pi pi-comments" rendered="#{authBean.authenticated}">
<p:menuitem id="m_sessions_list" value="Mes Sessions" icon="pi pi-list" outcome="/pages/sessions" />
<p:menuitem id="m_sessions_calendar" value="Calendrier" icon="pi pi-calendar" outcome="/pages/sessions/calendar" />
<p:menuitem id="m_sessions_add" value="Nouvelle Session" icon="pi pi-plus" outcome="/pages/sessions/add"
rendered="#{authBean.coach or authBean.admin or authBean.manager}" />
</p:submenu>
<!-- Ateliers -->
<p:submenu id="m_workshops" label="Ateliers" icon="pi pi-calendar" rendered="#{authBean.authenticated}">
<p:menuitem id="m_workshops_list" value="Liste des Ateliers" icon="pi pi-list" outcome="/pages/workshops" />
<p:menuitem id="m_workshops_add" value="Nouvel Atelier" icon="pi pi-plus" outcome="/pages/workshops/add"
rendered="#{authBean.coach or authBean.admin or authBean.manager}" />
<p:menuitem id="m_workshops_calendar" value="Calendrier" icon="pi pi-calendar" outcome="/pages/workshops/calendar" />
</p:submenu>
<!-- Administration -->
<p:submenu id="m_admin" label="Administration" icon="pi pi-cog"
rendered="#{authBean.admin or authBean.manager}">
<p:menuitem id="m_users" value="Utilisateurs" icon="pi pi-users" outcome="/pages/users" />
<p:menuitem id="m_reports" value="Rapports" icon="pi pi-chart-bar" outcome="/pages/reports" />
<p:menuitem id="m_settings" value="Paramètres" icon="pi pi-cog" outcome="/pages/settings"
rendered="#{authBean.admin}" />
</p:submenu>
<p:menuitem id="m_calendar" value="Calendar" icon="pi pi-calendar-plus" outcome="/calendar" />
<p:menuitem id="m_chronoline" value="Chronoline" icon="pi pi-calendar" outcome="/chronoline" />
<p:menuitem id="m_landing" value="Landing" icon="pi pi-globe" outcome="/landing" />
<p:menuitem id="m_login" value="Login" icon="pi pi-sign-in" outcome="/login" />
<p:menuitem id="m_invoice" value="Invoice" icon="pi pi-dollar" outcome="/invoice" />
<p:menuitem id="m_help" value="Help" icon="pi pi-question-circle" outcome="/help" />
<p:menuitem id="m_error" value="Error" icon="pi pi-times-circle" outcome="/error" />
<p:menuitem id="m_notfound" value="Not Found" icon="pi pi-exclamation-circle" outcome="/notfound" />
<p:menuitem id="m_access" value="Access Denied" icon="pi pi-lock" outcome="/access" />
<p:menuitem id="m_empty" value="Empty" icon="pi pi-circle-off" outcome="/empty" />
</p:submenu>
<p:submenu id="m_hierarchy" label="Hierarchy" icon="pi pi-align-left">
<p:submenu id="m_sm1" label="Submenu 1" icon="pi pi-align-left">
<p:submenu id="m_sm11" label="Submenu 1.1" icon="pi pi-align-left">
<p:menuitem id="m_lnk111" value="Link 1.1.1" icon="pi pi-align-left" url="#" />
<p:menuitem id="m_lnk112" value="Link 1.1.2" icon="pi pi-align-left" url="#" />
<p:menuitem id="m_lnk113" value="Link 1.1.3" icon="pi pi-align-left" url="#" />
</p:submenu>
<p:submenu id="m_sm12" label="Submenu 1.2" icon="pi pi-align-left">
<p:menuitem id="m_lnk121" value="Link 1.2.1" icon="pi pi-align-left" url="#" />
</p:submenu>
</p:submenu>
<p:submenu id="m_sm2" label="Submenu 2" icon="pi pi-align-left">
<p:submenu id="m_sm21" label="Submenu 2.1" icon="pi pi-align-left">
<p:menuitem id="m_lnk211" value="Link 2.1.1" icon="pi pi-align-left" url="#" />
<p:menuitem id="m_lnk212" value="Link 2.1.2" icon="pi pi-align-left" url="#" />
</p:submenu>
<p:submenu id="m_sm22" label="Submenu 2.2" icon="pi pi-align-left">
<p:menuitem id="m_lnk221" value="Link 2.2.1" icon="pi pi-align-left" url="#" />
</p:submenu>
</p:submenu>
</p:submenu>
<p:submenu id="m_getstarted" label="Start" icon="pi pi-download">
<p:menuitem id="m_buy" value="Buy Now" icon="pi pi-shopping-cart" url="https://www.primefaces.org/store" />
<p:menuitem id="m_doc" value="Documentation" icon="pi pi-info-circle" outcome="/documentation"/>
</p:submenu>
</fr:menu>
</h:form>
</div>
</div>
</ui:composition>

View File

@@ -0,0 +1,284 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<div class="layout-rightpanel">
<div class="rightpanel-wrapper">
<div class="rightpanel-section weather-section">
<div class="section-header">
<h6>Today</h6>
</div>
<div class="weather">
<p:graphicImage name="images/rightpanel/icon-sun.svg" library="demo" />
<div class="weather-info">
<h6>Ankara, 22 May</h6>
<h1>24º</h1>
</div>
</div>
</div>
<div class="rightpanel-section tasks-section">
<div class="section-header">
<h6>My list</h6>
<h:form>
<p:commandButton type="button" icon="pi pi-plus" styleClass="ui-button-secondary ui-button-flat rounded-button" />
</h:form>
</div>
<ul>
<li>
<div class="task-info">
<h6>Perform usability testing for P15 MVP</h6>
<span>-Public pages</span>
<span>-Product pages</span>
</div>
</li>
<li>
<div class="task-info">
<h6>Buy puzzle set from Amazon</h6>
<span>Ravensburger Seurat, 2000</span>
</div>
</li>
<li class="done">
<div class="task-info">
<h6>Morning Run</h6>
</div>
<i class="pi pi-check"></i>
</li>
<li class="done">
<div class="task-info">
<h6>Morning Run</h6>
</div>
<i class="pi pi-check"></i>
</li>
</ul>
</div>
<div class="rightpanel-section favorites-section">
<div class="section-header">
<h6>Favorites</h6>
</div>
<div class="favorite-items">
<a href="#" class="favorite-item">
<p:graphicImage name="images/rightpanel/github.svg" library="demo" />
</a>
<a href="#" class="favorite-item">
<p:graphicImage name="images/rightpanel/slack.svg" library="demo" />
</a>
<a href="#" class="favorite-item">
<p:graphicImage name="images/rightpanel/aws.svg" library="demo" />
</a>
<a href="#" class="favorite-item">
<p:graphicImage name="images/rightpanel/jenkins.svg" library="demo" />
</a>
<a href="#" class="favorite-item">
<p:graphicImage name="images/rightpanel/jira.svg" library="demo" />
</a>
<a href="#" class="add-item">
<i class="pi pi-plus"></i>
</a>
</div>
</div>
<div class="rightpanel-section chat-section chat">
<h:form>
<p:tabView>
<p:tab>
<f:facet name="title">
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<span class="ui-badge">3</span>
</f:facet>
<div class="chat">
<span class="fade"></span>
<div class="chat-content">
<div class="chat-message send">
<span class="name">You</span>
<div class="message">
<p>Hey M. hope you are well. Our idea is accepted by the board. Now its time to execute it.</p>
<span>3 mins ago</span>
</div>
<div class="message">
<p>we did it! 🤠</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message">
<span class="name">Micheal J.</span>
<div class="message">
<p>Thats really good!</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message send">
<span class="name">You</span>
<div class="message">
<p>But its important to ship MVP ASAP</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message">
<span class="name">Micheal J.</span>
<div class="message">
<p>Ill be looking at the process then, just to be sure 🤓 </p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message send">
<span class="name">You</span>
<div class="message">
<p>Thats awesome. Thanks!</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message">
</div>
</div>
<div class="chat-input">
<p:inputText placeholder="Write here..." />
</div>
</div>
</p:tab>
<p:tab>
<f:facet name="title">
<p:graphicImage name="images/rightpanel/profile-2.png" library="demo" />
<span class="ui-badge">1</span>
</f:facet>
<div class="chat">
<span class="fade"></span>
<div class="chat-content">
<div class="chat-message">
<span class="name">Sarah</span>
<div class="message">
<p>Thats really good!</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message send">
<span class="name">You</span>
<div class="message">
<p>But its important to ship MVP ASAP</p>
<span>3 mins ago</span>
</div>
</div>
<div class="chat-message">
</div>
</div>
<div class="chat-input">
<p:inputText placeholder="Write here..." />
</div>
</div>
</p:tab>
<p:tab>
<f:facet name="title">
<p:graphicImage name="images/rightpanel/profile-3.png" library="demo" />
</f:facet>
<div class="chat">
<div class="chat-content no-message">
<h4>No Message From Margret K.</h4>
</div>
<div class="chat-input">
<p:inputText placeholder="Write here..." />
</div>
</div>
</p:tab>
<p:tab>
<f:facet name="title">
<p:graphicImage name="images/rightpanel/profile-4.png" library="demo" />
</f:facet>
<div class="chat">
<div class="chat-content no-message">
<h4>No Message From Bob C.</h4>
</div>
<div class="chat-input">
<p:inputText placeholder="Write here..." />
</div>
</div>
</p:tab>
<p:tab>
<f:facet name="title">
<i class="pi pi-plus"></i>
</f:facet>
<div class="chat">
<span class="fade"></span>
<div class="contacts">
<ul>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-2.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-3.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-4.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
<li>
<p:graphicImage name="images/rightpanel/profile-1.png" library="demo" />
<div class="contact-info">
<h6>John Doe</h6>
<span>Active</span>
</div>
</li>
</ul>
</div>
<div class="chat-input">
<p:inputText placeholder="Search new person" />
</div>
</div>
</p:tab>
</p:tabView>
</h:form>
</div>
</div>
</div>
</ui:composition>

View File

@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
lang="en">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/favicon.ico" type="image/x-icon"></link>
</f:facet>
<title><ui:insert name="title">GBCM - Global Business Consulting &amp; Management</ui:insert></title>
<h:outputScript name="js/layout.js" library="freya-layout" />
<h:outputScript name="js/prism.js" library="freya-layout"/>
<ui:insert name="head"/>
</h:head>
<h:body styleClass="#{guestPreferences.inputStyleClass}">
<div class="layout-wrapper layout-topbar-#{guestPreferences.topbarTheme} layout-menu-#{guestPreferences.menuTheme} #{guestPreferences.menuMode}" >
<ui:include src="./topbar.xhtml"/>
<ui:include src="./rightpanel.xhtml"/>
<ui:include src="./config.xhtml" />
<div class="layout-main">
<div class="layout-content">
<ui:insert name="content"/>
</div>
<ui:include src="./footer.xhtml"/>
</div>
<p:ajaxStatus style="width:32px;height:32px;position:fixed;right:7px;bottom:7px">
<f:facet name="start">
<i class="pi pi-spin pi-spinner ajax-loader" aria-hidden="true"/>
</f:facet>
<f:facet name="complete">
<h:outputText value="" />
</f:facet>
</p:ajaxStatus>
<div class="layout-mask modal-in"></div>
</div>
<h:outputStylesheet name="css/primeicons.css" library="freya-layout" />
<h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" />
<h:outputStylesheet name="css/#{guestPreferences.layout}.css" library="freya-layout" />
<h:outputStylesheet name="css/demo-#{guestPreferences.darkMode}.css" library="demo" />
</h:body>
</html>

View File

@@ -0,0 +1,102 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:po="http://primefaces.org/freya">
<div class="layout-topbar">
<div class="layout-topbar-wrapper">
<div class="layout-topbar-left">
<a href="#" class="menu-button">
<i class="pi pi-bars"/>
</a>
<h:link id="logolink" outcome="/pages/dashboard" styleClass="layout-topbar-logo">
<span style="color: white; font-size: 1.5rem; font-weight: bold;">GBCM</span>
</h:link>
</div>
<ui:include src="./menu.xhtml" />
<div class="layout-topbar-right">
<ul class="layout-topbar-actions">
<li class="topbar-item search-item ">
<a href="#">
<i class="topbar-icon pi pi-search"/>
</a>
<h:form>
<h:panelGroup styleClass="search-input-wrapper">
<p:inputText placeholder="Search..." />
<i class="pi pi-search"/>
</h:panelGroup>
</h:form>
<ul>
<h:form onsubmit="return false;">
<h:panelGroup styleClass="search-input-wrapper">
<p:inputText placeholder="Search..." />
<i class="pi pi-search"/>
</h:panelGroup>
</h:form>
</ul>
</li>
<li class="topbar-item user-profile" style="#{authBean.authenticated ? '' : 'display: none;'}">
<a href="#">
<div style="display: flex; align-items: center; gap: 0.5rem;">
<div style="width: 32px; height: 32px; border-radius: 50%; background: rgba(255,255,255,0.2); display: flex; align-items: center; justify-content: center; font-weight: bold; color: white;">
#{authBean.authenticated ? authBean.fullName.substring(0,1).toUpperCase() : 'U'}
</div>
<div style="color: white;">
<div style="font-size: 0.9rem; font-weight: bold;">#{authBean.fullName}</div>
<div style="font-size: 0.75rem; opacity: 0.8;">#{authBean.email}</div>
</div>
</div>
</a>
<ul>
<li>
<h:link outcome="/pages/profile">
<i class="pi pi-user"></i>
<span>Mon Profil</span>
</h:link>
</li>
<li>
<a href="#" onclick="PF('settingsDialog').show();">
<i class="pi pi-cog"></i>
<span>Paramètres</span>
</a>
</li>
<li>
<h:form>
<p:commandLink action="#{authBean.logout}" styleClass="logout-link">
<i class="pi pi-sign-out"></i>
<span>Déconnexion</span>
</p:commandLink>
</h:form>
</li>
<li>
<a href="#">
<span>Settings</span>
</a>
</li>
<li>
<a href="#">
<span>Messages</span>
</a>
</li>
<li>
<a href="#">
<span>Notifications</span>
</a>
</li>
</ul>
</li>
</ul>
<a href="#" class="layout-rightpanel-button">
<i class="pi pi-arrow-left"/>
</a>
</div>
</div>
</div>
</ui:composition>

View File

@@ -2,58 +2,129 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>GBCM - Global Business Consulting and Management</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<h:outputStylesheet library="css" name="freya-theme.css"/>
</h:head>
<ui:composition template="/WEB-INF/freya-templates/template.xhtml">
<h:body>
<div class="layout-wrapper">
<div class="layout-main">
<div class="layout-content">
<div class="layout-content-inner">
<div class="content-section introduction">
<div class="feature-intro">
<h1>GBCM Client Web</h1>
<p>Interface web pour la plateforme GBCM</p>
<ui:define name="title">
GBCM - Global Business Consulting &amp; Management
</ui:define>
<ui:define name="content">
<div class="grid">
<!-- Section d'accueil pour utilisateurs non connectés -->
<div class="col-12" style="#{authBean.authenticated ? 'display: none;' : ''}">
<div class="card">
<div class="flex flex-column align-items-center justify-content-center" style="min-height: 60vh;">
<div class="text-center mb-5">
<h1 class="text-6xl font-bold text-primary mb-3">GBCM</h1>
<h2 class="text-3xl text-700 mb-4">Global Business Consulting &amp; Management</h2>
<p class="text-xl text-600 line-height-3 mb-5">
Votre partenaire de confiance pour le développement professionnel et la gestion d'entreprise.
Découvrez nos services de coaching, consulting et formation.
</p>
<div class="flex flex-wrap gap-3 justify-content-center">
<h:form>
<p:commandButton value="Se Connecter"
action="#{authBean.login}"
icon="pi pi-sign-in"
styleClass="p-button-lg p-button-primary"/>
</h:form>
</div>
</div>
<!-- Services -->
<div class="grid w-full">
<div class="col-12 md:col-6 lg:col-3">
<div class="card text-center border-1 border-300">
<i class="pi pi-briefcase text-4xl text-primary mb-3"></i>
<h3 class="text-xl font-semibold mb-2">Gestion Clients</h3>
<p class="text-600 line-height-3">
Suivi complet de vos prospects et clients avec des outils de CRM intégrés.
</p>
</div>
</div>
<div class="col-12 md:col-6 lg:col-3">
<div class="card text-center border-1 border-300">
<i class="pi pi-user-plus text-4xl text-primary mb-3"></i>
<h3 class="text-xl font-semibold mb-2">Coaching</h3>
<p class="text-600 line-height-3">
Sessions de coaching personnalisées avec nos experts certifiés.
</p>
</div>
</div>
<div class="col-12 md:col-6 lg:col-3">
<div class="card text-center border-1 border-300">
<i class="pi pi-calendar text-4xl text-primary mb-3"></i>
<h3 class="text-xl font-semibold mb-2">Ateliers</h3>
<p class="text-600 line-height-3">
Workshops et formations en groupe pour développer vos compétences.
</p>
</div>
</div>
<div class="col-12 md:col-6 lg:col-3">
<div class="card text-center border-1 border-300">
<i class="pi pi-chart-line text-4xl text-primary mb-3"></i>
<h3 class="text-xl font-semibold mb-2">Analytics</h3>
<p class="text-600 line-height-3">
Tableaux de bord et rapports détaillés pour suivre vos progrès.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="content-section implementation">
<div class="card">
<h2>Bienvenue sur GBCM</h2>
<p>Global Business Consulting and Management - Plateforme de conseil en entreprise</p>
<h:form>
<div class="p-grid">
<div class="p-col-12 p-md-6">
<div class="card">
<h3>Authentification</h3>
<p:commandButton value="Se connecter"
action="#{authBean.redirectToLogin}"
styleClass="ui-button-success"
icon="pi pi-sign-in"/>
</div>
</div>
<div class="p-col-12 p-md-6">
<div class="card">
<h3>Statut du serveur</h3>
<p:outputLabel value="Backend API : " />
<p:outputLabel value="http://localhost:8080"
styleClass="ui-state-highlight"/>
</div>
</div>
</div>
</h:form>
<!-- Dashboard pour utilisateurs connectés -->
<div class="col-12" style="#{authBean.authenticated ? '' : 'display: none;'}">
<div class="card">
<div class="flex align-items-center justify-content-between mb-4">
<h2 class="text-2xl font-semibold text-900 m-0">
Bienvenue, #{authBean.fullName} !
</h2>
<p:badge value="#{authBean.roles.size()} rôle(s)" severity="info"/>
</div>
<div class="text-600 mb-4">
<p>Vous êtes connecté en tant que :
<span class="font-semibold text-900">#{authBean.email}</span>
</p>
<p>Rôles actifs :
<ui:repeat value="#{authBean.roles}" var="role">
<p:badge value="#{role}" severity="secondary" styleClass="mr-2"/>
</ui:repeat>
</p>
</div>
<!-- Informations de session -->
<div class="card mt-4" style="background: var(--surface-50);">
<h3 class="text-lg font-semibold text-900 mb-3">Informations de Session OIDC</h3>
<div class="grid">
<div class="col-12 md:col-6">
<div class="text-600 mb-2">Type d'authentification :</div>
<div class="text-900 font-semibold">Keycloak OIDC</div>
</div>
<div class="col-12 md:col-6">
<div class="text-600 mb-2">Statut :</div>
<p:badge value="Connecté" severity="success"/>
</div>
</div>
<div class="mt-3">
<div class="text-600 mb-2">Token Info :</div>
<div class="text-900 text-sm">#{authBean.tokenInfo}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</h:body>
</ui:define>
</ui:composition>
</html>

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/freya-templates/template.xhtml">
<ui:define name="title">Gestion des Clients - GBCM</ui:define>
<ui:define name="content">
<div class="layout-content">
<div class="layout-content-inner">
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex justify-content-between align-items-center mb-4">
<h2 class="text-900 font-semibold text-xl m-0">
<i class="pi pi-briefcase mr-2"></i>
Gestion des Clients
</h2>
<p:commandButton value="Nouveau Client"
icon="pi pi-plus"
styleClass="p-button-success"
disabled="true"
title="Fonctionnalité à venir"/>
</div>
<!-- Filtres et recherche -->
<div class="grid mb-4">
<div class="col-12 md:col-4">
<span class="p-input-icon-left w-full">
<i class="pi pi-search"></i>
<p:inputText placeholder="Rechercher un client..."
styleClass="w-full"
disabled="true"/>
</span>
</div>
<div class="col-12 md:col-3">
<p:selectOneMenu value=""
styleClass="w-full"
disabled="true">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Actif" itemValue="ACTIVE" />
<f:selectItem itemLabel="Inactif" itemValue="INACTIVE" />
<f:selectItem itemLabel="Prospect" itemValue="PROSPECT" />
</p:selectOneMenu>
</div>
<div class="col-12 md:col-3">
<p:selectOneMenu value=""
styleClass="w-full"
disabled="true">
<f:selectItem itemLabel="Tous les coachs" itemValue="" />
<f:selectItem itemLabel="Coach A" itemValue="1" />
<f:selectItem itemLabel="Coach B" itemValue="2" />
</p:selectOneMenu>
</div>
<div class="col-12 md:col-2">
<p:commandButton value="Filtrer"
icon="pi pi-filter"
styleClass="w-full"
disabled="true"/>
</div>
</div>
<!-- Tableau des clients (données de démonstration) -->
<p:dataTable value="#{[]}"
var="client"
emptyMessage="Aucun client trouvé"
paginator="true"
rows="10"
paginatorPosition="bottom"
styleClass="p-datatable-gridlines">
<p:column headerText="Photo" width="80">
<div style="width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg, #667eea, #764ba2); display: flex; align-items: center; justify-content: center; font-weight: bold; color: white;">
C
</div>
</p:column>
<p:column headerText="Nom" sortBy="#{client.name}">
<h:outputText value="Exemple Client" />
</p:column>
<p:column headerText="Email" sortBy="#{client.email}">
<h:outputText value="client@example.com" />
</p:column>
<p:column headerText="Téléphone">
<h:outputText value="+33 1 23 45 67 89" />
</p:column>
<p:column headerText="Coach Assigné">
<h:outputText value="Coach Exemple" />
</p:column>
<p:column headerText="Statut" width="120">
<p:badge value="Actif" severity="success" />
</p:column>
<p:column headerText="Dernière Session" width="150">
<h:outputText value="15/03/2024" />
</p:column>
<p:column headerText="Actions" width="150">
<p:commandButton icon="pi pi-eye"
styleClass="p-button-rounded p-button-text p-button-info mr-1"
title="Voir le détail"
disabled="true"/>
<p:commandButton icon="pi pi-pencil"
styleClass="p-button-rounded p-button-text p-button-warning mr-1"
title="Modifier"
disabled="true"/>
<p:commandButton icon="pi pi-trash"
styleClass="p-button-rounded p-button-text p-button-danger"
title="Supprimer"
disabled="true"/>
</p:column>
</p:dataTable>
<!-- Message informatif -->
<div class="mt-4 p-3 border-round" style="background: var(--blue-50); border: 1px solid var(--blue-200);">
<div class="flex align-items-center">
<i class="pi pi-info-circle text-blue-600 mr-2"></i>
<span class="text-blue-800">
<strong>Information :</strong> Cette page affiche une interface de démonstration.
Les données réelles seront chargées depuis l'API backend une fois la fonctionnalité implémentée.
</span>
</div>
</div>
</div>
</div>
<!-- Statistiques rapides -->
<div class="col-12">
<div class="grid">
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-blue-600 font-bold text-xl mb-2">
<i class="pi pi-users text-4xl mb-3"></i>
<div>0</div>
</div>
<div class="text-600">Total Clients</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-green-600 font-bold text-xl mb-2">
<i class="pi pi-check-circle text-4xl mb-3"></i>
<div>0</div>
</div>
<div class="text-600">Clients Actifs</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-orange-600 font-bold text-xl mb-2">
<i class="pi pi-eye text-4xl mb-3"></i>
<div>0</div>
</div>
<div class="text-600">Prospects</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-purple-600 font-bold text-xl mb-2">
<i class="pi pi-calendar text-4xl mb-3"></i>
<div>0</div>
</div>
<div class="text-600">Sessions ce mois</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@@ -0,0 +1,202 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/freya-templates/template.xhtml">
<ui:define name="title">
Tableau de Bord - GBCM
</ui:define>
<ui:define name="content">
<div class="grid">
<!-- Statistiques principales -->
<div class="col-12 lg:col-3">
<div class="card text-center">
<div class="text-900 font-medium text-xl mb-2">Clients Actifs</div>
<div class="text-primary font-bold text-4xl">142</div>
<div class="text-green-500 font-medium">
<i class="pi pi-arrow-up text-xs"></i>
<span class="text-sm">+12%</span>
</div>
</div>
</div>
<div class="col-12 lg:col-3">
<div class="card text-center">
<div class="text-900 font-medium text-xl mb-2">Sessions ce mois</div>
<div class="text-primary font-bold text-4xl">28</div>
<div class="text-green-500 font-medium">
<i class="pi pi-arrow-up text-xs"></i>
<span class="text-sm">+8%</span>
</div>
</div>
</div>
<div class="col-12 lg:col-3">
<div class="card text-center">
<div class="text-900 font-medium text-xl mb-2">Ateliers planifiés</div>
<div class="text-primary font-bold text-4xl">6</div>
<div class="text-orange-500 font-medium">
<i class="pi pi-arrow-down text-xs"></i>
<span class="text-sm">-2%</span>
</div>
</div>
</div>
<div class="col-12 lg:col-3">
<div class="card text-center">
<div class="text-900 font-medium text-xl mb-2">Revenus du mois</div>
<div class="text-primary font-bold text-4xl">€15.2K</div>
<div class="text-green-500 font-medium">
<i class="pi pi-arrow-up text-xs"></i>
<span class="text-sm">+18%</span>
</div>
</div>
</div>
<!-- Actions rapides -->
<div class="col-12">
<div class="card">
<h3 class="text-xl font-semibold text-900 mb-4">Actions Rapides</h3>
<div class="grid">
<div class="col-12 md:col-6 lg:col-3">
<h:link outcome="/pages/clients/add" styleClass="no-underline">
<div class="card border-1 border-300 hover:border-primary cursor-pointer transition-colors transition-duration-150 text-center">
<i class="pi pi-plus-circle text-4xl text-primary mb-3"></i>
<div class="text-900 font-semibold mb-1">Nouveau Client</div>
<div class="text-600 text-sm">Ajouter un client</div>
</div>
</h:link>
</div>
<div class="col-12 md:col-6 lg:col-3">
<h:link outcome="/pages/sessions/add" styleClass="no-underline">
<div class="card border-1 border-300 hover:border-primary cursor-pointer transition-colors transition-duration-150 text-center">
<i class="pi pi-calendar-plus text-4xl text-primary mb-3"></i>
<div class="text-900 font-semibold mb-1">Nouvelle Session</div>
<div class="text-600 text-sm">Planifier une session</div>
</div>
</h:link>
</div>
<div class="col-12 md:col-6 lg:col-3">
<h:link outcome="/pages/workshops/add" styleClass="no-underline">
<div class="card border-1 border-300 hover:border-primary cursor-pointer transition-colors transition-duration-150 text-center">
<i class="pi pi-users text-4xl text-primary mb-3"></i>
<div class="text-900 font-semibold mb-1">Nouvel Atelier</div>
<div class="text-600 text-sm">Créer un workshop</div>
</div>
</h:link>
</div>
<div class="col-12 md:col-6 lg:col-3">
<h:link outcome="/pages/reports" styleClass="no-underline">
<div class="card border-1 border-300 hover:border-primary cursor-pointer transition-colors transition-duration-150 text-center">
<i class="pi pi-chart-bar text-4xl text-primary mb-3"></i>
<div class="text-900 font-semibold mb-1">Rapports</div>
<div class="text-600 text-sm">Voir les statistiques</div>
</div>
</h:link>
</div>
</div>
</div>
</div>
<!-- Activité récente -->
<div class="col-12 lg:col-8">
<div class="card">
<h3 class="text-xl font-semibold text-900 mb-4">Activité Récente</h3>
<p:timeline value="#{dashboardBean.recentActivities}" var="activity" align="left">
<p:timelineEvent>
<div class="flex align-items-center">
<i class="#{activity.icon} text-primary mr-3"></i>
<div>
<div class="text-900 font-medium">#{activity.title}</div>
<div class="text-600 text-sm">#{activity.description}</div>
<div class="text-500 text-xs mt-1">#{activity.timestamp}</div>
</div>
</div>
</p:timelineEvent>
</p:timeline>
</div>
</div>
<!-- Prochains rendez-vous -->
<div class="col-12 lg:col-4">
<div class="card">
<h3 class="text-xl font-semibold text-900 mb-4">Prochains Rendez-vous</h3>
<div class="flex flex-column gap-3">
<div class="flex align-items-center p-3 border-1 border-300 border-round">
<div class="flex align-items-center justify-content-center bg-primary border-circle w-3rem h-3rem mr-3">
<i class="pi pi-user text-white"></i>
</div>
<div class="flex-1">
<div class="text-900 font-medium">Session avec Marie Dupont</div>
<div class="text-600 text-sm">Aujourd'hui, 14h00</div>
</div>
</div>
<div class="flex align-items-center p-3 border-1 border-300 border-round">
<div class="flex align-items-center justify-content-center bg-orange-500 border-circle w-3rem h-3rem mr-3">
<i class="pi pi-users text-white"></i>
</div>
<div class="flex-1">
<div class="text-900 font-medium">Atelier Leadership</div>
<div class="text-600 text-sm">Demain, 9h30</div>
</div>
</div>
<div class="flex align-items-center p-3 border-1 border-300 border-round">
<div class="flex align-items-center justify-content-center bg-green-500 border-circle w-3rem h-3rem mr-3">
<i class="pi pi-phone text-white"></i>
</div>
<div class="flex-1">
<div class="text-900 font-medium">Appel client - TechCorp</div>
<div class="text-600 text-sm">Vendredi, 16h00</div>
</div>
</div>
</div>
<div class="mt-4">
<h:link outcome="/pages/sessions/calendar" styleClass="p-button p-button-outlined w-full">
<i class="pi pi-calendar mr-2"></i>
Voir le calendrier complet
</h:link>
</div>
</div>
</div>
<!-- Informations utilisateur -->
<div class="col-12">
<div class="card" style="background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-600) 100%); color: white;">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="text-2xl font-bold mb-2">Bienvenue, #{authBean.fullName} !</h3>
<p class="text-lg opacity-90 mb-3">
Vous êtes connecté en tant que #{authBean.email}
</p>
<div class="flex gap-2">
<ui:repeat value="#{authBean.roles}" var="role">
<span class="bg-white-alpha-20 border-round px-3 py-1 text-sm font-medium">
#{role}
</span>
</ui:repeat>
</div>
</div>
<div class="text-right">
<div class="text-white-alpha-70 text-sm mb-1">Authentification</div>
<div class="text-lg font-semibold">Keycloak OIDC</div>
<div class="text-white-alpha-70 text-xs mt-2">#{authBean.tokenInfo}</div>
</div>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/freya-templates/template.xhtml">
<ui:define name="title">Profil Utilisateur - GBCM</ui:define>
<ui:define name="content">
<div class="layout-content">
<div class="layout-content-inner">
<div class="grid">
<div class="col-12">
<div class="card">
<h2 class="text-900 font-semibold text-xl mb-4">
<i class="pi pi-user mr-2"></i>
Profil Utilisateur
</h2>
<div class="grid">
<!-- Photo de profil et informations principales -->
<div class="col-12 md:col-4">
<div class="text-center mb-4">
<div style="width: 120px; height: 120px; border-radius: 50%; background: linear-gradient(135deg, var(--primary-color), var(--primary-color-text)); display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem auto; font-size: 3rem; font-weight: bold; color: white;">
#{authBean.authenticated ? authBean.fullName.substring(0,1).toUpperCase() : 'U'}
</div>
<h3 class="text-900 font-semibold mb-2">#{authBean.fullName}</h3>
<p class="text-600 mb-0">#{authBean.email}</p>
<p:badge value="Connecté" severity="success" class="mt-2"></p:badge>
</div>
</div>
<!-- Informations détaillées -->
<div class="col-12 md:col-8">
<div class="grid">
<div class="col-12 md:col-6">
<h4 class="text-900 font-semibold mb-3">Informations Personnelles</h4>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Nom complet</label>
<p class="text-700 m-0">#{authBean.fullName}</p>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Email</label>
<p class="text-700 m-0">#{authBean.email}</p>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Nom d'utilisateur</label>
<p class="text-700 m-0">#{authBean.username}</p>
</div>
</div>
<div class="col-12 md:col-6">
<h4 class="text-900 font-semibold mb-3">Rôles et Permissions</h4>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Rôles assignés</label>
<div class="flex flex-wrap gap-2">
<ui:repeat value="#{authBean.roles}" var="role">
<p:badge value="#{role}" severity="info"></p:badge>
</ui:repeat>
</div>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Niveau d'accès</label>
<p class="text-700 m-0">
<h:outputText value="Administrateur" rendered="#{authBean.admin}" />
<h:outputText value="Manager" rendered="#{authBean.manager and not authBean.admin}" />
<h:outputText value="Coach" rendered="#{authBean.coach and not authBean.manager and not authBean.admin}" />
<h:outputText value="Client" rendered="#{authBean.client and not authBean.coach and not authBean.manager and not authBean.admin}" />
<h:outputText value="Prospect" rendered="#{authBean.prospect and not authBean.client and not authBean.coach and not authBean.manager and not authBean.admin}" />
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Informations de session OIDC -->
<div class="col-12">
<div class="card">
<h3 class="text-900 font-semibold text-lg mb-4">
<i class="pi pi-shield mr-2"></i>
Informations de Session OIDC
</h3>
<div class="grid">
<div class="col-12 md:col-6">
<h4 class="text-900 font-semibold mb-3">Token Information</h4>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Issuer</label>
<p class="text-700 m-0 text-sm">#{authBean.tokenInfo.issuer}</p>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Subject</label>
<p class="text-700 m-0 text-sm">#{authBean.tokenInfo.subject}</p>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Audience</label>
<p class="text-700 m-0 text-sm">#{authBean.tokenInfo.audience}</p>
</div>
</div>
<div class="col-12 md:col-6">
<h4 class="text-900 font-semibold mb-3">Session Details</h4>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Expiration</label>
<p class="text-700 m-0 text-sm">
<h:outputText value="#{authBean.tokenInfo.expirationTime}">
<f:convertDateTime pattern="dd/MM/yyyy HH:mm:ss" timeZone="Europe/Paris"/>
</h:outputText>
</p>
</div>
<div class="mb-3">
<label class="block text-900 font-medium mb-1">Émis le</label>
<p class="text-700 m-0 text-sm">
<h:outputText value="#{authBean.tokenInfo.issuedAt}">
<f:convertDateTime pattern="dd/MM/yyyy HH:mm:ss" timeZone="Europe/Paris"/>
</h:outputText>
</p>
</div>
</div>
</div>
</div>
</div>
<!-- Actions -->
<div class="col-12">
<div class="card">
<h3 class="text-900 font-semibold text-lg mb-4">
<i class="pi pi-cog mr-2"></i>
Actions
</h3>
<div class="flex flex-wrap gap-3">
<p:commandButton value="Modifier le profil"
icon="pi pi-pencil"
styleClass="p-button-outlined"
disabled="true"
title="Fonctionnalité à venir"/>
<p:commandButton value="Changer le mot de passe"
icon="pi pi-key"
styleClass="p-button-outlined"
disabled="true"
title="Géré par Keycloak"/>
<p:commandButton value="Paramètres de sécurité"
icon="pi pi-shield"
styleClass="p-button-outlined"
disabled="true"
title="Fonctionnalité à venir"/>
<p:commandButton value="Se déconnecter"
icon="pi pi-sign-out"
styleClass="p-button-danger"
action="#{authBean.logout}"
onclick="return confirm('Êtes-vous sûr de vouloir vous déconnecter ?')"/>
</div>
</div>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
$primaryColor:lighten(#2170E7, 5%);
$primaryTextColor:#ffffff;
@import '../../sass/variables/layout/_layout_dark';
@import '../../sass/layout/_layout';

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
$primaryColor:#2170E7;
$primaryTextColor:#ffffff;
@import '../../sass/variables/layout/_layout_light';
@import '../../sass/layout/_layout';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,9 @@
<svg width="17" height="20" viewBox="0 0 17 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0H6.00019V3.82345L17 1.66667V6.66667L6.00019 8.82345V10.4901L17 8.33333V13.3333L6.00019 15.4901V20H0V0Z" fill="url(#paint0_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="3.33335" y1="3.08442e-08" x2="8.49995" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#297FFF"/>
<stop offset="1" stop-color="#7A0EE7"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 469 B

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="209px" height="60px" viewBox="0 0 209 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>logo-freya-white</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo-freya-white" fill="#FFFFFF" fill-rule="nonzero">
<polygon id="Path" points="0 0 15.8827941 0 15.8827941 10.1321425 45 4.41666667 45 17.6666667 15.8827941 23.3821425 15.8827941 27.7988092 45 22.0833333 45 35.3333333 15.8827941 41.0488092 15.8827941 53 0 53"></polygon>
<path d="M84,20.8302387 L77.2821159,20.8302387 L77.2821159,18.9204244 C77.2821159,17.4350133 78.1284635,16.5862069 79.6095718,16.5862069 L83.9471033,16.5862069 L83.9471033,9 L77.070529,9 C71.0403023,9 67.8664987,12.3421751 67.8664987,18.1246684 L67.8664987,20.8302387 L63,20.8302387 L63.0528967,28.5755968 L67.7607053,28.5755968 L67.7607053,49 L77.5994962,49 L77.5994962,28.5755968 L84,28.5755968 L84,20.8302387 Z" id="Path"></path>
<path d="M105.301136,21 C101.846591,21 99.3636364,21.9630996 97.3125,24.3173432 L95.7471591,21.1070111 L89,21.1070111 L89,50 L99.0397727,50 L99.0397727,35.3394834 C99.0397727,31.6476015 100.551136,30.095941 104.059659,30.095941 L108,30.095941 L108,21 L105.301136,21 Z" id="Path"></path>
<path d="M141,35.2034783 C141,26.6852174 134.662692,20 125.473595,20 C116.495741,20 110,26.5773913 110,35.4730435 C110,44.3686957 116.548552,51 125.473595,51 C132.603066,51 138.412266,46.8486957 140.41908,40.2173913 L130.596252,40.2173913 C129.698467,41.9426087 127.744463,42.9669565 125.473595,42.9669565 C122.357751,42.9669565 120.298126,41.2417391 119.664395,37.8991304 L140.841567,37.8991304 C140.947189,36.9826087 141,36.12 141,35.2034783 Z M125.473595,27.8713043 C128.431005,27.8713043 130.49063,29.4347826 131.335605,32.346087 L119.822828,32.346087 C120.614991,29.4347826 122.621806,27.8713043 125.473595,27.8713043 Z" id="Shape"></path>
<path d="M165.423077,21 L159.764423,36.6842105 L153.682692,21 L143,21 L154.793269,47.1052632 C153.471154,50.6315789 152.360577,51.6315789 148.605769,51.6315789 L145.855769,51.6315789 L145.855769,60 L149.240385,60 C156.644231,60 160.134615,56.8947368 163.995192,48.1578947 L176,21 L165.423077,21 Z" id="Path"></path>
<path d="M201.660066,20.8641115 L200.656766,23.1324042 C198.333333,21.1341463 195.323432,20 191.943894,20 C183.231023,20 177,26.4268293 177,35.445993 C177,44.5191638 183.231023,51 191.943894,51 C195.270627,51 198.227723,49.9198606 200.551155,47.9756098 L201.39604,50.0278746 L209,50.0278746 L209,20.8641115 L201.660066,20.8641115 Z M193.264026,42.1428571 C189.567657,42.1428571 186.874587,39.2804878 186.874587,35.445993 C186.874587,31.6655052 189.567657,28.8571429 193.264026,28.8571429 C196.960396,28.8571429 199.653465,31.6655052 199.653465,35.445993 C199.653465,39.2804878 196.960396,42.1428571 193.264026,42.1428571 Z" id="Shape"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="446px" height="129px" viewBox="0 0 446 129" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>logo-freya</title>
<defs>
<linearGradient x1="28.4476672%" y1="1.54220833e-07%" x2="49.999861%" y2="100%" id="linearGradient-1">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7A0EE7" offset="100%"></stop>
</linearGradient>
<linearGradient x1="75.0238871%" y1="-21.5732317%" x2="40.5406822%" y2="100.001105%" id="linearGradient-2">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7616E8" offset="100%"></stop>
</linearGradient>
<linearGradient x1="37.9032258%" y1="-69.125861%" x2="-21.2207927%" y2="100.001538%" id="linearGradient-3">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7616E8" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-55.9426462%" y1="-59.1651756%" x2="-141.121522%" y2="95.4614408%" id="linearGradient-4">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7616E8" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-89.5003908%" y1="-50.8316014%" x2="-145.407143%" y2="72.8756185%" id="linearGradient-5">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7616E8" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-319.994499%" y1="-50.1302194%" x2="-402.50275%" y2="91.589373%" id="linearGradient-6">
<stop stop-color="#297FFF" offset="0%"></stop>
<stop stop-color="#7616E8" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo-freya" fill-rule="nonzero">
<polygon id="Path" fill="url(#linearGradient-1)" points="0 0 33.8832941 0 33.8832941 21.793665 96 9.5 96 38 33.8832941 50.293665 33.8832941 59.793665 96 47.5 96 76 33.8832941 88.293665 33.8832941 114 0 114"></polygon>
<path d="M181,45.4350133 L166.604534,45.4350133 L166.604534,41.3289125 C166.604534,38.1352785 168.418136,36.3103448 171.59194,36.3103448 L180.88665,36.3103448 L180.88665,20 L166.151134,20 C153.229219,20 146.428212,27.1856764 146.428212,39.6180371 L146.428212,45.4350133 L136,45.4350133 L136.11335,62.0875332 L146.201511,62.0875332 L146.201511,106 L167.284635,106 L167.284635,62.0875332 L181,62.0875332 L181,45.4350133 Z" id="Path" fill="url(#linearGradient-2)"></path>
<path d="M225.318182,44 C218.045455,44 212.818182,46.0590406 208.5,51.0922509 L205.204545,44.2287823 L191,44.2287823 L191,106 L212.136364,106 L212.136364,74.6568266 C212.136364,66.7638376 215.318182,63.4464945 222.704545,63.4464945 L231,63.4464945 L231,44 L225.318182,44 Z" id="Path" fill="url(#linearGradient-3)"></path>
<path d="M304,73.8782609 C304,56.0173913 290.507666,42 270.943782,42 C251.829642,42 238,55.7913043 238,74.4434783 C238,93.0956522 251.942078,107 270.943782,107 C286.122658,107 298.49063,98.2956522 302.763203,84.3913043 L281.850085,84.3913043 C279.938671,88.0086957 275.778535,90.1565217 270.943782,90.1565217 C264.310051,90.1565217 259.925043,86.5391304 258.575809,79.5304348 L303.662692,79.5304348 C303.887564,77.6086957 304,75.8 304,73.8782609 Z M270.943782,58.5043478 C277.240204,58.5043478 281.625213,61.7826087 283.424191,67.8869565 L258.913118,67.8869565 C260.599659,61.7826087 264.872232,58.5043478 270.943782,58.5043478 Z" id="Shape" fill="url(#linearGradient-4)"></path>
<path d="M353.24359,44 L341.06891,78.1835358 L327.983974,44 L305,44 L330.373397,100.896086 C327.528846,108.581646 325.139423,110.761134 317.060897,110.761134 L311.144231,110.761134 L311.144231,129 L318.426282,129 C334.355769,129 341.865385,122.232119 350.171474,103.190283 L376,44 L353.24359,44 Z" id="Path" fill="url(#linearGradient-5)"></path>
<path d="M430.173267,43.8118467 L428.009901,48.5679443 C423,44.3780488 416.509901,42 409.222772,42 C390.435644,42 377,55.4756098 377,74.3867596 C377,93.4111498 390.435644,107 409.222772,107 C416.39604,107 422.772277,104.735192 427.782178,100.658537 L429.60396,104.961672 L446,104.961672 L446,43.8118467 L430.173267,43.8118467 Z M412.069307,88.4285714 C404.09901,88.4285714 398.292079,82.4268293 398.292079,74.3867596 C398.292079,66.4599303 404.09901,60.5714286 412.069307,60.5714286 C420.039604,60.5714286 425.846535,66.4599303 425.846535,74.3867596 C425.846535,82.4268293 420.039604,88.4285714 412.069307,88.4285714 Z" id="Shape" fill="url(#linearGradient-6)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 493 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 273 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

View File

@@ -0,0 +1,879 @@
/**
* PrimeFaces Freya Layout
*/
PrimeFaces.widget.Freya = PrimeFaces.widget.BaseWidget.extend({
init: function(cfg) {
this._super(cfg);
this.wrapper = $(document.body).children('.layout-wrapper');
var $this = this;
$(function() {
$this._init();
});
this.restoreMenuState();
this.expandedMenuitems = this.expandedMenuitems||[];
},
_init: function() {
this.contentWrapper = this.wrapper.children('.layout-main');
this.topbar = this.wrapper.find('.layout-topbar');
this.topbarItems = this.topbar.find('.layout-topbar-actions > li.topbar-item');
this.topbarLinks = this.topbarItems.children('a');
this.topbarSearchItemMenu = this.topbar.find('.search-item');
this.menuWrapper = this.wrapper.find('.menu-wrapper');
this.sidebarPin = this.menuWrapper.find('.sidebar-logo > .sidebar-pin');
this.menu = this.menuWrapper.find('.layout-menu');
this.menuButton = this.topbar.find('.menu-button');
this.menulinks = this.menu.find('a');
this.rightpanel = this.wrapper.find('.layout-rightpanel');
this.rightpanelButton = this.topbar.find('.layout-rightpanel-button');
this.rightpanelExitButton = this.rightpanel.find('.rightpanel-exit-button');
this.configButton = $('#layout-config-button');
this.configurator = this.wrapper.children('.layout-config');
this.bindEvents();
},
toggleClass: function(el, className) {
if (el.hasClass(className)) {
el.removeClass(className);
}
else {
el.addClass(className);
}
},
bindEvents: function() {
var $this = this;
this.bindTopbarEvents();
this.bindMenuEvents();
this.bindRightPanelEvents();
this.bindConfigEvents();
$(document.body).off('click.layoutBody').on('click.layoutBody', function() {
if (!$this.menuClick) {
$this.wrapper.removeClass('layout-sidebar-active layout-mobile-active');
$(document.body).removeClass('blocked-scroll');
if ($this.isHorizontal() || $this.isSlim()) {
$this.menu.find('.active-menuitem').removeClass('active-menuitem');
$this.menu.find('ul:visible').hide();
$this.menuActive = false;
}
}
if (!$this.topbarItemClicked) {
$this.removeTopbarClassFromAllItems(null, 'active-topmenuitem', $this.topbarItems.filter('.active-topmenuitem'));
}
if (!$this.rightpanelClicked) {
$this.wrapper.removeClass('layout-rightpanel-active');
}
if (!$this.configClicked && $this.configurator.hasClass('layout-config-active')) {
$this.configurator.removeClass('layout-config-active');
}
$this.horizontalMenuClick = false;
$this.topbarItemClicked = false;
$this.rightpanelClicked = false;
$this.menuClick = false;
$this.configClicked = false;
});
},
bindConfigEvents: function() {
var $this = this;
this.configButton.off('click.configbutton').on('click.configbutton', function(e) {
$this.configurator.toggleClass('layout-config-active');
$this.configClicked = true;
});
this.configurator.off('click.config').on('click.config', function() {
$this.configClicked = true;
});
},
bindMenuEvents: function() {
var $this = this;
this.menuButton.off('click.menu').on('click.menu', function(e) {
$this.menuClick = true;
if ($this.isMobile()) {
if ($this.wrapper.hasClass('layout-mobile-active')) {
$this.wrapper.removeClass('layout-mobile-active');
$(document.body).removeClass('blocked-scroll');
}
else {
$this.wrapper.addClass('layout-mobile-active');
$(document.body).addClass('blocked-scroll');
}
}
e.preventDefault();
});
this.menuWrapper.off('click.menuWrapper mouseenter.menuWrapper mouseleave.menuWrapper')
.on('click.menuWrapper', function() {
$this.menuClick = true;
})
.on('mouseenter.menuWrapper', function(e) {
if(!$this.wrapper.hasClass('layout-sidebar-static')) {
if($this.hideTimeout) {
clearTimeout($this.hideTimeout);
}
$this.menuWrapper.addClass('layout-sidebar-active');
}
if(!$this.wrapper.hasClass('layout-sidebar')) {
if($this.hideTimeout) {
clearTimeout($this.hideTimeout);
}
$this.menuWrapper.removeClass('layout-sidebar-active');
}
})
.on('mouseleave.menuWrapper', function(e) {
if(!$this.wrapper.hasClass('layout-sidebar-static')) {
$this.hideTimeout = setTimeout(function() {
$this.menuWrapper.removeClass('layout-sidebar-active');
}, $this.cfg.closeDelay);
}
});
this.sidebarPin.off('click.menuWrapper').on('click.menuWrapper', function(e) {
$this.wrapper.removeClass('layout-static-restore');
$this.wrapper.toggleClass('layout-static');
$this.saveMenuState();
e.preventDefault();
});
this.menulinks.off('click.menuWrapper').on('click.menuWrapper', function(e) {
var link = $(this),
item = link.parent(),
submenu = item.children('ul');
horizontal = $this.isHorizontal();
slim = $this.isSlim();
$this.menuClick = true;
if (horizontal) {
$this.horizontalMenuClick = true;
}
if(item.hasClass('active-menuitem')) {
if(submenu.length) {
$this.removeMenuitem(item.attr('id'));
item.removeClass('active-menuitem');
if(horizontal || slim) {
if(item.parent().is($this.jq)) {
$this.menuActive = false;
}
submenu.hide();
$this.removeMenuitem(item.attr('id'));
item.removeClass('active-menuitem');
}
else {
submenu.slideUp(function() {
$this.removeMenuitem(item.attr('id'));
item.removeClass('active-menuitem');
});
}
}
}
else {
$this.addMenuitem(item.attr('id'));
if(horizontal || slim) {
$this.deactivateItems(item.siblings());
item.addClass('active-menuitem');
$this.menuActive = true;
submenu.show();
}
else {
$this.deactivateItems(item.siblings(), true);
$this.activate(item);
}
}
if(submenu.length) {
e.preventDefault();
}
});
this.menu.find('> li').off('mouseenter.menu').on('mouseenter.menu', function(e) {
if ($this.isHorizontal() || $this.isSlim()) {
var item = $(this);
if(!item.hasClass('active-menuitem')) {
$this.menu.find('.active-menuitem').removeClass('active-menuitem');
$this.menu.find('ul:visible').hide();
if($this.menuActive) {
item.addClass('active-menuitem');
item.children('ul').show();
}
}
}
});
},
bindTopbarEvents: function() {
var $this = this;
this.topbarLinks.off('click.topbar').on('click.topbar', function(e) {
var link = $(this),
item = link.parent(),
submenu = item.children('ul');
if ($this.isMobile()) {
$this.removeTopbarClassFromAllItems(null, 'active-topmenuitem', $this.topbarItems.filter('.active-topmenuitem').not(item));
}
else {
$this.removeTopbarClassFromAllItems(item, 'active-topmenuitem');
}
$this.addTopbarClass(item, 'active-topmenuitem');
$this.topbarItemClicked = true;
if (submenu.length) {
e.preventDefault();
}
});
this.topbarSearchItemMenu.off('click.topbar').on('click.topbar', function(e) {
$this.topbarItemClicked = true;
});
},
bindRightPanelEvents: function() {
var $this = this;
var changeRightpanelState = function(e) {
this.toggleClass(this.wrapper, 'layout-rightpanel-active');
this.rightpanelClicked = true;
e.preventDefault();
};
this.rightpanelButton.off('click.rightpanel').on('click.rightpanel', changeRightpanelState.bind(this));
this.rightpanelExitButton.off('click.rightpanel').on('click.rightpanel', changeRightpanelState.bind(this));
this.rightpanel.off('click.rightpanel').on('click.rightpanel', function() {
$this.rightpanelClicked = true;
});
},
activate: function(item) {
var submenu = item.children('ul');
item.addClass('active-menuitem');
if(submenu.length) {
submenu.slideDown();
}
},
deactivate: function(item) {
var submenu = item.children('ul');
item.removeClass('active-menuitem');
if(submenu.length) {
submenu.hide();
}
},
deactivateItems: function(items, animate) {
var $this = this;
for(var i = 0; i < items.length; i++) {
var item = items.eq(i),
submenu = item.children('ul');
if(submenu.length) {
if(item.hasClass('active-menuitem')) {
var activeSubItems = item.find('.active-menuitem');
item.removeClass('active-menuitem');
if(animate) {
submenu.slideUp('normal', function() {
$(this).parent().find('.active-menuitem').each(function() {
$this.deactivate($(this));
});
});
}
else {
item.find('.active-menuitem').each(function() {
$this.deactivate($(this));
});
}
$this.removeMenuitem(item.attr('id'));
activeSubItems.each(function() {
$this.removeMenuitem($(this).attr('id'));
});
}
else {
item.find('.active-menuitem').each(function() {
var subItem = $(this);
$this.deactivate(subItem);
$this.removeMenuitem(subItem.attr('id'));
});
}
}
else if(item.hasClass('active-menuitem')) {
$this.deactivate(item);
$this.removeMenuitem(item.attr('id'));
}
}
},
removeMenuitem: function (id) {
this.expandedMenuitems = $.grep(this.expandedMenuitems, function (value) {
return value !== id;
});
this.saveMenuState();
},
addMenuitem: function (id) {
if ($.inArray(id, this.expandedMenuitems) === -1) {
this.expandedMenuitems.push(id);
}
this.saveMenuState();
},
saveMenuState: function() {
if(this.wrapper.hasClass('layout-static'))
$.cookie('freya_menu_static', 'freya_menu_static', {path: '/'});
else
$.removeCookie('freya_menu_static', {path: '/'});
$.cookie('freya_expandeditems', this.expandedMenuitems.join(','), {path: '/'});
},
clearMenuState: function() {
this.expandedMenuitems = [];
$.removeCookie('freya_expandeditems', {path: '/'});
$.removeCookie('freya_menu_static', {path: '/'});
},
clearActiveItems: function() {
var activeItems = this.jq.find('li.active-menuitem'),
subContainers = activeItems.children('ul');
activeItems.removeClass('active-menuitem');
if(subContainers && subContainers.length) {
subContainers.hide();
}
},
clearLayoutState: function() {
this.clearMenuState();
this.clearActiveItems();
},
restoreMenuState: function() {
var menuCookie = $.cookie('freya_expandeditems');
if (!this.isSlim() && !this.isHorizontal() && menuCookie) {
this.expandedMenuitems = menuCookie.split(',');
for (var i = 0; i < this.expandedMenuitems.length; i++) {
var id = this.expandedMenuitems[i];
if (id) {
var menuitem = $("#" + this.expandedMenuitems[i].replace(/:/g, "\\:"));
menuitem.addClass('active-menuitem');
var submenu = menuitem.children('ul');
if(submenu.length) {
submenu.show();
}
}
}
}
var sidebarCookie = $.cookie('freya_menu_static');
if(sidebarCookie) {
this.wrapper.addClass('layout-static');
}
},
removeTopbarClassFromAllItems: function(item, className, items) {
var activeItems = item != null ? item.siblings('.' + className) : items;
activeItems.removeClass(className);
activeItems.children('ul').removeClass('fadeInDown');
},
addTopbarClass: function(item, className) {
var submenu = item.children('ul');
if (submenu.length) {
if (item.hasClass(className)) {
submenu.removeClass('fadeInDown').addClass('fadeOutUp');
setTimeout(function() {
item.removeClass(className);
submenu.removeClass('fadeOutUp');
}, 100);
}
else {
item.addClass(className);
submenu.addClass('fadeInDown');
}
}
},
hideTopBar: function() {
var $this = this;
this.topbarMenu.addClass('fadeOutUp');
setTimeout(function() {
$this.topbarMenu.removeClass('fadeOutUp topbar-menu-visible');
},500);
},
isMobile: function() {
return window.innerWidth < 992;
},
isHorizontal: function() {
return this.wrapper.hasClass('layout-horizontal') && !this.isMobile();
},
isSlim: function() {
return this.wrapper.hasClass('layout-slim') && !this.isMobile();
},
isStatic: function() {
return this.wrapper.hasClass('layout-static') && !this.isMobile();
}
});
PrimeFaces.FreyaConfigurator = {
changeLayout: function( componentTheme, darkMode ) {
this.changeLayoutsTheme(darkMode);
this.changeDemo(darkMode);
this.changeComponentsTheme(componentTheme, darkMode);
this.changeSectionTheme( darkMode, 'layout-menu');
this.changeSectionTheme( darkMode , 'layout-topbar');
},
changeLayoutsTheme: function(darkMode) {
newLayout = '-' + darkMode;
var linkElement = $('link[href*="layout-"]');
var href = linkElement.attr('href');
var startIndexOf = href.indexOf('layout-') + 6;
var endIndexOf = href.indexOf('.css');
var currentColor = href.substring(startIndexOf, endIndexOf);
this.replaceLink(linkElement, href.replace(currentColor, newLayout));
},
changeDemo: function(darkMode) {
newLayout = '-' + darkMode;
var linkElement = $('link[href*="demo-"]');
var href = linkElement.attr('href');
var startIndexOf = href.indexOf('demo-') + 4;
var endIndexOf = href.indexOf('.css');
var currentColor = href.substring(startIndexOf, endIndexOf);
this.replaceLink(linkElement, href.replace(currentColor, newLayout));
},
changeComponentsTheme: function(themeColor, darkMode) {
theme = this.getColor(themeColor, darkMode);
var library = 'primefaces-freya';
var linkElement = $('link[href*="theme.css"]');
var href = linkElement.attr('href');
var index = href.indexOf(library) + 1;
var currentTheme = href.substring(index + library.length);
this.replaceLink(linkElement, href.replace(currentTheme, theme));
},
changeSectionTheme: function(theme, section) {
var wrapperElement = $('.layout-wrapper');
var styleClass = wrapperElement.attr('class');
var tokens = styleClass.split(' ');
var sectionClass;
for (var i = 0; i < tokens.length; i++) {
if (tokens[i].indexOf(section + '-') > -1) {
sectionClass = tokens[i];
break;
}
}
wrapperElement.attr('class', styleClass.replace(sectionClass, section + '-' + theme));
},
changeMenuMode: function(menuMode) {
var wrapper = $(document.body).children('.layout-wrapper');
switch (menuMode) {
case 'layout-sidebar':
wrapper.addClass('layout-sidebar').removeClass('layout-slim layout-horizontal ');
this.clearLayoutState();
break;
case 'layout-horizontal':
wrapper.addClass('layout-horizontal').removeClass('layout-static layout-slim layout-sidebar');
this.clearLayoutState();
break;
case 'layout-slim':
wrapper.addClass('layout-slim').removeClass('layout-static layout-horizontal layout-sidebar');
this.clearLayoutState();
break;
default:
wrapper.addClass('layout-sidebar').removeClass('layout-slim layout-horizontal ');
this.clearLayoutState();
break;
}
},
beforeResourceChange: function() {
PrimeFaces.ajax.RESOURCE = null; //prevent resource append
},
replaceLink: function(linkElement, href) {
PrimeFaces.ajax.RESOURCE = 'javax.faces.Resource';
var isIE = this.isIE();
if (isIE) {
linkElement.attr('href', href);
}
else {
var cloneLinkElement = linkElement.clone(false);
cloneLinkElement.attr('href', href);
linkElement.after(cloneLinkElement);
cloneLinkElement.off('load').on('load', function() {
linkElement.remove();
});
// for dashboard
setTimeout(function() {
if (window['redrawChart']) {
window.redrawChart();
}
}, 100);
}
},
getColor: function(name, darkMode) {
return name + '-' + darkMode;
},
isIE: function() {
return /(MSIE|Trident\/|Edge\/)/i.test(navigator.userAgent);
},
clearLayoutState: function() {
var menu = PF('FreyaMenuWidget');
if (menu) {
menu.clearLayoutState();
}
},
updateInputStyle: function(value) {
if (value === 'filled')
$(document.body).addClass('ui-input-filled');
else
$(document.body).removeClass('ui-input-filled');
}
};
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2006, 2014 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD (Register as an anonymous module)
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch (e) { }
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (arguments.length > 1 && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {},
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
cookies = document.cookie ? document.cookie.split('; ') : [],
i = 0,
l = cookies.length;
for (; i < l; i++) {
var parts = cookies[i].split('='),
name = decode(parts.shift()),
cookie = parts.join('=');
if (key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));
if (PrimeFaces.widget.InputSwitch) {
PrimeFaces.widget.InputSwitch = PrimeFaces.widget.InputSwitch.extend({
init: function (cfg) {
this._super(cfg);
if (this.input.prop('checked')) {
this.jq.addClass('ui-inputswitch-checked');
}
},
check: function () {
var $this = this;
this.input.prop('checked', true).trigger('change');
setTimeout(function () {
$this.jq.addClass('ui-inputswitch-checked');
}, 100);
},
uncheck: function () {
var $this = this;
this.input.prop('checked', false).trigger('change');
setTimeout(function () {
$this.jq.removeClass('ui-inputswitch-checked');
}, 100);
}
});
}
if (PrimeFaces.widget.AccordionPanel) {
PrimeFaces.widget.AccordionPanel = PrimeFaces.widget.AccordionPanel.extend({
init: function (cfg) {
this._super(cfg);
this.headers.last().addClass('ui-accordion-header-last');
}
});
}
/* Issue #924 is fixed for 5.3+ and 6.0. (compatibility with 5.3) */
if(window['PrimeFaces'] && window['PrimeFaces'].widget.Dialog) {
PrimeFaces.widget.Dialog = PrimeFaces.widget.Dialog.extend({
enableModality: function() {
this._super();
$(document.body).children(this.jqId + '_modal').addClass('ui-dialog-mask');
},
syncWindowResize: function() {}
});
}
if (PrimeFaces.widget.SelectOneMenu) {
PrimeFaces.widget.SelectOneMenu = PrimeFaces.widget.SelectOneMenu.extend({
init: function (cfg) {
this._super(cfg);
var $this = this;
if (this.jq.parent().hasClass('ui-float-label')) {
this.m_panel = $(this.jqId + '_panel');
this.m_focusInput = $(this.jqId + '_focus');
this.m_panel.addClass('ui-input-overlay-panel');
this.jq.addClass('ui-inputwrapper');
if (this.input.val() != '') {
this.jq.addClass('ui-inputwrapper-filled');
}
this.input.off('change').on('change', function () {
$this.inputValueControl($(this));
});
this.m_focusInput.on('focus.ui-selectonemenu', function () {
$this.jq.addClass('ui-inputwrapper-focus');
})
.on('blur.ui-selectonemenu', function () {
$this.jq.removeClass('ui-inputwrapper-focus');
});
if (this.cfg.editable) {
this.label.on('input', function (e) {
$this.inputValueControl($(this));
}).on('focus', function () {
$this.jq.addClass('ui-inputwrapper-focus');
}).on('blur', function () {
$this.jq.removeClass('ui-inputwrapper-focus');
$this.inputValueControl($(this));
});
}
}
},
inputValueControl: function (input) {
if (input.val() != '')
this.jq.addClass('ui-inputwrapper-filled');
else
this.jq.removeClass('ui-inputwrapper-filled');
}
});
}
if (PrimeFaces.widget.Chips) {
PrimeFaces.widget.Chips = PrimeFaces.widget.Chips.extend({
init: function (cfg) {
this._super(cfg);
var $this = this;
if (this.jq.parent().hasClass('ui-float-label')) {
this.jq.addClass('ui-inputwrapper');
if ($this.jq.find('.ui-chips-token').length !== 0) {
this.jq.addClass('ui-inputwrapper-filled');
}
this.input.on('focus.ui-chips', function () {
$this.jq.addClass('ui-inputwrapper-focus');
}).on('input.ui-chips', function () {
$this.inputValueControl();
}).on('blur.ui-chips', function () {
$this.jq.removeClass('ui-inputwrapper-focus');
$this.inputValueControl();
});
}
},
inputValueControl: function () {
if (this.jq.find('.ui-chips-token').length !== 0 || this.input.val() != '')
this.jq.addClass('ui-inputwrapper-filled');
else
this.jq.removeClass('ui-inputwrapper-filled');
}
});
}
if (PrimeFaces.widget.DatePicker) {
PrimeFaces.widget.DatePicker = PrimeFaces.widget.DatePicker.extend({
init: function (cfg) {
this._super(cfg);
var $this = this;
if (this.jq.parent().hasClass('ui-float-label') && !this.cfg.inline) {
if (this.input.val() != '') {
this.jq.addClass('ui-inputwrapper-filled');
}
this.jqEl.off('focus.ui-datepicker blur.ui-datepicker change.ui-datepicker')
.on('focus.ui-datepicker', function () {
$this.jq.addClass('ui-inputwrapper-focus');
})
.on('blur.ui-datepicker', function () {
$this.jq.removeClass('ui-inputwrapper-focus');
})
.on('change.ui-datepicker', function () {
$this.inputValueControl($(this));
});
}
},
inputValueControl: function (input) {
if (input.val() != '')
this.jq.addClass('ui-inputwrapper-filled');
else
this.jq.removeClass('ui-inputwrapper-filled');
}
});
}

File diff suppressed because one or more lines are too long