Files
ms1inscription-v5/php/inc_fx_inscriptions_mobile.php
stephan 09f57dcce0 Refactor mobile registration profile rendering and update CSS for improved layout
This commit enhances the mobile registration interface by refactoring the profile rendering logic to include a flag for captains and updating the associated CSS for better layout and responsiveness. The version code is incremented to 4.72.682 to reflect these changes, further improving the user experience in mobile registrations.
2026-06-19 10:07:26 -04:00

970 lines
40 KiB
PHP

<?php
/**
* Liste inscriptions mobile — recherche, filtres, cartes, fiche.
*/
function fxInscrMobileIsEntry() {
return defined('MS1_INSCR_MOBILE_ENTRY') && MS1_INSCR_MOBILE_ENTRY;
}
function fxInscrMobileGetPromoteurEveIds($intComId) {
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();
}
$tab = array_map('intval', array_filter(explode(',', $row['com_eve_promoteur'])));
return array_values($tab);
}
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');
}
/** Libellé i18n sans echo parasite. */
function fxInscrMobileT($clef) {
return afficheTexte($clef, 0);
}
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 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 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'] !== '') {
$strWhere .= ' AND p.no_commande LIKE "%' . $objDatabase->fxEscape($arrReq['rech_no_commande']) . '%"';
}
if ($arrReq['rech_nom_equipe'] !== '') {
$strWhere .= ' AND p.par_nom_equipe LIKE "%' . $objDatabase->fxEscape($arrReq['rech_nom_equipe']) . '%"';
}
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(afficheTexte('participant-titre-capitaine', 0));
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 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">';
fxInscrMobileRenderNavBack($strBackUrl, afficheTexte('promoteur_back', 0));
fxInscrMobileRenderPageHead(fxInscrMobileT('inscr_mobile_title'), $strEveNom);
$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-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 ' data-qr-lang="' . fxInscrMobileEsc($strLangue) . '">';
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>';
// 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' => 'rech_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 '<button class="btn btn-primary btn-sm rounded-0 btn-block mt-2" type="submit" name="btn_recherche" value="1">' . fxInscrMobileEsc(fxInscrMobileT('txt_recherche')) . '</button>';
echo '</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">';
$strResetUrl = fxInscrMobileBuildUrl($strBaseUrl, $intEveId, 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,
), array('pg' => 1));
echo '<a class="btn btn-secondary btn-sm rounded-0" href="' . fxInscrMobileEsc($strResetUrl) . '">' . ($strLangue === 'fr' ? 'Réinitialiser' : 'Reset') . '</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;
$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">';
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');
echo '<div class="inscr-mobile-fiche-section inscr-mobile-fiche-section--details">';
fxInscrMobileRenderSectionTitle(fxInscrMobileT('inscr_mobile_details'), 'fa-info-circle');
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();
echo '</div>';
$strStyleEdit = $strStyleCancel = '';
$strStyleRetablir = ' d-none';
if ($blnCancelled) {
$strStyleEdit = $strStyleCancel = ' d-none';
$strStyleRetablir = '';
}
$strRenvoi = ($strLangue === 'fr') ? 'RENVOI' : 'RESEND';
echo '<div class="inscr-mobile-fiche-section inscr-mobile-fiche-section--gestion">';
fxInscrMobileRenderSectionTitle(fxInscrMobileT('inscr_mobile_section_management'), 'fa-cog');
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>';
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>';
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>';
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></div>';
echo '<div class="inscr-mobile-fiche-section inscr-mobile-fiche-section--editable">';
fxInscrMobileRenderSectionTitle(fxInscrMobileT('inscr_mobile_section_editable'), 'fa-pencil-square-o');
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>';
echo '<div class="inscr-mobile-bib-row">';
echo '<input class="form-control rounded-0" type="text" id="' . $strBibInputId . $intParId . '" value="' . fxInscrMobileEsc($strBib) . '">';
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></div>';
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']);
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>';
echo '</div>';
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);
}