diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-17 17:07:50 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-17 17:07:50 +0700 |
| commit | f99e0aba70efad0deb907d8e27f09fc9f527c8a4 (patch) | |
| tree | f0ac96e4e736a1d385e32553f0e641ee27e11fd3 /src2/components/products | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
Refactor
Diffstat (limited to 'src2/components/products')
| -rw-r--r-- | src2/components/products/ProductCard.js | 69 | ||||
| -rw-r--r-- | src2/components/products/ProductCategories.js | 62 | ||||
| -rw-r--r-- | src2/components/products/ProductSimilar.js | 25 | ||||
| -rw-r--r-- | src2/components/products/ProductSlider.js | 39 |
4 files changed, 195 insertions, 0 deletions
diff --git a/src2/components/products/ProductCard.js b/src2/components/products/ProductCard.js new file mode 100644 index 00000000..c79a4900 --- /dev/null +++ b/src2/components/products/ProductCard.js @@ -0,0 +1,69 @@ +import Link from "../elements/Link"; +import currencyFormat from "@/core/utils/currencyFormat"; +import { createSlug } from "@/core/utils/slug"; +import { ChevronRightIcon } from "@heroicons/react/20/solid"; +import Image from "../elements/Image"; + + +export default function ProductCard({ + data, + simpleProductTitleLine = false +}) { + let product = data; + return ( + <div className="product-card"> + <Link href={'/shop/product/' + createSlug(product.name, product.id)} className="block relative bg-white"> + <Image + src={product.image} + alt={product.name} + className="product-card__image" + /> + {product.variant_total > 1 ? ( + <div className="absolute bottom-2 left-2 badge-gray">{product.variant_total} Varian</div> + ) : ''} + </Link> + <div className="product-card__content"> + <div> + {typeof product.manufacture.name !== "undefined" ? ( + <Link href={'/shop/brands/' + createSlug(product.manufacture.name, product.manufacture.id)} className="product-card__brand">{product.manufacture.name}</Link> + ) : ( + <span className="product-card__brand">-</span> + )} + <Link href={'/shop/product/' + createSlug(product.name, product.id)} className={`product-card__title ${simpleProductTitleLine ? 'wrap-line-ellipsis-2' : 'wrap-line-ellipsis-3'}`}> + {product.name} + </Link> + </div> + <div className="mt-2"> + {product.lowest_price.discount_percentage > 0 ? ( + <div className="flex gap-x-1 items-center mb-1"> + <p className="text-caption-2 text-gray_r-11 line-through">{currencyFormat(product.lowest_price.price)}</p> + <span className="badge-solid-red">{product.lowest_price.discount_percentage}%</span> + </div> + ) : ''} + + {product.lowest_price.price_discount > 0 ? ( + <p className="text-caption-1 text-gray_r-12 font-bold"> + {currencyFormat(product.lowest_price.price_discount)} + </p> + ) : ( + <a + href="https://wa.me" + target="_blank" + rel="noreferrer" + className="flex items-center gap-x-1 text-caption-1" + > + Tanya Harga <ChevronRightIcon className="text-yellow_r-11 w-5 h-5" /> + </a> + )} + + {product.stock_total > 0 ? ( + <div className="flex gap-x-1 mt-2"> + <div className="badge-solid-red">Ready Stock</div> + <div className="badge-gray">{product.stock_total > 5 ? '> 5' : '< 5'}</div> + </div> + ) : ''} + </div> + </div> + </div> + ) +}
\ No newline at end of file diff --git a/src2/components/products/ProductCategories.js b/src2/components/products/ProductCategories.js new file mode 100644 index 00000000..3b671f29 --- /dev/null +++ b/src2/components/products/ProductCategories.js @@ -0,0 +1,62 @@ +import { useEffect, useState } from "react"; +import ProductSlider from "./ProductSlider"; +import apiOdoo from "@/core/utils/apiOdoo"; +import { LazyLoadComponent } from "react-lazy-load-image-component"; +import { SkeletonProduct } from "../elements/Skeleton"; + +const ProductCategory = ({ id }) => { + const [ content, setContent ] = useState(null); + + useEffect(() => { + const loadContent = async () => { + if (!content) { + const dataContent = await apiOdoo('GET', `/api/v1/categories_homepage?id=${id}`); + setContent(dataContent[0]); + } + } + loadContent(); + }, [id, content]); + + return ( + <div className="p-4 relative bg-yellow_r-2"> + { content ? ( + <ProductSlider + products={{ + products: content.products, + banner: { + image: content.image, + name: content.name, + url: `/shop/search?category=${content.name}` + } + }} + simpleProductTitleLine + bannerMode + /> + ) : <SkeletonProduct /> } + </div> + ); +} + +export default function ProductCategories() { + const [ contentIds, setContentIds ] = useState([]); + + useEffect(() => { + const getContentIds = async () => { + if (contentIds.length == 0) { + const dataContentIds = await apiOdoo('GET', '/api/v1/categories_homepage/ids'); + setContentIds(dataContentIds); + } + } + getContentIds(); + }, [ contentIds ]); + + return ( + <div className="flex flex-col gap-y-6"> + { contentIds.map((contentId) => ( + <LazyLoadComponent placeholder={<SkeletonProduct/>} key={contentId}> + <ProductCategory id={contentId} /> + </LazyLoadComponent> + )) } + </div> + ) +}
\ No newline at end of file diff --git a/src2/components/products/ProductSimilar.js b/src2/components/products/ProductSimilar.js new file mode 100644 index 00000000..9e2292cb --- /dev/null +++ b/src2/components/products/ProductSimilar.js @@ -0,0 +1,25 @@ +import apiOdoo from '@/core/utils/apiOdoo'; +import { useEffect, useState } from 'react'; +import ProductSlider from './ProductSlider'; + +export default function ProductSimilar({ productId }) { + const [similarProducts, setSimilarProducts] = useState(null); + + useEffect(() => { + const getSimilarProducts = async () => { + if (productId && !similarProducts) { + const dataSimilarProducts = await apiOdoo('GET', `/api/v1/product/${productId}/similar?limit=20`); + setSimilarProducts(dataSimilarProducts); + } + } + getSimilarProducts(); + }, [productId, similarProducts]); + + + return ( + <div className="p-4"> + <h2 className="font-bold mb-4">Kamu Mungkin Juga Suka</h2> + <ProductSlider products={similarProducts}/> + </div> + ) +}
\ No newline at end of file diff --git a/src2/components/products/ProductSlider.js b/src2/components/products/ProductSlider.js new file mode 100644 index 00000000..662a6511 --- /dev/null +++ b/src2/components/products/ProductSlider.js @@ -0,0 +1,39 @@ +import { Swiper, SwiperSlide } from "swiper/react"; +import ProductCard from "./ProductCard"; +import "swiper/css"; +import Image from "../elements/Image"; +import Link from "../elements/Link"; +import { SkeletonProduct } from "../elements/Skeleton"; +import { useState } from "react"; + +export default function ProductSlider({ + products, + simpleProductTitleLine = false, + bannerMode = false +}) { + const [ activeIndex, setActiveIndex ] = useState(0); + const swiperSliderFirstMove = (swiper) => { + setActiveIndex(swiper.activeIndex); + }; + + return ( + <> + { bannerMode && ( + <Image src={products.banner.image} alt={products.banner.name} className={`absolute rounded-r top-0 left-0 h-full max-w-[52%] idt-transition border border-gray_r-6 ` + (activeIndex > 0 ? 'opacity-0' : 'opacity-100')} /> + ) } + <Swiper freeMode={true} slidesPerView={2.2} spaceBetween={8} onSlideChange={swiperSliderFirstMove} prefix="product"> + { bannerMode && ( + <SwiperSlide> + <Link href={products.banner.url} className="w-full h-full block"></Link> + </SwiperSlide> + ) } + {products?.products?.map((product, index) => ( + <SwiperSlide key={index}> + <ProductCard data={product} simpleProductTitleLine={simpleProductTitleLine} /> + </SwiperSlide> + ))} + </Swiper> + { !products ? <SkeletonProduct /> : ''} + </> + ) +}
\ No newline at end of file |
