add: locale to menu drawers

This commit is contained in:
Mahyar Khanbolooki
2025-07-24 15:51:12 +03:30
parent 71069c42ca
commit c5d2a58e02
5 changed files with 88 additions and 40 deletions
+44 -36
View File
@@ -21,6 +21,7 @@ import ComboBox, { DropdownOption } from "@/components/combobox/ComboBox";
import clsx from "clsx"; import clsx from "clsx";
import CategorySmallItemRenderer from "@/components/listview/CategorySmallItemRenderer"; import CategorySmallItemRenderer from "@/components/listview/CategorySmallItemRenderer";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { useTranslation } from "react-i18next";
const categories = new Array(13).fill({ title: "خوراک", icon: "" }); const categories = new Array(13).fill({ title: "خوراک", icon: "" });
@@ -126,31 +127,34 @@ const foods = [
]; ];
const sortings = [ const sortings = [
'محبوب ترین', "PopularityDescending",
'بالاترین امتیاز', "DateDescending",
'جدید ترین', "PriceAscending",
'ارزان ترین', "RateDescending",
'گران ترین', "PriceDescending"
] ]
const contents: Array<DropdownOption> = [
{ id: '0', title: 'گیاهی' },
{ id: '1', title: 'حیوانی' }
]
const shippings: Array<DropdownOption> = [
{ id: '0', title: 'ارسال با پیک', label: '' },
]
const MenuIndex = () => { const MenuIndex = () => {
const { t: tCommon } = useTranslation('common');
const { t: tMenu } = useTranslation('menu', {
keyPrefix: "Menu"
});
const contents: Array<DropdownOption> = [
{ id: '0', title: tMenu('MenuFilterDrawer.SelectContent.Options.Normal'), label: '' },
{ id: '1', title: tMenu('MenuFilterDrawer.SelectContent.Options.Vegan'), label: '' },
]
const shippings: Array<DropdownOption> = [
{ id: '0', title: tMenu('MenuFilterDrawer.SelectDelivery.Options.Courier'), label: '' },
]
const [filterModal, setFilterModal] = useState(false); const [filterModal, setFilterModal] = useState(false);
const [sortingModal, setSortingModal] = useState(false); const [sortingModal, setSortingModal] = useState(false);
const [, setSorting] = useQueryState('sortBy', { defaultValue: '0' }); const [, setSorting] = useQueryState('sortBy', { defaultValue: '0' });
const [search, setSearch] = useQueryState("q", { defaultValue: '' }); const [search, setSearch] = useQueryState("q", { defaultValue: '' });
const [selectedCategory, setSelectedCategory] = useQueryState('category', { defaultValue: '0' }); const [selectedCategory, setSelectedCategory] = useQueryState('category', { defaultValue: '0' });
const [selectedContentId, setSelectedContentId] = useQueryState('contentType', { defaultValue: '0' }); const [selectedIngredients, setSelectedIngredients] = useQueryState('ingredients', { defaultValue: '0' });
const [selectedShippingId, setSelectedShippingId] = useQueryState('shippingType', { defaultValue: '0' }); const [selectedDeliveryId, setSelectedDeliveryId] = useQueryState('delivery', { defaultValue: '0' });
const smallCategoriesRef: React.RefObject<HTMLDivElement | null> = useRef(null); const smallCategoriesRef: React.RefObject<HTMLDivElement | null> = useRef(null);
const wrapperRef: React.RefObject<HTMLDivElement | null> = useRef(null); const wrapperRef: React.RefObject<HTMLDivElement | null> = useRef(null);
const [smallCategoriesVisible, setSmallCategoriesVisibility] = useState(false); const [smallCategoriesVisible, setSmallCategoriesVisibility] = useState(false);
@@ -199,12 +203,12 @@ const MenuIndex = () => {
setSorting(() => String(index)); setSorting(() => String(index));
} }
const changeSelectedContent = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => { const changeSelectedIngredients = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => {
setSelectedContentId(() => contents[index]?.id || contents[0].id); setSelectedIngredients(() => contents[index]?.id || contents[0].id);
} }
const changeSelectedShipping = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => { const changeSelectedDelivery = (e: React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => {
setSelectedShippingId(() => contents[index]?.id || contents[0].id); setSelectedDeliveryId(() => contents[index]?.id || contents[0].id);
} }
const filteredReceiptItems = useMemo(() => { const filteredReceiptItems = useMemo(() => {
@@ -220,7 +224,7 @@ const MenuIndex = () => {
return ( return (
<div className="flex flex-col gap-4 items-center pt-8" ref={wrapperRef}> <div className="flex flex-col gap-4 items-center pt-8" ref={wrapperRef}>
<div className="w-full"> <div className="w-full">
<SearchBox value={search} onChange={updateSearch} /> <SearchBox value={search} placeholder={tCommon('SearchPlaceholder')} onChange={updateSearch} />
<HorizontalScrollView className="w-full noscrollbar mt-4! py-4!"> <HorizontalScrollView className="w-full noscrollbar mt-4! py-4!">
{categories.map((item, index) => ( {categories.map((item, index) => (
<CategoryItemRenderer <CategoryItemRenderer
@@ -251,7 +255,7 @@ const MenuIndex = () => {
<div className="inline-flex gap-2 justify-around items-center"> <div className="inline-flex gap-2 justify-around items-center">
<button onClick={toggleFilterModal} className="rounded-xl h-8 bg-white ps-4 pe-2 py-1.5 inline-flex items-center justify-between gap-[7px]"> <button onClick={toggleFilterModal} className="rounded-xl h-8 bg-white ps-4 pe-2 py-1.5 inline-flex items-center justify-between gap-[7px]">
<EqualizerIcon /> <EqualizerIcon />
<span className="text-xs leading-5 font-medium">فیلتر بر اساس</span> <span className="text-xs leading-5 font-medium">{tMenu('MenuFilterDrawer.Label')}</span>
</button> </button>
<button onClick={toggleSortingModal} className="rounded-lg h-8 bg-white p-1.5"> <button onClick={toggleSortingModal} className="rounded-lg h-8 bg-white p-1.5">
<TextAlignIcon /> <TextAlignIcon />
@@ -298,25 +302,25 @@ const MenuIndex = () => {
</VerticalScrollView> </VerticalScrollView>
</section> </section>
<AnimatedBottomSheet title="فیلتر ها" visible={filterModal} outDelay={150} onClick={toggleFilterModal}> <AnimatedBottomSheet title={tMenu('MenuFilterDrawer.Heading')} visible={filterModal} outDelay={150} onClick={toggleFilterModal}>
<div className="ps-8.5 pe-[31px] mt-[89px]"> <div className="ps-8.5 pe-[31px] mt-[89px]">
<ComboBox <ComboBox
title="محتویات" title={tMenu('MenuFilterDrawer.SelectContent.Label')}
options={contents} options={contents}
selectedId={selectedContentId} selectedId={selectedIngredients}
onSelectionChange={changeSelectedContent} /> onSelectionChange={changeSelectedIngredients} />
<ComboBox <ComboBox
className="relative mt-9.5" className="relative mt-9.5"
title="روش ارسال" title={tMenu('MenuFilterDrawer.SelectDelivery.Label')}
options={shippings} options={shippings}
selectedId={selectedShippingId} selectedId={selectedDeliveryId}
onSelectionChange={changeSelectedShipping} /> onSelectionChange={changeSelectedDelivery} />
<div <div
className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer focus:outline-none focus:ring-2 focus:ring-black" className="flex w-full mt-[23px] h-11 items-center justify-between gap-2 px-3 py-4 relative bg-white/29 rounded-xl border border-solid border-neutral-200 cursor-pointer focus:outline-none focus:ring-2 focus:ring-black"
> >
<span className="inline-flex items-center gap-2.5 text-sm2"> <span className="inline-flex items-center gap-2.5 text-sm2">
<MedalStar size="16" color="#333333" /> <MedalStar size="16" color="#333333" />
دارای امتیاز پس از خرید {tMenu('MenuFilterDrawer.PlusPoint')}
</span> </span>
<Switch className="w-12 h-6" /> <Switch className="w-12 h-6" />
</div> </div>
@@ -325,7 +329,7 @@ const MenuIndex = () => {
> >
<span className="inline-flex items-center gap-2.5 text-sm2"> <span className="inline-flex items-center gap-2.5 text-sm2">
<TicketPercentIcon size={16} /> <TicketPercentIcon size={16} />
دارای کد تخفیف {tMenu('MenuFilterDrawer.DiscountState')}
</span> </span>
<Switch /> <Switch />
</div> </div>
@@ -333,21 +337,25 @@ const MenuIndex = () => {
<hr className="text-white/40 mt-12" /> <hr className="text-white/40 mt-12" />
<div className="px-9 pt-6 flex justify-between gap-[22px]"> <div className="px-9 pt-6 flex justify-between gap-[22px]">
<div className="w-full"> <div className="w-full">
<Button>اعمال فیلتر</Button> <Button>
{tMenu('MenuFilterDrawer.ButtonOk')}
</Button>
</div> </div>
<div className="w-full"> <div className="w-full">
<Button className="bg-disabled! text-disabled-text!">حذف فیلتر</Button> <Button className="bg-disabled! text-disabled-text!">
{tMenu('MenuFilterDrawer.ButtonCancel')}
</Button>
</div> </div>
</div> </div>
</AnimatedBottomSheet> </AnimatedBottomSheet>
<AnimatedBottomSheet title="مرتب کردن بر اساس" visible={sortingModal} inDelay={150} onClick={toggleSortingModal}> <AnimatedBottomSheet title={tMenu('MenuSortingDrawer.Heading')} visible={sortingModal} inDelay={150} onClick={toggleSortingModal}>
<div className="px-8.5 py-10 justify-between"> <div className="px-8.5 py-10 justify-between">
{sortings.map((v, i) => { {sortings.map((v, i) => {
return ( return (
<div key={i}> <div key={i}>
<div onClick={() => changeSorting(i)} className="text-sm2 font-medium cursor-pointer"> <div onClick={() => changeSorting(i)} className="text-sm2 font-medium cursor-pointer">
{v} {tMenu('MenuSortingDrawer.Options.' + v)}
</div> </div>
{i < sortings.length - 1 && <hr className="text-white/40 mb-4 mt-4" />} {i < sortings.length - 1 && <hr className="text-white/40 mb-4 mt-4" />}
</div> </div>
+1 -1
View File
@@ -11,7 +11,7 @@ export const metadata: Metadata = {
description: 'Webapp dashboard' description: 'Webapp dashboard'
} }
const i18nNamespaces = ['auth', 'common']; const i18nNamespaces = ['common', 'menu', 'auth'];
export default async function RootLayout({ export default async function RootLayout({
children, children,
+3 -2
View File
@@ -3,17 +3,18 @@ import SearchIcon from '../icons/SearchIcon';
type Props = { type Props = {
value: string; value: string;
placeholder?: string;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}; };
export default function SearchBox({ value, onChange }: Props) { export default function SearchBox({ value, placeholder = '', onChange }: Props) {
return ( return (
<div className="bg-white inline-flex rounded-xl px-4 h-10 w-full items-center content-center"> <div className="bg-white inline-flex rounded-xl px-4 h-10 w-full items-center content-center">
<SearchIcon stroke="#8C90A3" /> <SearchIcon stroke="#8C90A3" />
<input <input
onChange={onChange} onChange={onChange}
value={value} value={value}
placeholder="جستجو" placeholder={placeholder}
className="text-[#8C90A3] block outline-none border-none focus:ring-0 focus:outline-none text-sm px-[7px] h-full items-center w-full" className="text-[#8C90A3] block outline-none border-none focus:ring-0 focus:outline-none text-sm px-[7px] h-full items-center w-full"
type="text" type="text"
/> />
+2 -1
View File
@@ -28,5 +28,6 @@
"Description": "آیا میخواهید از سیستم خارج شوید؟", "Description": "آیا میخواهید از سیستم خارج شوید؟",
"ButtonOk": "بله خارج می‌شوم", "ButtonOk": "بله خارج می‌شوم",
"ButtonCancel": "منصرف شدم" "ButtonCancel": "منصرف شدم"
} },
"SearchPlaceholder": "جستجو"
} }
+38
View File
@@ -0,0 +1,38 @@
{
"Menu": {
"MenuFilterDrawer": {
"Label": "فیلتر بر اساس",
"Heading": "فیلتر ها",
"SelectContent": {
"Label": "محتویات",
"SearchLabel": "جستجو ...",
"Options": {
"Normal": "معمولی",
"Vegan": "گیاهی"
}
},
"SelectDelivery": {
"Label": "روش ارسال",
"SearchLabel": "جستجو ...",
"Options": {
"Courier": "ارسال با پیک"
}
},
"PlusPoint": "دارای امتیاز پس از خرید",
"DiscountState": "دارای کد تخفیف",
"ButtonOk": "اعمال فیلتر",
"ButtonCancel": "حذف فیلتر"
},
"MenuSortingDrawer": {
"Label": "",
"Heading": "مرتب کردن بر اساس",
"Options": {
"PopularityDescending": "محبوب ترین",
"RateDescending": "بالاترین امتیاز",
"DateDescending": "جدیدترین",
"PriceAscending": "ارزان ترین",
"PriceDescending": "گران ترین"
}
}
}
}