summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-10-11 10:22:11 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-10-11 14:09:27 +0700
commit23f67959168cd0126582c44f2a5b1bfdc45b268a (patch)
treea5a612967c92f52ccdf2081402822e5e29fe66a1 /src/lib
parent5b45d6ac182fcbe9d6e235a227688e0ae60869d9 (diff)
Add breadcrumb on detail product, search, brand, category page
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/brand/components/Brand.jsx4
-rw-r--r--src/lib/brand/components/Breadcrumb.jsx40
-rw-r--r--src/lib/category/components/Breadcrumb.jsx56
-rw-r--r--src/lib/category/components/Category.jsx2
-rw-r--r--src/lib/product/components/Product/Breadcrumb.jsx69
-rw-r--r--src/lib/product/components/Product/Product.jsx38
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx71
-rw-r--r--src/lib/product/components/Product/ProductMobile.jsx2
-rw-r--r--src/lib/product/components/ProductSearch.jsx4
-rw-r--r--src/lib/promotinProgram/components/PromotionType.jsx2
10 files changed, 225 insertions, 63 deletions
diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx
index 3c411969..3985b888 100644
--- a/src/lib/brand/components/Brand.jsx
+++ b/src/lib/brand/components/Brand.jsx
@@ -84,7 +84,7 @@ const Brand = ({ id }) => {
</MobileView>
<DesktopView>
- <div className='container mx-auto mt-10 mb-3'>
+ <div className='container mx-auto'>
<div className='min-h-[150px]'>
{brand.isLoading && <ImageSkeleton />}
{brand.data?.banners?.length == 0 && (
@@ -117,6 +117,7 @@ const Brand = ({ id }) => {
</SwiperSlide>
))}
</Swiper>
+
<div className='p-4'>
<div className='text-caption-1 text-gray_r-11 mb-2'>Produk dari brand:</div>
{brand?.data?.logo && (
@@ -137,7 +138,6 @@ const Brand = ({ id }) => {
</>
)}
</div>
- <Divider />
</div>
</DesktopView>
</>
diff --git a/src/lib/brand/components/Breadcrumb.jsx b/src/lib/brand/components/Breadcrumb.jsx
new file mode 100644
index 00000000..0fec2dad
--- /dev/null
+++ b/src/lib/brand/components/Breadcrumb.jsx
@@ -0,0 +1,40 @@
+import { Breadcrumb as ChakraBreadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react'
+import Link from 'next/link'
+import React from 'react'
+
+/**
+ * Renders a breadcrumb component with links to navigate through different pages.
+ *
+ * @param {Object} props - The props object containing the brand name.
+ * @param {string} props.brandName - The name of the brand to display in the breadcrumb.
+ * @return {JSX.Element} The rendered breadcrumb component.
+ */
+const Breadcrumb = ({ brandName }) => {
+ return (
+ <div className='container mx-auto py-4 md:py-6'>
+ <ChakraBreadcrumb>
+ <BreadcrumbItem>
+ <BreadcrumbLink as={Link} href='/' className='!text-danger-500 whitespace-nowrap'>
+ Home
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+
+ <BreadcrumbItem>
+ <BreadcrumbLink
+ as={Link}
+ href='/shop/brands'
+ className='!text-danger-500 whitespace-nowrap'
+ >
+ Brands
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+
+ <BreadcrumbItem isCurrentPage>
+ <BreadcrumbLink className='whitespace-nowrap'>{brandName}</BreadcrumbLink>
+ </BreadcrumbItem>
+ </ChakraBreadcrumb>
+ </div>
+ )
+}
+
+export default Breadcrumb
diff --git a/src/lib/category/components/Breadcrumb.jsx b/src/lib/category/components/Breadcrumb.jsx
new file mode 100644
index 00000000..127904ee
--- /dev/null
+++ b/src/lib/category/components/Breadcrumb.jsx
@@ -0,0 +1,56 @@
+import odooApi from '@/core/api/odooApi'
+import { createSlug } from '@/core/utils/slug'
+import {
+ Breadcrumb as ChakraBreadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ Skeleton
+} from '@chakra-ui/react'
+import Link from 'next/link'
+import React from 'react'
+import { useQuery } from 'react-query'
+
+/**
+ * Render a breadcrumb component.
+ *
+ * @param {object} categoryId - The ID of the category.
+ * @return {JSX.Element} The breadcrumb component.
+ */
+const Breadcrumb = ({ categoryId }) => {
+ const breadcrumbs = useQuery(
+ `category-breadcrumbs/${categoryId}`,
+ async () => await odooApi('GET', `/api/v1/category/${categoryId}/category-breadcrumb`)
+ )
+
+ return (
+ <div className='container mx-auto py-4 md:py-6'>
+ <Skeleton isLoaded={!breadcrumbs.isLoading} className='w-2/3'>
+ <ChakraBreadcrumb>
+ <BreadcrumbItem>
+ <BreadcrumbLink as={Link} href='/' className='!text-danger-500 whitespace-nowrap'>
+ Home
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+
+ {breadcrumbs.data?.map((category, index) => (
+ <BreadcrumbItem key={index} isCurrentPage={index === breadcrumbs.data.length - 1}>
+ {index === breadcrumbs.data.length - 1 ? (
+ <BreadcrumbLink className='whitespace-nowrap'>{category.name}</BreadcrumbLink>
+ ) : (
+ <BreadcrumbLink
+ as={Link}
+ href={createSlug('/shop/category/', category.name, category.id)}
+ className='!text-danger-500 whitespace-nowrap'
+ >
+ {category.name}
+ </BreadcrumbLink>
+ )}
+ </BreadcrumbItem>
+ ))}
+ </ChakraBreadcrumb>
+ </Skeleton>
+ </div>
+ )
+}
+
+export default Breadcrumb
diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx
index af696d42..e6ea5acf 100644
--- a/src/lib/category/components/Category.jsx
+++ b/src/lib/category/components/Category.jsx
@@ -30,7 +30,7 @@ const Category = () => {
return (
<DesktopView>
<div className='category-mega-box'>
- {categories.map((category) => (
+ {categories?.map((category) => (
<div key={category.id}>
<Link
href={createSlug('/shop/category/', category.name, category.id)}
diff --git a/src/lib/product/components/Product/Breadcrumb.jsx b/src/lib/product/components/Product/Breadcrumb.jsx
new file mode 100644
index 00000000..0554dba5
--- /dev/null
+++ b/src/lib/product/components/Product/Breadcrumb.jsx
@@ -0,0 +1,69 @@
+import odooApi from '@/core/api/odooApi'
+import { createSlug } from '@/core/utils/slug'
+import {
+ Breadcrumb as ChakraBreadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ Skeleton
+} from '@chakra-ui/react'
+import classNames from 'classnames'
+import Link from 'next/link'
+import { useQuery } from 'react-query'
+
+/**
+ * Renders a breadcrumb component based on the provided `productId`.
+ *
+ * @param {Object} props - The properties passed to the component.
+ * @param {number} props.productId - The ID of the product.
+ * @param {string} props.productName - The ID of the product.
+ * @return {ReactElement} The rendered breadcrumb component.
+ */
+const Breadcrumb = ({ productId, productName }) => {
+ const categories = useQuery(
+ `detail/categories/${productId}`,
+ async () => await odooApi('GET', `/api/v1/product/${productId}/category-breadcrumb`),
+ {
+ enabled: !!productId
+ }
+ )
+
+ return (
+ <Skeleton
+ isLoaded={!categories.isLoading}
+ className={classNames({
+ 'w-2/3': categories.isLoading,
+ 'w-full': !categories.isLoading
+ })}
+ >
+ <ChakraBreadcrumb
+ mb={10}
+ overflowX={'auto'}
+ className='text-caption-2 md:text-body-2 p-4 md:p-0'
+ >
+ <BreadcrumbItem>
+ <BreadcrumbLink as={Link} href='/' className='!text-danger-500 whitespace-nowrap'>
+ Home
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+
+ {categories.data?.map((category) => (
+ <BreadcrumbItem key={category.id}>
+ <BreadcrumbLink
+ as={Link}
+ href={createSlug('/shop/category/', category.name, category.id)}
+ className='!text-danger-500 whitespace-nowrap'
+ >
+ {category.name}
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+ ))}
+
+ <BreadcrumbItem isCurrentPage>
+ <BreadcrumbLink className='whitespace-nowrap'>{productName}</BreadcrumbLink>
+ </BreadcrumbItem>
+ </ChakraBreadcrumb>
+ </Skeleton>
+ )
+}
+
+export default Breadcrumb
diff --git a/src/lib/product/components/Product/Product.jsx b/src/lib/product/components/Product/Product.jsx
index 54490c26..6e983c2e 100644
--- a/src/lib/product/components/Product/Product.jsx
+++ b/src/lib/product/components/Product/Product.jsx
@@ -36,29 +36,21 @@ const Product = ({ product, isVariant = false }) => {
}
}, [product, isVariant])
- if (isVariant == true) {
- return (
- <>
- <ProductDesktopVariant
- product={product}
- wishlist={wishlist}
- toggleWishlist={toggleWishlist}
- />
- <ProductMobileVariant
- product={product}
- wishlist={wishlist}
- toggleWishlist={toggleWishlist}
- />
- </>
- )
- } else {
- return (
- <>
- <ProductMobile product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} />
- <ProductDesktop products={product} wishlist={wishlist} toggleWishlist={toggleWishlist} />
- </>
- )
- }
+ return isVariant == true ? (
+ <>
+ <ProductDesktopVariant
+ product={product}
+ wishlist={wishlist}
+ toggleWishlist={toggleWishlist}
+ />
+ <ProductMobileVariant product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} />
+ </>
+ ) : (
+ <>
+ <ProductMobile product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} />
+ <ProductDesktop products={product} wishlist={wishlist} toggleWishlist={toggleWishlist} />
+ </>
+ )
}
export default Product
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index 47e98c1a..ceb0cad7 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -24,6 +24,7 @@ import ColumnsSLA from './ColumnsSLA'
import { useProductCartContext } from '@/contexts/ProductCartContext'
import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
import { Info } from 'lucide-react'
+import Breadcrumb from './Breadcrumb'
const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -199,47 +200,49 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
return (
<DesktopView>
<div className='container mx-auto pt-10'>
+ <Breadcrumb productId={product.id} productName={product.name} />
<div className='flex'>
<div className='w-full flex flex-wrap'>
<div className='w-5/12'>
<div className='relative mb-2'>
- {product?.flashSale?.remainingTime > 0 && lowestPrice?.price.discountPercentage > 0 && (
- <div className={`absolute bottom-0 w-full`}>
- <div className='absolute bottom-0 w-full h-full'>
- <ImageNext
- src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'}
- width={1000}
- height={100}
- />
- </div>
- <div className='relative'>
- <div className='flex gap-x-2 items-center p-2'>
- <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
- <span className='text-lg font-bold'>
- {Math.floor(product.lowestPrice.discountPercentage)}%
- </span>
- </div>
- <div
- className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
- >
- <ImageNext
- src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
- width={17}
- height={10}
- />
- <span className='text-white text-lg font-semibold'>
- {product?.flashSale?.tag != 'false' || product?.flashSale?.tag
- ? product?.flashSale?.tag
- : 'FLASH SALE'}
- </span>
- </div>
- <div>
- <CountDown2 initialTime={product.flashSale.remainingTime} />
+ {product?.flashSale?.remainingTime > 0 &&
+ lowestPrice?.price.discountPercentage > 0 && (
+ <div className={`absolute bottom-0 w-full`}>
+ <div className='absolute bottom-0 w-full h-full'>
+ <ImageNext
+ src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'}
+ width={1000}
+ height={100}
+ />
+ </div>
+ <div className='relative'>
+ <div className='flex gap-x-2 items-center p-2'>
+ <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
+ <span className='text-lg font-bold'>
+ {Math.floor(product.lowestPrice.discountPercentage)}%
+ </span>
+ </div>
+ <div
+ className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
+ >
+ <ImageNext
+ src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ width={17}
+ height={10}
+ />
+ <span className='text-white text-lg font-semibold'>
+ {product?.flashSale?.tag != 'false' || product?.flashSale?.tag
+ ? product?.flashSale?.tag
+ : 'FLASH SALE'}
+ </span>
+ </div>
+ <div>
+ <CountDown2 initialTime={product.flashSale.remainingTime} />
+ </div>
</div>
</div>
</div>
- </div>
- )}
+ )}
<Image
src={product.image}
alt={product.name}
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx
index ffa75f72..402490f7 100644
--- a/src/lib/product/components/Product/ProductMobile.jsx
+++ b/src/lib/product/components/Product/ProductMobile.jsx
@@ -19,6 +19,7 @@ import { gtagAddToCart } from '@/core/utils/googleTag'
import odooApi from '@/core/api/odooApi'
import ImageNext from 'next/image'
import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
+import Breadcrumb from './Breadcrumb'
const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -160,6 +161,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
return (
<MobileView>
+ <Breadcrumb productId={product.id} productName={product.name} />
<div className='relative'>
{product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && (
<div className={`absolute bottom-0 w-full`}>
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index df9aa91b..f6987051 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -117,7 +117,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
<>
<MobileView>
{productSearch.isLoading && <ProductSearchSkeleton />}
- <div className='p-4'>
+ <div className='p-4 pt-0'>
<h1 className='mb-2 font-semibold text-h-sm'>Produk</h1>
<div className='mb-2 leading-6 text-gray_r-11'>
@@ -178,7 +178,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
</MobileView>
<DesktopView>
- <div className='container mx-auto mt-10 flex mb-3'>
+ <div className='container mx-auto flex mb-3'>
<div className='w-3/12'>
<ProductFilterDesktop
brands={brands || []}
diff --git a/src/lib/promotinProgram/components/PromotionType.jsx b/src/lib/promotinProgram/components/PromotionType.jsx
index ad7185e3..51f2622a 100644
--- a/src/lib/promotinProgram/components/PromotionType.jsx
+++ b/src/lib/promotinProgram/components/PromotionType.jsx
@@ -24,7 +24,7 @@ const PromotionType = ({
const id = variantId
const listProgram = async () => {
const programs = await getPromotionProgram({ id })
- if (programs.length > 0) {
+ if (programs?.length > 0) {
setPromotionList(programs)
setActiveTitle(programs?.[0].type.value)
}