Files
ms1inscription-v5/php/inc_fx_inscriptions_mobile.php
stephan 547390286b Enhance mobile registration feedback and fallback text handling
This commit improves the mobile registration module by refining the feedback messages displayed during the bib scanning process. It introduces additional conditions for fallback text to ensure users receive appropriate guidance based on their input. The version code is incremented to 4.72.698 to reflect these updates.
2026-06-22 15:43:48 -04:00

1360 lines
56 KiB
PHP

<?php
/**
* Liste inscriptions mobile — recherche, filtres, cartes, fiche.
*
* Deux entrees distinctes (meme module, navigation differente) :
* - Promoteur : /compte/inc_tableau_inscriptions_mobile → retour inc_tableau_promoteur
* - Acces v2 seul : /mobile → retour /mobile ou Mon compte
*
* Droits : v2 uniquement (fxInscrMobileCanAccess). i18n : toujours info_prg compte.php.
*/
function fxInscrMobileIsEntry() {
return defined('MS1_INSCR_MOBILE_ENTRY') && MS1_INSCR_MOBILE_ENTRY;
}
/** Utilisateur avec menu promoteur legacy (section Info promoteur). */
function fxInscrMobileUserHasPromoteurMenu($intComId) {
global $objDatabase;
$row = $objDatabase->fxGetRow(
'SELECT com_eve_promoteur, com_rapports FROM inscriptions_comptes WHERE com_id = ' . intval($intComId)
);
if ($row === null) {
return false;
}
return trim((string)$row['com_eve_promoteur']) !== '' || trim((string)$row['com_rapports']) !== '';
}
/** Permissions v2 requises pour la fiche inscriptions mobile (web). */
function fxInscrMobilePermKeysView() {
return array('registrations.view', 'inscriptions_mobile.view');
}
function fxInscrMobilePermKeysScan() {
return array('registrations.scan');
}
/** Permission action mobile (niveau fonction dans la fiche). */
function fxInscrMobileCanDo($intComId, $intEveId, $strActionPerm) {
fxInscrMobileLoadEveAcces();
if (!fxInscrMobileCanAccess($intComId, $intEveId)) {
return false;
}
if (fxEveAccesHasPermission(intval($intComId), intval($intEveId), $strActionPerm)) {
return true;
}
/* Kit inscriptions complet (desktop) inclut les actions mobile. */
if (fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'inscriptions.edit')) {
return true;
}
/* dossards.manage autorise aussi la modification du no dossard sur fiche mobile. */
if ($strActionPerm === 'inscriptions_mobile.bib_edit'
&& fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'dossards.manage')) {
return true;
}
return false;
}
function fxInscrMobileLoadEveAcces() {
require_once __DIR__ . '/inc_fx_eve_acces.php';
}
/**
* Evenements accessibles via acces v2 uniquement (pas com_eve_promoteur, pas super admin).
*/
function fxInscrMobileGetPromoteurEveIds($intComId) {
fxInscrMobileLoadEveAcces();
return fxEveAccesGetEventIdsWithInscrMobileAccess(intval($intComId));
}
function fxInscrMobileCanAccess($intComId, $intEveId) {
fxInscrMobileLoadEveAcces();
return fxEveAccesHasInscrMobileWebAccess(intval($intComId), intval($intEveId));
}
function fxInscrMobileCanScan($intComId, $intEveId) {
fxInscrMobileLoadEveAcces();
return fxEveAccesHasAnyPermission(intval($intComId), intval($intEveId), fxInscrMobilePermKeysScan());
}
function fxInscrMobileBaseUrl($strLangue, $blnMobileEntry = null) {
global $vDomaine;
if ($blnMobileEntry === null) {
$blnMobileEntry = fxInscrMobileIsEntry();
}
if ($blnMobileEntry) {
return $vDomaine . '/mobile';
}
return $vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_inscriptions_mobile' : '/account/inc_tableau_inscriptions_mobile');
}
function fxInscrMobileEsc($str) {
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
}
/** Page info / i18n des libelles inscriptions mobile (toujours compte.php). */
function fxInscrMobileTextesPage() {
return 'compte.php';
}
function fxInscrMobileLoadTextes($strLangue) {
static $tabCache = array();
static $strCacheLang = '';
if ($strCacheLang === $strLangue && !empty($tabCache)) {
return $tabCache;
}
$tabCache = obtenirTextepage(fxInscrMobileTextesPage(), $strLangue, 2);
if (!is_array($tabCache)) {
$tabCache = array();
}
$strCacheLang = $strLangue;
return $tabCache;
}
/**
* Recherche un libelle info par clef (toutes pages), priorite compte.php > global > mobile.php.
*/
function fxInscrMobileLookupTexteDb($strClef, $strLangue) {
global $objDatabase;
static $tabMemo = array();
$strMemoKey = $strClef . "\0" . $strLangue;
if (array_key_exists($strMemoKey, $tabMemo)) {
return $tabMemo[$strMemoKey];
}
$sql = "SELECT info_texte FROM info
WHERE info_clef = '" . $objDatabase->fxEscape($strClef) . "'
AND info_langue = '" . $objDatabase->fxEscape($strLangue) . "'
AND info_actif = 1
ORDER BY FIELD(info_prg, 'compte.php', 'global', 'mobile.php', 'mobile')
LIMIT 1";
$strTexte = $objDatabase->fxGetVar($sql);
if ($strTexte === null || trim((string)$strTexte) === '' || trim((string)$strTexte) === $strClef) {
$tabMemo[$strMemoKey] = null;
return null;
}
$tabMemo[$strMemoKey] = (string)$strTexte;
return $tabMemo[$strMemoKey];
}
function fxInscrMobileResolveTexte($strClef, $strLangue) {
global $vtexte_page;
$tab = fxInscrMobileLoadTextes($strLangue);
if (isset($tab[$strClef]['info_texte'])) {
$str = trim((string)$tab[$strClef]['info_texte']);
if ($str !== '' && $str !== $strClef) {
return $str;
}
}
if (is_array($vtexte_page) && isset($vtexte_page[$strClef]['info_texte'])) {
$str = trim((string)$vtexte_page[$strClef]['info_texte']);
if ($str !== '' && $str !== $strClef) {
return $str;
}
}
$strDb = fxInscrMobileLookupTexteDb($strClef, $strLangue);
if ($strDb !== null) {
return $strDb;
}
if (function_exists('fxAdminCanUseTextEditTools') && fxAdminCanUseTextEditTools()) {
global $vPage;
$memPage = $vPage;
$vPage = fxInscrMobileTextesPage();
$str = afficheTexte($strClef, 0);
$vPage = $memPage;
if (strpos($str, '*') === 0 && substr($str, -1) === '*') {
return fxInscrMobileFallbackTexte($strClef, $strLangue);
}
if (trim($str) === '' || trim($str) === $strClef) {
return fxInscrMobileFallbackTexte($strClef, $strLangue);
}
return $str;
}
return fxInscrMobileFallbackTexte($strClef, $strLangue);
}
/** Libelles integres (secours si table info non a jour). */
function fxInscrMobileFallbackTexte($strClef, $strLangue) {
static $tabMemo = array();
if (!isset($tabMemo[$strLangue])) {
$blnFr = ($strLangue !== 'en');
$tabMemo[$strLangue] = array(
'inscr_mobile_qr_title' => $blnFr ? 'Code QR — Lecteur' : 'QR code reader',
'inscr_mobile_qr_hint' => $blnFr ? 'Pointez la caméra vers le code QR du participant.' : 'Point the camera at the participant\'s QR code.',
'inscr_mobile_qr_invalid' => $blnFr ? 'Code QR invalide ou introuvable.' : 'Invalid or unknown QR code.',
'inscr_mobile_qr_not_found' => $blnFr ? 'Participant introuvable pour cet événement.' : 'Participant not found for this event.',
'inscr_mobile_qr_wrong_event' => $blnFr ? 'Ce code QR appartient à un autre événement : %s' : 'This QR code belongs to another event: %s',
'inscr_mobile_qr_camera_error' => $blnFr ? 'Impossible d\'accéder à la caméra.' : 'Unable to access the camera.',
'inscr_mobile_bib_scan_btn' => $blnFr ? 'Scanner le numéro' : 'Scan number',
'inscr_mobile_bib_scan_hint' => $blnFr ? 'Ouvrez la caméra, cadrez le numéro, puis touchez l\'image pour lire.' : 'Open the camera, frame the number, then tap the image to read.',
'inscr_mobile_bib_scan_ready' => $blnFr ? 'Cadrez le numéro, puis touchez l\'image' : 'Frame the number, then tap the image',
'inscr_mobile_bib_scan_tap' => $blnFr ? 'Toucher pour lire' : 'Tap to read',
'inscr_mobile_bib_scan_scanning' => $blnFr ? 'Lecture en cours...' : 'Reading...',
'inscr_mobile_bib_scan_loading' => $blnFr ? 'Initialisation (1re fois)...' : 'Initializing (first time)...',
'inscr_mobile_bib_scan_found' => $blnFr ? 'Numéro %s détecté — validez avec OK.' : 'Number %s detected — press OK.',
'inscr_mobile_bib_scan_invalid' => $blnFr ? 'Numéro illisible. Cadrez un seul numéro.' : 'Unreadable number. Frame a single number.',
);
}
if (isset($tabMemo[$strLangue][$strClef])) {
return $tabMemo[$strLangue][$strClef];
}
return $strClef;
}
/** Charge $vtexte_page pour le module mobile (entry /mobile ou compte). */
function fxInscrMobileInitTextes($strLangue) {
global $vtexte_page, $vPage;
$vPage = fxInscrMobileTextesPage();
$vtexte_page = fxInscrMobileLoadTextes($strLangue);
}
/** Libelle i18n sans echo parasite — independant de la page PHP courante. */
function fxInscrMobileT($strClef) {
global $strLangue;
if (!isset($strLangue) || $strLangue === '') {
$strLangue = 'fr';
}
$strTexte = fxInscrMobileResolveTexte($strClef, $strLangue);
if ($strTexte === $strClef || trim((string)$strTexte) === '') {
$strFallback = fxInscrMobileFallbackTexte($strClef, $strLangue);
if ($strFallback !== $strClef && trim((string)$strFallback) !== '') {
$strTexte = $strFallback;
}
}
if (function_exists('fxAdminTradMarker')) {
$strMarker = fxAdminTradMarker($strClef, 0);
if ($strMarker !== '' && strpos($strTexte, $strMarker) === false) {
$strTexte .= $strMarker;
}
}
return $strTexte;
}
function fxInscrMobileLoginActionUrl($strLangue) {
global $vDomaine;
if ($strLangue === 'en') {
return $vDomaine . '/mobile/en';
}
return $vDomaine . '/mobile';
}
function fxInscrMobileRenderLoginPage($strLangue) {
$strActionUrl = fxInscrMobileLoginActionUrl($strLangue);
$strLblUser = ($strLangue === 'fr') ? 'Nom d\'utilisateur' : 'Username';
$strLblPass = ($strLangue === 'fr') ? 'Mot de passe' : 'Password';
$strBtn = ($strLangue === 'fr') ? 'Connexion' : 'Sign in';
$strIntro = ($strLangue === 'fr')
? 'Connectez-vous pour accéder aux inscriptions mobile.'
: 'Sign in to access mobile registrations.';
echo '<div class="inscr-mobile-page inscr-mobile-login-wrap">';
echo '<div id="module-inscr-mobile" class="inscr-mobile-shell inscr-mobile-shell--login">';
fxInscrMobileRenderPageHead(
($strLangue === 'fr') ? 'Inscriptions mobile' : 'Mobile registrations'
);
echo '<p class="inscr-mobile-login-intro text-muted">' . fxInscrMobileEsc($strIntro) . '</p>';
echo '<form action="' . fxInscrMobileEsc($strActionUrl) . '" id="frm_inscr_mobile_login" method="post" class="inscr-mobile-login-form">';
echo '<input type="hidden" name="form_action" value="' . fxInscrMobileEsc(urlencode(base64_encode('login'))) . '">';
echo '<label class="inscr-mobile-label" for="txt_login_mobile">' . fxInscrMobileEsc($strLblUser) . '</label>';
echo '<input class="form-control form-control-sm rounded-0" type="text" id="txt_login_mobile" name="txt_login" required autofocus>';
echo '<label class="inscr-mobile-label" for="txt_password_mobile">' . fxInscrMobileEsc($strLblPass) . '</label>';
echo '<input class="form-control form-control-sm rounded-0" type="password" id="txt_password_mobile" name="txt_password" required>';
echo '<button class="btn btn-primary btn-sm rounded-0 btn-block mt-3" type="submit" id="btn_login_mobile" name="btn_login">' . fxInscrMobileEsc($strBtn) . '</button>';
echo '</form></div></div>';
}
/** Libellé menu promoteur V2 (même texte que l'ancien + suffixe V2). */
function fxInscrMobilePromoteurMenuLabel() {
return afficheTexte('tableau_promoteur_menueinscription', 0) . ' V2';
}
function fxInscrMobileListBackLabel($strLangue) {
if (fxInscrMobileIsEntry()) {
return ($strLangue === 'fr') ? 'Événements' : 'Events';
}
return fxInscrMobileT('promoteur_back');
}
function fxInscrMobileShouldShowListBack($intComId) {
if (!fxInscrMobileIsEntry()) {
return true;
}
return count(fxInscrMobileGetPromoteurEveIds($intComId)) > 1;
}
function fxInscrMobileRenderNavBack($strUrl, $strLabel) {
echo '<a class="btn btn-primary rounded-pill inscr-mobile-nav-back" href="' . fxInscrMobileEsc($strUrl) . '">';
echo '<i class="fa fa-chevron-left mr-2" aria-hidden="true"></i>' . fxInscrMobileEsc($strLabel);
echo '</a>';
}
function fxInscrMobileRenderPageHead($strTitle, $strSub = '') {
echo '<div class="inscr-mobile-page-head">';
echo '<h1 class="inscr-mobile-page-title">' . fxInscrMobileEsc($strTitle) . '</h1>';
if (trim((string)$strSub) !== '') {
echo '<p class="inscr-mobile-page-sub text-muted mb-0">' . fxInscrMobileEsc($strSub) . '</p>';
}
echo '</div>';
}
function fxInscrMobileRenderSectionTitle($strLabel, $strIconClass) {
echo '<h2 class="inscr-mobile-fiche-section__title">';
echo '<i class="fa ' . fxInscrMobileEsc($strIconClass) . ' inscr-mobile-fiche-section__icon" aria-hidden="true"></i>';
echo '<span>' . fxInscrMobileEsc($strLabel) . '</span>';
echo '</h2>';
}
function fxInscrMobileRenderFicheSectionStart($strModifier, $strLabel, $strIconClass, $blnOpen = true) {
echo '<details class="inscr-mobile-fiche-section inscr-mobile-fiche-section--' . fxInscrMobileEsc($strModifier) . '"';
if ($blnOpen) {
echo ' open';
}
echo '>';
echo '<summary class="inscr-mobile-fiche-section__title">';
echo '<i class="fa ' . fxInscrMobileEsc($strIconClass) . ' inscr-mobile-fiche-section__icon" aria-hidden="true"></i>';
echo '<span>' . fxInscrMobileEsc($strLabel) . '</span>';
echo '</summary>';
echo '<div class="inscr-mobile-fiche-section__body">';
}
function fxInscrMobileRenderFicheSectionEnd() {
echo '</div></details>';
}
function fxInscrMobileRenderPanelSummary($strLabel, $strIconClass) {
echo '<i class="fa ' . fxInscrMobileEsc($strIconClass) . ' inscr-mobile-panel__icon" aria-hidden="true"></i>';
echo '<span>' . fxInscrMobileEsc($strLabel) . '</span>';
}
function fxInscrMobileParseEveId($strRaw) {
if ($strRaw === null || $strRaw === '') {
return 0;
}
$strDecoded = base64_decode(urldecode($strRaw), true);
if ($strDecoded === false || $strDecoded === '') {
return 0;
}
return (int)$strDecoded;
}
function fxInscrMobileParseRequest() {
$arr = array(
'rech_prenom' => isset($_GET['rech_prenom']) ? trim($_GET['rech_prenom']) : '',
'rech_nom' => isset($_GET['rech_nom']) ? trim($_GET['rech_nom']) : '',
'rech_no_commande' => isset($_GET['rech_no_commande']) ? trim($_GET['rech_no_commande']) : '',
'rech_nom_equipe' => isset($_GET['rech_nom_equipe']) ? trim($_GET['rech_nom_equipe']) : '',
'chk_bib' => !empty($_GET['chk_bib']) ? 1 : 0,
'chk_cancelled' => !empty($_GET['chk_cancelled']) ? 1 : 0,
'sel_rech_epreuve' => 0,
'pg' => isset($_GET['pg']) ? max(1, intval($_GET['pg'])) : 1,
'pec_id' => isset($_GET['pec_id']) ? intval($_GET['pec_id']) : 0,
);
if (!empty($_GET['sel_rech_epreuve'])) {
$decoded = base64_decode(urldecode($_GET['sel_rech_epreuve']), true);
if ($decoded !== false && $decoded !== '') {
$arr['sel_rech_epreuve'] = intval($decoded);
} else {
$arr['sel_rech_epreuve'] = intval($_GET['sel_rech_epreuve']);
}
}
return $arr;
}
function fxInscrMobileFilterActiveCount($arrReq) {
$int = 0;
if ($arrReq['sel_rech_epreuve'] > 0) {
$int++;
}
if ($arrReq['chk_bib']) {
$int++;
}
if ($arrReq['chk_cancelled']) {
$int++;
}
return $int;
}
function fxInscrMobileEmptyListRequest() {
return array(
'rech_prenom' => '',
'rech_nom' => '',
'rech_no_commande' => '',
'rech_nom_equipe' => '',
'chk_bib' => 0,
'chk_cancelled' => 0,
'sel_rech_epreuve' => 0,
'pg' => 1,
'pec_id' => 0,
);
}
function fxInscrMobileSearchResetUrl($strBaseUrl, $intEveId) {
return fxInscrMobileBuildUrl($strBaseUrl, $intEveId, fxInscrMobileEmptyListRequest(), array('pg' => 1));
}
function fxInscrMobileBuildWhere($intEveId, $arrReq) {
global $objDatabase;
$strWhere = ' e.eve_id = ' . intval($intEveId);
if ($arrReq['rech_nom'] !== '') {
$strWhere .= ' AND p.par_nom LIKE "%' . $objDatabase->fxEscape($arrReq['rech_nom']) . '%"';
}
if ($arrReq['rech_prenom'] !== '') {
$strWhere .= ' AND p.par_prenom LIKE "%' . $objDatabase->fxEscape($arrReq['rech_prenom']) . '%"';
}
if ($arrReq['rech_no_commande'] !== '') {
$strEscCmd = $objDatabase->fxEscape($arrReq['rech_no_commande']);
$strWhere .= ' AND (e.no_commande LIKE "%' . $strEscCmd . '%" OR p.no_commande LIKE "%' . $strEscCmd . '%")';
}
if ($arrReq['rech_nom_equipe'] !== '') {
$strEscBibEquipe = $objDatabase->fxEscape($arrReq['rech_nom_equipe']);
$strWhere .= ' AND ('
. ' TRIM(p.no_bib) LIKE "%' . $strEscBibEquipe . '%"'
. ' OR TRIM(e.no_equipe) LIKE "%' . $strEscBibEquipe . '%"'
. ' OR e.pec_nom_equipe LIKE "%' . $strEscBibEquipe . '%"'
. ' OR p.par_nom_equipe LIKE "%' . $strEscBibEquipe . '%"'
. ')';
}
if ($arrReq['sel_rech_epreuve'] > 0) {
$strWhere .= ' AND p.epr_id = ' . intval($arrReq['sel_rech_epreuve']) . ' AND p.epr_id = e.epr_id';
}
if ($arrReq['chk_bib']) {
$strWhere .= " AND TRIM(p.no_bib) = ''";
}
if ($arrReq['chk_cancelled']) {
$strWhere .= ' AND e.is_cancelled = 1';
} else {
$strWhere .= ' AND e.is_cancelled = 0 AND e.pec_actif = 1';
}
return $strWhere;
}
function fxInscrMobileFetchRows($intEveId, $arrReq) {
global $objDatabase;
$strWhere = fxInscrMobileBuildWhere($intEveId, $arrReq);
$sql = 'SELECT p.no_bib, p.no_bib_remis, p.no_bib_remis_date, p.no_bib_remis_par, p.par_statut_course, p.par_id, p.par_equipe,'
. ' p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id,'
. ' e.no_commande, e.no_panier, e.no_equipe, e.pec_equipe'
. ' FROM resultats_epreuves_commandees e, resultats_participants p'
. ' WHERE ' . $strWhere . ' AND p.pec_id = e.pec_id_original'
. ' GROUP BY e.pec_id_original'
. ' ORDER BY p.par_nom, p.par_prenom';
return $objDatabase->fxGetResults($sql);
}
function fxInscrMobileFetchRowByPec($intPecId, $intEveId) {
global $objDatabase;
$sql = 'SELECT p.no_bib, p.no_bib_remis, p.no_bib_remis_date, p.no_bib_remis_par, p.par_statut_course, p.par_id, p.par_equipe,'
. ' p.par_prenom, p.par_nom, e.pec_id_original, e.epr_id, e.eve_id, e.pec_id, e.is_cancelled, p.rol_id,'
. ' e.no_commande, e.no_panier, e.no_equipe, e.pec_equipe'
. ' FROM resultats_epreuves_commandees e, resultats_participants p'
. ' WHERE e.eve_id = ' . intval($intEveId)
. ' AND e.pec_id_original = ' . intval($intPecId)
. ' AND p.pec_id = e.pec_id_original'
. ' LIMIT 1';
return $objDatabase->fxGetRow($sql);
}
function fxInscrMobileEpreuveLabel($intEprId, $strLangue) {
$tab = fxGetEpreuve($intEprId);
if ($tab === null) {
return '';
}
$str = '';
if (trim($tab['epr_categorie_' . $strLangue]) !== '') {
$str .= $tab['epr_categorie_' . $strLangue] . ' — ';
}
$str .= $tab['epr_type_' . $strLangue];
if (trim($tab['epr_nom_' . $strLangue]) !== '') {
$str .= ' — ' . $tab['epr_nom_' . $strLangue];
}
return fxUnescape($str);
}
function fxInscrMobileBibDisplay($arrRow) {
if (intval($arrRow['pec_equipe']) === 1) {
return fxShowBibNumber($arrRow['no_equipe'], $arrRow['epr_id'], 'equipe');
}
return fxShowBibNumber($arrRow['no_bib'], $arrRow['epr_id'], 'participant');
}
function fxInscrMobileRenderKvListOpen() {
echo '<div class="inscr-mobile-kv-list">';
}
function fxInscrMobileRenderKvListClose() {
echo '</div>';
}
function fxInscrMobileRenderKvRow($strLabel, $strValue, $blnHtml = false, $strExtraClass = '') {
if (!$blnHtml && trim((string)$strValue) === '') {
return;
}
$strClass = 'inscr-mobile-kv-row';
if ($strExtraClass !== '') {
$strClass .= ' ' . $strExtraClass;
}
echo '<div class="' . fxInscrMobileEsc($strClass) . '">';
echo '<div class="inscr-mobile-kv-row__label">' . fxInscrMobileEsc($strLabel) . '</div>';
echo '<div class="inscr-mobile-kv-row__value">';
if ($blnHtml) {
echo $strValue;
} else {
echo fxInscrMobileEsc($strValue);
}
echo '</div></div>';
}
function fxInscrMobileFetchFicheProfile($arrRow, $strLangue) {
global $objDatabase;
$intParId = (int)$arrRow['par_id'];
$intPecId = (int)$arrRow['pec_id_original'];
$intEveId = (int)$arrRow['eve_id'];
$strLangCol = ($strLangue === 'en') ? 'en' : 'fr';
$tabProfile = $objDatabase->fxGetRow(
'SELECT p.par_courriel, p.par_naissance, p.par_sexe, p.par_id_original'
. ' FROM resultats_participants p'
. ' WHERE p.par_id = ' . $intParId
. ' LIMIT 1'
);
if ($tabProfile === null) {
return array(
'bln_capitaine' => ((int)$arrRow['rol_id'] === 1),
'email' => '',
'birth_gender' => '',
'questions' => array(),
);
}
$strEmail = trim((string)$tabProfile['par_courriel']);
$strBirthGender = '';
$strNaissance = trim((string)$tabProfile['par_naissance']);
if ($strNaissance !== '' && $strNaissance !== '0000-00-00') {
$strBirthGender = fxShowDate($strNaissance, $strLangue)
. ' - '
. fxGetGender($tabProfile['par_sexe'], $strLangue);
}
$intParIdOriginal = (int)$tabProfile['par_id_original'];
$sqlQuestions = 'SELECT rq.que_choix_' . $strLangCol . ' AS que_choix,'
. ' iq.que_cart_label_' . $strLangCol . ' AS que_label,'
. ' rq.que_question_' . $strLangCol . ' AS que_question,'
. ' iq.que_tri, iq.que_id'
. ' FROM resultats_questions rq'
. ' INNER JOIN inscriptions_questions iq ON iq.que_id = rq.que_id'
. ' WHERE iq.que_cart_show = 1'
. ' AND iq.eve_id = ' . $intEveId
. ' AND rq.pec_id = ' . $intPecId
. ' AND (rq.par_id = ' . $intParId . ' OR rq.par_id = ' . $intParIdOriginal . ')'
. ' AND rq.que_actif = 1'
. " AND TRIM(COALESCE(rq.que_choix_" . $strLangCol . ", '')) <> ''"
. ' ORDER BY iq.que_tri, iq.que_id';
$tabQuestionsRaw = $objDatabase->fxGetResults($sqlQuestions);
$tabQuestions = array();
if ($tabQuestionsRaw !== null) {
for ($i = 1; $i <= count($tabQuestionsRaw); $i++) {
$tabQ = $tabQuestionsRaw[$i];
$strLabel = trim(fxUnescape($tabQ['que_label']));
if ($strLabel === '') {
$strLabel = trim(fxUnescape($tabQ['que_question']));
}
$strValue = trim(fxUnescape($tabQ['que_choix']));
if ($strLabel === '' || $strValue === '') {
continue;
}
$tabQuestions[] = array(
'label' => $strLabel,
'value' => $strValue,
);
}
}
return array(
'bln_capitaine' => ((int)$arrRow['rol_id'] === 1),
'email' => $strEmail,
'birth_gender' => $strBirthGender,
'questions' => $tabQuestions,
);
}
function fxInscrMobileRenderKvRowFlag($strText, $strExtraClass = '') {
$strClass = 'inscr-mobile-kv-row inscr-mobile-kv-row--flag';
if ($strExtraClass !== '') {
$strClass .= ' ' . $strExtraClass;
}
echo '<div class="' . fxInscrMobileEsc($strClass) . '">';
echo '<span class="inscr-mobile-kv-flag">' . fxInscrMobileEsc($strText) . '</span>';
echo '</div>';
}
function fxInscrMobileRenderFicheProfileKvRows($arrRow, $strLangue) {
$tabProfile = fxInscrMobileFetchFicheProfile($arrRow, $strLangue);
$blnFirstProfile = true;
$strProfileSep = 'inscr-mobile-kv-row--profile';
if ($tabProfile['bln_capitaine']) {
$strCaptainLabel = trim(fxInscrMobileT('participant-titre-capitaine'));
if ($strCaptainLabel === '') {
$strCaptainLabel = ($strLangue === 'fr') ? 'Capitaine' : 'Captain';
}
fxInscrMobileRenderKvRowFlag(
$strCaptainLabel,
$blnFirstProfile ? $strProfileSep : ''
);
$blnFirstProfile = false;
}
if ($tabProfile['email'] !== '') {
fxInscrMobileRenderKvRow(
fxInscrMobileT('inscr_mobile_email'),
$tabProfile['email'],
false,
$blnFirstProfile ? 'inscr-mobile-kv-row--profile' : ''
);
$blnFirstProfile = false;
}
if ($tabProfile['birth_gender'] !== '') {
fxInscrMobileRenderKvRow(
fxInscrMobileT('inscr_mobile_birthdate'),
$tabProfile['birth_gender'],
false,
$blnFirstProfile ? 'inscr-mobile-kv-row--profile' : ''
);
$blnFirstProfile = false;
}
foreach ($tabProfile['questions'] as $tabQuestion) {
fxInscrMobileRenderKvRow(
$tabQuestion['label'],
$tabQuestion['value'],
false,
$blnFirstProfile ? 'inscr-mobile-kv-row--profile' : ''
);
$blnFirstProfile = false;
}
}
/** Code statut course par défaut (Confirmé). */
function fxInscrMobileParStatutCourseDefault() {
return 'CONF';
}
function fxInscrMobileResolveParStatutCourse($strCurrent) {
$strCurrent = trim((string)$strCurrent);
return $strCurrent !== '' ? $strCurrent : fxInscrMobileParStatutCourseDefault();
}
/** Options statut course depuis info (info_description = opt). */
function fxInscrMobileGetStatutCourseOptions($strLangue) {
global $objDatabase;
static $tabCache = array();
if (isset($tabCache[$strLangue])) {
return $tabCache[$strLangue];
}
$sql = "SELECT info_texte, info_option2 FROM info"
. " WHERE info_actif = 1 AND info_clef = 'inscr_statut_course'"
. " AND info_langue = '" . $objDatabase->fxEscape($strLangue) . "'"
. " AND info_description = 'opt'"
. " ORDER BY info_trie";
$tabRows = $objDatabase->fxGetResults($sql);
$tabCache[$strLangue] = ($tabRows !== null) ? $tabRows : array();
return $tabCache[$strLangue];
}
function fxInscrMobileRenderStatutField($intParId, $strCurrent, $intEveId, $strLangue) {
$tabOptions = fxInscrMobileGetStatutCourseOptions($strLangue);
if (count($tabOptions) === 0) {
echo '<div class="inscr-mobile-muted">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_statut_label')) . '</div>';
return;
}
$strCurrent = fxInscrMobileResolveParStatutCourse($strCurrent);
$strSelectId = 'inscr_statut_' . (int)$intParId;
echo '<select class="form-control rounded-0 inscr-mobile-statut-select" id="' . fxInscrMobileEsc($strSelectId) . '"'
. ' data-par_id="' . (int)$intParId . '"'
. ' data-eve_id="' . rawurlencode(base64_encode((string)$intEveId)) . '">';
foreach ($tabOptions as $arrOpt) {
$strCode = trim((string)$arrOpt['info_option2']);
$strLabel = trim((string)$arrOpt['info_texte']);
if ($strCode === '') {
continue;
}
echo '<option value="' . fxInscrMobileEsc($strCode) . '"'
. ($strCurrent === $strCode ? ' selected' : '') . '>'
. fxInscrMobileEsc($strLabel) . '</option>';
}
echo '</select>';
}
/** Paramètres GET pour liens (sans double-encodage). */
function fxInscrMobileQueryParams($intEveId, $arrReq, $arrExtra = array()) {
$tab = array(
'promoteur_eve_id' => base64_encode((string)$intEveId),
);
if ($arrReq['rech_prenom'] !== '') {
$tab['rech_prenom'] = $arrReq['rech_prenom'];
}
if ($arrReq['rech_nom'] !== '') {
$tab['rech_nom'] = $arrReq['rech_nom'];
}
if ($arrReq['rech_no_commande'] !== '') {
$tab['rech_no_commande'] = $arrReq['rech_no_commande'];
}
if ($arrReq['rech_nom_equipe'] !== '') {
$tab['rech_nom_equipe'] = $arrReq['rech_nom_equipe'];
}
if ($arrReq['chk_bib']) {
$tab['chk_bib'] = 1;
}
if ($arrReq['chk_cancelled']) {
$tab['chk_cancelled'] = 1;
}
if ($arrReq['sel_rech_epreuve'] > 0) {
$tab['sel_rech_epreuve'] = base64_encode((string)$arrReq['sel_rech_epreuve']);
}
if (!empty($_GET['lng'])) {
$tab['lng'] = $_GET['lng'];
}
if (!empty($arrReq['pg']) && (int)$arrReq['pg'] > 1) {
$tab['pg'] = (int)$arrReq['pg'];
}
foreach ($arrExtra as $strKey => $mixVal) {
if ($mixVal === null || $mixVal === '' || ($strKey === 'pec_id' && (int)$mixVal === 0)) {
unset($tab[$strKey]);
} else {
$tab[$strKey] = $mixVal;
}
}
return $tab;
}
function fxInscrMobileBuildUrl($strBaseUrl, $intEveId, $arrReq, $arrExtra = array()) {
$tab = fxInscrMobileQueryParams($intEveId, $arrReq, $arrExtra);
$strQs = http_build_query($tab, '', '&');
return $strBaseUrl . ($strQs !== '' ? '?' . $strQs : '');
}
function fxInscrMobilePaginationUrl($strBaseUrl, $intEveId, $arrReq) {
$tab = fxInscrMobileQueryParams($intEveId, $arrReq, array('pec_id' => null));
unset($tab['pg'], $tab['pec_id']);
$strQs = http_build_query($tab, '', '&amp;');
return $strBaseUrl . ($strQs !== '' ? '?' . $strQs : '?promoteur_eve_id=' . rawurlencode(base64_encode((string)$intEveId)));
}
function fxInscrMobileRenderPagination($strBaseUrl, $intEveId, $arrReq, $intTotal, $intPerPage, $intPage) {
if ($intTotal <= $intPerPage) {
return '';
}
return '<div class="inscr-mobile-pager">'
. fxGetPagination(
fxInscrMobilePaginationUrl($strBaseUrl, $intEveId, $arrReq),
$intTotal,
$intPerPage,
$intPage
)
. '</div>';
}
function fxInscrMobileExtractQrToken($strRaw) {
$strRaw = trim((string)$strRaw);
if ($strRaw === '') {
return '';
}
if (preg_match('/[?&]t=([^&\s#]+)/', $strRaw, $tabMatch)) {
return urldecode($tabMatch[1]);
}
if (preg_match('/^https?:\/\//i', $strRaw)) {
$tabParts = parse_url($strRaw);
if (!empty($tabParts['query'])) {
parse_str($tabParts['query'], $tabQuery);
if (!empty($tabQuery['t'])) {
return trim((string)$tabQuery['t']);
}
}
}
if (preg_match('/^[a-zA-Z0-9_-]{6,64}$/', $strRaw)) {
return $strRaw;
}
return '';
}
function fxInscrMobileResolveQrScan($strRaw, $intEveId, $strLangue) {
global $objDatabase;
$strToken = fxInscrMobileExtractQrToken($strRaw);
if ($strToken === '') {
return array('state' => 'error', 'message' => fxInscrMobileT('inscr_mobile_qr_invalid'));
}
$tabToken = $objDatabase->fxGetRow(
'SELECT qr_public_id, pec_id_original, eve_id'
. ' FROM qr_tokens'
. " WHERE qr_public_id = '" . $objDatabase->fxEscape($strToken) . "'"
. ' LIMIT 1'
);
if ($tabToken === null) {
return array('state' => 'error', 'message' => fxInscrMobileT('inscr_mobile_qr_invalid'));
}
$intPecId = (int)$tabToken['pec_id_original'];
if ($intPecId <= 0) {
return array('state' => 'error', 'message' => fxInscrMobileT('inscr_mobile_qr_invalid'));
}
$tabPec = $objDatabase->fxGetRow(
'SELECT ec.pec_id_original'
. ' FROM resultats_epreuves_commandees ec'
. ' WHERE ec.pec_id_original = ' . $intPecId
. ' AND ec.eve_id = ' . intval($intEveId)
. ' AND ec.pec_actif = 1'
. ' LIMIT 1'
);
if ($tabPec !== null) {
$arrRow = fxInscrMobileFetchRowByPec($intPecId, $intEveId);
if ($arrRow === null) {
return array('state' => 'error', 'message' => fxInscrMobileT('inscr_mobile_qr_not_found'));
}
return array(
'state' => 'success',
'pec_id' => $intPecId,
);
}
$intQrEveId = (int)$tabToken['eve_id'];
if ($intQrEveId <= 0) {
$tabOther = $objDatabase->fxGetRow(
'SELECT ec.eve_id FROM resultats_epreuves_commandees ec'
. ' WHERE ec.pec_id_original = ' . $intPecId
. ' AND ec.pec_actif = 1'
. ' ORDER BY ec.pec_id_original DESC LIMIT 1'
);
if ($tabOther !== null) {
$intQrEveId = (int)$tabOther['eve_id'];
}
}
$strEveNom = '';
if ($intQrEveId > 0) {
$arrEv = fxGetEvenementsId($intQrEveId);
if (!empty($arrEv)) {
$strEveNom = fxUnescape($arrEv['eve_nom_' . $strLangue]);
}
}
if ($strEveNom === '') {
$strEveNom = '#' . $intQrEveId;
}
return array(
'state' => 'wrong_event',
'message' => str_replace('%s', $strEveNom, fxInscrMobileT('inscr_mobile_qr_wrong_event')),
'eve_nom' => $strEveNom,
);
}
function fxInscrMobileRenderEventPicker($tabEveIds, $strLangue, $strBaseUrl) {
global $objDatabase;
$strTitle = ($strLangue === 'fr') ? 'Choisir un événement' : 'Choose an event';
echo '<div id="module-inscr-mobile" class="inscr-mobile-shell">';
fxInscrMobileRenderPageHead($strTitle);
echo '<div class="inscr-mobile-event-list">';
foreach ($tabEveIds as $intEveId) {
$qry = 'SELECT e.* FROM inscriptions_evenements e WHERE e.eve_actif = 1 AND e.eve_id = ' . intval($intEveId);
$tabEv = $objDatabase->fxGetRow($qry);
if ($tabEv === null) {
continue;
}
$strUrl = fxInscrMobileBuildUrl($strBaseUrl, $intEveId, fxInscrMobileParseRequest(), array());
echo '<a class="inscr-mobile-event-item" href="' . fxInscrMobileEsc($strUrl) . '">';
echo '<span class="inscr-mobile-event-item__name">' . fxInscrMobileEsc(fxUnescape($tabEv['eve_nom_' . $strLangue])) . '</span>';
echo '<i class="fa fa-chevron-right" aria-hidden="true"></i>';
echo '</a>';
}
echo '</div></div>';
}
function fxInscrMobileRenderQrPanel($intEveId, $strLangue) {
global $vDomaine;
$intComId = intval($_SESSION['com_id'] ?? 0);
if (!fxInscrMobileCanScan($intComId, $intEveId)) {
return;
}
$strQrAjaxUrl = $vDomaine . '/ajax_inscr_mobile_qr.php';
echo '<details class="inscr-mobile-panel inscr-mobile-panel--qr" id="inscr-mobile-qr-panel"';
echo ' data-qr-resolve-url="' . fxInscrMobileEsc($strQrAjaxUrl) . '"';
echo ' data-qr-eve-id="' . fxInscrMobileEsc(base64_encode((string)$intEveId)) . '"';
echo ' data-qr-lang="' . fxInscrMobileEsc($strLangue) . '"';
echo ' data-qr-msg-invalid="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_invalid')) . '"';
echo ' data-qr-msg-wrong="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_wrong_event')) . '"';
echo ' data-qr-msg-camera="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_camera_error')) . '">';
echo '<summary class="inscr-mobile-panel__head">';
fxInscrMobileRenderPanelSummary(fxInscrMobileT('inscr_mobile_qr_title'), 'fa-qrcode');
echo '</summary>';
echo '<div class="inscr-mobile-panel__body">';
echo '<p class="inscr-mobile-qr-hint text-muted small mb-2">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_hint')) . '</p>';
echo '<div id="inscr-mobile-qr-feedback" class="alert d-none mb-2" role="alert"></div>';
echo '<div id="inscr-mobile-qr-reader-wrap" class="inscr-mobile-qr-reader-wrap">';
echo '<div id="inscr-mobile-qr-reader"></div>';
echo '</div></div></details>';
}
function fxInscrMobileRenderBibScanBlock($strBibInputId, $strLangue) {
echo '<div class="inscr-mobile-bib-scan-panel" hidden';
echo ' data-bib-input-id="' . fxInscrMobileEsc($strBibInputId) . '"';
echo ' data-msg-scanning="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_scanning')) . '"';
echo ' data-msg-loading="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_loading')) . '"';
echo ' data-msg-ready="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_ready')) . '"';
echo ' data-msg-found="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_found')) . '"';
echo ' data-msg-invalid="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_invalid')) . '"';
echo ' data-msg-camera="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_camera_error')) . '">';
echo '<p class="inscr-mobile-bib-scan-hint text-muted small mb-1">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_hint')) . '</p>';
echo '<div class="inscr-mobile-bib-scan-status small mb-1" aria-live="polite"></div>';
echo '<div class="inscr-mobile-bib-scan-capture" role="button" tabindex="0">';
echo '<div class="inscr-mobile-bib-scan-video"></div>';
echo '<span class="inscr-mobile-bib-scan-capture-label">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_tap')) . '</span>';
echo '</div>';
echo '</div>';
}
function fxInscrMobileRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
global $vDomaine;
$arrEvenement = fxGetEvenementsId($intEveId);
$strEveNom = fxUnescape($arrEvenement['eve_nom_' . $strLangue]);
$intFilterCount = fxInscrMobileFilterActiveCount($arrReq);
$strBackUrl = fxInscrMobileIsEntry()
? $strBaseUrl
: ($vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_promoteur' : '/account/inc_tableau_promoteur')
. '?promoteur_eve_id=' . rawurlencode(base64_encode((string)$intEveId)));
echo '<div id="module-inscr-mobile" class="inscr-mobile-shell" data-inscr-mobile="1">';
if (fxInscrMobileShouldShowListBack((int)$_SESSION['com_id'])) {
fxInscrMobileRenderNavBack($strBackUrl, fxInscrMobileListBackLabel($strLangue));
}
fxInscrMobileRenderPageHead(fxInscrMobileT('inscr_mobile_title'), $strEveNom);
fxInscrMobileRenderQrPanel($intEveId, $strLangue);
// Recherche (repliable — fermée par défaut pour montrer la liste d'abord)
echo '<details class="inscr-mobile-panel">';
echo '<summary class="inscr-mobile-panel__head">';
fxInscrMobileRenderPanelSummary(fxInscrMobileT('txt_recherche'), 'fa-search');
echo '</summary>';
echo '<div class="inscr-mobile-panel__body">';
echo '<form action="' . fxInscrMobileEsc($strBaseUrl) . '" method="get" class="inscr-mobile-form">';
echo '<input type="hidden" name="promoteur_eve_id" value="' . fxInscrMobileEsc(base64_encode((string)$intEveId)) . '">';
$arrFields = array(
'rech_prenom' => 'rech_prenom',
'rech_nom' => 'rech_nom',
'rech_no_commande' => 'rech_no_commande',
'rech_nom_equipe' => 'inscr_mobile_rech_bib_equipe',
);
foreach ($arrFields as $strKey => $strLbl) {
echo '<label class="inscr-mobile-label" for="' . $strKey . '">' . fxInscrMobileEsc(fxInscrMobileT($strLbl)) . '</label>';
echo '<input class="form-control form-control-sm rounded-0" type="text" id="' . $strKey . '" name="' . $strKey . '" value="' . fxInscrMobileEsc($arrReq[$strKey]) . '">';
}
if ($arrReq['sel_rech_epreuve'] > 0) {
echo '<input type="hidden" name="sel_rech_epreuve" value="' . fxInscrMobileEsc(base64_encode((string)$arrReq['sel_rech_epreuve'])) . '">';
}
if ($arrReq['chk_bib']) {
echo '<input type="hidden" name="chk_bib" value="1">';
}
if ($arrReq['chk_cancelled']) {
echo '<input type="hidden" name="chk_cancelled" value="1">';
}
echo '<div class="inscr-mobile-form-actions mt-2">';
echo '<a class="btn btn-secondary btn-sm rounded-0" href="' . fxInscrMobileEsc(fxInscrMobileSearchResetUrl($strBaseUrl, $intEveId)) . '">'
. fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_reset_search')) . '</a>';
echo '<button class="btn btn-primary btn-sm rounded-0" type="submit" name="btn_recherche" value="1">' . fxInscrMobileEsc(fxInscrMobileT('txt_recherche')) . '</button>';
echo '</div></form></div></details>';
// Filtres
global $objDatabase;
$tabEpreuves = $objDatabase->fxGetResults(
'SELECT * FROM inscriptions_epreuves e WHERE e.eve_id = ' . intval($intEveId) . ' AND epr_actif = 1 ORDER BY epr_id'
);
$strFilterLabel = fxInscrMobileT('inscr_mobile_filters');
if ($intFilterCount > 0) {
$strFilterLabel .= ' (' . $intFilterCount . ')';
}
echo '<details class="inscr-mobile-panel">';
echo '<summary class="inscr-mobile-panel__head">';
fxInscrMobileRenderPanelSummary($strFilterLabel, 'fa-filter');
echo '</summary>';
echo '<div class="inscr-mobile-panel__body">';
echo '<form action="' . fxInscrMobileEsc($strBaseUrl) . '" method="get" class="inscr-mobile-form">';
echo '<input type="hidden" name="promoteur_eve_id" value="' . fxInscrMobileEsc(base64_encode((string)$intEveId)) . '">';
foreach (array('rech_prenom', 'rech_nom', 'rech_no_commande', 'rech_nom_equipe') as $strKey) {
if ($arrReq[$strKey] !== '') {
echo '<input type="hidden" name="' . $strKey . '" value="' . fxInscrMobileEsc($arrReq[$strKey]) . '">';
}
}
echo '<label class="inscr-mobile-label" for="sel_rech_epreuve">' . fxInscrMobileEsc(fxInscrMobileT('sel_rech_epreuve')) . '</label>';
echo '<select class="form-control form-control-sm rounded-0" id="sel_rech_epreuve" name="sel_rech_epreuve">';
echo '<option value="">—</option>';
for ($i = 1; $i <= count($tabEpreuves); $i++) {
$strOpt = fxInscrMobileEpreuveLabel($tabEpreuves[$i]['epr_id'], $strLangue);
$strSel = ($arrReq['sel_rech_epreuve'] == $tabEpreuves[$i]['epr_id']) ? ' selected' : '';
$strVal = base64_encode((string)$tabEpreuves[$i]['epr_id']);
echo '<option value="' . fxInscrMobileEsc($strVal) . '"' . $strSel . '>' . fxInscrMobileEsc($strOpt) . '</option>';
}
echo '</select>';
echo '<label class="inscr-mobile-check mt-2"><input type="checkbox" name="chk_bib" value="1"' . ($arrReq['chk_bib'] ? ' checked' : '') . '> ' . fxInscrMobileEsc(fxInscrMobileT('chk_bib')) . '</label>';
echo '<label class="inscr-mobile-check"><input type="checkbox" name="chk_cancelled" value="1"' . ($arrReq['chk_cancelled'] ? ' checked' : '') . '> ' . fxInscrMobileEsc(fxInscrMobileT('chk_cancelled')) . '</label>';
echo '<div class="inscr-mobile-form-actions mt-2">';
echo '<a class="btn btn-secondary btn-sm rounded-0" href="' . fxInscrMobileEsc(fxInscrMobileSearchResetUrl($strBaseUrl, $intEveId)) . '">'
. fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_reset_search')) . '</a>';
echo '<button class="btn btn-primary btn-sm rounded-0" type="submit" name="apply_filters" value="1">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_apply_filters')) . '</button>';
echo '</div></form></div></details>';
// Liste complète dès l'ouverture
$tabRows = fxInscrMobileFetchRows($intEveId, $arrReq);
$intNbItemsParPage = 50;
$intNbTotal = ($tabRows !== null) ? count($tabRows) : 0;
$intPage = 1;
$intStart = 1;
$intEnd = $intNbItemsParPage;
if (!empty($_GET['pg'])) {
$intPage = max(1, intval($_GET['pg']));
}
if (intval($intPage) > 1) {
$intStart = ($intPage - 1) * $intNbItemsParPage + 1;
$intEnd = $intStart + $intNbItemsParPage - 1;
}
if ($intEnd > $intNbTotal) {
$intEnd = $intNbTotal;
}
echo '<div id="inscr-mobile-list" class="inscr-mobile-list-anchor">';
echo '<div class="inscr-mobile-list-head">';
if ($strLangue === 'fr') {
echo '<span>' . (int)$intNbTotal . ' inscription' . ($intNbTotal > 1 ? 's' : '') . '</span>';
} else {
echo '<span>' . (int)$intNbTotal . ' registration' . ($intNbTotal !== 1 ? 's' : '') . '</span>';
}
if ($intNbTotal > $intNbItemsParPage) {
$intNbPages = (int)ceil($intNbTotal / $intNbItemsParPage);
echo '<span class="inscr-mobile-list-head__pg">' . ($strLangue === 'fr' ? 'Page ' : 'Page ') . $intPage . ' / ' . $intNbPages . '</span>';
}
echo '</div>';
if ($intNbTotal > 0) {
echo '<div class="inscr-mobile-list">';
for ($j = $intStart; $j <= $intEnd; $j++) {
$row = $tabRows[$j];
$strFicheUrl = fxInscrMobileBuildUrl($strBaseUrl, $intEveId, $arrReq, array(
'pec_id' => (int)$row['pec_id_original'],
'pg' => $intPage,
));
$strBib = fxInscrMobileBibDisplay($row);
$strName = fxUnescape($row['par_nom']) . ', ' . fxUnescape($row['par_prenom']);
$strRace = fxInscrMobileEpreuveLabel($row['epr_id'], $strLangue);
$strCardClass = 'inscr-mobile-list-item';
if ($row['is_cancelled'] == '1') {
$strCardClass .= ' inscr-mobile-list-item--cancelled';
}
echo '<a class="' . $strCardClass . '" href="' . fxInscrMobileEsc($strFicheUrl) . '">';
echo '<span class="inscr-mobile-list-item__name">' . fxInscrMobileEsc($strName) . '</span>';
echo '<span class="inscr-mobile-list-item__race">' . fxInscrMobileEsc($strRace) . '</span>';
echo '<span class="inscr-mobile-list-item__order">' . fxInscrMobileEsc($row['no_commande']) . '</span>';
echo '<span class="inscr-mobile-list-item__bib">';
echo trim($strBib) !== '' ? fxInscrMobileEsc($strBib) : '—';
echo '</span>';
echo '<span class="inscr-mobile-list-item__check">';
if ($row['no_bib_remis'] == 1) {
echo '<span class="inscr-mobile-badge inscr-mobile-badge--ok">' . fxInscrMobileEsc(fxInscrMobileT('promoteur_bib_enregistre')) . '</span>';
}
echo '</span>';
echo '<i class="fa fa-chevron-right inscr-mobile-list-item__arrow" aria-hidden="true"></i>';
echo '</a>';
}
echo '</div>';
echo fxInscrMobileRenderPagination($strBaseUrl, $intEveId, $arrReq, $intNbTotal, $intNbItemsParPage, $intPage);
} else {
echo '<div class="alert alert-light border inscr-mobile-empty">' . fxInscrMobileEsc(fxInscrMobileT('txt_recherche_no_result')) . '</div>';
}
echo '</div>';
}
function fxInscrMobileRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow) {
global $vDomaine;
$intComId = intval($_SESSION['com_id'] ?? 0);
$intRowEveId = intval($arrRow['eve_id']);
$blnCanStatut = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.statut_edit');
$blnCanBib = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.bib_edit');
$blnCanRemis = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.bib_remis');
$blnCanEdit = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.edit');
$blnCanCancel = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.cancel');
$blnCanRestore = fxInscrMobileCanDo($intComId, $intRowEveId, 'inscriptions_mobile.restore');
$blnHasEditable = ($blnCanStatut || $blnCanBib || $blnCanRemis);
$blnHasGestion = ($blnCanEdit || $blnCanCancel || $blnCanRestore);
$strListUrl = fxInscrMobileBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null, 'pg' => $arrReq['pg']));
$strEveCode = fxGetEvenementsUrl($arrRow['eve_id']);
$strBib = fxInscrMobileBibDisplay($arrRow);
$intParId = $arrRow['par_id'];
$blnCancelled = ($arrRow['is_cancelled'] == '1');
$blnEquipe = (intval($arrRow['pec_equipe']) === 1);
$strBibAction = $blnEquipe ? 'no_equipe' : 'no_bib';
$strBibInputId = $blnEquipe ? 'txt_no_bib_e' : 'txt_no_bib_p';
if ($arrRow['no_bib_remis'] == 1) {
$strRemisClass = 'btn-success';
$strRemisIcon = '<i class="fa fa-check" aria-hidden="true"></i>';
$intRemisVal = 0;
} else {
$strRemisClass = 'btn-primary';
$strRemisIcon = '<i class="fa fa-sharp fa-regular fa-square fa-2xs" aria-hidden="true"></i>';
$intRemisVal = 1;
}
echo '<div id="module-inscr-mobile" class="inscr-mobile-shell inscr-mobile-fiche" data-inscr-mobile="1"';
$blnFromQr = !empty($_GET['from_qr']);
if ($blnFromQr) {
echo ' data-from-qr="1"';
}
echo '>';
fxInscrMobileRenderNavBack($strListUrl, fxInscrMobileT('inscr_mobile_back_list'));
echo '<div class="inscr-mobile-fiche-head">';
echo '<h1 class="inscr-mobile-page-title">' . fxInscrMobileEsc(fxUnescape($arrRow['par_nom']) . ', ' . fxUnescape($arrRow['par_prenom'])) . '</h1>';
echo '</div>';
$strDetailsType = $blnEquipe && fxIsParEquipe($arrRow['pec_id_original'], $arrRow['epr_id'])
? fxInscrMobileT('promoteur_bib_show_teamates')
: fxInscrMobileT('epreuve_individuelle');
fxInscrMobileRenderFicheSectionStart('details', fxInscrMobileT('inscr_mobile_details'), 'fa-info-circle', !$blnFromQr);
fxInscrMobileRenderKvListOpen();
fxInscrMobileRenderKvRow(fxInscrMobileT('inscr_mobile_epreuve'), fxInscrMobileEpreuveLabel($arrRow['epr_id'], $strLangue));
fxInscrMobileRenderKvRow(fxInscrMobileT('inscr_mobile_type'), $strDetailsType);
fxInscrMobileRenderKvRow(fxInscrMobileT('inscr_mobile_modified'), fxCheckMAJ($arrRow['pec_id_original'], $intParId, $strLangue), true);
fxInscrMobileRenderFicheProfileKvRows($arrRow, $strLangue);
fxInscrMobileRenderKvListClose();
fxInscrMobileRenderFicheSectionEnd();
$strStyleEdit = $strStyleCancel = '';
$strStyleRetablir = ' d-none';
if ($blnCancelled) {
$strStyleEdit = $strStyleCancel = ' d-none';
$strStyleRetablir = '';
}
$strRenvoi = ($strLangue === 'fr') ? 'RENVOI' : 'RESEND';
if ($blnHasGestion) {
fxInscrMobileRenderFicheSectionStart('gestion', fxInscrMobileT('inscr_mobile_section_management'), 'fa-cog', !$blnFromQr);
echo '<div class="inscr-mobile-gestion-actions">';
echo '<a class="btn btn-primary btn-sm rounded-pill" href="' . $vDomaine . '/facture.php?no_panier=' . rawurlencode($arrRow['no_panier']) . '&amp;lang=' . $strLangue . '" target="_blank">' . fxInscrMobileEsc($arrRow['no_commande']) . '</a>';
echo '<button class="btn btn-primary btn-sm rounded-0 link_confirmation" type="button"'
. ' data-no_panier="' . fxInscrMobileEsc($arrRow['no_panier']) . '"'
. ' data-no_commande="' . fxInscrMobileEsc($arrRow['no_commande']) . '"'
. ' data-lng="' . $strLangue . '">' . fxInscrMobileEsc($strRenvoi) . '</button>';
if ($blnCanEdit) {
echo '<button class="btn btn-primary btn-sm rounded-0 btn_edit_event_promo' . $strStyleEdit . '" type="button"'
. ' id="modifier_fiche" data-eve_code="' . fxInscrMobileEsc($strEveCode) . '"'
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrMobileEsc(fxInscrMobileT('btn_modifierinscriptions')) . '</button>';
}
echo '<button class="btn btn-warning btn-sm rounded-0" type="button" data-inscr-field="remboursement">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_remboursement')) . '</button>';
if ($blnCanCancel) {
echo '<button class="btn btn-secondary btn-sm rounded-0 btn_cancel_event_promo' . $strStyleCancel . '" type="button"'
. ' id="annuler_fiche" data-eve_code="' . fxInscrMobileEsc($strEveCode) . '"'
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrMobileEsc(fxInscrMobileT('btn_annulerinscriptions')) . '</button>';
}
if ($blnCanRestore) {
echo '<button class="btn btn-secondary btn-sm rounded-0 btn_retablir_event_promo' . $strStyleRetablir . '" type="button"'
. ' id="retablir_fiche" data-eve_code="' . fxInscrMobileEsc($strEveCode) . '"'
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '" data-eve_id="' . (int)$arrRow['eve_id'] . '"'
. ' value="' . (int)$arrRow['pec_id_original'] . '">' . fxInscrMobileEsc(fxInscrMobileT('btn_retablirinscriptions')) . '</button>';
}
echo '</div>';
fxInscrMobileRenderFicheSectionEnd();
}
if ($blnHasEditable) {
fxInscrMobileRenderFicheSectionStart('editable', fxInscrMobileT('inscr_mobile_section_editable'), 'fa-pencil-square-o', true);
if ($blnCanBib) {
$strFullBibInputId = $strBibInputId . $intParId;
$blnCanBibScan = fxInscrMobileCanScan($intComId, $intEveId);
echo '<div class="inscr-mobile-field-block" data-inscr-field="bib">';
echo '<div class="inscr-mobile-field-block__label">' . fxInscrMobileEsc(fxInscrMobileT('promoteur_bib_number')) . '</div>';
if ($blnCanBibScan) {
fxInscrMobileRenderBibScanBlock($strFullBibInputId, $strLangue);
}
echo '<div class="inscr-mobile-bib-row">';
echo '<input class="form-control rounded-0" type="text" id="' . $strFullBibInputId . '" value="' . fxInscrMobileEsc($strBib) . '">';
if ($blnCanBibScan) {
echo '<button class="btn btn-secondary rounded-0 inscr-mobile-bib-scan-toggle" type="button" aria-expanded="false"'
. ' title="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_btn')) . '"'
. ' aria-label="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_btn')) . '">';
echo '<i class="fa fa-camera" aria-hidden="true"></i>';
echo '</button>';
}
echo '<button class="btn btn-primary rounded-0 btn_bib" type="button" data-action="' . $strBibAction . '"'
. ' data-eve_id="' . rawurlencode(base64_encode((string)$arrRow['eve_id'])) . '"'
. ' data-epr_id="' . (int)$arrRow['epr_id'] . '"'
. ' data-par_id="' . (int)$intParId . '"'
. ' data-pec_id="' . (int)$arrRow['pec_id_original'] . '">OK</button>';
echo '</div>';
echo '</div>';
}
if ($blnCanStatut) {
echo '<div class="inscr-mobile-field-block inscr-mobile-field-block--statut" data-inscr-field="statut">';
echo '<div class="inscr-mobile-field-block__label">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_statut_label')) . '</div>';
fxInscrMobileRenderStatutField($intParId, $arrRow['par_statut_course'] ?? '', $arrRow['eve_id'], $strLangue);
echo '</div>';
}
$strRemisDate = trim((string)$arrRow['no_bib_remis_date']);
if ($strRemisDate === '0000-00-00 00:00:00') {
$strRemisDate = '';
}
$strRemisPar = trim((string)$arrRow['no_bib_remis_par']);
if ($blnCanRemis) {
echo '<div class="inscr-mobile-field-block" data-inscr-field="remis">';
echo '<div class="inscr-mobile-remis-row">';
echo '<div class="inscr-mobile-remis-row__left">';
echo '<div class="inscr-mobile-field-block__label inscr-mobile-field-block__label--inline">' . fxInscrMobileEsc(fxInscrMobileT('promoteur_bib_enregistre')) . '</div>';
echo '<span id="' . (int)$intParId . '">';
echo '<a class="btn btn-sm rounded-0 btn_remis ' . $strRemisClass . '" href="#" data-action="remis"'
. ' data-table="' . rawurlencode(base64_encode('resultats_participants')) . '"'
. ' data-field="no_bib_remis" data-key="par_id" data-valeur="' . $intRemisVal . '"'
. ' data-id="' . (int)$intParId . '">' . $strRemisIcon . '</a>';
echo '</span>';
echo '</div>';
echo '<div class="inscr-mobile-remis-row__meta inscr-mobile-muted">';
echo '<span id="date_' . (int)$intParId . '">' . fxInscrMobileEsc($strRemisDate) . '</span>';
if ($strRemisDate !== '' && $strRemisPar !== '') {
echo '<span class="inscr-mobile-remis-row__sep"> — </span>';
}
echo '<span id="par_' . (int)$intParId . '">' . fxInscrMobileEsc($strRemisPar) . '</span>';
echo '</div></div></div>';
}
fxInscrMobileRenderFicheSectionEnd();
}
echo '</div>';
}
function fxInscrMobileRun($intEveId, $strLangue) {
$strBaseUrl = fxInscrMobileBaseUrl($strLangue);
$arrReq = fxInscrMobileParseRequest();
if ($arrReq['pec_id'] > 0) {
$arrRow = fxInscrMobileFetchRowByPec($arrReq['pec_id'], $intEveId);
if ($arrRow === null) {
echo '<div class="alert alert-danger">' . fxInscrMobileEsc(fxInscrMobileT('txt_recherche_no_result')) . '</div>';
echo '<a class="btn btn-primary rounded-0" href="' . fxInscrMobileEsc(fxInscrMobileBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null))) . '">';
echo fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_back_list')) . '</a>';
return;
}
fxInscrMobileRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow);
return;
}
fxInscrMobileRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq);
}