diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-06-11 13:40:23 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-06-11 13:40:23 +0700 |
| commit | 9565ddf794165e297acf511a108f9a9643ee615d (patch) | |
| tree | 07bf6168f6f221c73bc8db5aa17e6bd097c6e4b2 /src | |
| parent | 5e5b67e5b98d3183044dc5149fe67a29feeb3c41 (diff) | |
<iman> update promotion program
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/promoApi.js | 4 | ||||
| -rw-r--r-- | src/lib/home/components/PromotionProgram.jsx | 14 | ||||
| -rw-r--r-- | src/pages/shop/promo/[slug].tsx | 77 | ||||
| -rw-r--r-- | src/pages/shop/promo/index.tsx | 188 |
4 files changed, 259 insertions, 24 deletions
diff --git a/src/api/promoApi.js b/src/api/promoApi.js index 535df021..ecae5080 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -13,11 +13,13 @@ export const fetchPromoItems = async (type) => { }; export const fetchPromoItemsSolr = async (type) => { + // let query = type ? `type_value_s:${type}` : '*:*'; let start = 0 let rows = 120 try { - const queryParams = new URLSearchParams({ q: `type_value_s:${type}` }); + const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + console.log("Constructed URL SLOR:", `/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index a3c09a9b..98bc7c7f 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -9,17 +9,19 @@ const BannerSection = () => { return ( <div className='px-4 sm:px-0'> - <div className='flex justify-between items-center mb-4'> + <div className='flex justify-between items-center mb-4 '> <div className='font-semibold sm:text-h-lg'>Promo Tersedia</div> {isDesktop && ( - <Link href='/shop/promo' className='!text-red-500 font-semibold'> - Lihat Semua - </Link> + <Link href='/shop/promo' + className="rounded-md bg-[#FAD147] px-3.5 py-2.5 text-sm font-semibold text-neutral-950 shadow-sm hover:bg-yellow-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-yellow-600" + > + Lihat Semua + </Link> )} </div> {promotionProgram.data && promotionProgram.data?.length > 0 && ( - <div className='bg-red-300 grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> + <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 @@ -28,7 +30,7 @@ const BannerSection = () => { quality={100} src={banner.image} alt={banner.name} - className='h-auto w-full rounded' + className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out' /> </Link> ))} diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index cd3e93c4..be5a715d 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -10,7 +10,6 @@ import { IPromotion } from '../../../../src-migrate/types/promotion' import React from 'react' import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; - const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { @@ -22,14 +21,15 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); - const visiblePromotions = promoData?.slice(startIndex, endIndex); + // const visiblePromotions = promoData?.slice(startIndex, endIndex); const [loading, setLoading] = useState(true); // Menambahkan status loading + const [fetchingData, setFetchingData] = useState(false) useEffect(() => { const loadPromo = async () => { try { - const items = await fetchPromoItemsSolr(Array.isArray(slug) ? slug[0] : slug) + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) console.log("slug sekarang ", slug) setPromoItems(items) @@ -112,18 +112,60 @@ export default function PromoDetail() { console.log("data yg dikirim ke ProductPromoCard", promoData) function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); + // Ganti semua tanda _ dengan spasi + string = string.replace(/_/g, ' '); + + // Kapitalisasi huruf pertama setelah spasi atau awal string + return string.replace(/(^\w|\s\w)/g, function(match) { + return match.toUpperCase(); + }); + + + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } } - const goToNextPage = () => { - setCurrentPage((prevPage) => prevPage + 1); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; + const visiblePromotions = promoData?.slice(0, currentPage * 12) + - const goToPreviousPage = () => { - setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; return ( <BasicLayout> @@ -142,14 +184,15 @@ export default function PromoDetail() { <div className='flex flex-wrap justify-center'> {visiblePromotions?.map((promotion) => ( <div key={promotion.id} className="min-w-[40px] max-w-[400px] mr-[20px] mb-[20px] sm:w-full md:w-1/2 lg:w-1/3 xl:w-1/4"> - <ProductPromoCard promotion={promotion} slug={Array.isArray(slug) ? slug[0] : slug} /> + <ProductPromoCard promotion={promotion}/> </div> ))} </div> - <div className="flex justify-center mt-4"> - <button onClick={goToPreviousPage} disabled={currentPage === 1} className="mr-2 px-4 py-2 bg-gray-200 rounded">Back</button> - <button onClick={goToNextPage} disabled={endIndex >= promoData.length} className="px-4 py-2 bg-gray-200 rounded">Next</button> - </div> + {fetchingData && ( + <div className='container flex justify-center my-4'> + <LogoSpinner width={48} height={48} /> + </div> + )} </> ) : ( <div className="text-center my-8"> diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx new file mode 100644 index 00000000..6f5134a3 --- /dev/null +++ b/src/pages/shop/promo/index.tsx @@ -0,0 +1,188 @@ +import dynamic from 'next/dynamic' +import { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import Seo from '../../../core/components/Seo.jsx' +import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx' +import { fetchPromoItemsSolr } from '../../../api/promoApi.js' +import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' +import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx' +import { IPromotion } from '../../../../src-migrate/types/promotion.ts' +import React from 'react' +import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) + +export default function Promo() { + const router = useRouter() + const { slug = '' } = router.query + const [promoItems, setPromoItems] = useState<any[]>([]) + const [promoData, setPromoData] = useState<IPromotion[] | null>(null) + const [loading, setLoading] = useState(true) + const [currentPage, setCurrentPage] = useState(1) + const [fetchingData, setFetchingData] = useState(false) + + useEffect(() => { + const loadPromo = async () => { + try { + const items = await fetchPromoItemsSolr(`*:*`) + console.log("slug sekarang ", slug) + + setPromoItems(items) + console.log("data dari promotion pakai SOLR", items) + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const promoDataPromises = items.map(async (item) => { + const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + + try { + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) + console.log("respon data ", response) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: SolrResponse<any[]> = await response.json() + console.log("data promo IPromotion[]", data) + + const promotions = await map(data.response.docs) + return promotions; + } catch (fetchError) { + console.error("Error fetching promotion data:", fetchError) + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + } catch (loadError) { + console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + }, [slug]) + + const map = async (promotions: any[]): Promise<IPromotion[]> => { + const result: IPromotion[] = [] + + for (const promotion of promotions) { + const data: IPromotion = { + id: promotion.id, + program_id: promotion.program_id_i, + name: promotion.name_s, + type: { + value: promotion.type_value_s, + label: promotion.type_label_s, + }, + limit: promotion.package_limit_i, + limit_user: promotion.package_limit_user_i, + limit_trx: promotion.package_limit_trx_i, + price: promotion.price_f, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + } + + result.push(data) + } + + return result + } + + console.log("data yg dikirim ke ProductPromoCard", promoData) + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } + } + + const visiblePromotions = promoData?.slice(0, currentPage * 12) + + return ( + <BasicLayout> + <Seo + title={`Promo ${Array.isArray(slug) ? slug[0] : slug} Terkini`} + description='B2B Marketplace MRO & Industri dengan Layanan Pembayaran Tempo, Faktur Pajak, Online Quotation, Garansi Resmi & Harga Kompetitif' + /> + {/* <Promocrumb brandName={capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug)} /> */} + <div className='container mx-auto mt-1 flex mb-1'> + <div className=''> + <h1 className='font-semibold'>Semua Promo di Indoteknik</h1> + </div> + </div> + {loading ? ( + <div className='container flex justify-center my-4'> + <LogoSpinner width={48} height={48} /> + </div> + ) : promoData && promoItems.length >= 1 ? ( + <> + <div className='flex flex-wrap justify-center'> + {visiblePromotions?.map((promotion) => ( + <div key={promotion.id} className="min-w-[40px] max-w-[400px] mr-[20px] mb-[20px] sm:w-full md:w-1/2 lg:w-1/3 xl:w-1/4"> + <ProductPromoCard promotion={promotion} /> + </div> + ))} + </div> + {fetchingData && ( + <div className='container flex justify-center my-4'> + <LogoSpinner width={48} height={48} /> + </div> + )} + </> + ) : ( + <div className="text-center my-8"> + <p>Belum ada promo pada kategori ini</p> + </div> + )} + </BasicLayout> + ) +} |
