feat(order-detail): collapsible order composition with table layout
- Extracted IIFE into CollapsibleOrderComposition component to fix React hooks error - Состав заказа свернут по умолчанию, разворачивается по клику - Позиции отображаются в табличном виде (grid 1fr + auto) - Количество и единицы измерения не обрезаются (whitespace-nowrap) - Парсинг работает из source_orders, order_list, order_list_structured
This commit is contained in:
parent
0d3be0502c
commit
a2196d232b
|
|
@ -232,6 +232,64 @@ const normalizeDateForInput = (value) => {
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CollapsibleOrderComposition = ({ order }) => {
|
||||||
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||||
|
const orders = parseOrderList(order);
|
||||||
|
const totalPositions = orders.reduce((sum, o) => sum + (o.items?.length || 0), 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="flex w-full items-center justify-between text-left"
|
||||||
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
|
>
|
||||||
|
<span className="font-semibold">Состав заказа</span>
|
||||||
|
<span className="flex items-center gap-2 text-sm text-[var(--color-text-muted)]">
|
||||||
|
{totalPositions > 0 ? `${totalPositions} поз.` : ''}
|
||||||
|
<svg
|
||||||
|
className="h-4 w-4 transition-transform"
|
||||||
|
style={{ transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)' }}
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={2}
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
{isExpanded && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{!orders.length ? (
|
||||||
|
<p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>
|
||||||
|
) : (
|
||||||
|
orders.map((orderItem, idx) => (
|
||||||
|
<div key={idx} className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4">
|
||||||
|
<p className="font-medium !text-[var(--color-text)] mb-3 text-sm">{orderItem.nom || orderItem.name || `Заказ ${idx + 1}`}</p>
|
||||||
|
{orderItem.items && orderItem.items.length > 0 ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{orderItem.items.map((item, itemIdx) => (
|
||||||
|
<div key={itemIdx} className="grid grid-cols-[1fr_auto] gap-x-4 gap-y-1 text-sm">
|
||||||
|
<span className="text-[var(--color-text)] min-w-0">{item.product_name || item.name || item.title || ''}</span>
|
||||||
|
<span className="text-[var(--color-text-muted)] whitespace-nowrap text-right">
|
||||||
|
{item.product_quantity || item.quantity || item.count || item.amount || ""} {item.product_ed || item.unit || ""}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const OrderDetailPanel = ({
|
export const OrderDetailPanel = ({
|
||||||
order,
|
order,
|
||||||
canManageDelivery = false,
|
canManageDelivery = false,
|
||||||
|
|
@ -693,36 +751,8 @@ export const OrderDetailPanel = ({
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
<Panel className="space-y-4 p-5">
|
<Panel className="space-y-4 p-5">
|
||||||
<strong>Состав заказа</strong>
|
<CollapsibleOrderComposition order={order} />
|
||||||
<div className="space-y-3">
|
|
||||||
{(() => {
|
|
||||||
const orders = parseOrderList(order);
|
|
||||||
if (!orders.length) {
|
|
||||||
return <p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>;
|
|
||||||
}
|
|
||||||
return orders.map((orderItem, idx) => (
|
|
||||||
<div key={idx} className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4">
|
|
||||||
<p className="font-medium !text-[var(--color-text)] mb-2">{orderItem.nom || orderItem.name || `Заказ ${idx + 1}`}</p>
|
|
||||||
{orderItem.items && orderItem.items.length > 0 ? (
|
|
||||||
<div className="space-y-1">
|
|
||||||
{orderItem.items.map((item, itemIdx) => (
|
|
||||||
<div key={itemIdx} className="flex justify-between text-sm">
|
|
||||||
<span className="text-[var(--color-text)]">{item.product_name || item.name || item.title || JSON.stringify(item)}</span>
|
|
||||||
<span className="text-[var(--color-text-muted)]">
|
|
||||||
{item.product_quantity || item.quantity || item.count || item.amount || ""} {item.product_ed || item.unit || ""}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
{userRole !== "driver" ? (
|
{userRole !== "driver" ? (
|
||||||
<Panel className="space-y-4 p-5">
|
<Panel className="space-y-4 p-5">
|
||||||
<strong>Дополнительные данные</strong>
|
<strong>Дополнительные данные</strong>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue