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 /src/lib/product/components/Product.jsx | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
Refactor
Diffstat (limited to 'src/lib/product/components/Product.jsx')
| -rw-r--r-- | src/lib/product/components/Product.jsx | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/src/lib/product/components/Product.jsx b/src/lib/product/components/Product.jsx new file mode 100644 index 00000000..2a3624e7 --- /dev/null +++ b/src/lib/product/components/Product.jsx @@ -0,0 +1,276 @@ +import Badge from "@/core/components/elements/Badge/Badge" +import Divider from "@/core/components/elements/Divider/Divider" +import Image from "@/core/components/elements/Image/Image" +import Link from "@/core/components/elements/Link/Link" +import currencyFormat from "@/core/utils/currencyFormat" +import { useEffect, useState } from "react" +import Select from "react-select" +import ProductSimilar from "./ProductSimilar" +import LazyLoad from "react-lazy-load" +import { toast } from "react-hot-toast" +import { addItemCart } from "@/core/utils/cart" + +const informationTabOptions = [ + { value: 'specification', label: 'Spesifikasi' }, + { value: 'description', label: 'Deskripsi' }, + { value: 'important', label: 'Info Penting' }, +] + +const Product = ({ product }) => { + const [ quantity, setQuantity ] = useState('1') + const [ selectedVariant, setSelectedVariant ] = useState(null) + const [ informationTab, setInformationTab ] = useState(null) + + const [ activeVariant, setActiveVariant ] = useState({ + id: product.id, + code: product.code, + name: product.name, + price: product.lowestPrice, + stock: product.stockTotal, + weight: product.weight, + }) + + const variantOptions = product.variants?.map((variant) => ({ + value: variant.id, + label: + (variant.code ? `[${variant.code}] ` : '') + + + (variant.attributes.length > 0 ? variant.attributes.join(', ') : product.name) + })) + + useEffect(() => { + if (!selectedVariant && variantOptions.length == 1) { + setSelectedVariant(variantOptions[0]) + } + }, [selectedVariant, variantOptions]) + + useEffect(() => { + if (selectedVariant) { + const variant = product.variants.find(variant => variant.id == selectedVariant.value) + const variantAttributes = variant.attributes.length > 0 ? ' - ' + variant.attributes.join(', ') : '' + console.log(variant); + setActiveVariant({ + id: variant.id, + code: variant.code, + name: variant.parent.name + variantAttributes, + price: variant.price, + stock: variant.stock, + weight: variant.weight + }) + } + }, [selectedVariant, product]) + + useEffect(() => { + if (!informationTab) { + setInformationTab(informationTabOptions[0].value) + } + }, [informationTab]) + + const handleClickCart = () => { + if (!selectedVariant) { + toast.error('Pilih varian terlebih dahulu') + return + } + if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) { + toast.error('Jumlah barang minimal 1') + return + } + addItemCart({ + productId: activeVariant.id, + quantity + }) + toast.success('Berhasil menambahkan ke keranjang') + } + + return ( + <> + <Image + src={product.image} + alt={product.name} + className="h-72 object-contain object-center w-full border-b border-gray_r-4 bg-white" + /> + + <div className="p-4"> + <Link href="/" className="mb-2">{ product.manufacture?.name }</Link> + <h1 className="leading-6 font-medium"> + {activeVariant?.name} + </h1> + { activeVariant?.price?.discountPercentage > 0 && ( + <div className="flex gap-x-1 items-center mt-2"> + <div className="text-gray_r-11 line-through text-caption-1"> + {currencyFormat(activeVariant?.price?.priceDiscount)} + </div> + <Badge type="solid-red"> + {activeVariant?.price?.discountPercentage}% + </Badge> + </div> + ) } + <h3 className="text-red_r-11 font-semibold mt-1"> + { activeVariant?.price?.price > 0 ? currencyFormat(activeVariant?.price?.price) : ( + <span className="text-gray_r-11 leading-6 font-normal"> + Hubungi kami untuk dapatkan harga terbaik, + <a href="https://wa.me/" className="text-red_r-11 underline">klik disini</a> + </span> + ) } + </h3> + </div> + + <Divider /> + + <div className="p-4"> + <div> + <label className="flex justify-between"> + Pilih Varian: + <span className="text-gray_r-11"> + { product?.variantTotal } Varian + </span> + </label> + <Select + name="variant" + classNamePrefix="form-select" + options={variantOptions} + className="mt-2" + value={selectedVariant} + onChange={(option) => setSelectedVariant(option)} + isSearchable={product.variantTotal > 10} + /> + </div> + <div className="mt-4 mb-2">Jumlah</div> + <div className="flex gap-x-3"> + <div className="w-2/12"> + <input + name="quantity" + type="number" + className="form-input" + value={quantity} + onChange={(e) => setQuantity(e.target.value)} + /> + </div> + <button + type="button" + className="btn-yellow flex-1" + onClick={handleClickCart} + > + Keranjang + </button> + <button + type="button" + className="btn-solid-red flex-1" + > + Beli + </button> + </div> + </div> + + <Divider /> + + <div className="p-4"> + <h2 className="font-semibold">Informasi Produk</h2> + <div className="flex gap-x-4 mt-4 mb-3"> + { informationTabOptions.map((option) => ( + <TabButton + value={option.value} + key={option.value} + active={informationTab == option.value} + onClick={() => setInformationTab(option.value)} + > + {option.label} + </TabButton> + )) } + </div> + + <TabContent + active={informationTab == 'specification'} + className="rounded border border-gray_r-6 divide-y divide-gray_r-6" + > + <SpecificationContent label="Jumlah Varian"> + <span>{product?.variantTotal} Varian</span> + </SpecificationContent> + <SpecificationContent label="Nomor SKU"> + <span>SKU-{product?.id}</span> + </SpecificationContent> + <SpecificationContent label="Part Number"> + <span>{activeVariant?.code || '-'}</span> + </SpecificationContent> + <SpecificationContent label="Stok"> + { activeVariant?.stock > 0 && ( + <span className="flex gap-x-1.5"> + <div className="badge-solid-red">Ready Stock</div> + <div className="badge-gray"> + { activeVariant?.stock > 5 ? '> 5' : '< 5' } + </div> + </span> + ) } + { activeVariant?.stock == 0 && ( + <a + href="https://wa.me" + className="text-red_r-11 font-medium" + > + Tanya Stok + </a> + ) } + </SpecificationContent> + <SpecificationContent label="Berat Barang"> + { activeVariant?.weight > 0 && ( + <span>{ activeVariant?.weight } KG</span> + ) } + { activeVariant?.weight == 0 && ( + <a + href="https://wa.me" + className="text-red_r-11 font-medium" + > + Tanya Berat + </a> + ) } + </SpecificationContent> + </TabContent> + + <TabContent + active={informationTab == 'description'} + className="leading-6 text-gray_r-11" + dangerouslySetInnerHTML={{__html: (product.description != '' ? product.description : 'Belum ada deskripsi produk.')}} + /> + </div> + + <Divider /> + + <div className="p-4"> + <h2 className="font-semibold mb-4">Kamu Mungkin Juga Suka</h2> + <LazyLoad> + <ProductSimilar query={product?.name.split(' ').slice(1, 3).join(' ')} /> + </LazyLoad> + </div> + </> + ) +} + +const TabButton = ({ children, active, ...props }) => { + const activeClassName = active ? 'text-red_r-11 border-b border-red_r-11' : 'text-gray_r-11' + return ( + <button + {...props} + type="button" + className={`font-medium pb-1 ${activeClassName}`} + > + { children } + </button> + ) +} + +const TabContent = ({ children, active, className, ...props }) => ( + <div + {...props} + className={`${active ? 'block' : 'hidden'} ${className}`} + > + { children } + </div> +) + +const SpecificationContent = ({ children, label }) => ( + <div className="flex justify-between p-3"> + <span className="text-gray_r-11">{ label }</span> + { children } + </div> +) + +export default Product
\ No newline at end of file |
