increable offers + fix bugs

This commit is contained in:
hamid zarghami
2025-10-16 11:23:38 +03:30
parent 0a3b819a7e
commit 225329f342
13 changed files with 291 additions and 163 deletions
+11 -4
View File
@@ -2,6 +2,7 @@
import { FC } from 'react'
import { useGetLanding } from '../hooks/useHomeData'
import Image from 'next/image'
import Link from 'next/link'
const Banners3: FC = () => {
@@ -10,15 +11,21 @@ const Banners3: FC = () => {
return (
<div className='flex gap-4'>
<div className='flex flex-col gap-2 h-full flex-1'>
<div className='flex-1 h-full cursor-pointer' onClick={() => data?.results?.banners?.[1]?.linkUrl && window.open(data.results.banners[1].linkUrl, '_blank')}>
<Image src={data?.results?.banners?.[1]?.imageUrl as string} height={500} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[1]?.altText as string} />
<div className='flex-1 h-full'>
<Link href={data?.results?.banners?.[1]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[1]?.imageUrl as string} height={500} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
<div className='flex-1 h-full cursor-pointer' onClick={() => data?.results?.banners?.[2]?.linkUrl && window.open(data.results.banners[2].linkUrl, '_blank')}>
<div className='flex-1 h-full'>
<Link href={data?.results?.banners?.[2]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[2]?.imageUrl as string} height={500} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[2]?.altText as string} />
</Link>
</div>
</div>
<div className='flex-1 h-full cursor-pointer' onClick={() => data?.results?.banners?.[0]?.linkUrl && window.open(data.results.banners[0].linkUrl, '_blank')}>
<div className='flex-1 h-full'>
<Link href={data?.results?.banners?.[0]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[0]?.imageUrl as string} height={1000} width={1000} className='flex-1 rounded-lg h-full object-cover' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
</div>
)
+9
View File
@@ -2,6 +2,7 @@
import { FC } from 'react'
import { useGetLanding } from '../hooks/useHomeData'
import Image from 'next/image'
import Link from 'next/link'
const Banners4: FC = () => {
const { data } = useGetLanding()
@@ -9,20 +10,28 @@ const Banners4: FC = () => {
return (
<div className='flex gap-6 h-[340px]'>
<div className='flex-1 bg-primary/10 h-full rounded-[10px]'>
<Link href={data?.results?.banners?.[3]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[3]?.imageUrl as string} height={340} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
<div className='w-[158px] flex flex-col gap-6'>
<div className='w-[158px] h-[158px] rounded-[10px] bg-slate-100'>
<Link href={data?.results?.banners?.[4]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[4]?.imageUrl as string} height={158} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
<div className='w-[158px] h-[158px] rounded-[10px] bg-slate-200'>
<Link href={data?.results?.banners?.[5]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[5]?.imageUrl as string} height={158} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
</div>
<div className='w-[400px] bg-amber-50'>
<Link href={data?.results?.banners?.[6]?.linkUrl || '#'}>
<Image src={data?.results?.banners?.[6]?.imageUrl as string} height={400} width={1000} className='flex-1 rounded-lg' alt={data?.results?.banners?.[0]?.altText as string} />
</Link>
</div>
</div>
+13 -4
View File
@@ -3,6 +3,7 @@ import { FC, useState, useEffect } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react';
import { Pagination } from 'swiper/modules';
import Image from 'next/image';
import Link from 'next/link';
import { useGetLanding } from '../hooks/useHomeData';
const Carousel: FC = () => {
@@ -32,10 +33,17 @@ const Carousel: FC = () => {
<Swiper pagination={true} modules={[Pagination]} className="mySwiper pb-5" style={{ zIndex: 0, position: 'relative' }}>
{sliders.map((slider) => (
<SwiperSlide key={slider._id}>
<div
className='h-[200px] sm:h-[300px] md:h-[400px] relative cursor-pointer'
onClick={() => slider.linkUrl && window.open(slider.linkUrl, '_blank')}
>
{slider.linkUrl ? (
<Link href={slider.linkUrl} className='block h-[200px] sm:h-[300px] md:h-[400px] relative'>
<Image
src={slider.imageUrl}
alt={slider.altText}
fill
className="object-cover rounded-lg"
/>
</Link>
) : (
<div className='h-[200px] sm:h-[300px] md:h-[400px] relative'>
<Image
src={slider.imageUrl}
alt={slider.altText}
@@ -43,6 +51,7 @@ const Carousel: FC = () => {
className="object-cover rounded-lg"
/>
</div>
)}
</SwiperSlide>
))}
</Swiper>
+14 -11
View File
@@ -4,9 +4,19 @@ import ProductCard from '@/components/ProductCard'
import Image from 'next/image'
import { Swiper, SwiperSlide } from 'swiper/react'
import { SHOP_CONFIG } from '@/config/const'
import { useGetLanding } from '../hooks/useHomeData'
const HotOffer: FC = () => {
const { data } = useGetLanding()
const incredibleOffers = data?.results?.incredibleOffers || []
if (!incredibleOffers.length) {
return null
}
return (
<div className='bg-[#F2F2F2] rounded-xl sm:rounded-2xl flex flex-col sm:flex-row py-4 sm:py-6'>
<div className='px-4 sm:px-6 w-full sm:min-w-[140px] sm:max-w-[180px] flex flex-col justify-center items-center sm:items-start'>
@@ -41,18 +51,11 @@ const HotOffer: FC = () => {
},
}}
>
<SwiperSlide className='!w-auto'>
<ProductCard />
</SwiperSlide>
<SwiperSlide className='!w-auto'>
<ProductCard />
</SwiperSlide>
<SwiperSlide className='!w-auto'>
<ProductCard />
</SwiperSlide>
<SwiperSlide className='!w-auto'>
<ProductCard />
{incredibleOffers.map((product) => (
<SwiperSlide key={product._id} className='!w-auto'>
<ProductCard item={product} />
</SwiperSlide>
))}
</Swiper>
</div>
</div>
+11 -2
View File
@@ -1,6 +1,15 @@
import axios from "@/config/axios";
import { SiteSettingResponse } from "@/app/privacy/types/Types";
export const getSiteSetting = async (name: string) => {
const { data } = await axios.get(`/site-setting?name=${name}`);
export const getSiteSetting = async (
name: string
): Promise<SiteSettingResponse> => {
const params = new URLSearchParams();
if (name !== "all") {
params.append("name", name);
}
const { data } = await axios.get<SiteSettingResponse>(
`/site-setting${params.toString() ? `?${params.toString()}` : ""}`
);
return data;
};
+39
View File
@@ -0,0 +1,39 @@
export interface DownloadAppDetail {
pic: string;
url: string;
_id: string;
id: string;
}
export interface SocialMediaLink {
icon: string;
url: string;
_id: string;
id: string;
}
export interface SiteSetting {
_id: string;
siteLogo: string;
footerDescription: string;
footerAddress: string;
footerEmail: string;
footerPhone: string;
downloadAppDetails: DownloadAppDetail[];
socialMediaLinks: SocialMediaLink[];
shipmentContent: string;
faqContent: string;
policyContent: string;
returnRulesContent: string;
jobsContent: string;
createdAt: string;
updatedAt: string;
}
export interface SiteSettingResponse {
status: number;
success: boolean;
results: {
siteSetting: SiteSetting;
};
}
+36 -9
View File
@@ -1,21 +1,34 @@
'use client'
import { Star1 } from 'iconsax-react'
import { FC, useEffect } from 'react'
import { Product } from '@/types/product.types'
import { FC, useEffect, useMemo } from 'react'
import { Product, Review } from '@/types/product.types'
import Image from 'next/image'
import { clx } from '@/helpers/utils'
import { useProductStore } from '../store/Store'
interface BaseInformationProps {
product: Product
reviews?: Review[]
}
const BaseInformation: FC<BaseInformationProps> = ({ product }) => {
const BaseInformation: FC<BaseInformationProps> = ({ product, reviews = [] }) => {
const { setVariantId, variantId } = useProductStore()
const brand = product.brand
// محاسبه میانگین امتیاز و تعداد دیدگاه‌ها
const { averageRating, reviewsCount } = useMemo(() => {
if (!reviews.length) {
return { averageRating: 0, reviewsCount: 0 }
}
const totalRating = reviews.reduce((sum, review) => sum + review.rating, 0)
return {
averageRating: Number((totalRating / reviews.length).toFixed(1)),
reviewsCount: reviews.length
}
}, [reviews])
// تابع برای انتخاب variant
const handleVariantSelect = (variantId: string) => {
setVariantId(variantId)
@@ -43,14 +56,28 @@ const BaseInformation: FC<BaseInformationProps> = ({ product }) => {
{brand.title_fa}
</h3>
<div className='size-1.5 rounded-full bg-[#E5E5E5]'></div>
<div className='flex items-center gap-1'>
<button
onClick={() => {
const reviewsSection = document.getElementById('reviews-section')
reviewsSection?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}}
className='flex items-center gap-1 hover:opacity-80 transition-opacity cursor-pointer'
>
<Star1 size={16} color='#FFC107' variant='Bold' className='sm:w-5 sm:h-5' />
<span className='text-xs sm:text-sm'>3.5</span>
</div>
<span className='text-xs sm:text-sm'>
{reviewsCount > 0 ? `${averageRating} امتیاز` : '۰ امتیاز'}
</span>
</button>
<div className='size-1.5 rounded-full bg-[#E5E5E5]'></div>
<div className='text-primary text-xs sm:text-sm'>
8 دیدگاه
</div>
<button
onClick={() => {
const reviewsSection = document.getElementById('reviews-section')
reviewsSection?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}}
className='text-primary text-xs sm:text-sm hover:underline'
>
{reviewsCount} دیدگاه
</button>
</div>
{/* نمایش variant ها */}
+1 -1
View File
@@ -33,7 +33,7 @@ const Reviews: FC<ReviewsProps> = ({ reviews = [] }) => {
}
return (
<div className="mt-12 sm:mt-16 w-full">
<div id="reviews-section" className="mt-12 sm:mt-16 w-full scroll-mt-20">
<div className="flex items-center justify-end gap-3 flex-row-reverse">
<h2 className="text-primary text-base sm:text-lg">نظرات خریداران</h2>
<div className="w-1 h-6 bg-primary rounded"></div>
+4 -3
View File
@@ -18,6 +18,7 @@ import Questions from '@/app/product/components/Questions'
import { useGetDetailProduct } from '@/app/product/hooks/useProductData'
import PageLoading from '@/components/PageLoading'
import { notFound } from 'next/navigation'
import { SHOP_CONFIG } from '@/config/const'
interface SingleProductProps {
id: string
@@ -42,7 +43,7 @@ const SingleProduct = ({ id }: SingleProductProps) => {
<Breadcrumb aria-label="breadcrumb">
<BreadcrumbList className="text-sm text-muted-foreground">
<BreadcrumbItem>
<BreadcrumbLink href="/">فروشگاه آناهیتا</BreadcrumbLink>
<BreadcrumbLink href="/">{SHOP_CONFIG.fullName}</BreadcrumbLink>
</BreadcrumbItem>
{categoryPath.map((category, index) => (
<div key={category.id} className="flex items-center">
@@ -51,7 +52,7 @@ const SingleProduct = ({ id }: SingleProductProps) => {
{index === categoryPath.length - 1 ? (
<BreadcrumbPage className="text-foreground">{category.title_fa}</BreadcrumbPage>
) : (
<BreadcrumbLink href={`/products?category=${category.id}`}>
<BreadcrumbLink href={`/products/${category.title_en}`}>
{category.title_fa}
</BreadcrumbLink>
)}
@@ -68,7 +69,7 @@ const SingleProduct = ({ id }: SingleProductProps) => {
<div className='flex-1 flex flex-col gap-6'>
<div className='flex flex-col lg:flex-row gap-4 sm:gap-6'>
<ProductImage product={product} />
<BaseInformation product={product} />
<BaseInformation product={product} reviews={reviews} />
</div>
<div>
<Specifications product={product} />
+14 -2
View File
@@ -21,6 +21,7 @@ import { useInfiniteCategoryProductsData } from '../hooks/useInfiniteProductsDat
import { IProduct } from '@/types/landing.types'
import { Product } from '@/types/products.types'
import { useSearchParams, useParams } from 'next/navigation'
import { SHOP_CONFIG } from '@/config/const'
const Products: NextPage = () => {
const [showMobileFilters, setShowMobileFilters] = useState(false)
@@ -109,8 +110,19 @@ const Products: NextPage = () => {
market_status: defaultVariant?.market_status || 'active',
price: price,
stock: defaultVariant?.stock || 0,
postingTime: defaultVariant?.postingTime || 0,
isFreeShip: defaultVariant?.isFreeShip || false,
isWholeSale: defaultVariant?.isWholeSale || false
isWholeSale: defaultVariant?.isWholeSale || false,
shop: defaultVariant?.shop || { _id: '', shopName: '', shopDescription: '', logo: '' },
shipmentMethod: defaultVariant?.shipmentMethod?.map(method => ({
_id: method._id,
name: method.name,
description: method.description,
deliveryTime: method.deliveryTime,
deliveryType: method.deliveryType as "Standard" | "SameDay" | "Express"
})) || [],
warranty: defaultVariant?.warranty || { _id: 0, duration: '', logoUrl: '', name: '' },
meterage: []
},
variants: (product.variants || []).map(variant => ({
...variant,
@@ -128,7 +140,7 @@ const Products: NextPage = () => {
<Breadcrumb aria-label="breadcrumb">
<BreadcrumbList className="text-sm text-muted-foreground">
<BreadcrumbItem>
<BreadcrumbLink href="/">فروشگاه آناهیتا</BreadcrumbLink>
<BreadcrumbLink href="/">{SHOP_CONFIG.fullName}</BreadcrumbLink>
</BreadcrumbItem>
{data?.pages?.[0]?.results.breadcrumb?.map((item, index) => (
<div key={item._id} className="flex items-center">
+7 -37
View File
@@ -30,10 +30,10 @@ const ProductCard: FC<Props> = ({ item }) => {
if (!item?._id || !item?.variants[0]?._id) return
if (isWished) {
removeWishlist({ productId: item._id.toString(), variantId: item.variants[0]._id })
removeWishlist({ productId: String(item._id), variantId: item.variants[0]._id })
setIsWished(false)
} else {
addWishlist({ productId: item._id.toString(), variantId: item.variants[0]._id })
addWishlist({ productId: String(item._id), variantId: item.variants[0]._id })
setIsWished(true)
}
}
@@ -53,54 +53,24 @@ const ProductCard: FC<Props> = ({ item }) => {
<h4 className='line-clamp-2 text-[#383E43] mt-4 sm:mt-6 text-xs sm:text-sm text-center leading-4 sm:leading-5 h-10 sm:h-12'>
{item.title_fa}
</h4>
{/* <div className='flex flex-wrap justify-end items-center gap-1.5 mt-4'>
{
item.variants.map((variant) => {
if (variant.meterage) {
return <div className='text-[10px] px-4 border border-border rounded-lg whitespace-nowrap' key={variant._id}>{variant?.meterage?.value}</div>
}
})
}
</div>
<div className='flex flex-wrap justify-end items-center gap-1.5 mt-4'>
{
item.variants.map((variant) => {
if (variant.color) {
return <div className='text-[10px] px-4 border border-border rounded-lg whitespace-nowrap' key={variant._id}>
<div className='size-2 rounded-full' style={{ backgroundColor: variant?.color?.value }}></div>
</div>
}
})
}
{
item.variants.map((variant) => {
if (variant.size) {
return <div className='text-[10px] px-4 border border-border rounded-lg whitespace-nowrap' key={variant._id}>{variant?.size?.value}</div>
}
})
}
</div> */}
<div className='flex items-center justify-between mt-4 sm:mt-5'>
<div className='flex flex-col gap-1'>
<div className='text-xs sm:text-sm font-bold'>
{item.default_variant.price.selling_price && item.default_variant.price.selling_price > 0
{item?.default_variant?.price?.selling_price && item.default_variant.price.selling_price > 0
? `${NumberFormat(item.default_variant.price.selling_price)} تومان`
: 'بدون قیمت'
}
</div>
{((item.default_variant.price.discount_percent > 0 && item.default_variant.price.selling_price > 0) ||
(item.default_variant.price.is_specialSale && item.default_variant.price.selling_price > 0)) && (
{((item?.default_variant?.price?.discount_percent > 0 && item.default_variant.price.selling_price > 0) ||
(item?.default_variant?.price?.is_specialSale && item.default_variant.price.selling_price > 0)) && (
<div className='text-xs sm:text-sm text-[#7F7F7F] line-through'>
{NumberFormat(item.default_variant.price.retailPrice)}
</div>
)}
</div>
{((item.default_variant.price.discount_percent > 0 && item.default_variant.price.selling_price > 0) ||
(item.default_variant.price.is_specialSale && item.default_variant.price.selling_price > 0)) && (
{((item?.default_variant?.price?.discount_percent > 0 && item.default_variant.price.selling_price > 0) ||
(item?.default_variant?.price?.is_specialSale && item.default_variant.price.selling_price > 0)) && (
<div className='bg-red-500 text-white text-xs px-2 py-1 rounded-full'>
{item.default_variant.price.discount_percent > 0
? `${item.default_variant.price.discount_percent}%`
+38 -33
View File
@@ -1,12 +1,17 @@
'use client'
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { Call, Instagram, Location, Sms, Youtube, Whatsapp } from 'iconsax-react'
import { Call, Location, Sms } from 'iconsax-react'
import Image from 'next/image'
import Link from 'next/link'
import { FC } from 'react'
import { SHOP_CONFIG } from '@/config/const'
import { useGetSiteSetting } from '@/app/privacy/hooks/usePrivacyData'
const Footer: FC = () => {
const { data: siteSetting } = useGetSiteSetting('all')
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'>
@@ -15,31 +20,36 @@ const Footer: FC = () => {
width={100}
height={100}
alt='logo'
src='/images/logo.png'
src={siteSetting?.results?.siteSetting?.siteLogo || '/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 dangerouslySetInnerHTML={{ __html: siteSetting?.results?.siteSetting?.footerDescription || '' }} className='mt-6 text-sm text-[#383E43] leading-6'>
</div>
<div className='mt-8 sm:mt-12 md:mt-20 text-[#383E43] text-sm'>
{siteSetting?.results?.siteSetting?.footerPhone && (
<div className='flex gap-3'>
<Call color='#383E43' size={20} />
<div>تلفن: 67341</div>
<div>تلفن: {siteSetting.results.siteSetting.footerPhone}</div>
</div>
)}
{siteSetting?.results?.siteSetting?.footerEmail && (
<div className='flex gap-3 mt-4'>
<Sms color='#383E43' size={20} />
<div>کدپستی: 1136834843</div>
<div>ایمیل: {siteSetting.results.siteSetting.footerEmail}</div>
</div>
)}
{siteSetting?.results?.siteSetting?.footerAddress && (
<div className='flex gap-3 mt-4'>
<Location color='#383E43' size={20} className='min-w-5' />
<div className='leading-5'>
تهران، میدان امام خمینی، خیابان فردوسی، خیابان سرهنگ سخائی
نبش کوچه بهنیا، پلاک40، طبقه چهارم، واحد12
{siteSetting.results.siteSetting.footerAddress}
</div>
</div>
)}
</div>
@@ -48,31 +58,26 @@ const Footer: FC = () => {
</div>
</div>
<div className='flex-1'>
{siteSetting?.results?.siteSetting?.downloadAppDetails && siteSetting.results.siteSetting.downloadAppDetails.length > 0 && (
<div className='w-full rounded-xl bg-[#F2F2F2] border border-border h-auto sm:h-[72px] flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 sm:px-6 sm:py-0 gap-3 sm:gap-0'>
<div className='text-[#383E43] text-sm sm:text-base font-light'>
دانلود اپلیکیشن
</div>
<div className='flex gap-2 flex-wrap'>
<Link href="https://apps.apple.com/app/id123456789" target="_blank" rel="noopener noreferrer">
{siteSetting.results.siteSetting.downloadAppDetails.map((app) => (
<Link key={app.id} href={app.url} 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'
alt='download app'
src={app.pic}
className='size-10 object-contain'
/>
</Link>
))}
</div>
</div>
)}
<div className='w-full rounded-xl bg-[#F2F2F2] border border-border h-auto sm:h-[72px] flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 sm:px-6 sm:py-0 gap-3 sm:gap-0 mt-4 sm:mt-6'>
<div className='text-[#383E43] text-sm sm:text-base font-light'>
@@ -90,29 +95,29 @@ const Footer: FC = () => {
</div>
</div>
{siteSetting?.results?.siteSetting?.socialMediaLinks && siteSetting.results.siteSetting.socialMediaLinks.length > 0 && (
<div className='w-full rounded-xl bg-[#F2F2F2] border border-border h-auto sm:h-[72px] flex flex-col sm:flex-row items-start sm:items-center justify-between p-4 sm:px-6 sm:py-0 gap-3 sm:gap-0 mt-4 sm:mt-6'>
<div className='text-[#383E43] text-sm sm:text-base font-light'>
ما را در شبکه های اجتماعی دنبال کنید
</div>
<div className='flex gap-1.5'>
<Link href="https://instagram.com/danakshop" target="_blank" rel="noopener noreferrer">
{siteSetting.results.siteSetting.socialMediaLinks.map((social) => (
<Link key={social.id} href={social.url} 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' />
<Image
src={social.icon}
alt='social media'
width={20}
height={20}
className='w-5 h-5 object-contain brightness-0 invert'
/>
</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>
+49 -12
View File
@@ -1,8 +1,27 @@
export interface IShop {
_id: string;
shopName: string;
shopDescription: string;
logo: string;
shopName?: string;
shopDescription?: string;
logo?: string;
}
export interface IBrand {
_id: string;
status: string;
title_en: string;
title_fa: string;
images: string[];
logoUrl: string;
}
export interface ISize {
_id: number;
value: string;
}
export interface ISpecification {
title: string;
values: string[];
}
export interface IPrice {
@@ -21,8 +40,14 @@ export interface IDefaultVariant {
market_status: string;
price: IPrice;
stock: number;
postingTime: number;
isFreeShip: boolean;
isWholeSale: boolean;
shop: IShop;
shipmentMethod: IShipmentMethod[];
warranty: IWarranty;
size?: ISize;
meterage: IMeterage[];
}
export interface IShipmentMethod {
@@ -70,18 +95,27 @@ export interface IProduct {
_id: number;
title_fa: string;
title_en: string;
seoTitle: string | null;
seoDescription: string | null;
model: string;
source?: string;
seoTitle?: string | null;
seoDescription?: string | null;
metaDescription?: string;
model?: string;
description: string;
tags: string[];
shop: IShop;
status: string;
advantages?: string[];
disAdvantages?: string[];
shop?: IShop;
status?: string;
imagesUrl: IImagesUrl;
url: string;
url?: string;
isFake?: string;
voice?: string | null;
specifications?: ISpecification[];
brand?: IBrand;
category?: ICategory;
default_variant: IDefaultVariant;
variants: IVariant[];
isWishlist: boolean;
variants: (IVariant | { _id: string })[];
isWishlist?: boolean;
}
export interface ICategory {
@@ -91,7 +125,10 @@ export interface ICategory {
icon: string;
imageUrl: string;
description: string;
url: string;
theme?: string;
leaf?: boolean;
parent?: string;
url?: string;
}
export interface ISlider {