const DriverShipmentReport = ({ shipmentData }) => { if (!Array.isArray(shipmentData) || shipmentData.length === 0) return null; return (
Проблемы с доставкой позиций

Не доставлено {shipmentData.length} {shipmentData.length === 1 ? "позиция" : shipmentData.length < 5 ? "позиции" : "позиций"}. Остальное — доставлено.

{shipmentData.map((item) => (
{item.name} {item.quantity || item.unit ? ( {[item.quantity, item.unit].filter(Boolean).join(" ")} ) : null}
{item.comment ? (

Причина: {item.comment}

) : (

Причина не указана

)}
))}
); }; import React from "react"; import { formatDateTime } from "../../utils/formatters"; import { Badge } from "../UI/Badge"; import { Button } from "../UI/Button"; import { Panel } from "../UI/Panel"; import { DriverShipmentPanel } from "../driver/DriverShipmentPanel"; import { CalendarWidget } from "./CalendarWidget"; import { StatusActionPanel } from "./StatusActionPanel"; import { DriverAssignmentPanel } from "./DriverAssignmentPanel"; import { matchesStopWord, useStopWords } from "../../hooks/useStopWords"; import { getOrderGroupDeliveryStatusLabel, getOrderGroupDisplayStatusLabel, getOrderGroupStatusTone, DELIVERY_GROUP_STATUS_LABELS, } from "../../services/orderGroupViews"; import { getErrorMessage, normalizeNom } from "../../utils/deliveryUtils"; const DELIVERY_TIME_OPTIONS = ["Первая половина дня", "Вторая половина дня"]; const STATUS_LABELS = DELIVERY_GROUP_STATUS_LABELS; const ConfirmModal = ({ open, title, message, onConfirm, onCancel }) => { if (!open) return null; return (
e.stopPropagation()}> {title &&

{title}

} {message &&

{message}

}
); }; const DELIVERY_TIME_ALIASES = { "До обеда": "Первая половина дня", "После обеда": "Вторая половина дня", }; const CollapsibleChips = ({ label, items }) => { const [open, setOpen] = React.useState(false); if (!Array.isArray(items) || items.length === 0) return null; return ( {open && ( {items.map((item, idx) => ( { navigator.clipboard?.writeText(item); }} >{item} ))} )} ); }; const renderList = (values) => { if (!Array.isArray(values) || !values.length) { return

Нет данных

; } return (
{values.map((value, index) => ( {value} ))}
); }; const renderValue = (value) => value || "Нет данных"; const getAllBillNumbers = (order) => { const orders = parseOrderList(order); if (!orders.length) return order.orderNumbers || []; return orders.map((o) => o.nom || o.name || '').filter(Boolean); }; const parseOrderList = (order) => { if (!order) return []; // Try orderList first (Supabase JSONB array of positions) if (order.orderList) { let parsed = order.orderList; if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { /* ignore */ } } if (Array.isArray(parsed)) return parsed; } // Fallback: orderListStructured (JSONB with { orders: [...] }) if (order.orderListStructured) { let parsed = order.orderListStructured; if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { /* ignore */ } } if (parsed && Array.isArray(parsed.orders)) return parsed.orders; } // Fallback: sourceOrders (1C exchange data) // 1C sends the FULL order composition (main + associated bills) in EVERY source order's orderList. // We must deduplicate by nom to avoid showing the same items multiple times. if (order.sourceOrders) { let parsed = order.sourceOrders; if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { /* ignore */ } } if (Array.isArray(parsed) && parsed.length > 0) { const seen = new Set(); const allItems = []; for (const src of parsed) { if (src && Array.isArray(src.orderList)) { for (const ol of src.orderList) { if (ol && (ol.items || ol.nom || ol.name)) { const normalizedNom = normalizeNom(ol.nom || ol.name || ''); // Deduplicate by nom — 1C repeats same orderList in every source order if (seen.has(normalizedNom)) continue; seen.add(normalizedNom); allItems.push(ol); } } } } if (allItems.length > 0) return allItems; // Legacy: return whole array if no orderList structure if (parsed[0].orderList && Array.isArray(parsed[0].orderList)) { return parsed[0].orderList; } return parsed; } } return []; }; const normalizeDeliveryTimeChoice = (value) => { const normalized = value ? String(value).trim() : ""; const deliveryTime = DELIVERY_TIME_ALIASES[normalized] || normalized; return DELIVERY_TIME_OPTIONS.includes(deliveryTime) ? deliveryTime : DELIVERY_TIME_OPTIONS[0]; }; const toDateKey = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; const fromDateKey = (value) => { const normalized = normalizeDateForInput(value); if (!normalized) { return null; } const [year, month, day] = normalized.split("-").map(Number); return new Date(year, month - 1, day); }; const addDays = (date, amount) => { const nextDate = new Date(date); nextDate.setDate(nextDate.getDate() + amount); return nextDate; }; const isWeekendDate = (date) => { const day = date.getDay(); return day === 0 || day === 6; }; export const getNextSelectableDateKey = (referenceDate = new Date()) => { let current = addDays(referenceDate, 1); while (isWeekendDate(current)) { current = addDays(current, 1); } return toDateKey(current); }; const normalizePhoneForTel = (phone) => { const cleaned = String(phone || "").trim(); if (!cleaned) return ""; if (cleaned.startsWith("+7")) return cleaned; if (cleaned.startsWith("8")) return "+7" + cleaned.slice(1); return "+7" + cleaned; }; const isFutureDeliveryDate = (value) => { const parsedDate = fromDateKey(value); if (!parsedDate) { return false; } return !isWeekendDate(parsedDate) && toDateKey(parsedDate) >= getNextSelectableDateKey(); }; const formatDateForDisplay = (value) => { if (!value) { return "Выберите дату"; } const [year, month, day] = value.split("-").map(Number); if (!year || !month || !day) { return value; } return new Date(year, month - 1, day).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric", }); }; const formatDeliveryDateDisplay = (value) => { const normalized = normalizeDateForInput(value); if (!normalized) { return renderValue(value); } return formatDateForDisplay(normalized); }; const startOfMonth = (date) => new Date(date.getFullYear(), date.getMonth(), 1); const addMonths = (date, amount) => new Date(date.getFullYear(), date.getMonth() + amount, 1); const buildCalendarDays = (currentMonth) => { const firstDay = startOfMonth(currentMonth); const lastDay = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 0); const firstWeekDay = (firstDay.getDay() + 6) % 7; const totalDays = lastDay.getDate(); const cells = []; for (let index = 0; index < firstWeekDay; index += 1) { cells.push(null); } for (let day = 1; day <= totalDays; day += 1) { cells.push(new Date(currentMonth.getFullYear(), currentMonth.getMonth(), day)); } while (cells.length % 7 !== 0) { cells.push(null); } return cells; }; const normalizeDateForInput = (value) => { if (!value) { return ""; } const normalized = String(value).trim(); if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) { return normalized; } const shortDateMatch = normalized.match(/^(\d{2})\.(\d{2})\.(\d{2})$/); if (shortDateMatch) { const [, day, month, year] = shortDateMatch; return `20${year}-${month}-${day}`; } return ""; }; const CollapsibleOrderComposition = ({ order }) => { const [isExpanded, setIsExpanded] = React.useState(false); const { stopWords, active } = useStopWords(); const orders = parseOrderList(order); const allPositions = orders.reduce((sum, o) => sum + (o.items?.length || 0), 0); const filteredPositions = active ? orders.reduce((sum, o) => { if (!o.items) return sum; return sum + o.items.filter((item) => { const name = String(item.product_name || item.name || item.title || ""); return !matchesStopWord(name, stopWords); }).length; }, 0) : allPositions; return (
{isExpanded && (
{!orders.length ? (

Позиции не указаны

) : ( orders.map((orderItem, idx) => (

{orderItem.nom || orderItem.name || `Заказ ${idx + 1}`}

{(() => { const filtered = (orderItem.items || []).filter((item) => { const name = String(item.product_name || item.name || item.title || ""); return active ? !matchesStopWord(name, stopWords) : true; }); if (filtered.length === 0 && active && (orderItem.items || []).length > 0) { return

Только услуги — скрыты стоп-словами

; } if (filtered.length === 0) { return

Позиции не указаны

; } return (
{filtered.map((item, itemIdx) => (
{item.product_name || item.name || item.title || ''} {item.product_quantity || item.quantity || item.count || item.amount || ""} {item.product_ed || item.unit || ""}
))}
); })()}
)) )}
)}
); }; const PaidStoragePanel = ({ order, onChangeDeliveryStatus, isSavingStatusChange, setFormMessage }) => { const [showConfirm, setShowConfirm] = React.useState(false); const isPaidStorage = (order.deliveryStatus || order.delivery_status) === "paid_storage"; if (isPaidStorage) { return (
Платное хранение
{order.paidStorageAt && (

Переведено: {formatDateTime(order.paidStorageAt)}

)}
); } return (
Платное хранение

Переведите заказ в статус платного хранения, если клиент не забрал товар в срок.

{showConfirm ? (

Перевести заказ в платное хранение? Клиент получит уведомление.

) : ( )}
); }; const PROBLEM_REASONS = [ { value: "client_absent", label: "Клиент не принял", description: "Клиент отказался или не вышел на связь" }, { value: "damage", label: "Повреждение заказа", description: "Товар повреждён при транспортировке" }, { value: "wrong_address", label: "Неверный адрес", description: "Адрес доставки указан неверно" }, { value: "other", label: "Другое", description: "Иная причина проблемы доставки" }, ]; const ProblemReasonModal = ({ onSelect, onCancel }) => (
e.stopPropagation()}>

