Implement multi-selection filter for race status in the registration management interface. Enhance UI with a mobile-friendly design for better user interaction. Update backend logic to handle selected statuses and ensure proper filtering in requests. This aligns with MSIN-4401 requirements for improved event management functionality.

This commit is contained in:
2026-07-13 11:52:58 -04:00
parent dd33cb6873
commit 9ec4fd9ead
4 changed files with 230 additions and 3 deletions

View File

@ -3532,6 +3532,93 @@ a.ms1-trad-link.btn-aide-trad{
margin:8px 0 0;
}
/* MSIN-4401 — Multi-sélection statut de course (tactile / mobile). */
.inscr-gestion-statut-multi{
position:relative;
margin-top:0;
}
.inscr-gestion-statut-multi__summary{
list-style:none;
display:flex;
align-items:center;
justify-content:space-between;
gap:8px;
min-height:38px;
padding:6px 10px;
border:1px solid #ced4da;
background:#fff;
font-size:14px;
color:#212529;
cursor:pointer;
-webkit-user-select:none;
user-select:none;
}
.inscr-gestion-statut-multi__summary::-webkit-details-marker{
display:none;
}
.inscr-gestion-statut-multi__summary::after{
content:'\f078';
font-family:FontAwesome;
font-size:12px;
color:#6c757d;
flex-shrink:0;
}
.inscr-gestion-statut-multi[open] > .inscr-gestion-statut-multi__summary::after{
content:'\f077';
}
.inscr-gestion-statut-multi__summary-text{
flex:1;
min-width:0;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.inscr-gestion-statut-multi__panel{
display:flex;
flex-direction:column;
gap:2px;
margin-top:4px;
padding:8px;
border:1px solid #ced4da;
background:#fff;
max-height:min(280px, 50vh);
overflow-y:auto;
-webkit-overflow-scrolling:touch;
}
.inscr-gestion-statut-multi__opt{
display:flex;
align-items:center;
gap:10px;
min-height:40px;
padding:6px 8px;
margin:0;
font-size:14px;
font-weight:400;
color:#212529;
cursor:pointer;
border-radius:2px;
-webkit-tap-highlight-color:transparent;
}
.inscr-gestion-statut-multi__opt:active,
.inscr-gestion-statut-multi__opt:hover{
background:#f1f3f5;
}
.inscr-gestion-statut-multi__opt input{
width:18px;
height:18px;
flex-shrink:0;
margin:0;
}
.inscr-gestion-form-actions{
display:flex;
flex-wrap:wrap;

View File

@ -890,6 +890,32 @@
Ms1Loader.show(inscrLoaderMsg);
}
});
// MSIN-4401 — Libellé du multi-select statut (Tous / N sélectionnés).
(function () {
function updateStatutMultiSummary(details) {
if (!details) {
return;
}
var textEl = details.querySelector('.inscr-gestion-statut-multi__summary-text');
if (!textEl) {
return;
}
var checked = details.querySelectorAll('input[name="sel_rech_statut[]"]:checked');
var n = checked.length;
var labelAll = details.getAttribute('data-label-all') || '';
var labelN = details.getAttribute('data-label-n') || '%d';
textEl.textContent = (n === 0) ? labelAll : labelN.replace('%d', String(n));
}
moduleInscr.addEventListener('change', function (e) {
var input = e.target;
if (!input || input.name !== 'sel_rech_statut[]') {
return;
}
updateStatutMultiSummary(input.closest('.inscr-gestion-statut-multi'));
});
})();
})();
})();

View File

