diff --git a/compte.php b/compte.php index db684e3..a9b46c9 100644 --- a/compte.php +++ b/compte.php @@ -23,6 +23,7 @@ require_once('superadm/php/inc_fx_excell.php'); require_once('php/inc_fx_liste_attente.php'); require_once('php/inc_fx_inscriptions_mobile.php'); require_once('php/inc_fx_eve_acces.php'); +require_once('php/inc_fx_promoteur_hub.php'); global $objDatabase, $vPage, $vDomaine; // vérifier les paramètres @@ -53,11 +54,22 @@ else if (!empty($_GET['code'])) $strCode = 'compte_' . $_GET['code']; else { - if (isset($_SESSION['com_id'])) - $strCode = "compte_accueil"; - else - $strCode = "compte_login"; + if (isset($_SESSION['com_id'])) { + if (fxPromoteurHubComUsesV2($_SESSION['com_id'])) { + $strCode = 'compte_promoteur_hub'; + } else { + $strCode = 'compte_accueil'; + } + } else { + $strCode = 'compte_login'; + } } + +if ($strCode === 'compte_promoteur_hub' && (!isset($_SESSION['com_id']) || !fxPromoteurHubComUsesV2($_SESSION['com_id']))) { + header('Location: ' . $vDomaine . '/' . ($strLangue === 'fr' ? 'compte' : 'account')); + exit; +} + $recPage = fxGetPage($strCode); if (count($recPage) < 1) { @@ -321,7 +333,8 @@ if (isset($_GET['promoteur_eve_id'])) { header('Location: ' . $vDomaine . '/' . $strPage); exit; } - } elseif (!fxIsPromoteur($_SESSION['com_id'], $intEveIdbase)) { + } elseif (!fxIsPromoteur($_SESSION['com_id'], $intEveIdbase) + && !fxEveAccesComHasV2ForEvent($_SESSION['com_id'], $intEveIdbase)) { header('Location: ' . $vDomaine . '/' . $strPage); exit; } @@ -476,6 +489,10 @@ require_once("inc_header.php"); case 'compte_annuler_inscription': include_once('annuler_inscription.php'); break; + case 'compte_promoteur_hub': + $blnBoutonRetour = false; + echo fxShowPromoteurHub($_SESSION['com_id'], $strLangue); + break; case 'compte_accueil': //MSIN-4371 if (fxEveAccesCanQrTest($_SESSION['com_id'])) { ?> diff --git a/css/style.css b/css/style.css index 8305424..a80139b 100644 --- a/css/style.css +++ b/css/style.css @@ -3094,3 +3094,11 @@ a.ms1-trad-link.btn-aide-trad{ color:#212529; } } + +.promoteur-hub-card-archived { + opacity: 0.72; +} + +.promoteur-hub-annonces .ms1-doc-trigger { + flex-shrink: 0; +} diff --git a/php/inc_fx_compte.php b/php/inc_fx_compte.php index fa29651..77438dc 100644 --- a/php/inc_fx_compte.php +++ b/php/inc_fx_compte.php @@ -1273,6 +1273,14 @@ function fxLoginCompte($infoLogin, $strLangue) else $strPage = 'account'; + if (($arrRetour['state'] ?? '') === 'true' && !empty($infoCompte['com_id'])) { + require_once dirname(__FILE__) . '/inc_fx_promoteur_hub.php'; + if (fxPromoteurHubComUsesV2($infoCompte['com_id'])) { + header('Location: ' . fxPromoteurHubUrl($strLangue)); + exit; + } + } + //header("Location: " . $vDomaine . '/' . $strPage); header("Location: " . fxGetReferer()); } @@ -1477,7 +1485,13 @@ function fxShowMenuCompte($arrCompteClient, $strLangue) '; } - // menu promoteur + // menu promoteur v2 (hub) — comptes migres uniquement + if (!function_exists('fxPromoteurHubComUsesV2')) { + require_once dirname(__FILE__) . '/inc_fx_promoteur_hub.php'; + } + $strRetour .= fxShowPromoteurHubMenuLink($arrCompteClient, $strLangue); + + // menu promoteur legacy if (trim($arrCompteClient['com_eve_promoteur']) != '' || trim($arrCompteClient['com_rapports']) != '') { // si le compte client a des événements dont il est le promoteur $arrEvePromoteur = explode(',', $arrCompteClient['com_eve_promoteur']); diff --git a/php/inc_fx_promoteur_hub.php b/php/inc_fx_promoteur_hub.php new file mode 100644 index 0000000..0fe23da --- /dev/null +++ b/php/inc_fx_promoteur_hub.php @@ -0,0 +1,411 @@ + 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; +} + +function fxPromoteurHubGetEvents($intComId, $strLangue = 'fr') +{ + global $objDatabase, $vDomaine, $vRepertoireFichiers; + + $arrHighlight = array(); + $arrArchived = array(); + $arrEventIds = fxEveAccesGetEventIds(intval($intComId)); + + if (empty($arrEventIds)) { + return array('highlight' => $arrHighlight, 'archived' => $arrArchived); + } + + $arrIds = array_values(array_unique(array_filter(array_map('intval', $arrEventIds), 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')); + + $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, + 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(), + 'url_promoteur' => fxPromoteurHubCanAccessPromoteurWeb($intComId, $intEveId) + ? fxPromoteurHubPromoteurTableUrl($intEveId, $strLang) + : '', + 'url_mobile' => '', + ); + + if (!function_exists('fxInscrMobileCanAccess')) { + require_once __DIR__ . '/inc_fx_inscriptions_mobile.php'; + } + + if (fxInscrMobileCanAccess(intval($intComId), $intEveId)) { + $arrItem['url_mobile'] = fxInscrMobileBaseUrl($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'); +} + +function fxPromoteurHubRenderEventCard($arrItem, $strLangue, $blnArchived = false) +{ + $strCardClass = 'card box_participant mb-3' . ($blnArchived ? ' promoteur-hub-card-archived' : ''); + + $html = '
'; + $html .= '
'; + $html .= '
'; + $html .= '
'; + $html .= '

