mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 13:02:50 +00:00
84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
import { Text, Tooltip } from '@mantine/core';
|
|
import { statusToneVars } from '@ema-platform/shared';
|
|
|
|
export interface WaitingForProps {
|
|
/** When the clock started — normally the moment the applicant submitted. */
|
|
since: string | null | undefined;
|
|
/**
|
|
* Days after which the wait reads as overdue. Amber at half of it, red past
|
|
* it. Defaults to 14, which is the shortest SLA any configured licence type
|
|
* currently uses; pass the real one where a queue knows it.
|
|
*/
|
|
slaDays?: number;
|
|
/** Set once the item is decided — a closed item is not waiting for anyone. */
|
|
done?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Fraction of the target elapsed before the wait reads as at-risk. Matches the
|
|
* licence queue's own `WARNING_RATIO`, so a queue using this component and one
|
|
* using `computeSla` turn amber at the same point rather than disagreeing.
|
|
*/
|
|
const WARNING_RATIO = 0.7;
|
|
|
|
/** Whole days between `since` and now, floored. Negative clock skew reads as 0. */
|
|
function daysSince(since: string): number {
|
|
const ms = Date.now() - new Date(since).getTime();
|
|
return Math.max(0, Math.floor(ms / 86_400_000));
|
|
}
|
|
|
|
/**
|
|
* How long an item has been sitting in a queue.
|
|
*
|
|
* No review queue showed this. An officer opening a list of thirty
|
|
* registrations could see what each one *was*, but not which had been waiting
|
|
* three days and which had been waiting three weeks — so the queue was worked
|
|
* top-down by whatever the sort happened to be rather than by urgency.
|
|
*
|
|
* Colour comes from the platform's status tones rather than its own scale, so
|
|
* "overdue" here is the same red as "rejected" everywhere else.
|
|
*/
|
|
export function WaitingFor({ since, slaDays = 14, done }: WaitingForProps) {
|
|
if (!since) {
|
|
return (
|
|
<Text size="sm" c="dimmed">
|
|
—
|
|
</Text>
|
|
);
|
|
}
|
|
|
|
const days = daysSince(since);
|
|
|
|
// A decided item keeps its elapsed time visible — useful when reviewing how
|
|
// long something took — but never coloured, because nothing is pending.
|
|
const tone = done
|
|
? 'neutral'
|
|
: days >= slaDays
|
|
? 'danger'
|
|
: days >= slaDays * WARNING_RATIO
|
|
? 'pending'
|
|
: 'neutral';
|
|
|
|
const label = days === 0 ? 'today' : `${days}d`;
|
|
|
|
return (
|
|
<Tooltip
|
|
label={
|
|
done
|
|
? `Took ${days} day${days === 1 ? '' : 's'}`
|
|
: `Waiting ${days} day${days === 1 ? '' : 's'} · ${slaDays}-day target`
|
|
}
|
|
withArrow
|
|
>
|
|
<Text
|
|
size="sm"
|
|
fw={tone === 'neutral' ? 400 : 600}
|
|
c={tone === 'neutral' ? 'dimmed' : undefined}
|
|
style={tone === 'neutral' ? undefined : { color: statusToneVars(tone).color }}
|
|
>
|
|
{label}
|
|
</Text>
|
|
</Tooltip>
|
|
);
|
|
}
|