summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortrisusilo <tri.susilo@altama.co.id>2023-10-03 08:27:50 +0000
committertrisusilo <tri.susilo@altama.co.id>2023-10-03 08:27:50 +0000
commitcf0b3bff8547783fe518351dd85debdc1e9633e4 (patch)
treeb0bc7f485865dca0eb17b8e0424a52037031dc98 /src
parent23b667695991fafeae523aff1de7df81770461cd (diff)
parent787d3aaa3187d3432c8e6b743b555ea3e4a4980c (diff)
Merged in CR/Pricelist (pull request #80)
CR/Pricelist
Diffstat (limited to 'src')
-rw-r--r--src/core/components/elements/Image/Image.jsx12
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx20
-rw-r--r--src/core/components/elements/Skeleton/ProductCardSkeleton.jsx68
-rw-r--r--src/lib/brand/components/Brands.jsx15
-rw-r--r--src/lib/cart/components/Cartheader.jsx12
-rw-r--r--src/lib/checkout/components/CheckoutOld.jsx1
-rw-r--r--src/lib/home/components/PreferredBrand.jsx6
-rw-r--r--src/lib/home/components/ServiceList.jsx105
-rw-r--r--src/lib/home/components/Skeleton/PopularProductSkeleton.jsx3
-rw-r--r--src/lib/home/hooks/usePreferredBrand.js13
-rw-r--r--src/lib/product/components/Product/ColumnsSLA.jsx89
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx172
-rw-r--r--src/lib/product/components/Product/ProductDesktopVariant.jsx164
-rw-r--r--src/lib/product/components/Product/ProductMobile.jsx70
-rw-r--r--src/lib/product/components/Product/ProductMobileVariant.jsx84
-rw-r--r--src/lib/product/components/ProductCard.jsx89
-rw-r--r--src/lib/product/components/ProductFilterDesktop.jsx165
-rw-r--r--src/lib/product/components/ProductSearch.jsx8
-rw-r--r--src/lib/product/components/ProductSlider.jsx2
-rw-r--r--src/pages/_app.jsx41
-rw-r--r--src/pages/api/shop/brands.js44
-rw-r--r--src/pages/api/shop/search.js17
-rw-r--r--src/pages/index.jsx5
23 files changed, 699 insertions, 506 deletions
diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx
index ba6bf50d..d7b19821 100644
--- a/src/core/components/elements/Image/Image.jsx
+++ b/src/core/components/elements/Image/Image.jsx
@@ -9,18 +9,18 @@ import 'react-lazy-load-image-component/src/effects/opacity.css'
* @param {string} props.alt - Alternative text to be displayed if the image is not found.
* @returns {JSX.Element} - Rendered `Image` component.
*/
-const Image = ({ ...props }) => (
- <>
+const Image = ({ ...props }) => {
+ return (
<LazyLoadImage
{...props}
src={props.src || '/images/noimage.jpeg'}
placeholderSrc='/images/indoteknik-placeholder.png'
+ effect='opacity'
alt={props.src ? props.alt : 'Image Not Found - Indoteknik'}
wrapperClassName='bg-white'
+ loading='eager'
/>
- </>
-)
-
-Image.defaultProps = LazyLoadImage.defaultProps
+ )
+}
export default Image
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index 3aba55c9..fb94e4a6 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -111,26 +111,6 @@ const NavbarDesktop = () => {
Quotation
</Link>
<Cardheader cartCount={cartCount}/>
- {/* <Link
- href='/shop/cart'
- target='_blank'
- rel='noreferrer'
- className='flex items-center gap-x-2 !text-gray_r-12/80'
- >
- <div className={`relative ${cartCount > 0 && 'mr-2'}`}>
- <ShoppingCartIcon className='w-7' />
- {cartCount > 0 && (
- <span className='absolute -top-2 -right-2 badge-solid-red rounded-full w-5 h-5 flex items-center justify-center'>
- {cartCount}
- </span>
- )}
- </div>
- <span>
- Keranjang
- <br />
- Belanja
- </span>
- </Link> */}
<Link
target='_blank'
rel='noreferrer'
diff --git a/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
index 84d1c0d1..1e0ca6a3 100644
--- a/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
+++ b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
@@ -1,26 +1,46 @@
-const ProductCardSkeleton = () => (
- <div
- role='status'
- className='p-4 max-w-sm rounded border border-gray-300 shadow animate-pulse md:p-6'
- >
- <div className='flex items-center justify-center h-36 mb-4 bg-gray-300 rounded' aria-busy>
- <svg
- className='w-12 h-12 text-gray-200'
- xmlns='http://www.w3.org/2000/svg'
- aria-hidden='true'
- fill='currentColor'
- viewBox='0 0 640 512'
- >
- <path d='M480 80C480 35.82 515.8 0 560 0C604.2 0 640 35.82 640 80C640 124.2 604.2 160 560 160C515.8 160 480 124.2 480 80zM0 456.1C0 445.6 2.964 435.3 8.551 426.4L225.3 81.01C231.9 70.42 243.5 64 256 64C268.5 64 280.1 70.42 286.8 81.01L412.7 281.7L460.9 202.7C464.1 196.1 472.2 192 480 192C487.8 192 495 196.1 499.1 202.7L631.1 419.1C636.9 428.6 640 439.7 640 450.9C640 484.6 612.6 512 578.9 512H55.91C25.03 512 .0006 486.1 .0006 456.1L0 456.1z' />
- </svg>
- </div>
- <div className='h-2 bg-gray-200 rounded-full w-10 mb-1'></div>
- <div className='h-2.5 bg-gray-200 rounded-full w-full mb-4'></div>
- <div className='h-2 bg-gray-200 rounded-full mb-2.5'></div>
- <div className='h-2 bg-gray-200 rounded-full mb-2.5'></div>
- <div className='h-2 bg-gray-200 rounded-full'></div>
- <span className='sr-only'>Loading...</span>
- </div>
-)
+import { Box, HStack, Skeleton, SkeletonText, VStack, useBreakpointValue } from '@chakra-ui/react'
+
+const ProductCardSkeleton = () => {
+ const wrapperHeight = useBreakpointValue({ base: '300px', md: '350px' })
+ return (
+ <Box
+ role='status'
+ w='100%'
+ bgColor='white'
+ h={wrapperHeight}
+ borderWidth='1px'
+ borderRadius='md'
+ >
+ <Skeleton height='50%' {...skeletonColors} />
+
+ <VStack padding='10px 12px 16px 12px' height='50%'>
+ <Box w='full'>
+ <Skeleton height='12px' w='30%' {...skeletonColors} />
+ <SkeletonText
+ noOfLines={2}
+ spacing='8px'
+ skeletonHeight='12px'
+ mt='12px'
+ {...skeletonColors}
+ />
+ </Box>
+
+ <VStack spacing='12px' alignItems='flex-start' mt='20px' w='full'>
+ <HStack spacing='8px' w='full'>
+ <Skeleton height='12px' w='60%' {...skeletonColors} />
+ <Skeleton height='12px' w='10%' {...skeletonColors} />
+ </HStack>
+ <Skeleton height='12px' w='50%' {...skeletonColors} />
+ </VStack>
+ </VStack>
+ <span className='sr-only'>Loading...</span>
+ </Box>
+ )
+}
+
+const skeletonColors = {
+ startColor: 'gray.200',
+ endColor: 'gray.400'
+}
export default ProductCardSkeleton
diff --git a/src/lib/brand/components/Brands.jsx b/src/lib/brand/components/Brands.jsx
index c7483e40..f6cb4fbf 100644
--- a/src/lib/brand/components/Brands.jsx
+++ b/src/lib/brand/components/Brands.jsx
@@ -1,7 +1,7 @@
-import odooApi from '@/core/api/odooApi'
import { useCallback, useEffect, useState } from 'react'
import BrandCard from './BrandCard'
import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
+import axios from 'axios'
const Brands = () => {
const alpha = Array.from(Array(26)).map((e, i) => i + 65)
@@ -13,13 +13,18 @@ const Brands = () => {
const loadBrand = useCallback(async () => {
setIsLoading(true)
- const name = startWith ? `${startWith}%` : ''
- const result = await odooApi(
+ const name = startWith ? `${startWith}*` : ''
+ //Get brand from odoo
+ /*const result = await odooApi(
'GET',
`/api/v1/manufacture?limit=0&offset=${manufactures.length}&name=${name}`
- )
+ )*/
+
+ // Change get brands from solr
+ const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=${name}`)
+
setIsLoading(false)
- setManufactures((manufactures) => [...manufactures, ...result.manufactures])
+ setManufactures((manufactures) => [...result.data])
}, [startWith])
const toggleStartWith = (alphabet) => {
diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx
index dd6c276e..cbe7c7e1 100644
--- a/src/lib/cart/components/Cartheader.jsx
+++ b/src/lib/cart/components/Cartheader.jsx
@@ -48,7 +48,7 @@ const Cardheader = (cartCount) => {
setProductCart(cart)
setCountCart(cart.productTotal)
setIsloading(false)
- }, [setProductCart])
+ }, [setProductCart, setIsloading])
useEffect(() => {
if (!products) return
@@ -158,14 +158,14 @@ const Cardheader = (cartCount) => {
</div>
</div>
))}
- {products.length === 0 && !isLoading && (
+ {auth && products.length === 0 && !isLoading && (
<div className='justify-center p-4'>
<p className='text-gray-500 text-center '>
Tidak Ada Produk di Keranjang Belanja Anda
</p>
</div>
)}
- {products.length > 0 && !isLoading && (
+ {auth && products.length > 0 && !isLoading && (
<>
<ul role='list' class='divide-y divide-gray-200 dark:divide-gray-700'>
{products &&
@@ -251,11 +251,11 @@ const Cardheader = (cartCount) => {
</>
)}
</div>
- {products.length > 0 && !isLoading && (
+ {auth && products.length > 0 && !isLoading && (
<>
<div className='mt-3'>
- <span className='text-gray-400 text-caption-2'>Sub Total Sebelum PPN : </span>
- <span className='font-semibold text-red-600'>Rp. {currencyFormat(subTotal)}</span>
+ <span className='text-gray-400 text-caption-2'>Subtotal Sebelum PPN : </span>
+ <span className='font-semibold text-red-600'>{currencyFormat(subTotal)}</span>
</div>
<div className='mt-5 mb-2'>
<button
diff --git a/src/lib/checkout/components/CheckoutOld.jsx b/src/lib/checkout/components/CheckoutOld.jsx
index 088b641b..6852059e 100644
--- a/src/lib/checkout/components/CheckoutOld.jsx
+++ b/src/lib/checkout/components/CheckoutOld.jsx
@@ -22,7 +22,6 @@ import DesktopView from '@/core/components/views/DesktopView'
import ExpedisiList from '../api/ExpedisiList'
import whatsappUrl from '@/core/utils/whatsappUrl'
import { createSlug } from '@/core/utils/slug'
-import { Button, Modal } from 'flowbite-react'
import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
const SELF_PICKUP_ID = 32
diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx
index 55abe0b7..571c4745 100644
--- a/src/lib/home/components/PreferredBrand.jsx
+++ b/src/lib/home/components/PreferredBrand.jsx
@@ -6,7 +6,9 @@ import useDevice from '@/core/hooks/useDevice'
import Link from '@/core/components/elements/Link/Link'
const PreferredBrand = () => {
- const { preferredBrands } = usePreferredBrand()
+ let query = 'level_s'
+ let params = 'prioritas'
+ const { preferredBrands } = usePreferredBrand(query)
const { isMobile, isDesktop } = useDevice()
return (
@@ -22,7 +24,7 @@ const PreferredBrand = () => {
{preferredBrands.isLoading && <PreferredBrandSkeleton />}
{!preferredBrands.isLoading && (
<Swiper slidesPerView={isMobile ? 3.5 : 7.5} spaceBetween={isMobile ? 12 : 24} freeMode>
- {preferredBrands.data?.manufactures.map((brand) => (
+ {preferredBrands.data?.data.map((brand) => (
<SwiperSlide key={brand.id}>
<BrandCard brand={brand} />
</SwiperSlide>
diff --git a/src/lib/home/components/ServiceList.jsx b/src/lib/home/components/ServiceList.jsx
new file mode 100644
index 00000000..b8799d7d
--- /dev/null
+++ b/src/lib/home/components/ServiceList.jsx
@@ -0,0 +1,105 @@
+import Image from 'next/image'
+import Link from '@/core/components/elements/Link/Link'
+
+const ServiceList = () => {
+ return (
+ <div className='px-4 sm:px-0'>
+ <div className='grid md:grid-cols-4 grid-cols-2 justify-between gap-2 items-center'>
+ <div className='w-full'>
+ <Link
+ href='/tentang-kami'
+ className='border border-gray-200 p-2 flex items-center gap-x-2 rounded-lg'
+ >
+ <div className=''>
+ <Image
+ width={24}
+ height={24}
+ quality={100}
+ src='/images/icon_service/ONE-STOP-SOLUTIONS.svg'
+ alt=''
+ className='h-20 w-20 rounded'
+ />
+ </div>
+ <div className=''>
+ <h1 className='text-gray-900 font-semibold text-base'>One Stop Solution</h1>
+ <p className='text-xs md:text-sm text-gray-500'>
+ Temukan Solusi Lengkap Anda dalam Satu Tempat.
+ </p>
+ </div>
+ </Link>
+ </div>
+ <div className='w-full'>
+ <Link
+ href='/tentang-kami'
+ className='border border-gray-200 p-2 flex items-center gap-x-2 rounded-lg'
+ >
+ <div className=''>
+ <Image
+ width={24}
+ height={24}
+ quality={100}
+ src='/images/icon_service/WARRANTY.svg'
+ alt=''
+ className='h-20 w-20 rounded'
+ />
+ </div>
+ <div>
+ <h1 className='text-gray-900 font-semibold text-base'>Garansi Resmi</h1>
+ <p className='text-xs md:text-sm text-gray-500'>
+ Garansi Keaslian Barang dan Jaminan Purna Jual.
+ </p>
+ </div>
+ </Link>
+ </div>
+ <div className='w-full '>
+ <Link
+ href='/tentang-kami'
+ className='border border-gray-200 p-2 flex items-center gap-x-2 rounded-lg'
+ >
+ <div className=''>
+ <Image
+ width={24}
+ height={24}
+ quality={100}
+ src='/images/icon_service/DUE-PAYMENT.svg'
+ alt=''
+ className='h-20 w-20 rounded'
+ />
+ </div>
+ <div>
+ <h1 className='text-gray-900 font-semibold text-base'>Pembayaran Tempo</h1>
+ <p className='text-xs md:text-sm text-gray-500'>
+ Lebih mudah mengatur pembelian dengan pembayaran tempo.
+ </p>
+ </div>
+ </Link>
+ </div>
+ <div className='w-full'>
+ <Link
+ href='/tentang-kami'
+ className='border border-gray-200 p-2 flex items-center gap-x-2 rounded-lg'
+ >
+ <div className=''>
+ <Image
+ width={24}
+ height={24}
+ quality={100}
+ src='/images/icon_service/TAX.svg'
+ alt=''
+ className='h-20 w-20 rounded'
+ />
+ </div>
+ <div>
+ <h1 className='text-gray-900 font-semibold text-base'>Faktur Pajak</h1>
+ <p className='text-xs md:text-sm text-gray-500'>
+ Dapat Faktur pajak untuk setiap transaksi dengan indoteknik.com
+ </p>
+ </div>
+ </Link>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default ServiceList
diff --git a/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx b/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx
index 29fda966..754bdd57 100644
--- a/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx
+++ b/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx
@@ -11,7 +11,8 @@ const PopularProductSkeleton = () => (
</div>
</MobileView>
<DesktopView>
- <div className='grid grid-cols-5 gap-x-3'>
+ <div className='grid grid-cols-6 gap-x-3'>
+ <ProductCardSkeleton />
<ProductCardSkeleton />
<ProductCardSkeleton />
<ProductCardSkeleton />
diff --git a/src/lib/home/hooks/usePreferredBrand.js b/src/lib/home/hooks/usePreferredBrand.js
index e56d361f..b7d707e6 100644
--- a/src/lib/home/hooks/usePreferredBrand.js
+++ b/src/lib/home/hooks/usePreferredBrand.js
@@ -1,3 +1,4 @@
+import axios from 'axios'
import preferredBrandApi from '../api/preferredBrandApi'
import { useQuery } from 'react-query'
@@ -10,4 +11,14 @@ const usePreferredBrand = () => {
}
}
-export default usePreferredBrand
+const GetBrands = (query) => {
+ const fetchingbrand = async () =>
+ await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=` + query)
+
+ const { data, isLoading } = useQuery('preferredBrand', fetchingbrand)
+ return {
+ preferredBrands: { data, isLoading }
+ }
+}
+
+export default GetBrands
diff --git a/src/lib/product/components/Product/ColumnsSLA.jsx b/src/lib/product/components/Product/ColumnsSLA.jsx
index 33da703a..e5296f96 100644
--- a/src/lib/product/components/Product/ColumnsSLA.jsx
+++ b/src/lib/product/components/Product/ColumnsSLA.jsx
@@ -1,8 +1,9 @@
import odooApi from '@/core/api/odooApi'
import { createSlug } from '@/core/utils/slug'
import whatsappUrl from '@/core/utils/whatsappUrl'
-import { Button, Spinner } from 'flowbite-react'
-import { memo, useEffect, useState } from 'react'
+import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
+import { Info } from 'lucide-react'
+import { memo } from 'react'
import { useQuery } from 'react-query'
const ColumnSLA = ({ variant, product }) => {
@@ -12,67 +13,35 @@ const ColumnSLA = ({ variant, product }) => {
return (
<>
<td>
- {dataSLA.isFetching ? (
- <div className='text-center'>
- <Spinner aria-label='Center-aligned spinner example' />
- </div>
- ) : dataSLA?.data?.qty > 0 ? (
- dataSLA?.data?.qty
- ) : (
- <a
- href={whatsappUrl('product', {
- name: variant.name,
- manufacture: product.manufacture?.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 font-medium'
- target='_blank'
- rel='noreferrer noopener'
- >
- Tanya Admin
- </a>
- )}
+ <Skeleton isLoaded={!dataSLA.isFetching} w='full'>
+ {dataSLA?.data?.qty > 0 ? (
+ dataSLA?.data?.qty
+ ) : (
+ <a
+ href={whatsappUrl('product', {
+ name: variant.name,
+ manufacture: product.manufacture?.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
+ })}
+ className='text-danger-500 font-medium'
+ target='_blank'
+ rel='noreferrer noopener'
+ >
+ Tanya Admin
+ </a>
+ )}
+ </Skeleton>
</td>
+
<td className='flex justify-center'>
- {dataSLA.isFetching ? (
- <Button color='gray'>
- <Spinner aria-label='Alternate spinner button example' />
- <span className='pl-3'>Loading...</span>
- </Button>
- ) : dataSLA?.data?.slaDate != '-' ? (
- <button
- type='button'
- title={`Masa Persiapan Barang ${dataSLA?.data?.slaDate}`}
- className={`flex gap-x-1 items-center p-2 rounded-lg w-full ${
- dataSLA?.data?.slaDate === 'indent' ? 'bg-indigo-900' : 'btn-light'
- }`}
- >
- <div
- className={`flex-1 text-caption-1 ${
- dataSLA?.data?.slaDate === 'indent' ? 'text-white' : ''
- }`}
- >
+ <Skeleton isLoaded={!dataSLA.isFetching} w='75%'>
+ <Tooltip placement='top' label={`Masa Persiapan Barang ${dataSLA?.data?.slaDate}`}>
+ <Box className='border border-gray_r-7 rounded-md p-2 flex justify-center items-center gap-x-2'>
{dataSLA?.data?.slaDate}
- </div>
- <div className='flex-end'>
- <svg
- aria-hidden='true'
- fill='none'
- stroke='currentColor'
- stroke-width='1.5'
- className={`w-7 h-7 ${dataSLA?.data?.slaDate === 'indent' ? 'text-white' : ''}`}
- >
- <path
- d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z'
- stroke-linecap='round'
- stroke-linejoin='round'
- ></path>
- </svg>
- </div>
- </button>
- ) : (
- '-'
- )}
+ <Info size={16} />
+ </Box>
+ </Tooltip>
+ </Skeleton>
</td>
</>
)
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index 6da289bc..0df60673 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -15,7 +15,6 @@ import ProductCard from '../ProductCard'
import productSimilarApi from '../../api/productSimilarApi'
import whatsappUrl from '@/core/utils/whatsappUrl'
import odooApi from '@/core/api/odooApi'
-import { Button, Spinner } from 'flowbite-react'
import PromotionType from '@/lib/promotinProgram/components/PromotionType'
import useAuth from '@/core/hooks/useAuth'
import ImageNext from 'next/image'
@@ -23,6 +22,8 @@ import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
import { LazyLoadComponent } from 'react-lazy-load-image-component'
import ColumnsSLA from './ColumnsSLA'
import { useProductCartContext } from '@/contexts/ProductCartContext'
+import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
+import { Info } from 'lucide-react'
const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -40,7 +41,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
const [selectVariantPromoActive, setSelectVariantPromoActive] = useState(null)
const [backgorundFlashSale, setBackgorundFlashSale] = useState(null)
- const {setRefreshCart , refreshCart} = useProductCartContext()
+ const { setRefreshCart, refreshCart } = useProductCartContext()
const getLowestPrice = useCallback(() => {
const prices = product.variants.map((variant) => variant.price)
@@ -256,16 +257,16 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<h1 className='text-title-md leading-10 font-medium'>{product?.name}</h1>
<div className='mt-10'>
<div className='flex p-3'>
- <div className='w-1/4 text-gray_r-12/70'>Nomor SKU</div>
- <div className='w-3/4'>SKU-{product.id}</div>
+ <div className='w-4/12 text-gray_r-12/70'>Nomor SKU</div>
+ <div className='w-8/12'>SKU-{product.id}</div>
</div>
<div className='flex p-3 bg-gray_r-4'>
- <div className='w-1/4 text-gray_r-12/70'>Part Number</div>
- <div className='w-3/4'>{product.code || '-'}</div>
+ <div className='w-4/12 text-gray_r-12/70'>Part Number</div>
+ <div className='w-8/12'>{product.code || '-'}</div>
</div>
<div className='flex p-3'>
- <div className='w-1/4 text-gray_r-12/70'>Manufacture</div>
- <div className='w-3/4'>
+ <div className='w-4/12 text-gray_r-12/70'>Manufacture</div>
+ <div className='w-8/12'>
{product.manufacture?.name ? (
<Link
href={createSlug(
@@ -282,9 +283,9 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
</div>
<div className='flex p-3 items-center bg-gray_r-4'>
- <div className='w-1/4 text-gray_r-12/70'>Persiapan Barang</div>
- <div className='w-3/4'>
- {product.variants.length > 1 ? (
+ <div className='w-4/12 text-gray_r-12/70'>Persiapan Barang</div>
+ <div className='w-8/12'>
+ {product.variants.length > 1 && (
<button
type='button'
onClick={goToVariantSection}
@@ -292,62 +293,32 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
>
<span className='text-red-600 text-sm'>Lihat Selengkapnya</span>
</button>
- ) : product.variants[0].sla ? (
- product.variants[0].sla?.slaDate != '-' ? (
- <button
- type='button'
- title={`Masa Persiapan Barang ${product.variants[0].sla?.slaDate}`}
- className={`flex gap-x-1 items-center p-2 rounded-lg w-auto ${
- product.variants[0].sla?.slaDate === 'indent'
- ? 'bg-indigo-900'
- : 'btn-light'
- }`}
- >
- <div
- className={`flex-1 text-caption-1 ${
- product.variants[0].sla?.slaDate === 'indent' ? 'text-white' : ''
- }`}
+ )}
+
+ {product.variants.length === 1 && (
+ <>
+ {!product.variants[0]?.sla && <Skeleton width='20%' height='16px' />}
+ {product.variants[0]?.sla && (
+ <Tooltip
+ placement='top'
+ label={`Masa Persiapan Barang ${product.variants[0]?.sla?.slaDate}`}
>
- {product.variants[0].sla?.slaDate}
- </div>
- <div className='flex-end'>
- <svg
- aria-hidden='true'
- fill='none'
- stroke='currentColor'
- stroke-width='1.5'
- className={`w-7 h-7 ${
- product.variants[0].sla?.slaDate === 'indent' ? 'text-white' : ''
- }`}
- >
- <path
- d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z'
- stroke-linecap='round'
- stroke-linejoin='round'
- ></path>
- </svg>
- </div>
- </button>
- ) : (
- '-'
- )
- ) : (
- <Button color='gray'>
- <Spinner aria-label='Alternate spinner button example' />
- <span className='pl-3'>Loading...</span>
- </Button>
+ <Box className='w-fit flex items-center gap-x-2'>
+ {product.variants[0]?.sla?.slaDate}
+ <Info size={16} />
+ </Box>
+ </Tooltip>
+ )}
+ </>
)}
</div>
</div>
+
{product.variants.length === 1 && (
<div className='flex p-3 '>
- <div className='w-1/4 text-gray_r-12/70'>Stock</div>
- <div className='w-3/4'>
- {isLoadingSLA && (
- <div className=''>
- <Spinner aria-label='Center-aligned spinner example' />
- </div>
- )}
+ <div className='w-4/12 text-gray_r-12/70'>Stock</div>
+ <div className='w-8/12'>
+ {!product.variants[0]?.sla && <Skeleton width='10%' height='16px' />}
{product?.variants[0].sla?.qty > 0 && (
<span>{product?.variants[0].sla?.qty}</span>
)}
@@ -366,9 +337,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
</div>
)}
+
<div className={`flex p-3 ${product.variants.length > 1 ? '' : 'bg-gray_r-4'} `}>
- <div className='w-1/4 text-gray_r-12/70'>Berat Barang</div>
- <div className='w-3/4'>
+ <div className='w-4/12 text-gray_r-12/70'>Berat Barang</div>
+ <div className='w-8/12'>
{product?.weight > 0 && <span>{product?.weight} KG</span>}
{product?.weight == 0 && (
<a
@@ -441,13 +413,13 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<div className='text-gray_r-12/80'>Harga mulai dari: </div>
)}
- {lowestPrice?.discountPercentage > 0 && (
+ {/* {lowestPrice?.discountPercentage > 0 && (
<div className='flex gap-x-1 items-center mt-2'>
<div className='badge-solid-red text-caption-1'>
{lowestPrice?.discountPercentage}%
</div>
- <div className='text-gray_r-11 line-through text-caption-1'>
- {currencyFormat(lowestPrice?.price)}
+ <div className='text-gray_r-9 text-caption-1'>
+ Include PPN {currencyFormat(lowestPrice?.price * process.env.NEXT_PUBLIC_PPN)}
</div>
{product.flashSale.remainingTime > 0 && (
<div className='bg-red-600 rounded-full mb-1 p-2 pl-3 pr-3 flex w-fit items-center gap-x-1'>
@@ -464,28 +436,54 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
)}
</div>
+ )} */}
+
+ {product?.flashSale?.remainingTime > 0 ? (
+ <>
+ <div className='flex gap-x-1 items-center mt-2'>
+ <div className='badge-solid-red text-caption-1'>
+ {lowestPrice?.discountPercentage}%
+ </div>
+ <div className='text-gray_r-9 line-through text-caption-1'>
+ {currencyFormat(lowestPrice?.price)}
+ </div>
+ <div className='text-danger-500 font-semibold text-xl'>
+ {currencyFormat(lowestPrice?.priceDiscount)}
+ </div>
+ </div>
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN: {currencyFormat(lowestPrice?.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <h3 className='text-danger-500 font-semibold mt-1 text-title-md'>
+ {lowestPrice?.price > 0 ? (
+ <>
+ {currencyFormat(lowestPrice?.price)}
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN: {currencyFormat(lowestPrice?.price * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <span className='text-gray_r-12/90 font-normal text-h-sm'>
+ Hubungi kami untuk dapatkan harga terbaik,&nbsp;
+ <a
+ href={whatsappUrl('product', {
+ name: product.name,
+ manufacture: product.manufacture?.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
+ })}
+ className='text-danger-500 underline'
+ rel='noopener noreferrer'
+ target='_blank'
+ >
+ klik disini
+ </a>
+ </span>
+ )}
+ </h3>
)}
- <h3 className='text-danger-500 font-semibold mt-1 text-title-md'>
- {lowestPrice?.priceDiscount > 0 ? (
- currencyFormat(lowestPrice?.priceDiscount)
- ) : (
- <span className='text-gray_r-12/90 font-normal text-h-sm'>
- Hubungi kami untuk dapatkan harga terbaik,&nbsp;
- <a
- href={whatsappUrl('product', {
- name: product.name,
- manufacture: product.manufacture?.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 underline'
- rel='noopener noreferrer'
- target='_blank'
- >
- klik disini
- </a>
- </span>
- )}
- </h3>
+
{product.variants.length > 1 ? (
<button
type='button'
diff --git a/src/lib/product/components/Product/ProductDesktopVariant.jsx b/src/lib/product/components/Product/ProductDesktopVariant.jsx
index 940ba46f..51739bc9 100644
--- a/src/lib/product/components/Product/ProductDesktopVariant.jsx
+++ b/src/lib/product/components/Product/ProductDesktopVariant.jsx
@@ -16,7 +16,9 @@ import productSimilarApi from '../../api/productSimilarApi'
import whatsappUrl from '@/core/utils/whatsappUrl'
import useAuth from '@/core/hooks/useAuth'
import odooApi from '@/core/api/odooApi'
-import { Button, Spinner } from 'flowbite-react'
+import { useProductCartContext } from '@/contexts/ProductCartContext'
+import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
+import { Info } from 'lucide-react'
const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant }) => {
const router = useRouter()
@@ -28,6 +30,8 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
const [addCartAlert, setAddCartAlert] = useState(false)
const [isLoadingSLA, setIsLoadingSLA] = useState(true)
+ const { setRefreshCart } = useProductCartContext()
+
const getLowestPrice = useCallback(() => {
const lowest = product.price
/* const lowest = prices.reduce((lowest, price) => {
@@ -71,6 +75,8 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
programLineId: null,
selected: true,
source: null
+ }).then(() => {
+ setRefreshCart(true)
})
setAddCartAlert(true)
}
@@ -144,16 +150,16 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
<h1 className='text-title-md leading-10 font-medium'>{product?.name}</h1>
<div className='mt-10'>
<div className='flex p-3'>
- <div className='w-1/4 text-gray_r-12/70'>Nomor SKU</div>
- <div className='w-3/4'>SKU-{product.id}</div>
+ <div className='w-4/12 text-gray_r-12/70'>Nomor SKU</div>
+ <div className='w-8/12'>SKU-{product.id}</div>
</div>
<div className='flex p-3 bg-gray_r-4'>
- <div className='w-1/4 text-gray_r-12/70'>Part Number</div>
- <div className='w-3/4'>{product.code || '-'}</div>
+ <div className='w-4/12 text-gray_r-12/70'>Part Number</div>
+ <div className='w-8/12'>{product.code || '-'}</div>
</div>
<div className='flex p-3'>
- <div className='w-1/4 text-gray_r-12/70'>Manufacture</div>
- <div className='w-3/4'>
+ <div className='w-4/12 text-gray_r-12/70'>Manufacture</div>
+ <div className='w-8/12'>
{product.manufacture?.name ? (
<Link
href={createSlug(
@@ -169,68 +175,36 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
)}
</div>
</div>
+
<div className='flex p-3 items-center bg-gray_r-4'>
- <div className='w-1/4 text-gray_r-12/70'>Persiapan Barang</div>
- <div className='w-3/4'>
- {product.sla ? (
- product.sla?.slaDate != '-' ? (
- <button
- type='button'
- title={`Masa Persiapan Barang ${product.sla?.slaDate}`}
- className={`flex gap-x-1 items-center p-2 rounded-lg w-auto ${
- product.sla?.slaDate === 'indent' ? 'bg-indigo-900' : 'btn-light'
- }`}
- >
- <div
- className={`flex-1 text-caption-1 ${
- product.sla?.slaDate === 'indent' ? 'text-white' : ''
- }`}
- >
- {product.sla?.slaDate}
- </div>
- <div className='flex-end'>
- <svg
- aria-hidden='true'
- fill='none'
- stroke='currentColor'
- stroke-width='1.5'
- className={`w-7 h-7 ${
- product.sla?.slaDate === 'indent' ? 'text-white' : ''
- }`}
- >
- <path
- d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z'
- stroke-linecap='round'
- stroke-linejoin='round'
- ></path>
- </svg>
- </div>
- </button>
- ) : (
- '-'
- )
- ) : (
- <Button color='gray'>
- <Spinner aria-label='Alternate spinner button example' />
- <span className='pl-3'>Loading...</span>
- </Button>
+ <div className='w-4/12 text-gray_r-12/70'>Persiapan Barang</div>
+ <div className='w-8/12'>
+ {!product?.sla && <Skeleton width='20%' height='16px' />}
+ {product?.sla && (
+ <Tooltip
+ placement='top'
+ label={`Masa Persiapan Barang ${product?.sla?.slaDate}`}
+ >
+ <Box className='w-fit flex items-center gap-x-2'>
+ {product?.sla?.slaDate}
+ <Info size={16} />
+ </Box>
+ </Tooltip>
)}
</div>
</div>
+
<div className='flex p-3'>
- <div className='w-1/4 text-gray_r-12/70'>Stock</div>
- <div className='w-3/4'>
- {isLoadingSLA && (
- <div className=''>
- <Spinner aria-label='Center-aligned spinner example' />
- </div>
- )}
+ <div className='w-4/12 text-gray_r-12/70'>Stock</div>
+ <div className='w-8/12'>
+ {!product?.sla && <Skeleton width='10%' height='16px' />}
{product?.sla?.qty > 0 && <span>{product?.sla?.qty}</span>}
{product?.sla?.qty == 0 && (
<a
href={whatsappUrl('product', {
name: product.name,
- url: createSlug('/shop/product/variant/', product.name, product.id, true)
+ manufacture: product?.manufacture?.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
})}
className='text-danger-500 font-medium'
>
@@ -240,8 +214,8 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
</div>
</div>
<div className='flex p-3 bg-gray_r-4'>
- <div className='w-1/4 text-gray_r-12/70'>Berat Barang</div>
- <div className='w-3/4'>
+ <div className='w-4/12 text-gray_r-12/70'>Berat Barang</div>
+ <div className='w-8/12'>
{product?.weight > 0 && <span>{product?.weight} KG</span>}
{product?.weight == 0 && (
<a
@@ -296,44 +270,52 @@ const ProductDesktopVariant = ({ product, wishlist, toggleWishlist, isVariant })
</div> */}
</div>
<div className='w-[25%]'>
- {lowestPrice?.priceDiscount > 0 ? (
+ {product?.flashSale?.remainingTime > 0 ? (
<>
- <div className='flex gap-x-2 mb-3 items-center'>
- <div className='flex'>
- <span className='text-gray-400 text-md'>Harga Sebelum PPN : </span>
- </div>
- <div className='flex'>
- <span className=' text-body-1 '>
- {currencyFormat(lowestPrice?.priceDiscount)}
- </span>
- </div>
- </div>
- <span className='font-semibold'>Termasuk PPN :</span>
- <div className='flex gap-x-1 items-center mt-2 '>
+ <div className='flex gap-x-1 items-center mt-2'>
<div className='badge-solid-red text-caption-1'>
{lowestPrice?.discountPercentage}%
</div>
- <div className='text-gray_r-11 line-through text-caption-1'>
- {currencyFormat(lowestPrice?.price * 1.11)}
+ <div className='text-gray_r-9 line-through text-caption-1'>
+ {currencyFormat(lowestPrice?.price)}
+ </div>
+ <div className='text-danger-500 font-semibold text-xl'>
+ {currencyFormat(lowestPrice?.priceDiscount)}
</div>
- <h3 className='text-danger-500 font-semibold text-title-sm'>
- {currencyFormat(lowestPrice?.priceDiscount * 1.11)}
- </h3>
+ </div>
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(lowestPrice?.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
</div>
</>
) : (
- <span className='text-gray_r-12/90 font-normal text-h-sm'>
- Hubungi kami untuk dapatkan harga terbaik,&nbsp;
- <a
- href={whatsappUrl('product', {
- name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 underline'
- >
- klik disini
- </a>
- </span>
+ <h3 className='text-danger-500 font-semibold mt-1 text-title-md'>
+ {lowestPrice?.price > 0 ? (
+ <>
+ {currencyFormat(lowestPrice?.price)}
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(lowestPrice?.price * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <span className='text-gray_r-12/90 font-normal text-h-sm'>
+ Hubungi kami untuk dapatkan harga terbaik,&nbsp;
+ <a
+ href={whatsappUrl('product', {
+ name: product.name,
+ manufacture: product.manufacture?.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
+ })}
+ className='text-danger-500 underline'
+ rel='noopener noreferrer'
+ target='_blank'
+ >
+ klik disini
+ </a>
+ </span>
+ )}
+ </h3>
)}
<div className='flex gap-x-3 mt-4'>
<input
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx
index 6b0b27a5..a9d34683 100644
--- a/src/lib/product/components/Product/ProductMobile.jsx
+++ b/src/lib/product/components/Product/ProductMobile.jsx
@@ -17,7 +17,6 @@ import whatsappUrl from '@/core/utils/whatsappUrl'
import PromotionType from '@/lib/promotinProgram/components/PromotionType'
import { gtagAddToCart } from '@/core/utils/googleTag'
import odooApi from '@/core/api/odooApi'
-import { Button, Spinner } from 'flowbite-react'
import ImageNext from 'next/image'
import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
@@ -101,7 +100,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
price: variant.price,
stock: variant.stock,
weight: variant.weight,
- hasProgram: variant.hasProgram
+ hasProgram: variant.hasProgram,
+ isFlashsale: variant.isFlashsale
}
setActiveVariant(newActiveVariant)
@@ -152,6 +152,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
router.push(`/shop/checkout?source=buy`)
}
+ console.log('ini log', activeVariant)
+
const productSimilarQuery = [
product?.name,
`fq=-product_id_i:${product.id}`,
@@ -232,32 +234,48 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
<div className='text-gray_r-12/80 text-caption-2 mt-2 mb-1'>Harga mulai dari: </div>
)}
- {activeVariant?.price?.discountPercentage > 0 && (
- <div className='flex gap-x-1 items-center'>
- <div className='text-gray_r-11 line-through text-caption-1'>
- {currencyFormat(activeVariant?.price?.price)}
+ {activeVariant.isFlashsale ? (
+ <>
+ <div className='flex gap-x-1 items-center'>
+ <div className='badge-solid-red'>{activeVariant?.price?.discountPercentage}%</div>
+ <div className='text-gray_r-11 line-through text-caption-1'>
+ {currencyFormat(activeVariant?.price?.price)}
+ </div>
+ <div className='text-danger-500 font-semibold'>
+ {currencyFormat(activeVariant?.price?.priceDiscount)}
+ </div>
</div>
- <div className='badge-solid-red'>{activeVariant?.price?.discountPercentage}%</div>
- </div>
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <h3 className='text-danger-500 font-semibold mt-1'>
+ {activeVariant?.price?.priceDiscount > 0 ? (
+ <>
+ {currencyFormat(activeVariant?.price?.priceDiscount)}
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <span className='text-gray_r-11 leading-6 font-normal'>
+ Hubungi kami untuk dapatkan harga terbaik,&nbsp;
+ <a
+ href={whatsappUrl('product', {
+ name: product.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
+ })}
+ className='text-danger-500 underline'
+ >
+ klik disini
+ </a>
+ </span>
+ )}
+ </h3>
)}
- <h3 className='text-danger-500 font-semibold mt-1'>
- {activeVariant?.price?.priceDiscount > 0 ? (
- currencyFormat(activeVariant?.price?.priceDiscount)
- ) : (
- <span className='text-gray_r-11 leading-6 font-normal'>
- Hubungi kami untuk dapatkan harga terbaik,&nbsp;
- <a
- href={whatsappUrl('product', {
- name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 underline'
- >
- klik disini
- </a>
- </span>
- )}
- </h3>
</div>
<Divider />
diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx
index e0ba90c3..a7b1a543 100644
--- a/src/lib/product/components/Product/ProductMobileVariant.jsx
+++ b/src/lib/product/components/Product/ProductMobileVariant.jsx
@@ -16,7 +16,7 @@ import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
import whatsappUrl from '@/core/utils/whatsappUrl'
import { gtagAddToCart } from '@/core/utils/googleTag'
import odooApi from '@/core/api/odooApi'
-import { Button, Spinner } from 'flowbite-react'
+import { Skeleton } from '@chakra-ui/react'
const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
const router = useRouter()
@@ -39,7 +39,8 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
name: product.name,
price: getLowestPrice(),
stock: product.stockTotal,
- weight: product.weight
+ weight: product.weight,
+ isFlashSale: product.isFlashsale
})
useEffect(() => {
@@ -50,7 +51,8 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
name: product.name,
price: product.price,
stock: product.stock,
- weight: product.weight
+ weight: product.weight,
+ isFlashSale: product.isFlashsale
})
}
}, [selectedVariant, product])
@@ -80,6 +82,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
})
setAddCartAlert(true)
}
+ console.log('ini log', activeVariant)
const handleClickBuy = () => {
if (!validAction()) return
@@ -89,7 +92,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
quantity,
programLineId: null,
selected: true,
- source : 'buy'
+ source: 'buy'
})
router.push(`/shop/checkout?source=buy`)
}
@@ -139,47 +142,47 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
</div>
<h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1>
- {activeVariant?.price?.priceDiscount > 0 ? (
+ {activeVariant.isFlashsale ? (
<>
<div className='flex gap-x-1 items-center'>
- <div className='text-gray_r-11 text-caption-1'>Harga Sebelum PPN :</div>
- <div className='text-gray_r-12 line-through text-caption-1'>
- {' '}
+ <div className='badge-solid-red'>{activeVariant?.price?.discountPercentage}%</div>
+ <div className='text-gray_r-11 line-through text-caption-1'>
+ {currencyFormat(activeVariant?.price?.price)}
+ </div>
+ <div className='text-danger-500 font-semibold'>
{currencyFormat(activeVariant?.price?.priceDiscount)}
</div>
</div>
- <div className='mt-2'>
- <span className='font-semibold '>Termasuk PPN :</span>
- <div className='flex gap-x-2 items-center mt-2'>
- {activeVariant?.price?.discountPercentage > 0 && (
- <>
- <div className='badge-solid-red'>
- {activeVariant?.price?.discountPercentage}%
- </div>
- <div className='text-gray_r-11 line-through text-caption-1'>
- {currencyFormat(activeVariant?.price?.price * 1.11)}
- </div>
- </>
- )}
- <h3 className='text-danger-500 font-semibold'>
- {currencyFormat(activeVariant?.price?.priceDiscount * 1.11)}
- </h3>
- </div>
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
</div>
</>
) : (
- <span className='text-gray_r-11 leading-6 font-normal'>
- Hubungi kami untuk dapatkan harga terbaik,&nbsp;
- <a
- href={whatsappUrl('product', {
- name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 underline'
- >
- klik disini
- </a>
- </span>
+ <h3 className='text-danger-500 font-semibold mt-1'>
+ {activeVariant?.price?.priceDiscount > 0 ? (
+ <>
+ {currencyFormat(activeVariant?.price?.priceDiscount)}
+ <div className='text-gray_r-9 text-base font-normal mt-1'>
+ Termasuk PPN:{' '}
+ {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <span className='text-gray_r-11 leading-6 font-normal'>
+ Hubungi kami untuk dapatkan harga terbaik,&nbsp;
+ <a
+ href={whatsappUrl('product', {
+ name: product.name,
+ url: createSlug('/shop/product/', product.name, product.id, true)
+ })}
+ className='text-danger-500 underline'
+ >
+ klik disini
+ </a>
+ </span>
+ )}
+ </h3>
)}
</div>
@@ -230,10 +233,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
<SpecificationContent label='Ketersediaan'>
<span>
{isLoadingSLA ? (
- <Button color='gray'>
- <Spinner aria-label='Alternate spinner button example' />
- <span className='pl-3'>Loading...</span>
- </Button>
+ <Skeleton width='100px' height='full' />
) : product?.sla?.slaDate != '-' ? (
<button
type='button'
@@ -267,7 +267,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
</svg>
</div>
</button>
- ): (
+ ) : (
'-'
)}
</span>
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index 10ffdaec..16c63c00 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -82,30 +82,47 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
<Link
href={createSlug('/shop/product/', product?.name, product?.id)}
- className={`mb-2 !text-gray_r-12 leading-6 block ${
+ className={`mb-3 !text-gray_r-12 leading-6 block ${
simpleTitle ? 'line-clamp-2 h-12' : 'line-clamp-3 h-[64px]'
}`}
title={product?.name}
>
{product?.name}
</Link>
- {product?.lowestPrice.discountPercentage > 0 && (
- <div className='flex gap-x-1 mb-1 items-center'>
- <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
- {currencyFormat(product.lowestPrice.price)}
+ {product?.flashSale?.id > 0 ? (
+ <>
+ {product?.lowestPrice.discountPercentage > 0 && (
+ <div className='flex gap-x-1 mb-1 items-center'>
+ <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
+ {currencyFormat(product.lowestPrice.price)}
+ </div>
+ <div className='badge-solid-red'>{product?.lowestPrice.discountPercentage}%</div>
+ </div>
+ )}
+
+ <div className='text-danger-500 font-semibold mb-2'>
+ {product?.lowestPrice.priceDiscount > 0 ? (
+ currencyFormat(product?.lowestPrice.priceDiscount)
+ ) : (
+ <a href={callForPriceWhatsapp}>Call for price</a>
+ )}
</div>
- <div className='badge-solid-red'>{product?.lowestPrice.discountPercentage}%</div>
+ </>
+ ) : (
+ <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'>
+ {product?.lowestPrice.price > 0 ? (
+ <>
+ {currencyFormat(product?.lowestPrice.price)}
+ <div className='text-gray_r-9 text-[11px] font-normal sm:text-caption-2 mt-2'>
+ + PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <a href={callForPriceWhatsapp}>Call for price</a>
+ )}
</div>
)}
- <div className='text-danger-500 font-semibold mb-2'>
- {product?.lowestPrice.priceDiscount > 0 ? (
- currencyFormat(product?.lowestPrice.priceDiscount)
- ) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
- )}
- </div>
-
{product?.stockTotal > 0 && (
<div className='flex gap-x-1'>
<div className='badge-solid-red'>Ready Stock</div>
@@ -169,30 +186,46 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
<Link
href={createSlug('/shop/product/', product?.name, product?.id)}
- className={`mb-2 !text-gray_r-12 leading-6 ${
+ className={`mb-3 !text-gray_r-12 leading-6 ${
simpleTitle ? 'line-clamp-2' : 'line-clamp-3'
}`}
>
{product?.name}
</Link>
+ {product?.flashSale?.id > 0 ? (
+ <>
+ {product?.lowestPrice.discountPercentage > 0 && (
+ <div className='flex gap-x-1 mb-1 items-center'>
+ <div className='badge-solid-red'>{product?.lowestPrice?.discountPercentage}%</div>
+ <div className='text-gray_r-11 line-through text-caption-2'>
+ {currencyFormat(product?.lowestPrice?.price)}
+ </div>
+ </div>
+ )}
- {product?.lowestPrice?.discountPercentage > 0 && (
- <div className='flex gap-x-1 mb-1 items-center'>
- <div className='badge-solid-red'>{product?.lowestPrice?.discountPercentage}%</div>
- <div className='text-gray_r-11 line-through text-caption-2'>
- {currencyFormat(product?.lowestPrice?.price)}
+ <div className='text-danger-500 font-semibold mb-2'>
+ {product?.lowestPrice?.priceDiscount > 0 ? (
+ currencyFormat(product?.lowestPrice?.priceDiscount)
+ ) : (
+ <a href={callForPriceWhatsapp}>Call for price</a>
+ )}
</div>
+ </>
+ ) : (
+ <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'>
+ {product?.lowestPrice.price > 0 ? (
+ <>
+ {currencyFormat(product?.lowestPrice.price)}
+ <div className='text-gray_r-9 text-[11px] sm:text-caption-2 font-normal mt-2'>
+ + PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN)}
+ </div>
+ </>
+ ) : (
+ <a href={callForPriceWhatsapp}>Call for price</a>
+ )}
</div>
)}
- <div className='text-danger-500 font-semibold mb-2'>
- {product?.lowestPrice?.priceDiscount > 0 ? (
- currencyFormat(product?.lowestPrice?.priceDiscount)
- ) : (
- <a href={callForPriceWhatsapp}>Call for price</a>
- )}
- </div>
-
{product?.stockTotal > 0 && (
<div className='flex gap-x-1'>
<div className='badge-solid-red'>Ready Stock</div>
diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx
index ce6c12ed..b64349c7 100644
--- a/src/lib/product/components/ProductFilterDesktop.jsx
+++ b/src/lib/product/components/ProductFilterDesktop.jsx
@@ -2,7 +2,21 @@ import { useRouter } from 'next/router'
import { useState } from 'react'
import _ from 'lodash'
import { toQuery } from 'lodash-contrib'
-import { Accordion, Checkbox, Label, TextInput } from 'flowbite-react'
+import {
+ Accordion,
+ AccordionButton,
+ AccordionIcon,
+ AccordionItem,
+ AccordionPanel,
+ Box,
+ Button,
+ Checkbox,
+ Input,
+ InputGroup,
+ InputLeftAddon,
+ Stack,
+ VStack
+} from '@chakra-ui/react'
const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => {
const router = useRouter()
@@ -13,7 +27,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
const [priceFrom, setPriceFrom] = useState(query?.priceFrom)
const [priceTo, setPriceTo] = useState(query?.priceTo)
- const handleCategorysChange = (event) => {
+ const handleCategoriesChange = (event) => {
const value = event.target.value
const isChecked = event.target.checked
if (isChecked) {
@@ -48,80 +62,95 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
return (
<>
- <Accordion flush={true} alwaysOpen={true}>
- <Accordion.Panel>
- <Accordion.Title>Kategori</Accordion.Title>
- <Accordion.Content className='overflow-auto max-h-[200px]'>
- <div className='flex flex-col gap-4 scroll-snap' id='checkbox'>
+ <Accordion defaultIndex={[0]} allowMultiple>
+ <AccordionItem>
+ <AccordionButton padding={[2, 4]}>
+ <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
+ Brand
+ </Box>
+ <AccordionIcon />
+ </AccordionButton>
+
+ <AccordionPanel>
+ <Stack gap={3} direction='column' maxH={'240px'} overflow='auto'>
+ {brands.map((brand, index) => (
+ <div className='flex items-center gap-2' key={index}>
+ <Checkbox
+ isChecked={brandValues.includes(brand)}
+ onChange={handleBrandsChange}
+ value={brand}
+ size='md'
+ >
+ {brand}
+ </Checkbox>
+ </div>
+ ))}
+ </Stack>
+ </AccordionPanel>
+ </AccordionItem>
+
+ <AccordionItem>
+ <AccordionButton padding={[2, 4]}>
+ <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
+ Kategori
+ </Box>
+ <AccordionIcon />
+ </AccordionButton>
+
+ <AccordionPanel>
+ <Stack gap={3} direction='column' maxH={'240px'} overflow='auto'>
{categories.map((category, index) => (
<div className='flex items-center gap-2' key={index}>
<Checkbox
- id={`categoryOption${index}`}
- checked={categoryValues.includes(category)}
- onChange={handleCategorysChange}
+ isChecked={categoryValues.includes(category)}
+ onChange={handleCategoriesChange}
value={category}
- />
- <Label htmlFor={`categoryOption${index}`} className='dark:text-gray_r-12/80'>
+ size='md'
+ >
{category}
- </Label>
+ </Checkbox>
</div>
))}
- </div>
- </Accordion.Content>
- </Accordion.Panel>
- <Accordion.Panel>
- {!defaultBrand && (
- <>
- <Accordion.Title>Brand</Accordion.Title>
- <Accordion.Content className='overflow-auto max-h-[200px]'>
- <div className='flex flex-col gap-4 scroll-snap' id='checkbox'>
- {brands.map((brand, index) => (
- <div className='flex items-center gap-2' key={index}>
- <Checkbox
- id={`brandOption${index}`}
- checked={brandValues.includes(brand)}
- onChange={handleBrandsChange}
- value={brand}
- />
- <Label htmlFor={`brandOption${index}`} className='dark:text-gray_r-12/80'>
- {brand}
- </Label>
- </div>
- ))}
- </div>
- </Accordion.Content>
- </>
- )}
- </Accordion.Panel>
- <Accordion.Panel>
- <Accordion.Title>Harga</Accordion.Title>
- <Accordion.Content>
- <div className='mb-3'>
- <TextInput
- placeholder='Harga Minimum'
- addon='Rp'
- type='number'
- value={priceFrom}
- onChange={(e) => setPriceFrom(e.target.value)}
- />
- </div>
- <div className='mb-3'>
- <TextInput
- placeholder='Harga Maximum'
- addon='Rp'
- type='number'
- value={priceTo}
- onChange={(e) => setPriceTo(e.target.value)}
- />
- </div>
- </Accordion.Content>
- </Accordion.Panel>
+ </Stack>
+ </AccordionPanel>
+ </AccordionItem>
+
+ <AccordionItem>
+ <AccordionButton padding={[2, 4]}>
+ <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
+ Harga
+ </Box>
+ <AccordionIcon />
+ </AccordionButton>
+
+ <AccordionPanel paddingY={4}>
+ <VStack gap={4}>
+ <InputGroup>
+ <InputLeftAddon>Rp</InputLeftAddon>
+ <Input
+ type='number'
+ placeholder='Harga minimum'
+ value={priceFrom}
+ onChange={(e) => setPriceFrom(e.target.value)}
+ />
+ </InputGroup>
+ <InputGroup>
+ <InputLeftAddon>Rp</InputLeftAddon>
+ <Input
+ type='number'
+ placeholder='Harga maximum'
+ value={priceTo}
+ onChange={(e) => setPriceTo(e.target.value)}
+ />
+ </InputGroup>
+ </VStack>
+ </AccordionPanel>
+ </AccordionItem>
</Accordion>
- <div className='p-5'>
- <button type='button' className='btn-solid-red w-full mt-6' onClick={handleSubmit}>
- Terapkan
- </button>
- </div>
+
+ <Button className='w-full mt-6' colorScheme='red' onClick={handleSubmit}>
+ Terapkan
+ </Button>
</>
)
}
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index ae9618d2..df9aa91b 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -39,9 +39,11 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
const oddIndexSuggestions = response.data.spellcheck.suggestions.filter(
(_, index) => index % 2 === 1
)
+
const oddIndexCollations = response.data.spellcheck.collations.filter(
(_, index) => index % 2 === 1
)
+
const dataSpellings = oddIndexSuggestions.reduce((acc, curr) => {
oddIndexCollations.forEach((collation) => {
acc.push(collation.collationQuery)
@@ -52,7 +54,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
return acc
}, [])
- setQ(dataSpellings[0])
+ if (dataSpellings.length > 0) {
+ setQ(dataSpellings[0])
+ }
setSpellings(dataSpellings)
})
@@ -183,7 +187,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
defaultBrand={defaultBrand}
/>
</div>
- <div className='w-9/12 p-3'>
+ <div className='w-9/12 pl-6'>
<h1 className='text-2xl mb-2 font-semibold'>Hasil Pencarian</h1>
<div className='flex justify-between items-center mb-2'>
<div className='mb-2 leading-6 text-gray_r-11'>
diff --git a/src/lib/product/components/ProductSlider.jsx b/src/lib/product/components/ProductSlider.jsx
index dedbd6ab..54f209cc 100644
--- a/src/lib/product/components/ProductSlider.jsx
+++ b/src/lib/product/components/ProductSlider.jsx
@@ -10,7 +10,7 @@ import MobileView from '@/core/components/views/MobileView'
import DesktopView from '@/core/components/views/DesktopView'
const bannerClassName =
- 'absolute rounded-r top-0 left-0 h-full w-auto md:w-[20%] idt-transition border border-gray_r-6'
+ 'absolute rounded-r top-0 left-0 h-full w-auto md:w-[20%] border border-gray_r-6'
const ProductSlider = ({ products, simpleTitle = false, bannerMode = false }) => {
const bannerRef = useRef('')
diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx
index 0062f7fc..afebc293 100644
--- a/src/pages/_app.jsx
+++ b/src/pages/_app.jsx
@@ -1,36 +1,27 @@
import '../styles/globals.css'
import 'react-loading-skeleton/dist/skeleton.css'
+
import NextProgress from 'next-progress'
import { useRouter, Router } from 'next/router'
import { AnimatePresence, motion } from 'framer-motion'
import { Toaster } from 'react-hot-toast'
import { QueryClient, QueryClientProvider } from 'react-query'
import useDevice from '@/core/hooks/useDevice'
-import { createContext, useContext, useEffect, useState } from 'react'
+import { useEffect, useState } from 'react'
import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
import { SessionProvider } from 'next-auth/react'
-import { getAuth } from '@/core/utils/auth'
import { ProductProvider } from '@/contexts/ProductContext'
import { ProductCartProvider } from '@/contexts/ProductCartContext'
+import { ChakraProvider } from '@chakra-ui/react'
+import theme from '../../chakra.theme'
const queryClient = new QueryClient()
-export const AuthContext = createContext({
- authenticated: false,
- setAuthenticated: (auth) => {}
-})
-
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
const router = useRouter()
const { isMobile } = useDevice()
const [animateLoader, setAnimateLoader] = useState(false)
- const [authenticated, setAuthenticated] = useState(null)
- const auth = getAuth()
-
- // useEffect(() => {
- // setAuthenticated(auth)
- // }, [auth])
useEffect(() => {
const handleRouteChangeStart = () => setAnimateLoader(true)
@@ -63,14 +54,13 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }) {
}, [isMobile])
return (
- // <AuthContext.Provider value={{authenticated, setAuthenticated}}>
<SessionProvider session={session}>
<AnimatePresence>
{animateLoader && (
<motion.div
- initial={{ opacity: 0 }}
+ initial={{ opacity: 0.4 }}
animate={{ opacity: 1 }}
- exit={{ opacity: 0 }}
+ exit={{ opacity: 0.4 }}
transition={{
duration: 0.1
}}
@@ -90,20 +80,15 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }) {
/>
<NextProgress color='#F01C21' options={{ showSpinner: false }} />
<QueryClientProvider client={queryClient}>
- <AnimatePresence
- mode='popLayout'
- initial={false}
- onExitComplete={() => window.scrollTo(0, 0)}
- >
- <ProductProvider>
- <ProductCartProvider>
- {!animateLoader && <Component {...pageProps} key={router.asPath} />}
- </ProductCartProvider>
- </ProductProvider>
- </AnimatePresence>
+ <ProductProvider>
+ <ProductCartProvider>
+ <ChakraProvider theme={theme}>
+ <Component {...pageProps} key={router.asPath} />
+ </ChakraProvider>
+ </ProductCartProvider>
+ </ProductProvider>
</QueryClientProvider>
</SessionProvider>
- // </AuthContext.Provider>
)
}
diff --git a/src/pages/api/shop/brands.js b/src/pages/api/shop/brands.js
new file mode 100644
index 00000000..e93fe2c9
--- /dev/null
+++ b/src/pages/api/shop/brands.js
@@ -0,0 +1,44 @@
+import axios from 'axios'
+
+export default async function handler(req, res) {
+ try {
+ let params = '*:*'
+ let sort = 'sort=if(exists(sequence_i),0,1) asc,sequence_i asc, if(exists(image_s),0,1) asc '
+ let rows = 2000
+
+ if (req.query.params) {
+ rows = 100
+ switch (req?.query?.params) {
+ case 'level_s':
+ params = 'level_s:prioritas'
+ break
+ default:
+ params = `name_s:${req.query.params}`
+ }
+ }
+ let brands = await axios(
+ process.env.SOLR_HOST +
+ `/solr/brands/select?q=${params}&q.op=OR&indent=true&rows=${rows}&${sort}`
+ )
+
+ let dataBrands = responseMap(brands.data.response.docs)
+
+ res.status(200).json(dataBrands)
+ } catch (error) {
+ console.error('Error fetching data from Solr:', error)
+ res.status(500).json({ error: 'Internal Server Error' })
+ }
+}
+
+const responseMap = (brands) => {
+ return brands.map((brand) => {
+ let brandMapping = {
+ id: brand.id,
+ name: brand.display_name_s,
+ logo: brand.image_s || '',
+ sequance: brand.sequence_i || ''
+ }
+
+ return brandMapping
+ })
+}
diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js
index d465d94b..7b44ef37 100644
--- a/src/pages/api/shop/search.js
+++ b/src/pages/api/shop/search.js
@@ -49,7 +49,8 @@ export default async function handler(req, res) {
'qf=name_s',
`start=${offset}`,
`rows=${limit}`,
- `sort=${paramOrderBy}`
+ `sort=${paramOrderBy}`,
+ `fq=-publish_b:false`
]
if (priceFrom > 0 || priceTo > 0) {
@@ -103,17 +104,19 @@ const escapeSolrQuery = (query) => {
const productResponseMap = (products, pricelist) => {
return products.map((product) => {
- let price = product.price_f || 0
+ let price = product.price_tier1_v2_f || 0
let priceDiscount = product.price_discount_f || 0
let discountPercentage = product.discount_f || 0
if (pricelist) {
- const pricelistDiscount = product?.[`price_${pricelist}_f`] || false
- const pricelistDiscountPerc = product?.[`discount_${pricelist}_f`] || false
+ // const pricelistDiscount = product?.[`price_${pricelist}_f`] || false
+ // const pricelistDiscountPerc = product?.[`discount_${pricelist}_f`] || false
- if (pricelistDiscount && pricelistDiscount > 0) priceDiscount = pricelistDiscount
- if (pricelistDiscountPerc && pricelistDiscountPerc > 0)
- discountPercentage = pricelistDiscountPerc
+ // if (pricelistDiscount && pricelistDiscount > 0) priceDiscount = pricelistDiscount
+ // if (pricelistDiscountPerc && pricelistDiscountPerc > 0)
+ // discountPercentage = pricelistDiscountPerc
+
+ price = product?.[`price_${pricelist}_v2_f`] || 0
}
if (product?.flashsale_id_i > 0) {
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 47a0a493..64f3ac10 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -31,6 +31,7 @@ const FlashSale = dynamic(() => import('@/lib/flashSale/components/FlashSale'),
const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection'))
const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId'))
const CustomerReviews = dynamic(() => import('@/lib/review/components/CustomerReviews'))
+const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList'))
export default function Home() {
const bannerRef = useRef(null)
@@ -72,6 +73,7 @@ export default function Home() {
</div>
<div className='my-16 flex flex-col gap-y-16'>
+ <ServiceList />
<PreferredBrand />
<FlashSale />
<PromotinProgram />
@@ -88,6 +90,9 @@ export default function Home() {
</DelayRender>
<div className='flex flex-col gap-y-12 my-6'>
<DelayRender renderAfter={400}>
+ <ServiceList />
+ </DelayRender>
+ <DelayRender renderAfter={400}>
<PreferredBrand />
</DelayRender>
<DelayRender renderAfter={600}>