' . fxPromoteurHubEsc($arrItem['nom']) . '

'; + + if ($arrItem['date_label'] !== '') { + $html .= '
' . fxPromoteurHubEsc($arrItem['date_label']) . '
'; + } + + if ($arrItem['lieu'] !== '') { + $html .= '
' . fxPromoteurHubEsc($arrItem['lieu']) . '
'; + } + + if (!empty($arrItem['roles'])) { + $html .= '
' . fxPromoteurHubEsc(implode(' · ', $arrItem['roles'])) . '
'; + } + + $html .= '
'; + $html .= '
'; + + if ($arrItem['url_promoteur'] !== '') { + $html .= ''; + $html .= '' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_btn_tableau', 0)); + $html .= ''; + } + + if ($arrItem['url_mobile'] !== '') { + $html .= ''; + $html .= '' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_btn_mobile', 0)); + $html .= ''; + } + + $html .= '
'; + + return $html; +} + +function fxPromoteurHubRenderEventSection($arrItems, $strTitleClef, $strLangue, $blnArchived = false) +{ + if (empty($arrItems)) { + return ''; + } + + $html = '

' . fxPromoteurHubEsc(afficheTexte($strTitleClef, 0)) . '

'; + $html .= '
'; + + foreach ($arrItems as $arrItem) { + $html .= fxPromoteurHubRenderEventCard($arrItem, $strLangue, $blnArchived); + } + + $html .= '
'; + + return $html; +} + +function fxShowPromoteurHub($intComId, $strLangue = 'fr') +{ + $arrBuckets = fxPromoteurHubGetEvents(intval($intComId), $strLangue); + $html = ''; + + $html .= '
'; + $html .= '

' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_intro', 0)) . '

