summaryrefslogtreecommitdiff
path: root/src-migrate
diff options
context:
space:
mode:
authortrisusilo48 <tri.susilo@altama.co.id>2024-09-09 10:01:12 +0700
committertrisusilo48 <tri.susilo@altama.co.id>2024-09-09 10:01:12 +0700
commitafd84f86d2f26a3e0347dab7552060717030df19 (patch)
treed63d095e16a6dd052fb7d6858e78c1aac1115794 /src-migrate
parentf8133c76306d9f70e01ac510c74dcfabe7f79b37 (diff)
parent495b327ba0a45b17f4f0156f846ebe8bddbcd075 (diff)
Merge branch 'release' into CR/product_detail
# Conflicts: # src-migrate/modules/product-detail/components/ProductDetail.tsx
Diffstat (limited to 'src-migrate')
-rw-r--r--src-migrate/libs/auth.ts5
-rw-r--r--src-migrate/modules/cart/components/Item.tsx9
-rw-r--r--src-migrate/modules/cart/components/ItemAction.tsx1
-rw-r--r--src-migrate/modules/cart/stores/useCartStore.ts4
-rw-r--r--src-migrate/modules/product-detail/components/AddToCart.tsx171
-rw-r--r--src-migrate/modules/product-detail/components/PriceAction.tsx2
-rw-r--r--src-migrate/modules/product-detail/components/ProductDetail.tsx4
-rw-r--r--src-migrate/modules/product-promo/components/AddToCart.tsx171
-rw-r--r--src-migrate/modules/product-promo/components/Card.tsx10
-rw-r--r--src-migrate/modules/product-promo/components/Modal.tsx8
-rw-r--r--src-migrate/modules/product-promo/components/ModalContent.tsx8
-rw-r--r--src-migrate/modules/product-promo/components/Section.tsx9
-rw-r--r--src-migrate/modules/promo/components/Hero.tsx10
-rw-r--r--src-migrate/modules/promo/components/HeroDiskon.tsx22
-rw-r--r--src-migrate/modules/promo/components/PromoList.tsx8
-rw-r--r--src-migrate/modules/promo/components/Voucher.tsx16
-rw-r--r--src-migrate/pages/api/product-variant/[id].tsx1
-rw-r--r--src-migrate/pages/shop/cart/index.tsx4
-rw-r--r--src-migrate/services/product.ts1
-rw-r--r--src-migrate/types/cart.ts2
-rw-r--r--src-migrate/types/product.ts1
-rw-r--r--src-migrate/types/promotion.ts7
22 files changed, 369 insertions, 105 deletions
diff --git a/src-migrate/libs/auth.ts b/src-migrate/libs/auth.ts
index 86ce26e1..e8516747 100644
--- a/src-migrate/libs/auth.ts
+++ b/src-migrate/libs/auth.ts
@@ -1,5 +1,8 @@
import { deleteCookie, getCookie, setCookie } from 'cookies-next';
import { AuthProps } from '~/types/auth';
+// @ts-ignore
+import camelcaseObjectDeep from 'camelcase-object-deep';
+
const COOKIE_KEY = 'auth';
@@ -14,7 +17,7 @@ export const getAuth = (): AuthProps | boolean => {
};
export const setAuth = (user: AuthProps): boolean => {
- setCookie(COOKIE_KEY, JSON.stringify(user));
+ setCookie(COOKIE_KEY, JSON.stringify(camelcaseObjectDeep(user)));
return true;
};
diff --git a/src-migrate/modules/cart/components/Item.tsx b/src-migrate/modules/cart/components/Item.tsx
index 47893498..6ffbb524 100644
--- a/src-migrate/modules/cart/components/Item.tsx
+++ b/src-migrate/modules/cart/components/Item.tsx
@@ -17,11 +17,11 @@ import CartItemSelect from './ItemSelect'
type Props = {
item: CartItemProps
editable?: boolean
+ selfPicking?: boolean
pilihSemuaCart?: boolean
}
-const CartItem = ({ item, editable = true,}: Props) => {
-
+const CartItem = ({ item, editable = true, selfPicking}: Props) => {
return (
<div className={style.wrapper}>
{item.cart_type === 'promotion' && (
@@ -53,6 +53,11 @@ const CartItem = ({ item, editable = true,}: Props) => {
<CartItem.Image item={item} />
<div className={style.details}>
+ {(item.is_in_bu) && (item.on_hand_qty >= item.quantity) && (
+ <div className='text-[10px] text-red-500 italic'>
+ *Barang ini bisa di pickup maksimal pukul 16.00
+ </div>
+ )}
<CartItem.Name item={item} />
<div className='mt-2 flex justify-between w-full'>
diff --git a/src-migrate/modules/cart/components/ItemAction.tsx b/src-migrate/modules/cart/components/ItemAction.tsx
index e5e7f314..7220e362 100644
--- a/src-migrate/modules/cart/components/ItemAction.tsx
+++ b/src-migrate/modules/cart/components/ItemAction.tsx
@@ -13,7 +13,6 @@ import { useDebounce } from 'usehooks-ts'
import { useCartStore } from '../stores/useCartStore'
import { useProductCartContext } from '@/contexts/ProductCartContext'
-
type Props = {
item: CartItem
}
diff --git a/src-migrate/modules/cart/stores/useCartStore.ts b/src-migrate/modules/cart/stores/useCartStore.ts
index 3b50ec32..c2ebf50f 100644
--- a/src-migrate/modules/cart/stores/useCartStore.ts
+++ b/src-migrate/modules/cart/stores/useCartStore.ts
@@ -54,7 +54,7 @@ export const useCartStore = create<State & Action>((set, get) => ({
const computeSummary = (cart: CartProps) => {
let subtotal = 0;
let discount = 0;
- for (const item of cart.products) {
+ for (const item of cart?.products) {
if (!item.selected) continue;
let price = 0;
@@ -71,4 +71,4 @@ const computeSummary = (cart: CartProps) => {
let grandTotal = total + tax;
return { subtotal, discount, total, tax, grandTotal };
-};
+}; \ No newline at end of file
diff --git a/src-migrate/modules/product-detail/components/AddToCart.tsx b/src-migrate/modules/product-detail/components/AddToCart.tsx
index 097db98a..a5284637 100644
--- a/src-migrate/modules/product-detail/components/AddToCart.tsx
+++ b/src-migrate/modules/product-detail/components/AddToCart.tsx
@@ -1,19 +1,35 @@
-import { Button, useToast } from '@chakra-ui/react'
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
+import style from '../styles/price-action.module.css';
+import { Button, Link, useToast } from '@chakra-ui/react'
+import product from 'next-seo/lib/jsonld/product'
import { useRouter } from 'next/router'
-
+import { useEffect, useState } from 'react'
+import Image from '~/components/ui/image'
import { getAuth } from '~/libs/auth'
import { upsertUserCart } from '~/services/cart'
+import LazyLoad from 'react-lazy-load';
+import ProductSimilar from '../../../../src/lib/product/components/ProductSimilar';
+import { IProductDetail } from '~/types/product';
+import ImageNext from 'next/image';
+import { useProductCartContext } from '@/contexts/ProductCartContext'
+import { createSlug } from '~/libs/slug'
+import formatCurrency from '~/libs/formatCurrency'
+import { useProductDetail } from '../stores/useProductDetail';
type Props = {
variantId: number | null,
quantity?: number;
source?: 'buy' | 'add_to_cart';
+ products : IProductDetail
}
+type Status = 'idle' | 'loading' | 'success'
+
const AddToCart = ({
variantId,
quantity = 1,
- source = 'add_to_cart'
+ source = 'add_to_cart',
+ products
}: Props) => {
const auth = getAuth()
const router = useRouter()
@@ -22,40 +38,65 @@ const AddToCart = ({
isClosable: true
})
- const handleClick = async () => {
+ const {
+ askAdminUrl,
+ } = useProductDetail();
+
+ const [product, setProducts] = useState(products);
+ const [status, setStatus] = useState<Status>('idle')
+ const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading } =
+ useProductCartContext()
+
+ const productSimilarQuery = [
+ product?.name,
+ `fq=-product_id_i:${product.id}`,
+ `fq=-manufacture_id_i:${product.manufacture?.id || 0}`,
+ ].join('&');
+ const [addCartAlert, setAddCartAlert] = useState(false);
+
+ const handleButton = async () => {
if (typeof auth !== 'object') {
const currentUrl = encodeURIComponent(router.asPath)
router.push(`/login?next=${currentUrl}`)
return;
}
-
+
if (
!variantId ||
isNaN(quantity) ||
typeof auth !== 'object'
) return;
-
- toast.promise(
- upsertUserCart({
- userId: auth.id,
+ if (status === 'success') return
+ setStatus('loading')
+ await upsertUserCart({
+ userId: auth.id,
type: 'product',
id: variantId,
qty: quantity,
selected: true,
source: source,
qtyAppend: true
- }),
- {
- loading: { title: 'Menambahkan ke keranjang', description: 'Mohon tunggu...' },
- success: { title: 'Menambahkan ke keranjang', description: 'Berhasil menambahkan ke keranjang belanja' },
- error: { title: 'Menambahkan ke keranjang', description: 'Gagal menambahkan ke keranjang belanja' },
- }
- )
-
+ })
+ setStatus('idle')
+ setRefreshCart(true);
+ setAddCartAlert(true);
+
+ toast({
+ title: 'Tambah ke keranjang',
+ description: 'Berhasil menambahkan barang ke keranjang belanja',
+ status: 'success',
+ duration: 3000,
+ isClosable: true,
+ position: 'top',
+ })
+
if (source === 'buy') {
router.push('/shop/checkout?source=buy')
}
}
+ useEffect(() => {
+ if (status === 'success') setTimeout(() => { setStatus('idle') }, 3000)
+ }, [status])
const btnConfig = {
'add_to_cart': {
@@ -69,10 +110,98 @@ const AddToCart = ({
}
return (
- <Button onClick={handleClick} colorScheme={btnConfig[source].colorScheme} className='w-full'>
- {btnConfig[source].text}
- </Button>
+ <div className='w-full'>
+ <Button onClick={handleButton} colorScheme={btnConfig[source].colorScheme} className='w-full'>
+ {btnConfig[source].text}
+ </Button>
+ <BottomPopup
+ className='!container'
+ title='Berhasil Ditambahkan'
+ active={addCartAlert}
+ close={() => {
+ setAddCartAlert(false);
+ }}
+ >
+ <div className='flex mt-4'>
+ <div className='w-[10%]'>
+ <ImageNext
+ src={product.image}
+ alt={product.name}
+ className='h-32 object-contain object-center w-full border border-gray_r-4'
+ width={80}
+ height={80}
+ />
+ </div>
+ <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'>
+ {!!product.manufacture.name ? (
+ <Link
+ href={createSlug('/shop/brands/', product.manufacture.name, product.manufacture.id.toString())}
+ className=' hover:underline'
+ color={"red"}
+ >
+ {product.manufacture.name}
+ </Link>
+ ) : '-'}
+ <p className='text-ellipsis overflow-hidden'>
+ {product.name}
+ </p>
+ <p>
+ {product.code}
+ </p>
+ {!!product.lowest_price && product.lowest_price.price > 0 && (
+ <>
+ <div className='flex items-end gap-x-2'>
+ {product.lowest_price.discount_percentage > 0 && (
+ <>
+ <div className='badge-solid-red'>
+ {Math.floor(product.lowest_price.discount_percentage)}%
+ </div>
+ <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
+ Rp {formatCurrency(product.lowest_price.price || 0)}
+ </div>
+ </>
+ )}
+ <div className='text-danger-500 font-semibold'>
+ Rp {formatCurrency(product.lowest_price.price_discount || 0)}
+ </div>
+ </div>
+ </>
+ )}
+
+ {!!product.lowest_price && product.lowest_price.price === 0 && (
+ <span>
+ Hubungi kami untuk dapatkan harga terbaik,{' '}
+ <Link
+ href={askAdminUrl}
+ target='_blank'
+ className='font-medium underline'
+ color={'red'}
+ >
+ klik disini
+ </Link>
+ </span>
+ )}
+ </div>
+ <div className='ml-3 flex items-center font-normal'>
+ <Link
+ href='/shop/cart'
+ className='flex-1 py-2 text-gray_r-12 btn-yellow'
+ >
+ Lihat Keranjang
+ </Link>
+ </div>
+ </div>
+ <div className='mt-8 mb-4'>
+ <div className='text-h-sm font-semibold mb-6'>
+ Kamu Mungkin Juga Suka
+ </div>
+ <LazyLoad>
+ <ProductSimilar query={productSimilarQuery} />
+ </LazyLoad>
+ </div>
+ </BottomPopup>
+ </div>
)
}
-export default AddToCart \ No newline at end of file
+export default AddToCart \ No newline at end of file
diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx
index b46afac9..6042d578 100644
--- a/src-migrate/modules/product-detail/components/PriceAction.tsx
+++ b/src-migrate/modules/product-detail/components/PriceAction.tsx
@@ -121,12 +121,14 @@ const PriceAction = ({ product }: Props) => {
<div className={style['action-wrapper']}>
<AddToCart
+ products={product}
variantId={activeVariantId}
quantity={Number(quantityInput)}
/>
{!isApproval && (
<AddToCart
source='buy'
+ products={product}
variantId={activeVariantId}
quantity={Number(quantityInput)}
/>
diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index c19c288a..554a3868 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -103,9 +103,7 @@ const ProductDetail = ({ product }: Props) => {
)}
<div className='h-4 md:h-10' />
- {!!activeVariantId && !isApproval && (
- <ProductPromoSection productId={activeVariantId} />
- )}
+ {!!activeVariantId && !isApproval && <ProductPromoSection product={product} productId={activeVariantId} />}
{/* <div className={style['section-card']}>
<h2 className={style['heading']}>
diff --git a/src-migrate/modules/product-promo/components/AddToCart.tsx b/src-migrate/modules/product-promo/components/AddToCart.tsx
index 87017c14..7b3863f9 100644
--- a/src-migrate/modules/product-promo/components/AddToCart.tsx
+++ b/src-migrate/modules/product-promo/components/AddToCart.tsx
@@ -5,53 +5,71 @@ import { useEffect, useState } from 'react'
import { getAuth } from '~/libs/auth'
import { upsertUserCart } from '~/services/cart'
-import { IPromotion } from '~/types/promotion'
+import { IPromotion, IProductVariantPromo } from '~/types/promotion'
import DesktopView from '../../../../src/core/components/views/DesktopView';
import MobileView from '../../../../src/core/components/views/MobileView';
-
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
+import ImageNext from 'next/image';
+import Link from 'next/link'
+import LazyLoad from 'react-lazy-load'
+import ProductSimilar from '../../../../src/lib/product/components/ProductSimilar';
+import { IProductDetail } from '~/types/product';
+import { useProductCartContext } from '@/contexts/ProductCartContext'
+import { createSlug } from '~/libs/slug'
+import formatCurrency from '~/libs/formatCurrency'
+import { useProductDetail } from '../../product-detail/stores/useProductDetail';
type Props = {
promotion: IPromotion
+ product: IProductDetail
+ variant: IProductVariantPromo,
}
type Status = 'idle' | 'loading' | 'success'
-const ProductPromoAddToCart = ({ promotion }: Props) => {
+const ProductPromoAddToCart = ({product, promotion, variant }: Props) => {
const auth = getAuth()
const toast = useToast()
const router = useRouter()
-
+ const {askAdminUrl} = useProductDetail();
const [status, setStatus] = useState<Status>('idle')
-
+ const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading } =
+ useProductCartContext()
+ const productSimilarQuery = [
+ promotion?.name,
+ `fq=-product_id_i:${promotion.products[0].product_id}`,
+ ].join('&');
+ const [addCartAlert, setAddCartAlert] = useState(false);
+
const handleButton = async () => {
if (typeof auth !== 'object') {
- const currentUrl = encodeURIComponent(router.asPath)
- router.push(`/login?next=${currentUrl}`)
- return
- }
- if (status === 'success') return
-
- setStatus('loading')
- await upsertUserCart({
- userId: auth.id,
- type: 'promotion',
- id: promotion.id,
- qty: 1,
- selected: true,
- source: 'add_to_cart',
- qtyAppend: true
- })
- setStatus('idle')
-
- toast({
- title: 'Tambah ke keranjang',
- description: 'Berhasil menambahkan barang ke keranjang belanja',
- status: 'success',
- duration: 3000,
- isClosable: true,
- position: 'top',
- })
+ const currentUrl = encodeURIComponent(router.asPath)
+ router.push(`/login?next=${currentUrl}`)
+ return
}
+ if (status === 'success') return
+ setStatus('loading')
+ await upsertUserCart({
+ userId: auth.id,
+ type: 'promotion',
+ id: promotion.id,
+ qty: 1,
+ selected: true,
+ source: 'add_to_cart',
+ qtyAppend: true
+ })
+ setStatus('idle')
+ setRefreshCart(true);
+ setAddCartAlert(true);
+ toast({
+ title: 'Tambah ke keranjang',
+ description: 'Berhasil menambahkan barang ke keranjang belanja',
+ status: 'success',
+ duration: 3000,
+ isClosable: true,
+ position: 'top',
+ })
+}
useEffect(() => {
if (status === 'success') setTimeout(() => { setStatus('idle') }, 3000)
@@ -92,6 +110,97 @@ const ProductPromoAddToCart = ({ promotion }: Props) => {
{status === 'success' && <span>Berhasil</span>}
{status !== 'success' && <span>Keranjang</span>}
</Button>
+ <BottomPopup
+ className='!container'
+ title='Berhasil Ditambahkan'
+ active={addCartAlert}
+ close={() => {
+ setAddCartAlert(false);
+ }}
+ >
+ <div className='flex mt-4'>
+ <div className='w-[10%]'>
+ <ImageNext
+ src={
+ product?.image
+ ? product?.image
+ : variant?.image || ''
+ }
+ alt={product?.name ? product?.name : variant?.display_name || ''}
+ className='h-32 object-contain object-center w-full border border-gray_r-4'
+ width={80}
+ height={80}
+ />
+
+ </div>
+ <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'>
+ {!!product?.manufacture?.name || variant?.manufacture && (
+ <Link
+ href={createSlug('/shop/brands/', product?.manufacture?.name? product?.manufacture?.name : variant?.manufacture?.manufacture_name, product?.manufacture?.id? product?.manufacture?.id.toString() : variant?.manufacture?.manufacture_id.toString())}
+ className=' hover:underline text-red-500'
+ color={"red"}
+ >
+ {product?.manufacture?.name ? product?.manufacture?.name : variant?.manufacture?.manufacture_name}
+ </Link>
+ )}
+ <p className='text-ellipsis overflow-hidden'>
+ {product?.name ? product?.name : variant?.name}
+ </p>
+ <p>
+ {product?.code}
+ </p>
+ {(!!product?.lowest_price && product?.lowest_price?.price > 0) || variant?.price?.price > 0 && (
+ <>
+ <div className='flex items-end gap-x-2'>
+ {(product?.lowest_price?.discount_percentage > 0) || variant?.price?.discount_percentage > 0 && (
+ <>
+ <div className='badge-solid-red'>
+ {Math.floor(product?.lowest_price?.discount_percentage ? product?.lowest_price?.discount_percentage : variant?.price?.discount_percentage)}%
+ </div>
+ <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
+ Rp {formatCurrency(product?.lowest_price?.price ? product?.lowest_price?.price || 0 : variant?.price?.price || 0)}
+ </div>
+ </>
+ )}
+ <div className='text-danger-500 font-semibold'>
+ Rp {formatCurrency(product?.lowest_price?.price_discount? product?.lowest_price?.price_discount || 0 : variant?.price?.price_discount)}
+ </div>
+ </div>
+ </>
+ )}
+
+ {(!!product?.lowest_price && product?.lowest_price?.price === 0) || variant?.price?.price === 0 && (
+ <span>
+ Hubungi kami untuk dapatkan harga terbaik,{' '}
+ <Link
+ href={askAdminUrl}
+ target='_blank'
+ className='font-medium underline'
+ color={'red'}
+ >
+ klik disini
+ </Link>
+ </span>
+ )}
+ </div>
+ <div className='ml-3 flex items-center font-normal'>
+ <Link
+ href='/shop/cart'
+ className='flex-1 py-2 text-gray_r-12 btn-yellow'
+ >
+ Lihat Keranjang
+ </Link>
+ </div>
+ </div>
+ <div className='mt-8 mb-4'>
+ <div className='text-h-sm font-semibold mb-6'>
+ Kamu Mungkin Juga Suka
+ </div>
+ <LazyLoad>
+ <ProductSimilar query={productSimilarQuery} />
+ </LazyLoad>
+ </div>
+ </BottomPopup>
</DesktopView>
</div>
)
diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx
index 728d23ca..b8abe5ec 100644
--- a/src-migrate/modules/product-promo/components/Card.tsx
+++ b/src-migrate/modules/product-promo/components/Card.tsx
@@ -15,16 +15,16 @@ import clsxm from '~/libs/clsxm'
import ProductPromoItem from './Item'
import ProductPromoAddToCart from "./AddToCart"
import ProductPromoCardCountdown from "./CardCountdown"
-
+import { IProductDetail } from '~/types/product';
import MobileView from '../../../../src/core/components/views/MobileView';
import DesktopView from '../../../../src/core/components/views/DesktopView';
type Props = {
promotion: IPromotion
-
+ product: IProductDetail
}
-const ProductPromoCard = ({ promotion}: Props) => {
+const ProductPromoCard = ({product, promotion}: Props) => {
const [products, setProducts] = useState<IProductVariantPromo[]>([])
const [freeProducts, setFreeProducts] = useState<IProductVariantPromo[]>([])
const [error, setError] = useState<string | null>(null)
@@ -132,7 +132,7 @@ const ProductPromoCard = ({ promotion}: Props) => {
</div>
<div>
- <ProductPromoAddToCart promotion={promotion} />
+ <ProductPromoAddToCart product={product} promotion={promotion} variant={products[0]} />
</div>
</div>
@@ -189,7 +189,7 @@ const ProductPromoCard = ({ promotion}: Props) => {
</div>
</div>
<div>
- <ProductPromoAddToCart promotion={promotion} />
+ <ProductPromoAddToCart product={product} promotion={promotion} variant={products[0]}/>
</div>
</div>
diff --git a/src-migrate/modules/product-promo/components/Modal.tsx b/src-migrate/modules/product-promo/components/Modal.tsx
index 0de672c2..1722b9df 100644
--- a/src-migrate/modules/product-promo/components/Modal.tsx
+++ b/src-migrate/modules/product-promo/components/Modal.tsx
@@ -3,8 +3,12 @@ import { Modal } from "~/components/ui/modal"
import { useModalStore } from '../stores/useModalStore'
import ProductPromoCategoryTab from './CategoryTab'
import ProductPromoModalContent from './ModalContent'
+import { IProductDetail } from '~/types/product';
-const ProductPromoModal = () => {
+type Props = {
+ product: IProductDetail
+}
+const ProductPromoModal = ({product}:Props) => {
const { active, closeModal } = useModalStore()
return (
@@ -17,7 +21,7 @@ const ProductPromoModal = () => {
<div className='h-4' />
- <ProductPromoModalContent />
+ <ProductPromoModalContent product={product} />
</Modal>
)
}
diff --git a/src-migrate/modules/product-promo/components/ModalContent.tsx b/src-migrate/modules/product-promo/components/ModalContent.tsx
index ab5129f8..256ef61a 100644
--- a/src-migrate/modules/product-promo/components/ModalContent.tsx
+++ b/src-migrate/modules/product-promo/components/ModalContent.tsx
@@ -6,7 +6,11 @@ import { getVariantPromoByCategory } from "~/services/productVariant"
import { useModalStore } from "../stores/useModalStore"
import ProductPromoCard from "./Card"
-const ProductPromoModalContent = () => {
+import { IProductDetail } from '~/types/product';
+type Props = {
+ product: IProductDetail
+}
+const ProductPromoModalContent = ({product}:Props) => {
const { activeTab, variantId } = useModalStore()
const promotionsQuery = useQuery(
@@ -24,7 +28,7 @@ const ProductPromoModalContent = () => {
<Skeleton isLoaded={!promotionsQuery.isLoading} className='min-h-[70vh] max-h-[70vh]'>
<div className="grid grid-cols-1 gap-y-6 pb-6">
{promotions?.data.map((promo) => (
- <ProductPromoCard key={promo.id} promotion={promo} />
+ <ProductPromoCard key={promo.id} promotion={promo} product={product} />
))}
{promotions?.data.length === 0 && (
<div className="py-10 rounded-lg h-fit text-center text-body-1 font-semibold text-gray-800 bg-gray-200">Belum ada promo pada kategori ini</div>
diff --git a/src-migrate/modules/product-promo/components/Section.tsx b/src-migrate/modules/product-promo/components/Section.tsx
index 4e8a7dd5..e1719998 100644
--- a/src-migrate/modules/product-promo/components/Section.tsx
+++ b/src-migrate/modules/product-promo/components/Section.tsx
@@ -9,12 +9,14 @@ import { IPromotion } from '~/types/promotion'
import { useModalStore } from "../stores/useModalStore"
import ProductPromoCard from './Card'
import ProductPromoModal from "./Modal"
+import { IProductDetail } from '~/types/product';
type Props = {
productId: number;
+ product: IProductDetail;
}
-const ProductPromoSection = ({ productId }: Props) => {
+const ProductPromoSection = ({ product, productId }: Props) => {
const promotionsQuery = useQuery({
queryKey: [`promotions.highlight`, productId],
queryFn: async () => await fetch(`/api/product-variant/${productId}/promotion/highlight`).then((res) => res.json()) as { data: IPromotion[] }
@@ -23,14 +25,13 @@ const ProductPromoSection = ({ productId }: Props) => {
const promotions = promotionsQuery.data
const { openModal } = useModalStore()
-
return (
<SmoothRender
isLoaded={(promotions?.data && promotions?.data.length > 0) || false}
height='450px'
duration='700ms'
>
- <ProductPromoModal />
+ <ProductPromoModal product={product}/>
{promotions?.data && promotions?.data.length > 0 && (
<div className={style.titleWrapper}>
@@ -50,7 +51,7 @@ const ProductPromoSection = ({ productId }: Props) => {
>
{promotions?.data.map((promotion) => (
<div key={promotion.id} className="min-w-[400px] max-w-[400px]">
- <ProductPromoCard promotion={promotion} />
+ <ProductPromoCard product={product} promotion={promotion} />
</div>
))}
</Skeleton>
diff --git a/src-migrate/modules/promo/components/Hero.tsx b/src-migrate/modules/promo/components/Hero.tsx
index c5f0afad..97cbe0b7 100644
--- a/src-migrate/modules/promo/components/Hero.tsx
+++ b/src-migrate/modules/promo/components/Hero.tsx
@@ -60,12 +60,12 @@ const Hero = () => {
<DesktopView>
<div className={style['wrapper']}>
<Swiper {...swiperBanner}>
- {banners.map((banner, index) => (
+ {banners?.map((banner, index) => (
<SwiperSlide key={index} className='flex flex-row'>
<div className={style['desc-section']}>
- <div className={style['title']}>{banner.headlineBanner? banner.headlineBanner : "Pasti Hemat & Untung Selama Belanja di Indoteknik.com!"}</div>
+ <div className={style['title']}>{banner?.headlineBanner? banner?.headlineBanner : "Pasti Hemat & Untung Selama Belanja di Indoteknik.com!"}</div>
<div className='h-4' />
- <div className={style['subtitle']}>{banner.descriptionBanner? banner.descriptionBanner : "Cari paket yang kami sediakan dengan penawaran harga & Nikmati kemudahan dalam setiap transaksi dengan fitur lengkap Pembayaran hingga barang sampai!"}</div>
+ <div className={style['subtitle']}>{banner?.descriptionBanner? banner?.descriptionBanner : "Cari paket yang kami sediakan dengan penawaran harga & Nikmati kemudahan dalam setiap transaksi dengan fitur lengkap Pembayaran hingga barang sampai!"}</div>
</div>
<div className={style['banner-section']}>
<Image
@@ -89,8 +89,8 @@ const Hero = () => {
width={439}
height={150}
quality={100}
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
className='w-full h-full object-cover object-center rounded-2xl'
/>
</SwiperSlide>
diff --git a/src-migrate/modules/promo/components/HeroDiskon.tsx b/src-migrate/modules/promo/components/HeroDiskon.tsx
index 6d38c763..8b8edcc0 100644
--- a/src-migrate/modules/promo/components/HeroDiskon.tsx
+++ b/src-migrate/modules/promo/components/HeroDiskon.tsx
@@ -39,7 +39,7 @@ const Hero = () => {
queryFn: () => getBanner({ type: 'banner-promotion' })
})
- const banners = useMemo(() => bannerQuery.data || [], [bannerQuery.data]);
+ const banners = useMemo(() => bannerQuery?.data || [], [bannerQuery?.data]);
useEffect(() => {
if (banners.length > 1) {
@@ -56,8 +56,8 @@ const Hero = () => {
{banners.map((banner, index) => (
<SwiperSlide key={index}>
<Image
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
width={666}
height={480}
className='w-[446px] h-[446px] object-fill object-center rounded-2xl'
@@ -71,8 +71,8 @@ const Hero = () => {
{banners.map((banner, index) => (
<SwiperSlide key={index}>
<Image
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
width={666}
height={450}
className='w-[400px] h-[217px] object-cover object-center rounded-2xl '
@@ -86,8 +86,8 @@ const Hero = () => {
{banners.map((banner, index) => (
<SwiperSlide key={index}>
<Image
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
width={666}
height={450}
className='w-[400px] h-[217px] object-cover object-center rounded-2xl'
@@ -101,8 +101,8 @@ const Hero = () => {
{banners.map((banner, index) => (
<SwiperSlide key={index}>
<Image
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
width={666}
height={450}
className='w-[400px] h-[217px] object-cover object-center rounded-2xl'
@@ -116,8 +116,8 @@ const Hero = () => {
{banners.map((banner, index) => (
<SwiperSlide key={index}>
<Image
- src={banner.image}
- alt={banner.name}
+ src={banner?.image}
+ alt={banner?.name}
width={666}
height={450}
className='w-[400px] h-[217px] object-cover object-center rounded-2xl'
diff --git a/src-migrate/modules/promo/components/PromoList.tsx b/src-migrate/modules/promo/components/PromoList.tsx
index 42725034..d59d1867 100644
--- a/src-migrate/modules/promo/components/PromoList.tsx
+++ b/src-migrate/modules/promo/components/PromoList.tsx
@@ -59,7 +59,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => {
const items = await fetchPromoItemsSolr(`type_value_s:${slug}`, 0, 10);
setPromoItems(items);
- const promoDataPromises = items.map(async (item) => {
+ const promoDataPromises = items?.map(async (item) => {
try {
const response = await fetchPromoItemsSolr(`id:${item.id}`, 0, 10);
return response;
@@ -69,7 +69,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => {
});
const promoDataArray = await Promise.all(promoDataPromises);
- const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
+ const mergedPromoData = promoDataArray?.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
setPromoData(mergedPromoData);
} catch (error) {
@@ -114,7 +114,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => {
{promoData?.map((promotion: IPromotion) => (
<SwiperSlide key={promotion.id}>
<div className="min-w-36 max-w-[400px] mb-[20px] sm:w-full md:w-full lg:w-full xl:w-full">
- <ProductPromoCard promotion={promotion} />
+ <ProductPromoCard product={promoItems} promotion={promotion} />
</div>
</SwiperSlide>
))}
@@ -122,7 +122,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => {
)}
{isMobile && (promoData?.map((promotion: IPromotion) => (
<div key={promotion.id} className="min-w-[400px] max-w-[400px]">
- <ProductPromoCard promotion={promotion} />
+ <ProductPromoCard product={promoItems} promotion={promotion} />
</div>
)))}
diff --git a/src-migrate/modules/promo/components/Voucher.tsx b/src-migrate/modules/promo/components/Voucher.tsx
index e5877e51..510fe746 100644
--- a/src-migrate/modules/promo/components/Voucher.tsx
+++ b/src-migrate/modules/promo/components/Voucher.tsx
@@ -56,7 +56,7 @@ const VoucherComponent = () => {
spaceBetween: 2,
};
- const dataVouchers = useMemo(() => voucherQuery.data || [], [voucherQuery.data]);
+ const dataVouchers = useMemo(() => voucherQuery?.data || [], [voucherQuery?.data]);
const vouchers = auth?.id? listVouchers : dataVouchers;
@@ -121,30 +121,30 @@ const VoucherComponent = () => {
<div className='h-6' />
- {voucherQuery.isLoading && (
+ {voucherQuery?.isLoading && (
<div className='grid grid-cols-3 gap-x-4 animate-pulse'>
{Array.from({ length: 3 }).map((_, index) => (
<div key={index} className='w-full h-[160px] bg-gray-200 rounded-xl' />
))}
</div>
)}
- {!voucherQuery.isLoading && (
+ {!voucherQuery?.isLoading && (
<div className={style['voucher-section']}>
<Swiper {...swiperVoucher}>
{vouchers?.map((voucher) => (
<SwiperSlide key={voucher.id} className='pb-2'>
<div className={style['voucher-card']}>
- <Image src={voucher.image} alt={voucher.name} width={128} height={128} className={style['voucher-image']} />
+ <Image src={voucher?.image} alt={voucher?.name} width={128} height={128} className={style['voucher-image']} />
<div className={style['voucher-content']}>
- <div className={style['voucher-title']}>{voucher.name}</div>
- <div className={style['voucher-desc']}>{voucher.description}</div>
+ <div className={style['voucher-title']}>{voucher?.name}</div>
+ <div className={style['voucher-desc']}>{voucher?.description}</div>
<div className={style['voucher-bottom']}>
<div>
<div className={style['voucher-code-desc']}>Kode Promo</div>
- <div className={style['voucher-code']}>{voucher.code}</div>
+ <div className={style['voucher-code']}>{voucher?.code}</div>
</div>
- <button className={style['voucher-copy']} onClick={() => copyText(voucher.code)}>Salin</button>
+ <button className={style['voucher-copy']} onClick={() => copyText(voucher?.code)}>Salin</button>
</div>
</div>
</div>
diff --git a/src-migrate/pages/api/product-variant/[id].tsx b/src-migrate/pages/api/product-variant/[id].tsx
index 955fde6a..2c46ac89 100644
--- a/src-migrate/pages/api/product-variant/[id].tsx
+++ b/src-migrate/pages/api/product-variant/[id].tsx
@@ -38,6 +38,7 @@ const map = async (variant: any, price_tier: string) => {
data.name = variant.name_s
data.default_code = variant.default_code_s
data.price = { discount_percentage: 0, price, price_discount: price }
+ data.manufacture = {manufacture_name: variant.manufacture_name_s, manufacture_id:variant.manufacture_id_i}
return data
}
diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx
index 5e3e042a..4768f62d 100644
--- a/src-migrate/pages/shop/cart/index.tsx
+++ b/src-migrate/pages/shop/cart/index.tsx
@@ -176,7 +176,7 @@ const CartPage = () => {
return (
<>
- <div className={`${isTop ? 'border-b-[0px]' : 'border-b-[1px]'} sticky top-[157px] bg-white py-4 border-gray-300 z-50 w-3/4`}>
+ <div className={`${isTop ? 'border-b-[0px]' : 'border-b-[1px]'} sticky md:top-[157px] flex-col bg-white py-4 border-gray-300 z-50 sm:w-full md:w-3/4`}>
<div className={`${style['title']}`}>Keranjang Belanja</div>
<div className='h-2' />
<div className={`flex items-center object-center justify-between `}>
@@ -315,4 +315,4 @@ const CartPage = () => {
);
};
-export default CartPage;
+export default CartPage; \ No newline at end of file
diff --git a/src-migrate/services/product.ts b/src-migrate/services/product.ts
index fe415d11..a6abba47 100644
--- a/src-migrate/services/product.ts
+++ b/src-migrate/services/product.ts
@@ -43,7 +43,6 @@ export const getProductSimilar = async ({
const query = [
`q=${name}`,
'page=1',
- 'orderBy=popular-weekly',
'operation=OR',
'priceFrom=1',
];
diff --git a/src-migrate/types/cart.ts b/src-migrate/types/cart.ts
index 4e3c8b99..a3115103 100644
--- a/src-migrate/types/cart.ts
+++ b/src-migrate/types/cart.ts
@@ -32,6 +32,8 @@ export type CartItem = {
id: number;
name: string;
stock: number;
+ is_in_bu: boolean;
+ on_hand_qty: number;
weight: number;
attributes: string[];
parent: {
diff --git a/src-migrate/types/product.ts b/src-migrate/types/product.ts
index 927a0ca3..3854f304 100644
--- a/src-migrate/types/product.ts
+++ b/src-migrate/types/product.ts
@@ -12,6 +12,7 @@ export interface IProduct {
variant_total: number;
description: string;
isSni: boolean;
+ is_in_bu: boolean;
isTkdn: boolean;
categories: {
id: string;
diff --git a/src-migrate/types/promotion.ts b/src-migrate/types/promotion.ts
index 85190aad..dce442ad 100644
--- a/src-migrate/types/promotion.ts
+++ b/src-migrate/types/promotion.ts
@@ -10,15 +10,18 @@ export interface IPromotion {
limit_user: number;
limit_trx: number;
price: number;
+ image: string;
total_qty: number;
products: {
product_id: number;
qty: number;
+ name: string;
}[];
free_products: {
product_id: number;
qty: number;
}[];
+
}
export interface IProductVariantPromo {
@@ -34,6 +37,10 @@ export interface IProductVariantPromo {
price_discount: number;
};
qty: number;
+ manufacture: {
+ manufacture_name: string;
+ manufacture_id:number;
+ }
}
export type CategoryPromo = 'bundling' | 'discount_loading' | 'merchandise';