From 0e42cc45d13e49403ed5b1a6d7d5fa8e89c5018d Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 15 Jul 2026 08:52:27 -0400 Subject: [PATCH] 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. --- css/style.css | 109 +++++++++++++++++- js/v2/inscr-gestion.js | 103 +++++++++++++++++ php/inc_fx_inscriptions_gestion.php | 95 ++++++++++++--- php/inc_settings.php | 4 +- php/inc_v2_assets.php | 14 +++ ...48-inscr-gestion-list-inline-bib-remis.sql | 48 ++++++++ 6 files changed, 352 insertions(+), 21 deletions(-) create mode 100644 sql/MSIN-4448-inscr-gestion-list-inline-bib-remis.sql diff --git a/css/style.css b/css/style.css index dc0e570..7d4a94b 100644 --- a/css/style.css +++ b/css/style.css @@ -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; } diff --git a/js/v2/inscr-gestion.js b/js/v2/inscr-gestion.js index cb01d1c..d9af67c 100644 --- a/js/v2/inscr-gestion.js +++ b/js/v2/inscr-gestion.js @@ -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(''); + } 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; diff --git a/php/inc_fx_inscriptions_gestion.php b/php/inc_fx_inscriptions_gestion.php index 8a55af5..50ea99e 100644 --- a/php/inc_fx_inscriptions_gestion.php +++ b/php/inc_fx_inscriptions_gestion.php @@ -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 ''; if ($intNbTotal > 0) { - echo '
'; + // 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 '
'; // 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 ''; echo '
'; + $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)) . ''; } - $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 '
'; + echo '' + . fxInscrGestionEsc($strName) . $strCancelBadge . ''; + echo '' . fxInscrGestionEsc($strRace) . ''; + echo '' + . fxInscrGestionEsc($row['no_commande']) . ''; - echo ''; - echo '' . fxInscrGestionEsc($strName) . $strCancelBadge . ''; - echo '' - . fxInscrGestionEsc($strRace) . ''; - echo '' . fxInscrGestionEsc($row['no_commande']) . ''; echo ''; - 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 '
'; + echo ''; + echo ''; + echo '
'; + } elseif (trim($strBib) !== '') { echo '' . fxInscrGestionEsc($strBib) . ''; } else { echo ''; } echo '
'; - // 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 ''; + echo '
'; echo '' . fxInscrGestionEsc($strStatutLabel) . ''; - echo ''; + echo ''; + echo ''; - if ($blnRemis) { + if ($blnCanRemis) { + $intRemisVal = $blnRemis ? 0 : 1; + $strRemisMod = $blnRemis ? 'yes' : 'no'; + echo ''; + } elseif ($blnRemis) { echo ''; echo ''; @@ -2138,8 +2202,11 @@ function fxInscrGestionRenderList($intEveId, $strLangue, $strBaseUrl, $arrReq) { echo ''; } echo ''; - echo ''; - echo ''; + + echo '' + . ''; + echo '
'; } echo '
'; diff --git a/php/inc_settings.php b/php/inc_settings.php index b219fd5..5cfc3b6 100644 --- a/php/inc_settings.php +++ b/php/inc_settings.php @@ -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'); diff --git a/php/inc_v2_assets.php b/php/inc_v2_assets.php index c96d005..0a710bb 100644 --- a/php/inc_v2_assets.php +++ b/php/inc_v2_assets.php @@ -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'] ?? '') + ), + ], ]; } diff --git a/sql/MSIN-4448-inscr-gestion-list-inline-bib-remis.sql b/sql/MSIN-4448-inscr-gestion-list-inline-bib-remis.sql new file mode 100644 index 0000000..b9d2492 --- /dev/null +++ b/sql/MSIN-4448-inscr-gestion-list-inline-bib-remis.sql @@ -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());