Причина проблемы

Укажите причину возникшей проблемы с доставкой.

{PROBLEM_REASONS.map((reason) => ( ))}
); export const OrderDetailPanel = ({ order, canManageDelivery = false, onSaveManualDeliveryChoice, isSavingDeliveryChoice = false, isSavingDriverAssignment = false, isSavingStatusChange = false, drivers = [], onAssignDriver, onChangeDeliveryStatus, userRole, }) => { const [problemReason, setProblemReason] = React.useState(null); const [pendingStatus, setPendingStatus] = React.useState(null); const [deliveryDate, setDeliveryDate] = React.useState(""); const [deliveryTime, setDeliveryTime] = React.useState(DELIVERY_TIME_OPTIONS[0]); const [formMessage, setFormMessage] = React.useState(""); const [shipmentState, setShipmentState] = React.useState(null); const [isCalendarOpen, setIsCalendarOpen] = React.useState(false); const [driverMessage, setDriverMessage] = React.useState(""); const [selectedDriverId, setSelectedDriverId] = React.useState(order?.assignedDriverId || ""); const [deliveryType, setDeliveryType] = React.useState(order?.deliveryType || "delivery"); const [pickupDate, setPickupDate] = React.useState(order?.pickupDate || ""); const [pickupTimeSlot, setPickupTimeSlot] = React.useState(DELIVERY_TIME_OPTIONS[0]); const [deliveryAddress, setDeliveryAddress] = React.useState(order?.originalDeliveryAddress || order?.deliveryAddress || order?.customerAddress || ""); const [confirmAction, setConfirmAction] = React.useState(null); const [isEditingDate, setIsEditingDate] = React.useState(false); const handleShipmentChange = React.useCallback((state) => { setShipmentState(state); }, []); const minSelectableDateKey = React.useMemo(() => getNextSelectableDateKey(), []); const [currentMonth, setCurrentMonth] = React.useState(() => { const existingDeliveryDate = fromDateKey(order?.deliveryDate); const fallbackDate = fromDateKey(minSelectableDateKey) || new Date(); const sourceDate = existingDeliveryDate && isFutureDeliveryDate(toDateKey(existingDeliveryDate)) ? existingDeliveryDate : fallbackDate; return startOfMonth(sourceDate); }); const calendarDays = React.useMemo(() => buildCalendarDays(currentMonth), [currentMonth]); const monthLabel = React.useMemo( () => currentMonth.toLocaleDateString("ru-RU", { month: "long", year: "numeric", }), [currentMonth], ); const canGoBack = toDateKey(currentMonth) > toDateKey(startOfMonth(fromDateKey(minSelectableDateKey) || new Date())); React.useEffect(() => { setSelectedDriverId(order?.assignedDriverId || ""); setIsEditingDate(false); }, [order?.id, order?.assignedDriverId]); React.useEffect(() => { const normalizedDeliveryDate = normalizeDateForInput(order?.deliveryDate); const nextSelectableDateKey = getNextSelectableDateKey(); const selectedDateKey = isFutureDeliveryDate(normalizedDeliveryDate) ? normalizedDeliveryDate : nextSelectableDateKey; setDeliveryDate(selectedDateKey); const selectedDate = fromDateKey(selectedDateKey) || new Date(); setCurrentMonth(startOfMonth(selectedDate)); setDeliveryTime(normalizeDeliveryTimeChoice(order?.deliveryTime || order?.deliveryHalfDay)); setDeliveryType(order?.deliveryType || "delivery"); setPickupDate(order?.pickupDate || ""); setPickupTimeSlot(normalizeDeliveryTimeChoice(order?.pickupTimeSlot || order?.deliveryTime || order?.deliveryHalfDay)); setDeliveryAddress(order?.originalDeliveryAddress || order?.deliveryAddress || order?.customerAddress || ""); setFormMessage(""); }, [order?.id, order?.deliveryDate, order?.deliveryHalfDay, order?.deliveryTime, order?.deliveryType, order?.pickupDate, order?.pickupTimeSlot]); if (!order) { return (

Выберите группу для просмотра деталей.

); } const isDeliveryAgreed = ["agreed", "driver_assigned", "loaded", "on_route", "delivered", "picked_up"].includes(order.deliveryStatus || order.delivery_status); const isPickupOrder = order.deliveryType === "pickup" || order.deliveryStatus === "pickup" || order.delivery_status === "pickup"; // Show "agreed" banner only when selected tab matches the already-agreed type const agreedTypeMatchesTab = isDeliveryAgreed && !isEditingDate && ( (deliveryType === "pickup" && isPickupOrder) || (deliveryType === "delivery" && !isPickupOrder) ); const canEditDelivery = canManageDelivery && ["admin", "mega_admin", "logistician"].includes(userRole); const agreedDeliveryLabel = [ formatDeliveryDateDisplay(order.deliveryDate), order.deliveryTime || order.deliveryHalfDay, ].filter((value) => value && value !== "Нет данных").join(" · "); const handleSaveDeliveryChoice = async () => { const effectiveDate = deliveryType === "pickup" ? pickupDate : deliveryDate; const effectiveTime = deliveryType === "pickup" ? pickupTimeSlot : deliveryTime; if (!effectiveDate || !effectiveTime) { setFormMessage(deliveryType === "pickup" ? "Укажите дату и время самовывоза." : "Укажите дату и половину дня доставки."); return; } if (!isFutureDeliveryDate(effectiveDate)) { setFormMessage(deliveryType === "pickup" ? "Выберите дату самовывоза позже сегодняшнего дня." : "Выберите дату доставки позже сегодняшнего дня."); return; } try { const result = await onSaveManualDeliveryChoice?.({ orderGroupId: order.id, deliveryDate: deliveryType === "pickup" ? pickupDate : deliveryDate, deliveryTime: deliveryType === "pickup" ? pickupTimeSlot : deliveryTime, deliveryType, ...(deliveryType === "pickup" ? { pickupDate, pickupTimeSlot } : {}), ...(deliveryType === "delivery" ? { deliveryAddress: deliveryAddress.trim() } : {}), }); if (result?.success) { setFormMessage(deliveryType === "pickup" ? "Самовывоз согласован вручную." : "Доставка согласована вручную."); return; } setFormMessage(getErrorMessage(result?.error, "Не удалось сохранить согласование доставки.")); } catch (error) { setFormMessage(getErrorMessage(error, "Не удалось сохранить согласование доставки.")); } }; const handleAssignDriver = async () => { if (!selectedDriverId) { setDriverMessage("Выберите водителя"); return; } if (!order.deliveryDate) { setDriverMessage("Сначала укажите дату и время доставки."); return; } setDriverMessage(""); const response = await onAssignDriver({ orderGroupId: order.id, driverId: selectedDriverId, }); if (!response.success) { setDriverMessage(response.error || "Не удалось назначить водителя"); } else { setDriverMessage("Водитель назначен"); } }; return (

{isPickupOrder ? "Карточка группы самовывоза" : "Карточка группы доставки"}

{order.displayTitle || order.customerName || order.groupKey}

{(() => { const parts = []; if (order.orderNumbers && order.orderNumbers.length > 0) parts.push(order.orderNumbers.join(", ")); const sub = order.displaySubtitle || [order.customerPhone, order.customerDate].filter(Boolean).join(" · "); if (sub) parts.push(sub); return parts.join(" · ") || "Не указано"; })()}

{getOrderGroupDisplayStatusLabel(order)}
{(() => { const isPickup = isPickupOrder; const deliveryTypeLabel = isPickup ? "Самовывоз" : (order.deliveryStatus === "requires_address" || order.delivery_status === "requires_address") ? "Доставка (требуется адрес)" : "Доставка"; const dateLabel = isPickup ? "Дата самовывоза" : "Дата доставки"; const timeLabel = isPickup ? "Время самовывоза" : "Время доставки"; const addressLabel = isPickup ? "Адрес клиента" : "Адрес доставки"; const effectiveAddress = isPickup ? (order.customerAddress || "") : (order.deliveryAddress || ""); return (

{dateLabel}

{formatDeliveryDateDisplay(order.deliveryDate)}

{timeLabel}

{renderValue(order.deliveryTime || order.deliveryHalfDay)}

Тип

{deliveryTypeLabel}

{(order.deliveryStatus === "requires_address" || order.delivery_status === "requires_address") && (
📍

Адрес доставки не указан

Клиент выбрал доставку, но адрес отсутствует. Уточните адрес у клиента и заполните поле ниже.

)}

Водитель

{order.assignedDriverId ? renderValue(order.assignedDriverName) : (isPickup ? "Не нужен" : "Не назначен")}

Телефон

{renderValue(order.customerPhone)}
{!isPickup || effectiveAddress ? (

{addressLabel}

{renderValue(effectiveAddress)}

) : null}
); })()}

Заказ

{(() => { const mainNumbers = order.orderNumbers || []; const allNumbers = order.allBillNumbers || []; const mainSet = new Set(mainNumbers.map(String)); const extraNumbers = allNumbers.filter((n) => !mainSet.has(String(n))); if (mainNumbers.length > 0) { return ( {mainNumbers.map((num, idx) => ( { navigator.clipboard?.writeText(num); }} >{num} ))} {extraNumbers.length > 0 && ( )} ); } return renderValue(order.orderNumberSummary); })()}

