Implement contextual return functionality for bib management and enhance UI interactions
This commit introduces several enhancements related to the bib management system, specifically focusing on contextual return paths from various panels. New functions are added to encode and decode return URLs, allowing users to navigate back to specific sections (e.g., anomalies, quantity summary) seamlessly. Additionally, JavaScript functions are updated to manage UI interactions, such as expanding panels based on URL parameters. The overall user experience is improved by ensuring that the correct panels are focused and displayed upon return. This change is part of the ongoing efforts to enhance the bib assignment management system (MSIN-4436).
This commit is contained in:
@ -1072,19 +1072,84 @@
|
||||
return row.querySelectorAll('.batch-select-range:checked').length;
|
||||
}
|
||||
|
||||
/** MSIN-4436 — Développe un bloc repliable #module-bib. */
|
||||
function bibExpandBlock(block) {
|
||||
if (!block || !block.classList.contains('is-collapsed')) {
|
||||
return;
|
||||
}
|
||||
|
||||
block.classList.remove('is-collapsed');
|
||||
let btn = block.querySelector('.epr-block-toggle');
|
||||
if (btn) {
|
||||
btn.setAttribute('aria-expanded', 'true');
|
||||
let label = btn.getAttribute('data-label-collapse') || '';
|
||||
if (label) {
|
||||
btn.setAttribute('aria-label', label);
|
||||
btn.setAttribute('title', label);
|
||||
}
|
||||
let icon = btn.querySelector('.fa');
|
||||
if (icon) {
|
||||
icon.classList.add('fa-chevron-up');
|
||||
icon.classList.remove('fa-chevron-down');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bibFocusApplied = false;
|
||||
|
||||
/** MSIN-4436 — Retour depuis fiche inscription : rouvrir le panneau ciblé. */
|
||||
function bibApplyFocusFromUrlOnce() {
|
||||
if (bibFocusApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
let focus = new URLSearchParams(window.location.search).get('bib_focus');
|
||||
if (!focus) {
|
||||
return;
|
||||
}
|
||||
|
||||
bibFocusApplied = true;
|
||||
|
||||
let panelId = null;
|
||||
if (focus === 'anomalies') {
|
||||
panelId = 'bib-anomalies-panel';
|
||||
} else if (focus === 'qty_summary') {
|
||||
panelId = 'bib-qty-summary-panel';
|
||||
} else if (focus === 'event_config') {
|
||||
panelId = 'bib-event-config-panel';
|
||||
}
|
||||
|
||||
if (!panelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let panel = document.getElementById(panelId);
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
bibExpandBlock(panel);
|
||||
|
||||
if (focus === 'qty_summary' && panel.getAttribute('data-bib-qty-summary-deferred') === '1') {
|
||||
refreshBibQtySummaryPanel();
|
||||
}
|
||||
|
||||
panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
|
||||
/** MSIN-4379 — Rafraîchit le dashboard anomalies (chien de garde). */
|
||||
function refreshBibAnomaliesPanel() {
|
||||
let mount = document.getElementById('bib-anomalies-mount');
|
||||
if (!mount || !moduleBib) {
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let eveId = moduleBib.dataset.eveId || '';
|
||||
if (!eveId) {
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
bibFetch('/ajax_bib_range.php', {
|
||||
return bibFetch('/ajax_bib_range.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
@ -2868,7 +2933,11 @@
|
||||
|
||||
// MSIN-4436 — Anomalies : coquille légère au chargement, détail en AJAX.
|
||||
if (document.querySelector('#bib-anomalies-panel[data-bib-anomalies-deferred="1"]')) {
|
||||
refreshBibAnomaliesPanel();
|
||||
refreshBibAnomaliesPanel().then(function () {
|
||||
bibApplyFocusFromUrlOnce();
|
||||
});
|
||||
} else {
|
||||
bibApplyFocusFromUrlOnce();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@ -7,6 +7,9 @@
|
||||
* - Promoteur : /compte/inc_tableau_inscriptions_gestion → retour inc_tableau_promoteur
|
||||
* - Acces v2 seul : /mobile → retour /mobile ou Mon compte
|
||||
*
|
||||
* MSIN-4436 — Parametre inscr_return (URL interne encodee) : retour contextuel depuis la fiche
|
||||
* (ex. panneau anomalies dossards) au lieu de la liste des inscriptions.
|
||||
*
|
||||
* Droits : v2 uniquement (fxInscrGestionCanAccess). i18n : toujours info_prg compte.php.
|
||||
*/
|
||||
|
||||
@ -148,6 +151,85 @@ function fxInscrGestionBaseUrl($strLangue, $blnMobileEntry = null) {
|
||||
return $vDomaine . ($strLangue === 'fr' ? '/compte/inc_tableau_inscriptions_gestion' : '/account/inc_tableau_inscriptions_gestion');
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4436 — Encode une URL interne relative (/compte/... ou /account/...) pour inscr_return.
|
||||
*/
|
||||
function fxInscrGestionEncodeReturnUrl($strRelativePath) {
|
||||
$strRelativePath = trim((string)$strRelativePath);
|
||||
if ($strRelativePath === '' || $strRelativePath[0] !== '/') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return rtrim(strtr(base64_encode($strRelativePath), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4436 — Décode inscr_return ; retourne le chemin relatif validé ou ''.
|
||||
*/
|
||||
function fxInscrGestionDecodeReturnPath($strToken) {
|
||||
$strToken = trim((string)$strToken);
|
||||
if ($strToken === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$strB64 = strtr($strToken, '-_', '+/');
|
||||
$intPad = strlen($strB64) % 4;
|
||||
if ($intPad > 0) {
|
||||
$strB64 .= str_repeat('=', 4 - $intPad);
|
||||
}
|
||||
|
||||
$strPath = base64_decode($strB64, true);
|
||||
if ($strPath === false || $strPath === '' || $strPath[0] !== '/') {
|
||||
return '';
|
||||
}
|
||||
if (preg_match('#^https?://#i', $strPath)) {
|
||||
return '';
|
||||
}
|
||||
if (!preg_match('#^/(compte|account)/#', $strPath)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $strPath;
|
||||
}
|
||||
|
||||
/** MSIN-4436 — URL absolue de retour depuis inscr_return, ou '' si invalide. */
|
||||
function fxInscrGestionDecodeReturnUrl($strToken) {
|
||||
global $vDomaine;
|
||||
|
||||
$strPath = fxInscrGestionDecodeReturnPath($strToken);
|
||||
if ($strPath === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $vDomaine . $strPath;
|
||||
}
|
||||
|
||||
/** MSIN-4436 — Bouton retour fiche : URL externe (inscr_return) ou liste filtrée. */
|
||||
function fxInscrGestionResolveBackUrl($strBaseUrl, $intEveId, $arrReq) {
|
||||
if (!empty($arrReq['inscr_return'])) {
|
||||
$strReturn = fxInscrGestionDecodeReturnUrl($arrReq['inscr_return']);
|
||||
if ($strReturn !== '') {
|
||||
return $strReturn;
|
||||
}
|
||||
}
|
||||
|
||||
return fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null, 'pg' => $arrReq['pg']));
|
||||
}
|
||||
|
||||
/** MSIN-4436 — Libellé du bouton retour selon le contexte d'origine. */
|
||||
function fxInscrGestionResolveBackLabel($arrReq, $strLangue = 'fr') {
|
||||
if (!empty($arrReq['inscr_return'])) {
|
||||
$strPath = fxInscrGestionDecodeReturnPath($arrReq['inscr_return']);
|
||||
if ($strPath !== '' && strpos($strPath, 'inc_tableau_gestion_epreuves') !== false) {
|
||||
return fxInscrGestionT('inscr_gestion_back_bib');
|
||||
}
|
||||
|
||||
return fxInscrGestionT('inscr_gestion_back_prev');
|
||||
}
|
||||
|
||||
return fxInscrGestionT('inscr_gestion_back_list');
|
||||
}
|
||||
|
||||
function fxInscrGestionEsc($str) {
|
||||
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
@ -284,6 +366,8 @@ function fxInscrGestionFallbackTexte($strClef, $strLangue) {
|
||||
'inscr_gestion_statut_annule' => $blnFr ? 'Annulée' : 'Cancelled',
|
||||
'inscr_gestion_statut_transfert' => $blnFr ? 'Transférée' : 'Transferred',
|
||||
'inscr_gestion_statut_modif' => $blnFr ? 'Modifiée (changement d\'épreuve)' : 'Modified (race change)',
|
||||
'inscr_gestion_back_bib' => $blnFr ? 'Retour aux dossards' : 'Back to bibs',
|
||||
'inscr_gestion_back_prev' => $blnFr ? 'Retour' : 'Back',
|
||||
);
|
||||
}
|
||||
|
||||
@ -471,6 +555,8 @@ function fxInscrGestionParseRequest() {
|
||||
'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,
|
||||
// MSIN-4436 — Page d'origine (ex. gestion dossards) pour le bouton retour de la fiche.
|
||||
'inscr_return' => isset($_GET['inscr_return']) ? trim((string)$_GET['inscr_return']) : '',
|
||||
// q = 1 lorsque l'utilisateur a lance une recherche/filtre. La liste reste vide tant que q = 0.
|
||||
'q' => 0,
|
||||
);
|
||||
@ -519,6 +605,7 @@ function fxInscrGestionEmptyListRequest() {
|
||||
'sel_rech_epreuve' => 0,
|
||||
'pg' => 1,
|
||||
'pec_id' => 0,
|
||||
'inscr_return' => '',
|
||||
'q' => 0,
|
||||
);
|
||||
}
|
||||
@ -990,6 +1077,9 @@ function fxInscrGestionQueryParams($intEveId, $arrReq, $arrExtra = array()) {
|
||||
if (!empty($arrReq['pg']) && (int)$arrReq['pg'] > 1) {
|
||||
$tab['pg'] = (int)$arrReq['pg'];
|
||||
}
|
||||
if (!empty($arrReq['inscr_return'])) {
|
||||
$tab['inscr_return'] = $arrReq['inscr_return'];
|
||||
}
|
||||
|
||||
foreach ($arrExtra as $strKey => $mixVal) {
|
||||
if ($mixVal === null || $mixVal === '' || ($strKey === 'pec_id' && (int)$mixVal === 0)) {
|
||||
@ -1473,7 +1563,7 @@ function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq,
|
||||
$blnHasGestion = ($blnCanEdit || $blnCanCancel || $blnCanRestore || $blnCanRefund);
|
||||
$blnInspect = function_exists('fxAdminPermInspectModeActive') && fxAdminPermInspectModeActive();
|
||||
|
||||
$strListUrl = fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null, 'pg' => $arrReq['pg']));
|
||||
$strBackUrl = fxInscrGestionResolveBackUrl($strBaseUrl, $intEveId, $arrReq);
|
||||
$strEveCode = fxGetEvenementsUrl($arrRow['eve_id']);
|
||||
$strBib = fxInscrGestionBibDisplay($arrRow);
|
||||
$intParId = $arrRow['par_id'];
|
||||
@ -1499,7 +1589,7 @@ function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq,
|
||||
}
|
||||
echo '>';
|
||||
|
||||
fxInscrGestionRenderNavBack($strListUrl, fxInscrGestionT('inscr_gestion_back_list'));
|
||||
fxInscrGestionRenderNavBack($strBackUrl, fxInscrGestionResolveBackLabel($arrReq, $strLangue));
|
||||
echo '<div class="inscr-gestion-fiche-head">';
|
||||
echo '<h1 class="inscr-gestion-page-title">' . fxInscrGestionEsc(fxUnescape($arrRow['par_nom']) . ', ' . fxUnescape($arrRow['par_prenom'])) . '</h1>';
|
||||
echo '</div>';
|
||||
@ -1701,8 +1791,8 @@ function fxInscrGestionRun($intEveId, $strLangue) {
|
||||
$arrRow = fxInscrGestionFetchRowByPec($arrReq['pec_id'], $intEveId);
|
||||
if ($arrRow === null) {
|
||||
echo '<div class="alert alert-danger">' . fxInscrGestionEsc(fxInscrGestionT('txt_recherche_no_result')) . '</div>';
|
||||
echo '<a class="btn btn-primary rounded-0" href="' . fxInscrGestionEsc(fxInscrGestionBuildUrl($strBaseUrl, $intEveId, $arrReq, array('pec_id' => null))) . '">';
|
||||
echo fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_back_list')) . '</a>';
|
||||
echo '<a class="btn btn-primary rounded-0" href="' . fxInscrGestionEsc(fxInscrGestionResolveBackUrl($strBaseUrl, $intEveId, $arrReq)) . '">';
|
||||
echo fxInscrGestionEsc(fxInscrGestionResolveBackLabel($arrReq, $strLangue)) . '</a>';
|
||||
return;
|
||||
}
|
||||
fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq, $arrRow);
|
||||
|
||||
@ -5795,6 +5795,25 @@ function renderBibQtySummaryPanel($int_eve_id, $strLangue = 'fr', $tabSummary =
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4436 — Chemin relatif de retour vers la page gestion dossards (avec focus optionnel).
|
||||
*/
|
||||
function fxBibGestionEpreuvesReturnPath($int_eve_id, $strLangue = 'fr', $strFocus = '') {
|
||||
$strBase = ($strLangue === 'fr')
|
||||
? '/compte/inc_tableau_gestion_epreuves'
|
||||
: '/account/inc_tableau_gestion_epreuves';
|
||||
|
||||
$strPath = $strBase
|
||||
. '?promoteur_eve_id=' . rawurlencode(base64_encode((string)(int)$int_eve_id))
|
||||
. '&lng=' . rawurlencode($strLangue);
|
||||
|
||||
if ($strFocus !== '') {
|
||||
$strPath .= '&bib_focus=' . rawurlencode($strFocus);
|
||||
}
|
||||
|
||||
return $strPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4436 — URL fiche gestion inscriptions v2 pour une anomalie dossard.
|
||||
* Réutilise fxInscrGestionBuildUrl (même lien que la liste des inscriptions).
|
||||
@ -5816,6 +5835,10 @@ function fxBibAnomalyInscrGestionUrl($int_eve_id, $int_pec_id, $strLangue = 'fr'
|
||||
return '';
|
||||
}
|
||||
|
||||
$strReturn = fxInscrGestionEncodeReturnUrl(
|
||||
fxBibGestionEpreuvesReturnPath($int_eve_id, $strLangue, 'anomalies')
|
||||
);
|
||||
|
||||
return fxInscrGestionBuildUrl(
|
||||
fxInscrGestionBaseUrl($strLangue, false),
|
||||
$int_eve_id,
|
||||
@ -5823,6 +5846,7 @@ function fxBibAnomalyInscrGestionUrl($int_eve_id, $int_pec_id, $strLangue = 'fr'
|
||||
[
|
||||
'pec_id' => $int_pec_id,
|
||||
'lng' => $strLangue,
|
||||
'inscr_return' => $strReturn,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
18
sql/MSIN-4436-inscr-gestion-return.sql
Normal file
18
sql/MSIN-4436-inscr-gestion-return.sql
Normal file
@ -0,0 +1,18 @@
|
||||
-- MSIN-4436 — Retour contextuel fiche gestion inscriptions (ex. depuis anomalies dossards)
|
||||
-- Idempotent
|
||||
|
||||
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)
|
||||
SELECT 'inscr_gestion_back_bib', 'fr', 'Retour aux dossards', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'inscr_gestion_back_bib' AND info_langue = 'fr' AND info_prg = 'compte.php');
|
||||
|
||||
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)
|
||||
SELECT 'inscr_gestion_back_bib', 'en', 'Back to bibs', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'inscr_gestion_back_bib' AND info_langue = 'en' AND info_prg = 'compte.php');
|
||||
|
||||
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)
|
||||
SELECT 'inscr_gestion_back_prev', 'fr', 'Retour', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'inscr_gestion_back_prev' AND info_langue = 'fr' AND info_prg = 'compte.php');
|
||||
|
||||
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)
|
||||
SELECT 'inscr_gestion_back_prev', 'en', 'Back', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'inscr_gestion_back_prev' AND info_langue = 'en' AND info_prg = 'compte.php');
|
||||
Reference in New Issue
Block a user