supersam/src/components/logistics/LogisticsReadinessBoard.jsx

125 lines
4.7 KiB
JavaScript

import React from "react";
import {
filterOrderGroups,
getOrderGroupDisplayStatusLabel,
getOrderGroupDisplayStatusValue,
getOrderGroupStatusTone,
ORDER_GROUP_DISPLAY_STATUS_OPTIONS,
} from "../../services/orderGroupViews";
import { Badge } from "../UI/Badge";
import { Panel } from "../UI/Panel";
import { OrderFilters } from "../orders/OrderFilters";
const renderOrderNumbers = (group) => {
if (!Array.isArray(group.orderNumbers) || !group.orderNumbers.length) {
return <span>Номера не указаны</span>;
}
return (
<div className="flex flex-wrap gap-2">
{group.orderNumbers.map((number) => (
<span
key={number}
className="rounded-full bg-[var(--color-surface)] px-3 py-1 text-xs text-[var(--color-text-muted)]"
>
{number}
</span>
))}
</div>
);
};
export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusOptions = ORDER_GROUP_DISPLAY_STATUS_OPTIONS }) => {
const [filters, setFilters] = React.useState({ query: "", displayStatus: "all" });
const filteredGroups = React.useMemo(
() => filterOrderGroups(orderGroups, filters),
[filters, orderGroups],
);
// Group by display status value
const statusGroups = React.useMemo(() => {
const map = new Map();
for (const group of filteredGroups) {
const statusValue = getOrderGroupDisplayStatusValue(group);
if (!map.has(statusValue)) {
const label = getOrderGroupDisplayStatusLabel(group);
map.set(statusValue, { label, groups: [] });
}
map.get(statusValue).groups.push(group);
}
return map;
}, [filteredGroups]);
const totalGroups = filteredGroups.length;
return (
<div className="space-y-6">
<Panel className="space-y-4 p-5">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="min-w-0">
<h2 className="text-lg font-semibold">Наборы доставки</h2>
</div>
<Badge tone="neutral">{totalGroups} групп</Badge>
</div>
<OrderFilters
filters={filters}
setFilters={setFilters}
statusOptions={statusOptions}
/>
</Panel>
{!totalGroups ? (
<div className="rounded-[28px] border border-dashed border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4 text-sm text-[var(--color-text-muted)]">
По этому поиску ничего не найдено.
</div>
) : (
<div className="grid gap-6 xl:grid-cols-2">
{Array.from(statusGroups.entries()).map(([statusValue, { label, groups }]) => {
if (!groups.length) return null;
return (
<div key={statusValue} className="space-y-3">
<div className="flex items-center gap-2">
<h3 className="font-semibold">{label}</h3>
<Badge tone="neutral">{groups.length}</Badge>
</div>
{groups.map((group) => (
<button
key={group.id}
className="w-full rounded-[24px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4 !text-left !text-[var(--color-text)] transition hover:bg-[var(--color-accent-soft)] sm:p-5"
onClick={() => {
if (onSelectSet) {
onSelectSet(group.id);
}
}}
type="button"
>
<div className="space-y-2">
<div className="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-3">
<div className="break-words text-base font-semibold leading-tight !text-[var(--color-text)] sm:text-lg">
{group.displayTitle || group.customerName || group.groupKey}
</div>
<Badge className="self-start" tone={getOrderGroupStatusTone(group)}>
{getOrderGroupDisplayStatusLabel(group)}
</Badge>
</div>
<div className="text-sm leading-6 text-[var(--color-text-muted)]">
{group.customerDate || "—"} · {group.customerPhone || "—"} · {group.ordersCount || 0}{" "}
{group.ordersCount === 1 ? "заказ" : group.ordersCount < 5 ? "заказа" : "заказов"}
</div>
<div>{renderOrderNumbers(group)}</div>
</div>
</button>
))}
</div>
);
})}
</div>
)}
</div>
);
};