summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/promoApi.js17
-rw-r--r--src/pages/shop/promo/[slug].tsx501
2 files changed, 404 insertions, 114 deletions
diff --git a/src/api/promoApi.js b/src/api/promoApi.js
index ecae5080..4c386fba 100644
--- a/src/api/promoApi.js
+++ b/src/api/promoApi.js
@@ -1,5 +1,6 @@
// src/api/promoApi.js
import odooApi from '@/core/api/odooApi';
+import { type } from 'os';
// import { SolrResponse } from "../../../../src-migrate/types/solr.ts";
export const fetchPromoItems = async (type) => {
@@ -15,11 +16,10 @@ export const fetchPromoItems = async (type) => {
export const fetchPromoItemsSolr = async (type) => {
// let query = type ? `type_value_s:${type}` : '*:*';
let start = 0
- let rows = 120
+ let rows = 100
try {
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}`);
}
@@ -32,6 +32,18 @@ export const fetchPromoItemsSolr = async (type) => {
}
};
+export const fetchVariantSolr = async(data)=>{
+ try {
+ const queryParams = new URLSearchParams({ q: data });
+ const response = await fetch(`/solr/variants/select?${queryParams.toString()}`);
+ const responseData = await response.json();
+ return responseData;
+ } catch (error) {
+ console.error("Error fetching promotion data:", error);
+ return [];
+ }
+};
+
const map = async (promotions) => {
const result = [];
for (const promotion of promotions) {
@@ -49,6 +61,7 @@ const map = async (promotions) => {
price: promotion.price_f,
total_qty: promotion.total_qty_i,
products: JSON.parse(promotion.products_s),
+ product_id: promotion.product_ids[0],
free_products: JSON.parse(promotion.free_products_s),
};
result.push(data);
diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx
index 1935c61f..70280d1f 100644
--- a/src/pages/shop/promo/[slug].tsx
+++ b/src/pages/shop/promo/[slug].tsx
@@ -1,4 +1,5 @@
import dynamic from 'next/dynamic'
+import NextImage from 'next/image';
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import Seo from '../../../core/components/Seo'
@@ -10,6 +11,7 @@ import { IPromotion } from '../../../../src-migrate/types/promotion'
import React from 'react'
import { SolrResponse } from "../../../../src-migrate/types/solr.ts";
import DesktopView from '../../../core/components/views/DesktopView';
+import MobileView from '../../../core/components/views/MobileView';
import 'swiper/swiper-bundle.css';
import useDevice from '../../../core/hooks/useDevice'
import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop';
@@ -17,22 +19,47 @@ import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react';
import { formatCurrency } from '../../../core/utils/formatValue';
import Pagination from '../../../core/components/elements/Pagination/Pagination';
import { cons } from 'lodash-contrib'
+// import SideBanner from '~/modules/side-banner';
+import SideBanner from '../../../../src-migrate/modules/side-banner';
+import whatsappUrl from '../../../core/utils/whatsappUrl';
+import { toQuery } from 'lodash-contrib';
+import _ from 'lodash';
const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout'))
export default function PromoDetail() {
const router = useRouter()
- const { slug = '', brand, category } = router.query
+ const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query
const [promoItems, setPromoItems] = useState<any[]>([])
const [promoData, setPromoData] = useState<IPromotion[] | null>(null)
- const [currentPage, setCurrentPage] = useState(1);
+ const [currentPage, setCurrentPage] = useState(parseInt(page as string, 10) || 1);
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 [loading, setLoading] = useState(true);
const { isMobile, isDesktop } = useDevice()
const [brands, setBrands] = useState<Brand[]>([]);
const [categories, setCategories] = useState<Category[]>([]);
+ const [brandValues, setBrandValues] = useState<string[]>([]);
+ const [categoryValues, setCategoryValues] = useState<string[]>([]);
+ const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular');
+ const [spellings, setSpellings] = useState(null);
+
+ useEffect(() => {
+ // Initialize brandValues based on router.query.brand
+ if (router.query.brand) {
+ const brandsArray = Array.isArray(router.query.brand) ? router.query.brand : [router.query.brand];
+ setBrandValues(brandsArray);
+ } else {
+ setBrandValues([]);
+ }
+
+ // Initialize categoryValues based on router.query.category
+ if (router.query.category) {
+ const categoriesArray = Array.isArray(router.query.category) ? router.query.category : [router.query.category];
+ setCategoryValues(categoriesArray);
+ } else {
+ setCategoryValues([]);
+ }
+ }, [router.query.brand, router.query.category]);
interface Brand {
brand: string;
@@ -49,11 +76,15 @@ export default function PromoDetail() {
setLoading(true);
const brandsData: Brand[] = [];
const categoriesData: Category[] = [];
-
+
+ const pageNumber = Array.isArray(page) ? parseInt(page[0], 10) : parseInt(page, 10);
+ setCurrentPage(pageNumber)
try {
- const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`)
- setPromoItems(items)
+ // const start = (pageNumber-1) * itemsPerPage;
+ const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`);
+ setPromoItems(items);
+ console.log("promoItems lastIndexOf",promoItems.length)
if (items.length === 0) {
setPromoData([])
@@ -61,67 +92,76 @@ export default function PromoDetail() {
return;
}
+ const brandArray = Array.isArray(brand) ? brand : brand.split(',');
+ const categoryArray = Array.isArray(category) ? category : category.split(',');
+ console.log("brandArray",brandArray)
+ console.log("categoryArray",categoryArray)
const promoDataPromises = items.map(async (item) => {
// const queryParams = new URLSearchParams({ q: `id:${item.id}` })
console.log("produk id",item.product_id)
try {
- if(brand && category){
- const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand} && category_name :${category}`);
- const product = response.response.docs[0];
- const product_id = product.id
- console.log("data brand ",brand)
- console.log("data respon varian ",product)
- console.log("data ID respon varian ",product_id)
- const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`)
- console.log("data response2 ",response2)
- return response2;
- }else if(brand){ // belum bisa menangani lebih dari 1 brand
- const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand}`);
+ let brandQuery = '';
+ if (brand) {
+ brandQuery = brandArray.map(b => `manufacture_name_s:${b}`).join(' OR ');
+ brandQuery = `(${brandQuery})`;
+ }
+
+ let categoryQuery = '';
+ if (category) {
+ categoryQuery = categoryArray.map(c => `category_name:${c}`).join(' OR ');
+ categoryQuery = `(${categoryQuery})`;
+ }
+
+ let priceQuery = '';
+ if (priceFrom && priceTo) {
+ priceQuery = `price_f:[${priceFrom} TO ${priceTo}]`;
+ } else if (priceFrom) {
+ priceQuery = `price_f:[${priceFrom} TO *]`;
+ } else if (priceTo) {
+ priceQuery = `price_f:[* TO ${priceTo}]`;
+ }
+
+ let combinedQuery = '';
+ let combinedQueryPrice = `${priceQuery}`;
+ if (brand && category && priceFrom || priceTo) {
+ combinedQuery = `${brandQuery} AND ${categoryQuery} `;
+ } else if (brand && category) {
+ combinedQuery = `${brandQuery} AND ${categoryQuery}`;
+ } else if (brand && priceFrom || priceTo) {
+ combinedQuery = `${brandQuery}`;
+ } else if (category && priceFrom || priceTo) {
+ combinedQuery = `${categoryQuery}`;
+ } else if (brand) {
+ combinedQuery = brandQuery;
+ } else if (category) {
+ combinedQuery = categoryQuery;
+ } else if (priceFrom || priceTo) {
+ }
+ console.log("combinedQuery",combinedQuery)
+
+ if (combinedQuery && priceFrom || priceTo) {
+ const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`);
const product = response.response.docs[0];
- const product_id = product.id
- console.log("data brand ",brand)
- console.log("data respon varian ",product)
- console.log("data ID respon varian ",product_id)
- const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`)
- console.log("data response2 ",response2)
+ const product_id = product.id;
+ const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`);
+ // const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `);
return response2;
- }else if (category){ // belum bisa menangani lebih dari 1 category
- const response = await fetchVariantSolr(`id:${item.product_id} && category_name :${category}`);
+ }else if(combinedQuery){
+ const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`);
const product = response.response.docs[0];
- const product_id = product.id
- console.log("data brand ",brand)
- console.log("data respon varian ",product)
- console.log("data ID respon varian ",product_id)
- const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`)
+ const product_id = product.id;
+ const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `);
return response2;
- }else{
- const response = await fetchPromoItemsSolr( `id:${item.id}`)
- console.log("data respon",response)
+ }
+ else {
+ const response = await fetchPromoItemsSolr(`id:${item.id}`);
return response;
}
- // if(brand || category){
- // let query = `id:${item.product_id}`;
- // if (brand) query += ` OR manufacture_name_s:${brand}`;
- // if (category) query += ` OR category_name:${category}`;
- // const response = await fetchVariantSolr(query);
- // const product = response.response.docs[0];
- // const product_id = product.id
- // const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`)
- // return response2;
-
- // }else{
- // const response = await fetchPromoItemsSolr( `id:${item.id}`)
- // console.log("data respon",response)
- // return response;
- // }
-
-
- } catch (fetchError) {
- // console.error("Error fetching promotion data:", fetchError)
- return [];
- }
- });
+ } catch (fetchError) {
+ return [];
+ }
+ });
const promoDataArray = await Promise.all(promoDataPromises);
const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
@@ -130,11 +170,10 @@ export default function PromoDetail() {
const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => {
if (promoData) {
const dataBrandCategory = promoData.map(async (item) => {
- // const response = await fetch(`/solr/variants/select?${queryParams2.toString()}`);
let response;
if(category){
- // response = await fetchVariantSolr(`id:${item.products[0].product_id} && manufacture_name_s:${brand}`);
- response = await fetchVariantSolr(`id:${item.products[0].product_id} && category_name:${category}`);
+ const categoryQuery = categoryArray.map(c => `category_name:${c}`).join(' OR ');
+ response = await fetchVariantSolr(`id:${item.products[0].product_id} AND (${categoryQuery})`);
}else{
response = await fetchVariantSolr(`id:${item.products[0].product_id}`)
}
@@ -190,34 +229,8 @@ export default function PromoDetail() {
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)
- }
+ },[slug, brand, category, priceFrom, priceTo, currentPage]);
- return result
- }
function capitalizeFirstLetter(string) {
string = string.replace(/_/g, ' ');
@@ -226,40 +239,304 @@ export default function PromoDetail() {
});
}
- const visiblePromotions = promoData?.slice(0, currentPage * 12)
+ const handleDeleteFilter = async (source, value) => {
+ let params = {
+ q: router.query.q,
+ orderBy: orderBy,
+ brand: brandValues.join(','),
+ category: categoryValues.join(','),
+ priceFrom: priceFrom || '',
+ priceTo: priceTo || '',
+ };
+
+ let brands = brandValues;
+ let catagories = categoryValues;
+ switch (source) {
+ case 'brands':
+ brands = brandValues.filter((item) => item !== value);
+ params.brand = brands.join(',');
+ await setBrandValues(brands);
+ break;
+ case 'category':
+ catagories = categoryValues.filter((item) => item !== value);
+ params.category = catagories.join(',');
+ await setCategoryValues(catagories);
+ break;
+ case 'price':
+ params.priceFrom = ''; // Setel ke string kosong jika ingin menghapus nilai
+ params.priceTo = ''; // Setel ke string kosong jika ingin menghapus nilai
+ break;
+ case 'delete':
+ params = {
+ q: router.query.q,
+ orderBy: orderBy,
+ brand: '',
+ category: '',
+ priceFrom: '',
+ priceTo: '',
+ };
+ break;
+ }
+
+ handleSubmitFilter(params);
+ };
+ const handleSubmitFilter = (params) => {
+ params = _.pickBy(params, _.identity);
+ params = toQuery(params);
+ router.push(`${Array.isArray(slug) ? slug[0] : slug}?${params}`);
+ // router.push(`${Array.isArray(slug) ? slug[0] : slug}`);
+ };
+ const handlePageChange = (selectedPage: number) => {
+ setCurrentPage(selectedPage);
+ router.push(`/shop/promo/${slug}?page=${selectedPage}`);
+ };
+
+ const { search } = router.query;
+ const prefixUrl = `/promo/${slug}`;
+
+ console.log("halaman sekarang", currentPage)
+ console.log("data yang di potong", (currentPage-1) * itemsPerPage, currentPage * 12)
+
+ const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12)
+ // const visiblePromotions = promoData?.slice( 0, 12)
const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock';
+ const whatPromo = capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug)
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)} />
- <ProductFilterDesktop
- brands={brands || []}
- categories={categories || []}
- prefixUrl={'/shop/promo'}
- defaultBrand={null}
- />
- {loading ? (
- <div className='container flex justify-center my-4'>
- <LogoSpinner width={48} height={48} />
- </div>
- ) : promoData && promoItems.length >= 1 ? (
- <>
- <div className=''>
- {visiblePromotions?.map((promotion) => (
- <div key={promotion.id} className="min-w-[400px] max-w-[400px] mb-[20px] sm:w-full md:w-1/2 lg:w-1/3 xl:w-1/4">
- <ProductPromoCard promotion={promotion}/>
+ <Promocrumb brandName={whatPromo} />
+
+ <DesktopView>
+ <div className='container mx-auto flex mb-3'>
+ <div className='w-3/12'>
+ <ProductFilterDesktop
+ brands={brands || []}
+ categories={categories || []}
+ prefixUrl={'/shop/promo'}
+ defaultBrand={null}
+ />
+ <div className='h-6' />
+ <SideBanner />
+ </div>
+ <div className='w-9/12 pl-6'>
+ <h1 className='text-2xl mb-2 font-semibold'>Promo {whatPromo}</h1>
+ <FilterChoicesComponent
+ brandValues={brandValues}
+ categoryValues={categoryValues}
+ priceFrom={priceFrom}
+ priceTo={priceTo}
+ handleDeleteFilter={handleDeleteFilter}
+ />
+ {/* <div className='flex justify-between items-center mb-5'>
+ <div className='leading-6 text-gray_r-11'>
+ {!spellings ? (
+ <>
+ Menampilkan&nbsp;
+ {pageCount > 1 ? (
+ <>
+ {productStart + 1}-
+ {parseInt(productStart) + parseInt(productRows) >
+ productFound
+ ? productFound
+ : parseInt(productStart) + parseInt(productRows)}
+ &nbsp;dari&nbsp;
+ </>
+ ) : (
+ ''
+ )}
+ {productFound}
+ &nbsp;produk{' '}
+ {query.q && (
+ <>
+ untuk pencarian{' '}
+ <span className='font-semibold'>{query.q}</span>
+ </>
+ )}
+ </>
+ ) : (
+ SpellingComponent
+ )}
+ </div>
+ <div className='justify-end flex '>
+ <div className='ml-3'>
+ <select
+ name='urutan'
+ className='form-input'
+ value={orderBy}
+ onChange={(e) => handleOrderBy(e)}
+ >
+ {orderOptions.map((option, index) => (
+ <option key={index} value={option.value}>
+ {' '}
+ {option.label}{' '}
+ </option>
+ ))}
+ </select>
+ </div>
+ <div className='ml-3'>
+ <select
+ name='limit'
+ className='form-input'
+ value={router.query?.limit || ''}
+ onChange={(e) => handleLimit(e)}
+ >
+ {numRows.map((option, index) => (
+ <option key={index} value={option}>
+ {' '}
+ {option}{' '}
+ </option>
+ ))}
+ </select>
+ </div>
+ </div>
+ </div> */}
+ {loading ? (
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ ) : promoData && promoItems.length >= 1 ? (
+ <>
+ <div className='grid grid-cols-3 gap-x-96 gap-y-1'>
+ {visiblePromotions?.map((promotion) => (
+ <div key={promotion.id} className="min-w-[400px] max-w-[400px] mb-[20px] sm:w-full md:w-1/2 lg:w-1/3 xl:w-1/4 ">
+ <ProductPromoCard promotion={promotion}/>
+ </div>
+ ))}
+ </div>
+ </>
+ ) : (
+ <div className="text-center my-8">
+ <p>Belum ada promo pada kategori ini</p>
+ </div>
+ )}
+ <div className='flex justify-between items-center mt-6 mb-2'>
+ <div className='pt-2 pb-6 flex items-center gap-x-3'>
+ <NextImage
+ src='/images/logo-question.png'
+ alt='Logo Question Indoteknik'
+ width={60}
+ height={60}
+ />
+ <div className='text-gray_r-12/90'>
+ <span>
+ Barang yang anda cari tidak ada?{' '}
+ <a
+ href={
+ router.query?.q
+ ? whatsappUrl('productSearch', {
+ name: router.query.q,
+ })
+ : whatsappUrl()
+ }
+ className='text-danger-500'
+ >
+ Hubungi Kami
+ </a>
+ </span>
+ </div>
+ </div>
+
+ <Pagination
+ pageCount={Math.ceil(promoItems.length/itemsPerPage )}
+ // pageCount={Math.ceil(5)}
+ currentPage={currentPage}
+ url={`${Array.isArray(slug) ? slug[0] : slug}`}
+ className='mt-6 mb-2'
+ />
</div>
- ))}
+
</div>
- </>
- ) : (
- <div className="text-center my-8">
- <p>Belum ada promo pada kategori ini</p>
</div>
- )}
+ {console.log("promoItems lastIndexOf",promoItems.length)}
+ </DesktopView>
</BasicLayout>
)
-}
+ }
+
+const FilterChoicesComponent = ({
+ brandValues,
+ categoryValues,
+ priceFrom,
+ priceTo,
+ handleDeleteFilter,
+ }) => (
+ <div className='flex items-center'>
+ <HStack spacing={2} className='flex-wrap'>
+ {brandValues?.map((value, index) => (
+ <Tag
+ size='lg'
+ key={index}
+ borderRadius='lg'
+ variant='outline'
+ colorScheme='gray'
+ >
+ <TagLabel>{value}</TagLabel>
+ <TagCloseButton onClick={() => handleDeleteFilter('brands', value)} />
+ </Tag>
+ ))}
+
+ {categoryValues?.map((value, index) => (
+ <Tag
+ size='lg'
+ key={index}
+ borderRadius='lg'
+ variant='outline'
+ colorScheme='gray'
+ >
+ <TagLabel>{value}</TagLabel>
+ <TagCloseButton
+ onClick={() => handleDeleteFilter('category', value)}
+ />
+ </Tag>
+ ))}
+ {priceFrom && priceTo && (
+ <Tag size='lg' borderRadius='lg' variant='outline' colorScheme='gray'>
+ <TagLabel>
+ {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)}
+ </TagLabel>
+ <TagCloseButton
+ onClick={() => handleDeleteFilter('price', priceFrom)}
+ />
+ </Tag>
+ )}
+ {brandValues?.length > 0 ||
+ categoryValues?.length > 0 ||
+ priceFrom ||
+ priceTo ? (
+ <span>
+ <button
+ className='btn-transparent py-2 px-5 h-[40px] text-red-700'
+ onClick={() => handleDeleteFilter('delete')}
+ >
+ Hapus Semua
+ </button>
+ </span>
+ ) : (
+ ''
+ )}
+ </HStack>
+ </div>
+);
+
+// {loading ? (
+// <div className='container flex justify-center my-4'>
+// <LogoSpinner width={48} height={48} />
+// </div>
+// ) : promoData && promoItems.length >= 1 ? (
+// <>
+// <div className=''>
+// {visiblePromotions?.map((promotion) => (
+// <div key={promotion.id} className="min-w-[400px] max-w-[400px] mb-[20px] sm:w-full md:w-1/2 lg:w-1/3 xl:w-1/4">
+// <ProductPromoCard promotion={promotion}/>
+// </div>
+// ))}
+// </div>
+// </>
+// ) : (
+// <div className="text-center my-8">
+// <p>Belum ada promo pada kategori ini</p>
+// </div>
+// )} \ No newline at end of file