merge filter and sort

This commit is contained in:
hamid zarghami
2026-02-14 11:02:09 +03:30
parent ebb3b7d079
commit a8deff9267
6 changed files with 88 additions and 91 deletions
@@ -1,10 +1,11 @@
'use client';
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import Button from "@/components/button/PrimaryButton";
import AnimatedBottomSheet from "@/components/bottomsheet/AnimatedBottomSheet";
import { Switch } from "@/components/ui/switch";
import { TicketPercentIcon } from "lucide-react";
import { TicketPercentIcon, ChevronDown } from "lucide-react";
import clsx from "clsx";
type MenuFilterDrawerProps = {
visible: boolean;
@@ -12,6 +13,9 @@ type MenuFilterDrawerProps = {
searchQuery: string;
onSearchChange: (value: string) => void;
onApply: () => void;
sortings: ReadonlyArray<string>;
activeSortIndex: number;
onSortChange: (index: number) => void;
tMenu: (key: string) => string;
};
@@ -21,15 +25,34 @@ const MenuFilterDrawer = ({
searchQuery,
onSearchChange,
onApply,
sortings,
activeSortIndex,
onSortChange,
tMenu,
}: MenuFilterDrawerProps) => {
const [tempQuery, setTempQuery] = useState(searchQuery);
const [tempSortIndex, setTempSortIndex] = useState(activeSortIndex);
const [sortSelectOpen, setSortSelectOpen] = useState(false);
const sortSelectRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (visible) {
setTempQuery(searchQuery);
setTempSortIndex(activeSortIndex);
setSortSelectOpen(false);
}
}, [visible, searchQuery]);
}, [visible, searchQuery, activeSortIndex]);
useEffect(() => {
if (!sortSelectOpen || !visible) return;
const handleClickOutside = (e: MouseEvent) => {
if (sortSelectRef.current && !sortSelectRef.current.contains(e.target as Node)) {
setSortSelectOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [sortSelectOpen, visible]);
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTempQuery(e.target.value);
@@ -37,12 +60,14 @@ const MenuFilterDrawer = ({
const handleApply = () => {
onSearchChange(tempQuery);
onSortChange(tempSortIndex);
onApply();
onClose();
};
const handleCancel = () => {
setTempQuery(searchQuery);
setTempSortIndex(activeSortIndex);
onClose();
};
@@ -54,6 +79,7 @@ const MenuFilterDrawer = ({
onClick={onClose}
>
<div className="px-6 mt-5">
{/* فیلتر: جستجو */}
<div className="flex flex-col gap-2">
<label className="text-sm2 text-foreground">
{tMenu("MenuFilterDrawer.SelectContent.Label")}
@@ -66,6 +92,7 @@ const MenuFilterDrawer = ({
className="w-full h-11 px-3 py-2.5 rounded-normal border border-border bg-container/29 focus:outline-none focus:ring-2 focus:ring-black text-xs!"
/>
</div>
{/* فیلتر: دارای کد تخفیف */}
<div className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-container/29 rounded-xl border border-solid border-border cursor-pointer focus:outline-none focus:ring-2 focus:ring-black">
<span className="inline-flex items-center gap-2.5 text-sm2">
<TicketPercentIcon size={16} />
@@ -73,6 +100,46 @@ const MenuFilterDrawer = ({
</span>
<Switch />
</div>
{/* مرتب‌سازی - Select با کلیک باز می‌شود */}
<div className="mt-6" ref={sortSelectRef}>
<label className="text-sm2 text-foreground block mb-3">
{tMenu("MenuSortingDrawer.Heading")}
</label>
<button
type="button"
onClick={() => setSortSelectOpen((prev) => !prev)}
className="w-full h-11 px-3 py-2.5 rounded-xl border border-border bg-container/29 flex items-center justify-between gap-2 text-right text-sm2 text-foreground focus:outline-none focus:ring-2 focus:ring-black"
>
<span>{tMenu(`MenuSortingDrawer.Options.${sortings[tempSortIndex]}`)}</span>
<ChevronDown
className={clsx("w-4 h-4 shrink-0 transition-transform", sortSelectOpen && "rotate-180")}
/>
</button>
{sortSelectOpen && (
<div className="mt-1 rounded-xl border border-border bg-container/29 overflow-hidden">
{sortings.map((value, index) => {
const isActive = index === tempSortIndex;
return (
<button
key={value}
type="button"
onClick={() => {
setTempSortIndex(index);
setSortSelectOpen(false);
}}
className={clsx(
"flex items-center justify-between w-full py-3 px-3 text-sm2 transition-colors text-right",
isActive ? "text-primary font-semibold bg-primary/10" : "text-foreground hover:bg-muted/50"
)}
>
<span>{tMenu(`MenuSortingDrawer.Options.${value}`)}</span>
</button>
);
})}
</div>
)}
</div>
</div>
<hr className="text-white/40 mt-12" />
<div className="px-9 pt-6 flex justify-between gap-[22px]">
@@ -1,54 +0,0 @@
'use client';
import AnimatedBottomSheet from "@/components/bottomsheet/AnimatedBottomSheet";
import clsx from "clsx";
import React from "react";
type MenuSortingDrawerProps = {
visible: boolean;
onClose: () => void;
sortings: ReadonlyArray<string>;
activeIndex: number;
onSelect: (index: number) => void;
tMenu: (key: string) => string;
};
const MenuSortingDrawer = ({
visible,
onClose,
sortings,
activeIndex,
onSelect,
tMenu,
}: MenuSortingDrawerProps) => {
return (
<AnimatedBottomSheet
title={tMenu("MenuSortingDrawer.Heading")}
visible={visible}
inDelay={150}
onClick={onClose}
>
<div className="px-8.5 py-10 flex flex-col gap-2">
{sortings.map((value, index) => {
const isActive = index === activeIndex;
return (
<button
key={value}
type="button"
onClick={() => onSelect(index)}
className={clsx(
"flex items-center justify-between py-3 text-sm2 transition-colors",
isActive ? "text-primary font-semibold" : "text-foreground"
)}
>
<span>{tMenu(`MenuSortingDrawer.Options.${value}`)}</span>
</button>
);
})}
</div>
</AnimatedBottomSheet>
);
};
export default MenuSortingDrawer;