fix: some duplications and tags
This commit is contained in:
@@ -12,16 +12,16 @@ type Props = object
|
||||
|
||||
function FoodPage({ }: Props) {
|
||||
const quantity = useReceiptStore(state => state.items[0]?.quantity || 0);
|
||||
|
||||
const increment = useReceiptStore(state => state.increment);
|
||||
const decrement = useReceiptStore(state => state.decrement);
|
||||
|
||||
const price = 0; // TODO: Replace with actual price if needed
|
||||
|
||||
return (
|
||||
<div className='w-full -translate-y-2'>
|
||||
<div className="relative w-full rounded-2xl overflow-hidden">
|
||||
<Image
|
||||
className='w-full '
|
||||
className='w-full'
|
||||
src={'/assets/images/food-preview-hq.png'}
|
||||
alt='Food image'
|
||||
height={100}
|
||||
@@ -41,9 +41,9 @@ function FoodPage({ }: Props) {
|
||||
|
||||
<div className="relative px-6 pt-6 pb-7.5 bg-white w-full rounded-3xl overflow-hidden -translate-y-6">
|
||||
<div className="w-full inline-flex justify-between items-center">
|
||||
<div className="text-base font-bold">
|
||||
<h5 className="text-base font-bold">
|
||||
کباب چوبی مخصوص
|
||||
</div>
|
||||
</h5>
|
||||
<button className='p-2 bg-[#EAECF0] rounded-lg'>
|
||||
<Heart size={24} className='fill-black' />
|
||||
</button>
|
||||
@@ -65,12 +65,12 @@ function FoodPage({ }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="mt-4 text-xs">
|
||||
محتویات: <br />
|
||||
گوشت، سبزیجات، پیاز، ادویه جات معطر و ....
|
||||
<p>محتویات:</p>
|
||||
<p>گوشت، سبزیجات، پیاز، ادویه جات معطر و ....</p>
|
||||
</div>
|
||||
|
||||
<div className='mt-12 flex justify-between items-center'>
|
||||
<span dir='ltr'>{0} T</span>
|
||||
<span dir='ltr'>{price} T</span>
|
||||
<motion.div
|
||||
whileTap={{ scale: 1.05 }}
|
||||
className="bg-background active:drop-shadow-xs max-w-[115px] rounded-md w-full h-8 inline-flex p-1 justify-between items-center gap-2"
|
||||
@@ -81,7 +81,7 @@ function FoodPage({ }: Props) {
|
||||
className="inline-flex w-full justify-center items-center gap-2"
|
||||
>
|
||||
<PlusIcon />
|
||||
<div className="text-sm2 pt-0.5 font-medium">افزودن</div>
|
||||
<span className="text-sm2 pt-0.5 font-medium">افزودن</span>
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
@@ -100,8 +100,6 @@ function FoodPage({ }: Props) {
|
||||
>
|
||||
{quantity}
|
||||
</motion.div>
|
||||
|
||||
|
||||
<button
|
||||
onClick={() => decrement(0)}
|
||||
className="bg-white hover:bg-white/60 active:bg-white/30 rounded-sm p-2"
|
||||
@@ -117,4 +115,4 @@ function FoodPage({ }: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
export default FoodPage
|
||||
export default FoodPage
|
||||
|
||||
@@ -31,13 +31,14 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
|
||||
const firstTab = () => {
|
||||
return (
|
||||
<div className='py-4'>
|
||||
<div className="bg-container rounded-container shadow-container p-4">
|
||||
<section aria-labelledby="about-title" className='py-4'>
|
||||
<section
|
||||
className="bg-container rounded-container shadow-container p-4">
|
||||
<div className="flex justify-between items-center border-b-[1.5px] border-gray-200 pb-[25px]">
|
||||
<div className="">
|
||||
<div className='text-sm2 font-bold leading-5'>{data.title_fa}</div>
|
||||
<div className="text-sm2 leading-5 mt-4">تاسیس:{data.foundationDate}</div>
|
||||
<div className="text-sm2 leading-5 mt-2">نوع محصولات: {data.offering}</div>
|
||||
<h2 className='text-sm2 font-bold leading-5'>{data.title_fa}</h2>
|
||||
<p className="text-sm2 leading-5 mt-4">تاسیس: {data.foundationDate}</p>
|
||||
<p className="text-sm2 leading-5 mt-2">نوع محصولات: {data.offering}</p>
|
||||
</div>
|
||||
<div className="rounded-normal overflow-clip">
|
||||
<Image
|
||||
@@ -51,7 +52,7 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-[23px]">
|
||||
<div className="text-sm2 font-bold leading-5">درباره مجموعه</div>
|
||||
<h3 className="text-sm2 font-bold leading-5">درباره مجموعه</h3>
|
||||
<p className="text-sm2 leading-5 mt-3 border-spacing-48" style={{ wordSpacing: '0.01em' }}>
|
||||
{data.description}
|
||||
</p>
|
||||
@@ -60,10 +61,11 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
<span className='text-sm2 text-disabled-text font-medium pt-0.5'>عکس های رستوران</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="bg-container rounded-container shadow-container pt-3 pb-3.5 px-[16px] mt-4 grid grid-cols-3 items-center">
|
||||
<div className='text-sm2 font-medium leading-5'>ارتباط</div>
|
||||
<section
|
||||
className="bg-container rounded-container shadow-container pt-3 pb-3.5 px-[16px] mt-4 grid grid-cols-3 items-center">
|
||||
<h2 className='text-sm2 font-medium leading-5'>ارتباط</h2>
|
||||
<div className='col-span-1 text-center flex justify-center gap-4'>
|
||||
{data.contacts.phone &&
|
||||
<a href={`tel://${data.contacts.phone}`} className='bg-[#EAEDF5] p-2 rounded-normal'>
|
||||
@@ -86,18 +88,20 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="bg-container rounded-container shadow-container px-4 pt-6 pb-6 mt-4">
|
||||
<div className='text-sm2 font-medium leading-5'>آدرس</div>
|
||||
<div className='text-sm2 mt-[9px] leading-5'>{data.address}</div>
|
||||
<section className="bg-container rounded-container shadow-container px-4 pt-6 pb-6 mt-4">
|
||||
<h2 className='text-sm2 font-medium leading-5'>آدرس</h2>
|
||||
<p className='text-sm2 mt-[9px] leading-5'>{data.address}</p>
|
||||
<div className='inline-flex gap-2 mt-[23px] items-center '>
|
||||
<Location size={20} className='stroke-disabled-text' />
|
||||
<span className='text-sm2 text-disabled-text '>عکس های رستوران</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="bg-container rounded-container shadow-container py-6 px-4 mt-4 flex justify-between items-center">
|
||||
<section
|
||||
aria-label='ساعات کاری'
|
||||
className="bg-container rounded-container shadow-container py-6 px-4 mt-4 flex justify-between items-center">
|
||||
<div className="flex items-center gap-2 justify-start">
|
||||
<Clock size={16} className='stroke-disabled-text' />
|
||||
<div className='text-sm2 font-medium leading-5 mt-0.5 text-[#8C90A3]'>باز</div>
|
||||
@@ -107,32 +111,36 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
<div className="">
|
||||
<ArrowDown2 size={16} className='stroke-[#292D32]' />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{data.open.map((v, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
style={{ boxShadow: '0px 0px 14px 0px #0000000F' }}
|
||||
className="bg-[#F6F6FA] rounded-container leading-5 py-6 px-4 mt-4 flex justify-between items-center">
|
||||
<div className="text-sm2">
|
||||
{v.day}
|
||||
<section>
|
||||
{data.open.map((v, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
style={{ boxShadow: '0px 0px 14px 0px #0000000F' }}
|
||||
className="bg-[#F6F6FA] rounded-container leading-5 py-6 px-4 mt-4 flex justify-between items-center">
|
||||
<div className="text-sm2">
|
||||
{v.day}
|
||||
</div>
|
||||
<div className='text-sm2 font-light'>
|
||||
{v.close} - {v.open}
|
||||
</div>
|
||||
</div>
|
||||
<div className='text-sm2 font-light'>
|
||||
{v.close} - {v.open}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</section>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const secondTab = () => {
|
||||
|
||||
return (
|
||||
<div className='py-4'>
|
||||
<div className="bg-container rounded-container shadow-container p-4 py-6 grid grid-cols-2 items-center">
|
||||
<section aria-labelledby="reviews-title" className='py-4'>
|
||||
<section
|
||||
aria-label='امتیاز کاربران'
|
||||
className="bg-container rounded-container shadow-container p-4 py-6 grid grid-cols-2 items-center">
|
||||
<div className="text-center font-bold text-5xl">
|
||||
4.1
|
||||
</div>
|
||||
@@ -143,11 +151,11 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
<RateBar className='mt-1' content='2' percentage='12' />
|
||||
<RateBar className='mt-1' content='1' percentage='89' />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="bg-container rounded-container shadow-container pt-3 pb-3.5 px-[16px] mt-4">
|
||||
<section className="bg-container rounded-container shadow-container pt-3 pb-3.5 px-[16px] mt-4">
|
||||
<div className="flex justify-between items-center border-b-[1.5px] border-border pb-2">
|
||||
<div className='text-sm2 font-medium leading-5'>نظرات کاربران</div>
|
||||
<h2 className='text-sm2 font-medium leading-5'>نظرات کاربران</h2>
|
||||
<button onClick={toggleSortingModal} className="rounded-xl h-8 bg-white ps-4 pe-2 py-1.5 inline-flex items-center justify-between gap-[7px]">
|
||||
<EqualizerIcon />
|
||||
<span className="text-xs leading-5 font-medium">{sortings[+sorting]}</span>
|
||||
@@ -155,17 +163,19 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
</div>
|
||||
<div className="">
|
||||
|
||||
<Comment
|
||||
className='pt-8'
|
||||
user='علیرضا عابدزاده'
|
||||
rating={5.0}
|
||||
date='18 آذر 1401'
|
||||
text='لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است'
|
||||
tags={['پیتزا قارچ مخصوص', 'چیز برگر ژیوان']}
|
||||
/>
|
||||
<article>
|
||||
<Comment
|
||||
className='pt-8'
|
||||
user='علیرضا عابدزاده'
|
||||
rating={5.0}
|
||||
date='18 آذر 1401'
|
||||
text='لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است'
|
||||
tags={['پیتزا قارچ مخصوص', 'چیز برگر ژیوان']}
|
||||
/>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<AnimatedBottomSheet title="مرتب کردن بر اساس" visible={sortingModal} inDelay={150} onClick={toggleSortingModal}>
|
||||
<div className="px-8.5 py-10 justify-between">
|
||||
{sortings.map((v, i) => {
|
||||
@@ -180,7 +190,7 @@ function AboutPage({ data }: Readonly<{ data: AboutDataModel; }>) {
|
||||
})}
|
||||
</div>
|
||||
</AnimatedBottomSheet>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function generateStaticParams() {
|
||||
|
||||
async function layout({ children }: Readonly<{ children: React.ReactNode; params: Promise<Params> }>) {
|
||||
return (
|
||||
<div>{children}</div>
|
||||
<>{children}</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ export default async function Page({ params }: { params: Promise<Params> }) {
|
||||
const data = await getAboutData(name);
|
||||
|
||||
return (
|
||||
<div><AboutPage data={data} /></div>
|
||||
<><AboutPage data={data} /></>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ReactQueryProvider } from "@/components/providers/ReactQueryProvider";
|
||||
import ClientSideWrapper from "@/components/wrapper/ClientSideWrapper";
|
||||
import ClientMenuRouteWrapper from "@/components/wrapper/ClientMenuRouteWrapper.tsx";
|
||||
|
||||
@@ -13,12 +12,10 @@ export default function MenuLayout({
|
||||
}>) {
|
||||
|
||||
return (
|
||||
<ReactQueryProvider>
|
||||
<ClientSideWrapper>
|
||||
<ClientMenuRouteWrapper>
|
||||
{children}
|
||||
</ClientMenuRouteWrapper>
|
||||
</ClientSideWrapper>
|
||||
</ReactQueryProvider>
|
||||
<ClientSideWrapper>
|
||||
<ClientMenuRouteWrapper>
|
||||
{children}
|
||||
</ClientMenuRouteWrapper>
|
||||
</ClientSideWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import ClientSideWrapper from "@/components/wrapper/ClientSideWrapper";
|
||||
|
||||
export const metadata = {
|
||||
title: 'Orders',
|
||||
}
|
||||
@@ -11,8 +9,8 @@ export default function MenuLayout({
|
||||
}>) {
|
||||
|
||||
return (
|
||||
<ClientSideWrapper>
|
||||
<>
|
||||
{children}
|
||||
</ClientSideWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+20
-21
@@ -155,37 +155,37 @@ const MenuIndex = () => {
|
||||
const wrapperRef: React.RefObject<HTMLDivElement | null> = useRef(null);
|
||||
const [smallCategoriesVisible, setSmallCategoriesVisibility] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let m_wrapperRef = null;
|
||||
if (wrapperRef.current) {
|
||||
m_wrapperRef = wrapperRef;
|
||||
wrapperRef.current?.parentElement?.addEventListener('scroll', onScroll);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (m_wrapperRef?.current)
|
||||
m_wrapperRef.current?.parentElement?.removeEventListener('scroll', onScroll)
|
||||
}
|
||||
})
|
||||
|
||||
const onScroll = () => {
|
||||
const onScroll = useCallback(() => {
|
||||
if (!wrapperRef?.current?.parentElement?.scrollTop || !smallCategoriesRef.current?.offsetTop) return;
|
||||
if (wrapperRef?.current?.parentElement?.scrollTop >= smallCategoriesRef.current?.offsetTop) {
|
||||
|
||||
if (wrapperRef.current.parentElement.scrollTop >= smallCategoriesRef.current.offsetTop) {
|
||||
setSmallCategoriesVisibility(true);
|
||||
} else {
|
||||
setSmallCategoriesVisibility(false);
|
||||
}
|
||||
}
|
||||
}, [wrapperRef, smallCategoriesRef]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!wrapperRef.current) return;
|
||||
|
||||
const parent = wrapperRef.current.parentElement;
|
||||
if (!parent) return;
|
||||
|
||||
parent.addEventListener('scroll', onScroll);
|
||||
|
||||
return () => {
|
||||
parent.removeEventListener('scroll', onScroll);
|
||||
}
|
||||
}, [onScroll]);
|
||||
|
||||
|
||||
const updateSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [setSearch]);
|
||||
|
||||
const updateCategory = useCallback((id: number) => {
|
||||
setSelectedCategory(String(id));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [setSelectedCategory]);
|
||||
|
||||
const toggleFilterModal = useCallback(() => {
|
||||
setFilterModal((state) => !state);
|
||||
@@ -242,7 +242,6 @@ const MenuIndex = () => {
|
||||
</HorizontalScrollView>
|
||||
|
||||
<section className="w-full">
|
||||
|
||||
<div className="flex justify-between items-center relative" ref={smallCategoriesRef} >
|
||||
<span className="text-base font-medium">
|
||||
{categories[+selectedCategory]?.title}
|
||||
|
||||
@@ -3,22 +3,36 @@ import React from 'react'
|
||||
|
||||
function TransactionsIndex() {
|
||||
return (
|
||||
<div>
|
||||
<div className='font-medium'>کدهای تخفیف</div>
|
||||
<section>
|
||||
<h1 className='font-medium'>کدهای تخفیف</h1>
|
||||
|
||||
<div className='mt-3 bg-container rounded-normal grid grid-cols-4 items-center'>
|
||||
|
||||
<div className='col-span-3 py-9.5 pe-7 ps-5'>
|
||||
<div className='font-bold'>کدهای تخفیف شما</div>
|
||||
<p className='text-xs mt-[7px]'>کد تخفیف مورد نظر را کپی کنید و در بخش پرداخت ها استفاده کنید</p>
|
||||
<section
|
||||
aria-label="درباره کدهای تخفیف"
|
||||
className='mt-3 bg-container rounded-normal grid grid-cols-4 items-center'
|
||||
>
|
||||
<div className='col-span-3 py-9.5 pe-7 ps-5 relative'>
|
||||
<div className='w-full h-full absolute top-0 left-0 overflow-clip'>
|
||||
<svg width="301" height="146" viewBox="0 0 301 146" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.15">
|
||||
<path d="M262.479 152.795C202.8 122.128 120.111 132.267 77.763 175.315C35.4154 218.362 49.3247 278.14 109.004 308.807C168.683 339.474 251.373 329.335 293.721 286.287C336.069 243.24 322.159 183.462 262.479 152.795Z" stroke="#AFAFAF" />
|
||||
<path d="M298.808 115.866C239.129 85.1988 156.44 95.3379 114.092 138.385C71.7445 181.433 85.6538 241.21 145.333 271.877C205.012 302.544 287.702 292.405 330.05 249.358C372.398 206.31 358.488 146.533 298.808 115.866Z" stroke="#AFAFAF" />
|
||||
<path d="M347.543 66.3263C287.863 35.6595 205.174 45.7986 162.826 88.8461C120.479 131.894 134.388 191.671 194.067 222.338C253.747 253.005 336.437 242.866 378.784 199.819C421.132 156.771 407.222 96.9933 347.543 66.3263Z" stroke="#AFAFAF" />
|
||||
<path d="M416.657 -3.92933C356.977 -34.5961 274.288 -24.457 231.941 18.5905C189.593 61.638 203.502 121.415 263.182 152.082C322.861 182.749 405.551 172.61 447.899 129.563C490.246 86.5153 476.336 26.7377 416.657 -3.92933Z" stroke="#AFAFAF" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className='font-bold text-base'>کدهای تخفیف شما</h2>
|
||||
<p className='text-xs mt-[7px]'>کد تخفیف مورد نظر را کپی کنید و در بخش پرداختها استفاده کنید</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ background: 'linear-gradient(165.51deg, #000000 -8.44%, #C3C7DD 100%)' }}
|
||||
className='col-span-1 h-full text-end py-4 px-5.5 flex flex-col justify-between rounded-e-normal'>
|
||||
<p className='text-sm2 text-white'>
|
||||
<span className='font-medium'>Your</span>
|
||||
<br />
|
||||
className='col-span-1 h-full text-end py-4 px-5.5 flex flex-col justify-between rounded-e-normal'
|
||||
style={{
|
||||
background: 'linear-gradient(165.51deg, #000000 -8.44%, #C3C7DD 100%)',
|
||||
}}
|
||||
>
|
||||
<p className='text-sm2 text-white leading-tight'>
|
||||
<span className='font-medium'>Your</span><br />
|
||||
<span className='font-bold'>Coupon</span>
|
||||
</p>
|
||||
|
||||
@@ -43,47 +57,34 @@ function TransactionsIndex() {
|
||||
<path d="M71.3666 0H68.209V20H71.3666V0Z" fill="white" />
|
||||
</svg>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div className='mt-6 bg-container rounded-normal flex justify-between items-center'>
|
||||
<div className='col-span-3 py-4 pe-7 ps-5 border-e-2 w-full border-border border-dashed'>
|
||||
<div className='font-bold text-sm2'>مبلغ تخفیف: 50,000 تومان</div>
|
||||
<p className='text-xs mt-[7px]'>قابل استفاده برای همه ی منو ها و محصولات</p>
|
||||
<Button className='font-light! w-fit! px-10 py-1.5 mt-4 text-xs rounded-lg'>کپی کد</Button>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-sm2 transform -rotate-90 text-[#B2B2B2] font-medium'>
|
||||
F12BB587
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-6 bg-container rounded-normal flex justify-between items-center'>
|
||||
<div className='col-span-3 py-4 pe-7 ps-5 border-e-2 w-full border-border border-dashed'>
|
||||
<div className='font-bold text-sm2'>مبلغ تخفیف: 50,000 تومان</div>
|
||||
<p className='text-xs mt-[7px]'>قابل استفاده برای همه ی منو ها و محصولات</p>
|
||||
<Button className='font-light! w-fit! px-10 py-1.5 mt-4 text-xs rounded-lg'>کپی کد</Button>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-sm2 transform -rotate-90 text-[#B2B2B2] font-medium'>
|
||||
F12BB587
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-6 bg-container rounded-normal flex justify-between items-center'>
|
||||
<div className='col-span-3 py-4 pe-7 ps-5 border-e-2 w-full border-border border-dashed'>
|
||||
<div className='font-bold text-sm2'>مبلغ تخفیف: 50,000 تومان</div>
|
||||
<p className='text-xs mt-[7px]'>قابل استفاده برای همه ی منو ها و محصولات</p>
|
||||
<Button className='font-light! w-fit! px-10 py-1.5 mt-4 text-xs rounded-lg'>کپی کد</Button>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-sm2 transform -rotate-90 text-[#B2B2B2] font-medium'>
|
||||
F12BB587
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section className="mt-6 space-y-6" aria-label="لیست کدهای تخفیف">
|
||||
{[1, 2, 3].map((_, i) => (
|
||||
<article
|
||||
key={i}
|
||||
className='bg-container rounded-normal flex justify-between items-center'
|
||||
>
|
||||
<div className='py-4 pe-7 ps-5 border-e-2 w-full border-border border-dashed'>
|
||||
<h3 className='font-bold text-sm2'>مبلغ تخفیف: 50,000 تومان</h3>
|
||||
<p className='text-xs mt-[7px]'>قابل استفاده برای همهی منوها و محصولات</p>
|
||||
<Button
|
||||
className='w-fit px-10 py-1.5 mt-4 text-xs rounded-lg font-light'
|
||||
aria-label="کپی کد تخفیف"
|
||||
>
|
||||
کپی کد
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<p className='text-sm2 transform -rotate-90 text-[#B2B2B2] font-medium' aria-label="کد تخفیف">
|
||||
F12BB587
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</section>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default TransactionsIndex
|
||||
export default TransactionsIndex
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
import { ReactQueryProvider } from '@/components/providers/ReactQueryProvider'
|
||||
import { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -8,10 +6,8 @@ export const metadata: Metadata = {
|
||||
|
||||
export default function AuthLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ReactQueryProvider>
|
||||
<div className="h-full">
|
||||
{children}
|
||||
</div>
|
||||
</ReactQueryProvider>
|
||||
<main className="h-full">
|
||||
{children}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,5 +1,6 @@
|
||||
import { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import { ReactQueryProvider } from "@/components/providers/ReactQueryProvider";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Dashboard',
|
||||
@@ -19,7 +20,9 @@ export default function RootLayout({
|
||||
dir="rtl"
|
||||
className={`antialiased bg-background h-full`}
|
||||
>
|
||||
{children}
|
||||
<ReactQueryProvider>
|
||||
{children}
|
||||
</ReactQueryProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
"use client"
|
||||
|
||||
import { ReactQueryProvider } from '@/components/providers/ReactQueryProvider'
|
||||
|
||||
export default function ProfileLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ReactQueryProvider>
|
||||
<main className="h-full p-4">
|
||||
{children}
|
||||
</main>
|
||||
</ReactQueryProvider>
|
||||
<main className="h-full p-4">
|
||||
{children}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
+116
-151
@@ -1,8 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import React, { useMemo, useRef, useState } from 'react'
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { motion, PanInfo, Variants } from 'framer-motion';
|
||||
import MenuItemType from './SideMenuItem'
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import NotificationBellIcon from '../icons/NotificationBellIcon';
|
||||
import CupIcon from '../icons/CupIcon';
|
||||
@@ -13,9 +12,9 @@ import GameControllerIcon from '../icons/GameControllerIcon';
|
||||
import ThumbsUpIcon from '../icons/ThumbsUpIcon';
|
||||
import NoteBoardIcon from '../icons/NoteBoardIcon';
|
||||
import DirectboxReceiveIcon from '../icons/DirectboxReceiveIcon';
|
||||
import BlurredOverlayContainer from '../overlays/BlurredOverlayContainer';
|
||||
import SettingIcon from '../icons/SettingsIcon';
|
||||
import ExitIcon from '../icons/ExitIcon';
|
||||
import BlurredOverlayContainer from '../overlays/BlurredOverlayContainer';
|
||||
import NightModeSwitch from '../button/NightModeSwitch';
|
||||
import Button from '../button/PrimaryButton';
|
||||
import { useAuthStore } from '@/zustand/authStore';
|
||||
@@ -27,61 +26,39 @@ type MenuItemType = {
|
||||
title: string;
|
||||
icon: React.ReactElement;
|
||||
auth?: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
const menuItems: Array<Array<MenuItemType>> = [
|
||||
[
|
||||
{
|
||||
href: '/', title: 'اعلان ها', icon: <NotificationBellIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'my-services', title: 'باشگاه مشتریان', icon: <CupIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'services', title: 'کد های تخفیف', icon: <TicketDiscountIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'orders', title: 'لیست سفارشات', icon: <CalendarSearchIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'transactions', title: 'لیست تراکنش ها', icon: <ReceiptIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: '/', title: 'بازی و سرگرمی ها', icon: <GameControllerIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'my-services', title: 'معرفی به دوستان', icon: <ThumbsUpIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'services', title: 'گزارش اشکال', icon: <NoteBoardIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
href: 'invoices', title: 'نصب اپلیکیشن', icon: <DirectboxReceiveIcon width={20} height={20} />
|
||||
},
|
||||
{ href: '/', title: 'اعلان ها', icon: <NotificationBellIcon width={20} height={20} /> },
|
||||
{ href: 'my-services', title: 'باشگاه مشتریان', icon: <CupIcon width={20} height={20} /> },
|
||||
{ href: 'services', title: 'کد های تخفیف', icon: <TicketDiscountIcon width={20} height={20} /> },
|
||||
{ href: 'orders', title: 'لیست سفارشات', icon: <CalendarSearchIcon width={20} height={20} /> },
|
||||
{ href: 'transactions', title: 'لیست تراکنش ها', icon: <ReceiptIcon width={20} height={20} /> },
|
||||
{ href: '/', title: 'بازی و سرگرمی ها', icon: <GameControllerIcon width={20} height={20} /> },
|
||||
{ href: 'my-services', title: 'معرفی به دوستان', icon: <ThumbsUpIcon width={20} height={20} /> },
|
||||
{ href: 'services', title: 'گزارش اشکال', icon: <NoteBoardIcon width={20} height={20} /> },
|
||||
{ href: 'invoices', title: 'نصب اپلیکیشن', icon: <DirectboxReceiveIcon width={20} height={20} /> }
|
||||
],
|
||||
[],
|
||||
[
|
||||
{
|
||||
auth: true, href: undefined, title: 'تنظیمات', icon: <SettingIcon width={20} height={20} />
|
||||
},
|
||||
{
|
||||
auth: true, href: '?logout', title: 'خروج', icon: <ExitIcon width={20} height={20} />
|
||||
},
|
||||
{ auth: true, href: undefined, title: 'تنظیمات', icon: <SettingIcon width={20} height={20} /> },
|
||||
{ auth: true, href: '?logout', title: 'خروج', icon: <ExitIcon width={20} height={20} /> }
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
type Props = {
|
||||
menuState: boolean,
|
||||
toggleMenuState: React.MouseEventHandler<HTMLDivElement> | undefined
|
||||
nightModeState: boolean,
|
||||
togglenightModeState: React.MouseEventHandler<HTMLDivElement> | undefined
|
||||
}
|
||||
menuState: boolean;
|
||||
toggleMenuState: React.MouseEventHandler<HTMLDivElement> | undefined;
|
||||
nightModeState: boolean;
|
||||
togglenightModeState: React.MouseEventHandler<HTMLDivElement> | undefined;
|
||||
};
|
||||
|
||||
function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeState }: Props) {
|
||||
const menuStateMemo = useMemo(() => menuState, [menuState]);
|
||||
const [logoutModalVisible, setLogoutModalVisible] = useState(false);
|
||||
const closeRef: React.Ref<HTMLDivElement> | undefined = useRef(null);
|
||||
const userIsAuthenticated = true; //useAuthStore((state) => state.isAuthenticated);
|
||||
const closeRef = useRef<HTMLDivElement>(null);
|
||||
const userIsAuthenticated = true; // useAuthStore((state) => state.isAuthenticated);
|
||||
const authLogout = useAuthStore((state) => state.logout);
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
@@ -89,35 +66,20 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
const pathname = usePathname();
|
||||
|
||||
const variants: Variants = {
|
||||
hidden: {
|
||||
x: '100%',
|
||||
transition: {
|
||||
duration: 0.1,
|
||||
ease: 'easeInOut',
|
||||
},
|
||||
},
|
||||
visible: {
|
||||
x: 0,
|
||||
transition: {
|
||||
delay: 0.075,
|
||||
duration: 0.1,
|
||||
ease: 'easeInOut',
|
||||
},
|
||||
},
|
||||
hidden: { x: '100%', transition: { duration: 0.1, ease: 'easeInOut' } },
|
||||
visible: { x: 0, transition: { delay: 0.075, duration: 0.1, ease: 'easeInOut' } }
|
||||
};
|
||||
|
||||
const onDrag = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
|
||||
if (info.offset.x > 20) {
|
||||
if (closeRef.current) {
|
||||
closeRef.current.click();
|
||||
}
|
||||
if (info.offset.x > 20 && closeRef.current) {
|
||||
closeRef.current.click();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const toggleLogoutModalVisiblity = (e: React.MouseEvent<HTMLAnchorElement> | React.MouseEvent<HTMLButtonElement> | React.MouseEvent<HTMLDivElement> | undefined) => {
|
||||
const toggleLogoutModalVisiblity = (e?: React.MouseEvent) => {
|
||||
e?.stopPropagation();
|
||||
setLogoutModalVisible((state) => !state);
|
||||
}
|
||||
};
|
||||
|
||||
const onLogout = (e: React.MouseEvent<HTMLButtonElement> | null) => {
|
||||
if (!e) return;
|
||||
@@ -127,102 +89,105 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
}
|
||||
};
|
||||
|
||||
const hrefOnClicks: Array<{ href: string, handler: React.MouseEventHandler<HTMLAnchorElement> | undefined }> = [
|
||||
{ href: '?logout', handler: toggleLogoutModalVisiblity }
|
||||
]
|
||||
const hrefOnClicks = [{ href: '?logout', handler: toggleLogoutModalVisiblity }];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='w-full' ref={closeRef} onClick={toggleMenuState} >
|
||||
<div className='w-full' ref={closeRef} onClick={toggleMenuState}>
|
||||
<BlurredOverlayContainer bgOpacity={40} visible={menuStateMemo} outDelay={150} inDuration={200}>
|
||||
<motion.div
|
||||
drag='x'
|
||||
dragConstraints={{ left: 0, right: 20 }}
|
||||
transition={{ type: "spring", stiffness: 200, damping: 20 }}
|
||||
dragTransition={{ bounceDamping: 10, bounceStiffness: 600 }}
|
||||
dragElastic={0.05}
|
||||
onDragEnd={onDrag}
|
||||
initial="hidden"
|
||||
animate={menuState ? 'visible' : 'hidden'}
|
||||
variants={variants}
|
||||
data-visible={menuState}
|
||||
data-isvisible={menuStateMemo}
|
||||
onClick={(e) => { e.stopPropagation(); }}
|
||||
className={`fixed top-0 bottom-0 right-0 ease-in-out not-xl:!rounded-s-none overflow-clip bg-white w-[200px] h-dvh flex flex-col z-40`}>
|
||||
<ul className="overflow-y-scroll noscrollbar pt-20 pb-10 flex flex-col justify-between h-full ">
|
||||
<li>
|
||||
<div className='flex flex-col gap-[60px]'>
|
||||
<div className='flex flex-col gap-[23px]'>
|
||||
<div className='pt-2 text-start text-sm px-12 text-menu-header'>منو</div>
|
||||
{menuItems[0].filter((x) => x.auth ? userIsAuthenticated && x : x).map((v, i) => {
|
||||
const isActive = pathname === `/${name}/${v.href}`
|
||||
return <SideMenuItem
|
||||
className={clsx(
|
||||
isActive && 'text-foreground!'
|
||||
)}
|
||||
key={i}
|
||||
href={(v.href ?? '')}
|
||||
title={v.title}
|
||||
icon={
|
||||
<div className={clsx(
|
||||
isActive ? 'text-foreground!' : 'text-icon-deactive'
|
||||
)}
|
||||
>
|
||||
{v.icon}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className='flex flex-col gap-6 pt-16'>
|
||||
{menuItems[2].filter((x) => x.auth ? userIsAuthenticated && x : x).map((v, i) => {
|
||||
return <SideMenuItem
|
||||
key={i}
|
||||
href={v.href || ''}
|
||||
onClick={v.href && hrefOnClicks.find((i) => i.href === v.href)?.handler || undefined}
|
||||
title={v.title}
|
||||
icon={<div className='text-icon-deactive'>{v.icon}</div>}
|
||||
/>
|
||||
})}
|
||||
<SideMenuItem href={''} title={''} icon={<></>}><NightModeSwitch checked={nightModeState} onClick={togglenightModeState} /></SideMenuItem>
|
||||
</li>
|
||||
</ul>
|
||||
</motion.div>
|
||||
<aside aria-label="منوی کناری">
|
||||
<motion.nav
|
||||
drag='x'
|
||||
dragConstraints={{ left: 0, right: 20 }}
|
||||
transition={{ type: "spring", stiffness: 200, damping: 20 }}
|
||||
dragTransition={{ bounceDamping: 10, bounceStiffness: 600 }}
|
||||
dragElastic={0.05}
|
||||
onDragEnd={onDrag}
|
||||
initial="hidden"
|
||||
animate={menuState ? 'visible' : 'hidden'}
|
||||
variants={variants}
|
||||
data-visible={menuState}
|
||||
data-isvisible={menuStateMemo}
|
||||
onClick={(e) => { e.stopPropagation(); }}
|
||||
className="fixed top-0 bottom-0 right-0 bg-white w-[200px] h-dvh flex flex-col z-40 overflow-clip not-xl:!rounded-s-none"
|
||||
>
|
||||
<section className="flex-1 overflow-y-scroll noscrollbar pt-20 pb-10 flex flex-col justify-between">
|
||||
<div>
|
||||
<header className="px-12">
|
||||
<h6 className="text-start text-sm text-menu-header mt-2 mb-[23px]">منو</h6>
|
||||
</header>
|
||||
|
||||
<nav aria-label="لینکهای اصلی">
|
||||
<ul>
|
||||
{menuItems[0]
|
||||
.filter(item => !item.auth || (item.auth && userIsAuthenticated))
|
||||
.map((item, index) => {
|
||||
const isActive = pathname === `/${name}/${item.href}`;
|
||||
return (
|
||||
<li key={index} className="mt-[18px]">
|
||||
<SideMenuItem
|
||||
className={clsx(isActive && 'text-foreground!')}
|
||||
href={item.href ?? ''}
|
||||
title={item.title}
|
||||
icon={
|
||||
<span className={clsx(isActive ? 'text-foreground!' : 'text-icon-deactive')}>
|
||||
{item.icon}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<section aria-label="پایین منو">
|
||||
<ul className="flex flex-col gap-6 pt-16">
|
||||
{menuItems[2]
|
||||
.filter(item => !item.auth || (item.auth && userIsAuthenticated))
|
||||
.map((item, index) => (
|
||||
<SideMenuItem
|
||||
key={index}
|
||||
href={item.href ?? ''}
|
||||
onClick={
|
||||
typeof item.href === 'string'
|
||||
? hrefOnClicks.find((i) => i.href === item.href)?.handler
|
||||
: undefined
|
||||
} title={item.title}
|
||||
icon={<span className="text-icon-deactive">{item.icon}</span>}
|
||||
/>
|
||||
))}
|
||||
<SideMenuItem href={''} title={''} icon={<></>}>
|
||||
<NightModeSwitch checked={nightModeState} onClick={togglenightModeState} />
|
||||
</SideMenuItem>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</motion.nav>
|
||||
</aside>
|
||||
</BlurredOverlayContainer>
|
||||
</div>
|
||||
<BlurredOverlayContainer visible={logoutModalVisible} onClick={toggleLogoutModalVisiblity} inDuration={100} outDuration={100} outDelay={75}>
|
||||
<div
|
||||
className='absolute top-1/2 left-0 w-full px-6' onClick={toggleLogoutModalVisiblity}>
|
||||
<motion.div
|
||||
animate={{ y: logoutModalVisible ? [10, 0] : [0, 10], }}
|
||||
transition={{ duration: 0.1, ease: 'easeInOut' }}
|
||||
className='top-1/2 min-w-xs w-full max-w-sm justify-self-center text-center -translate-y-1/2 px-6 pt-8 pb-9 drop-shadow-container bg-white/63 rounded-4xl'
|
||||
>
|
||||
<div className='text-base font-medium'>خروج از سیستم</div>
|
||||
<div className='text-xs font-medium mt-6'>آیا میخواهید از سیستم خارج شوید؟</div>
|
||||
<div className='grid grid-cols-2 gap-5.5 mt-8'>
|
||||
<Button
|
||||
onClick={onLogout}
|
||||
className='text-sm font-normal'
|
||||
>
|
||||
بله خارج میشوم
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
className='bg-disabled! text-disabled2! text-sm font-normal'
|
||||
onClick={toggleLogoutModalVisiblity}
|
||||
>
|
||||
منصرف شدم
|
||||
</Button>
|
||||
{/* Logout Modal */}
|
||||
<BlurredOverlayContainer visible={logoutModalVisible} onClick={toggleLogoutModalVisiblity} inDuration={100} outDuration={100} outDelay={75}>
|
||||
<div className="absolute top-1/2 left-0 w-full px-6" onClick={toggleLogoutModalVisiblity}>
|
||||
<motion.div
|
||||
animate={{ y: logoutModalVisible ? [10, 0] : [0, 10] }}
|
||||
transition={{ duration: 0.1, ease: 'easeInOut' }}
|
||||
className="top-1/2 min-w-xs w-full max-w-sm text-center -translate-y-1/2 px-6 pt-8 pb-9 drop-shadow-container bg-white/63 rounded-4xl"
|
||||
>
|
||||
<h2 className="text-base font-medium">خروج از سیستم</h2>
|
||||
<p className="text-xs font-medium mt-6">آیا میخواهید از سیستم خارج شوید؟</p>
|
||||
<div className="grid grid-cols-2 gap-5.5 mt-8">
|
||||
<Button onClick={onLogout} className="text-sm font-normal">بله خارج میشوم</Button>
|
||||
<Button onClick={toggleLogoutModalVisiblity} className="bg-disabled! text-disabled2! text-sm font-normal">منصرف شدم</Button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</BlurredOverlayContainer>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default SideMenu;
|
||||
export default SideMenu;
|
||||
@@ -11,11 +11,16 @@ export default function SideMenuItem({ href, title, icon, className, children, .
|
||||
<Link
|
||||
{...restProps}
|
||||
href={href}
|
||||
className={`inline-flex gap-2 ps-8 border-transparent text-disabled-text text-[0.7rem] items-center font-light text-nowrap overflow-hidden h-6
|
||||
data-[active]:border-s-6 data-[active]:border-black data-[active]:text-black ${className}`}>
|
||||
className={`
|
||||
inline-flex gap-2 ps-8 items-center h-6 overflow-hidden text-nowrap
|
||||
text-[0.7rem] font-light text-disabled-text border-transparent
|
||||
data-[active]:border-s-6 data-[active]:border-black data-[active]:text-black
|
||||
${className}
|
||||
`}
|
||||
>
|
||||
{children}
|
||||
{icon}
|
||||
<div>{title}</div>
|
||||
<span className="flex-shrink-0">{icon}</span>
|
||||
<span>{title}</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -35,8 +35,8 @@ function BottomNavBar() {
|
||||
|
||||
{/* 🔽 Your HTML content inside SVG */}
|
||||
<foreignObject x="0" y="10" width="100%" height="80">
|
||||
<div
|
||||
className="absolute z-20 w-full h-full px-2 grid grid-cols-5 gap-x-2 text-[10px] items-end"
|
||||
<nav
|
||||
className="h-full px-2 grid grid-cols-5 gap-x-2 text-[10px] items-end"
|
||||
>
|
||||
<BottomNavLink href={`/${name}/orders`} icon={<BagIcon width={20} height={20} />} value="سبد خرید" />
|
||||
<BottomNavLink href={`/${name}/pager`} icon={<PagerIcon width={20} height={20} />} value="پیجر" />
|
||||
@@ -52,7 +52,7 @@ function BottomNavBar() {
|
||||
value="منو" />
|
||||
<BottomNavLink href={`/${name}/notifications`} icon={<NotifiBoardIcon width={20} height={20} />} value="اعلان ها" />
|
||||
<BottomNavLink href={'/auth'} icon={<HeartIcon width={20} height={20} />} value="پسند ها" />
|
||||
</div>
|
||||
</nav>
|
||||
</foreignObject>
|
||||
|
||||
<defs>
|
||||
|
||||
@@ -23,17 +23,17 @@ function Comment({ user, rating, date, text, tags, className = '' }: Props) {
|
||||
<span className='ms-3 text-sm2'>{date}</span>
|
||||
</div>
|
||||
|
||||
<div className='text-xs mt-3'>
|
||||
<p className='text-xs mt-3'>
|
||||
{text}
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div className='mt-3 flex flex-wrap items-center justify-start gap-2'>
|
||||
<ul className='mt-3 flex flex-wrap items-center justify-start gap-2'>
|
||||
{tags.map((v, i) => (
|
||||
<div key={i} className='text-xs py-1.5 px-3 bg-[#F2F2F2] rounded-sm text-center'>
|
||||
<li key={i} className='text-xs py-1.5 px-3 bg-[#F2F2F2] rounded-sm text-center'>
|
||||
{v}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user