@ -370,6 +370,10 @@ function fxInscrGestionFallbackTexte($strClef, $strLangue) {
'inscr_gestion_chk_cancelled' => $blnFr
? 'Montrer les inscriptions annulées ou transférées'
: 'Show cancelled or transferred registrations',
// MSIN-4401 — Filtre recherche par statut de course (multi-sélection).
'inscr_gestion_rech_statut' => $blnFr ? 'Statut de course' : 'Race status',
'inscr_gestion_rech_statut_all' => $blnFr ? 'Tous les statuts' : 'All statuses',
'inscr_gestion_rech_statut_n' => $blnFr ? '%d sélectionnés' : '%d selected',
);
}
@ -546,6 +550,27 @@ function fxInscrGestionParseEveId($strRaw) {
return (int)$strDecoded;
}
/**
* MSIN-4401 — Codes statut de course soumis (GET sel_rech_statut[]), whitelistes.
* Tableau vide = aucun filtre (tous les statuts).
*/
function fxInscrGestionParseStatutFilter($mixRaw) {
if (!is_array($mixRaw)) {
return array();
}
$tabOut = array();
foreach ($mixRaw as $mixCode) {
$strCode = strtoupper(trim((string)$mixCode));
$strCode = preg_replace('/[^A-Z0-9_]/', '', $strCode);
if ($strCode !== '') {
$tabOut[$strCode] = $strCode;
}
}
return array_values($tabOut);
}
function fxInscrGestionParseRequest() {
$arr = array(
'rech_prenom' => isset($_GET['rech_prenom']) ? trim($_GET['rech_prenom']) : '',
@ -555,6 +580,10 @@ function fxInscrGestionParseRequest() {
'chk_bib' => !empty($_GET['chk_bib']) ? 1 : 0,
'chk_cancelled' => !empty($_GET['chk_cancelled']) ? 1 : 0,
'sel_rech_epreuve' => 0,
// MSIN-4401 — Filtre multi statut de course (vide = tous).
'sel_rech_statut' => fxInscrGestionParseStatutFilter(
isset($_GET['sel_rech_statut']) ? $_GET['sel_rech_statut'] : array()
),
'pg' => isset($_GET['pg']) ? max(1, intval($_GET['pg'])) : 1,
'pec_id' => isset($_GET['pec_id']) ? intval($_GET['pec_id']) : 0,
// MSIN-4436 — Page d'origine (ex. gestion dossards) pour le bouton retour de la fiche.
@ -576,7 +605,8 @@ function fxInscrGestionParseRequest() {
// ou au moins un critere present (utile pour le retour depuis une fiche / la pagination).
$blnSubmit = !empty($_GET['btn_recherche']) || !empty($_GET['apply_filters']) || !empty($_GET['q']);
$blnCriteria = ($arr['rech_prenom'] !== '' || $arr['rech_nom'] !== '' || $arr['rech_no_commande'] !== ''
|| $arr['rech_nom_equipe'] !== '' || $arr['sel_rech_epreuve'] > 0 || $arr['chk_bib'] || $arr['chk_cancelled']);
|| $arr['rech_nom_equipe'] !== '' || $arr['sel_rech_epreuve'] > 0 || $arr['chk_bib'] || $arr['chk_cancelled']
|| count($arr['sel_rech_statut']) > 0);
$arr['q'] = ($blnSubmit || $blnCriteria) ? 1 : 0;
return $arr;
@ -593,6 +623,9 @@ function fxInscrGestionFilterActiveCount($arrReq) {
if ($arrReq['chk_cancelled']) {
$int++;
}
if (!empty($arrReq['sel_rech_statut']) && is_array($arrReq['sel_rech_statut']) && count($arrReq['sel_rech_statut']) > 0) {
$int++;
}
return $int;
}
@ -605,6 +638,7 @@ function fxInscrGestionEmptyListRequest() {
'chk_bib' => 0,
'chk_cancelled' => 0,
'sel_rech_epreuve' => 0,
'sel_rech_statut' => array(),
'pg' => 1,
'pec_id' => 0,
'inscr_return' => '',
@ -652,6 +686,27 @@ function fxInscrGestionBuildWhere($intEveId, $arrReq) {
$strWhere .= ' AND e.is_cancelled = 0 AND e.pec_actif = 1';
}
// MSIN-4401 — Filtre statut de course (vide = tous). CONF inclut aussi les valeurs vides (défaut).
if (!empty($arrReq['sel_rech_statut']) && is_array($arrReq['sel_rech_statut'])) {
$tabCodes = array();
foreach ($arrReq['sel_rech_statut'] as $strCode) {
$strCode = strtoupper(trim((string)$strCode));
$strCode = preg_replace('/[^A-Z0-9_]/', '', $strCode);
if ($strCode !== '') {
$tabCodes[$strCode] = "'" . $objDatabase->fxEscape($strCode) . "'";
}
}
if (count($tabCodes) > 0) {
$strIn = implode(',', $tabCodes);
if (isset($tabCodes['CONF'])) {
$strWhere .= ' AND (p.par_statut_course IN (' . $strIn . ')'
. " OR TRIM(IFNULL(p.par_statut_course, '')) = '')";
} else {
$strWhere .= ' AND p.par_statut_course IN (' . $strIn . ')';
}
}
}
return $strWhere;
}
@ -1042,6 +1097,58 @@ function fxInscrGestionRenderStatutField($intParId, $strCurrent, $intEveId, $str
echo '</select>';
}
/**
* MSIN-4401 — Multi-sélection statut de course (mobile-friendly : panneau + cases à cocher).
* Aucune case cochée = tous les statuts.
*/
function fxInscrGestionRenderStatutFilter($arrReq, $strLangue) {
$tabOptions = fxInscrGestionGetStatutCourseOptions($strLangue);
if (count($tabOptions) === 0) {
return;
}
$tabSelected = (!empty($arrReq['sel_rech_statut']) && is_array($arrReq['sel_rech_statut']))
? $arrReq['sel_rech_statut']
: array();
$tabSelectedMap = array();
foreach ($tabSelected as $strCode) {
$tabSelectedMap[$strCode] = true;
}
$intNb = count($tabSelected);
$strSummary = ($intNb === 0)
? fxInscrGestionT('inscr_gestion_rech_statut_all')
: sprintf(fxInscrGestionT('inscr_gestion_rech_statut_n'), $intNb);
echo '<label class="inscr-gestion-label" for="inscr-gestion-statut-multi-summary">'
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_rech_statut')) . '</label>';
echo '<details class="inscr-gestion-statut-multi"'
. ' data-label-all="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_rech_statut_all')) . '"'
. ' data-label-n="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_rech_statut_n')) . '">';
echo '<summary class="inscr-gestion-statut-multi__summary" id="inscr-gestion-statut-multi-summary">'
. '<span class="inscr-gestion-statut-multi__summary-text">' . fxInscrGestionEsc($strSummary) . '</span>'
. '</summary>';
echo '<div class="inscr-gestion-statut-multi__panel" role="group"'
. ' aria-label="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_rech_statut')) . '">';
foreach ($tabOptions as $arrOpt) {
$strCode = trim((string)$arrOpt['info_option2']);
$strLabel = trim((string)$arrOpt['info_texte']);
if ($strCode === '') {
continue;
}
$strId = 'sel_rech_statut_' . preg_replace('/[^A-Za-z0-9_]/', '_', $strCode);
$blnChecked = isset($tabSelectedMap[$strCode]);
echo '<label class="inscr-gestion-statut-multi__opt" for="' . fxInscrGestionEsc($strId) . '">';
echo '<input type="checkbox" id="' . fxInscrGestionEsc($strId) . '"'
. ' name="sel_rech_statut[]" value="' . fxInscrGestionEsc($strCode) . '"'
. ($blnChecked ? ' checked' : '') . '>';
echo '<span>' . fxInscrGestionEsc($strLabel) . '</span>';
echo '</label>';
}
echo '</div></details>';
}
/** Paramètres GET pour liens (sans double-encodage). */
function fxInscrGestionQueryParams($intEveId, $arrReq, $arrExtra = array()) {
$tab = array(
@ -1069,6 +1176,10 @@ function fxInscrGestionQueryParams($intEveId, $arrReq, $arrExtra = array()) {
if ($arrReq['sel_rech_epreuve'] > 0) {
$tab['sel_rech_epreuve'] = base64_encode((string)$arrReq['sel_rech_epreuve']);
}
// MSIN-4401 — Conserver le filtre multi-statut dans pagination / fiche.
if (!empty($arrReq['sel_rech_statut']) && is_array($arrReq['sel_rech_statut'])) {
$tab['sel_rech_statut'] = array_values($arrReq['sel_rech_statut']);
}
if (!empty($_GET['lng'])) {
$tab['lng'] = $_GET['lng'];
}
@ -1391,6 +1502,9 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
}
echo '</select>';
// MSIN-4401 — Filtre multi statut de course (tous si aucune sélection).
fxInscrGestionRenderStatutFilter($arrReq, $strLangue);
echo '<label class="inscr-gestion-check mt-2"><input type="checkbox" name="chk_bib" value="1"' . ($arrReq['chk_bib'] ? ' checked' : '') . '> ' . fxInscrGestionEsc(fxInscrGestionT('chk_bib')) . '</label>';
echo '<label class="inscr-gestion-check"><input type="checkbox" name="chk_cancelled" value="1"' . ($arrReq['chk_cancelled'] ? ' checked' : '') . '> ' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_chk_cancelled')) . '</label>';

View File

@ -7,8 +7,8 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.784');
define('_DATE_CODE', '2026-07-09');
define('_VERSION_CODE', '4.72.785');
define('_DATE_CODE', '2026-07-13');
//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}/)