Merge remote-tracking branch 'refs/remotes/origin/master'
deploy to danak / build_and_deploy (push) Has been cancelled
deploy to danak / build_and_deploy (push) Has been cancelled
This commit is contained in:
@@ -3,7 +3,6 @@ import React from 'react'
|
|||||||
import CategoryItem from './CategoryItem'
|
import CategoryItem from './CategoryItem'
|
||||||
import { useGetCategories } from '@/share/hooks/useShareData'
|
import { useGetCategories } from '@/share/hooks/useShareData'
|
||||||
import { Category } from '@/share/types/SharedTypes'
|
import { Category } from '@/share/types/SharedTypes'
|
||||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
|
||||||
|
|
||||||
const Categories = () => {
|
const Categories = () => {
|
||||||
|
|
||||||
@@ -11,24 +10,14 @@ const Categories = () => {
|
|||||||
const parentCategories = data?.results?.data?.filter(cat => !cat.parent) || []
|
const parentCategories = data?.results?.data?.filter(cat => !cat.parent) || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex justify-center'>
|
<div className='w-full overflow-x-auto overflow-y-hidden'>
|
||||||
<Swiper
|
<div className='flex justify-center gap-4 sm:gap-6 md:gap-6 w-full min-w-max px-4 sm:px-8 md:px-20'>
|
||||||
spaceBetween={16}
|
|
||||||
slidesPerView={'auto'}
|
|
||||||
centeredSlides={true}
|
|
||||||
className='h-full'
|
|
||||||
breakpoints={{
|
|
||||||
640: {
|
|
||||||
spaceBetween: 24,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{parentCategories?.map((item: Category) => (
|
{parentCategories?.map((item: Category) => (
|
||||||
<SwiperSlide key={item._id} className='!w-auto'>
|
<div key={item._id} className='flex-shrink-0'>
|
||||||
<CategoryItem image={item.imageUrl} title={item.title_fa} categoryUrl={item.title_en} />
|
<CategoryItem image={item.imageUrl} title={item.title_fa} categoryUrl={item.title_en} />
|
||||||
</SwiperSlide>
|
</div>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -18,17 +18,17 @@ export const dynamic = 'force-dynamic'
|
|||||||
const HomePage: NextPage = () => {
|
const HomePage: NextPage = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className='w-full'>
|
||||||
<Carousel />
|
<Carousel />
|
||||||
<div className='mt-12 sm:mt-16 md:mt-24 px-4 sm:px-8 md:px-20'>
|
<div className='mt-12 sm:mt-16 md:mt-24 px-4 sm:px-8 md:px-20'>
|
||||||
<HotOffer />
|
<HotOffer />
|
||||||
<div className='mt-12 sm:mt-16 md:mt-24'>
|
</div>
|
||||||
|
<div className='mt-12 sm:mt-16 md:mt-24 w-full'>
|
||||||
<Categories />
|
<Categories />
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-12 sm:mt-16 md:mt-24'>
|
<div className='mt-12 sm:mt-16 md:mt-24 px-4 sm:px-8 md:px-20'>
|
||||||
<Banners3 />
|
<Banners3 />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='mt-12 sm:mt-16 md:mt-24 bg-[#FAF8F6] p-4 sm:p-8 md:p-20'>
|
<div className='mt-12 sm:mt-16 md:mt-24 bg-[#FAF8F6] p-4 sm:p-8 md:p-20'>
|
||||||
<NewestProducts />
|
<NewestProducts />
|
||||||
|
|||||||
@@ -4,16 +4,20 @@ import { useSharedStore } from '@/share/store/sharedStore'
|
|||||||
import OnlineCart from './OnlineCart'
|
import OnlineCart from './OnlineCart'
|
||||||
import OfflineCart from './OfflineCart'
|
import OfflineCart from './OfflineCart'
|
||||||
|
|
||||||
const Cart = () => {
|
interface CartProps {
|
||||||
|
stock: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Cart = ({ stock }: CartProps) => {
|
||||||
const { variantId } = useProductStore()
|
const { variantId } = useProductStore()
|
||||||
const { isLogin } = useSharedStore()
|
const { isLogin } = useSharedStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{isLogin ? (
|
{isLogin ? (
|
||||||
<OnlineCart variantId={variantId} />
|
<OnlineCart variantId={variantId} stock={stock} />
|
||||||
) : (
|
) : (
|
||||||
<OfflineCart variantId={variantId} />
|
<OfflineCart variantId={variantId} stock={stock} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { useLocalCart } from '../hooks/useLocalCart'
|
|||||||
|
|
||||||
interface OfflineCartProps {
|
interface OfflineCartProps {
|
||||||
variantId: string
|
variantId: string
|
||||||
|
stock: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const OfflineCart: React.FC<OfflineCartProps> = ({ variantId }) => {
|
const OfflineCart: React.FC<OfflineCartProps> = ({ variantId, stock }) => {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
|
|
||||||
// Local cart hooks for non-logged in users
|
// Local cart hooks for non-logged in users
|
||||||
@@ -24,7 +25,11 @@ const OfflineCart: React.FC<OfflineCartProps> = ({ variantId }) => {
|
|||||||
const [isInCart, setIsInCart] = useState<boolean>(false)
|
const [isInCart, setIsInCart] = useState<boolean>(false)
|
||||||
const [quantity, setQuantity] = useState<number>(1)
|
const [quantity, setQuantity] = useState<number>(1)
|
||||||
|
|
||||||
|
const isOutOfStock = stock <= 0
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
|
if (isOutOfStock) return
|
||||||
|
|
||||||
addToLocalCart(Number(id), variantId, 1)
|
addToLocalCart(Number(id), variantId, 1)
|
||||||
setIsInCart(true)
|
setIsInCart(true)
|
||||||
setQuantity(1)
|
setQuantity(1)
|
||||||
@@ -48,8 +53,9 @@ const OfflineCart: React.FC<OfflineCartProps> = ({ variantId }) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setQuantity(number)
|
const clampedQuantity = Math.min(number, stock)
|
||||||
updateLocalCartItem(Number(id), variantId, number)
|
setQuantity(clampedQuantity)
|
||||||
|
updateLocalCartItem(Number(id), variantId, clampedQuantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEmptyCart = () => {
|
const handleEmptyCart = () => {
|
||||||
@@ -59,21 +65,30 @@ const OfflineCart: React.FC<OfflineCartProps> = ({ variantId }) => {
|
|||||||
setQuantity(0)
|
setQuantity(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isOutOfStock) {
|
||||||
|
return (
|
||||||
|
<Button className="w-full mt-8" disabled>
|
||||||
|
ناموجود
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
!isInCart ?
|
!isInCart ?
|
||||||
<Button className='w-full mt-8' onClick={handleAddToCart}>
|
<Button className="w-full mt-8" onClick={handleAddToCart}>
|
||||||
افزودن به سبد خرید
|
افزودن به سبد خرید
|
||||||
</Button>
|
</Button>
|
||||||
:
|
:
|
||||||
<div className={"flex items-center gap-2 sm:gap-4 mt-8"}>
|
<div className="flex items-center gap-2 sm:gap-4 mt-8">
|
||||||
<div className="h-10 sm:h-12 rounded-lg sm:rounded-xl border border-border bg-white px-2 sm:px-4 flex-1 flex items-center justify-between">
|
<div className="h-10 sm:h-12 rounded-lg sm:rounded-xl border border-border bg-white px-2 sm:px-4 flex-1 flex items-center justify-between">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleQuantityChange(quantity + 1)}
|
onClick={() => handleQuantityChange(quantity + 1)}
|
||||||
className="p-1"
|
className="disabled:opacity-40 disabled:cursor-not-allowed p-1"
|
||||||
aria-label="increase quantity"
|
aria-label="increase quantity"
|
||||||
|
disabled={quantity >= stock}
|
||||||
>
|
>
|
||||||
<Add size={18} color={PRIMARY_COLOR} className="sm:w-5 sm:h-5" />
|
<Add size={18} color={PRIMARY_COLOR} className="sm:w-5 sm:h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import { extractErrorMessage } from '@/helpers/errorUtils'
|
|||||||
|
|
||||||
interface OnlineCartProps {
|
interface OnlineCartProps {
|
||||||
variantId: string
|
variantId: string
|
||||||
|
stock: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const OnlineCart: React.FC<OnlineCartProps> = ({ variantId }) => {
|
const OnlineCart: React.FC<OnlineCartProps> = ({ variantId, stock }) => {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
|
|
||||||
// API hooks for logged in users
|
// API hooks for logged in users
|
||||||
@@ -23,7 +24,11 @@ const OnlineCart: React.FC<OnlineCartProps> = ({ variantId }) => {
|
|||||||
const [isInCart, setIsInCart] = useState<boolean>(false)
|
const [isInCart, setIsInCart] = useState<boolean>(false)
|
||||||
const [quantity, setQuantity] = useState<number>(1)
|
const [quantity, setQuantity] = useState<number>(1)
|
||||||
|
|
||||||
|
const isOutOfStock = stock <= 0
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
|
if (isOutOfStock) return
|
||||||
|
|
||||||
addToCart({
|
addToCart({
|
||||||
productId: Number(id),
|
productId: Number(id),
|
||||||
variantId: variantId,
|
variantId: variantId,
|
||||||
@@ -40,14 +45,8 @@ const OnlineCart: React.FC<OnlineCartProps> = ({ variantId }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check API cart for logged in users
|
|
||||||
console.log('cart', cart);
|
|
||||||
console.log('variantId', variantId);
|
|
||||||
|
|
||||||
const item = cart?.results?.cart?.items?.find(item => item.variant?._id === variantId)
|
const item = cart?.results?.cart?.items?.find(item => item.variant?._id === variantId)
|
||||||
|
|
||||||
console.log('item', item);
|
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
setIsInCart(true)
|
setIsInCart(true)
|
||||||
setQuantity(item.quantity)
|
setQuantity(item.quantity)
|
||||||
@@ -62,13 +61,14 @@ const OnlineCart: React.FC<OnlineCartProps> = ({ variantId }) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clampedQuantity = Math.min(number, stock)
|
||||||
const oldQuantity = quantity
|
const oldQuantity = quantity
|
||||||
setQuantity(number)
|
setQuantity(clampedQuantity)
|
||||||
|
|
||||||
updateCart({
|
updateCart({
|
||||||
productId: Number(id),
|
productId: Number(id),
|
||||||
variantId: variantId,
|
variantId: variantId,
|
||||||
quantity: number,
|
quantity: clampedQuantity,
|
||||||
}, {
|
}, {
|
||||||
onError: (error: Error) => {
|
onError: (error: Error) => {
|
||||||
toast(extractErrorMessage(error), 'error')
|
toast(extractErrorMessage(error), 'error')
|
||||||
@@ -93,22 +93,30 @@ const OnlineCart: React.FC<OnlineCartProps> = ({ variantId }) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isOutOfStock) {
|
||||||
|
return (
|
||||||
|
<Button className="w-full mt-8" disabled>
|
||||||
|
ناموجود
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
!isInCart && !isPending ?
|
!isInCart && !isPending ?
|
||||||
<Button isLoading={isAddingToCart} className='w-full mt-8' onClick={handleAddToCart}>
|
<Button isLoading={isAddingToCart} className="w-full mt-8" onClick={handleAddToCart}>
|
||||||
افزودن به سبد خرید
|
افزودن به سبد خرید
|
||||||
</Button>
|
</Button>
|
||||||
:
|
:
|
||||||
<div className={"flex items-center gap-2 sm:gap-4 mt-8"}>
|
<div className="flex items-center gap-2 sm:gap-4 mt-8">
|
||||||
<div className="h-10 sm:h-12 rounded-lg sm:rounded-xl border border-border bg-white px-2 sm:px-4 flex-1 flex items-center justify-between">
|
<div className="h-10 sm:h-12 rounded-lg sm:rounded-xl border border-border bg-white px-2 sm:px-4 flex-1 flex items-center justify-between">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleQuantityChange(quantity + 1)}
|
onClick={() => handleQuantityChange(quantity + 1)}
|
||||||
className="disabled:opacity-40 disabled:cursor-not-allowed p-1"
|
className="disabled:opacity-40 disabled:cursor-not-allowed p-1"
|
||||||
aria-label="increase quantity"
|
aria-label="increase quantity"
|
||||||
disabled={isAddingToCart || isUpdatingCart}
|
disabled={isAddingToCart || isUpdatingCart || quantity >= stock}
|
||||||
>
|
>
|
||||||
<Add size={18} color={PRIMARY_COLOR} className="sm:w-5 sm:h-5" />
|
<Add size={18} color={PRIMARY_COLOR} className="sm:w-5 sm:h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Separator } from '@/components/ui/separator'
|
||||||
import { BoxTick, I3DRotate } from 'iconsax-react'
|
import { I3DRotate } from 'iconsax-react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Product } from '@/types/product.types'
|
import { Product } from '@/types/product.types'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
@@ -20,10 +20,10 @@ const ShopInformation = ({ product }: ShopInformationProps) => {
|
|||||||
? product.variants.find((variant) => variant._id === variantId) || product.default_variant
|
? product.variants.find((variant) => variant._id === variantId) || product.default_variant
|
||||||
: product.default_variant
|
: product.default_variant
|
||||||
|
|
||||||
const shop = selectedVariant.shop
|
// const shop = selectedVariant.shop
|
||||||
const price = selectedVariant.price
|
const price = selectedVariant.price
|
||||||
const warranty = selectedVariant.warranty
|
const warranty = selectedVariant.warranty
|
||||||
const postingTime = selectedVariant.postingTime
|
// const postingTime = selectedVariant.postingTime
|
||||||
|
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return price.toLocaleString('fa-IR')
|
return price.toLocaleString('fa-IR')
|
||||||
@@ -107,7 +107,7 @@ const ShopInformation = ({ product }: ShopInformationProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Cart />
|
<Cart stock={selectedVariant.stock} />
|
||||||
{/* <Button
|
{/* <Button
|
||||||
onClick={handleChatWithSeller}
|
onClick={handleChatWithSeller}
|
||||||
className='w-full mt-3 bg-[#323232] hover:bg-[#424242] flex items-center justify-center gap-2'
|
className='w-full mt-3 bg-[#323232] hover:bg-[#424242] flex items-center justify-center gap-2'
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const SingleProduct = ({ id }: SingleProductProps) => {
|
|||||||
notFound()
|
notFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
const { product, categoryPath, reviews, stats } = productData.results
|
const { product, categoryPath, stats } = productData.results
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mt-14 px-4 sm:px-6 md:px-8 lg:px-12 xl:px-20'>
|
<div className='mt-14 px-4 sm:px-6 md:px-8 lg:px-12 xl:px-20'>
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
export const TOKEN_NAME = "sh_token";
|
export const TOKEN_NAME = "sh_token";
|
||||||
export const REFRESH_TOKEN_NAME = "sh_refresh_token";
|
export const REFRESH_TOKEN_NAME = "sh_refresh_token";
|
||||||
// export const BASE_URL = "https://shop-api.dev.danakcorp.com";
|
export const BASE_URL = "https://api.fajrtabloshop.com";
|
||||||
export const BASE_URL = "http://localhost:4000";
|
// export const BASE_URL = "http://192.168.99.235:4000";
|
||||||
|
|
||||||
export const PRIMARY_COLOR = "#DA2129";
|
export const PRIMARY_COLOR = "#DA2129";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user