1810 lines
73 KiB
PHP
1810 lines
73 KiB
PHP
<?php
|
||
|
||
/**
|
||
* Hub promoteur — MSIN-4401
|
||
* Liste / droits du hub = accès V2 uniquement (inscriptions_eve_acces).
|
||
* Legacy (com_eve_promoteur) reste dans le menu « Info promoteur », pas dans le hub.
|
||
*/
|
||
|
||
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
||
|
||
// Seuil de quantite a partir duquel une epreuve est consideree "illimitee"
|
||
// (ancien usage : plafond geant pour suivre les ventes sans gerer la limite).
|
||
if (!defined('PHUB_SEUIL_ILLIMITE')) {
|
||
define('PHUB_SEUIL_ILLIMITE', 10000);
|
||
}
|
||
|
||
function fxPromoteurHubComUsesV2($intComId)
|
||
{
|
||
return fxEveAccesComHasV2(intval($intComId));
|
||
}
|
||
|
||
/** La page compte_promoteur_hub est-elle installee (SQL applique) ? */
|
||
function fxPromoteurHubPageExists()
|
||
{
|
||
global $objDatabase;
|
||
|
||
static $blnExists = null;
|
||
|
||
if ($blnExists !== null) {
|
||
return $blnExists;
|
||
}
|
||
|
||
if (!isset($objDatabase)) {
|
||
$blnExists = false;
|
||
return $blnExists;
|
||
}
|
||
|
||
$intNb = $objDatabase->fxGetVar(
|
||
"SELECT COUNT(*) FROM inscriptions_pages WHERE pag_code = 'compte_promoteur_hub' AND pag_actif = 1"
|
||
);
|
||
|
||
$blnExists = ($intNb !== null && intval($intNb) > 0);
|
||
|
||
return $blnExists;
|
||
}
|
||
|
||
/** Hub v2 disponible (acces v2 + page CMS) — pour lien menu, pas pour forcer /compte. */
|
||
function fxPromoteurHubIsAvailable($intComId)
|
||
{
|
||
return fxPromoteurHubComUsesV2(intval($intComId)) && fxPromoteurHubPageExists();
|
||
}
|
||
|
||
/**
|
||
* Atterrissage par défaut sur le hub v2 (/compte, redirect après login public).
|
||
* Compte avec accès v2 + page hub installée → tableau de bord promoteur.
|
||
* Le toggle promoteur_legacy_actif ne s'applique qu'aux droits com_eve_promoteur (fxIsPromoteur), pas ici.
|
||
*/
|
||
function fxPromoteurHubShouldUse($intComId)
|
||
{
|
||
return fxPromoteurHubIsAvailable($intComId);
|
||
}
|
||
|
||
function fxPromoteurHubUrl($strLangue = 'fr', $intEveId = 0)
|
||
{
|
||
global $vDomaine;
|
||
|
||
$strUrl = $vDomaine . ($strLangue === 'fr' ? '/compte/promoteur_hub' : '/account/promoteur_hub');
|
||
// MSIN-4399 — Deep-link : hub_eve=id pour rouvrir la carte / menu de l'événement.
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId > 0) {
|
||
$strUrl .= '?hub_eve=' . $intEveId;
|
||
}
|
||
|
||
return $strUrl;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4399 — Retour « tableau promoteur » depuis un menu V2 :
|
||
* hub + focus eve si dispo, sinon ancien inc_tableau_promoteur.
|
||
*/
|
||
function fxPromoteurHubOrLegacyBackUrl($intEveId, $strLangue = 'fr')
|
||
{
|
||
global $vDomaine;
|
||
|
||
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
|
||
$intEveId = intval($intEveId);
|
||
$intComId = intval($_SESSION['com_id'] ?? 0);
|
||
|
||
if ($intComId > 0 && fxPromoteurHubIsAvailable($intComId)) {
|
||
return fxPromoteurHubUrl($strLangue, $intEveId);
|
||
}
|
||
|
||
$strPage = ($strLangue === 'en') ? '/account' : '/compte';
|
||
|
||
return $vDomaine . $strPage . '/inc_tableau_promoteur'
|
||
. '?promoteur_eve_id=' . urlencode(base64_encode((string)$intEveId));
|
||
}
|
||
|
||
/**
|
||
* MSIN-4399 — eve_id à ouvrir automatiquement sur le hub (?hub_eve= ou promoteur_eve_id).
|
||
*/
|
||
function fxPromoteurHubParseFocusEveId()
|
||
{
|
||
if (!empty($_GET['hub_eve'])) {
|
||
return max(0, intval($_GET['hub_eve']));
|
||
}
|
||
|
||
if (!empty($_GET['promoteur_eve_id'])) {
|
||
$mix = $_GET['promoteur_eve_id'];
|
||
$decoded = base64_decode(urldecode((string)$mix), true);
|
||
if ($decoded !== false && $decoded !== '' && ctype_digit((string)$decoded)) {
|
||
return intval($decoded);
|
||
}
|
||
if (ctype_digit((string)$mix)) {
|
||
return intval($mix);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
function fxPromoteurHubParticipantUrl($strLangue = 'fr')
|
||
{
|
||
global $vDomaine;
|
||
|
||
return $vDomaine . ($strLangue === 'fr' ? '/compte/accueil' : '/account/accueil');
|
||
}
|
||
|
||
function fxPromoteurHubPromoteurTableUrl($intEveId, $strLangue = 'fr')
|
||
{
|
||
global $vDomaine;
|
||
|
||
$strBase = ($strLangue === 'fr') ? '/compte/inc_tableau_promoteur' : '/account/inc_tableau_promoteur';
|
||
|
||
return $vDomaine . $strBase . '?promoteur_eve_id=' . urlencode(base64_encode(intval($intEveId)));
|
||
}
|
||
|
||
function fxPromoteurHubPermKeysWeb()
|
||
{
|
||
// MSIN-4401 — pages hub + détails V2 (plus d'anciennes clés API)
|
||
return array(
|
||
'hub.dashboard',
|
||
'inscriptions_gestion.view',
|
||
'inscriptions_gestion.qr_scan',
|
||
'inscriptions_gestion.statut_edit',
|
||
'inscriptions_gestion.bib_edit',
|
||
'inscriptions_gestion.bib_remis',
|
||
'inscriptions_gestion.edit',
|
||
'inscriptions_gestion.cancel',
|
||
'inscriptions_gestion.restore',
|
||
'inscriptions_gestion.refund',
|
||
'inscriptions.view',
|
||
'inscriptions.edit',
|
||
'dossards.view',
|
||
'dossards.manage',
|
||
'epreuves.view',
|
||
'epreuves.edit_qte',
|
||
'rabais.view',
|
||
'rabais.manage',
|
||
'emails.send',
|
||
'reports.chrono',
|
||
'reports.finances',
|
||
'reports.finances_membership',
|
||
'reports.finances_events',
|
||
'reports.payments',
|
||
'reports.adhesions',
|
||
'reports.adhesions_sales',
|
||
'reports.finances_captains',
|
||
'reports.custom',
|
||
'team.view',
|
||
'team.invite',
|
||
'team.manage',
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Accès web promoteur pour un événement : Legacy (com_eve_promoteur) OU permissions V2.
|
||
* Utilisé hors hub (ex. modes paiement promoteur). Le hub lui-même ne passe plus par Legacy.
|
||
*/
|
||
function fxPromoteurHubCanAccessPromoteurWeb($intComId, $intEveId, $arrLegacyFlip = null)
|
||
{
|
||
if (is_array($arrLegacyFlip) && isset($arrLegacyFlip[intval($intEveId)])) {
|
||
return true;
|
||
}
|
||
|
||
if (!function_exists('fxIsPromoteur')) {
|
||
require_once __DIR__ . '/inc_fonctions.php';
|
||
}
|
||
|
||
if (fxIsPromoteur(intval($intComId), intval($intEveId))) {
|
||
return true;
|
||
}
|
||
|
||
if (!fxEveAccesComHasV2ForEvent(intval($intComId), intval($intEveId))) {
|
||
return false;
|
||
}
|
||
|
||
return fxEveAccesHasAnyPermission(intval($intComId), intval($intEveId), fxPromoteurHubPermKeysWeb());
|
||
}
|
||
|
||
/**
|
||
* MSIN-4401 — Accès menu fonctionnalités hub : V2 uniquement (pas de bypass Legacy).
|
||
* Prérequis : $arrV2EventFlip, $arrWebPermFlip préchargés.
|
||
*/
|
||
function fxPromoteurHubCanAccessPromoteurWebBatch($intComId, $intEveId, $arrV2EventFlip, $arrWebPermFlip)
|
||
{
|
||
$intEveId = intval($intEveId);
|
||
|
||
if (!isset($arrV2EventFlip[$intEveId])) {
|
||
return false;
|
||
}
|
||
|
||
return isset($arrWebPermFlip[$intEveId]);
|
||
}
|
||
|
||
function fxPromoteurHubParseDateTs($strDate)
|
||
{
|
||
$strDate = trim((string)$strDate);
|
||
|
||
if ($strDate === '' || strpos($strDate, '0000-00-00') === 0) {
|
||
return 0;
|
||
}
|
||
|
||
return strtotime(substr($strDate, 0, 10));
|
||
}
|
||
|
||
function fxPromoteurHubHighlightUntilTs($strDateDebut, $strDateFin)
|
||
{
|
||
$intDebut = fxPromoteurHubParseDateTs($strDateDebut);
|
||
$intFin = fxPromoteurHubParseDateTs($strDateFin);
|
||
$intRef = ($intFin > 0) ? max($intDebut, $intFin) : $intDebut;
|
||
|
||
if ($intRef <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
return strtotime('+14 days', $intRef);
|
||
}
|
||
|
||
function fxPromoteurHubFormatEventDate($arrEvent, $strLangue)
|
||
{
|
||
$strDebut = trim($arrEvent['eve_date_debut'] ?? '');
|
||
$strFin = trim($arrEvent['eve_date_fin'] ?? '');
|
||
|
||
if ($strDebut === '' || strpos($strDebut, '0000-00-00') === 0) {
|
||
return '';
|
||
}
|
||
|
||
$strFmtDebut = date('Y-m-d', fxPromoteurHubParseDateTs($strDebut));
|
||
$intFin = fxPromoteurHubParseDateTs($strFin);
|
||
|
||
if ($intFin <= 0 || $strFmtDebut === date('Y-m-d', $intFin)) {
|
||
return $strFmtDebut;
|
||
}
|
||
|
||
return $strFmtDebut . ' — ' . date('Y-m-d', $intFin);
|
||
}
|
||
|
||
function fxPromoteurHubGetRoleLabelsByEvent($intComId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$arrByEve = array();
|
||
$tabRows = fxEveAccesListByComId(intval($intComId));
|
||
|
||
if (!is_array($tabRows)) {
|
||
return $arrByEve;
|
||
}
|
||
|
||
for ($i = 1; $i <= count($tabRows); $i++) {
|
||
$row = $tabRows[$i];
|
||
if (($row['ea_statut'] ?? '') !== 'actif') {
|
||
continue;
|
||
}
|
||
|
||
$intEveId = intval($row['eve_id'] ?? 0);
|
||
if ($intEveId <= 0) {
|
||
continue;
|
||
}
|
||
|
||
$strLabel = trim($row['role_label_fr'] ?? '');
|
||
if ($strLabel === '') {
|
||
$strLabel = trim($row['role_code'] ?? '');
|
||
}
|
||
|
||
if ($strLabel === '') {
|
||
continue;
|
||
}
|
||
|
||
if (!isset($arrByEve[$intEveId])) {
|
||
$arrByEve[$intEveId] = array();
|
||
}
|
||
|
||
if (!in_array($strLabel, $arrByEve[$intEveId], true)) {
|
||
$arrByEve[$intEveId][] = $strLabel;
|
||
}
|
||
}
|
||
|
||
return $arrByEve;
|
||
}
|
||
|
||
/** Evenements promoteur legacy (com_eve_promoteur) pour ce compte. */
|
||
function fxPromoteurHubGetLegacyEventIds($intComId)
|
||
{
|
||
if (!function_exists('fxPromoteurLegacySiteEnabled')) {
|
||
require_once __DIR__ . '/inc_fonctions.php';
|
||
}
|
||
|
||
if (!fxPromoteurLegacySiteEnabled()) {
|
||
return array();
|
||
}
|
||
|
||
global $objDatabase;
|
||
|
||
$row = $objDatabase->fxGetRow(
|
||
'SELECT com_eve_promoteur FROM inscriptions_comptes WHERE com_id = ' . intval($intComId)
|
||
);
|
||
|
||
if ($row === null || trim((string)$row['com_eve_promoteur']) === '') {
|
||
return array();
|
||
}
|
||
|
||
return array_map('trim', explode(',', $row['com_eve_promoteur']));
|
||
}
|
||
|
||
function fxPromoteurHubGetEvents($intComId, $strLangue = 'fr')
|
||
{
|
||
global $objDatabase, $vDomaine, $vRepertoireFichiers;
|
||
|
||
$arrHighlight = array();
|
||
$arrArchived = array();
|
||
|
||
// MSIN-4401 — Hub V2 : uniquement les événements avec accès V2 (pas de fantômes Legacy).
|
||
$arrV2EventIds = fxEveAccesGetEventIds(intval($intComId));
|
||
|
||
$arrIds = array_values(array_unique(array_filter(array_map('intval', $arrV2EventIds), function ($v) {
|
||
return $v > 0;
|
||
})));
|
||
|
||
if (empty($arrIds)) {
|
||
return array('highlight' => $arrHighlight, 'archived' => $arrArchived);
|
||
}
|
||
|
||
$strLang = in_array($strLangue, array('fr', 'en'), true) ? $strLangue : 'fr';
|
||
$strAlt = ($strLang === 'fr') ? 'en' : 'fr';
|
||
$arrRoles = fxPromoteurHubGetRoleLabelsByEvent(intval($intComId));
|
||
$intToday = strtotime(date('Y-m-d'));
|
||
$arrV2EventFlip = array_flip($arrIds);
|
||
$arrWebPermFlip = array_flip(fxEveAccesGetEventIdsWithAnyPermission(intval($intComId), fxPromoteurHubPermKeysWeb()));
|
||
|
||
if (!function_exists('fxInscrGestionGetPromoteurEveIds')) {
|
||
require_once __DIR__ . '/inc_fx_inscriptions_gestion.php';
|
||
}
|
||
$arrInscrGestionFlip = array_flip(array_map('intval', fxInscrGestionGetPromoteurEveIds(intval($intComId))));
|
||
|
||
$sql = "
|
||
SELECT e.eve_id, e.eve_nom_fr, e.eve_nom_en, e.eve_date_debut, e.eve_date_fin,
|
||
e.eve_lieu_fr, e.eve_lieu_en, e.eve_photo_fr, e.eve_photo_en,
|
||
e.te_id, e.eve_qte_modifiable, e.eve_rapport_finances_capitaines,
|
||
t.te_icone
|
||
FROM inscriptions_evenements e
|
||
JOIN inscriptions_types_evenements t ON t.te_id = e.te_id
|
||
WHERE e.eve_actif = 1
|
||
AND e.eve_id IN (" . implode(',', $arrIds) . ")
|
||
ORDER BY e.eve_date_debut ASC, e.eve_nom_fr ASC
|
||
";
|
||
$tabEvents = $objDatabase->fxGetResults($sql);
|
||
|
||
if (!is_array($tabEvents)) {
|
||
return array('highlight' => $arrHighlight, 'archived' => $arrArchived);
|
||
}
|
||
|
||
for ($i = 1; $i <= count($tabEvents); $i++) {
|
||
$row = $tabEvents[$i];
|
||
$intEveId = intval($row['eve_id']);
|
||
$strNom = trim($row['eve_nom_' . $strLang] ?? '');
|
||
|
||
if ($strNom === '') {
|
||
$strNom = trim($row['eve_nom_' . $strAlt] ?? '');
|
||
}
|
||
|
||
$strLieu = trim($row['eve_lieu_' . $strLang] ?? '');
|
||
if ($strLieu === '') {
|
||
$strLieu = trim($row['eve_lieu_' . $strAlt] ?? '');
|
||
}
|
||
|
||
if (intval($row['eve_id']) === 175 && trim($row['eve_photo_' . $strLang] ?? '') !== '') {
|
||
$strIcon = $vDomaine . $vRepertoireFichiers . '/images/evenements/' . $row['eve_photo_' . $strLang];
|
||
} else {
|
||
$strIcon = $vDomaine . '/images/' . ($row['te_icone'] ?? '');
|
||
}
|
||
|
||
$intHighlightUntil = fxPromoteurHubHighlightUntilTs($row['eve_date_debut'] ?? '', $row['eve_date_fin'] ?? '');
|
||
$blnHighlight = ($intHighlightUntil <= 0) || ($intToday <= $intHighlightUntil);
|
||
|
||
$arrItem = array(
|
||
'eve_id' => $intEveId,
|
||
'nom' => $strNom,
|
||
'lieu' => $strLieu,
|
||
'date_label' => fxPromoteurHubFormatEventDate($row, $strLang),
|
||
'ts_debut' => fxPromoteurHubParseDateTs($row['eve_date_debut'] ?? ''),
|
||
'icon' => $strIcon,
|
||
'roles' => $arrRoles[$intEveId] ?? array(),
|
||
'te_id' => intval($row['te_id'] ?? 0),
|
||
'qte_modifiable' => intval($row['eve_qte_modifiable'] ?? 0),
|
||
'rapport_capitaines' => intval($row['eve_rapport_finances_capitaines'] ?? 0),
|
||
'com_id' => intval($intComId),
|
||
'url_promoteur' => fxPromoteurHubCanAccessPromoteurWebBatch($intComId, $intEveId, $arrV2EventFlip, $arrWebPermFlip)
|
||
? fxPromoteurHubPromoteurTableUrl($intEveId, $strLang)
|
||
: '',
|
||
'url_mobile' => '',
|
||
);
|
||
|
||
if (isset($arrInscrGestionFlip[$intEveId])) {
|
||
$arrItem['url_mobile'] = fxInscrGestionBaseUrl($strLang, false)
|
||
. '?promoteur_eve_id=' . urlencode(base64_encode($intEveId));
|
||
}
|
||
|
||
if ($blnHighlight) {
|
||
$arrHighlight[] = $arrItem;
|
||
} else {
|
||
$arrArchived[] = $arrItem;
|
||
}
|
||
}
|
||
|
||
usort($arrHighlight, function ($a, $b) {
|
||
$ta = intval($a['ts_debut'] ?? 0);
|
||
$tb = intval($b['ts_debut'] ?? 0);
|
||
if ($ta === $tb) {
|
||
return strcasecmp($a['nom'], $b['nom']);
|
||
}
|
||
if ($ta <= 0) {
|
||
return 1;
|
||
}
|
||
if ($tb <= 0) {
|
||
return -1;
|
||
}
|
||
return $ta <=> $tb;
|
||
});
|
||
|
||
usort($arrArchived, function ($a, $b) {
|
||
$ta = intval($a['ts_debut'] ?? 0);
|
||
$tb = intval($b['ts_debut'] ?? 0);
|
||
if ($ta === $tb) {
|
||
return strcasecmp($b['nom'], $a['nom']);
|
||
}
|
||
return $tb <=> $ta;
|
||
});
|
||
|
||
return array('highlight' => $arrHighlight, 'archived' => $arrArchived);
|
||
}
|
||
|
||
function fxPromoteurHubEsc($str)
|
||
{
|
||
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
||
}
|
||
|
||
/** Page info / i18n hub promoteur — toujours compte.php (y compris AJAX). */
|
||
function fxPromoteurHubInfoPage()
|
||
{
|
||
return 'compte.php';
|
||
}
|
||
|
||
/**
|
||
* Lit info_texte depuis $vtexte_page ou la BD (compte.php / global).
|
||
* N'écrit jamais dans info — évite les doublons info_prg=ajax_promoteur_hub.php.
|
||
*/
|
||
function fxPromoteurHubGetInfoRow($clef)
|
||
{
|
||
global $vtexte_page, $objDatabase, $strLangue;
|
||
|
||
if (!empty($vtexte_page[$clef])) {
|
||
return $vtexte_page[$clef];
|
||
}
|
||
|
||
static $hubInfoCache = array();
|
||
if (array_key_exists($clef, $hubInfoCache)) {
|
||
return $hubInfoCache[$clef];
|
||
}
|
||
|
||
if (!isset($objDatabase)) {
|
||
$hubInfoCache[$clef] = array();
|
||
return $hubInfoCache[$clef];
|
||
}
|
||
|
||
$strLang = !empty($strLangue) ? $strLangue : 'fr';
|
||
$strPage = fxPromoteurHubInfoPage();
|
||
$sql = "SELECT info_texte, info_aide, info_prg FROM info
|
||
WHERE info_actif = 1
|
||
AND info_clef = '" . $objDatabase->fxEscape($clef) . "'
|
||
AND info_langue = '" . $objDatabase->fxEscape($strLang) . "'
|
||
AND info_prg IN ('" . $strPage . "', 'global')
|
||
ORDER BY FIELD(info_prg, '" . $strPage . "', 'global')
|
||
LIMIT 1";
|
||
$row = $objDatabase->fxGetRow($sql);
|
||
if (!is_array($row) || empty($row)) {
|
||
// Entrées legacy créées par erreur sous ajax_promoteur_hub.php — lecture seule.
|
||
$sqlLegacy = "SELECT info_texte, info_aide, info_prg FROM info
|
||
WHERE info_actif = 1
|
||
AND info_clef = '" . $objDatabase->fxEscape($clef) . "'
|
||
AND info_langue = '" . $objDatabase->fxEscape($strLang) . "'
|
||
AND info_prg = 'ajax_promoteur_hub.php'
|
||
LIMIT 1";
|
||
$row = $objDatabase->fxGetRow($sqlLegacy);
|
||
}
|
||
$hubInfoCache[$clef] = is_array($row) ? $row : array();
|
||
return $hubInfoCache[$clef];
|
||
}
|
||
|
||
/** Repli FR/EN si clé absente ou mal saisie en BD (menu fonctionnalités AJAX). */
|
||
function fxPromoteurHubStaticFallback($clef, $strLangParam = '')
|
||
{
|
||
if ($strLangParam === '') {
|
||
global $strLangue;
|
||
$strLangParam = !empty($strLangue) ? $strLangue : 'fr';
|
||
}
|
||
$lng = ($strLangParam === 'en') ? 'en' : 'fr';
|
||
// MSIN-4401 — filet si Info absente (jamais la source de vérité).
|
||
$tab = array(
|
||
'promoteur_hub_section_gestion' => array('fr' => 'Gestion', 'en' => 'Management'),
|
||
'promoteur_hub_link_dashboard' => array('fr' => 'Tableau de bord V2', 'en' => 'V2 dashboard'),
|
||
'promoteur_hub_no_features' => array(
|
||
'fr' => 'Aucune fonctionnalité disponible avec vos droits actuels.',
|
||
'en' => 'No features available with your current permissions.',
|
||
),
|
||
'promoteur_hub_menu' => array('fr' => 'Tableau de bord V2', 'en' => 'V2 dashboard'),
|
||
'tableau_promoteur_menurapports' => array('fr' => 'Rapports', 'en' => 'Reports'),
|
||
'tableau_promoteur_menudossard' => array('fr' => 'Dossards', 'en' => 'Bibs'),
|
||
'tableau_promoteur_menuepreuves' => array('fr' => 'Épreuves', 'en' => 'Races'),
|
||
'tableau_promoteur_menu_gestion_qte_dossards' => array('fr' => 'Gestion des quantités et dossards', 'en' => 'Quantities and bib management'),
|
||
'tableau_promoteur_menueinscription' => array('fr' => 'Inscriptions', 'en' => 'Registrations'),
|
||
'tableau_promoteur_rabais' => array('fr' => 'Rabais', 'en' => 'Discounts'),
|
||
'tableau_promoteur_envoie_email_questions' => array('fr' => 'Envoi courriel questions', 'en' => 'Send question emails'),
|
||
'promoteur_hub_load_menu' => array('fr' => 'Chargement du menu…', 'en' => 'Loading menu…'),
|
||
'promoteur_hub_load_dashboard' => array('fr' => 'Chargement du tableau de bord…', 'en' => 'Loading dashboard…'),
|
||
'promoteur_hub_epreuves_title' => array('fr' => 'Épreuves en vente', 'en' => 'Events for sale'),
|
||
'promoteur_hub_produits_title' => array('fr' => 'Produits en vente', 'en' => 'Products for sale'),
|
||
'promoteur_hub_bibs_sold' => array('fr' => 'dossards vendus', 'en' => 'bibs sold'),
|
||
'promoteur_hub_restant' => array('fr' => 'restant', 'en' => 'left'),
|
||
'promoteur_hub_unlimited' => array('fr' => 'illimité', 'en' => 'unlimited'),
|
||
'promoteur_hub_prix_courant' => array('fr' => 'Prix courant', 'en' => 'Current price'),
|
||
'promoteur_hub_prochain_prix' => array('fr' => 'Prochain prix', 'en' => 'Next price'),
|
||
'promoteur_hub_des' => array('fr' => 'dès', 'en' => 'on'),
|
||
'promoteur_hub_dossards_remis' => array('fr' => 'Dossards remis', 'en' => 'Bibs handed out'),
|
||
'promoteur_hub_liste_active' => array('fr' => 'liste active', 'en' => 'list active'),
|
||
'promoteur_hub_waiting_n' => array('fr' => 'en attente', 'en' => 'waiting'),
|
||
'promoteur_hub_waiting_list' => array('fr' => 'Liste d\'attente', 'en' => 'Waiting list'),
|
||
'promoteur_hub_disponible' => array('fr' => 'disponible(s)', 'en' => 'available'),
|
||
'promoteur_hub_vendus_title' => array('fr' => 'Vendus', 'en' => 'Sold'),
|
||
'promoteur_hub_vendus_lbl' => array('fr' => 'vendu(s)', 'en' => 'sold'),
|
||
'promoteur_hub_paniers_title' => array('fr' => 'Dans des paniers incomplets', 'en' => 'In incomplete carts'),
|
||
'promoteur_hub_paniers_lbl' => array('fr' => 'panier(s)', 'en' => 'cart(s)'),
|
||
'promoteur_hub_menu_features' => array('fr' => 'Menu des fonctionnalités', 'en' => 'Features menu'),
|
||
// MSIN-4451 — total = somme des inscriptions par épreuve (pas d'humains uniques)
|
||
'promoteur_hub_flash_inscrits' => array('fr' => 'épreuves vendues', 'en' => 'entries sold'),
|
||
'promoteur_hub_flash_participants' => array('fr' => 'participants', 'en' => 'participants'),
|
||
'promoteur_hub_flash_rempli' => array('fr' => 'rempli', 'en' => 'filled'),
|
||
'promoteur_hub_flash_places' => array('fr' => 'places restantes', 'en' => 'spots left'),
|
||
'promoteur_hub_flash_revenus' => array('fr' => 'revenus est.', 'en' => 'est. revenue'),
|
||
'promoteur_hub_badge_completes' => array('fr' => 'complète(s)', 'en' => 'sold out'),
|
||
'promoteur_hub_badge_presque' => array('fr' => 'presque pleine(s)', 'en' => 'almost full'),
|
||
'promoteur_hub_badge_attente' => array('fr' => 'en attente', 'en' => 'waiting'),
|
||
'promoteur_hub_badge_limite' => array('fr' => 'limite', 'en' => 'deadline'),
|
||
'promoteur_hub_ajax_session' => array('fr' => 'Session expirée', 'en' => 'Session expired'),
|
||
'promoteur_hub_ajax_invalid' => array('fr' => 'Requête invalide', 'en' => 'Invalid request'),
|
||
'promoteur_hub_ajax_denied' => array('fr' => 'Accès refusé', 'en' => 'Access denied'),
|
||
'promoteur_hub_ajax_not_found' => array('fr' => 'Événement introuvable', 'en' => 'Event not found'),
|
||
'promoteur_hub_ajax_error' => array('fr' => 'Erreur', 'en' => 'Error'),
|
||
'promoteur_hub_rapport_chrono' => array('fr' => 'chrono + questions', 'en' => 'chrono + questions'),
|
||
'promoteur_hub_rapport_finances' => array('fr' => 'Transactions-Finances', 'en' => 'Transactions-Finances'),
|
||
'promoteur_hub_rapport_finances_all' => array('fr' => 'Transactions-Finances-Tout', 'en' => 'Transactions-Finances-All'),
|
||
'promoteur_hub_rapport_finances_adh' => array('fr' => 'Transactions-Finances-Adhésions Seul', 'en' => 'Transactions-Finances-Memberships only'),
|
||
'promoteur_hub_rapport_finances_eve' => array('fr' => 'Transactions-Finances-Événements Seul', 'en' => 'Transactions-Finances-Events only'),
|
||
'promoteur_hub_rapport_adhesions' => array('fr' => 'adhésions actives', 'en' => 'active memberships'),
|
||
'promoteur_hub_rapport_adhesions_annuelles' => array('fr' => 'liste d\'adhésions annuelles', 'en' => 'annual memberships list'),
|
||
'promoteur_hub_rapport_finances_capitaines' => array('fr' => 'Transactions-Finances (capitaines seulement)', 'en' => 'Transactions-Finances (captains only)'),
|
||
'promoteur_hub_rapport_paiements' => array('fr' => 'Paiements', 'en' => 'Payments'),
|
||
);
|
||
|
||
return $tab[$clef][$lng] ?? '';
|
||
}
|
||
|
||
/**
|
||
* Libellé hub — sur compte.php délègue à afficheTexte ; en AJAX, lecture seule.
|
||
*/
|
||
function fxPromoteurHubTexte($clef, $mem_echo = 0)
|
||
{
|
||
if (!defined('MS1_PROMOTEUR_HUB_AJAX') || !MS1_PROMOTEUR_HUB_AJAX) {
|
||
return afficheTexte($clef, $mem_echo);
|
||
}
|
||
|
||
$row = fxPromoteurHubGetInfoRow($clef);
|
||
$str = trim($row['info_texte'] ?? '');
|
||
|
||
if ($str === '' || $str === $clef || $str === '*' . $clef . '*') {
|
||
$str = fxPromoteurHubStaticFallback($clef);
|
||
if ($str === '') {
|
||
$str = $clef;
|
||
}
|
||
}
|
||
|
||
if ($mem_echo == 1) {
|
||
echo $str;
|
||
}
|
||
|
||
return $str;
|
||
}
|
||
|
||
/**
|
||
* Liste des fonctions d'un evenement (groupes : rapports + gestion),
|
||
* fidele a inc_tableau_promoteur.php.
|
||
*/
|
||
/**
|
||
* MSIN-4401 — liens hub :
|
||
* - Super admin / kit total (grants_all) → tout
|
||
* - Accès V2 présent → menus selon les pages du kit (prioritaire sur legacy)
|
||
* - Legacy seul (com_eve_promoteur, sans V2) → menus complets comme avant
|
||
*/
|
||
function fxPromoteurHubGetEventLinks($arrItem, $strLangue)
|
||
{
|
||
global $vDomaine, $objDatabase;
|
||
|
||
$intEveId = intval($arrItem['eve_id']);
|
||
$intComId = intval($arrItem['com_id'] ?? ($_SESSION['com_id'] ?? 0));
|
||
$intTeId = intval($arrItem['te_id'] ?? 0);
|
||
$blnDon = ($intTeId == 9);
|
||
$strE = urlencode(base64_encode($intEveId));
|
||
$strRapport = $vDomaine . '/superadm/rapport_new.php?r=';
|
||
$strCompte = $vDomaine . ($strLangue === 'fr' ? '/compte/' : '/account/');
|
||
$year = date('Y');
|
||
$strDateTq = $year . '-04-01 00:00:00';
|
||
|
||
if (!function_exists('fxEveAccesHasAnyPermission')) {
|
||
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
||
}
|
||
if (!function_exists('fxIsPromoteur')) {
|
||
require_once __DIR__ . '/inc_fonctions.php';
|
||
}
|
||
|
||
$blnSuper = !empty($_SESSION['usa_id']);
|
||
$blnHasV2 = fxEveAccesComHasV2ForEvent($intComId, $intEveId);
|
||
$blnLegacyPromoteur = fxIsPromoteur($intComId, $intEveId);
|
||
// Menus « tout ouvert » legacy seulement si PAS de kit V2 sur cet événement
|
||
$blnLegacyMenus = $blnLegacyPromoteur && !$blnHasV2;
|
||
$blnGrantsAll = $blnHasV2 && fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId);
|
||
|
||
$fnCan = function ($arrKeys) use ($intComId, $intEveId, $blnSuper, $blnLegacyMenus, $blnGrantsAll) {
|
||
if ($blnSuper || $blnLegacyMenus || $blnGrantsAll) {
|
||
return true;
|
||
}
|
||
return fxEveAccesHasAnyPermission($intComId, $intEveId, $arrKeys);
|
||
};
|
||
|
||
$arrRapports = array();
|
||
$arrGestion = array();
|
||
|
||
// ---- Rapports (niveau 1 V2 : chrono / finances / paiements) ----
|
||
if ($intTeId != 9 && $fnCan(array('reports.chrono'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_chrono', 0),
|
||
'url' => $strRapport . 'chrono&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
|
||
if ($fnCan(array('reports.finances', 'reports.finances_membership', 'reports.finances_events'))) {
|
||
if ($intTeId == 13) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_finances_all', 0),
|
||
'url' => $strRapport . 'finances-membership&e=' . $strE . '&lng=' . $strLangue . '&a-ach_maj_from=' . urlencode($strDateTq) . '&btn_search=',
|
||
'target' => '_blank',
|
||
);
|
||
} else {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_finances', 0),
|
||
'url' => $strRapport . 'finances&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
}
|
||
|
||
if ($intTeId == 13 && $fnCan(array('reports.finances_membership', 'reports.finances_events', 'reports.adhesions', 'reports.adhesions_sales'))) {
|
||
if ($fnCan(array('reports.finances_membership'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_finances_adh', 0),
|
||
'url' => $strRapport . 'finances-membership-tq&e=' . $strE . '&lng=' . $strLangue . '&a-ach_maj_from=' . urlencode($strDateTq) . '&btn_search=',
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
if ($fnCan(array('reports.finances_events'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_finances_eve', 0),
|
||
'url' => $strRapport . 'finances-membership-autre&e=' . $strE . '&lng=' . $strLangue . '&a-ach_maj_from=' . urlencode($strDateTq) . '&btn_search=',
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
if ($fnCan(array('reports.adhesions'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_adhesions', 0),
|
||
'url' => $strRapport . 'adhesions&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
if ($fnCan(array('reports.adhesions_sales'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_adhesions_annuelles', 0),
|
||
'url' => $strRapport . 'adhesions-ventes&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
}
|
||
|
||
if (intval($arrItem['rapport_capitaines'] ?? 0) == 1 && $fnCan(array('reports.finances_captains'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_finances_capitaines', 0),
|
||
'url' => $strRapport . 'finances-pnq&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
|
||
if ($fnCan(array('reports.payments'))) {
|
||
$arrRapports[] = array(
|
||
'label' => fxPromoteurHubTexte('promoteur_hub_rapport_paiements', 0),
|
||
'url' => $strRapport . 'remboursements&e=' . $strE . '&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
|
||
if (($blnLegacyMenus || $blnGrantsAll || $blnSuper || $fnCan(array('reports.custom'))) && function_exists('fxGetMenussuperadm')) {
|
||
$tabRapports = fxGetMenussuperadm(0, 0, 1, $intEveId);
|
||
if (is_array($tabRapports)) {
|
||
for ($intCtr = 1; $intCtr <= count($tabRapports); $intCtr++) {
|
||
$arrRapports[] = array(
|
||
'label' => fxUnescape($tabRapports[$intCtr]['men_nom']),
|
||
'url' => $vDomaine . '/superadm/index.php?t=' . urlencode(base64_encode(fxUnescape($tabRapports[$intCtr]['men_id']))) . '&a=report&lng=' . $strLangue,
|
||
'target' => '_blank',
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ---- Gestion ----
|
||
// MSIN-4399 — Entrées V2 en tête de liste, puis legacy / autres.
|
||
if (!$blnDon && $fnCan(array('dossards.manage', 'epreuves.edit_qte'))) {
|
||
$strMenuQte = fxPromoteurHubTexte('tableau_promoteur_menu_gestion_qte_dossards', 0);
|
||
$arrGestion[] = array('label' => $strMenuQte, 'url' => $strCompte . 'inc_tableau_gestion_epreuves?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-pencil-square-o');
|
||
}
|
||
|
||
if (!function_exists('fxInscrGestionCanAccess')) {
|
||
require_once __DIR__ . '/inc_fx_inscriptions_gestion.php';
|
||
}
|
||
if (fxInscrGestionCanAccess($intComId, $intEveId)) {
|
||
$arrGestion[] = array('label' => fxInscrGestionPromoteurMenuLabel(), 'url' => $strCompte . 'inc_tableau_inscriptions_gestion?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-users');
|
||
}
|
||
|
||
if (!function_exists('fxEveAccesCanTeamInvite')) {
|
||
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
||
}
|
||
if (!function_exists('fxEveAccesPromoteurMenuLabel')) {
|
||
require_once __DIR__ . '/inc_fx_eve_acces_promoteur.php';
|
||
}
|
||
if (fxEveAccesCanTeamInvite($intComId, $intEveId)) {
|
||
$arrGestion[] = array(
|
||
'label' => fxEveAccesPromoteurMenuLabel($strLangue),
|
||
'url' => $strCompte . 'inc_tableau_eve_acces?promoteur_eve_id=' . $strE . '&lng=' . $strLangue,
|
||
'icon' => 'fa-key',
|
||
);
|
||
}
|
||
|
||
if (!$blnDon) {
|
||
// Menus legacy (dossards / quantités classiques) : promoteur legacy seul (sans kit V2)
|
||
if ($blnLegacyMenus || $blnSuper || $blnGrantsAll) {
|
||
$arrGestion[] = array('label' => fxPromoteurHubTexte('tableau_promoteur_menudossard', 0), 'url' => $strCompte . 'inc_tableau_dossards?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-id-card-o');
|
||
|
||
if (intval($arrItem['qte_modifiable'] ?? 0) == 1) {
|
||
$arrGestion[] = array('label' => fxPromoteurHubTexte('tableau_promoteur_menuepreuves', 0), 'url' => $strCompte . 'inc_tableau_epreuves?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-pencil-square-o');
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($blnLegacyMenus || $blnSuper || $blnGrantsAll) {
|
||
$arrGestion[] = array('label' => fxPromoteurHubTexte('tableau_promoteur_menueinscription', 0), 'url' => $strCompte . 'inc_tableau_inscriptions?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-users');
|
||
}
|
||
|
||
if ($fnCan(array('rabais.view', 'rabais.manage'))) {
|
||
$arrGestion[] = array('label' => fxPromoteurHubTexte('tableau_promoteur_rabais', 0), 'url' => $strCompte . 'inc_tableau_rabais?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-money');
|
||
}
|
||
|
||
if ($intTeId == 13 && ($blnLegacyMenus || $blnSuper || $blnGrantsAll)) {
|
||
$arrGestion[] = array('label' => fxPromoteurHubTexte('tableau_promoteur_envoie_email_questions', 0), 'url' => $strCompte . 'inc_tableau_mail_questions?promoteur_eve_id=' . $strE . '&lng=' . $strLangue, 'icon' => 'fa-paper-plane');
|
||
}
|
||
|
||
return array('rapports' => $arrRapports, 'gestion' => $arrGestion);
|
||
}
|
||
|
||
function fxPromoteurHubRenderLinkList($arrLinks, $strDefaultIcon)
|
||
{
|
||
if (empty($arrLinks)) {
|
||
return '';
|
||
}
|
||
|
||
$html = '<ul class="list-unstyled mb-0">';
|
||
|
||
foreach ($arrLinks as $arrLink) {
|
||
$strIcon = !empty($arrLink['icon']) ? $arrLink['icon'] : $strDefaultIcon;
|
||
$strTarget = !empty($arrLink['target']) ? ' target="' . fxPromoteurHubEsc($arrLink['target']) . '"' : '';
|
||
|
||
$html .= '<li class="mb-2">';
|
||
$html .= '<a class="btn btn-outline-primary btn-block text-left rounded-0" href="' . fxPromoteurHubEsc($arrLink['url']) . '"' . $strTarget . '>';
|
||
$html .= '<i class="fa ' . fxPromoteurHubEsc($strIcon) . ' mr-2" aria-hidden="true"></i>' . fxPromoteurHubEsc($arrLink['label']);
|
||
$html .= '</a></li>';
|
||
}
|
||
|
||
$html .= '</ul>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
/** MSIN-4401 — le menu fonctionnalités a-t-il au moins un lien (gestion ou rapports) ? */
|
||
function fxPromoteurHubEventHasFeatureLinks($arrItem, $strLangue)
|
||
{
|
||
$arrLinks = fxPromoteurHubGetEventLinks($arrItem, $strLangue);
|
||
|
||
return !empty($arrLinks['gestion']) || !empty($arrLinks['rapports']);
|
||
}
|
||
|
||
function fxPromoteurHubRenderEventPanelContent($arrItem, $strLangue)
|
||
{
|
||
$arrLinks = fxPromoteurHubGetEventLinks($arrItem, $strLangue);
|
||
$blnGestion = !empty($arrLinks['gestion']);
|
||
$blnRapports = !empty($arrLinks['rapports']);
|
||
|
||
// MSIN-4401 — pas d'en-têtes vides si aucun droit dans la section
|
||
if (!$blnGestion && !$blnRapports) {
|
||
return '<p class="text-muted small mb-0">'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_no_features', 0))
|
||
. '</p>';
|
||
}
|
||
|
||
$html = '<div class="row">';
|
||
|
||
if ($blnGestion) {
|
||
$strCol = $blnRapports ? 'col-12 col-lg-6 mb-3' : 'col-12 mb-3';
|
||
$html .= '<div class="' . $strCol . '">';
|
||
$html .= '<h6 class="text-uppercase text-muted mb-2"><i class="fa fa-cogs mr-2" aria-hidden="true"></i>'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_section_gestion', 0)) . '</h6>';
|
||
$html .= fxPromoteurHubRenderLinkList($arrLinks['gestion'], 'fa-list');
|
||
$html .= '</div>';
|
||
}
|
||
|
||
if ($blnRapports) {
|
||
$strCol = $blnGestion ? 'col-12 col-lg-6 mb-3' : 'col-12 mb-3';
|
||
$html .= '<div class="' . $strCol . '">';
|
||
$html .= '<h6 class="text-uppercase text-muted mb-2"><i class="fa fa-file mr-2" aria-hidden="true"></i>'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('tableau_promoteur_menurapports', 0)) . '</h6>';
|
||
$html .= fxPromoteurHubRenderLinkList($arrLinks['rapports'], 'fa-bar-chart');
|
||
$html .= '</div>';
|
||
}
|
||
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
/** Coquille du menu fonctionnalités — contenu chargé en AJAX au premier clic. */
|
||
function fxPromoteurHubRenderEventPanelShell($arrItem, $strLangue)
|
||
{
|
||
$strPanelId = 'hub-fn-' . intval($arrItem['eve_id']);
|
||
$intEveId = intval($arrItem['eve_id']);
|
||
$strLoadMsg = fxPromoteurHubTexte('promoteur_hub_load_menu', 0);
|
||
|
||
global $vDomaine;
|
||
$strRunnerSrc = $vDomaine . '/images/ms1-runner-loader.gif?v=' . _VERSION_CODE;
|
||
|
||
$html = '<div class="collapse promoteur-hub-functions mt-3" id="' . fxPromoteurHubEsc($strPanelId) . '"'
|
||
. ' data-hub-eve-id="' . $intEveId . '" data-hub-lang="' . fxPromoteurHubEsc($strLangue) . '">';
|
||
$html .= '<div class="promoteur-hub-links-placeholder ms1-loader ms1-loader--inline" role="status" aria-live="polite" aria-busy="true">'
|
||
. '<img class="ms1-loader__runner" src="' . fxPromoteurHubEsc($strRunnerSrc) . '" alt="" role="presentation" decoding="async">'
|
||
. '<span class="ms1-loader__label">' . fxPromoteurHubEsc($strLoadMsg) . '</span></div>';
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
function fxPromoteurHubRenderEventPanel($arrItem, $strLangue)
|
||
{
|
||
$strPanelId = 'hub-fn-' . intval($arrItem['eve_id']);
|
||
|
||
$html = '<div class="collapse promoteur-hub-functions mt-3" id="' . fxPromoteurHubEsc($strPanelId) . '">';
|
||
$html .= fxPromoteurHubRenderEventPanelContent($arrItem, $strLangue);
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
/** Métadonnées événement pour le menu AJAX (1 requête légère). */
|
||
function fxPromoteurHubGetEventItemForLinks($intComId, $intEveId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId <= 0 || !isset($objDatabase)) {
|
||
return null;
|
||
}
|
||
|
||
$row = $objDatabase->fxGetRow(
|
||
'SELECT eve_id, te_id, eve_qte_modifiable, eve_rapport_finances_capitaines
|
||
FROM inscriptions_evenements
|
||
WHERE eve_id = ' . $intEveId . ' AND eve_actif = 1'
|
||
);
|
||
|
||
if ($row === null) {
|
||
return null;
|
||
}
|
||
|
||
return array(
|
||
'eve_id' => intval($row['eve_id']),
|
||
'te_id' => intval($row['te_id'] ?? 0),
|
||
'qte_modifiable' => intval($row['eve_qte_modifiable'] ?? 0),
|
||
'rapport_capitaines' => intval($row['eve_rapport_finances_capitaines'] ?? 0),
|
||
'com_id' => intval($intComId),
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Statistiques par epreuve pour un evenement (vendus / restant / max,
|
||
* check-in, liste d'attente, prix courant + date du prochain palier).
|
||
* Requetes agregees (1 par metrique) plutot qu'une boucle fxGetQuantites,
|
||
* pour rester rapide dans le hub.
|
||
*
|
||
* Retourne array('epreuves' => [...], 'flash' => [...]) ou null si aucune epreuve.
|
||
*/
|
||
function fxPromoteurHubGetEpreuveStats($intEveId, $strLangue = 'fr')
|
||
{
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId <= 0 || !isset($objDatabase)) {
|
||
return null;
|
||
}
|
||
|
||
$strLang = in_array($strLangue, array('fr', 'en'), true) ? $strLangue : 'fr';
|
||
$strAlt = ($strLang === 'fr') ? 'en' : 'fr';
|
||
|
||
// ---- Liste des epreuves ----
|
||
$sqlEpreuves = "
|
||
SELECT epr_id, epr_categorie_fr, epr_categorie_en, epr_type_fr, epr_type_en,
|
||
epr_nom_fr, epr_nom_en, epr_date, epr_heure, epr_date_limite,
|
||
epr_qte, epr_qte_origine, epr_qte_limitee, epr_equipe, epr_nb_participants
|
||
FROM inscriptions_epreuves
|
||
WHERE eve_id = " . $intEveId . " AND epr_actif = 1
|
||
ORDER BY epr_tri, epr_type_" . $strLang . ", epr_nom_" . $strLang . "
|
||
";
|
||
$tabEpreuves = $objDatabase->fxGetResults($sqlEpreuves);
|
||
|
||
if (!is_array($tabEpreuves) || count($tabEpreuves) === 0) {
|
||
return null;
|
||
}
|
||
|
||
$arrIds = array();
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++) {
|
||
$arrIds[] = intval($tabEpreuves[$i]['epr_id']);
|
||
}
|
||
$strIds = implode(',', $arrIds);
|
||
|
||
// ---- Vendus / inscrits (confirmes, non annules) ----
|
||
$arrVendus = array();
|
||
$sqlVendus = "
|
||
SELECT p.epr_id AS epr_id, COUNT(DISTINCT e.pec_id_original) AS nb
|
||
FROM resultats_epreuves_commandees e
|
||
JOIN resultats_participants p
|
||
ON p.epr_id = e.epr_id AND p.pec_id = e.pec_id_original
|
||
WHERE p.is_cancelled = 0 AND p.epr_id IN (" . $strIds . ")
|
||
GROUP BY p.epr_id
|
||
";
|
||
$tabVendus = $objDatabase->fxGetResults($sqlVendus);
|
||
if (is_array($tabVendus)) {
|
||
for ($i = 1; $i <= count($tabVendus); $i++) {
|
||
$arrVendus[intval($tabVendus[$i]['epr_id'])] = intval($tabVendus[$i]['nb']);
|
||
}
|
||
}
|
||
|
||
// MSIN-4451 — Humains uniques (même personne sur 2 épreuves = 1).
|
||
// Clé : courriel normalisé ; sans courriel → par_id_original (pas de fusion).
|
||
$intFlashParticipants = 0;
|
||
$sqlParticipants = "
|
||
SELECT COUNT(DISTINCT
|
||
CASE
|
||
WHEN TRIM(IFNULL(p.par_courriel, '')) <> '' THEN LOWER(TRIM(p.par_courriel))
|
||
ELSE CONCAT('id:', p.par_id_original)
|
||
END
|
||
) AS nb
|
||
FROM resultats_epreuves_commandees e
|
||
JOIN resultats_participants p
|
||
ON p.epr_id = e.epr_id AND p.pec_id = e.pec_id_original
|
||
WHERE p.is_cancelled = 0 AND p.epr_id IN (" . $strIds . ")
|
||
";
|
||
$tabParticipants = $objDatabase->fxGetResults($sqlParticipants);
|
||
if (is_array($tabParticipants) && isset($tabParticipants[1]['nb'])) {
|
||
$intFlashParticipants = intval($tabParticipants[1]['nb']);
|
||
}
|
||
|
||
// ---- Check-in (dossards remis) ----
|
||
$arrCheckin = array();
|
||
$sqlCheckin = "
|
||
SELECT epr_id, COUNT(*) AS nb
|
||
FROM resultats_participants
|
||
WHERE no_bib_remis = 1 AND epr_id IN (" . $strIds . ")
|
||
GROUP BY epr_id
|
||
";
|
||
$tabCheckin = $objDatabase->fxGetResults($sqlCheckin);
|
||
if (is_array($tabCheckin)) {
|
||
for ($i = 1; $i <= count($tabCheckin); $i++) {
|
||
$arrCheckin[intval($tabCheckin[$i]['epr_id'])] = intval($tabCheckin[$i]['nb']);
|
||
}
|
||
}
|
||
|
||
// ---- Liste d'attente : nombre + statut actif ----
|
||
$arrAttenteNb = array();
|
||
$sqlAttente = "
|
||
SELECT epr_id, COUNT(1) AS nb
|
||
FROM inscriptions_liste_attente_participants
|
||
WHERE (lispar_statut = 1 OR lispar_statut = 2) AND epr_id IN (" . $strIds . ")
|
||
GROUP BY epr_id
|
||
";
|
||
$tabAttente = $objDatabase->fxGetResults($sqlAttente);
|
||
if (is_array($tabAttente)) {
|
||
for ($i = 1; $i <= count($tabAttente); $i++) {
|
||
$arrAttenteNb[intval($tabAttente[$i]['epr_id'])] = intval($tabAttente[$i]['nb']);
|
||
}
|
||
}
|
||
|
||
$arrAttenteActive = array();
|
||
$sqlAttenteActive = "
|
||
SELECT epr_id, lis_active
|
||
FROM inscriptions_liste_attente
|
||
WHERE epr_id IN (" . $strIds . ")
|
||
";
|
||
$tabAttenteActive = $objDatabase->fxGetResults($sqlAttenteActive);
|
||
if (is_array($tabAttenteActive)) {
|
||
for ($i = 1; $i <= count($tabAttenteActive); $i++) {
|
||
$arrAttenteActive[intval($tabAttenteActive[$i]['epr_id'])] = intval($tabAttenteActive[$i]['lis_active']);
|
||
}
|
||
}
|
||
|
||
// ---- Prix (paliers publics) : prix courant + date du prochain palier ----
|
||
$arrTiers = array();
|
||
$sqlPrix = "
|
||
SELECT epr_id, ep_montant, ep_montant_affiche, ep_date_limite
|
||
FROM inscriptions_epreuves_prix
|
||
WHERE ep_prive = 0 AND epr_id IN (" . $strIds . ")
|
||
ORDER BY epr_id, ep_date_limite ASC
|
||
";
|
||
$tabPrix = $objDatabase->fxGetResults($sqlPrix);
|
||
if (is_array($tabPrix)) {
|
||
for ($i = 1; $i <= count($tabPrix); $i++) {
|
||
$intEpr = intval($tabPrix[$i]['epr_id']);
|
||
$fltMontant = (floatval($tabPrix[$i]['ep_montant_affiche']) > 0)
|
||
? floatval($tabPrix[$i]['ep_montant_affiche'])
|
||
: floatval($tabPrix[$i]['ep_montant']);
|
||
if (!isset($arrTiers[$intEpr])) {
|
||
$arrTiers[$intEpr] = array();
|
||
}
|
||
$arrTiers[$intEpr][] = array(
|
||
'montant' => $fltMontant,
|
||
'date_limite' => trim((string)($tabPrix[$i]['ep_date_limite'] ?? '')),
|
||
);
|
||
}
|
||
}
|
||
|
||
$strToday = date('Y-m-d');
|
||
|
||
// ---- Assemblage par epreuve + agregat flash ----
|
||
$arrEpreuves = array();
|
||
$intFlashVendus = 0;
|
||
$intFlashMax = 0;
|
||
$intFlashAttente = 0;
|
||
$intFlashCompletes = 0;
|
||
$intFlashPresque = 0;
|
||
$fltFlashRevenus = 0.0;
|
||
$strFlashProchaineLimite = '';
|
||
|
||
for ($i = 1; $i <= count($tabEpreuves); $i++) {
|
||
$row = $tabEpreuves[$i];
|
||
$intEpr = intval($row['epr_id']);
|
||
|
||
$strTitre = trim((string)($row['epr_type_' . $strLang] ?? ''));
|
||
if ($strTitre === '') {
|
||
$strTitre = trim((string)($row['epr_type_' . $strAlt] ?? ''));
|
||
}
|
||
$strNom = trim((string)($row['epr_nom_' . $strLang] ?? ''));
|
||
if ($strNom === '') {
|
||
$strNom = trim((string)($row['epr_nom_' . $strAlt] ?? ''));
|
||
}
|
||
$strCategorie = trim((string)($row['epr_categorie_' . $strLang] ?? ''));
|
||
if ($strTitre === '') {
|
||
$strTitre = ($strNom !== '') ? $strNom : ('#' . $intEpr);
|
||
}
|
||
|
||
$intVendus = $arrVendus[$intEpr] ?? 0;
|
||
$intRestant = intval($row['epr_qte']);
|
||
// Max courant = places vendues + restantes ; origine = max initial fixe.
|
||
$intMax = $intVendus + $intRestant;
|
||
$intOrigine = intval($row['epr_qte_origine']);
|
||
// Ancien usage : un plafond "geant" (>= 10000) servait de faux maximum pour
|
||
// suivre les ventes sans gerer la limite. On le traite comme illimite.
|
||
$blnIllimitee = (intval($row['epr_qte_limitee']) !== 1)
|
||
|| $intMax >= PHUB_SEUIL_ILLIMITE
|
||
|| $intOrigine >= PHUB_SEUIL_ILLIMITE;
|
||
|
||
$fltPct = ($blnIllimitee || $intMax <= 0) ? 0 : round(($intVendus / $intMax) * 100);
|
||
if ($fltPct > 100) {
|
||
$fltPct = 100;
|
||
}
|
||
|
||
// Etat de remplissage : complete / presque / ok / illimitee
|
||
if ($blnIllimitee) {
|
||
$strEtat = 'illimitee';
|
||
} elseif ($intRestant <= 0) {
|
||
$strEtat = 'complete';
|
||
$intFlashCompletes++;
|
||
} elseif ($fltPct >= 90) {
|
||
$strEtat = 'presque';
|
||
$intFlashPresque++;
|
||
} elseif ($fltPct >= 75) {
|
||
$strEtat = 'attention';
|
||
} else {
|
||
$strEtat = 'ok';
|
||
}
|
||
|
||
// Prix courant + date du prochain palier
|
||
$fltPrixCourant = null;
|
||
$strPrixDateFin = '';
|
||
$fltPrixProchain = null;
|
||
if (!empty($arrTiers[$intEpr])) {
|
||
$arrEprTiers = $arrTiers[$intEpr];
|
||
$intIdxCourant = -1;
|
||
foreach ($arrEprTiers as $intIdx => $arrTier) {
|
||
if ($arrTier['date_limite'] !== '' && $arrTier['date_limite'] >= $strToday) {
|
||
$intIdxCourant = $intIdx;
|
||
break;
|
||
}
|
||
}
|
||
if ($intIdxCourant === -1) {
|
||
// Tous les paliers sont passes : on prend le dernier (prix final), pas de prochain.
|
||
$intIdxCourant = count($arrEprTiers) - 1;
|
||
}
|
||
$fltPrixCourant = $arrEprTiers[$intIdxCourant]['montant'];
|
||
$strPrixDateFin = $arrEprTiers[$intIdxCourant]['date_limite'];
|
||
if (isset($arrEprTiers[$intIdxCourant + 1])) {
|
||
$fltPrixProchain = $arrEprTiers[$intIdxCourant + 1]['montant'];
|
||
}
|
||
}
|
||
|
||
$intAttenteNb = $arrAttenteNb[$intEpr] ?? 0;
|
||
$blnAttenteActive = !empty($arrAttenteActive[$intEpr]);
|
||
|
||
// Agregat flash
|
||
$intFlashVendus += $intVendus;
|
||
if (!$blnIllimitee) {
|
||
$intFlashMax += $intMax;
|
||
}
|
||
$intFlashAttente += $intAttenteNb;
|
||
if ($fltPrixCourant !== null) {
|
||
$fltFlashRevenus += $fltPrixCourant * $intVendus;
|
||
}
|
||
// Prochaine date limite d'inscription (la plus proche, dans le futur)
|
||
$strLimiteInscr = trim((string)($row['epr_date_limite'] ?? ''));
|
||
if ($strLimiteInscr !== '' && strpos($strLimiteInscr, '0000') !== 0 && $strLimiteInscr >= $strToday) {
|
||
if ($strFlashProchaineLimite === '' || $strLimiteInscr < $strFlashProchaineLimite) {
|
||
$strFlashProchaineLimite = $strLimiteInscr;
|
||
}
|
||
}
|
||
|
||
$arrEpreuves[] = array(
|
||
'epr_id' => $intEpr,
|
||
'titre' => $strTitre,
|
||
'nom' => $strNom,
|
||
'categorie' => $strCategorie,
|
||
'date' => trim((string)($row['epr_date'] ?? '')),
|
||
'heure' => trim((string)($row['epr_heure'] ?? '')),
|
||
'date_limite_inscr' => $strLimiteInscr,
|
||
'equipe' => (intval($row['epr_equipe']) === 1),
|
||
'nb_participants' => intval($row['epr_nb_participants']),
|
||
'vendus' => $intVendus,
|
||
'restant' => $intRestant,
|
||
'max' => $intMax,
|
||
'origine' => $intOrigine,
|
||
'illimitee' => $blnIllimitee,
|
||
'pct' => $fltPct,
|
||
'etat' => $strEtat,
|
||
'checkin' => $arrCheckin[$intEpr] ?? 0,
|
||
'attente_nb' => $intAttenteNb,
|
||
'attente_active' => $blnAttenteActive,
|
||
'prix_courant' => $fltPrixCourant,
|
||
'prix_date_fin' => $strPrixDateFin,
|
||
'prix_prochain' => $fltPrixProchain,
|
||
);
|
||
}
|
||
|
||
$intPctGlobal = ($intFlashMax > 0) ? round(($intFlashVendus / $intFlashMax) * 100) : 0;
|
||
if ($intPctGlobal > 100) {
|
||
$intPctGlobal = 100;
|
||
}
|
||
|
||
$arrFlash = array(
|
||
'total_vendus' => $intFlashVendus,
|
||
'total_participants' => $intFlashParticipants,
|
||
'total_max' => $intFlashMax,
|
||
'total_restant' => max(0, $intFlashMax - $intFlashVendus),
|
||
'pct_global' => $intPctGlobal,
|
||
'revenus' => $fltFlashRevenus,
|
||
'nb_epreuves' => count($arrEpreuves),
|
||
'nb_completes' => $intFlashCompletes,
|
||
'nb_presque' => $intFlashPresque,
|
||
'total_attente' => $intFlashAttente,
|
||
'prochaine_date_limite' => $strFlashProchaineLimite,
|
||
);
|
||
|
||
return array('epreuves' => $arrEpreuves, 'flash' => $arrFlash);
|
||
}
|
||
|
||
/**
|
||
* Rendu de la ligne resume (bande flash + badges d'alerte). Toujours visible.
|
||
*/
|
||
function fxPromoteurHubRenderFlash($arrStats, $strLangue = 'fr')
|
||
{
|
||
if (empty($arrStats) || empty($arrStats['epreuves'])) {
|
||
return '';
|
||
}
|
||
|
||
$arrFlash = $arrStats['flash'];
|
||
|
||
$html = '';
|
||
|
||
// ---- Bande flash ----
|
||
$html .= '<div class="promoteur-hub-flash">';
|
||
|
||
// MSIN-4451 — Duo : épreuves vendues (KPI) + participants uniques (sous-ligne)
|
||
$html .= '<div class="phub-flash-item phub-flash-main">';
|
||
$html .= '<span class="phub-flash-num">' . intval($arrFlash['total_vendus']) . '</span>';
|
||
$html .= '<span class="phub-flash-lbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_flash_inscrits', 0)) . '</span>';
|
||
$html .= '<span class="phub-flash-sub">'
|
||
. intval($arrFlash['total_participants']) . ' '
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_flash_participants', 0))
|
||
. '</span>';
|
||
$html .= '</div>';
|
||
|
||
if (intval($arrFlash['total_max']) > 0) {
|
||
$html .= '<div class="phub-flash-item">';
|
||
$html .= '<span class="phub-flash-num">' . intval($arrFlash['pct_global']) . '%</span>';
|
||
$html .= '<span class="phub-flash-lbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_flash_rempli', 0)) . '</span>';
|
||
$html .= '</div>';
|
||
|
||
$html .= '<div class="phub-flash-item">';
|
||
$html .= '<span class="phub-flash-num">' . intval($arrFlash['total_restant']) . '</span>';
|
||
$html .= '<span class="phub-flash-lbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_flash_places', 0)) . '</span>';
|
||
$html .= '</div>';
|
||
}
|
||
|
||
if (floatval($arrFlash['revenus']) > 0) {
|
||
$html .= '<div class="phub-flash-item">';
|
||
$html .= '<span class="phub-flash-num">' . fxPromoteurHubEsc(fxShowPrix($arrFlash['revenus'], $strLangue)) . '</span>';
|
||
$html .= '<span class="phub-flash-lbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_flash_revenus', 0)) . '</span>';
|
||
$html .= '</div>';
|
||
}
|
||
|
||
$html .= '</div>'; // .promoteur-hub-flash
|
||
|
||
// ---- Badges d'alerte (MSIN-4452 : texte seul, sans icône) ----
|
||
$arrBadges = array();
|
||
if (intval($arrFlash['nb_completes']) > 0) {
|
||
$arrBadges[] = array('cls' => 'phub-badge-danger',
|
||
'txt' => intval($arrFlash['nb_completes']) . ' ' . fxPromoteurHubTexte('promoteur_hub_badge_completes', 0));
|
||
}
|
||
if (intval($arrFlash['nb_presque']) > 0) {
|
||
$arrBadges[] = array('cls' => 'phub-badge-warn',
|
||
'txt' => intval($arrFlash['nb_presque']) . ' ' . fxPromoteurHubTexte('promoteur_hub_badge_presque', 0));
|
||
}
|
||
if (intval($arrFlash['total_attente']) > 0) {
|
||
$arrBadges[] = array('cls' => 'phub-badge-info',
|
||
'txt' => intval($arrFlash['total_attente']) . ' ' . fxPromoteurHubTexte('promoteur_hub_badge_attente', 0));
|
||
}
|
||
if ($arrFlash['prochaine_date_limite'] !== '') {
|
||
$arrBadges[] = array('cls' => 'phub-badge-soft',
|
||
'txt' => fxPromoteurHubTexte('promoteur_hub_badge_limite', 0) . ' ' . fxShowDate($arrFlash['prochaine_date_limite'], $strLangue, 1));
|
||
}
|
||
if (!empty($arrBadges)) {
|
||
$html .= '<div class="promoteur-hub-badges">';
|
||
foreach ($arrBadges as $arrBadge) {
|
||
$html .= '<span class="phub-badge ' . $arrBadge['cls'] . '">'
|
||
. fxPromoteurHubEsc($arrBadge['txt']) . '</span>';
|
||
}
|
||
$html .= '</div>';
|
||
}
|
||
|
||
return $html;
|
||
}
|
||
|
||
/**
|
||
* Rendu de la grille de tuiles par epreuve (contenu du collapse « Tableau de bord »).
|
||
*/
|
||
function fxPromoteurHubRenderEpreuvesGrid($arrStats, $strLangue = 'fr')
|
||
{
|
||
if (empty($arrStats) || empty($arrStats['epreuves'])) {
|
||
return '';
|
||
}
|
||
|
||
// ---- Titre de section ----
|
||
$html = '<h6 class="promoteur-hub-produits-title text-uppercase text-muted">'
|
||
. '<i class="fa fa-flag-checkered mr-2" aria-hidden="true"></i>'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_epreuves_title', 0)) . '</h6>';
|
||
|
||
// ---- Tuiles par epreuve ----
|
||
$html .= '<div class="promoteur-hub-epreuves-grid">';
|
||
|
||
foreach ($arrStats['epreuves'] as $arrEpr) {
|
||
$strEtat = $arrEpr['etat'];
|
||
$html .= '<div class="phub-epr-tile phub-etat-' . fxPromoteurHubEsc($strEtat) . '">';
|
||
|
||
// En-tete : titre + categorie
|
||
$html .= '<div class="phub-epr-head">';
|
||
$html .= '<span class="phub-epr-titre">' . fxPromoteurHubEsc($arrEpr['titre']) . '</span>';
|
||
if ($arrEpr['categorie'] !== '') {
|
||
$html .= '<span class="phub-epr-cat">' . fxPromoteurHubEsc($arrEpr['categorie']) . '</span>';
|
||
}
|
||
if ($arrEpr['nom'] !== '' && $arrEpr['nom'] !== $arrEpr['titre']) {
|
||
$html .= '<span class="phub-epr-sub">' . fxPromoteurHubEsc($arrEpr['nom']) . '</span>';
|
||
}
|
||
$html .= '</div>';
|
||
|
||
// Gros chiffre : nombre de dossards vendus
|
||
$html .= '<div class="phub-epr-big">';
|
||
$html .= '<span class="phub-epr-bignum">' . intval($arrEpr['vendus']) . '</span>';
|
||
if (!$arrEpr['illimitee']) {
|
||
$html .= '<span class="phub-epr-max">/ ' . intval($arrEpr['max']) . '</span>';
|
||
}
|
||
$html .= '<span class="phub-epr-biglbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_bibs_sold', 0)) . '</span>';
|
||
$html .= '</div>';
|
||
|
||
// Barre de progression
|
||
if (!$arrEpr['illimitee'] && intval($arrEpr['max']) > 0) {
|
||
$html .= '<div class="phub-epr-bar"><span style="width:' . intval($arrEpr['pct']) . '%"></span></div>';
|
||
$html .= '<div class="phub-epr-barlbl">' . intval($arrEpr['pct']) . '% · '
|
||
. intval($arrEpr['restant']) . ' ' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_restant', 0)) . '</div>';
|
||
} else {
|
||
$html .= '<div class="phub-epr-barlbl phub-epr-illimite"><span class="phub-infini mr-1" aria-hidden="true">∞</span>'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_unlimited', 0)) . '</div>';
|
||
}
|
||
|
||
// Pastilles secondaires
|
||
$html .= '<div class="phub-epr-chips">';
|
||
|
||
if ($arrEpr['prix_courant'] !== null) {
|
||
$html .= '<span class="phub-chip phub-chip-prix" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_prix_courant', 0)) . '">'
|
||
. '<i class="fa fa-tag mr-1" aria-hidden="true"></i>' . fxPromoteurHubEsc(fxShowPrix($arrEpr['prix_courant'], $strLangue)) . '</span>';
|
||
|
||
if ($arrEpr['prix_prochain'] !== null && $arrEpr['prix_date_fin'] !== '' && $arrEpr['prix_date_fin'] >= date('Y-m-d')) {
|
||
$html .= '<span class="phub-chip phub-chip-next" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_prochain_prix', 0)) . '">'
|
||
. '<i class="fa fa-arrow-up mr-1" aria-hidden="true"></i>'
|
||
. fxPromoteurHubEsc(fxShowPrix($arrEpr['prix_prochain'], $strLangue))
|
||
. ' ' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_des', 0)) . ' '
|
||
. fxShowDate($arrEpr['prix_date_fin'], $strLangue, 1) . '</span>';
|
||
}
|
||
}
|
||
|
||
if (intval($arrEpr['checkin']) > 0) {
|
||
$html .= '<span class="phub-chip phub-chip-checkin" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_dossards_remis', 0)) . '">'
|
||
. '<i class="fa fa-check mr-1" aria-hidden="true"></i>' . intval($arrEpr['checkin']) . '</span>';
|
||
}
|
||
|
||
if (intval($arrEpr['attente_nb']) > 0 || $arrEpr['attente_active']) {
|
||
$strAtt = $arrEpr['attente_active'] && intval($arrEpr['attente_nb']) === 0
|
||
? fxPromoteurHubTexte('promoteur_hub_liste_active', 0)
|
||
: intval($arrEpr['attente_nb']) . ' ' . fxPromoteurHubTexte('promoteur_hub_waiting_n', 0);
|
||
$html .= '<span class="phub-chip phub-chip-attente" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_waiting_list', 0)) . '">'
|
||
. '<i class="fa fa-hourglass-half mr-1" aria-hidden="true"></i>' . fxPromoteurHubEsc($strAtt) . '</span>';
|
||
}
|
||
|
||
if ($arrEpr['date'] !== '' && strpos($arrEpr['date'], '0000') !== 0) {
|
||
$html .= '<span class="phub-chip phub-chip-date"><i class="fa fa-calendar-o mr-1" aria-hidden="true"></i>'
|
||
. fxShowDate($arrEpr['date'], $strLangue, 1) . '</span>';
|
||
}
|
||
|
||
$html .= '</div>'; // .phub-epr-chips
|
||
|
||
$html .= '</div>'; // .phub-epr-tile
|
||
}
|
||
|
||
$html .= '</div>'; // .promoteur-hub-epreuves-grid
|
||
|
||
return $html;
|
||
}
|
||
|
||
/**
|
||
* Produits a vendre (avec quantites) pour un evenement.
|
||
* Meme logique que superadm/check_qte_produits.php :
|
||
* restant = total (pro_qte) - vendus (commandes non annulees) - panier (paniers incomplets).
|
||
*
|
||
* Retourne un tableau de produits ou null si l'evenement n'a aucun produit actif.
|
||
*/
|
||
function fxPromoteurHubGetProduits($intEveId, $strLangue = 'fr')
|
||
{
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId <= 0 || !isset($objDatabase)) {
|
||
return null;
|
||
}
|
||
|
||
$strLang = in_array($strLangue, array('fr', 'en'), true) ? $strLangue : 'fr';
|
||
$strAlt = ($strLang === 'fr') ? 'en' : 'fr';
|
||
|
||
$sql = "
|
||
SELECT p1.pro_id, p1.pro_nom_fr, p1.pro_nom_en, p1.pro_qte AS dispo,
|
||
COALESCE(v.vendus, 0) AS vendus,
|
||
COALESCE(pa.panier, 0) AS panier
|
||
FROM inscriptions_produits_new p1
|
||
LEFT JOIN (
|
||
SELECT p2.pro_id, COUNT(*) AS vendus
|
||
FROM resultats_produits_new p2
|
||
JOIN resultats_epreuves_commandees c
|
||
ON c.pec_id_original = p2.pec_id AND c.is_cancelled = 0
|
||
JOIN inscriptions_produits_new px
|
||
ON px.pro_id = p2.pro_id AND px.eve_id = " . $intEveId . "
|
||
GROUP BY p2.pro_id
|
||
) v ON v.pro_id = p1.pro_id
|
||
LEFT JOIN (
|
||
SELECT p3.pro_id, COUNT(*) AS panier
|
||
FROM inscriptions_panier_produits_new p3
|
||
JOIN inscriptions_panier_acheteurs a
|
||
ON a.no_panier = p3.no_panier AND a.sta_id = 1
|
||
JOIN inscriptions_produits_new px
|
||
ON px.pro_id = p3.pro_id AND px.eve_id = " . $intEveId . "
|
||
GROUP BY p3.pro_id
|
||
) pa ON pa.pro_id = p1.pro_id
|
||
WHERE p1.eve_id = " . $intEveId . " AND p1.pro_actif = 1
|
||
ORDER BY p1.pro_nom_" . $strLang . ", p1.pro_nom_fr
|
||
";
|
||
$tabProduits = $objDatabase->fxGetResults($sql);
|
||
|
||
if (!is_array($tabProduits) || count($tabProduits) === 0) {
|
||
return null;
|
||
}
|
||
|
||
$arrProduits = array();
|
||
for ($i = 1; $i <= count($tabProduits); $i++) {
|
||
$row = $tabProduits[$i];
|
||
|
||
$strNom = trim((string)($row['pro_nom_' . $strLang] ?? ''));
|
||
if ($strNom === '') {
|
||
$strNom = trim((string)($row['pro_nom_' . $strAlt] ?? ''));
|
||
}
|
||
|
||
$intTotal = intval($row['dispo']);
|
||
$intVendus = intval($row['vendus']);
|
||
$intPanier = intval($row['panier']);
|
||
$intRestant = $intTotal - $intVendus - $intPanier;
|
||
if ($intRestant < 0) {
|
||
$intRestant = 0;
|
||
}
|
||
|
||
// Ancien usage : un plafond "geant" (>= 10000) sert de faux maximum
|
||
// pour suivre les ventes sans gerer la limite -> illimite.
|
||
$blnIllimite = ($intTotal >= PHUB_SEUIL_ILLIMITE);
|
||
|
||
$arrProduits[] = array(
|
||
'pro_id' => intval($row['pro_id']),
|
||
'nom' => ($strNom !== '') ? $strNom : ('#' . intval($row['pro_id'])),
|
||
'total' => $intTotal,
|
||
'vendus' => $intVendus,
|
||
'panier' => $intPanier,
|
||
'restant' => $intRestant,
|
||
'illimite' => $blnIllimite,
|
||
);
|
||
}
|
||
|
||
return $arrProduits;
|
||
}
|
||
|
||
/**
|
||
* Rendu de la section « Produits en vente » (liste produits + quantites).
|
||
* MSIN-4454 — Gros chiffre = vendus / total ; pastille = disponibles.
|
||
* N'affiche rien si aucun produit.
|
||
*/
|
||
function fxPromoteurHubRenderProduits($arrProduits, $strLangue = 'fr')
|
||
{
|
||
if (empty($arrProduits)) {
|
||
return '';
|
||
}
|
||
|
||
$html = '<div class="promoteur-hub-produits">';
|
||
$html .= '<h6 class="promoteur-hub-produits-title text-uppercase text-muted">'
|
||
. '<i class="fa fa-shopping-bag mr-2" aria-hidden="true"></i>'
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_produits_title', 0)) . '</h6>';
|
||
$html .= '<div class="promoteur-hub-produits-grid">';
|
||
|
||
foreach ($arrProduits as $arrProd) {
|
||
$blnIllimite = !empty($arrProd['illimite']);
|
||
$blnEpuise = (!$blnIllimite && intval($arrProd['restant']) <= 0);
|
||
$strState = $blnIllimite ? 'illimitee' : ($blnEpuise ? 'complete' : 'ok');
|
||
|
||
$html .= '<div class="phub-prod-tile phub-etat-' . $strState . '">';
|
||
|
||
$html .= '<span class="phub-prod-nom">' . fxPromoteurHubEsc($arrProd['nom']) . '</span>';
|
||
|
||
// MSIN-4454 — Gros chiffre : vendus (aligné sur les tuiles épreuves)
|
||
$html .= '<div class="phub-prod-big">';
|
||
$html .= '<span class="phub-prod-num">' . intval($arrProd['vendus']) . '</span>';
|
||
if (!$blnIllimite) {
|
||
$html .= '<span class="phub-prod-tot">/ ' . intval($arrProd['total']) . '</span>';
|
||
}
|
||
$html .= '<span class="phub-prod-lbl">' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_vendus_lbl', 0)) . '</span>';
|
||
$html .= '</div>';
|
||
|
||
$html .= '<div class="phub-epr-chips">';
|
||
$html .= '<span class="phub-chip phub-chip-checkin" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_disponible', 0)) . '">';
|
||
if ($blnIllimite) {
|
||
$html .= '<span class="phub-infini mr-1" aria-hidden="true">∞</span>';
|
||
} else {
|
||
$html .= intval($arrProd['restant']) . ' ';
|
||
}
|
||
$html .= fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_disponible', 0)) . '</span>';
|
||
if (intval($arrProd['panier']) > 0) {
|
||
$html .= '<span class="phub-chip phub-chip-attente" title="' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_paniers_title', 0)) . '">'
|
||
. '<i class="fa fa-shopping-cart mr-1" aria-hidden="true"></i>' . intval($arrProd['panier']) . ' '
|
||
. fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_paniers_lbl', 0)) . '</span>';
|
||
}
|
||
$html .= '</div>'; // .phub-epr-chips
|
||
|
||
$html .= '</div>'; // .phub-prod-tile
|
||
}
|
||
|
||
$html .= '</div>'; // .promoteur-hub-produits-grid
|
||
$html .= '</div>'; // .promoteur-hub-produits
|
||
|
||
return $html;
|
||
}
|
||
|
||
/** Stats lourdes (resultats_*) pour une carte hub — utilisé par AJAX au clic. */
|
||
function fxPromoteurHubRenderEventStatsBundle($intEveId, $strLangue = 'fr')
|
||
{
|
||
$arrStats = fxPromoteurHubGetEpreuveStats(intval($intEveId), $strLangue);
|
||
$arrProduits = fxPromoteurHubGetProduits(intval($intEveId), $strLangue);
|
||
|
||
return array(
|
||
'flash' => fxPromoteurHubRenderFlash($arrStats, $strLangue),
|
||
'html' => fxPromoteurHubRenderEpreuvesGrid($arrStats, $strLangue)
|
||
. fxPromoteurHubRenderProduits($arrProduits, $strLangue),
|
||
);
|
||
}
|
||
|
||
/** MSIN-4401 — Accès hub à cet événement : V2 uniquement (pas Legacy). */
|
||
function fxPromoteurHubComHasEvent($intComId, $intEveId)
|
||
{
|
||
$intEveId = intval($intEveId);
|
||
if ($intComId <= 0 || $intEveId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
return fxEveAccesComHasV2ForEvent(intval($intComId), $intEveId);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4401 — droit de voir le Tableau de bord (chiffres hub).
|
||
* Super admin / kit total / legacy seul → oui ; sinon hub.dashboard.
|
||
*/
|
||
function fxPromoteurHubCanViewDashboard($intComId, $intEveId)
|
||
{
|
||
if (!empty($_SESSION['usa_id'])) {
|
||
return true;
|
||
}
|
||
|
||
$intComId = intval($intComId);
|
||
$intEveId = intval($intEveId);
|
||
if ($intComId <= 0 || $intEveId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
if (!function_exists('fxEveAccesHasPermission')) {
|
||
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
||
}
|
||
if (!function_exists('fxIsPromoteur')) {
|
||
require_once __DIR__ . '/inc_fonctions.php';
|
||
}
|
||
|
||
if (fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId)) {
|
||
return true;
|
||
}
|
||
|
||
$blnHasV2 = fxEveAccesComHasV2ForEvent($intComId, $intEveId);
|
||
if (!$blnHasV2 && fxIsPromoteur($intComId, $intEveId)) {
|
||
return true;
|
||
}
|
||
|
||
return fxEveAccesHasPermission($intComId, $intEveId, 'hub.dashboard');
|
||
}
|
||
|
||
function fxPromoteurHubRenderEventCard($arrItem, $strLangue, $blnArchived = false)
|
||
{
|
||
$strCardClass = 'card promoteur-hub-card mb-3' . ($blnArchived ? ' promoteur-hub-card-archived' : '');
|
||
|
||
$intEveId = intval($arrItem['eve_id']);
|
||
$intComId = intval($arrItem['com_id'] ?? ($_SESSION['com_id'] ?? 0));
|
||
|
||
// Stats reportées au clic (AJAX) : N événements × requêtes resultats_* = timeout avec données prod.
|
||
$strFlash = '';
|
||
$strGrid = '';
|
||
$strProduits = '';
|
||
$blnHasStats = !$blnArchived && fxPromoteurHubCanViewDashboard($intComId, $intEveId);
|
||
// MSIN-4401 — bouton menu seulement s'il y a au moins un lien (pas d'en-têtes vides)
|
||
$blnFonctions = fxPromoteurHubEventHasFeatureLinks($arrItem, $strLangue);
|
||
$strEprId = 'hub-epr-' . $intEveId;
|
||
$strFnId = 'hub-fn-' . $intEveId;
|
||
|
||
$html = '<div class="' . fxPromoteurHubEsc($strCardClass) . '" id="hub-eve-' . $intEveId . '"'
|
||
. ' data-hub-eve-id="' . $intEveId . '">';
|
||
$html .= '<div class="card-body">';
|
||
|
||
// ---- Haut : identite (gauche) + resume flash (droite) ----
|
||
$html .= '<div class="row promoteur-hub-card-row">';
|
||
$html .= '<div class="' . ($blnHasStats || $strFlash !== '' ? 'col-12 col-lg-5' : 'col-12') . ' promoteur-hub-card-main">';
|
||
$html .= '<div class="d-flex align-items-center flex-wrap">';
|
||
$html .= '<div class="promoteur-hub-card-icon mr-3"><img src="' . fxPromoteurHubEsc($arrItem['icon']) . '" width="64" alt=""></div>';
|
||
$html .= '<div class="flex-grow-1">';
|
||
$html .= '<h2 class="h5 mb-1 promoteur-hub-event-title">' . fxPromoteurHubEsc($arrItem['nom']) . '</h2>';
|
||
|
||
if ($arrItem['date_label'] !== '') {
|
||
$html .= '<div class="text-muted small"><i class="fa fa-calendar-o mr-1" aria-hidden="true"></i>' . fxPromoteurHubEsc($arrItem['date_label']) . '</div>';
|
||
}
|
||
|
||
if ($arrItem['lieu'] !== '') {
|
||
$html .= '<div class="text-muted small"><i class="fa fa-map-marker mr-1" aria-hidden="true"></i>' . fxPromoteurHubEsc($arrItem['lieu']) . '</div>';
|
||
}
|
||
|
||
if (!empty($arrItem['roles'])) {
|
||
$html .= '<div class="small mt-1 text-muted">' . fxPromoteurHubEsc(implode(' · ', $arrItem['roles'])) . '</div>';
|
||
}
|
||
|
||
$html .= '</div></div>';
|
||
$html .= '</div>'; // .promoteur-hub-card-main
|
||
|
||
if ($blnHasStats) {
|
||
$html .= '<div class="col-12 col-lg-7 promoteur-hub-card-flash-wrap"></div>';
|
||
} elseif ($strFlash !== '') {
|
||
$html .= '<div class="col-12 col-lg-7 promoteur-hub-card-flash">' . $strFlash . '</div>';
|
||
}
|
||
|
||
$html .= '</div>'; // .promoteur-hub-card-row
|
||
|
||
// ---- Boutons d'action (pleine largeur) ----
|
||
if ($blnHasStats || $blnFonctions) {
|
||
$html .= '<div class="promoteur-hub-actions mt-3">';
|
||
|
||
if ($blnHasStats) {
|
||
$html .= '<button type="button" class="btn btn-primary rounded-pill mr-2 mb-2 promoteur-hub-toggle collapsed" data-toggle="collapse" data-target="#' . fxPromoteurHubEsc($strEprId) . '" aria-expanded="false" aria-controls="' . fxPromoteurHubEsc($strEprId) . '">';
|
||
$html .= '<i class="fa fa-tachometer mr-2" aria-hidden="true"></i>' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_btn_tableau', 0));
|
||
$html .= '<i class="fa fa-chevron-down ml-2 promoteur-hub-toggle-caret" aria-hidden="true"></i>';
|
||
$html .= '</button>';
|
||
}
|
||
|
||
if ($blnFonctions) {
|
||
$html .= '<button type="button" class="btn btn-outline-primary rounded-pill mb-2 promoteur-hub-toggle collapsed" data-toggle="collapse" data-target="#' . fxPromoteurHubEsc($strFnId) . '" aria-expanded="false" aria-controls="' . fxPromoteurHubEsc($strFnId) . '">';
|
||
$html .= '<i class="fa fa-bars mr-2" aria-hidden="true"></i>' . fxPromoteurHubEsc(fxPromoteurHubTexte('promoteur_hub_menu_features', 0));
|
||
$html .= '<i class="fa fa-chevron-down ml-2 promoteur-hub-toggle-caret" aria-hidden="true"></i>';
|
||
$html .= '</button>';
|
||
}
|
||
|
||
$html .= '</div>'; // .promoteur-hub-actions
|
||
}
|
||
|
||
// ---- Collapse : stats chargées au clic (ajax_promoteur_hub.php) ----
|
||
if ($blnHasStats) {
|
||
global $vDomaine;
|
||
$strLoadMsg = fxPromoteurHubTexte('promoteur_hub_load_dashboard', 0);
|
||
$strRunnerSrc = $vDomaine . '/images/ms1-runner-loader.gif?v=' . _VERSION_CODE;
|
||
$html .= '<div class="collapse promoteur-hub-epreuves-collapse mt-2" id="' . fxPromoteurHubEsc($strEprId) . '"'
|
||
. ' data-hub-eve-id="' . $intEveId . '" data-hub-lang="' . fxPromoteurHubEsc($strLangue) . '">';
|
||
$html .= '<div class="promoteur-hub-stats-placeholder ms1-loader ms1-loader--inline" role="status" aria-live="polite" aria-busy="true">'
|
||
. '<img class="ms1-loader__runner" src="' . fxPromoteurHubEsc($strRunnerSrc) . '" alt="" role="presentation" decoding="async">'
|
||
. '<span class="ms1-loader__label">' . fxPromoteurHubEsc($strLoadMsg) . '</span></div>';
|
||
$html .= '</div>';
|
||
} elseif ($strGrid !== '' || $strProduits !== '') {
|
||
$html .= '<div class="collapse promoteur-hub-epreuves-collapse mt-2" id="' . fxPromoteurHubEsc($strEprId) . '">' . $strGrid . $strProduits . '</div>';
|
||
}
|
||
|
||
// ---- Collapse : menu des fonctionnalites (gestion + rapports) — chargé en AJAX ----
|
||
if ($blnFonctions) {
|
||
$html .= fxPromoteurHubRenderEventPanelShell($arrItem, $strLangue);
|
||
}
|
||
|
||
$html .= '</div></div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
function fxPromoteurHubRenderEventSection($arrItems, $strTitleClef, $strLangue, $blnArchived = false)
|
||
{
|
||
if (empty($arrItems)) {
|
||
return '';
|
||
}
|
||
|
||
$html = '<h2 class="h4 mt-4 mb-3 promoteur-hub-section-title">' . fxPromoteurHubEsc(afficheTexte($strTitleClef, 0)) . '</h2>';
|
||
$html .= '<div class="promoteur promoteur-hub-events">';
|
||
|
||
foreach ($arrItems as $arrItem) {
|
||
$html .= fxPromoteurHubRenderEventCard($arrItem, $strLangue, $blnArchived);
|
||
}
|
||
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
function fxShowPromoteurHub($intComId, $strLangue = 'fr')
|
||
{
|
||
if (function_exists('fxV2RegisterScript')) {
|
||
fxV2RegisterScript('promoteur-hub');
|
||
}
|
||
|
||
$arrBuckets = fxPromoteurHubGetEvents(intval($intComId), $strLangue);
|
||
$html = '';
|
||
|
||
$html .= '<div class="promoteur-hub-toolbar mb-4 d-flex flex-wrap align-items-center justify-content-between">';
|
||
$html .= '<p class="mb-2 mb-md-0 text-muted">' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_intro', 0)) . '</p>';
|
||
$html .= '<a class="btn btn-outline-secondary rounded-pill" href="' . fxPromoteurHubEsc(fxPromoteurHubParticipantUrl($strLangue)) . '">';
|
||
$html .= '<i class="fa fa-user mr-2" aria-hidden="true"></i>' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_link_participant', 0));
|
||
$html .= '</a>';
|
||
$html .= '</div>';
|
||
|
||
// Annonces : uniquement si le module doc a reellement des pages (sinon pas de "?" mort)
|
||
if (function_exists('fxDocRenderModule')) {
|
||
$strDocModule = fxDocRenderModule('promoteur_hub_annonces');
|
||
if ($strDocModule !== '') {
|
||
$html .= '<div class="promoteur-hub-annonces alert alert-info d-flex align-items-center mb-4">';
|
||
$html .= '<div class="flex-grow-1 mr-2">' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_annonces_titre', 0)) . '</div>';
|
||
$html .= fxDocRenderTrigger('promoteur_hub_annonces');
|
||
$html .= $strDocModule;
|
||
$html .= '</div>';
|
||
}
|
||
}
|
||
|
||
$html .= fxPromoteurHubRenderEventSection($arrBuckets['highlight'], 'promoteur_hub_section_highlight', $strLangue, false);
|
||
$html .= fxPromoteurHubRenderEventSection($arrBuckets['archived'], 'promoteur_hub_section_archived', $strLangue, true);
|
||
|
||
if (empty($arrBuckets['highlight']) && empty($arrBuckets['archived'])) {
|
||
$html .= '<div class="alert alert-warning">' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_empty', 0)) . '</div>';
|
||
}
|
||
|
||
return $html;
|
||
}
|
||
|
||
/**
|
||
* MSIN-4401 — Bouton retour hub V2 depuis l'espace client (miroir de « Mon espace client MS1 »).
|
||
*/
|
||
function fxShowPromoteurHubEspaceClientToolbar($intComId, $strLangue = 'fr')
|
||
{
|
||
if (!fxPromoteurHubIsAvailable(intval($intComId))) {
|
||
return '';
|
||
}
|
||
|
||
$strLabel = afficheTexte('promoteur_hub_link_dashboard', 0);
|
||
if ($strLabel === '' || $strLabel === 'promoteur_hub_link_dashboard' || $strLabel === '*promoteur_hub_link_dashboard*') {
|
||
$strLabel = fxPromoteurHubStaticFallback('promoteur_hub_link_dashboard', $strLangue);
|
||
}
|
||
|
||
$html = '<div class="promoteur-hub-toolbar mb-4 d-flex flex-wrap align-items-center justify-content-end">';
|
||
$html .= '<a class="btn btn-outline-primary rounded-pill" href="' . fxPromoteurHubEsc(fxPromoteurHubUrl($strLangue)) . '">';
|
||
$html .= '<i class="fa fa-tachometer mr-2" aria-hidden="true"></i>' . fxPromoteurHubEsc($strLabel);
|
||
$html .= '</a>';
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
function fxShowPromoteurHubMenuLink($arrCompteClient, $strLangue)
|
||
{
|
||
global $vDomaine;
|
||
|
||
if (!fxPromoteurHubIsAvailable(intval($arrCompteClient['com_id'] ?? 0))) {
|
||
return '';
|
||
}
|
||
|
||
// MSIN-4401 — compteur menu hub = événements V2 seulement
|
||
$arrIds = array_unique(array_filter(array_map('intval', fxEveAccesGetEventIds(intval($arrCompteClient['com_id']))), function ($v) {
|
||
return $v > 0;
|
||
}));
|
||
$intNb = count($arrIds);
|
||
$strNb = '';
|
||
|
||
if ($intNb > 0) {
|
||
$strNb = '<small>(' . $intNb . ' ';
|
||
$strNb .= ($intNb > 1) ? afficheTexte('compte_evenement_pluriel', 0) : afficheTexte('compte_evenement_singulier', 0);
|
||
$strNb .= ')</small>';
|
||
}
|
||
|
||
$strLabel = afficheTexte('promoteur_hub_menu', 0);
|
||
if ($strLabel === '' || $strLabel === 'promoteur_hub_menu' || $strLabel === '*promoteur_hub_menu*') {
|
||
$strLabel = fxPromoteurHubStaticFallback('promoteur_hub_menu', $strLangue);
|
||
}
|
||
|
||
return '
|
||
<li class="nav-item">
|
||
<a class="nav-list" href="' . fxPromoteurHubEsc(fxPromoteurHubUrl($strLangue)) . '">
|
||
<i class="fa fa-tachometer" aria-hidden="true"></i> ' . fxPromoteurHubEsc($strLabel) . $strNb . '
|
||
</a>
|
||
</li>
|
||
';
|
||
}
|