104 lines
3.3 KiB
JavaScript
104 lines
3.3 KiB
JavaScript
import React from "react";
|
|
import { Button } from "../UI/Button";
|
|
import { Panel } from "../UI/Panel";
|
|
import { formatDeliveryDate, getDeliveryRelativeDayLabel } from "./deliveryDateFormatting";
|
|
|
|
const groupSlotsByDate = (slots) => {
|
|
const groups = new Map();
|
|
|
|
const getSlotPriority = (slot) => {
|
|
const time = String(slot?.time || "").toLowerCase();
|
|
|
|
if (time.includes("первая") || time.includes("до обеда")) {
|
|
return 0;
|
|
}
|
|
|
|
if (time.includes("вторая") || time.includes("после обеда")) {
|
|
return 1;
|
|
}
|
|
|
|
return 2;
|
|
};
|
|
|
|
for (const slot of slots) {
|
|
if (!groups.has(slot.date)) {
|
|
groups.set(slot.date, []);
|
|
}
|
|
|
|
groups.get(slot.date).push(slot);
|
|
}
|
|
|
|
return Array.from(groups.entries())
|
|
.map(([date, dateSlots]) => [
|
|
date,
|
|
[...dateSlots].sort((left, right) => getSlotPriority(left) - getSlotPriority(right)),
|
|
])
|
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
};
|
|
|
|
const getDeliverySlotGroupHeading = (dateStr, referenceDate = new Date()) => {
|
|
const relative = getDeliveryRelativeDayLabel(dateStr, referenceDate);
|
|
const formatted = formatDeliveryDate(dateStr);
|
|
|
|
if (relative) {
|
|
return `Доставка ${relative.charAt(0).toLowerCase()}${relative.slice(1)} · ${formatted}`;
|
|
}
|
|
|
|
return `Доставка ${formatted}`;
|
|
};
|
|
|
|
export { formatDeliveryDate, formatDeliverySlotGroupLabel } from "./deliveryDateFormatting";
|
|
export { getDeliverySlotGroupHeading };
|
|
|
|
export const DeliverySlotsPicker = ({
|
|
slots,
|
|
onSelectSlot,
|
|
selectedSlotId,
|
|
referenceDate = new Date(),
|
|
}) => {
|
|
if (!slots || !slots.length) {
|
|
return (
|
|
<Panel className="p-5 sm:p-6">
|
|
<p className="text-sm text-[var(--color-text-muted)]">Нет доступных слотов для выбора. Логист назначит слот позже.</p>
|
|
</Panel>
|
|
);
|
|
}
|
|
|
|
const grouped = groupSlotsByDate(slots);
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{grouped.map(([date, dateSlots]) => (
|
|
<details key={date} className="group rounded-[28px] border border-[var(--color-border)] bg-[var(--color-surface)] shadow-soft backdrop-blur" open>
|
|
<summary className="cursor-pointer list-none p-5 sm:p-6">
|
|
<div className="flex items-center justify-between gap-3">
|
|
<h4 className="font-medium">{getDeliverySlotGroupHeading(date, referenceDate)}</h4>
|
|
<span className="text-sm text-[var(--color-text-muted)] group-open:hidden">Раскрыть</span>
|
|
<span className="hidden text-sm text-[var(--color-text-muted)] group-open:inline">Свернуть</span>
|
|
</div>
|
|
</summary>
|
|
<div className="px-5 pb-5 sm:px-6 sm:pb-6">
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
{dateSlots.map((slot) => {
|
|
const isSelected = selectedSlotId === slot.id;
|
|
|
|
return (
|
|
<Button
|
|
key={slot.id}
|
|
variant={isSelected ? "primary" : "secondary"}
|
|
aria-pressed={isSelected}
|
|
onClick={() => onSelectSlot(slot)}
|
|
>
|
|
{slot.time}
|
|
{isSelected ? " — Выбрано" : ""}
|
|
</Button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</details>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|