ui: restructure filters — search wider on row 1, SMS + hide-completed toggle switch on row 2
This commit is contained in:
parent
0cdd9f52a4
commit
46fac18e28
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessible iOS-style toggle switch.
|
||||||
|
* @param {object} props
|
||||||
|
* @param {boolean} props.checked
|
||||||
|
* @param {function} props.onChange Called with the next boolean value.
|
||||||
|
* @param {string} [props.label] Visible text next to the switch.
|
||||||
|
* @param {string} [props.title] Hover tooltip.
|
||||||
|
* @param {string} [props.className]
|
||||||
|
*/
|
||||||
|
export const Switch = ({ checked = false, onChange, label, title, className = "" }) => {
|
||||||
|
const id = React.useId();
|
||||||
|
return (
|
||||||
|
<label htmlFor={id} className={`inline-flex cursor-pointer select-none items-center gap-2.5 text-sm text-[var(--color-text)] ${className}`} title={title}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id={id}
|
||||||
|
role="switch"
|
||||||
|
aria-checked={checked}
|
||||||
|
onClick={() => onChange && onChange(!checked)}
|
||||||
|
className={`relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border transition-colors ${
|
||||||
|
checked
|
||||||
|
? "border-[var(--color-accent)] bg-[var(--color-accent)]"
|
||||||
|
: "border-[var(--color-border)] bg-[var(--color-surface-strong)]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
className={`inline-block h-5 w-5 transform rounded-full bg-white shadow transition-transform ${
|
||||||
|
checked ? "translate-x-[22px]" : "translate-x-0.5"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
{label ? <span>{label}</span> : null}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,7 @@ import { Button } from "../UI/Button";
|
||||||
import { Input } from "../UI/Input";
|
import { Input } from "../UI/Input";
|
||||||
import { Panel } from "../UI/Panel";
|
import { Panel } from "../UI/Panel";
|
||||||
import { DatePicker } from "../UI/DatePicker";
|
import { DatePicker } from "../UI/DatePicker";
|
||||||
|
import { Switch } from "../UI/Switch";
|
||||||
|
|
||||||
const DropdownSelect = ({ value, options, onChange, placeholder }) => {
|
const DropdownSelect = ({ value, options, onChange, placeholder }) => {
|
||||||
const [isOpen, setIsOpen] = React.useState(false);
|
const [isOpen, setIsOpen] = React.useState(false);
|
||||||
|
|
@ -129,8 +130,8 @@ export const OrderFilters = ({ filters, setFilters, statusOptions = [], cities =
|
||||||
return (
|
return (
|
||||||
<Panel className="p-4">
|
<Panel className="p-4">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{/* Row 1: Status + City + DeliveryType + Search */}
|
{/* Row 1: Status + City + DeliveryType + Search (search spans wider) */}
|
||||||
<div className="grid gap-3 md:grid-cols-[minmax(12rem,0.7fr)_minmax(0,0.5fr)_minmax(0,0.5fr)_minmax(0,1.4fr)] md:items-end">
|
<div className="grid gap-3 md:grid-cols-[minmax(12rem,0.7fr)_minmax(0,0.5fr)_minmax(0,0.5fr)_minmax(0,1.6fr)] md:items-end">
|
||||||
<div ref={statusMenuRef} className="relative flex min-w-0 flex-col gap-2">
|
<div ref={statusMenuRef} className="relative flex min-w-0 flex-col gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -196,29 +197,6 @@ export const OrderFilters = ({ filters, setFilters, statusOptions = [], cities =
|
||||||
placeholder="Тип получения"
|
placeholder="Тип получения"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex items-end gap-3">
|
|
||||||
<DropdownSelect
|
|
||||||
value={filters.smsStatus || "all"}
|
|
||||||
options={smsProblemOptions}
|
|
||||||
onChange={(v) => updateFilter("smsStatus", v)}
|
|
||||||
placeholder="Проблемы SMS"
|
|
||||||
/>
|
|
||||||
{typeof onToggleHideCompleted === "function" && (
|
|
||||||
<label
|
|
||||||
className="mb-0.5 flex shrink-0 cursor-pointer select-none items-center gap-2 text-sm text-[var(--color-text)]"
|
|
||||||
title="Доставленные и отгруженные заказы скрыты"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={hideCompleted}
|
|
||||||
onChange={() => onToggleHideCompleted((prev) => !prev)}
|
|
||||||
className="h-4 w-4 cursor-pointer accent-[var(--color-accent)]"
|
|
||||||
/>
|
|
||||||
<span>Скрыть завершённые</span>
|
|
||||||
</label>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
className="h-[46px] py-0"
|
className="h-[46px] py-0"
|
||||||
placeholder="Поиск по группе, клиенту или телефону"
|
placeholder="Поиск по группе, клиенту или телефону"
|
||||||
|
|
@ -227,8 +205,8 @@ export const OrderFilters = ({ filters, setFilters, statusOptions = [], cities =
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Row 2: Date range */}
|
{/* Row 2: Date range + SMS problems (width matches its text) + hide-completed toggle */}
|
||||||
<div className="flex items-end gap-3 flex-wrap">
|
<div className="flex flex-wrap items-end gap-3">
|
||||||
<DatePicker
|
<DatePicker
|
||||||
value={filters.dateFrom || ""}
|
value={filters.dateFrom || ""}
|
||||||
onChange={(v) => updateFilter("dateFrom", v)}
|
onChange={(v) => updateFilter("dateFrom", v)}
|
||||||
|
|
@ -252,6 +230,23 @@ export const OrderFilters = ({ filters, setFilters, statusOptions = [], cities =
|
||||||
✕ Сбросить
|
✕ Сбросить
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<DropdownSelect
|
||||||
|
value={filters.smsStatus || "all"}
|
||||||
|
options={smsProblemOptions}
|
||||||
|
onChange={(v) => updateFilter("smsStatus", v)}
|
||||||
|
placeholder="Проблемы SMS"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{typeof onToggleHideCompleted === "function" && (
|
||||||
|
<Switch
|
||||||
|
checked={hideCompleted}
|
||||||
|
onChange={onToggleHideCompleted}
|
||||||
|
label="Скрыть завершённые"
|
||||||
|
title="Доставленные и отгруженные заказы скрыты"
|
||||||
|
className="mb-0.5"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue