Implement inline editing for bib numbers and status confirmation in the participant management interface. Enhance CSS for better layout and usability, including wider columns for editable bibs and improved button styles. Update JavaScript to handle inline edits and confirmations, ensuring a smoother user experience. This change addresses MSIN-4448 and improves overall functionality in the inscriptions management system.

This commit is contained in:
2026-07-15 08:52:27 -04:00
parent a18197b31c
commit 0e42cc45d1
6 changed files with 352 additions and 21 deletions

View File

@ -3890,6 +3890,18 @@ a.ms1-trad-link.btn-aide-trad{
text-decoration:none;
}
/* MSIN-4448 — Colonne dossard plus large quand edition inline active. */
.inscr-gestion-list--can-edit-bib{
--ig-list-cols:
minmax(9.5rem, 1.15fr)
minmax(11rem, 1.9fr)
minmax(6.75rem, 0.7fr)
minmax(6.5rem, 8.5rem)
minmax(5.5rem, 7.5rem)
2.5rem
1.15rem;
}
/* En-tete de colonnes : meme grille que les lignes pour un alignement parfait. */
.inscr-gestion-list-cols{
display:grid;
@ -3916,28 +3928,51 @@ a.ms1-trad-link.btn-aide-trad{
border-bottom:none;
}
.inscr-gestion-list > a.inscr-gestion-list-item:nth-of-type(even){
/* Zebra : en-tete = child 1 ; 1re ligne (child 2) blanche, 2e (child 3) alternee. */
.inscr-gestion-list > .inscr-gestion-list-item:nth-child(odd){
background:#f7faff;
}
.inscr-gestion-list-item:hover,
.inscr-gestion-list-item:focus{
.inscr-gestion-list-item:focus-within{
color:inherit;
text-decoration:none;
background:#eaf3ff;
}
.inscr-gestion-list-item a.inscr-gestion-list-item__name,
.inscr-gestion-list-item a.inscr-gestion-list-item__race,
.inscr-gestion-list-item a.inscr-gestion-list-item__order,
.inscr-gestion-list-item a.inscr-gestion-list-item__statut{
color:inherit;
text-decoration:none;
min-width:0;
}
.inscr-gestion-list-item a.inscr-gestion-list-item__arrow{
text-decoration:none;
min-width:0;
}
.inscr-gestion-list-item a.inscr-gestion-list-item__name:hover,
.inscr-gestion-list-item a.inscr-gestion-list-item__race:hover,
.inscr-gestion-list-item a.inscr-gestion-list-item__order:hover,
.inscr-gestion-list-item a.inscr-gestion-list-item__statut:hover{
color:inherit;
text-decoration:none;
}
.inscr-gestion-list-item--cancellation{
background:#fff5f5;
border-color:#f1b0b7;
}
.inscr-gestion-list-item--cancellation:nth-of-type(even){
.inscr-gestion-list > .inscr-gestion-list-item--cancellation:nth-child(odd){
background:#fff0f0;
}
.inscr-gestion-list-item--cancellation:hover,
.inscr-gestion-list-item--cancellation:focus{
.inscr-gestion-list-item--cancellation:focus-within{
background:#ffecec;
}
@ -4010,6 +4045,57 @@ a.ms1-trad-link.btn-aide-trad{
min-width:0;
}
/* MSIN-4448 — Saisie dossard compacte dans la liste (sans camera). */
.inscr-gestion-list-bib-edit{
display:inline-flex;
align-items:center;
gap:4px;
max-width:100%;
vertical-align:middle;
}
.inscr-gestion-list-bib-input{
width:4.25rem;
max-width:100%;
padding:2px 6px;
font-size:12px;
font-weight:700;
font-variant-numeric:tabular-nums;
text-align:center;
line-height:1.35;
}
.inscr-gestion-list-bib-edit .btn_bib{
padding:2px 7px;
font-size:11px;
line-height:1.35;
flex-shrink:0;
}
button.inscr-gestion-list-remis{
margin:0;
padding:0;
cursor:pointer;
appearance:none;
-webkit-appearance:none;
background:inherit;
border:none;
}
button.inscr-gestion-list-remis.inscr-gestion-remis--no{
background:#eef1f4;
border:1px solid #dee2e6;
}
button.inscr-gestion-list-remis:focus{
outline:2px solid #80bdff;
outline-offset:2px;
}
button.inscr-gestion-list-remis:hover{
filter:brightness(0.97);
}
.inscr-gestion-bib-pill{
display:inline-block;
max-width:100%;
@ -4099,6 +4185,9 @@ a.ms1-trad-link.btn-aide-trad{
}
.inscr-gestion-list-item__arrow{
display:inline-flex;
align-items:center;
justify-content:center;
color:#8aa8d4;
flex-shrink:0;
justify-self:end;
@ -4116,6 +4205,16 @@ a.ms1-trad-link.btn-aide-trad{
1.15rem;
}
.inscr-gestion-list--can-edit-bib{
--ig-list-cols:
minmax(8.5rem, 1.2fr)
minmax(10rem, 2fr)
minmax(6rem, 8rem)
minmax(4.75rem, 6.5rem)
2.5rem
1.15rem;
}
.inscr-gestion-list-cols__order,
.inscr-gestion-list-item__order{
display:none;
@ -4832,7 +4931,7 @@ a.ms1-trad-link.btn-aide-trad{
border-radius:0;
}
.inscr-gestion-list > a.inscr-gestion-list-item:nth-of-type(even){
.inscr-gestion-list > .inscr-gestion-list-item:nth-child(odd){
background:#f7faff;
}

View File

@ -54,6 +54,109 @@
var $preloader = $('#preloader');
var $preloader_text = $('#preloader_text');
// MSIN-4448 — Remis inline liste (meme endpoint / confirmation que la fiche ; UI pastille).
(function () {
var remisOp = cfg.remisOperator || {};
var remisTable = (typeof window.btoa === 'function')
? window.btoa('resultats_participants')
: '';
function applyListRemisUi($btn, remisYes) {
$btn.toggleClass('inscr-gestion-remis--yes', remisYes);
$btn.toggleClass('inscr-gestion-remis--no', !remisYes);
$btn.attr('aria-pressed', remisYes ? 'true' : 'false');
$btn.data('valeur', remisYes ? 0 : 1);
if (remisYes) {
$btn.html('<i class="fa fa-check-circle" aria-hidden="true"></i>');
} else {
$btn.empty();
}
}
function doListRemis($btn) {
var intId = parseInt($btn.data('id'), 10) || 0;
var intValeur = parseInt($btn.data('valeur'), 10);
if (intId <= 0 || (intValeur !== 0 && intValeur !== 1)) {
return;
}
$preloader_text.html(cfg.preloaderWait || '');
$preloader.show();
$.post((cfg.domain || '') + '/superadm/enregistrer.php', {
action: 'remis',
table: remisTable,
field: 'no_bib_remis',
key: 'par_id',
valeur: intValeur,
id: intId,
par_id: remisOp.par_id || 0,
par: remisOp.par || ''
}, function (result) {
$preloader.fadeOut();
if (fxInscrRedirectIfSessionExpired(result)) {
return;
}
if (result && result.state === 'success') {
applyListRemisUi($btn, intValeur === 1);
} else {
window.alert((result && (result.message || result.state)) || t('errNetwork') || 'Error');
}
}, 'json').fail(function () {
$preloader.fadeOut();
window.alert(t('errNetwork') || 'Error');
});
}
$body.on('click', '.inscr-gestion-list-remis', function (event) {
event.preventDefault();
event.stopPropagation();
var $btn = $(this);
var intValeur = parseInt($btn.data('valeur'), 10);
// Retrait (valeur 0) : confirmation — meme garde-fou que la fiche.
if (intValeur === 0) {
if (typeof window.bootbox === 'undefined') {
if (window.confirm(t('remisConfirmMsg'))) {
doListRemis($btn);
}
return;
}
window.bootbox.confirm({
title: t('remisConfirmTitle') || 'Confirmation',
message: t('remisConfirmMsg'),
buttons: {
confirm: {
label: t('remisConfirmOk') || 'OK',
className: 'btn btn-danger rounded-0'
},
cancel: {
label: t('remisConfirmCancel') || 'Cancel',
className: 'btn btn-secondary rounded-0'
}
},
callback: function (ok) {
if (ok === true) {
doListRemis($btn);
}
}
});
return;
}
doListRemis($btn);
});
// Valider le dossard inline avec Entree (declenche le .btn_bib legacy).
$body.on('keydown', '.inscr-gestion-list-bib-input', function (event) {
if (event.which !== 13 && event.key !== 'Enter') {
return;
}
event.preventDefault();
$(this).closest('.inscr-gestion-list-bib-edit').find('.btn_bib').trigger('click');
});
})();
(function () {
var pendingStatutXhr = null;
var lastStatutParId = null;

View File

@ -484,6 +484,14 @@ function fxInscrGestionFallbackTexte($strClef, $strLangue) {
// MSIN-4399 — Colonne statut de course (entre dossard et remis).
'inscr_gestion_col_statut' => $blnFr ? 'Statut' : 'Status',
'inscr_gestion_col_remis' => $blnFr ? 'Remis' : 'Issued',
// MSIN-4448 — Edition inline liste (OK dossard + confirmation remis).
'inscr_gestion_bib_ok' => 'OK',
'inscr_gestion_remis_confirm_title' => $blnFr ? 'Confirmation' : 'Confirmation',
'inscr_gestion_remis_confirm_msg' => $blnFr
? 'Êtes-vous certain de vouloir retirer la mention « dossard récupéré » pour ce participant ?'
: 'Are you sure you want to remove the "bib retrieved" status for this participant?',
'inscr_gestion_remis_confirm_ok' => $blnFr ? 'Retirer' : 'Remove',
'inscr_gestion_remis_confirm_cancel' => $blnFr ? 'Annuler' : 'Cancel',
// MSIN-4328 — bouton superadmin vers fiche ChronoTrack
'inscr_gestion_btn_chronotrack' => $blnFr ? 'Voir dans ChronoTrack' : 'View in ChronoTrack',
'inscr_gestion_list_count_one' => $blnFr ? '%d inscription' : '%d registration',
@ -2057,7 +2065,19 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
echo '</div>';
if ($intNbTotal > 0) {
echo '<div class="inscr-gestion-list">';
// MSIN-4448 — Edition inline dossard / remis selon droits granulaires (sans camera).
$intComId = intval($_SESSION['com_id'] ?? 0);
$blnCanBib = fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.bib_edit');
$blnCanRemis = fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.bib_remis');
$strListClass = 'inscr-gestion-list';
if ($blnCanBib) {
$strListClass .= ' inscr-gestion-list--can-edit-bib';
}
if ($blnCanRemis) {
$strListClass .= ' inscr-gestion-list--can-edit-remis';
}
echo '<div class="' . $strListClass . '">';
// En-tete de colonnes (memes colonnes que les lignes ; masque en vue cellulaire).
// aria-hidden : purement visuel — libellés Info (pas de FR/EN en dur).
@ -2078,12 +2098,16 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
echo '<span class="inscr-gestion-list-cols__arrow"></span>';
echo '</div>';
$strRemisLabel = fxInscrGestionT('promoteur_bib_enregistre');
$strBibOkLabel = fxInscrGestionT('inscr_gestion_bib_ok');
for ($j = $intStart; $j <= $intEnd; $j++) {
$row = $tabRows[$j];
$strFicheUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array(
'pec_id' => (int)$row['pec_id_original'],
'pg' => $intPage,
));
$strFicheHref = fxInscrGestionEsc($strFicheUrl);
$strBib = fxInscrGestionBibDisplay($row);
$strName = fxUnescape($row['par_nom']) . ', ' . fxUnescape($row['par_prenom']);
@ -2105,30 +2129,70 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
. fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_statut_' . $strCause)) . '</span>';
}
$strRemisLabel = fxInscrGestionT('promoteur_bib_enregistre');
$blnRemis = (intval($row['no_bib_remis']) === 1);
$intParId = (int)$row['par_id'];
$blnEquipe = (intval($row['pec_equipe']) === 1);
// MSIN-4448 — Ligne en div : cellules nav (lien) vs dossard/remis editables.
echo '<div class="' . $strCardClass . '">';
echo '<a class="inscr-gestion-list-item__name" href="' . $strFicheHref . '">'
. fxInscrGestionEsc($strName) . $strCancelBadge . '</a>';
echo '<a class="inscr-gestion-list-item__race" href="' . $strFicheHref . '" title="'
. fxInscrGestionEsc($strRace) . '">' . fxInscrGestionEsc($strRace) . '</a>';
echo '<a class="inscr-gestion-list-item__order" href="' . $strFicheHref . '">'
. fxInscrGestionEsc($row['no_commande']) . '</a>';
echo '<a class="' . $strCardClass . '" href="' . fxInscrGestionEsc($strFicheUrl) . '">';
echo '<span class="inscr-gestion-list-item__name">' . fxInscrGestionEsc($strName) . $strCancelBadge . '</span>';
echo '<span class="inscr-gestion-list-item__race" title="' . fxInscrGestionEsc($strRace) . '">'
. fxInscrGestionEsc($strRace) . '</span>';
echo '<span class="inscr-gestion-list-item__order">' . fxInscrGestionEsc($row['no_commande']) . '</span>';
echo '<span class="inscr-gestion-list-item__bib">';
if (trim($strBib) !== '') {
if ($blnCanBib) {
// Meme ids / classes que la fiche → handlers footer (doublon + ajax_promoteur).
$strBibAction = $blnEquipe ? 'no_equipe' : 'no_bib';
$strBibInputId = ($blnEquipe ? 'txt_no_bib_e' : 'txt_no_bib_p') . $intParId;
echo '<div class="inscr-gestion-list-bib-edit">';
echo '<input class="form-control form-control-sm rounded-0 inscr-gestion-list-bib-input" type="text"'
. ' id="' . fxInscrGestionEsc($strBibInputId) . '"'
. ' value="' . fxInscrGestionEsc($strBib) . '"'
. ' maxlength="6" autocomplete="off"'
. ' aria-label="' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_col_dossard')) . '">';
echo '<button class="btn btn-primary btn-sm rounded-0 btn_bib" type="button"'
. ' data-action="' . fxInscrGestionEsc($strBibAction) . '"'
. ' data-eve_id="' . rawurlencode(base64_encode((string)$row['eve_id'])) . '"'
. ' data-epr_id="' . (int)$row['epr_id'] . '"'
. ' data-par_id="' . $intParId . '"'
. ' data-pec_id="' . (int)$row['pec_id_original'] . '"'
. ' title="' . fxInscrGestionEsc($strBibOkLabel) . '"'
. ' aria-label="' . fxInscrGestionEsc($strBibOkLabel) . '">OK</button>';
echo '</div>';
} elseif (trim($strBib) !== '') {
echo '<span class="inscr-gestion-bib-pill">' . fxInscrGestionEsc($strBib) . '</span>';
} else {
echo '<span class="inscr-gestion-bib-pill inscr-gestion-bib-pill--empty">—</span>';
}
echo '</span>';
// MSIN-4399 — Affichage lecture seule (édition sur la fiche).
// MSIN-4399 — Statut de course en lecture seule dans la liste (edition sur la fiche).
$strStatutMod = preg_replace('/[^A-Za-z0-9_-]/', '', strtolower($strStatutCode));
echo '<span class="inscr-gestion-list-item__statut">';
echo '<a class="inscr-gestion-list-item__statut" href="' . $strFicheHref . '">';
echo '<span class="inscr-gestion-statut-pill inscr-gestion-statut-pill--' . fxInscrGestionEsc($strStatutMod) . '"'
. ' title="' . fxInscrGestionEsc($strStatutLabel) . '">'
. fxInscrGestionEsc($strStatutLabel) . '</span>';
echo '</span>';
echo '</a>';
echo '<span class="inscr-gestion-list-item__check">';
if ($blnRemis) {
if ($blnCanRemis) {
$intRemisVal = $blnRemis ? 0 : 1;
$strRemisMod = $blnRemis ? 'yes' : 'no';
echo '<button type="button" class="inscr-gestion-remis inscr-gestion-remis--'
. $strRemisMod . ' inscr-gestion-list-remis"'
. ' data-id="' . $intParId . '"'
. ' data-valeur="' . $intRemisVal . '"'
. ' title="' . fxInscrGestionEsc($strRemisLabel) . '"'
. ' aria-label="' . fxInscrGestionEsc($strRemisLabel) . '"'
. ' aria-pressed="' . ($blnRemis ? 'true' : 'false') . '">';
if ($blnRemis) {
echo '<i class="fa fa-check-circle" aria-hidden="true"></i>';
}
echo '</button>';
} elseif ($blnRemis) {
echo '<span class="inscr-gestion-remis inscr-gestion-remis--yes" title="'
. fxInscrGestionEsc($strRemisLabel) . '">';
echo '<i class="fa fa-check-circle" aria-hidden="true"></i>';
@ -2138,8 +2202,11 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) {
echo '<span class="inscr-gestion-remis inscr-gestion-remis--no" aria-hidden="true"></span>';
}
echo '</span>';
echo '<i class="fa fa-chevron-right inscr-gestion-list-item__arrow" aria-hidden="true"></i>';
echo '</a>';
echo '<a class="inscr-gestion-list-item__arrow" href="' . $strFicheHref . '"'
. ' aria-label="' . fxInscrGestionEsc($strName) . '">'
. '<i class="fa fa-chevron-right" aria-hidden="true"></i></a>';
echo '</div>';
}
echo '</div>';

View File

@ -7,8 +7,8 @@
* Constantes *
*
**************/
define('_VERSION_CODE', '4.72.823');
define('_DATE_CODE', '2026-07-14');
define('_VERSION_CODE', '4.72.824');
define('_DATE_CODE', '2026-07-15');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');

View File

@ -114,7 +114,21 @@ if (!function_exists('fxV2RegisterScript')) {
'bibScanCamera' => function_exists('fxInscrGestionScanLabel')
? fxInscrGestionScanLabel('inscr_gestion_qr_camera_error')
: '',
// MSIN-4448 — Remis inline liste (confirmation retrait).
'remisConfirmTitle' => fxInscrGestionT('inscr_gestion_remis_confirm_title'),
'remisConfirmMsg' => fxInscrGestionT('inscr_gestion_remis_confirm_msg'),
'remisConfirmOk' => fxInscrGestionT('inscr_gestion_remis_confirm_ok'),
'remisConfirmCancel' => fxInscrGestionT('inscr_gestion_remis_confirm_cancel'),
] : [],
// MSIN-4448 — Operateur pour no_bib_remis_par (chemin superadm / usa_id).
'remisOperator' => [
'par_id' => intval($_SESSION['com_info']['com_id'] ?? ($_SESSION['com_id'] ?? 0)),
'par' => trim(
(string)($_SESSION['com_info']['com_prenom'] ?? '')
. ' '
. (string)($_SESSION['com_info']['com_nom'] ?? '')
),
],
];
}

View File

@ -0,0 +1,48 @@
-- MSIN-4448 — Edition inline dossard / remis dans la liste + libelles droits / Info
-- Prefrequis : permissions inscriptions_gestion.bib_edit / bib_remis (phase 2 acces v2)
-- Idempotent (UPDATE permissions + DELETE/INSERT info)
/* ------------------------------------------------------------------
1. Clarifier les droits kits : lecture seule = sans la case ;
lecture-ecriture = case cochee (liste + fiche).
------------------------------------------------------------------ */
UPDATE `inscriptions_eve_permissions`
SET
`perm_label_fr` = 'Gestion inscription : no dossard (liste + fiche)',
`perm_label_en` = 'Registration mgmt: bib number (list + sheet)',
`perm_description_fr` = 'Modifier le numero de dossard dans la liste et sur la fiche (lecture seule si non coche)',
`perm_description_en` = 'Edit bib number in the list and on the sheet (read-only if unchecked)'
WHERE `perm_key` = 'inscriptions_gestion.bib_edit';
UPDATE `inscriptions_eve_permissions`
SET
`perm_label_fr` = 'Gestion inscription : dossard remis (liste + fiche)',
`perm_label_en` = 'Registration mgmt: bib handed out (list + sheet)',
`perm_description_fr` = 'Marquer dossard remis dans la liste et sur la fiche (lecture seule si non coche)',
`perm_description_en` = 'Mark bib handed out in the list and on the sheet (read-only if unchecked)'
WHERE `perm_key` = 'inscriptions_gestion.bib_remis';
/* ------------------------------------------------------------------
2. Libelles Info (confirmation remis + OK)
------------------------------------------------------------------ */
DELETE FROM info
WHERE info_prg = 'compte.php'
AND info_clef IN (
'inscr_gestion_bib_ok',
'inscr_gestion_remis_confirm_title',
'inscr_gestion_remis_confirm_msg',
'inscr_gestion_remis_confirm_ok',
'inscr_gestion_remis_confirm_cancel'
);
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) VALUES
('inscr_gestion_bib_ok', 'fr', 'OK', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_bib_ok', 'en', 'OK', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_title', 'fr', 'Confirmation', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_title', 'en', 'Confirmation', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_msg', 'fr', 'Êtes-vous certain de vouloir retirer la mention « dossard récupéré » pour ce participant ?', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_msg', 'en', 'Are you sure you want to remove the "bib retrieved" status for this participant?', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_ok', 'fr', 'Retirer', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_ok', 'en', 'Remove', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_cancel', 'fr', 'Annuler', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW()),
('inscr_gestion_remis_confirm_cancel', 'en', 'Cancel', '', 'compte.php', 'MSIN-4448', 0, 1, '', '', '', NOW());