Клиент

{renderValue(order.customerName)}

Дата счёта

{renderValue(order.customerDate)}

Всего заказов

{order.ordersCount ?? 0}

Готово

{order.readyCount ?? 0}

{(order.notReadyCount ?? 0) > 0 ? (

Не готово

{order.notReadyCount}

) : null}

Обновлена

{formatDateTime(order.updatedAt)}

{isPickupOrder ? "Статус самовывоза" : "Статус доставки"}

{getOrderGroupDeliveryStatusLabel(order.deliveryStatus || order.delivery_status)}

{canManageDelivery ? (
Ручное согласование

{isDeliveryAgreed ? "Дата и время уже зафиксированы." : "Если клиент согласовал доставку или самовывоз по телефону, сохраните дату и время здесь."}

{/* Delivery type tabs */}
{deliveryType === "pickup" && (

ℹ️ Условия хранения

Бесплатное хранение — 2 рабочих дня с даты готовности.

Начиная с 3-го рабочего дня — 300 ₽/день платного хранения.

)} {deliveryType === "delivery" && (
setDeliveryAddress(e.target.value)} placeholder="Введите адрес доставки" className="w-full rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] px-4 py-3 text-sm !text-[var(--color-text)] placeholder:text-[var(--color-text-muted)] focus:border-[var(--color-accent)] focus:outline-none" />
)} {agreedTypeMatchesTab ? (

{deliveryType === "pickup" ? "Самовывоз согласован" : "Доставка согласована"}

{agreedDeliveryLabel || "Дата и время сохранены"}

Согласовано
{canEditDelivery ? ( ) : null}
) : deliveryType === "delivery" ? ( { setDeliveryDate(dateKey); setFormMessage(""); }} minDateKey={minSelectableDateKey} isCalendarOpen={isCalendarOpen} setIsCalendarOpen={setIsCalendarOpen} currentMonth={currentMonth} setCurrentMonth={setCurrentMonth} calendarDays={calendarDays} monthLabel={monthLabel} canGoBack={canGoBack} timeOptions={DELIVERY_TIME_OPTIONS} selectedTime={deliveryTime} onTimeChange={(option) => { setDeliveryTime(option); setFormMessage(""); }} layoutClassName="flex flex-col gap-3 md:flex-row md:items-start md:relative md:z-10" calendarClassName="relative space-y-3 md:min-w-0 md:flex-1 md:pr-4" timeClassName="grid gap-2 sm:grid-cols-2 md:w-[320px] md:flex-none" /> ) : ( { setPickupDate(dateKey); setFormMessage(""); }} minDateKey={minSelectableDateKey} isCalendarOpen={isCalendarOpen} setIsCalendarOpen={setIsCalendarOpen} currentMonth={currentMonth} setCurrentMonth={setCurrentMonth} calendarDays={calendarDays} monthLabel={monthLabel} canGoBack={canGoBack} timeOptions={DELIVERY_TIME_OPTIONS} selectedTime={pickupTimeSlot} onTimeChange={(option) => { setPickupTimeSlot(option); setFormMessage(""); }} layoutClassName="space-y-3" calendarClassName="relative" timeClassName="grid gap-2 sm:grid-cols-2" /> )} {formMessage ? (

{formMessage}

) : null}
) : null} {deliveryType === "delivery" && ( { setSelectedDriverId(id); setDriverMessage(""); }} onConfirmDriver={() => setConfirmAction({ type: 'driver' })} driverMessage={driverMessage} drivers={drivers} /> )} { if (action.type === "hint") { setFormMessage(action.hint); } else if (action.type === "status") { setConfirmAction({ type: "status", status: action.status }); } }} /> {formMessage && ["manager", "logistician", "admin", "mega_admin"].includes(userRole) && order && onChangeDeliveryStatus ? (

{formMessage}

) : null} {["manager", "logistician", "admin", "mega_admin"].includes(userRole) && order && onChangeDeliveryStatus ? ( ) : null} {userRole === "driver" && order ? ( ) : null} {userRole === "driver" && order && onChangeDeliveryStatus ? (
Статус доставки

Выберите статус и нажмите «Сохранить».

{problemReason !== null ? ( { setPendingStatus({ value: "problem", reason: reasonValue, reasonLabel }); setProblemReason(null); }} onCancel={() => setProblemReason(null)} /> ) : null}
{(() => { const currentStatus = order.deliveryStatus || order.delivery_status; const IN_TRANSIT_STATUSES = ["loaded", "on_route"]; const isOnRoute = IN_TRANSIT_STATUSES.includes(currentStatus); let statusOptions = []; if (currentStatus === "delivered" || currentStatus === "picked_up" || currentStatus === "problem" || currentStatus === "cancelled" || currentStatus === "paid_storage") { statusOptions = []; } else { statusOptions = [ { value: "delivered", label: "Доставлено" }, { value: "picked_up", label: "Вывезено" }, { value: "problem", label: "Проблема" }, ]; } if (statusOptions.length === 0) return null; return statusOptions.map((statusOption) => { const isSelected = pendingStatus?.value === statusOption.value; const isDeliveredBtn = statusOption.value === "delivered"; const deliveryBlocked = isDeliveredBtn && shipmentState && !shipmentState.canMarkDelivered; return ( ); }); })()}
{pendingStatus ? (
) : null} {formMessage ? (

{formMessage}

) : null}
) : null} Счета {(() => { const mainNumbers = order.orderNumbers || []; const allNumbers = getAllBillNumbers(order); const mainSet = new Set(mainNumbers.map(String)); const extraNumbers = allNumbers.filter((n) => !mainSet.has(String(n))); return (
{mainNumbers.length > 0 && (

Основной счёт

{mainNumbers.map((num, idx) => ( {num} ))}
)} {extraNumbers.length > 0 && (

{mainNumbers.length > 0 ? "Составные заказы" : "Все счета"}

{extraNumbers.map((num, idx) => ( {num} ))}
)} {mainNumbers.length === 0 && extraNumbers.length === 0 && (

Нет данных

)}
); })()}
{userRole !== "driver" && (order?.driver_shipment_data || order?.driverShipmentData) ? ( ) : null} {userRole !== "driver" ? ( Дополнительные данные
{order.firstSmsSentAt ? (

1-е SMS отправлено

{formatDateTime(order.firstSmsSentAt)}

) : null} {order.secondSmsSentAt ? (

2-е SMS отправлено

{formatDateTime(order.secondSmsSentAt)}

) : null} {!order.firstSmsSentAt && !order.secondSmsSentAt ? (

SMS отправлено

Нет

) : null}

Ручное согласование выполнено

{order.manualConfirmationAt ? formatDateTime(order.manualConfirmationAt) : "Нет"}

Платное хранение

{order.paidStorageAt ? formatDateTime(order.paidStorageAt) : "Нет"}

{order.createdFromExchangeAt ? (

Создано из обмена

{formatDateTime(order.createdFromExchangeAt)}

) : null}
) : null} { setConfirmAction(null); handleSaveDeliveryChoice(); }} onCancel={() => setConfirmAction(null)} /> d.id === selectedDriverId)?.name || 'выбранного водителя'} на эту группу?`} onConfirm={() => { setConfirmAction(null); handleAssignDriver(); }} onCancel={() => setConfirmAction(null)} /> { const status = confirmAction.status; setConfirmAction(null); onChangeDeliveryStatus({ orderGroupId: order.id, status }).then((response) => { if (!response.success) setFormMessage(response.error || 'Не удалось обновить статус'); else setFormMessage(''); }); }} onCancel={() => setConfirmAction(null)} />
); };