Refactor ChronoTrack API push panel to enhance user experience with clearer status messages and improved layout. Update button actions and add collapsible details section for better visibility of synchronization results. This change aims to streamline participant data management and provide more intuitive feedback during the push process.

This commit is contained in:
2026-07-14 11:53:07 -04:00
parent 7ce5dd0941
commit 71e57d6eb1

View File

@ -246,24 +246,42 @@ function fxChronotrackApiAdminRenderRaceMapping($intEveId, $arrConfig, $strLangu
function fxChronotrackApiAdminRenderPushPanel($intEveId, $blnClosed = false) {
echo '<div class="card mb-4 border-primary" id="ct_api_push_card">';
echo '<div class="card-header">Synchronisation manuelle (participants)</div>';
echo '<div class="card-header">Synchronisation ChronoTrack</div>';
echo '<div class="card-body">';
if ($blnClosed) {
echo '<div class="alert alert-warning py-2 small mb-2">Événement fermé — push manuel autorisé pour tests ou rattrapage.</div>';
echo '<div class="alert alert-warning py-2 small mb-2">Événement fermé — envoi manuel encore possible.</div>';
}
echo '<p class="small text-muted mb-2">Push <strong>différentiel</strong> MS1 → ChronoTrack '
. '(nouveaux / modifiés depuis le dernier push OK). External ID = <code>par_id_original</code>.</p>';
echo '<div id="ct_api_push_summary" class="mb-2 text-muted small">Cliquez <strong>Actualiser</strong>.</div>';
echo '<div id="ct_api_push_blocked_wrap" class="mb-2 d-none"></div>';
echo '<div class="mb-2">';
echo '<button type="button" class="btn btn-primary btn-sm" id="ct_api_btn_push" disabled>';
echo '<i class="fa fa-cloud-upload" aria-hidden="true"></i>&nbsp;Pousser le différentiel</button> ';
echo '<button type="button" class="btn btn-outline-secondary btn-sm" id="ct_api_btn_push_refresh">';
// Zone employé : statut clair + actions dabord. MSIN-4328
echo '<div id="ct_api_push_status" class="ct-api-push-status mb-3">';
echo '<div class="text-muted small">Cliquez <strong>Actualiser</strong> pour vérifier sil y a des changements à envoyer.</div>';
echo '</div>';
echo '<div class="ct-api-push-actions mb-2">';
echo '<button type="button" class="btn btn-outline-secondary" id="ct_api_btn_push_refresh">';
echo '<i class="fa fa-refresh" aria-hidden="true"></i>&nbsp;Actualiser</button> ';
echo '<button type="button" class="btn btn-primary btn-lg" id="ct_api_btn_push" disabled>';
echo '<i class="fa fa-cloud-upload" aria-hidden="true"></i>&nbsp;Envoyer vers ChronoTrack</button>';
echo '</div>';
echo '<p class="small text-muted mb-2">La sync automatique arrivera bientôt — pour linstant, un clic suffit quand il y a du nouveau.</p>';
echo '<div id="ct_api_push_result" class="small mb-3"></div>';
// Détails / debug : sous les boutons, repliés par défaut
echo '<div class="card border-light mb-0" id="ct_api_push_details_card">';
echo '<div class="card-header py-2 bg-white">';
echo '<a class="d-block text-muted small collapsed" data-toggle="collapse" href="#ct_api_push_details_collapse" '
. 'role="button" aria-expanded="false">';
echo 'Détails &amp; exclus <span class="text-muted">(compteurs, liste à corriger)</span>';
echo '</a></div>';
echo '<div class="collapse" id="ct_api_push_details_collapse"><div class="card-body py-2">';
echo '<div id="ct_api_push_summary" class="mb-2 text-muted small"></div>';
echo '<div id="ct_api_push_blocked_wrap" class="mb-2 d-none"></div>';
echo '<button type="button" class="btn btn-outline-info btn-sm" id="ct_api_btn_ct_count">';
echo '<i class="fa fa-calculator" aria-hidden="true"></i>&nbsp;Nb ChronoTrack Live</button>';
echo '</div>';
echo '<div id="ct_api_push_result" class="small mt-2"></div>';
echo '<p class="small text-muted mt-2 mb-0">Info technique : external ID = <code>par_id_original</code>. '
. 'Le comptage Live sert aussi à lier les entry_id pour le bouton fiche.</p>';
echo '</div></div></div>';
echo '</div></div>';
}
@ -309,6 +327,32 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
#ct_api_push_summary .ct-api-dash-table td.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
#ct_api_push_summary .ct-api-dash-push { font-size: 0.85rem; margin-bottom: 0; }
#ct_api_config_collapse .card { box-shadow: none; }
.ct-api-push-status {
padding: 12px 14px;
border-radius: 8px;
background: #f8f9fa;
border: 1px solid #e9ecef;
}
.ct-api-push-status--ok {
background: #e8f7ee;
border-color: #b7e4c7;
}
.ct-api-push-status--todo {
background: #fff8e6;
border-color: #ffe1a6;
}
.ct-api-push-status__title {
font-size: 1.15rem;
font-weight: 700;
margin: 0 0 4px;
line-height: 1.3;
}
.ct-api-push-status__hint {
margin: 0;
font-size: 0.9rem;
}
.ct-api-push-actions .btn-lg { font-size: 1.05rem; padding: 0.55rem 1.1rem; }
#ct_api_push_details_card .card-header a { text-decoration: none; }
</style>
<?php fxChronotrackApiAdminRenderLoaderAssets($vDomaine); ?>
<script>
@ -800,13 +844,20 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
function renderPushPreview(res) {
var $sum = $('#ct_api_push_summary');
var $status = $('#ct_api_push_status');
var $btn = $('#ct_api_btn_push');
objPushPreview = res;
if (!$sum.length) {
if (!$sum.length && !$status.length) {
return;
}
if (!res || res.state !== 'ok') {
$sum.html('<div class="text-danger">' + escHtml((res && res.message) ? res.message : 'Erreur') + '</div>');
if ($status.length) {
$status.removeClass('ct-api-push-status--ok ct-api-push-status--todo')
.html('<div class="text-danger">' + escHtml((res && res.message) ? res.message : 'Erreur') + '</div>');
}
if ($sum.length) {
$sum.html('');
}
$('#ct_api_push_blocked_wrap').addClass('d-none').empty();
$btn.prop('disabled', true);
return;
@ -821,6 +872,34 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
var blnFirst = !!res.is_first_push;
var strLastPush = res.last_push_at || null;
// Bannière employé (ludique / claire)
if ($status.length) {
$status.removeClass('ct-api-push-status--ok ct-api-push-status--todo');
if (intPending > 0) {
$status.addClass('ct-api-push-status--todo');
var strTodoTitle = blnFirst
? (intPending + ' à envoyer (premier envoi)')
: (intPending + ' changement' + (intPending > 1 ? 's' : '') + ' à envoyer');
$status.html(
'<p class="ct-api-push-status__title">' + escHtml(strTodoTitle) + '</p>'
+ '<p class="ct-api-push-status__hint mb-0">Cliquez <strong>Envoyer vers ChronoTrack</strong> — seuls les nouveaux / modifiés partent.</p>'
);
} else {
$status.addClass('ct-api-push-status--ok');
var strOk = 'Tout est à jour';
if (strLastPush) {
strOk += ' <span class="text-muted font-weight-normal" style="font-size:0.85rem;">· dernier envoi '
+ escHtml(strLastPush) + '</span>';
}
$status.html(
'<p class="ct-api-push-status__title text-success">' + strOk + '</p>'
+ '<p class="ct-api-push-status__hint mb-0 text-muted">'
+ intEligible + ' éligibles · rien à envoyer pour le moment.</p>'
);
}
}
// Détails (sous les boutons, zone repliable)
var html = '<table class="table table-sm table-bordered ct-api-dash-table mb-1">';
html += '<thead><tr><th>MS1</th><th class="text-right">Total</th><th class="text-right">Éligibles</th>';
html += '<th class="text-right">Exclus</th><th class="text-right">Différentiel</th></tr></thead><tbody>';
@ -836,30 +915,21 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
+ intCtLiveCount + '</strong> inscription(s) '
+ '<button type="button" class="btn btn-link btn-sm p-0 align-baseline" id="ct_api_btn_ct_count_inline">recompter</button></p>';
} else {
html += '<p class="ct-api-dash-push mb-1 text-muted">ChronoTrack Live : total non chargé '
+ '(bouton <em>Nb ChronoTrack Live</em> — optionnel).</p>';
}
if (intPending > 0) {
html += '<p class="ct-api-dash-push mb-1"><strong>À pousser :</strong> '
+ intPending + (blnFirst ? ' (premier envoi / baseline)' : ' modifié(s) depuis le dernier push')
+ '</p>';
} else {
html += '<p class="ct-api-dash-push mb-1 text-success"><strong>À jour</strong> — rien à repousser';
if (strLastPush) {
html += ' <span class="text-muted">(dernier push ' + escHtml(strLastPush) + ')</span>';
}
html += '</p>';
html += '<p class="ct-api-dash-push mb-1 text-muted">ChronoTrack Live : total non chargé (bouton ci-dessous).</p>';
}
$sum.html(html);
renderBlockedPanel(res);
$btn.prop('disabled', intPending <= 0);
// Ouvre les détails seulement sil y a des exclus à corriger
if (intBlocked > 0) {
$('#ct_api_push_details_collapse').collapse('show');
}
}
function renderPushResult(res, strTitle) {
var $res = $('#ct_api_push_result');
var strHeading = strTitle || 'Résultat du push';
var strHeading = strTitle || 'Résultat';
var strClass = 'text-danger';
if (res && res.state === 'warning') {
strClass = 'text-warning';
@ -881,7 +951,8 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
function loadPushPreview(blnForce) {
var $sum = $('#ct_api_push_summary');
if (!$sum.length) {
var $status = $('#ct_api_push_status');
if (!$sum.length && !$status.length) {
return;
}
if (xhrPushPreview && xhrPushPreview.readyState !== 4) {
@ -890,7 +961,10 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
}
xhrPushPreview.abort();
}
$sum.html(waitHtml('Lecture MS1 (éligibles / différentiel)…'));
if ($status.length) {
$status.removeClass('ct-api-push-status--ok ct-api-push-status--todo')
.html(waitHtml('Vérification des changements…'));
}
xhrPushPreview = $.ajax({
url: strAjaxUrl,
type: 'POST',
@ -910,7 +984,10 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
var strMsg = (strStatus === 'timeout')
? 'Délai dépassé — réessayez Actualiser.'
: 'Erreur réseau (preview).';
$sum.html('<div class="text-danger">' + escHtml(strMsg) + '</div>');
if ($status.length) {
$status.removeClass('ct-api-push-status--ok ct-api-push-status--todo')
.html('<div class="text-danger">' + escHtml(strMsg) + '</div>');
}
}).always(function () {
xhrPushPreview = null;
});