fix: order numbers clickable+copy, expandable sub-accounts, preserve delivery address on pickup switch, opaque calendar, tab-aware date label
This commit is contained in:
parent
005d4467bc
commit
fb5728ba43
|
|
@ -76,6 +76,34 @@ const DELIVERY_TIME_ALIASES = {
|
||||||
"После обеда": "Вторая половина дня",
|
"После обеда": "Вторая половина дня",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CollapsibleChips = ({ label, items }) => {
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
if (!Array.isArray(items) || items.length === 0) return null;
|
||||||
|
return (
|
||||||
|
<span className="inline">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="ml-1 cursor-pointer rounded-full bg-[var(--color-surface)] px-2 py-0.5 text-xs font-medium text-[var(--color-text-muted)] transition hover:bg-[var(--color-accent-soft)] hover:text-[var(--color-accent)]"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
>
|
||||||
|
{label} {open ? "▲" : "▼"}
|
||||||
|
</button>
|
||||||
|
{open && (
|
||||||
|
<span className="ml-1 inline-flex flex-wrap gap-1">
|
||||||
|
{items.map((item, idx) => (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className="cursor-pointer rounded-full bg-[var(--color-surface)] px-2 py-0.5 text-xs text-[var(--color-text-muted)] transition hover:bg-[var(--color-accent-soft)] hover:text-[var(--color-accent)]"
|
||||||
|
title="Нажмите, чтобы скопировать"
|
||||||
|
onClick={() => { navigator.clipboard?.writeText(item); }}
|
||||||
|
>{item}</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderList = (values) => {
|
const renderList = (values) => {
|
||||||
if (!Array.isArray(values) || !values.length) {
|
if (!Array.isArray(values) || !values.length) {
|
||||||
return <p className="text-sm text-[var(--color-text-muted)]">Нет данных</p>;
|
return <p className="text-sm text-[var(--color-text-muted)]">Нет данных</p>;
|
||||||
|
|
@ -574,7 +602,7 @@ export const OrderDetailPanel = ({
|
||||||
const [deliveryType, setDeliveryType] = React.useState(order?.deliveryType || "delivery");
|
const [deliveryType, setDeliveryType] = React.useState(order?.deliveryType || "delivery");
|
||||||
const [pickupDate, setPickupDate] = React.useState(order?.pickupDate || "");
|
const [pickupDate, setPickupDate] = React.useState(order?.pickupDate || "");
|
||||||
const [pickupTimeSlot, setPickupTimeSlot] = React.useState(DELIVERY_TIME_OPTIONS[0]);
|
const [pickupTimeSlot, setPickupTimeSlot] = React.useState(DELIVERY_TIME_OPTIONS[0]);
|
||||||
const [deliveryAddress, setDeliveryAddress] = React.useState(order?.deliveryAddress || order?.customerAddress || "");
|
const [deliveryAddress, setDeliveryAddress] = React.useState(order?.originalDeliveryAddress || order?.deliveryAddress || order?.customerAddress || "");
|
||||||
const [confirmAction, setConfirmAction] = React.useState(null);
|
const [confirmAction, setConfirmAction] = React.useState(null);
|
||||||
const minSelectableDateKey = React.useMemo(() => getNextSelectableDateKey(), []);
|
const minSelectableDateKey = React.useMemo(() => getNextSelectableDateKey(), []);
|
||||||
const [currentMonth, setCurrentMonth] = React.useState(() => {
|
const [currentMonth, setCurrentMonth] = React.useState(() => {
|
||||||
|
|
@ -613,6 +641,7 @@ export const OrderDetailPanel = ({
|
||||||
setDeliveryType(order?.deliveryType || "delivery");
|
setDeliveryType(order?.deliveryType || "delivery");
|
||||||
setPickupDate(order?.pickupDate || "");
|
setPickupDate(order?.pickupDate || "");
|
||||||
setPickupTimeSlot(normalizeDeliveryTimeChoice(order?.pickupTimeSlot || order?.deliveryTime || order?.deliveryHalfDay));
|
setPickupTimeSlot(normalizeDeliveryTimeChoice(order?.pickupTimeSlot || order?.deliveryTime || order?.deliveryHalfDay));
|
||||||
|
setDeliveryAddress(order?.originalDeliveryAddress || order?.deliveryAddress || order?.customerAddress || "");
|
||||||
setFormMessage("");
|
setFormMessage("");
|
||||||
}, [order?.id, order?.deliveryDate, order?.deliveryHalfDay, order?.deliveryTime, order?.deliveryType, order?.pickupDate, order?.pickupTimeSlot]);
|
}, [order?.id, order?.deliveryDate, order?.deliveryHalfDay, order?.deliveryTime, order?.deliveryType, order?.pickupDate, order?.pickupTimeSlot]);
|
||||||
|
|
||||||
|
|
@ -655,7 +684,7 @@ export const OrderDetailPanel = ({
|
||||||
deliveryDate: deliveryType === "pickup" ? pickupDate : deliveryDate,
|
deliveryDate: deliveryType === "pickup" ? pickupDate : deliveryDate,
|
||||||
deliveryTime: deliveryType === "pickup" ? pickupTimeSlot : deliveryTime,
|
deliveryTime: deliveryType === "pickup" ? pickupTimeSlot : deliveryTime,
|
||||||
deliveryType,
|
deliveryType,
|
||||||
...(deliveryType === "pickup" ? { pickupDate, pickupTimeSlot, deliveryAddress: "" } : {}),
|
...(deliveryType === "pickup" ? { pickupDate, pickupTimeSlot } : {}),
|
||||||
...(deliveryType === "delivery" ? { deliveryAddress: deliveryAddress.trim() } : {}),
|
...(deliveryType === "delivery" ? { deliveryAddress: deliveryAddress.trim() } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -800,9 +829,19 @@ export const OrderDetailPanel = ({
|
||||||
if (mainNumbers.length > 0) {
|
if (mainNumbers.length > 0) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<span className="font-bold">{mainNumbers.join(", ")}</span>
|
{mainNumbers.map((num, idx) => (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className="mr-1 cursor-pointer rounded-full bg-[var(--color-accent-soft)] px-2.5 py-0.5 text-sm font-bold text-[var(--color-accent)] transition hover:opacity-80 active:opacity-60"
|
||||||
|
title="Нажмите, чтобы скопировать"
|
||||||
|
onClick={() => { navigator.clipboard?.writeText(num); }}
|
||||||
|
>{num}</span>
|
||||||
|
))}
|
||||||
{extraNumbers.length > 0 && (
|
{extraNumbers.length > 0 && (
|
||||||
<span className="text-[var(--color-text-muted)]"> +{extraNumbers.length} сч.</span>
|
<CollapsibleChips
|
||||||
|
label={`+${extraNumbers.length} сч.`}
|
||||||
|
items={extraNumbers}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
@ -921,7 +960,7 @@ export const OrderDetailPanel = ({
|
||||||
disabled={isSavingDeliveryChoice}
|
disabled={isSavingDeliveryChoice}
|
||||||
className="text-sm"
|
className="text-sm"
|
||||||
>
|
>
|
||||||
Изменить {(order.deliveryType === "pickup" || order.deliveryStatus === "pickup" || order.delivery_status === "pickup") ? "дату самовывоза" : "дату доставки"}
|
Изменить дату {deliveryType === "pickup" ? "самовывоза" : "доставки"}
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -939,7 +978,7 @@ export const OrderDetailPanel = ({
|
||||||
<span aria-hidden="true" className="text-[var(--color-text-muted)]">▾</span>
|
<span aria-hidden="true" className="text-[var(--color-text-muted)]">▾</span>
|
||||||
</button>
|
</button>
|
||||||
{isCalendarOpen ? (
|
{isCalendarOpen ? (
|
||||||
<div className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface)] p-3 shadow-soft absolute left-0 top-full z-50 mt-2 w-[300px]">
|
<div className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-3 shadow-lg absolute left-0 top-full z-50 mt-2 w-[300px]">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<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)]">
|
||||||
|
|
@ -1070,7 +1109,7 @@ export const OrderDetailPanel = ({
|
||||||
<span aria-hidden="true" className="text-[var(--color-text-muted)]">▾</span>
|
<span aria-hidden="true" className="text-[var(--color-text-muted)]">▾</span>
|
||||||
</button>
|
</button>
|
||||||
{isCalendarOpen ? (
|
{isCalendarOpen ? (
|
||||||
<div className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface)] p-3 shadow-soft absolute left-0 top-full z-50 mt-2 w-[300px]">
|
<div className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-3 shadow-lg absolute left-0 top-full z-50 mt-2 w-[300px]">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">Календарь самовывоза</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-[var(--color-text-muted)]">Календарь самовывоза</p>
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,9 @@ export const mapOrderGroupRowToDeliveryGroup = (row) => {
|
||||||
? "pickup"
|
? "pickup"
|
||||||
: (row.delivery_type || "delivery");
|
: (row.delivery_type || "delivery");
|
||||||
|
|
||||||
// Clear placeholder pickup address
|
// Preserve original address for pre-filling delivery form (don't clear for pickup)
|
||||||
|
const originalDeliveryAddress = deliveryAddress;
|
||||||
|
// For display: show nothing for pickup placeholder addresses
|
||||||
const resolvedDeliveryAddress = (effectiveDeliveryType === "pickup" && (deliveryAddress.toUpperCase() === "САМОВЫВОЗ" || !deliveryAddress))
|
const resolvedDeliveryAddress = (effectiveDeliveryType === "pickup" && (deliveryAddress.toUpperCase() === "САМОВЫВОЗ" || !deliveryAddress))
|
||||||
? ""
|
? ""
|
||||||
: deliveryAddress;
|
: deliveryAddress;
|
||||||
|
|
@ -170,6 +172,7 @@ export const mapOrderGroupRowToDeliveryGroup = (row) => {
|
||||||
customerPhoneNormalized: parsedKey.phone || normalizePhone(customerPhone),
|
customerPhoneNormalized: parsedKey.phone || normalizePhone(customerPhone),
|
||||||
customerDate,
|
customerDate,
|
||||||
deliveryAddress: resolvedDeliveryAddress,
|
deliveryAddress: resolvedDeliveryAddress,
|
||||||
|
originalDeliveryAddress,
|
||||||
customerAddress,
|
customerAddress,
|
||||||
city,
|
city,
|
||||||
assignedDriverId: row.assigned_driver_id || null,
|
assignedDriverId: row.assigned_driver_id || null,
|
||||||
|
|
@ -277,7 +280,6 @@ export const updateOrderGroupDeliveryChoice = async ({
|
||||||
if (deliveryType === "pickup") {
|
if (deliveryType === "pickup") {
|
||||||
updatePayload.pickup_date = pickupDate || null;
|
updatePayload.pickup_date = pickupDate || null;
|
||||||
updatePayload.pickup_time_slot = pickupTimeSlot || null;
|
updatePayload.pickup_time_slot = pickupTimeSlot || null;
|
||||||
updatePayload.delivery_address = "";
|
|
||||||
} else {
|
} else {
|
||||||
updatePayload.pickup_date = null;
|
updatePayload.pickup_date = null;
|
||||||
updatePayload.pickup_time_slot = null;
|
updatePayload.pickup_time_slot = null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue