privacy + return policy

This commit is contained in:
hamid zarghami
2025-10-04 15:17:30 +03:30
parent 5fe9d5a8a4
commit 49c2dc7f2a
12 changed files with 506 additions and 72 deletions
+2 -1
View File
@@ -3,13 +3,14 @@ import { Calendar, Eye, User } from 'iconsax-react'
import LastPost from '../components/LastPost'
import { NextPage } from 'next'
import Layout from '@/hoc/Layout'
import { SHOP_CONFIG } from '@/config/const'
const BlogDetail: NextPage = () => {
return (
<div className="max-w-7xl mx-auto px-4 py-8">
{/* Breadcrumb */}
<div className="text-sm text-gray-500 mb-6">
فروشگاه سندس طلا / راهنما ها / تست اقلام و قطعات / گلکسی بوک
فروشگاه {SHOP_CONFIG.name} / راهنما ها / تست اقلام و قطعات / گلکسی بوک
</div>
<div className="flex gap-8">
+3 -2
View File
@@ -3,6 +3,7 @@
import { NextPage } from 'next'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
import Layout from '@/hoc/Layout'
import { SHOP_CONFIG } from '@/config/const'
const FaqPage: NextPage = () => {
const faqData = [
@@ -15,8 +16,8 @@ const FaqPage: NextPage = () => {
answer: "این خطا معمولاً زمانی رخ می‌دهد که شماره ملی قبلاً در سیستم ثبت شده است. در صورت اطمینان از صحت اطلاعات، با پشتیبانی تماس بگیرید."
},
{
question: "برای ثبت نام در سندس کالا به چه مدارکی نیاز است؟",
answer: "برای ثبت نام در سندس کالا نیاز به مدارک شناسایی، مجوزهای کسب و کار و اطلاعات بانکی معتبر دارید."
question: `برای ثبت نام در ${SHOP_CONFIG.fullName} به چه مدارکی نیاز است؟`,
answer: `برای ثبت نام در ${SHOP_CONFIG.fullName} نیاز به مدارک شناسایی، مجوزهای کسب و کار و اطلاعات بانکی معتبر دارید.`
},
{
question: "نام تجاری به چه معناست ؟",
+4 -2
View File
@@ -2,7 +2,8 @@
import { FC } from 'react'
import ProductCard from '@/components/ProductCard'
import Image from 'next/image'
import { Swiper, SwiperSlide } from 'swiper/react';
import { Swiper, SwiperSlide } from 'swiper/react'
import { SHOP_CONFIG } from '@/config/const'
const HotOffer: FC = () => {
@@ -14,7 +15,8 @@ const HotOffer: FC = () => {
<br />
داغ
<br />
سندس
{SHOP_CONFIG.name}
<br />
کالا
</div>
<div className='mt-4 sm:mt-6 flex justify-center'>
+10
View File
@@ -0,0 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import * as api from "../service/Service";
export const useGetSiteSetting = (name: string) => {
return useQuery({
queryKey: ["site-setting", name],
queryFn: () => api.getSiteSetting(name),
enabled: !!name,
});
};
+110
View File
@@ -0,0 +1,110 @@
'use client'
import Layout from '@/hoc/Layout'
import { NextPage } from 'next'
import { useGetSiteSetting } from './hooks/usePrivacyData'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@/components/ui/breadcrumb'
import { Separator } from '@/components/ui/separator'
import { ShieldTick } from 'iconsax-react'
import Link from 'next/link'
const PrivacyPage: NextPage = () => {
const { data } = useGetSiteSetting('policyContent')
return (
<Layout>
<div className="mt-14 px-4 sm:px-6 md:px-8 lg:px-12 xl:px-20 max-w-full overflow-x-hidden">
{/* Breadcrumb */}
<div className="mb-6 sm:mb-8">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/" className="text-gray-600 hover:text-gray-800">
خانه
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className='rotate-180' />
<BreadcrumbItem>
<BreadcrumbPage className="text-gray-800 font-medium">
حریم خصوصی
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
{/* عنوان اصلی */}
<div className="text-center mb-8 sm:mb-12">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 bg-primary/10 rounded-full mb-4 sm:mb-6">
<ShieldTick
color='#DA2129'
size={32}
className="sm:w-10 sm:h-10 text-primary"
/>
</div>
<h1 className="text-xl sm:text-2xl lg:text-3xl font-bold text-gray-800 mb-3 sm:mb-4">
سیاستهای حفظ حریم خصوصی
</h1>
<p className="text-gray-600 text-sm sm:text-base max-w-2xl mx-auto leading-relaxed">
اطلاعاتی درباره نحوه جمعآوری، استفاده و حفاظت از دادههای شخصی شما در پلتفرم ما
</p>
</div>
<Separator className="mb-8 sm:mb-12" />
{/* محتوای اصلی */}
{data?.results ? (
<div className="bg-white rounded-lg border border-gray-100 shadow-sm p-4 sm:p-6 lg:p-8">
<div
className="prose prose-sm sm:prose-base lg:prose-lg prose-gray max-w-none
prose-headings:text-gray-800 prose-headings:font-bold
prose-p:text-gray-700 prose-p:leading-relaxed prose-p:mb-4
prose-li:text-gray-700 prose-li:leading-relaxed
prose-strong:text-gray-800 prose-strong:font-semibold
prose-ul:space-y-2 prose-ol:space-y-2"
dangerouslySetInnerHTML={{ __html: data.results.siteSetting.policyContent }}
/>
</div>
) : (
<div className="bg-white rounded-lg border border-gray-100 shadow-sm p-8 text-center">
<div className="inline-flex items-center justify-center w-12 h-12 bg-gray-100 rounded-full mb-4">
<ShieldTick size={20} className="text-gray-400" />
</div>
<p className="text-gray-500 text-sm sm:text-base">
در حال بارگذاری اطلاعات...
</p>
</div>
)}
{/* بخش تماس برای سوالات بیشتر */}
<div className="mt-8 sm:mt-12 bg-gradient-to-r from-primary/5 to-primary/10 rounded-lg p-4 sm:p-6 lg:p-8 text-center">
<h3 className="text-lg sm:text-xl font-semibold text-gray-800 mb-3 sm:mb-4">
سوالی دارید؟
</h3>
<p className="text-gray-600 text-sm sm:text-base mb-4 sm:mb-6 leading-relaxed max-w-2xl mx-auto">
اگر در مورد سیاستهای حفظ حریم خصوصی سوال یا نگرانی دارید،
میتوانید با تیم پشتیبانی ما تماس بگیرید.
</p>
<Link
href="/contact"
className="inline-flex items-center gap-2 bg-primary text-white px-4 py-2 sm:px-6 sm:py-3 rounded-lg hover:bg-primary/90 transition-colors text-sm sm:text-base font-medium"
>
تماس با ما
</Link>
</div>
</div>
</Layout>
)
}
export default PrivacyPage
+6
View File
@@ -0,0 +1,6 @@
import axios from "@/config/axios";
export const getSiteSetting = async (name: string) => {
const { data } = await axios.get(`/site-setting?name=${name}`);
return data;
};
+94
View File
@@ -0,0 +1,94 @@
'use client'
import Layout from '@/hoc/Layout'
import { NextPage } from 'next'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@/components/ui/breadcrumb'
import { Separator } from '@/components/ui/separator'
import { ArrowRotateLeft } from 'iconsax-react'
import Link from 'next/link'
import { useGetSiteSetting } from '../privacy/hooks/usePrivacyData'
const ReturnPolicyPage: NextPage = () => {
const { data } = useGetSiteSetting('returnRulesContent')
return (
<Layout>
<div className="mt-14 px-4 sm:px-6 md:px-8 lg:px-12 xl:px-20 max-w-full overflow-x-hidden">
{/* Breadcrumb */}
<div className="mb-6 sm:mb-8">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/" className="text-gray-600 hover:text-gray-800">
خانه
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className='rotate-180' />
<BreadcrumbItem>
<BreadcrumbPage className="text-gray-800 font-medium">
قوانین مرجوعی کالا
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
{/* عنوان اصلی */}
<div className="text-center mb-8 sm:mb-12">
<div className="inline-flex items-center justify-center w-16 h-16 sm:w-20 sm:h-20 bg-primary/10 rounded-full mb-4 sm:mb-6">
<ArrowRotateLeft
size={32}
color='#000000'
className="sm:w-10 sm:h-10 text-primary"
/>
</div>
<h1 className="text-xl sm:text-2xl lg:text-3xl font-bold text-gray-800 mb-3 sm:mb-4">
قوانین مرجوعی کالا
</h1>
<p className="text-gray-600 text-sm sm:text-base max-w-2xl mx-auto leading-relaxed">
سیاستهای بازگشت کالا و شرایط مرجوعی در فروشگاه ما را مطالعه کنید
</p>
</div>
<Separator className="mb-8 sm:mb-12" />
{/* محتوای اصلی */}
{data?.results ? (
<div className="bg-white rounded-lg border border-gray-100 shadow-sm p-4 sm:p-6 lg:p-8">
<div
className="prose prose-sm sm:prose-base lg:prose-lg prose-gray max-w-none
prose-headings:text-gray-800 prose-headings:font-bold
prose-p:text-gray-700 prose-p:leading-relaxed prose-p:mb-4
prose-li:text-gray-700 prose-li:leading-relaxed
prose-strong:text-gray-800 prose-strong:font-semibold
prose-ul:space-y-2 prose-ol:space-y-2"
dangerouslySetInnerHTML={{ __html: data.results.siteSetting.returnRulesContent }}
/>
</div>
) : (
<div className="bg-white rounded-lg border border-gray-100 shadow-sm p-8 text-center">
<div className="inline-flex items-center justify-center w-12 h-12 bg-gray-100 rounded-full mb-4">
<ArrowRotateLeft size={20} className="text-gray-400" />
</div>
<p className="text-gray-500 text-sm sm:text-base">
در حال بارگذاری اطلاعات...
</p>
</div>
)}
</div>
</Layout>
)
}
export default ReturnPolicyPage
+61
View File
@@ -0,0 +1,61 @@
'use client'
import { FC, ReactNode } from 'react'
import Link from 'next/link'
import { useSharedStore } from '@/share/store/sharedStore'
interface MenuItemProps {
icon: ReactNode
title: string
href: string
requiresLogin?: boolean
className?: string
onClick?: () => void
}
const MenuItem: FC<MenuItemProps> = ({
icon,
title,
href,
requiresLogin = false,
className = '',
onClick
}) => {
const { isLogin } = useSharedStore()
const handleClick = () => {
if (onClick) {
onClick()
}
}
const content = (
<div
className={`flex items-center gap-2.5 cursor-pointer transition-colors hover:text-blue-600 ${className}`}
onClick={handleClick}
>
<div className="text-[#333333] group-hover:text-blue-600 transition-colors">
{icon}
</div>
<div className="text-[#333333] group-hover:text-blue-600 transition-colors">
{title}
</div>
</div>
)
// اگر نیاز به لاگین دارد و کاربر لاگین نیست، لینک را غیرفعال می‌کنیم
if (requiresLogin && !isLogin) {
return (
<div className="opacity-50 cursor-not-allowed">
{content}
</div>
)
}
return (
<Link href={href} className="group">
{content}
</Link>
)
}
export default MenuItem
+6
View File
@@ -4,3 +4,9 @@ export const BASE_URL = "https://shop-api.dev.danakcorp.com";
// export const BASE_URL = "http://192.168.1.111:4000";
export const PRIMARY_COLOR = "#DA2129";
// تنظیمات فروشگاه
export const SHOP_CONFIG = {
name: "فجر مرکزی", // نام فروشگاه - می‌توان آن را تغییر داد
fullName: "تابلو فجر مرکزی", // نام کامل فروشگاه
};
+92 -36
View File
@@ -1,14 +1,24 @@
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { Call, Instagram, Location, Sms } from 'iconsax-react'
import { Call, Instagram, Location, Sms, Youtube, Whatsapp } from 'iconsax-react'
import Image from 'next/image'
import Link from 'next/link'
import { FC } from 'react'
import { SHOP_CONFIG } from '@/config/const'
const Footer: FC = () => {
return (
<div className='mt-12 sm:mt-16 md:mt-24 bg-[#F5F5F5] p-4 sm:p-8 md:p-20 flex flex-col lg:flex-row gap-8 sm:gap-12 md:gap-20'>
<div className='bg-[#F2F2F2] w-full lg:max-w-[450px] p-4 sm:p-6 md:p-7 rounded-2xl border border-border'>
<div>LOGO</div>
<div className='flex justify-center'>
<Image
width={100}
height={100}
alt='logo'
src='/images/logo.png'
className='w-full h-auto max-h-20 max-w-20 object-contain'
/>
</div>
<div className='mt-6 text-sm text-[#383E43] '>
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده
</div>
@@ -43,20 +53,24 @@ const Footer: FC = () => {
دانلود اپلیکیشن
</div>
<div className='flex gap-2 flex-wrap'>
<Image
width={132}
height={48}
alt='download from app store'
src='/images/appstore.png'
className='w-24 sm:w-[132px] h-auto'
/>
<Image
width={142}
height={48}
alt='download from google play'
src='/images/googleplay.png'
className='w-24 sm:w-[142px] h-auto'
/>
<Link href="https://apps.apple.com/app/id123456789" target="_blank" rel="noopener noreferrer">
<Image
width={132}
height={48}
alt='download from app store'
src='/images/appstore.png'
className='w-24 sm:w-[132px] h-auto hover:opacity-80 transition-opacity'
/>
</Link>
<Link href="https://play.google.com/store/apps/details?id=com.danak.shop" target="_blank" rel="noopener noreferrer">
<Image
width={142}
height={48}
alt='download from google play'
src='/images/googleplay.png'
className='w-24 sm:w-[142px] h-auto hover:opacity-80 transition-opacity'
/>
</Link>
</div>
</div>
@@ -82,41 +96,83 @@ const Footer: FC = () => {
</div>
<div className='flex gap-1.5'>
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center'>
<Instagram size={20} color='#fff' />
</div>
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center'>
<Instagram size={20} color='#fff' />
</div>
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center'>
<Instagram size={20} color='#fff' />
</div>
<Link href="https://instagram.com/danakshop" target="_blank" rel="noopener noreferrer">
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center transition-colors'>
<Instagram size={20} color='#fff' />
</div>
</Link>
<Link href="https://wa.me/989123456789" target="_blank" rel="noopener noreferrer">
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center transition-colors'>
<Whatsapp size={20} color='#fff' />
</div>
</Link>
<Link href="https://youtube.com/@danakshop" target="_blank" rel="noopener noreferrer">
<div className='size-10 bg-[#878787] hover:bg-primary rounded-full flex justify-center items-center transition-colors'>
<Youtube size={20} color='#fff' />
</div>
</Link>
</div>
</div>
<div className='mt-8 sm:mt-12 md:mt-20 flex flex-col sm:flex-row justify-between gap-6 sm:gap-0'>
<div>
<div className='text-sm sm:text-base font-medium'>همراه با سندس کالا</div>
<div className='text-sm sm:text-base font-medium'>همراه با {SHOP_CONFIG.fullName}</div>
<ul className='flex mt-4 sm:mt-6 flex-col gap-3 sm:gap-4 font-light'>
<li className='text-[#878787] text-sm sm:text-base'>تماس با ما</li>
<li className='text-[#878787] text-sm sm:text-base'>درباره سندس کالا</li>
<li className='text-[#878787] text-sm sm:text-base'>فروش در سندس کالا</li>
<li>
<Link href="/contact" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
تماس با ما
</Link>
</li>
<li>
<Link href="/about" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
درباره {SHOP_CONFIG.fullName}
</Link>
</li>
<li>
<Link href="/contact" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
فروش در {SHOP_CONFIG.fullName}
</Link>
</li>
</ul>
</div>
<div>
<div className='text-sm sm:text-base font-medium'>راهنمای خرید از سندس کالا</div>
<div className='text-sm sm:text-base font-medium'>راهنمای خرید از {SHOP_CONFIG.fullName}</div>
<ul className='flex mt-4 sm:mt-6 flex-col gap-3 sm:gap-4 font-light'>
<li className='text-[#878787] text-sm sm:text-base'>نحوه ثبت سفارش</li>
<li className='text-[#878787] text-sm sm:text-base'>قوانین مرجوعی کالا</li>
<li className='text-[#878787] text-sm sm:text-base'>پاسخ به پرسش ها متداول</li>
<li>
<Link href="/faq" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
نحوه ثبت سفارش
</Link>
</li>
<li>
<Link href="/return-policy" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
قوانین مرجوعی کالا
</Link>
</li>
<li>
<Link href="/faq" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
پاسخ به پرسش ها متداول
</Link>
</li>
</ul>
</div>
<div>
<div className='text-sm sm:text-base font-medium'>خدمات مشتریان</div>
<ul className='flex mt-4 sm:mt-6 flex-col gap-3 sm:gap-4 font-light'>
<li className='text-[#878787] text-sm sm:text-base'>حساب کاربری من</li>
<li className='text-[#878787] text-sm sm:text-base'>سبد خرید</li>
<li className='text-[#878787] text-sm sm:text-base'>حریم حصوصی</li>
<li>
<Link href="/profile" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
حساب کاربری من
</Link>
</li>
<li>
<Link href="/cart" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
سبد خرید
</Link>
</li>
<li>
<Link href="/privacy" className='text-[#878787] hover:text-primary transition-colors text-sm sm:text-base'>
حریم خصوصی
</Link>
</li>
</ul>
</div>
</div>
+49 -17
View File
@@ -1,7 +1,8 @@
'use client'
import Input from '@/components/Input'
import MenuItem from '@/components/MenuItem'
import { Separator } from '@/components/ui/separator'
import { DocumentText, Home, Profile, HambergerMenu } from 'iconsax-react'
import { DocumentText, Home, Profile, HambergerMenu, InfoCircle, Messages1 } from 'iconsax-react'
import { FC, Fragment, useEffect, useState } from 'react'
import Menu from './components/Menu'
import { useSharedStore } from './store/sharedStore'
@@ -86,14 +87,34 @@ const Header: FC = () => {
<Menu />
<Separator style={{ height: 20 }} orientation='vertical' />
<div className='flex items-center gap-2.5 cursor-pointer hover:text-purple-600 transition-colors'>
<Home size={20} color='#333333' />
<div className='text-[#333333]'>صفحه نخست</div>
</div>
<div className='flex items-center gap-2.5 cursor-pointer hover:text-purple-600 transition-colors'>
<DocumentText size={20} color='#333333' />
<div className='text-[#333333]'>مجله</div>
</div>
<MenuItem
icon={<Home size={20} color='#333333' />}
title="صفحه نخست"
href="/"
/>
<MenuItem
icon={<DocumentText size={20} color='#333333' />}
title="مجله"
href="/blogs"
/>
<MenuItem
icon={<DocumentText size={20} color='#333333' />}
title="پیگیری سفارشات"
href="/profile/orders"
requiresLogin={true}
/>
<MenuItem
icon={<InfoCircle size={18} color='#333333' />}
title="درباره ما"
href="/about"
/>
<MenuItem
icon={<Messages1 size={18} color='#333333' />}
title="تماس با ما"
href="/contact"
/>
</div>
{/* منوی موبایل */}
@@ -106,14 +127,25 @@ const Header: FC = () => {
</div>
<div className='space-y-3'>
<div className='flex items-center gap-3 py-2 cursor-pointer hover:bg-gray-50 rounded-lg px-2'>
<Home size={20} color='#333333' />
<span className='text-sm text-gray-800'>صفحه نخست</span>
</div>
<div className='flex items-center gap-3 py-2 cursor-pointer hover:bg-gray-50 rounded-lg px-2'>
<DocumentText size={20} color='#333333' />
<span className='text-sm text-gray-800'>مجله</span>
</div>
<MenuItem
icon={<Home size={20} />}
title="صفحه نخست"
href="/"
className="py-2 hover:bg-gray-50 rounded-lg px-2"
/>
<MenuItem
icon={<DocumentText size={20} />}
title="مجله"
href="/blogs"
className="py-2 hover:bg-gray-50 rounded-lg px-2"
/>
<MenuItem
icon={<DocumentText size={20} />}
title="پیگیری سفارشات"
href="/profile/orders"
requiresLogin={true}
className="py-2 hover:bg-gray-50 rounded-lg px-2"
/>
</div>
<div className='pt-4 border-t border-gray-100'>
+69 -14
View File
@@ -4,7 +4,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { useGetCart } from '@/app/cart/hooks/useCartData'
import { useGetCart, useUpdateCart } from '@/app/cart/hooks/useCartData'
import { useRemoveFromCart } from '@/app/cart/hooks/useCartData'
import { CartItemType } from '@/app/cart/types/Types'
import { LocalCartItem } from '@/app/product/store/LocalCartStore'
@@ -18,35 +18,64 @@ import { Button } from '@/components/ui/button'
import { useSharedStore } from '@/share/store/sharedStore'
import { useLocalCart } from '@/app/product/hooks/useLocalCart'
import { useOfflineCartProducts, EnrichedOfflineCartItem } from '@/share/hooks/useOfflineCartProducts'
import { useEffect, useRef } from 'react'
const Cart = () => {
const { isLogin } = useSharedStore()
const { data: cartData, isLoading } = useGetCart()
const removeFromCartMutation = useRemoveFromCart()
const updateCartMutation = useUpdateCart()
// Local cart hooks for offline users
const {
localCartItems,
removeFromLocalCart,
getLocalCartItemsCount
getLocalCartItemsCount,
clearLocalCart
} = useLocalCart()
// Track previous login state to detect login events
const prevIsLoginRef = useRef(isLogin)
// Get enriched product data for offline cart items
const {
enrichedCartItems,
isLoading: isLoadingOfflineProducts
} = useOfflineCartProducts(localCartItems)
// Sync local cart to server when user logs in
useEffect(() => {
const prevIsLogin = prevIsLoginRef.current
prevIsLoginRef.current = isLogin
// Check if user just logged in and has local cart items
if (!prevIsLogin && isLogin && localCartItems.length > 0) {
// Add each local cart item to server cart
const syncPromises = localCartItems.map(async (item) => {
try {
await updateCartMutation.mutateAsync({
productId: item.productId,
variantId: item.variantId,
quantity: item.quantity
})
} catch (error) {
console.error('Failed to sync cart item:', item, error)
}
})
// Clear local cart after sync attempt
Promise.all(syncPromises).finally(() => {
clearLocalCart()
})
}
}, [isLogin, localCartItems, updateCartMutation, clearLocalCart])
const handleRemoveItem = async (productId: number, variantId: string) => {
if (isLogin) {
try {
await removeFromCartMutation.mutateAsync({
productId,
variantId
})
} catch (error) {
console.error('Error removing item from cart:', error)
}
await removeFromCartMutation.mutateAsync({
productId,
variantId
})
} else {
removeFromLocalCart(productId, variantId)
}
@@ -102,7 +131,16 @@ const Cart = () => {
/>
))
) : (
<div className='text-center py-4 text-gray-500'>سبد خرید شما خالی است</div>
<div className='text-center py-4'>
<div className='text-gray-500 mb-2'>
{!isLogin ? 'سبد خرید شما خالی است' : 'سبد خرید شما خالی است'}
</div>
{!isLogin && (
<div className='text-xs text-gray-400'>
آیتمهای اضافه شده به سبد خرید در مرورگر شما ذخیره میشوند
</div>
)}
</div>
)}
</div>
@@ -114,6 +152,20 @@ const Cart = () => {
</Button>
</Link>
)}
{/* Login encouragement message for offline users */}
{!isLogin && (
<div className='mt-4 p-3 bg-blue-50 border border-blue-200 rounded-lg text-center'>
<div className='text-xs text-blue-700 mb-2'>
برای ذخیره سبد خرید و همگامسازی در همه دستگاهها، وارد حساب کاربری شوید
</div>
<Link href="/auth" className='inline-block'>
<Button size="sm" variant="outline" className='text-blue-600 border-blue-300 hover:bg-blue-100'>
ورود به حساب
</Button>
</Link>
</div>
)}
</div>
</PopoverContent>
</Popover>
@@ -133,7 +185,7 @@ const CartItemCard = ({
// Handle both online and offline items with enriched data
const productTitle = isOnline
? (item as CartItemType).product.title_fa
: (item as EnrichedOfflineCartItem).product?.title_fa || 'در حال بارگذاری...'
: (item as EnrichedOfflineCartItem).product?.title_fa || 'در حال بارگذاری محصول...'
const productImage = isOnline
? (item as CartItemType).product.imagesUrl.cover
@@ -153,6 +205,7 @@ const CartItemCard = ({
// Check if product data is still loading for offline items
const isProductLoading = !isOnline && !(item as EnrichedOfflineCartItem).product
const hasError = !isOnline && !isProductLoading && !(item as EnrichedOfflineCartItem).variant
return (
<div className='bg-white rounded-lg p-3 flex gap-3 shadow-sm border border-gray-100'>
@@ -173,12 +226,14 @@ const CartItemCard = ({
{productCategory}
</div>
<div className='text-sm text-gray-800 mb-2 line-clamp-2'>
{isProductLoading ? 'در حال بارگذاری...' : productTitle}
{hasError ? 'خطا در بارگذاری محصول' : isProductLoading ? 'در حال بارگذاری محصول...' : productTitle}
</div>
<div className='flex items-center justify-between'>
<div className='text-sm font-semibold text-gray-900'>
{isProductLoading ? (
{hasError ? (
`${quantity} عدد`
) : isProductLoading ? (
'در حال بارگذاری...'
) : (
`${NumberFormat(productPrice)} تومان`
)}