refactor: migrate P1/P2 SLA banner to lt-sla-p1/lt-sla-p2 component
Replaces the lt-alert workaround with the new purpose-built SLA banner component now in base.css: - lt-sla-p1 (pulsing red) / lt-sla-p2 (static amber) wrapper classes - Structured subcomponents: lt-sla-icon, lt-sla-info, lt-sla-title, lt-sla-bar + lt-sla-fill (gradient fill), lt-sla-meta, lt-sla-dismiss - Dismiss now uses banner.hidden + sessionStorage key lt_sla_dismissed_<id> (aligns with web_template pattern; previous code used classList 'dismissed') - Elapsed/remaining/breach state driven by same tick() interval, now updating lt-sla-fill width instead of a separate lt-progress bar inside lt-alert-msg Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+42
-56
@@ -215,56 +215,58 @@ include __DIR__ . '/layout_header.php';
|
||||
1 => 8, 2 => 24, default => 72
|
||||
};
|
||||
$elapsedSeconds = time() - strtotime($ticket['created_at']);
|
||||
$elapsedHours = round($elapsedSeconds / 3600, 1);
|
||||
$slaPct = min(100, round(($elapsedSeconds / ($slaTargetHours * 3600)) * 100));
|
||||
$slaBreached = $elapsedSeconds >= ($slaTargetHours * 3600);
|
||||
$alertClass = $priorityNum === 1 ? 'lt-alert--error' : 'lt-alert--warning';
|
||||
$alertIcon = $priorityNum === 1 ? '[ ! ]' : '[ ~ ]';
|
||||
$alertLabel = $priorityNum === 1 ? 'CRITICAL — P1 Ticket' : 'HIGH PRIORITY — P2 Ticket';
|
||||
$progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progress--red' : 'lt-progress--green');
|
||||
$slaClass = $priorityNum === 1 ? 'lt-sla-p1' : 'lt-sla-p2';
|
||||
$slaIcon = $priorityNum === 1 ? '[ ! ]' : '[ ~ ]';
|
||||
$slaLabel = $priorityNum === 1 ? 'P1 Critical' : 'P2 High';
|
||||
$slaId = 'sla-' . htmlspecialchars($ticket['ticket_id'], ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<!-- Priority alert banner — P1/P2 only, dismissible per session -->
|
||||
<div class="lt-alert <?= $alertClass ?>" id="priorityAlertBanner"
|
||||
role="alert" aria-live="polite"
|
||||
data-alert-id="priority-banner-<?= htmlspecialchars($ticket['ticket_id']) ?>"
|
||||
<!-- SLA banner — P1/P2 only, dismissible per session -->
|
||||
<div class="<?= $slaClass ?>" id="priorityAlertBanner" role="alert" aria-live="polite"
|
||||
data-sla-id="<?= $slaId ?>"
|
||||
data-created-at="<?= (int)strtotime($ticket['created_at']) ?>"
|
||||
data-sla-hours="<?= $slaTargetHours ?>"
|
||||
style="margin-bottom:0.75rem">
|
||||
<span class="lt-alert-icon" aria-hidden="true"><?= $alertIcon ?></span>
|
||||
<div class="lt-alert-body">
|
||||
<div class="lt-alert-title"><?= $alertLabel ?></div>
|
||||
<div class="lt-alert-msg">
|
||||
SLA target: <strong><?= $slaTargetHours ?>h</strong> —
|
||||
Elapsed: <strong id="slaElapsedTimer"><?= $elapsedHours ?>h</strong>
|
||||
<?php if (!$slaBreached) : ?>
|
||||
— Remaining: <strong id="slaCountdownTimer" class="lt-text-cyan"></strong>
|
||||
<?php else : ?>
|
||||
— <span class="lt-text-danger" id="slaCountdownTimer">SLA BREACHED (+<strong id="slaOverrunTimer"><?= round(($elapsedSeconds - $slaTargetHours * 3600) / 3600, 1) ?>h</strong>)</span>
|
||||
<span class="lt-sla-icon" aria-hidden="true"><?= $slaIcon ?></span>
|
||||
<div class="lt-sla-info">
|
||||
<div class="lt-sla-title">
|
||||
<?= $slaLabel ?> — SLA: <span id="slaElapsedTimer"></span> elapsed of <?= $slaTargetHours ?>h limit
|
||||
<?php if ($slaBreached) : ?>
|
||||
<span class="lt-text-danger" id="slaBreachLabel">BREACHED</span>
|
||||
<?php endif ?>
|
||||
<div class="lt-progress lt-progress--sm <?= $progressClass ?>" id="slaProgress" style="margin-top:0.35rem"
|
||||
aria-label="SLA progress <?= $slaPct ?>%">
|
||||
<div class="lt-progress-bar" id="slaProgressBar" style="width:<?= $slaPct ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-sla-bar" aria-label="SLA progress <?= $slaPct ?>%" id="slaProgress">
|
||||
<div class="lt-sla-fill" id="slaProgressBar" style="width:<?= $slaPct ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="lt-alert-close" data-action="dismiss-priority-banner" aria-label="Dismiss">✕</button>
|
||||
<?php if (!$slaBreached) : ?>
|
||||
<div class="lt-sla-meta" id="slaCountdownTimer"></div>
|
||||
<?php else : ?>
|
||||
<div class="lt-sla-meta lt-text-danger" id="slaCountdownTimer">+<span id="slaOverrunTimer"><?= round(($elapsedSeconds - $slaTargetHours * 3600) / 3600, 1) ?>h</span> over</div>
|
||||
<?php endif ?>
|
||||
<button type="button" class="lt-sla-dismiss" aria-label="Dismiss">✕</button>
|
||||
</div>
|
||||
<script nonce="<?= htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8') ?>">
|
||||
(function(){
|
||||
var banner = document.getElementById('priorityAlertBanner');
|
||||
var id = 'priority-banner-<?= htmlspecialchars($ticket['ticket_id']) ?>';
|
||||
try { if(sessionStorage.getItem('lt_dismissed_'+id)) banner.classList.add('dismissed'); } catch(e) {}
|
||||
var id = banner.dataset.slaId;
|
||||
try { if (id && sessionStorage.getItem('lt_sla_dismissed_' + id)) banner.hidden = true; } catch(e) {}
|
||||
|
||||
banner.querySelector('.lt-sla-dismiss').addEventListener('click', function() {
|
||||
banner.hidden = true;
|
||||
try { if (id) sessionStorage.setItem('lt_sla_dismissed_' + id, '1'); } catch(e) {}
|
||||
});
|
||||
|
||||
// Live SLA timers — start after base.js initialises lt
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (!banner || banner.classList.contains('dismissed')) return;
|
||||
if (banner.hidden) return;
|
||||
var createdAt = parseInt(banner.dataset.createdAt, 10) * 1000;
|
||||
var slaMs = parseInt(banner.dataset.slaHours, 10) * 3600 * 1000;
|
||||
var deadline = new Date(createdAt + slaMs);
|
||||
var elapsedEl = document.getElementById('slaElapsedTimer');
|
||||
var slaMs = parseInt(banner.dataset.slaHours, 10) * 3600 * 1000;
|
||||
var deadline = new Date(createdAt + slaMs);
|
||||
var elapsedEl = document.getElementById('slaElapsedTimer');
|
||||
var countdownEl = document.getElementById('slaCountdownTimer');
|
||||
var overrunEl = document.getElementById('slaOverrunTimer');
|
||||
var progressBar = document.getElementById('slaProgressBar');
|
||||
var overrunEl = document.getElementById('slaOverrunTimer');
|
||||
var fillBar = document.getElementById('slaProgressBar');
|
||||
var progressWrap = document.getElementById('slaProgress');
|
||||
|
||||
function fmtHMS(ms) {
|
||||
@@ -274,35 +276,19 @@ include __DIR__ . '/layout_header.php';
|
||||
}
|
||||
|
||||
function tick() {
|
||||
var now = Date.now();
|
||||
var elapsed = now - createdAt;
|
||||
var now = Date.now();
|
||||
var elapsed = now - createdAt;
|
||||
var remaining = deadline - now;
|
||||
var pct = Math.min(100, Math.round((elapsed / slaMs) * 100));
|
||||
var pct = Math.min(100, Math.round((elapsed / slaMs) * 100));
|
||||
|
||||
if (elapsedEl) elapsedEl.textContent = fmtHMS(elapsed);
|
||||
if (progressBar) progressBar.style.width = pct + '%';
|
||||
if (elapsedEl) elapsedEl.textContent = fmtHMS(elapsed);
|
||||
if (fillBar) fillBar.style.width = pct + '%';
|
||||
if (progressWrap) progressWrap.setAttribute('aria-label', 'SLA progress ' + pct + '%');
|
||||
|
||||
if (remaining > 0) {
|
||||
// SLA not yet breached
|
||||
if (countdownEl) {
|
||||
countdownEl.textContent = fmtHMS(remaining) + ' remaining';
|
||||
countdownEl.className = pct >= 75 ? 'lt-text-danger' : 'lt-text-cyan';
|
||||
}
|
||||
if (progressWrap && pct >= 75) {
|
||||
progressWrap.className = progressWrap.className.replace('lt-progress--green','lt-progress--red');
|
||||
}
|
||||
if (countdownEl) countdownEl.textContent = fmtHMS(remaining) + ' remaining';
|
||||
} else {
|
||||
// Breached
|
||||
if (countdownEl && !overrunEl) {
|
||||
countdownEl.innerHTML = 'SLA BREACHED (+' + fmtHMS(-remaining) + ')';
|
||||
countdownEl.className = 'lt-text-danger';
|
||||
} else if (overrunEl) {
|
||||
overrunEl.textContent = fmtHMS(-remaining);
|
||||
}
|
||||
if (progressWrap && !progressWrap.classList.contains('lt-progress--red')) {
|
||||
progressWrap.className = progressWrap.className.replace('lt-progress--green','').replace('lt-progress--red','') + ' lt-progress--red';
|
||||
}
|
||||
if (overrunEl) overrunEl.textContent = fmtHMS(-remaining);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user