'; + $html .= ''; + $html .= '' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_link_participant', 0)); + $html .= ''; + $html .= '
'; + + if (function_exists('fxDocRenderBlock')) { + $strDoc = fxDocRenderBlock('promoteur_hub_annonces'); + if ($strDoc !== '') { + $html .= '
'; + $html .= '
' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_annonces_titre', 0)) . '
'; + $html .= $strDoc; + $html .= '
'; + } + } + + $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 .= '
' . fxPromoteurHubEsc(afficheTexte('promoteur_hub_empty', 0)) . '
'; + } + + return $html; +} + +function fxShowPromoteurHubMenuLink($arrCompteClient, $strLangue) +{ + global $vDomaine; + + if (!fxPromoteurHubComUsesV2(intval($arrCompteClient['com_id'] ?? 0))) { + return ''; + } + + $arrIds = fxEveAccesGetEventIds(intval($arrCompteClient['com_id'])); + $intNb = count($arrIds); + $strNb = ''; + + if ($intNb > 0) { + $strNb = '(' . $intNb . ' '; + $strNb .= ($intNb > 1) ? afficheTexte('compte_evenement_pluriel', 0) : afficheTexte('compte_evenement_singulier', 0); + $strNb .= ')'; + } + + return ' + + '; +} diff --git a/php/inc_settings.php b/php/inc_settings.php index e0f7e5a..4a441dc 100644 --- a/php/inc_settings.php +++ b/php/inc_settings.php @@ -7,8 +7,8 @@ * Constantes * * **************/ -define('_VERSION_CODE', '4.72.699'); -define('_DATE_CODE', '2026-06-22'); +define('_VERSION_CODE', '4.72.700'); +define('_DATE_CODE', '2026-06-25'); //MSIN-4290 define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe'); // Outil temporaire ms1_kc_set.php — modifier key_chain_http (lien /kc/{pk}/) diff --git a/sql/MSIN-promoteur-hub-phase1.sql b/sql/MSIN-promoteur-hub-phase1.sql new file mode 100644 index 0000000..081b9d5 --- /dev/null +++ b/sql/MSIN-promoteur-hub-phase1.sql @@ -0,0 +1,51 @@ +-- Hub promoteur — page compte + libelles (acces v2 uniquement) +SET NAMES utf8mb4; + +DELETE FROM inscriptions_pages WHERE pag_code = 'compte_promoteur_hub'; + +INSERT INTO inscriptions_pages ( + pag_code, pag_label_fr, pag_label_en, + pag_titre_fr, pag_titre_en, + pag_texte_fr, pag_texte_en, + pag_keywords_fr, pag_keywords_en, + pag_tri, pag_maj, pag_menu, pag_actif +) VALUES ( + 'compte_promoteur_hub', + 'Promoteur', 'Promoter', + 'Mes evenements', 'My events', + '', '', + '', '', + 0, NOW(), 0, 1 +); + +DELETE FROM info WHERE info_clef IN ( + 'promoteur_hub_menu', + 'promoteur_hub_intro', + 'promoteur_hub_link_participant', + 'promoteur_hub_annonces_titre', + 'promoteur_hub_section_highlight', + 'promoteur_hub_section_archived', + 'promoteur_hub_btn_tableau', + 'promoteur_hub_btn_mobile', + 'promoteur_hub_empty' +) AND info_prg = 'compte.php'; + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) VALUES +('promoteur_hub_menu', 'fr', 'Mes evenements (promoteur)', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_menu', 'en', 'My events (promoter)', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_intro', 'fr', 'Acces a vos tableaux de bord par evenement.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_intro', 'en', 'Access your event dashboards.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_link_participant', 'fr', 'Mon espace participant', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_link_participant', 'en', 'My participant space', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_annonces_titre', 'fr', 'Nouveautes MS1', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_annonces_titre', 'en', 'MS1 updates', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_section_highlight', 'fr', 'En vedette', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_section_highlight', 'en', 'Highlights', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_section_archived', 'fr', 'Evenements passes', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_section_archived', 'en', 'Past events', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_btn_tableau', 'fr', 'Tableau de bord', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_btn_tableau', 'en', 'Dashboard', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_btn_mobile', 'fr', 'Inscriptions mobile', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_btn_mobile', 'en', 'Mobile registrations', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_empty', 'fr', 'Aucun evenement accessible pour le moment.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('promoteur_hub_empty', 'en', 'No accessible events at this time.', '', 'compte.php', '', 0, 1, '', '', '', NOW());