reponsiveness on the dispatch section
This commit is contained in:
@@ -2394,28 +2394,6 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.testing-container .zone-order-card.going-on::after {
|
||||
content: 'IN PROGRESS';
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 12px;
|
||||
padding: 3px 9px;
|
||||
border-radius: 999px;
|
||||
background: #16a34a;
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
box-shadow: 0 2px 6px rgba(34, 197, 94, 0.4);
|
||||
animation: zone-order-going-on-pulse 1.6s ease-in-out infinite;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@keyframes zone-order-going-on-pulse {
|
||||
0%, 100% { box-shadow: 0 2px 6px rgba(34, 197, 94, 0.4); }
|
||||
50% { box-shadow: 0 2px 14px rgba(34, 197, 94, 0.75); }
|
||||
}
|
||||
|
||||
/* When the in-progress card is the focused stop, keep the green priority
|
||||
signal but tint a hair stronger so the click state is still felt. */
|
||||
.testing-container .zone-order-card.going-on.active {
|
||||
@@ -4079,6 +4057,12 @@
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
/* Hide floating chips overlay when split-map Compare Mode is active,
|
||||
since the operator is focused on one single rider and list is redundant. */
|
||||
.testing-container #body.compare-mode #ov-tr {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.testing-container #ov-br {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
@@ -5434,3 +5418,487 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Laptop Responsive Tuning (max-width: 1366px) ── */
|
||||
@media (max-width: 1366px) {
|
||||
/* Header adjustments */
|
||||
.testing-container #hdr {
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.testing-container .logo-name {
|
||||
font-size: 15px;
|
||||
}
|
||||
.testing-container .logo-badge {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 13px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.testing-container .logo {
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container #clock {
|
||||
font-size: 11px;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
.testing-container .hdr-stats {
|
||||
gap: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.testing-container .strat-stat {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .strat-stat-label {
|
||||
display: none; /* Hide profit/loss labels early to fit numbers */
|
||||
}
|
||||
.testing-container .live-status {
|
||||
font-size: 11px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.testing-container .live-status-sub {
|
||||
display: none; /* Hide total orders suffix to save space */
|
||||
}
|
||||
.testing-container .live-date-label {
|
||||
font-size: 11px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .live-date-label span {
|
||||
display: none; /* Hide the word 'Date' */
|
||||
}
|
||||
.testing-container .live-date-label input[type="date"] {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* Strategy Tab Row adjustments */
|
||||
.testing-container #strat-row {
|
||||
height: 38px;
|
||||
padding: 0 16px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .sbt {
|
||||
padding: 6px 10px;
|
||||
font-size: 11px;
|
||||
gap: 5px;
|
||||
}
|
||||
.testing-container .sbt .sbt-icon {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* Batch Slots Row adjustments */
|
||||
.testing-container #batch-row {
|
||||
padding: 6px 16px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .batch-label {
|
||||
font-size: 11px;
|
||||
}
|
||||
.testing-container .batch-btn {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* Sidebar Layout adjustments */
|
||||
.testing-container #sidebar {
|
||||
width: 320px;
|
||||
flex-basis: 320px;
|
||||
}
|
||||
.testing-container .sidebar-toggle-tab {
|
||||
left: 320px;
|
||||
}
|
||||
|
||||
/* Dynamic reduction in Compare Mode to keep dual maps wide enough */
|
||||
.testing-container #body.compare-mode #sidebar {
|
||||
width: 250px;
|
||||
flex-basis: 250px;
|
||||
}
|
||||
.testing-container #body.compare-mode .sidebar-toggle-tab {
|
||||
left: 250px;
|
||||
}
|
||||
.testing-container #body.compare-mode .sidebar-toggle-tab.is-collapsed {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Trim sidebar item paddings to increase visual density */
|
||||
.testing-container .sb-header {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
.testing-container .sb-tile {
|
||||
padding: 6px 8px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .sb-tile-value {
|
||||
font-size: 16px;
|
||||
}
|
||||
.testing-container .rcard {
|
||||
padding: 10px;
|
||||
}
|
||||
.testing-container .rcard-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
.testing-container .rcard-zone {
|
||||
font-size: 10px;
|
||||
}
|
||||
.testing-container .step-wrap {
|
||||
padding: 10px;
|
||||
}
|
||||
.testing-container #route-detail {
|
||||
padding: 12px;
|
||||
}
|
||||
.testing-container .rd-rider-name {
|
||||
font-size: 18px;
|
||||
}
|
||||
.testing-container .rd-stats-grid {
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .rd-stat {
|
||||
padding: 8px 4px 6px;
|
||||
}
|
||||
.testing-container .rd-stat-value {
|
||||
font-size: 14px;
|
||||
}
|
||||
.testing-container .rd-stat-label {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Dual-map Compare Mode Header compression for 14" laptops */
|
||||
.testing-container .compare-header-v2 {
|
||||
padding: 8px 12px 6px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-header-row .compare-title {
|
||||
font-size: 13px;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-title-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
.testing-container .compare-title-badge {
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-overall-btn,
|
||||
.testing-container .compare-sync-toggle {
|
||||
padding: 4px 8px;
|
||||
font-size: 10px;
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .compare-overall-btn svg,
|
||||
.testing-container .compare-sync-toggle svg {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Compare Mode Step Timeline Compression for 14" laptops */
|
||||
.testing-container .compare-timeline-wrap {
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .compare-timeline {
|
||||
padding: 4px 12px 6px;
|
||||
flex-wrap: nowrap !important;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none; /* Hide standard Firefox scrollbar */
|
||||
-ms-overflow-style: none; /* Hide IE scrollbar */
|
||||
}
|
||||
.testing-container .compare-timeline::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
.testing-container .compare-timeline::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
.testing-container .compare-timeline::-webkit-scrollbar-thumb {
|
||||
background: rgba(99, 102, 241, 0.25);
|
||||
border-radius: 999px;
|
||||
}
|
||||
.testing-container .compare-timeline:hover::-webkit-scrollbar-thumb {
|
||||
background: rgba(99, 102, 241, 0.5);
|
||||
}
|
||||
|
||||
.testing-container .compare-step {
|
||||
gap: 4px; /* Tighten spacer-circle layout vertical spacing */
|
||||
}
|
||||
.testing-container .compare-step-circle {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 10px;
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.1), 0 0 0 1px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.testing-container .compare-step.is-focused .compare-step-circle {
|
||||
transform: scale(1.1);
|
||||
box-shadow:
|
||||
0 2px 6px rgba(15, 23, 42, 0.15),
|
||||
0 0 0 2px #fff,
|
||||
0 0 0 3px var(--step-color, #6366f1);
|
||||
}
|
||||
.testing-container .compare-step-spacer {
|
||||
width: 10px;
|
||||
margin-bottom: 14px; /* Shift connecting lines up for 24px circles */
|
||||
}
|
||||
.testing-container .compare-step-tick {
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-step-flag {
|
||||
top: -3px;
|
||||
right: -3px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
/* Progress Strip inside Timeline */
|
||||
.testing-container .compare-progress-strip {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.testing-container .compare-progress-text {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Legend compacting for laptops */
|
||||
.testing-container .compare-legend {
|
||||
padding-top: 2px;
|
||||
margin-top: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-legend-item {
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-legend-swatch {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
.testing-container .compare-legend-note {
|
||||
display: none; /* Hide wordy GPS smoothing notes */
|
||||
}
|
||||
|
||||
/* Bottom Delta Card panel compression for 14" laptops */
|
||||
.testing-container .compare-delta {
|
||||
padding: 8px 12px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-delta-title {
|
||||
margin-bottom: 4px;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-step-badge {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.testing-container .compare-delta-title-main {
|
||||
font-size: 12px;
|
||||
}
|
||||
.testing-container .compare-delta-title-sub {
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-delta-status {
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.testing-container .compare-delta-grid {
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-delta-cell {
|
||||
padding: 5px 8px 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-label {
|
||||
font-size: 9px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-val {
|
||||
font-size: 13px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-unit {
|
||||
font-size: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-sub {
|
||||
font-size: 9px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Laptop Height Tuning (max-height: 750px) ── */
|
||||
@media (max-height: 750px) {
|
||||
/* Let's shrink header rows even further on short screen heights */
|
||||
.testing-container #hdr {
|
||||
height: 42px;
|
||||
}
|
||||
.testing-container #strat-row {
|
||||
height: 34px;
|
||||
}
|
||||
.testing-container #batch-row {
|
||||
padding: 4px 16px;
|
||||
}
|
||||
|
||||
/* Dual-map Compare Mode Header compression */
|
||||
.testing-container .compare-header-v2 {
|
||||
padding: 8px 12px 6px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-header-row .compare-title {
|
||||
font-size: 13px;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-title-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
.testing-container .compare-title-badge {
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-overall-btn,
|
||||
.testing-container .compare-sync-toggle {
|
||||
padding: 4px 8px;
|
||||
font-size: 10px;
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .compare-overall-btn svg,
|
||||
.testing-container .compare-sync-toggle svg {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Compare Mode Step Timeline Compression */
|
||||
.testing-container .compare-timeline-wrap {
|
||||
gap: 4px;
|
||||
}
|
||||
.testing-container .compare-timeline {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.testing-container .compare-step {
|
||||
gap: 4px; /* Reduced from 11px to bring timeline elements tighter */
|
||||
}
|
||||
.testing-container .compare-step-circle {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 10px;
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.1), 0 0 0 1px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.testing-container .compare-step.is-focused .compare-step-circle {
|
||||
transform: scale(1.1);
|
||||
box-shadow:
|
||||
0 2px 6px rgba(15, 23, 42, 0.15),
|
||||
0 0 0 2px #fff,
|
||||
0 0 0 3px var(--step-color, #6366f1);
|
||||
}
|
||||
.testing-container .compare-step-spacer {
|
||||
width: 10px;
|
||||
margin-bottom: 14px; /* Shift spacer dynamically up to align with 24px circles */
|
||||
}
|
||||
.testing-container .compare-step-tick {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Progress Strip inside Timeline */
|
||||
.testing-container .compare-progress-strip {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.testing-container .compare-progress-text {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Legend compacting */
|
||||
.testing-container .compare-legend {
|
||||
padding-top: 2px;
|
||||
margin-top: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-legend-item {
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-legend-swatch {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
.testing-container .compare-legend-note {
|
||||
display: none; /* Hide verbose Kalman note on short screens */
|
||||
}
|
||||
|
||||
/* Bottom Delta Card panel compression */
|
||||
.testing-container .compare-delta {
|
||||
padding: 8px 12px;
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-delta-title {
|
||||
margin-bottom: 4px;
|
||||
gap: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-step-badge {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.testing-container .compare-delta-title-main {
|
||||
font-size: 12px;
|
||||
}
|
||||
.testing-container .compare-delta-title-sub {
|
||||
font-size: 9px;
|
||||
}
|
||||
.testing-container .compare-delta-status {
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Delta Grid - cells and labels */
|
||||
.testing-container .compare-delta-grid {
|
||||
gap: 6px;
|
||||
}
|
||||
.testing-container .compare-delta-cell {
|
||||
padding: 5px 8px 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-label {
|
||||
font-size: 9px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-val {
|
||||
font-size: 13px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-unit {
|
||||
font-size: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-cell-sub {
|
||||
font-size: 9px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Day summary toggle styles */
|
||||
.testing-container .compare-delta.is-collapsible.is-collapsed {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.testing-container .compare-delta-toggle-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted, #64748b);
|
||||
font-size: 18px;
|
||||
transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1), color 0.15s ease;
|
||||
}
|
||||
.testing-container .compare-delta-title:hover .compare-delta-toggle-icon {
|
||||
color: var(--accent, #6366f1);
|
||||
}
|
||||
|
||||
@media (max-width: 1366px) {
|
||||
.testing-container .compare-delta.is-collapsible.is-collapsed {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-toggle-icon {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 750px) {
|
||||
.testing-container .compare-delta.is-collapsible.is-collapsed {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.testing-container .compare-delta-toggle-icon {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
@@ -973,6 +973,7 @@ const Dispatch = ({
|
||||
// per-rider). Kept as a single state flag so we don't entangle it with
|
||||
// viewMode/focused* logic.
|
||||
const [compareOpen, setCompareOpen] = useState(false);
|
||||
const [daySummaryOpen, setDaySummaryOpen] = useState(false);
|
||||
// In controlled mode the parent owns selectedRiderId, so handleRiderFocus only
|
||||
// fires onRiderSelect — focusedRider won't update until the parent re-renders.
|
||||
// This ref lets us defer setCompareOpen(true) until focusedRider is confirmed.
|
||||
@@ -1586,6 +1587,7 @@ const Dispatch = ({
|
||||
// stuck on a step that may not exist in their day.
|
||||
useEffect(() => {
|
||||
setFocusedCompareStep(null);
|
||||
setDaySummaryOpen(false);
|
||||
}, [compareOpen, focusedRider?.id]);
|
||||
|
||||
// Mirror pan/zoom from whichever map the user is driving. Called by
|
||||
@@ -2989,7 +2991,7 @@ const Dispatch = ({
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div id="body" className={sidebarCollapsed ? 'sidebar-collapsed' : ''}>
|
||||
<div id="body" className={`${sidebarCollapsed ? 'sidebar-collapsed' : ''} ${compareOpen ? 'compare-mode' : ''}`.trim()}>
|
||||
<button
|
||||
type="button"
|
||||
className={`sidebar-toggle-tab${sidebarCollapsed ? ' is-collapsed' : ''}`}
|
||||
@@ -4369,8 +4371,13 @@ const Dispatch = ({
|
||||
: '';
|
||||
const total = sum.onTime + sum.late;
|
||||
return (
|
||||
<div className="compare-delta">
|
||||
<div className="compare-delta-title">
|
||||
<div className={`compare-delta is-collapsible${daySummaryOpen ? ' is-expanded' : ' is-collapsed'}`}>
|
||||
<div
|
||||
className="compare-delta-title"
|
||||
onClick={() => setDaySummaryOpen((v) => !v)}
|
||||
style={{ cursor: 'pointer', userSelect: 'none' }}
|
||||
title={daySummaryOpen ? 'Collapse Day Summary' : 'Expand Day Summary'}
|
||||
>
|
||||
<span
|
||||
className="compare-delta-step-badge"
|
||||
style={{ background: focusedRider.color }}
|
||||
@@ -4378,49 +4385,65 @@ const Dispatch = ({
|
||||
<MdPublic />
|
||||
</span>
|
||||
<div className="compare-delta-title-text">
|
||||
<div className="compare-delta-title-main">Day summary</div>
|
||||
<div className="compare-delta-title-main" style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
||||
Day summary
|
||||
<span
|
||||
className="compare-delta-toggle-icon"
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
transform: daySummaryOpen ? 'rotate(180deg)' : 'rotate(0deg)',
|
||||
transition: 'transform 0.22s cubic-bezier(0.4, 0, 0.2, 1)'
|
||||
}}
|
||||
>
|
||||
<MdExpandMore />
|
||||
</span>
|
||||
</div>
|
||||
<div className="compare-delta-title-sub">
|
||||
Click any step above to scrutinize that delivery
|
||||
{daySummaryOpen
|
||||
? 'Click to collapse summary'
|
||||
: 'Click to expand summary · Click any step above to scrutinize'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="compare-delta-grid">
|
||||
<div className="compare-delta-cell">
|
||||
<span className="compare-delta-cell-label">Total distance</span>
|
||||
<span className="compare-delta-cell-val">
|
||||
{sum.actualKm.toFixed(1)}{' '}
|
||||
<span className="compare-delta-cell-unit">km</span>
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
planned {sum.plannedKm.toFixed(1)} km
|
||||
</span>
|
||||
{daySummaryOpen && (
|
||||
<div className="compare-delta-grid">
|
||||
<div className="compare-delta-cell">
|
||||
<span className="compare-delta-cell-label">Total distance</span>
|
||||
<span className="compare-delta-cell-val">
|
||||
{sum.actualKm.toFixed(1)}{' '}
|
||||
<span className="compare-delta-cell-unit">km</span>
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
planned {sum.plannedKm.toFixed(1)} km
|
||||
</span>
|
||||
</div>
|
||||
<div className={`compare-delta-cell${sum.anomalies > 0 ? ' is-anomaly' : ''}`}>
|
||||
<span className="compare-delta-cell-label">Route deviation</span>
|
||||
<span className={`compare-delta-cell-val ${deltaCls}`}>
|
||||
{sum.kmDeltaPct != null
|
||||
? `${sum.kmDeltaPct > 0 ? '+' : ''}${sum.kmDeltaPct.toFixed(0)}%`
|
||||
: '—'}
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
{sum.anomalies > 0
|
||||
? `${sum.anomalies} step${sum.anomalies > 1 ? 's' : ''} flagged`
|
||||
: 'within plan'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="compare-delta-cell">
|
||||
<span className="compare-delta-cell-label">On-time</span>
|
||||
<span className="compare-delta-cell-val">
|
||||
{sum.onTime}
|
||||
{total > 0 && (
|
||||
<span className="compare-delta-cell-unit">/{total}</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
{sum.late > 0 ? `${sum.late} late` : 'all on schedule'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`compare-delta-cell${sum.anomalies > 0 ? ' is-anomaly' : ''}`}>
|
||||
<span className="compare-delta-cell-label">Route deviation</span>
|
||||
<span className={`compare-delta-cell-val ${deltaCls}`}>
|
||||
{sum.kmDeltaPct != null
|
||||
? `${sum.kmDeltaPct > 0 ? '+' : ''}${sum.kmDeltaPct.toFixed(0)}%`
|
||||
: '—'}
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
{sum.anomalies > 0
|
||||
? `${sum.anomalies} step${sum.anomalies > 1 ? 's' : ''} flagged`
|
||||
: 'within plan'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="compare-delta-cell">
|
||||
<span className="compare-delta-cell-label">On-time</span>
|
||||
<span className="compare-delta-cell-val">
|
||||
{sum.onTime}
|
||||
{total > 0 && (
|
||||
<span className="compare-delta-cell-unit">/{total}</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="compare-delta-cell-sub">
|
||||
{sum.late > 0 ? `${sum.late} late` : 'all on schedule'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
Reference in New Issue
Block a user