updates on the astryx desing

This commit is contained in:
2026-08-14 16:09:14 +05:30
parent d3dd687a8d
commit a46212f291
106 changed files with 10244 additions and 24738 deletions

View File

@@ -1,5 +1,4 @@
import React, { useMemo } from 'react';
import { useTheme, useMediaQuery } from '@mui/material';
import {
MdPublic,
MdSwapHoriz,
@@ -21,12 +20,16 @@ import {
MdHourglassBottom
} from 'react-icons/md';
import {
onActivate,
useIsNarrowViewport,
stepColor,
getStatusStyle,
FINAL_STATUSES,
SKIPPED_STATUSES,
ordinal
} from './dispatchShared';
import StatusBadge from 'components/nearle_components/StatusBadge';
import { STATUS } from 'themes/dt/tokens';
// Right-side data panel rendered in Compare mode. Pure presentation +
// memoized derivations: feed it the comparison state from Dispatch and
@@ -65,8 +68,7 @@ function CompareDataPanel({
// scoped media-query block in Dispatch.css uses to stack the side-by-side
// timing/clock columns vertically and let stat chips wrap). No data,
// handler, or derivation behaviour changes on any breakpoint.
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isMobile = useIsNarrowViewport();
// All derivations live in a single useMemo so the cost of re-running
// them is paid only when an upstream input actually changes — not on
@@ -105,7 +107,13 @@ function CompareDataPanel({
(sum.onTime / onTimeForScore) * 25 +
((totalForScore - sum.anomalies) / totalForScore) * 15
);
const scoreColor = score >= 85 ? '#16a34a' : score >= 65 ? '#f59e0b' : '#dc2626';
// A compliance score is a health reading, not a lifecycle status, so it
// must NOT go through StatusBadge — it reads the raw hexes from the STATUS
// palette, which is the sanctioned "arbitrary accent" channel (root
// CLAUDE.md §6.3). Thresholds (85/65) and the ring mechanism below are
// deliberately unchanged; only the three constants are retargeted, so a QA
// A/B comparison should show identical scores and bands.
const scoreColor = score >= 85 ? STATUS.success : score >= 65 ? STATUS.warning : STATUS.error;
const scoreLabel = score >= 85 ? 'Excellent' : score >= 65 ? 'Acceptable' : 'Needs review';
// KPIs derived from delivery timestamps.
@@ -253,7 +261,11 @@ function CompareDataPanel({
className={`cdp-seq-diff${
focusedCompareStep === d.sequenceStep ? ' is-focused' : ''
}${focusable ? '' : ' is-nested'}`}
role="treeitem"
aria-selected={focusedCompareStep === d.sequenceStep}
tabIndex={0}
onClick={() => focusStep(d.sequenceStep)}
onKeyDown={onActivate(() => focusStep(d.sequenceStep))}
>
<span
className="cdp-seq-diff-num"
@@ -433,7 +445,9 @@ function CompareDataPanel({
<div
className="cdp-section-head cdp-section-head-clickable"
onClick={() => setSequenceOpen((v) => !v)}
onKeyDown={onActivate(() => setSequenceOpen((v) => !v))}
role="button"
tabIndex={0}
aria-expanded={sequenceOpen}
title={sequenceOpen ? 'Collapse route sequence' : 'Expand route sequence'}
>
@@ -455,7 +469,7 @@ function CompareDataPanel({
{sequenceOpen && (
<div className="cdp-seq">
{outOfOrderSteps.length > 0 ? (
<ul className="cdp-seq-diffs">
<ul className="cdp-seq-diffs" role="tree" aria-label="Route sequence differences">
{seqRuns.map((run, runIdx) => {
if (run.items.length === 1) {
return renderDiffRow(run.items[0]);
@@ -472,7 +486,11 @@ function CompareDataPanel({
<React.Fragment key={`run-${runIdx}-${first.d.sequenceStep}`}>
<li
className={`cdp-seq-diff is-group${isOpen ? ' is-expanded' : ''}${groupFocused ? ' is-focused' : ''}`}
role="treeitem"
aria-selected={groupFocused}
tabIndex={0}
onClick={() => toggleSeqGroup(runIdx)}
onKeyDown={onActivate(() => toggleSeqGroup(runIdx))}
aria-expanded={isOpen}
>
<span className="cdp-seq-group-num">
@@ -508,8 +526,8 @@ function CompareDataPanel({
</span>
</li>
{isOpen && (
<li className="cdp-seq-group-children-wrap">
<ul className="cdp-seq-group-children">
<li className="cdp-seq-group-children-wrap" role="presentation">
<ul className="cdp-seq-group-children" role="group">
{run.items.map((it) => renderDiffRow(it, false))}
</ul>
</li>
@@ -670,7 +688,9 @@ function CompareDataPanel({
<div
className="cdp-highlight is-best"
onClick={() => focusStep(bestStep.sequenceStep)}
onKeyDown={onActivate(() => focusStep(bestStep.sequenceStep))}
role="button"
tabIndex={0}
title="Focus this step"
>
<span className="cdp-highlight-rail" aria-hidden="true" />
@@ -710,7 +730,9 @@ function CompareDataPanel({
<div
className="cdp-highlight is-worst"
onClick={() => focusStep(worstStep.sequenceStep)}
onKeyDown={onActivate(() => focusStep(worstStep.sequenceStep))}
role="button"
tabIndex={0}
title="Focus this step"
>
<span className="cdp-highlight-rail" aria-hidden="true" />
@@ -810,7 +832,7 @@ function CompareDataPanel({
? 'is-under'
: ''
: '';
const statusStyle = getStatusStyle(focused.orderstatus);
const profit = parseFloat(focused.order?.profit || 0);
return (
<section className="cdp-section">
@@ -845,14 +867,7 @@ function CompareDataPanel({
Order #{focused.orderid}
</div>
</div>
{focused.orderstatus && (
<span
className="compare-delta-status"
style={{ background: statusStyle.bg, color: statusStyle.fg }}
>
{statusStyle.label}
</span>
)}
{focused.orderstatus && <StatusBadge status={focused.orderstatus} />}
</div>
<div className="compare-delta-grid">
<div className={`compare-delta-cell${focused.anomaly ? ' is-anomaly' : ''}`}>
@@ -920,7 +935,7 @@ function CompareDataPanel({
Deviations ({deviations.length})
</span>
</div>
<ul className="cdp-dev-list">
<ul className="cdp-dev-list" role="listbox" aria-label="Step deviations">
{deviations.map((d) => {
const color = stepColor(d.sequenceStep - 1);
const kmSign = d.kmDelta >= 0 ? '+' : '';
@@ -928,7 +943,11 @@ function CompareDataPanel({
<li
key={`dev-${d.sequenceStep}`}
className={`cdp-dev-item${focusedCompareStep === d.sequenceStep ? ' is-focused' : ''}`}
role="option"
aria-selected={focusedCompareStep === d.sequenceStep}
tabIndex={0}
onClick={() => focusStep(d.sequenceStep)}
onKeyDown={onActivate(() => focusStep(d.sequenceStep))}
>
<span className="cdp-dev-num" style={{ background: color }}>
{d.sequenceStep}
@@ -970,7 +989,7 @@ function CompareDataPanel({
{delivered}/{compareDeltas.length} delivered
</span>
</div>
<ul className="cdp-step-list">
<ul className="cdp-step-list" role="listbox" aria-label="Route steps">
{compareDeltas.map((d) => {
const color = stepColor(d.sequenceStep - 1);
const statusLow = String(d.orderstatus || '').toLowerCase();
@@ -978,7 +997,7 @@ function CompareDataPanel({
const isSkipped = SKIPPED_STATUSES.has(statusLow);
const isCorrect = isDelivered && !d.anomaly;
const isFocused = focusedCompareStep === d.sequenceStep;
const statusStyle = getStatusStyle(d.orderstatus);
const profit = parseFloat(d.order?.profit || 0);
const kmSign = d.kmDelta >= 0 ? '+' : '';
const timeCls =
@@ -1001,7 +1020,11 @@ function CompareDataPanel({
<li
key={`step-${d.sequenceStep}`}
className={stepCls}
role="option"
aria-selected={isFocused}
tabIndex={0}
onClick={() => focusStep(d.sequenceStep)}
onKeyDown={onActivate(() => focusStep(d.sequenceStep))}
>
<span className="cdp-step-num" style={{ background: color }}>
{d.sequenceStep}
@@ -1021,14 +1044,7 @@ function CompareDataPanel({
<span className="cdp-step-title">
{d.deliverycustomer || `Step ${d.sequenceStep}`}
</span>
{d.orderstatus && (
<span
className="cdp-step-status"
style={{ background: statusStyle.bg, color: statusStyle.fg }}
>
{statusStyle.label}
</span>
)}
{d.orderstatus && <StatusBadge status={d.orderstatus} />}
</div>
<div className="cdp-step-sub">
{d.pickupcustomer ? `from ${d.pickupcustomer} · ` : ''}