diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-09-25 14:07:26 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-09-25 14:07:26 +0700 |
| commit | e7313b4d7006bed37a408d26f15028892839b73a (patch) | |
| tree | d0d6c9455ca6aac305efc094639dd6886b34fb14 /src/lib/home | |
| parent | d1c0e083ac8f64dfaa8505fc11e30728dbd5a58d (diff) | |
| parent | e8f640d3fd4984fe5854c2faf7ead9b3b5aebbf2 (diff) | |
Merge branch 'new-release' into bug-product
Diffstat (limited to 'src/lib/home')
| -rw-r--r-- | src/lib/home/api/CategoryPilihanApi.js | 8 | ||||
| -rw-r--r-- | src/lib/home/api/categoryManagementApi.js | 44 | ||||
| -rw-r--r-- | src/lib/home/components/BannerSection.jsx | 20 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryDynamic.jsx | 182 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryDynamicMobile.jsx | 150 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryHomeId.jsx | 18 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryPilihan.jsx | 168 | ||||
| -rw-r--r-- | src/lib/home/components/PreferredBrand.jsx | 56 | ||||
| -rw-r--r-- | src/lib/home/components/PromotionProgram.jsx | 118 | ||||
| -rw-r--r-- | src/lib/home/components/ServiceList.jsx | 34 | ||||
| -rw-r--r-- | src/lib/home/hooks/useCategoryPilihan.js | 13 |
11 files changed, 704 insertions, 107 deletions
diff --git a/src/lib/home/api/CategoryPilihanApi.js b/src/lib/home/api/CategoryPilihanApi.js new file mode 100644 index 00000000..8a0b38d3 --- /dev/null +++ b/src/lib/home/api/CategoryPilihanApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const categoryPilihanApi = async () => { + const dataCategoryPilihan = await odooApi('GET', '/api/v1/lob_homepage') + return dataCategoryPilihan +} + +export default categoryPilihanApi diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js new file mode 100644 index 00000000..2ff4fdfc --- /dev/null +++ b/src/lib/home/api/categoryManagementApi.js @@ -0,0 +1,44 @@ +export const fetchCategoryManagementSolr = async () => { + let sort = 'sort=sequence_i asc'; + try { + const response = await fetch( + `/solr/category_management/query?q=*:*&q.op=OR&indent=true&${sort}&&rows=20` + ); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + const promotions = await map(data.response.docs); + return promotions; + } catch (error) { + console.error('Error fetching promotion data:', error); + return []; + } +}; + +const map = async (promotions) => { + return promotions.map((promotion) => { + let parsedCategories = promotion.categories.map((category) => { + // Parse string JSON utama + let parsedCategory = JSON.parse(category); + + // Parse setiap elemen di child_frontend_id_i jika ada + if (parsedCategory.child_frontend_id_i) { + parsedCategory.child_frontend_id_i = + parsedCategory.child_frontend_id_i.map((child) => JSON.parse(child)); + } + + return parsedCategory; + }); + let productMapped = { + id: promotion.id, + name: promotion.name_s, + image: promotion.image_s, + sequence: promotion.sequence_i, + numFound: promotion.numFound_i, + categories: parsedCategories, + category_id: promotion.category_id_i, + }; + return productMapped; + }); +}; diff --git a/src/lib/home/components/BannerSection.jsx b/src/lib/home/components/BannerSection.jsx index 2010503d..f83c36fc 100644 --- a/src/lib/home/components/BannerSection.jsx +++ b/src/lib/home/components/BannerSection.jsx @@ -1,12 +1,12 @@ -import Link from '@/core/components/elements/Link/Link' -import Image from 'next/image' +import Link from '@/core/components/elements/Link/Link'; +import Image from 'next/image'; -const { useQuery } = require('react-query') -const { default: bannerSectionApi } = require('../api/bannerSectionApi') +const { useQuery } = require('react-query'); +const { default: bannerSectionApi } = require('../api/bannerSectionApi'); const BannerSection = () => { - const fetchBannerSection = async () => await bannerSectionApi() - const bannerSection = useQuery('bannerSection', fetchBannerSection) + const fetchBannerSection = async () => await bannerSectionApi(); + const bannerSection = useQuery('bannerSection', fetchBannerSection); return ( bannerSection.data && @@ -17,7 +17,7 @@ const BannerSection = () => { <Image width={1024} height={512} - quality={100} + quality={85} src={banner.image} alt={banner.name} className='h-auto w-full rounded' @@ -26,7 +26,7 @@ const BannerSection = () => { ))} </div> ) - ) -} + ); +}; -export default BannerSection +export default BannerSection; diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx new file mode 100644 index 00000000..49a9a93f --- /dev/null +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -0,0 +1,182 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { fetchCategoryManagementSolr } from '../api/categoryManagementApi'; +import NextImage from 'next/image'; +import Link from 'next/link'; +import { createSlug } from '@/core/utils/slug'; +import { Skeleton } from '@chakra-ui/react'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import 'swiper/css/navigation'; +import 'swiper/css/pagination'; +import { Pagination } from 'swiper'; + +const CategoryDynamic = () => { + const [categoryManagement, setCategoryManagement] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const loadBrand = useCallback(async () => { + setIsLoading(true); + const items = await fetchCategoryManagementSolr(); + + setIsLoading(false); + setCategoryManagement(items); + }, []); + + useEffect(() => { + loadBrand(); + }, [loadBrand]); + + // const [categoryData, setCategoryData] = useState({}); + // const [subCategoryData, setSubCategoryData] = useState({}); + + // useEffect(() => { + // const fetchCategoryData = async () => { + // if (categoryManagement && categoryManagement.data) { + // const updatedCategoryData = {}; + // const updatedSubCategoryData = {}; + + // for (const category of categoryManagement.data) { + // const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); + + // updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; + + // for (const subCategory of countLevel1?.children) { + // updatedSubCategoryData[subCategory.id] = subCategory?.numFound; + // } + // } + + // setCategoryData(updatedCategoryData); + // setSubCategoryData(updatedSubCategoryData); + // } + // }; + + // fetchCategoryData(); + // }, [categoryManagement.isLoading]); + + const swiperBanner = { + modules: [Pagination], + classNames: 'mySwiper', + slidesPerView: 3, + spaceBetween: 10, + pagination: { + dynamicBullets: true, + clickable: true, + }, + }; + + return ( + <div> + {categoryManagement && + categoryManagement?.map((category) => { + // const countLevel1 = categoryData[category.categoryIdI] || 0; + return ( + <Skeleton key={category.id} isLoaded={!isLoading}> + <div key={category.id}> + <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'> + <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'> + {category.name} + </h1> + {/* <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?.category_id + )} + className='!text-red-500 font-semibold' + > + Lihat Semua + </Link> + </div> + + {/* Swiper for SubCategories */} + <Swiper {...swiperBanner}> + {category.categories.map((subCategory) => { + // const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; + + return ( + <SwiperSlide key={subCategory.id}> + <div 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 p-4' + /> + <div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'> + <h2 className='font-semibold text-lg mr-2'> + {subCategory?.name} + </h2> + {/* <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?.id_level_2 + )} + 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] min-h-[240px] content-start'> + {subCategory.child_frontend_id_i.map( + (childCategory) => ( + <div key={childCategory.id} className=''> + <Link + href={createSlug( + '/shop/category/', + childCategory?.name, + childCategory?.id_level_3 + )} + 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} + className='p-2 ml-1' + 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'> + <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'> + {childCategory.name} + </h3> + </div> + </Link> + </div> + ) + )} + </div> + </div> + </div> + </SwiperSlide> + ); + })} + </Swiper> + </div> + </Skeleton> + ); + })} + </div> + ); +}; + +export default CategoryDynamic; diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx new file mode 100644 index 00000000..4a8f13cf --- /dev/null +++ b/src/lib/home/components/CategoryDynamicMobile.jsx @@ -0,0 +1,150 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import NextImage from 'next/image'; +import Link from 'next/link'; +import { createSlug } from '@/core/utils/slug'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import { fetchCategoryManagementSolr } from '../api/categoryManagementApi'; + +const CategoryDynamicMobile = () => { + const [selectedCategory, setSelectedCategory] = useState({}); + const [categoryManagement, setCategoryManagement] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const loadBrand = useCallback(async () => { + setIsLoading(true); + const items = await fetchCategoryManagementSolr(); + + setIsLoading(false); + setCategoryManagement(items); + }, []); + + useEffect(() => { + loadBrand(); + }, [loadBrand]); + + useEffect(() => { + const loadPromo = async () => { + try { + if (categoryManagement?.length > 0) { + const initialSelections = categoryManagement.reduce( + (acc, category) => { + if (category.categories.length > 0) { + acc[category.id] = category.categories[0].id_level_2; + } + return acc; + }, + {} + ); + setSelectedCategory(initialSelections); + } + } catch (loadError) { + // console.error("Error loading promo items:", loadError); + } + }; + + loadPromo(); + }, [categoryManagement]); + + const handleCategoryLevel2Click = (categoryIdI, idLevel2) => { + setSelectedCategory((prev) => ({ + ...prev, + [categoryIdI]: idLevel2, + })); + }; + + return ( + <div className='p-4'> + {categoryManagement && + categoryManagement?.map((category) => ( + <div key={category.id}> + <div className='bagian-judul flex flex-row justify-between items-center gap-3 mb-4 mt-4'> + <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'> + {category.name} + </h1> + <Link + href={createSlug( + '/shop/category/', + category?.name, + category?.category_id + )} + className='!text-red-500 font-semibold text-sm' + > + Lihat Semua + </Link> + </div> + <Swiper slidesPerView={2.3} spaceBetween={10}> + {category.categories.map((index) => ( + <SwiperSlide key={index.id}> + <div + onClick={() => + handleCategoryLevel2Click(category.id, index?.id_level_2) + } + className={`border flex justify-start items-center max-w-48 max-h-16 rounded ${ + selectedCategory[category.id] === index?.id_level_2 + ? 'bg-red-50 border-red-500 text-red-500' + : 'border-gray-200 text-gray-900' + }`} + > + <div className='p-1 flex justify-start items-center'> + <div className='flex flex-row justify-center items-center'> + <NextImage + src={ + index.image ? index.image : '/images/noimage.jpeg' + } + alt={index.name} + width={30} + height={30} + className='' + /> + <div className='bagian-judul flex flex-col justify-center items-start gap-1 ml-2'> + <h2 className='font-semibold text-[10px] line-clamp-1'> + {index?.name} + </h2> + </div> + </div> + </div> + </div> + </SwiperSlide> + ))} + </Swiper> + <div className='p-3 mt-2 border'> + <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'> + {category.categories.map( + (index) => + selectedCategory[category.id] === index?.id_level_2 && + index?.child_frontend_id_i.map((x) => ( + <div key={x.id}> + <Link + href={createSlug( + '/shop/category/', + x?.name, + x?.id_level_3 + )} + className='flex flex-row gap-1 border rounded group hover:border-red-500' + > + <NextImage + src={x.image ? x.image : '/images/noimage.jpeg'} + alt={x.name} + width={40} + height={40} + className='p-2' + /> + <div className='bagian-judul flex flex-col justify-center items-start gap-1 break-words line-clamp-2 group-hover:text-red-500'> + <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-[10px]'> + {x?.name} + </h3> + </div> + </Link> + </div> + )) + )} + </div> + </div> + </div> + ))} + </div> + ); +}; + +export default CategoryDynamicMobile; diff --git a/src/lib/home/components/CategoryHomeId.jsx b/src/lib/home/components/CategoryHomeId.jsx index 71428e27..9f436dac 100644 --- a/src/lib/home/components/CategoryHomeId.jsx +++ b/src/lib/home/components/CategoryHomeId.jsx @@ -1,13 +1,15 @@ -import { LazyLoadComponent } from 'react-lazy-load-image-component' -import useCategoryHomeId from '../hooks/useCategoryHomeId' -import CategoryHome from './CategoryHome' +import { LazyLoadComponent } from 'react-lazy-load-image-component'; +import useCategoryHomeId from '../hooks/useCategoryHomeId'; +import CategoryHome from './CategoryHome'; const CategoryHomeId = () => { - const { categoryHomeIds } = useCategoryHomeId() + const { categoryHomeIds } = useCategoryHomeId(); return ( <div> - <div className='font-semibold sm:text-h-lg mb-6 px-4 sm:px-0'>Kategori Pilihan</div> + <h1 className='font-semibold text-[14px] sm:text-h-lg mb-6 px-4 sm:px-0'> + Kategori Pilihan + </h1> <div className='flex flex-col gap-y-10'> {categoryHomeIds.data?.map((id) => ( <LazyLoadComponent key={id}> @@ -16,7 +18,7 @@ const CategoryHomeId = () => { ))} </div> </div> - ) -} + ); +}; -export default CategoryHomeId +export default CategoryHomeId; diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx new file mode 100644 index 00000000..2e5ca721 --- /dev/null +++ b/src/lib/home/components/CategoryPilihan.jsx @@ -0,0 +1,168 @@ +import Image from 'next/image'; +import useCategoryHome from '../hooks/useCategoryHome'; +import Link from '@/core/components/elements/Link/Link'; +import { createSlug } from '@/core/utils/slug'; +import { useEffect, useState } from 'react'; +import { bannerApi } from '../../../api/bannerApi'; +const { useQuery } = require('react-query'); +import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton'; +import useCategoryPilihan from '../hooks/useCategoryPilihan'; +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; + +const CategoryPilihan = ({ id, categories }) => { + const { isDesktop, isMobile } = useDevice(); + const { categoryPilihan } = useCategoryPilihan(); + const heroBanner = useQuery( + 'categoryPilihan', + bannerApi({ type: 'banner-category-list' }) + ); + return ( + categoryPilihan.length > 0 && ( + <section> + {isDesktop && ( + <div> + <div className='flex flex-row items-center mb-4'> + <div className='font-semibold sm:text-h-lg mr-2'> + LOB Kategori Pilihan + </div> + <p className='text-gray_r-10 text-sm'> + 200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia! + </p> + </div> + {heroBanner.data && heroBanner.data?.length > 0 && ( + <div className='flex w-full h-full justify-center mb-4 bg-cover bg-center'> + <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}> + <Image + width={1260} + height={170} + quality={85} + src={heroBanner.data[0].image} + alt={heroBanner.data[0].name} + className='h-full object-cover w-full' + /> + </Link> + </div> + )} + <div className='group/item grid grid-cols-6 gap-y-2 w-full h-full col-span-2 '> + {categoryPilihan?.data?.map((category) => ( + <div + key={category.id} + className='KartuInti h-48 w-60 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group' + > + <div className='KartuB absolute h-48 w-60 inset-0 flex items-center justify-center '> + <div className='group/edit flex items-center justify-end h-48 w-60 flex-col group-hover/item:visible'> + <div className=' h-36 flex justify-end items-end'> + <Image + className='group-hover:scale-105 transition-transform duration-300 ' + src={ + category?.image + ? category?.image + : '/images/noimage.jpeg' + } + width={120} + height={120} + alt={category?.name} + /> + </div> + <h2 className='text-gray-700 content-center h-12 border-t-[1px] px-1 w-60 border-gray-200 font-normal text-sm text-center'> + {category?.industries} + </h2> + </div> + </div> + <div className='KartuA relative inset-0 flex h-36 w-60 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '> + <Link + href={createSlug( + '/shop/lob/', + category?.industries, + category?.id + )} + className='category-mega-box__parent text-white rounded-lg' + > + Lihat semua + </Link> + </div> + </div> + ))} + </div> + </div> + )} + {isMobile && ( + <div className='p-4'> + <div className='flex flex-row items-center mb-4'> + <div className='font-semibold sm:text-h-md mr-2'> + LOB Kategori Pilihan + </div> + {/* <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p> */} + </div> + <div className='flex'> + {heroBanner.data && heroBanner.data?.length > 0 && ( + <div className=' object-fill '> + <Link + key={heroBanner.data[0].id} + href={heroBanner.data[0].url} + > + <Image + width={439} + height={150} + quality={85} + src={heroBanner.data[0].image} + alt={heroBanner.data[0].name} + className='object-cover' + /> + </Link> + </div> + )} + </div> + <Swiper slidesPerView={2.1} spaceBetween={10}> + {categoryPilihan?.data?.map((category) => ( + <SwiperSlide key={category.id}> + <div + key={category.id} + className='KartuInti mt-2 h-48 w-48 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group' + > + <div className='KartuB absolute h-48 w-48 inset-0 flex items-center justify-center '> + <div className='group/edit flex items-center justify-end h-48 w-48 flex-col group-hover/item:visible'> + <div className=' h-36 flex justify-end items-end'> + <Image + className='group-hover:scale-105 transition-transform duration-300 ' + src={ + category?.image + ? category?.image + : '/images/noimage.jpeg' + } + width={120} + height={120} + alt={category?.name} + /> + </div> + <h2 className='text-gray-700 content-center h-12 border-t-[1px] px-1 w-48 border-gray-200 font-normal text-sm text-center'> + {category?.industries} + </h2> + </div> + </div> + <div className='KartuA relative inset-0 flex h-36 w-48 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '> + <Link + href={createSlug( + '/shop/lob/', + category?.industries, + category?.id + )} + className='category-mega-box__parent text-white rounded-lg' + > + Lihat semua + </Link> + </div> + </div> + </SwiperSlide> + ))} + </Swiper> + </div> + )} + </section> + ) + ); +}; + +export default CategoryPilihan; diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx index 6b64a444..eefced60 100644 --- a/src/lib/home/components/PreferredBrand.jsx +++ b/src/lib/home/components/PreferredBrand.jsx @@ -1,4 +1,5 @@ import { Swiper, SwiperSlide } from 'swiper/react' +import { Navigation, Pagination, Autoplay } from 'swiper'; import { useCallback, useEffect, useState } from 'react' import usePreferredBrand from '../hooks/usePreferredBrand' import PreferredBrandSkeleton from './Skeleton/PreferredBrandSkeleton' @@ -8,7 +9,7 @@ import Link from '@/core/components/elements/Link/Link' import axios from 'axios' const PreferredBrand = () => { - let query = 'level_s' + let query = '' let params = 'prioritas' const [isLoading, setIsLoading] = useState(true) const [startWith, setStartWith] = useState(null) @@ -17,7 +18,7 @@ const PreferredBrand = () => { const loadBrand = useCallback(async () => { setIsLoading(true) const name = startWith ? `${startWith}*` : '' - const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=${name}`) + const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?rows=20`) setIsLoading(false) setManufactures((manufactures) => [...result.data]) @@ -34,38 +35,51 @@ const PreferredBrand = () => { useEffect(() => { loadBrand() - }, [loadBrand]) + }, []) - const { preferredBrands } = usePreferredBrand(query) + // const { preferredBrands } = usePreferredBrand(query) const { isMobile, isDesktop } = useDevice() - + const swiperBanner = { + modules:[Navigation, Pagination, Autoplay], + autoplay: { + delay: 4000, + disableOnInteraction: false + }, + loop: true, + className: 'h-[70px] md:h-[100px] w-full', + slidesPerView: isMobile ? 4 : 8, + spaceBetween: isMobile ? 12 : 0, + pagination: { + dynamicBullets: true, + dynamicMainBullets: isMobile ? 6 : 8, + clickable: true, + } + } + const preferredBrandsData = manufactures ? manufactures.slice(0, 20) : [] return ( <div className='px-4 sm:px-0'> <div className='flex justify-between items-center mb-4'> - <div className='font-semibold sm:text-h-lg'>Brand Pilihan</div> + <h1 className='font-semibold text-[14px] sm:text-h-lg'><Link href='/shop/brands' className='!text-black font-semibold'>Brand Pilihan</Link></h1> {isDesktop && ( <Link href='/shop/brands' className='!text-red-500 font-semibold'> Lihat Semua </Link> )} - {isMobile && ( - <Link href='/shop/brands' className='!text-red-500 font-semibold sm:text-h-sm'> - Lihat Semua - </Link> + </div> + <div className=''> + {manufactures.isLoading && <PreferredBrandSkeleton />} + {!manufactures.isLoading && ( + <Swiper {...swiperBanner}> + {preferredBrandsData.map((manufacture) => ( + <SwiperSlide key={manufacture.id}> + <BrandCard brand={manufacture} /> + </SwiperSlide> + ))} + </Swiper> )} </div> - {manufactures.isLoading && <PreferredBrandSkeleton />} - {!manufactures.isLoading && ( - <Swiper slidesPerView={isMobile ? 3.5 : 7.5} spaceBetween={isMobile ? 12 : 24} freeMode> - {manufactures.map((manufacture) => ( - <SwiperSlide key={manufacture.id}> - <BrandCard brand={manufacture} /> - </SwiperSlide> - ))} - </Swiper> - )} </div> ) } -export default PreferredBrand +export default PreferredBrand
\ No newline at end of file diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index c2f76069..ae06bd4d 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -1,13 +1,16 @@ -import Link from '@/core/components/elements/Link/Link' -import Image from 'next/image' +import Link from '@/core/components/elements/Link/Link'; +import Image from 'next/image'; import { bannerApi } from '@/api/bannerApi'; -import useDevice from '@/core/hooks/useDevice' +import useDevice from '@/core/hooks/useDevice'; import { Swiper, SwiperSlide } from 'swiper/react'; -import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton'; -const { useQuery } = require('react-query') +import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton'; +const { useQuery } = require('react-query'); const BannerSection = () => { - const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); - const { isMobile, isDesktop } = useDevice() + const promotionProgram = useQuery( + 'promotionProgram', + bannerApi({ type: 'banner-promotion' }) + ); + const { isMobile, isDesktop } = useDevice(); if (promotionProgram.isLoading) { return <BannerPromoSkeleton />; @@ -16,60 +19,65 @@ const BannerSection = () => { return ( <div className='px-4 sm:px-0'> <div className='flex justify-between items-center mb-4 '> - <div className='font-semibold sm:text-h-lg'>Promo Tersedia</div> + <h1 className='font-semibold text-[14px] sm:text-h-lg'> + {' '} + <Link href='/shop/promo' className='!text-black font-semibold'> + Promo Tersedia + </Link> + </h1> {isDesktop && ( <Link href='/shop/promo' className='!text-red-500 font-semibold'> - Lihat Semua - </Link> + Lihat Semua + </Link> )} {isMobile && ( - <Link href='/shop/promo' className='!text-red-500 font-semibold sm:text-h-sm'> - Lihat Semua - </Link> - )} - </div> - {isDesktop && (promotionProgram.data && - promotionProgram.data?.length > 0 && ( - <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> - {promotionProgram.data?.map((banner) => ( - <Link key={banner.id} href={banner.url}> - <Image - width={439} - height={150} - quality={100} - src={banner.image} - alt={banner.name} - className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out' - /> + <Link + href='/shop/promo' + className='!text-red-500 font-semibold sm:text-h-sm' + > + Lihat Semua </Link> - ))} + )} </div> - - ))} + {isDesktop && + promotionProgram.data && + promotionProgram.data?.length > 0 && ( + <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> + {promotionProgram.data?.map((banner) => ( + <Link key={banner.id} href={banner.url}> + <Image + width={439} + height={150} + quality={85} + src={banner.image} + alt={banner.name} + className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out' + /> + </Link> + ))} + </div> + )} -{isMobile && ( - - <Swiper slidesPerView={1.1} spaceBetween={8} freeMode> - {promotionProgram.data?.map((banner) => ( - <SwiperSlide key={banner.id}> - <Link key={banner.id} href={banner.url}> - <Image - width={439} - height={150} - quality={100} - src={banner.image} - alt={banner.name} - className='h-auto w-full rounded ' - /> - </Link> - </SwiperSlide> - ))} - </Swiper> - - )} + {isMobile && ( + <Swiper slidesPerView={1.1} spaceBetween={8} freeMode> + {promotionProgram.data?.map((banner) => ( + <SwiperSlide key={banner.id}> + <Link key={banner.id} href={banner.url}> + <Image + width={439} + height={150} + quality={85} + src={banner.image} + alt={banner.name} + className='h-auto w-full rounded ' + /> + </Link> + </SwiperSlide> + ))} + </Swiper> + )} </div> - - ) -} + ); +}; -export default BannerSection +export default BannerSection; diff --git a/src/lib/home/components/ServiceList.jsx b/src/lib/home/components/ServiceList.jsx index b8799d7d..5b16915d 100644 --- a/src/lib/home/components/ServiceList.jsx +++ b/src/lib/home/components/ServiceList.jsx @@ -1,5 +1,5 @@ -import Image from 'next/image' -import Link from '@/core/components/elements/Link/Link' +import Image from 'next/image'; +import Link from '@/core/components/elements/Link/Link'; const ServiceList = () => { return ( @@ -14,14 +14,16 @@ const ServiceList = () => { <Image width={24} height={24} - quality={100} + quality={85} 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> + <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> @@ -37,14 +39,16 @@ const ServiceList = () => { <Image width={24} height={24} - quality={100} + quality={85} 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> + <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> @@ -60,14 +64,16 @@ const ServiceList = () => { <Image width={24} height={24} - quality={100} + quality={85} 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> + <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> @@ -83,14 +89,16 @@ const ServiceList = () => { <Image width={24} height={24} - quality={100} + quality={85} 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> + <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> @@ -99,7 +107,7 @@ const ServiceList = () => { </div> </div> </div> - ) -} + ); +}; -export default ServiceList +export default ServiceList; diff --git a/src/lib/home/hooks/useCategoryPilihan.js b/src/lib/home/hooks/useCategoryPilihan.js new file mode 100644 index 00000000..12a86f7e --- /dev/null +++ b/src/lib/home/hooks/useCategoryPilihan.js @@ -0,0 +1,13 @@ +import categoryPilihanApi from '../api/CategoryPilihanApi' +import { useQuery } from 'react-query' + +const useCategoryPilihan = () => { + const fetchCategoryPilihan = async () => await categoryPilihanApi() + const { isLoading, data } = useQuery('categoryPilihanApi', fetchCategoryPilihan) + + return { + categoryPilihan: { data, isLoading } + } +} + +export default useCategoryPilihan
\ No newline at end of file |
