feat: Тип column replaces Проблема, red highlight for problem rows, delivery type filter, clean status options
- OrdersTable: replaced 'Проблема' column with 'Тип' (Самовывоз/Доставка) - Problem rows highlighted red (bg rgba danger 10%) - Mobile cards also show Тип label - OrderFilters: added deliveryType dropdown (Доставка/Самовывоз) - filterOrderGroups: filter by deliveryType - useOrderGroups: deliveryType in default filters state - Cleaned ORDER_GROUP_DISPLAY_STATUS_OPTIONS: removed 'Повторное SMS' and 'SMS отправлены' (not used)
This commit is contained in:
parent
8d3d8dc0fe
commit
54386e9710
|
|
@ -105,6 +105,16 @@ export const OrderFilters = ({ filters, setFilters, statusOptions = [], cities =
|
|||
</select>
|
||||
)}
|
||||
|
||||
<select
|
||||
value={filters.deliveryType || ""}
|
||||
onChange={(e) => updateFilter("deliveryType", e.target.value)}
|
||||
className="h-[46px] rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] px-4 text-sm outline-none focus:border-[var(--color-accent)]"
|
||||
>
|
||||
<option value="">Тип получения</option>
|
||||
<option value="delivery">Доставка</option>
|
||||
<option value="pickup">Самовывоз</option>
|
||||
</select>
|
||||
|
||||
<Input
|
||||
className="h-[46px] py-0"
|
||||
placeholder="Поиск по группе, клиенту или телефону"
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ const renderOrderNumbers = (group) => {
|
|||
return `${visible.join(", ")} +${remaining}`;
|
||||
};
|
||||
|
||||
const getDeliveryTypeLabel = (deliveryType) => {
|
||||
if (deliveryType === "pickup") return "Самовывоз";
|
||||
if (deliveryType === "delivery") return "Доставка";
|
||||
return "—";
|
||||
};
|
||||
|
||||
const renderMobileOrderNumbers = (group) => {
|
||||
const numbers = group.allBillNumbers || group.orderNumbers;
|
||||
if (!Array.isArray(numbers) || !numbers.length) {
|
||||
|
|
@ -111,14 +117,21 @@ export const OrdersTable = ({
|
|||
Группы не найдены. Попробуйте изменить поиск или статус.
|
||||
</div>
|
||||
) : null}
|
||||
{orderGroups.map((group) => (
|
||||
{orderGroups.map((group) => {
|
||||
const hasProblem = group.hasDeliveryProblem;
|
||||
const baseClass = "w-full rounded-[22px] border text-left transition";
|
||||
const selectedClass = selectedOrderGroupId === group.id
|
||||
? "border-[var(--color-accent)] bg-[var(--color-accent-soft)]"
|
||||
: hasProblem
|
||||
? "border-[var(--color-danger)] bg-[rgba(201,61,61,0.1)]"
|
||||
: "border-[var(--color-border)] bg-[var(--color-surface-strong)]";
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={group.id}
|
||||
variant="ghost"
|
||||
onClick={() => onOpenOrder(group.id)}
|
||||
className={["w-full rounded-[22px] border text-left transition",
|
||||
selectedOrderGroupId === group.id ? "border-[var(--color-accent)] bg-[var(--color-accent-soft)]" : "border-[var(--color-border)] bg-[var(--color-surface-strong)]",
|
||||
].join(" ")}
|
||||
className={[baseClass, selectedClass].join(" ")}
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<div className="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-3">
|
||||
|
|
@ -136,6 +149,7 @@ export const OrdersTable = ({
|
|||
|
||||
<div className="mt-3 text-sm text-[var(--color-text-muted)]">{buildGroupSummary(group)}</div>
|
||||
<div className="mt-2 text-sm text-[var(--color-text-muted)]">{renderMobileOrderNumbers(group)}</div>
|
||||
<div className="mt-2 text-sm text-[var(--color-text-muted)]">Тип: {getDeliveryTypeLabel(group.deliveryType)}</div>
|
||||
{group.hasDeliveryProblem && (
|
||||
<div className="mt-2 rounded-lg border border-[var(--color-warning)] bg-[var(--color-warning-soft)] px-2 py-1 text-xs">
|
||||
<span className="font-medium text-[var(--color-warning)]">⚠ Проблема с доставкой</span>
|
||||
|
|
@ -151,7 +165,8 @@ export const OrdersTable = ({
|
|||
{formatDateTime(group.updatedAt)}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="hidden overflow-x-auto md:block">
|
||||
|
|
@ -167,14 +182,22 @@ export const OrdersTable = ({
|
|||
<div className="px-5 py-4 font-medium">Статус</div>
|
||||
<div className="px-5 py-4 font-medium">Водитель</div>
|
||||
<div className="px-5 py-4 font-medium">Дата доставки</div>
|
||||
<div className="px-5 py-4 font-medium">Проблема</div>
|
||||
<div className="px-5 py-4 font-medium">Тип</div>
|
||||
<div className="px-5 py-4 font-medium">Обновлён</div>
|
||||
</div>
|
||||
{orderGroups.map((group) => (
|
||||
{orderGroups.map((group) => {
|
||||
const hasProblem = group.hasDeliveryProblem;
|
||||
const rowClassName = `grid grid-cols-[minmax(180px,2.5fr)_minmax(100px,1.2fr)_minmax(100px,1fr)_minmax(80px,1fr)_minmax(120px,1.2fr)_minmax(80px,0.8fr)_minmax(130px,1.2fr)] gap-0 w-full border-t border-[var(--color-border)] text-left transition ${
|
||||
hasProblem
|
||||
? "bg-[rgba(201,61,61,0.1)] hover:bg-[rgba(201,61,61,0.15)]"
|
||||
: "hover:bg-[var(--color-accent-soft)]"
|
||||
} ${selectedOrderGroupId === group.id ? "bg-[var(--color-accent-soft)]" : ""}`;
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={group.id}
|
||||
variant="ghost"
|
||||
className={`grid grid-cols-[minmax(180px,2.5fr)_minmax(100px,1.2fr)_minmax(100px,1fr)_minmax(80px,1fr)_minmax(120px,1.2fr)_minmax(80px,0.8fr)_minmax(130px,1.2fr)] gap-0 w-full border-t border-[var(--color-border)] text-left transition hover:bg-[var(--color-accent-soft)] ${selectedOrderGroupId === group.id ? "bg-[var(--color-accent-soft)]" : ""}`}
|
||||
className={rowClassName}
|
||||
onClick={() => onOpenOrder(group.id)}
|
||||
>
|
||||
<div className="px-5 py-4">
|
||||
|
|
@ -201,26 +224,14 @@ export const OrdersTable = ({
|
|||
)}
|
||||
</div>
|
||||
<div className="px-5 py-4 text-sm">
|
||||
{group.hasDeliveryProblem ? (
|
||||
<div>
|
||||
<span className="text-[var(--color-warning)] font-medium">⚠ Проблема</span>
|
||||
{group.deliveryProblemNote && (
|
||||
<div className="mt-0.5 text-xs text-[var(--color-text-muted)] line-clamp-2">
|
||||
{group.deliveryProblemNote}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : Array.isArray(group?.driverShipmentData) && group.driverShipmentData.length > 0 ? (
|
||||
<span className="text-[var(--color-accent)]">✓ Ок</span>
|
||||
) : (
|
||||
<span className="text-[var(--color-text-muted)]">—</span>
|
||||
)}
|
||||
{getDeliveryTypeLabel(group.deliveryType)}
|
||||
</div>
|
||||
<div className="px-5 py-4 text-sm text-[var(--color-text-muted)]">
|
||||
{formatDateTime(group.updatedAt)}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const useOrderGroups = () => {
|
|||
const [filters, setFilters] = React.useState({
|
||||
query: "",
|
||||
displayStatus: "all",
|
||||
deliveryType: "",
|
||||
});
|
||||
const [selectedOrderGroupId, setSelectedOrderGroupId] = React.useState(null);
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
|
|
|
|||
|
|
@ -305,6 +305,11 @@ export const filterOrderGroups = (groups, filters = {}) => {
|
|||
}
|
||||
}
|
||||
|
||||
const deliveryTypeFilter = (filters.deliveryType || "").trim().toLowerCase();
|
||||
if (deliveryTypeFilter && group.deliveryType !== deliveryTypeFilter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -333,8 +338,6 @@ export const ORDER_GROUP_DISPLAY_STATUS_OPTIONS = [
|
|||
{ value: "delivery:paid_storage", label: DELIVERY_GROUP_STATUS_LABELS.paid_storage },
|
||||
{ value: "delivery:cancelled", label: DELIVERY_GROUP_STATUS_LABELS.cancelled },
|
||||
{ value: "status:manual_required", label: "Требует ручной обработки" },
|
||||
{ value: "status:second_sms_sent", label: "Повторное SMS" },
|
||||
{ value: "status:sms_sent", label: "SMS отправлены" },
|
||||
{ value: "status:ready_for_notification", label: "Готово к уведомлению" },
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue