diff options
| -rw-r--r-- | src-migrate/modules/cart/components/Item.tsx | 4 | ||||
| -rw-r--r-- | src-migrate/modules/cart/components/ItemSelect.tsx | 33 | ||||
| -rw-r--r-- | src-migrate/modules/promo/components/Hero.tsx | 15 | ||||
| -rw-r--r-- | src-migrate/pages/shop/cart/index.tsx | 108 | ||||
| -rw-r--r-- | src/core/components/elements/Navbar/NavbarDesktop.jsx | 4 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryDynamic.jsx | 115 |
6 files changed, 140 insertions, 139 deletions
diff --git a/src-migrate/modules/cart/components/Item.tsx b/src-migrate/modules/cart/components/Item.tsx index 74180fc9..47893498 100644 --- a/src-migrate/modules/cart/components/Item.tsx +++ b/src-migrate/modules/cart/components/Item.tsx @@ -20,7 +20,7 @@ type Props = { pilihSemuaCart?: boolean } -const CartItem = ({ item, editable = true, pilihSemuaCart }: Props) => { +const CartItem = ({ item, editable = true,}: Props) => { return ( <div className={style.wrapper}> @@ -46,7 +46,7 @@ const CartItem = ({ item, editable = true, pilihSemuaCart }: Props) => { <div className={style.mainProdWrapper}> {editable && ( - <CartItemSelect item={item} itemSelected={pilihSemuaCart} /> + <CartItemSelect item={item} /> )} <div className='w-4' /> diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx index 6b6b8f2b..b904a1de 100644 --- a/src-migrate/modules/cart/components/ItemSelect.tsx +++ b/src-migrate/modules/cart/components/ItemSelect.tsx @@ -1,5 +1,5 @@ import { Checkbox, Spinner } from '@chakra-ui/react' -import React, { useState, useEffect } from 'react' +import React, { useState } from 'react' import { getAuth } from '~/libs/auth' import { CartItem } from '~/types/cart' @@ -9,17 +9,15 @@ import { useCartStore } from '../stores/useCartStore' type Props = { item: CartItem - itemSelected?: boolean } -const CartItemSelect = ({ item, itemSelected }: Props) => { +const CartItemSelect = ({ item }: Props) => { const auth = getAuth() const { loadCart } = useCartStore() const [isLoad, setIsLoad] = useState<boolean>(false) - const [isChecked, setIsChecked] = useState<boolean>(itemSelected ?? true) - const handleChange = async (isChecked: boolean) => { + const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { if (typeof auth !== 'object') return setIsLoad(true) @@ -28,40 +26,29 @@ const CartItemSelect = ({ item, itemSelected }: Props) => { type: item.cart_type, id: item.id, qty: item.quantity, - selected: isChecked, + selected: e.target.checked }) await loadCart(auth.id) setIsLoad(false) } - useEffect(() => { - if (typeof itemSelected === 'boolean') { - setIsChecked(itemSelected) - handleChange(itemSelected) - } - }, [itemSelected]) - - const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => { - const { checked } = e.target - setIsChecked(checked) - handleChange(checked) - } - return ( <div className='w-6 my-auto'> - {isLoad && <Spinner className='my-auto' size='sm' />} + {isLoad && ( + <Spinner className='my-auto' size='sm' /> + )} {!isLoad && ( <Checkbox borderColor='gray.600' colorScheme='red' size='lg' - isChecked={isChecked} - onChange={handleCheckboxChange} + isChecked={item.selected} + onChange={handleChange} /> )} </div> ) } -export default CartItemSelect +export default CartItemSelect
\ No newline at end of file diff --git a/src-migrate/modules/promo/components/Hero.tsx b/src-migrate/modules/promo/components/Hero.tsx index 801136e9..110052ba 100644 --- a/src-migrate/modules/promo/components/Hero.tsx +++ b/src-migrate/modules/promo/components/Hero.tsx @@ -13,8 +13,8 @@ import DesktopView from '@/core/components/views/DesktopView'; import {bannerApi} from '../../../../src/api/bannerApi' interface IPromotionProgram { - headline_banner: string; - description_banner: string; + headlineBanner: string; + descriptionBanner: string; image: string ; name: string; } @@ -43,7 +43,7 @@ const swiperBannerMob = { }; const Hero = () => { - const heroBanner = useQuery('heroBannerSecondary', bannerApi({ type: 'banner-semua-promo' })) + const heroBanner = useQuery('allPromo', bannerApi({ type: 'banner-semua-promo' })); const banners: IPromotionProgram[] = useMemo( () => heroBanner?.data || [], @@ -55,7 +55,8 @@ const Hero = () => { pagination: { dynamicBullets: false, clickable: true }, }; - + console.log("banner",banners) + // console.log("headlineBanner",banners[0].headlineBanner) return ( <> <DesktopView> @@ -64,9 +65,9 @@ const Hero = () => { {banners.map((banner, index) => ( <SwiperSlide key={index} className='flex flex-row'> <div className={style['desc-section']}> - <div className={style['title']}>{banner.headline_banner? banner.headline_banner : "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.description_banner? banner.description_banner : "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 @@ -74,7 +75,7 @@ const Hero = () => { alt={banner.name} width={666} height={450} - quality={100} + quality={90} className='w-full h-full object-fit object-center rounded-2xl' /> </div> </SwiperSlide> diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx index 2ecf1c03..0eb9c554 100644 --- a/src-migrate/pages/shop/cart/index.tsx +++ b/src-migrate/pages/shop/cart/index.tsx @@ -2,29 +2,30 @@ import style from './cart.module.css'; import React, { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; -import { Button, Checkbox, Toast, Tooltip } from '@chakra-ui/react'; +import { Button, Checkbox, Tooltip } from '@chakra-ui/react'; import { toast } from 'react-hot-toast'; import { useRouter } from 'next/router'; import { getAuth } from '~/libs/auth'; import { useCartStore } from '~/modules/cart/stores/useCartStore'; -import CartItem from '~/modules/cart/components/Item'; +import CartItemModule from '~/modules/cart/components/Item'; import CartSummary from '~/modules/cart/components/Summary'; import clsxm from '~/libs/clsxm'; import useDevice from '@/core/hooks/useDevice'; import CartSummaryMobile from '~/modules/cart/components/CartSummaryMobile'; import Image from '~/components/ui/image'; +import { CartItem } from '~/types/cart' +import { upsertUserCart } from '~/services/cart' const CartPage = () => { const router = useRouter(); const auth = getAuth(); - const [isStepApproval, setIsStepApproval] = React.useState(false); - const [isSelectedAll, setIsSelectedAll] = useState<boolean>(false); - const [isButtonChek, setIsButtonChek] = useState<boolean>(false); - const [buttonSelectNow, setButtonSelectNow] = useState<boolean>(true); + const [isStepApproval, setIsStepApproval] = useState(false); + const [isSelectedAll, setIsSelectedAll] = useState(false); + const [isButtonChek, setIsButtonChek] = useState(false); + const [buttonSelectNow, setButtonSelectNow] = useState(true); const { loadCart, cart, summary } = useCartStore(); - const useDivvice = useDevice(); useEffect(() => { @@ -32,78 +33,85 @@ const CartPage = () => { loadCart(auth.id); setIsStepApproval(auth?.feature?.soApproval); } - }, [auth, loadCart, cart, isButtonChek, ]); - - + }, [auth, loadCart, cart, isButtonChek]); + const hasSelectedPromo = useMemo(() => { if (!cart) return false; - for (const item of cart.products) { - if (item.cart_type === 'promotion' && item.selected) return true; - } - return false; + return cart.products.some(item => item.cart_type === 'promotion' && item.selected); }, [cart]); const hasSelected = useMemo(() => { if (!cart) return false; - for (const item of cart.products) { - if (item.selected) return true; - } - return false; + return cart.products.some(item => item.selected); }, [cart]); const hasSelectNoPrice = useMemo(() => { if (!cart) return false; - for (const item of cart.products) { - if (item.selected && item.price.price_discount == 0) return true; - } - return false; + return cart.products.some(item => item.selected && item.price.price_discount === 0); }, [cart]); - - const handleCheckout = (()=>{ - router.push('/shop/checkout'); - }) - const handleQuotation = (()=>{ - if(hasSelectedPromo || !hasSelected){ + const hasSelectedAll = useMemo(() => { + if (!cart || !Array.isArray(cart.products)) return false; + return cart.products.every(item => item.selected); + }, [cart]); + + const handleCheckout = () => { + router.push('/shop/checkout'); + } + + const handleQuotation = () => { + if (hasSelectedPromo || !hasSelected) { toast.error('Maaf, Barang promo tidak dapat dibuat quotation'); - }else{ + } else { router.push('/shop/quotation'); } - }) + } + + const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { + if (typeof auth !== 'object' || !cart) return; + + const newSelected = e.target.checked; + setIsSelectedAll(newSelected); - const handleChange = (()=>{ - setButtonSelectNow(!buttonSelectNow) - setIsSelectedAll(!isSelectedAll) - setIsButtonChek(!isButtonChek) - }) + for (const item of cart.products) { + await upsertUserCart({ + userId: auth.id, + type: item.cart_type, + id: item.id, + qty: item.quantity, + selected: newSelected + }); + } + await loadCart(auth.id); + } return ( <> <div className={style['title']}>Keranjang Belanja</div> <div className='h-2' /> - <div className='flex items-center object-center mt-2'> - <Checkbox - borderColor='gray.600' - colorScheme='red' - size='lg' - isChecked={isButtonChek} - onChange={handleChange} - /> <p className='p-2 text-caption-2'> - {buttonSelectNow? "Select all" : "Unchek all" } - </p> - </div> + <div className='flex items-center object-center mt-2'> + <Checkbox + borderColor='gray.600' + colorScheme='red' + size='lg' + isChecked={hasSelectedAll} + onChange={handleChange} + /> + <p className='p-2 text-caption-2'> + {hasSelectedAll ? "Unchek all" : "Select all"} + </p> + </div> <div className={style['content']}> <div className={style['item-wrapper']}> <div className={style['item-skeleton']}> - {!cart && <CartItem.Skeleton count={5} height='120px' />} + {!cart && <CartItemModule.Skeleton count={5} height='120px' />} </div> <div className={style['items']}> {cart?.products.map((item) => ( - <CartItem key={item.id} item={item} pilihSemuaCart={isSelectedAll} /> + <CartItemModule key={item.id} item={item} /> ))} - {cart?.products?.length === 0 && ( <div className='flex flex-col items-center'> @@ -145,7 +153,7 @@ const CartPage = () => { <CartSummary {...summary} isLoaded={!!cart} /> )} - <div className={isStepApproval ? style['summary-buttons-step-approval'] : style['summary-buttons'] }> + <div className={isStepApproval ? style['summary-buttons-step-approval'] : style['summary-buttons']}> <Tooltip label={ hasSelectedPromo && diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index f157297e..c6e80e87 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -213,7 +213,7 @@ const NavbarDesktop = () => { rel="noreferrer" > <p className="absolute inset-0 flex justify-center items-center group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200 z-10">Semua Promo</p> - <div className='w-full h-full flex justify-end items-start'> + {/* <div className='w-full h-full flex justify-end items-start'> <Image src='/images/ICON PROMO DISKON.svg' alt='promo' @@ -222,7 +222,7 @@ const NavbarDesktop = () => { quality={100} className={`inline-block z-20`} /> - </div> + </div> */} </Link> diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index 6ab03ec3..f2d1a16f 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -4,6 +4,7 @@ import NextImage from 'next/image'; import Link from "next/link"; import { createSlug } from '@/core/utils/slug'; import odooApi from '@/core/api/odooApi'; +import { Skeleton} from '@chakra-ui/react' const CategoryDynamic = () => { const { categoryManagement } = useCategoryManagement(); @@ -17,14 +18,10 @@ const CategoryDynamic = () => { const updatedSubCategoryData = {}; for (const category of categoryManagement.data) { - // Calculate level 1 products const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); - // console.log("countLevel1.child",countLevel1) updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; - - // Calculate level 2 products for each sub-category for (const subCategory of countLevel1.children) { updatedSubCategoryData[subCategory.id] = subCategory.numFound; } @@ -41,62 +38,70 @@ const CategoryDynamic = () => { return ( <div> - {categoryManagement && categoryManagement.data?.map((category) => { - const countLevel1 = categoryData[category.categoryIdI] || 0; - - return ( - <div key={category.id}> - <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'> - <div className='font-semibold sm:text-h-lg mr-2'>{category.name}</div> - <p className='text-gray_r-10 text-sm'>{countLevel1} Produk tersedia</p> - <Link href={createSlug('/shop/category/', category?.name, category?.categoryIdI)} className="!text-red-500 font-semibold">Lihat Semua</Link> - </div> - <div className='grid grid-cols-3 gap-2'> - {category.categories.map((subCategory) => { - const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; + {categoryManagement && categoryManagement.data?.map((category) => { + const countLevel1 = categoryData[category.categoryIdI] || 0; + + return ( + <Skeleton key={category.id} isLoaded={categoryManagement}> + <div key={category.id}> + <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'> + <div className='font-semibold sm:text-h-lg mr-2'>{category.name}</div> + <Skeleton isLoaded={countLevel1 !=0}> + <p className={`text-gray_r-10 text-sm`}>{countLevel1} Produk tersedia</p> + </Skeleton> + <Link href={createSlug('/shop/category/', category?.name, category?.categoryIdI)} className="!text-red-500 font-semibold">Lihat Semua</Link> + </div> + <div className='grid grid-cols-3 gap-2'> + {category.categories.map((subCategory) => { + const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; - return ( - <div key={subCategory.id} className='border rounded justify-start items-start'> - <div className='p-3'> - <div className='flex flex-row border rounded mb-2 justify-start items-center'> - <NextImage - src={subCategory.image ? subCategory.image : "/images/noimage.jpeg"} - alt={subCategory.name} - width={90} - height={30} - className='object-fit' - /> - <div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'> - <div className='font-semibold text-lg mr-2'>{subCategory.name}</div> - <p className='text-gray_r-10 text-sm'>{countLevel2} Produk tersedia</p> - <Link href={createSlug('/shop/category/', subCategory?.name, subCategory?.idLevel2)} className="!text-red-500 font-semibold">Lihat Semua</Link> - </div> - </div> - <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'> - {subCategory.childFrontendIdI.map((childCategory) => ( - <div key={childCategory.id}> - <Link href={createSlug('/shop/category/', childCategory?.name, childCategory?.idLevel3)} className="flex flex-row gap-2 border rounded group hover:border-red-500"> - <NextImage - src={childCategory.image ? childCategory.image : "/images/noimage.jpeg"} - alt={childCategory.name} - width={40} - height={40} - /> - <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'> - <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>{childCategory.name}</div> - </div> - </Link> + return ( + <div key={subCategory.id} className='border rounded justify-start items-start'> + <div className='p-3'> + <div className='flex flex-row border rounded mb-2 justify-start items-center'> + <NextImage + src={subCategory.image ? subCategory.image : "/images/noimage.jpeg"} + alt={subCategory.name} + width={90} + height={30} + className='object-fit' + /> + <div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'> + <div className='font-semibold text-lg mr-2'>{subCategory.name}</div> + <Skeleton isLoaded={countLevel2 != 0}> + <p className={`text-gray_r-10 text-sm`}> + {countLevel2} Produk tersedia + </p> + </Skeleton> + <Link href={createSlug('/shop/category/', subCategory?.name, subCategory?.idLevel2)} className="!text-red-500 font-semibold">Lihat Semua</Link> </div> - ))} + </div> + <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'> + {subCategory.childFrontendIdI.map((childCategory) => ( + <div key={childCategory.id}> + <Link href={createSlug('/shop/category/', childCategory?.name, childCategory?.idLevel3)} className="flex flex-row gap-2 border rounded group hover:border-red-500"> + <NextImage + src={childCategory.image ? childCategory.image : "/images/noimage.jpeg"} + alt={childCategory.name} + width={40} + height={40} + /> + <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'> + <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>{childCategory.name}</div> + </div> + </Link> + </div> + ))} + </div> </div> </div> - </div> - ); - })} + ); + })} + </div> </div> - </div> - ); - })} + </Skeleton> + ); + })} </div> ); }; |
