From 49c2dc7f2ab323d84cc83dc0dc9f5005b607516c Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 4 Oct 2025 15:17:30 +0330 Subject: [PATCH] privacy + return policy --- src/app/blogs/[id]/page.tsx | 3 +- src/app/faq/page.tsx | 5 +- src/app/home/components/HotOffer.tsx | 6 +- src/app/privacy/hooks/usePrivacyData.ts | 10 ++ src/app/privacy/page.tsx | 110 ++++++++++++++++++++ src/app/privacy/service/Service.ts | 6 ++ src/app/return-policy/page.tsx | 94 +++++++++++++++++ src/components/MenuItem.tsx | 61 +++++++++++ src/config/const.ts | 6 ++ src/share/Footer.tsx | 128 +++++++++++++++++------- src/share/Header.tsx | 66 ++++++++---- src/share/components/Cart.tsx | 83 ++++++++++++--- 12 files changed, 506 insertions(+), 72 deletions(-) create mode 100644 src/app/privacy/hooks/usePrivacyData.ts create mode 100644 src/app/privacy/page.tsx create mode 100644 src/app/privacy/service/Service.ts create mode 100644 src/app/return-policy/page.tsx create mode 100644 src/components/MenuItem.tsx diff --git a/src/app/blogs/[id]/page.tsx b/src/app/blogs/[id]/page.tsx index 0c5d17d..782aec4 100644 --- a/src/app/blogs/[id]/page.tsx +++ b/src/app/blogs/[id]/page.tsx @@ -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 (
{/* Breadcrumb */}
- فروشگاه سندس طلا / راهنما ها / تست اقلام و قطعات / گلکسی بوک + فروشگاه {SHOP_CONFIG.name} / راهنما ها / تست اقلام و قطعات / گلکسی بوک
diff --git a/src/app/faq/page.tsx b/src/app/faq/page.tsx index c7d0afb..6b8dc14 100644 --- a/src/app/faq/page.tsx +++ b/src/app/faq/page.tsx @@ -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: "نام تجاری به چه معناست ؟", diff --git a/src/app/home/components/HotOffer.tsx b/src/app/home/components/HotOffer.tsx index 4b77a4a..ac69b9f 100644 --- a/src/app/home/components/HotOffer.tsx +++ b/src/app/home/components/HotOffer.tsx @@ -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 = () => {
داغ
- سندس + {SHOP_CONFIG.name} +
کالا
diff --git a/src/app/privacy/hooks/usePrivacyData.ts b/src/app/privacy/hooks/usePrivacyData.ts new file mode 100644 index 0000000..fc69ffc --- /dev/null +++ b/src/app/privacy/hooks/usePrivacyData.ts @@ -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, + }); +}; diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx new file mode 100644 index 0000000..76705ad --- /dev/null +++ b/src/app/privacy/page.tsx @@ -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 ( + +
+ {/* Breadcrumb */} +
+ + + + + + خانه + + + + + + + حریم خصوصی + + + + +
+ + {/* عنوان اصلی */} +
+
+ +
+

+ سیاست‌های حفظ حریم خصوصی +

+

+ اطلاعاتی درباره نحوه جمع‌آوری، استفاده و حفاظت از داده‌های شخصی شما در پلتفرم ما +

+
+ + + + {/* محتوای اصلی */} + {data?.results ? ( +
+
+
+ ) : ( +
+
+ +
+

+ در حال بارگذاری اطلاعات... +

+
+ )} + + {/* بخش تماس برای سوالات بیشتر */} +
+

+ سوالی دارید؟ +

+

+ اگر در مورد سیاست‌های حفظ حریم خصوصی سوال یا نگرانی دارید، + می‌توانید با تیم پشتیبانی ما تماس بگیرید. +

+ + تماس با ما + +
+
+ + ) +} + +export default PrivacyPage diff --git a/src/app/privacy/service/Service.ts b/src/app/privacy/service/Service.ts new file mode 100644 index 0000000..0595d78 --- /dev/null +++ b/src/app/privacy/service/Service.ts @@ -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; +}; diff --git a/src/app/return-policy/page.tsx b/src/app/return-policy/page.tsx new file mode 100644 index 0000000..a16a15d --- /dev/null +++ b/src/app/return-policy/page.tsx @@ -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 ( + +
+ {/* Breadcrumb */} +
+ + + + + + خانه + + + + + + + قوانین مرجوعی کالا + + + + +
+ + {/* عنوان اصلی */} +
+
+ +
+

+ قوانین مرجوعی کالا +

+

+ سیاست‌های بازگشت کالا و شرایط مرجوعی در فروشگاه ما را مطالعه کنید +

+
+ + + + {/* محتوای اصلی */} + {data?.results ? ( +
+
+
+ ) : ( +
+
+ +
+

+ در حال بارگذاری اطلاعات... +

+
+ )} + +
+ + ) +} + +export default ReturnPolicyPage diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx new file mode 100644 index 0000000..4b40e67 --- /dev/null +++ b/src/components/MenuItem.tsx @@ -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 = ({ + icon, + title, + href, + requiresLogin = false, + className = '', + onClick +}) => { + const { isLogin } = useSharedStore() + + const handleClick = () => { + if (onClick) { + onClick() + } + } + + const content = ( +
+
+ {icon} +
+
+ {title} +
+
+ ) + + // اگر نیاز به لاگین دارد و کاربر لاگین نیست، لینک را غیرفعال می‌کنیم + if (requiresLogin && !isLogin) { + return ( +
+ {content} +
+ ) + } + + return ( + + {content} + + ) +} + +export default MenuItem diff --git a/src/config/const.ts b/src/config/const.ts index fb72f0e..f9f4998 100644 --- a/src/config/const.ts +++ b/src/config/const.ts @@ -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: "تابلو فجر مرکزی", // نام کامل فروشگاه +}; diff --git a/src/share/Footer.tsx b/src/share/Footer.tsx index 0c4c047..b5b19d2 100644 --- a/src/share/Footer.tsx +++ b/src/share/Footer.tsx @@ -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 (
-
LOGO
+
+ logo +
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده
@@ -43,20 +53,24 @@ const Footer: FC = () => { دانلود اپلیکیشن
- download from app store - download from google play + + download from app store + + + download from google play +
@@ -82,41 +96,83 @@ const Footer: FC = () => {
-
- -
-
- -
-
- -
+ +
+ +
+ + +
+ +
+ + +
+ +
+
-
همراه با سندس کالا
+
همراه با {SHOP_CONFIG.fullName}
    -
  • تماس با ما
  • -
  • درباره سندس کالا
  • -
  • فروش در سندس کالا
  • +
  • + + تماس با ما + +
  • +
  • + + درباره {SHOP_CONFIG.fullName} + +
  • +
  • + + فروش در {SHOP_CONFIG.fullName} + +
-
راهنمای خرید از سندس کالا
+
راهنمای خرید از {SHOP_CONFIG.fullName}
    -
  • نحوه ثبت سفارش
  • -
  • قوانین مرجوعی کالا
  • -
  • پاسخ به پرسش ها متداول
  • +
  • + + نحوه ثبت سفارش + +
  • +
  • + + قوانین مرجوعی کالا + +
  • +
  • + + پاسخ به پرسش ها متداول + +
خدمات مشتریان
    -
  • حساب کاربری من
  • -
  • سبد خرید
  • -
  • حریم حصوصی
  • +
  • + + حساب کاربری من + +
  • +
  • + + سبد خرید + +
  • +
  • + + حریم خصوصی + +
diff --git a/src/share/Header.tsx b/src/share/Header.tsx index c121d0b..2a82d99 100644 --- a/src/share/Header.tsx +++ b/src/share/Header.tsx @@ -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 = () => { -
- -
صفحه نخست
-
-
- -
مجله
-
+ } + title="صفحه نخست" + href="/" + /> + } + title="مجله" + href="/blogs" + /> + } + title="پیگیری سفارشات" + href="/profile/orders" + requiresLogin={true} + /> + + } + title="درباره ما" + href="/about" + /> + + } + title="تماس با ما" + href="/contact" + />
{/* منوی موبایل */} @@ -106,14 +127,25 @@ const Header: FC = () => {
-
- - صفحه نخست -
-
- - مجله -
+ } + title="صفحه نخست" + href="/" + className="py-2 hover:bg-gray-50 rounded-lg px-2" + /> + } + title="مجله" + href="/blogs" + className="py-2 hover:bg-gray-50 rounded-lg px-2" + /> + } + title="پیگیری سفارشات" + href="/profile/orders" + requiresLogin={true} + className="py-2 hover:bg-gray-50 rounded-lg px-2" + />
diff --git a/src/share/components/Cart.tsx b/src/share/components/Cart.tsx index 4cd52b8..88f09d6 100644 --- a/src/share/components/Cart.tsx +++ b/src/share/components/Cart.tsx @@ -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 = () => { /> )) ) : ( -
سبد خرید شما خالی است
+
+
+ {!isLogin ? 'سبد خرید شما خالی است' : 'سبد خرید شما خالی است'} +
+ {!isLogin && ( +
+ آیتم‌های اضافه شده به سبد خرید در مرورگر شما ذخیره می‌شوند +
+ )} +
)}
@@ -114,6 +152,20 @@ const Cart = () => { )} + + {/* Login encouragement message for offline users */} + {!isLogin && ( +
+
+ برای ذخیره سبد خرید و همگام‌سازی در همه دستگاه‌ها، وارد حساب کاربری شوید +
+ + + +
+ )} @@ -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 (
@@ -173,12 +226,14 @@ const CartItemCard = ({ {productCategory}
- {isProductLoading ? 'در حال بارگذاری...' : productTitle} + {hasError ? 'خطا در بارگذاری محصول' : isProductLoading ? 'در حال بارگذاری محصول...' : productTitle}
- {isProductLoading ? ( + {hasError ? ( `${quantity} عدد` + ) : isProductLoading ? ( + 'در حال بارگذاری...' ) : ( `${NumberFormat(productPrice)} تومان` )}