updates on the ui changes and changed into doormile
This commit is contained in:
102
src/components/doormile/BatchEfficiency.jsx
Normal file
102
src/components/doormile/BatchEfficiency.jsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { Gauge, RefreshCw } from 'lucide-react';
|
||||
import { Button, EmptyState, SectionHeader, Stack, Surface } from '@/components/ds';
|
||||
import { fetchBatchEfficiency } from '@/api/doormile';
|
||||
import { messageOf } from '@/api/doormile/notify';
|
||||
import { number } from '@/lib/doormileFormat';
|
||||
|
||||
/**
|
||||
* The solver's own read on how well a wave was packed.
|
||||
*
|
||||
* This calls the dispatch optimiser, not the Doormile API, and its response has
|
||||
* no agreed schema — so nothing here assumes a field name. Whatever the service
|
||||
* returns is rendered: numbers get formatted, nested objects are shown as JSON,
|
||||
* and a shape nobody has seen before is still readable rather than blank.
|
||||
*
|
||||
* It is behind a button rather than fetched with the board because it is an
|
||||
* analysis an operator asks for, and running it automatically would put a call
|
||||
* to an external service on every date and wave change.
|
||||
*/
|
||||
|
||||
const titleise = (key) =>
|
||||
String(key)
|
||||
.replace(/[_-]+/g, ' ')
|
||||
.replace(/\b\w/g, (c) => c.toUpperCase());
|
||||
|
||||
const renderValue = (value) => {
|
||||
if (value === null || value === undefined || value === '') return '—';
|
||||
if (typeof value === 'number') return number(value);
|
||||
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
|
||||
if (typeof value === 'object') return JSON.stringify(value);
|
||||
return String(value);
|
||||
};
|
||||
|
||||
/** @param {any} props */
|
||||
export function BatchEfficiency({ batch, orders = [], tenantId }) {
|
||||
const analyse = useMutation({
|
||||
mutationFn: () => fetchBatchEfficiency({ batch, tenantId }),
|
||||
});
|
||||
|
||||
const result = analyse.data?.data ?? analyse.data;
|
||||
const entries =
|
||||
result && typeof result === 'object' && !Array.isArray(result) ? Object.entries(result) : [];
|
||||
|
||||
return (
|
||||
<Surface radius="xl" padding="lg">
|
||||
<SectionHeader
|
||||
title="Batch efficiency"
|
||||
subtitle="How well the optimiser packed this wave. Runs against the solver, on request."
|
||||
icon={Gauge}
|
||||
actions={
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => analyse.mutate()}
|
||||
loading={analyse.isPending}
|
||||
disabled={orders.length === 0}
|
||||
>
|
||||
<RefreshCw className="mr-1.5 h-3.5 w-3.5" /> Analyse
|
||||
</Button>
|
||||
}
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{orders.length === 0 ? (
|
||||
<EmptyState
|
||||
icon={Gauge}
|
||||
size="sm"
|
||||
title="Nothing in this wave"
|
||||
description="Pick a wave with orders in it to analyse."
|
||||
/>
|
||||
) : analyse.isError ? (
|
||||
<p className="text-body-sm text-destructive">
|
||||
{messageOf(analyse.error, 'The solver did not answer')}
|
||||
</p>
|
||||
) : !analyse.data ? (
|
||||
<p className="text-body-sm text-ink-3">
|
||||
{orders.length} order{orders.length === 1 ? '' : 's'} in this wave. Run the analysis to see how the solver
|
||||
rates it.
|
||||
</p>
|
||||
) : entries.length === 0 ? (
|
||||
/* A response that is not a flat object — an array, a scalar, an error
|
||||
envelope. Shown raw rather than dropped. */
|
||||
<pre className="overflow-x-auto rounded-lg bg-surface-sunken p-3 text-caption text-ink-2">
|
||||
{JSON.stringify(result, null, 2)}
|
||||
</pre>
|
||||
) : (
|
||||
<Stack space="xs">
|
||||
{entries.map(([key, value]) => (
|
||||
<div
|
||||
key={key}
|
||||
className="flex items-center justify-between gap-4 rounded-lg bg-surface-subtle px-3 py-2"
|
||||
>
|
||||
<span className="text-caption uppercase tracking-wide text-ink-3">{titleise(key)}</span>
|
||||
<span className="text-body-sm font-semibold text-ink-1">{renderValue(value)}</span>
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user