fix: add explicit text color and order composition to OrderDetailPanel
This commit is contained in:
parent
f6bbfe1ba2
commit
0056e71b39
|
|
@ -38,6 +38,33 @@ const renderList = (values) => {
|
||||||
|
|
||||||
const renderValue = (value) => value || "Нет данных";
|
const renderValue = (value) => value || "Нет данных";
|
||||||
|
|
||||||
|
const parseOrderList = (order) => {
|
||||||
|
if (!order) return [];
|
||||||
|
|
||||||
|
if (order.order_list_structured) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(order.order_list_structured);
|
||||||
|
if (parsed && Array.isArray(parsed.orders)) {
|
||||||
|
return parsed.orders;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.order_list) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(order.order_list);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
const getErrorMessage = (error, fallbackMessage) => {
|
const getErrorMessage = (error, fallbackMessage) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
return fallbackMessage;
|
return fallbackMessage;
|
||||||
|
|
@ -331,19 +358,19 @@ export const OrderDetailPanel = ({
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
Дата доставки
|
Дата доставки
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-base font-medium text-[var(--color-text)]">{formatDeliveryDateDisplay(order.deliveryDate)}</p>
|
<p className="mt-1 text-base font-medium !text-[var(--color-text)]">{formatDeliveryDateDisplay(order.deliveryDate)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
Время доставки
|
Время доставки
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-base font-medium text-[var(--color-text)]">{renderValue(order.deliveryTime || order.deliveryHalfDay)}</p>
|
<p className="mt-1 text-base font-medium !text-[var(--color-text)]">{renderValue(order.deliveryTime || order.deliveryHalfDay)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
Водитель
|
Водитель
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-base font-medium text-[var(--color-text)]">{order.assignedDriverId ? renderValue(order.assignedDriverName) : "Не назначен"}</p>
|
<p className="mt-1 text-base font-medium !text-[var(--color-text)]">{order.assignedDriverId ? renderValue(order.assignedDriverName) : "Не назначен"}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
|
|
@ -351,7 +378,7 @@ export const OrderDetailPanel = ({
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href={`tel:${normalizePhoneForTel(order.customerPhone)}`}
|
href={`tel:${normalizePhoneForTel(order.customerPhone)}`}
|
||||||
className="mt-1 block text-base font-medium text-[var(--color-accent)] hover:underline"
|
className="mt-1 block text-base font-medium !text-[var(--color-accent)] hover:underline"
|
||||||
>
|
>
|
||||||
{renderValue(order.customerPhone)}
|
{renderValue(order.customerPhone)}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -360,42 +387,42 @@ export const OrderDetailPanel = ({
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">
|
||||||
Адрес доставки
|
Адрес доставки
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-base font-medium text-[var(--color-text)]">{renderValue(order.deliveryAddress)}</p>
|
<p className="mt-1 text-base font-medium !text-[var(--color-text)]">{renderValue(order.deliveryAddress)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-x-4 gap-y-2 grid-cols-2 md:grid-cols-4">
|
<div className="grid gap-x-4 gap-y-2 grid-cols-2 md:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Номер счёта</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Номер счёта</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{renderValue(order.orderNumberSummary)}</p>
|
<p className="font-medium !text-[var(--color-text)]">{renderValue(order.orderNumberSummary)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Клиент</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Клиент</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{renderValue(order.customerName)}</p>
|
<p className="font-medium !text-[var(--color-text)]">{renderValue(order.customerName)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Дата счёта</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Дата счёта</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{renderValue(order.customerDate)}</p>
|
<p className="font-medium !text-[var(--color-text)]">{renderValue(order.customerDate)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Всего заказов</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Всего заказов</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{order.ordersCount ?? 0}</p>
|
<p className="font-medium !text-[var(--color-text)]">{order.ordersCount ?? 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Готово</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Готово</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{order.readyCount ?? 0}</p>
|
<p className="font-medium !text-[var(--color-text)]">{order.readyCount ?? 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Не готово</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Не готово</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{order.notReadyCount ?? 0}</p>
|
<p className="font-medium !text-[var(--color-text)]">{order.notReadyCount ?? 0}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Обновлена</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Обновлена</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{formatDateTime(order.updatedAt)}</p>
|
<p className="font-medium !text-[var(--color-text)]">{formatDateTime(order.updatedAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Статус доставки</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Статус доставки</p>
|
||||||
<p className="font-medium text-[var(--color-text)]">{getOrderGroupDeliveryStatusLabel(order.deliveryStatus || order.delivery_status)}</p>
|
<p className="font-medium !text-[var(--color-text)]">{getOrderGroupDeliveryStatusLabel(order.deliveryStatus || order.delivery_status)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
@ -491,7 +518,7 @@ export const OrderDetailPanel = ({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{isDeliveryAgreed ? (
|
{isDeliveryAgreed ? (
|
||||||
<div className="rounded-[24px] border border-[rgba(18,128,92,0.35)] bg-[var(--color-accent-soft)] p-4 text-[var(--color-text)]">
|
<div className="rounded-[24px] border border-[rgba(18,128,92,0.35)] bg-[var(--color-accent-soft)] p-4 !text-[var(--color-text)]">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-accent)]">
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-accent)]">
|
||||||
|
|
@ -511,7 +538,7 @@ export const OrderDetailPanel = ({
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Дата доставки"
|
aria-label="Дата доставки"
|
||||||
aria-expanded={isCalendarOpen}
|
aria-expanded={isCalendarOpen}
|
||||||
className="flex min-h-[54px] w-full items-center justify-between rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] px-4 text-left text-sm font-medium text-[var(--color-text)] transition hover:border-[var(--color-accent)] focus:border-[var(--color-accent)] focus:outline-none"
|
className="flex min-h-[54px] w-full items-center justify-between rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] px-4 text-left text-sm font-medium !text-[var(--color-text)] transition hover:border-[var(--color-accent)] focus:border-[var(--color-accent)] focus:outline-none"
|
||||||
onClick={() => setIsCalendarOpen((current) => !current)}
|
onClick={() => setIsCalendarOpen((current) => !current)}
|
||||||
>
|
>
|
||||||
<span>{formatDateForDisplay(deliveryDate)}</span>
|
<span>{formatDateForDisplay(deliveryDate)}</span>
|
||||||
|
|
@ -536,7 +563,7 @@ export const OrderDetailPanel = ({
|
||||||
type="button"
|
type="button"
|
||||||
disabled={!canGoBack}
|
disabled={!canGoBack}
|
||||||
aria-label="Предыдущий месяц"
|
aria-label="Предыдущий месяц"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded-full border border-[var(--color-border)] text-sm text-[var(--color-text-muted)] transition hover:border-[var(--color-accent)] hover:text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-40"
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-[var(--color-border)] text-sm text-[var(--color-text-muted)] transition hover:border-[var(--color-accent)] hover:!text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
onClick={() => setCurrentMonth((month) => addMonths(month, -1))}
|
onClick={() => setCurrentMonth((month) => addMonths(month, -1))}
|
||||||
>
|
>
|
||||||
‹
|
‹
|
||||||
|
|
@ -544,7 +571,7 @@ export const OrderDetailPanel = ({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Следующий месяц"
|
aria-label="Следующий месяц"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded-full border border-[var(--color-border)] text-sm text-[var(--color-text-muted)] transition hover:border-[var(--color-accent)] hover:text-[var(--color-text)]"
|
className="flex h-9 w-9 items-center justify-center rounded-full border border-[var(--color-border)] text-sm text-[var(--color-text-muted)] transition hover:border-[var(--color-accent)] hover:!text-[var(--color-text)]"
|
||||||
onClick={() => setCurrentMonth((month) => addMonths(month, 1))}
|
onClick={() => setCurrentMonth((month) => addMonths(month, 1))}
|
||||||
>
|
>
|
||||||
›
|
›
|
||||||
|
|
@ -580,10 +607,10 @@ export const OrderDetailPanel = ({
|
||||||
className={[
|
className={[
|
||||||
"relative flex aspect-square items-center justify-center rounded-xl border text-sm font-semibold transition",
|
"relative flex aspect-square items-center justify-center rounded-xl border text-sm font-semibold transition",
|
||||||
isSelected
|
isSelected
|
||||||
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)] text-[var(--color-text)]"
|
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)] !text-[var(--color-text)]"
|
||||||
: isWeekend
|
: isWeekend
|
||||||
? "border-dashed border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)]"
|
? "border-dashed border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)]"
|
||||||
: "border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)] hover:border-[var(--color-accent)] hover:text-[var(--color-text)]",
|
: "border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)] hover:border-[var(--color-accent)] hover:!text-[var(--color-text)]",
|
||||||
isDisabled ? "cursor-not-allowed opacity-45" : "",
|
isDisabled ? "cursor-not-allowed opacity-45" : "",
|
||||||
].join(" ")}
|
].join(" ")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -622,8 +649,8 @@ export const OrderDetailPanel = ({
|
||||||
className={[
|
className={[
|
||||||
"min-h-[54px] rounded-2xl border px-4 text-left text-sm font-medium transition",
|
"min-h-[54px] rounded-2xl border px-4 text-left text-sm font-medium transition",
|
||||||
deliveryTime === option
|
deliveryTime === option
|
||||||
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)] text-[var(--color-text)]"
|
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)] !text-[var(--color-text)]"
|
||||||
: "border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)] hover:border-[var(--color-accent)] hover:text-[var(--color-text)]",
|
: "border-[var(--color-border)] bg-[var(--color-surface)] text-[var(--color-text-muted)] hover:border-[var(--color-accent)] hover:!text-[var(--color-text)]",
|
||||||
].join(" ")}
|
].join(" ")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeliveryTime(option);
|
setDeliveryTime(option);
|
||||||
|
|
@ -654,6 +681,37 @@ export const OrderDetailPanel = ({
|
||||||
{renderList(order.orderNumbers)}
|
{renderList(order.orderNumbers)}
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
|
<Panel className="space-y-4 p-5">
|
||||||
|
<strong>Состав заказа</strong>
|
||||||
|
<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 || `Заказ ${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}</span>
|
||||||
|
<span className="text-[var(--color-text-muted)]">
|
||||||
|
{item.product_quantity} {item.product_ed}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
{userRole !== "driver" ? (
|
{userRole !== "driver" ? (
|
||||||
<Panel className="space-y-4 p-5">
|
<Panel className="space-y-4 p-5">
|
||||||
<strong>Дополнительные данные</strong>
|
<strong>Дополнительные данные</strong>
|
||||||
|
|
@ -661,29 +719,29 @@ export const OrderDetailPanel = ({
|
||||||
{order.firstSmsSentAt ? (
|
{order.firstSmsSentAt ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">1-е SMS отправлено</p>
|
<p className="text-xs text-[var(--color-text-muted)]">1-е SMS отправлено</p>
|
||||||
<p className="mt-1 font-medium text-[var(--color-text)]">{formatDateTime(order.firstSmsSentAt)}</p>
|
<p className="mt-1 font-medium !text-[var(--color-text)]">{formatDateTime(order.firstSmsSentAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{order.secondSmsSentAt ? (
|
{order.secondSmsSentAt ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">2-е SMS отправлено</p>
|
<p className="text-xs text-[var(--color-text-muted)]">2-е SMS отправлено</p>
|
||||||
<p className="mt-1 font-medium text-[var(--color-text)]">{formatDateTime(order.secondSmsSentAt)}</p>
|
<p className="mt-1 font-medium !text-[var(--color-text)]">{formatDateTime(order.secondSmsSentAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{!order.firstSmsSentAt && !order.secondSmsSentAt ? (
|
{!order.firstSmsSentAt && !order.secondSmsSentAt ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">SMS отправлено</p>
|
<p className="text-xs text-[var(--color-text-muted)]">SMS отправлено</p>
|
||||||
<p className="mt-1 font-medium text-[var(--color-text)]">Нет</p>
|
<p className="mt-1 font-medium !text-[var(--color-text)]">Нет</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Ручное согласование выполнено</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Ручное согласование выполнено</p>
|
||||||
<p className="mt-1 font-medium text-[var(--color-text)]">{order.manualConfirmationAt ? formatDateTime(order.manualConfirmationAt) : "Нет"}</p>
|
<p className="mt-1 font-medium !text-[var(--color-text)]">{order.manualConfirmationAt ? formatDateTime(order.manualConfirmationAt) : "Нет"}</p>
|
||||||
</div>
|
</div>
|
||||||
{order.createdFromExchangeAt ? (
|
{order.createdFromExchangeAt ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-[var(--color-text-muted)]">Создано из обмена</p>
|
<p className="text-xs text-[var(--color-text-muted)]">Создано из обмена</p>
|
||||||
<p className="mt-1 font-medium text-[var(--color-text)]">{formatDateTime(order.createdFromExchangeAt)}</p>
|
<p className="mt-1 font-medium !text-[var(--color-text)]">{formatDateTime(order.createdFromExchangeAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue