ui: restructure filters — search wider on row 1, SMS + hide-completed toggle switch on row 2

This commit is contained in:
Hermes 2026-08-19 12:36:27 +02:00
parent 0cdd9f52a4
commit 46fac18e28
2 changed files with 60 additions and 27 deletions

View File

@ -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>
);
};

View File

@ -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>