summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMqdd <ahmadmiqdad27@gmail.com>2025-11-19 10:39:14 +0700
committerMqdd <ahmadmiqdad27@gmail.com>2025-11-19 10:39:14 +0700
commitadae00439898ccb0b2c20f2043aa4cd72bb23045 (patch)
tree8ce3e41598e7d83495c6bd5e88340ee50c6b4495 /src
parenta98d28611e845e753e4a817650da0996f3236806 (diff)
<Miqdad> canonical Promo
Diffstat (limited to 'src')
-rw-r--r--src/pages/shop/promo/[slug].jsx350
1 files changed, 191 insertions, 159 deletions
diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx
index cfb2c841..a0ffecea 100644
--- a/src/pages/shop/promo/[slug].jsx
+++ b/src/pages/shop/promo/[slug].jsx
@@ -1,16 +1,16 @@
-import dynamic from 'next/dynamic'
+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.jsx'
-import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx'
-import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx'
-import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx'
-import React from 'react'
+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 LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx';
+import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx';
+import React from 'react';
import DesktopView from '../../../core/components/views/DesktopView.jsx';
import MobileView from '../../../core/components/views/MobileView.jsx';
import 'swiper/swiper-bundle.css';
-import useDevice from '../../../core/hooks/useDevice.js'
+import useDevice from '../../../core/hooks/useDevice.js';
import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion.jsx';
import ProductFilter from '../../../lib/product/components/ProductFilter.jsx';
import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react';
@@ -21,15 +21,17 @@ import _ from 'lodash';
import useActive from '../../../core/hooks/useActive.js';
import useProductSearch from '../../../lib/promo/hooks/usePromotionSearch.js';
-const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx'))
+const BasicLayout = dynamic(() =>
+ import('../../../core/components/layouts/BasicLayout.jsx')
+);
export default function PromoDetail() {
- const router = useRouter()
- const { slug = '', brand ='', category='', page = '1' } = router.query
+ const router = useRouter();
+ const { slug = '', brand = '', category = '', page = '1' } = router.query;
const [currentPage, setCurrentPage] = useState(parseInt(10) || 1);
const [orderBy, setOrderBy] = useState(router.query?.orderBy);
const popup = useActive();
- const prefixUrl = `/shop/promo/${slug}`
+ const prefixUrl = `/shop/promo/${slug}`;
const [queryFinal, setQueryFinal] = useState({});
const [limit, setLimit] = useState(30);
const [q, setQ] = useState('*');
@@ -42,38 +44,55 @@ export default function PromoDetail() {
: []
: []
);
-
+
const [categoryValues, setCategory] = useState(
router.query?.category?.split(',') || router.query?.category?.split(',')
);
-
+
const [priceFrom, setPriceFrom] = useState(router.query?.priceFrom || null);
const [priceTo, setPriceTo] = useState(router.query?.priceTo || null);
-
useEffect(() => {
const newQuery = {
fq: `type_value_s:${slug}`,
- page : router.query.page? router.query.page : 1,
- brand : router.query.brand? router.query.brand : '',
- category : router.query.category? router.query.category : '',
- priceFrom : router.query.priceFrom? router.query.priceFrom : '',
- priceTo : router.query.priceTo? router.query.priceTo : '',
- limit : router.query.limit? router.query.limit : '',
- orderBy : router.query.orderBy? router.query.orderBy : ''
+ page: router.query.page ? router.query.page : 1,
+ brand: router.query.brand ? router.query.brand : '',
+ category: router.query.category ? router.query.category : '',
+ priceFrom: router.query.priceFrom ? router.query.priceFrom : '',
+ priceTo: router.query.priceTo ? router.query.priceTo : '',
+ limit: router.query.limit ? router.query.limit : '',
+ orderBy: router.query.orderBy ? router.query.orderBy : '',
};
setFinalQuery(newQuery);
-}, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]);
+ }, [
+ router.query,
+ prefixUrl,
+ slug,
+ brand,
+ category,
+ priceFrom,
+ priceTo,
+ currentPage,
+ ]);
useEffect(() => {
- setQueryFinal({ ...finalQuery, q, limit, orderBy });
- }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage, finalQuery]);
+ setQueryFinal({ ...finalQuery, q, limit, orderBy });
+ }, [
+ router.query,
+ prefixUrl,
+ slug,
+ brand,
+ category,
+ priceFrom,
+ priceTo,
+ currentPage,
+ finalQuery,
+ ]);
const { productSearch } = useProductSearch({
query: queryFinal,
operation: 'OR',
});
-
const pageCount = Math.ceil(productSearch.data?.response.numFound / limit);
const productStart = productSearch.data?.responseHeader.params.start;
const productRows = limit;
@@ -86,7 +105,8 @@ export default function PromoDetail() {
const brands = [];
for (
let i = 0;
- i < productSearch.data?.facet_counts?.facet_fields?.manufacture_name_s.length;
+ i <
+ productSearch.data?.facet_counts?.facet_fields?.manufacture_name_s.length;
i += 2
) {
const brand =
@@ -104,7 +124,8 @@ export default function PromoDetail() {
i < productSearch.data?.facet_counts?.facet_fields?.category_name.length;
i += 2
) {
- const name = productSearch.data?.facet_counts?.facet_fields?.category_name[i];
+ const name =
+ productSearch.data?.facet_counts?.facet_fields?.category_name[i];
const qty =
productSearch.data?.facet_counts?.facet_fields?.category_name[i + 1];
if (qty > 0) {
@@ -114,8 +135,8 @@ export default function PromoDetail() {
function capitalizeFirstLetter(string) {
string = string.replace(/_/g, ' ');
- return string.replace(/(^\w|\s\w)/g, function(match) {
- return match.toUpperCase();
+ return string.replace(/(^\w|\s\w)/g, function (match) {
+ return match.toUpperCase();
});
}
@@ -144,8 +165,8 @@ export default function PromoDetail() {
break;
case 'price':
params.priceFrom = '';
- params.priceTo = '';
- break;
+ params.priceTo = '';
+ break;
case 'delete':
params = {
q: router.query.q,
@@ -165,37 +186,41 @@ export default function PromoDetail() {
params = toQuery(params);
router.push(`${slug}?${params}`);
};
-
const toQuery = (obj) => {
const str = Object.keys(obj)
- .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
- .join('&')
- return str
- }
-
- const whatPromo = capitalizeFirstLetter(slug)
- const queryWithoutSlug = _.omit(router.query, ['slug'])
-
+ .map(
+ (key) => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`
+ )
+ .join('&');
+ return str;
+ };
+
+ const whatPromo = capitalizeFirstLetter(slug);
+ const queryWithoutSlug = _.omit(router.query, ['slug']);
+
return (
<BasicLayout>
<Seo
- title={`Promo ${Array.isArray(slug) ? slug[0] : slug} Terkini`}
+ 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'
+ canonical={`${process.env.NEXT_PUBLIC_SELF_HOST}${
+ router.asPath.split('?')[0]
+ }`}
/>
<Promocrumb brandName={whatPromo} />
<MobileView>
<div className='p-4 pt-0'>
<h1 className='mb-2 font-semibold text-h-sm'>Promo {whatPromo}</h1>
-
- <FilterChoicesComponent
- brandValues={brandValues}
- categoryValues={categoryValues}
- priceFrom={priceFrom}
- priceTo={priceTo}
- handleDeleteFilter={handleDeleteFilter}
- />
- {products?.length >= 1 && (
+
+ <FilterChoicesComponent
+ brandValues={brandValues}
+ categoryValues={categoryValues}
+ priceFrom={priceFrom}
+ priceTo={priceTo}
+ handleDeleteFilter={handleDeleteFilter}
+ />
+ {products?.length >= 1 && (
<div className='flex items-center gap-x-2 mb-5 justify-between'>
<div>
<button
@@ -207,134 +232,141 @@ export default function PromoDetail() {
</div>
</div>
)}
- {productSearch.isLoading && <div className='container flex justify-center my-4'>
- <LogoSpinner width={48} height={48} />
- </div>}
+ {productSearch.isLoading && (
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ )}
{products && (
- <>
- <div className='grid grid-cols-1 gap-x-1 gap-y-1'>
- {products?.map((promotion) => (
- <div key={promotion.id} className="min-w-36 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='grid grid-cols-1 gap-x-1 gap-y-1'>
+ {products?.map((promotion) => (
+ <div
+ key={promotion.id}
+ className='min-w-36 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>
+ </>
+ )}
- <Pagination
- pageCount={pageCount}
- currentPage={parseInt(page)}
- url={`${prefixUrl}?${toQuery(_.omit(queryWithoutSlug, ['page']))}`}
- className='mt-6 mb-2'
- />
- <ProductFilter
- active={popup.active}
- close={popup.deactivate}
- brands={brands || []}
- categories={categories || []}
- prefixUrl={router.asPath.includes('?') ? `${router.asPath}` : `${router.asPath}?`}
- defaultBrand={null}
- />
+ <Pagination
+ pageCount={pageCount}
+ currentPage={parseInt(page)}
+ url={`${prefixUrl}?${toQuery(_.omit(queryWithoutSlug, ['page']))}`}
+ className='mt-6 mb-2'
+ />
+ <ProductFilter
+ active={popup.active}
+ close={popup.deactivate}
+ brands={brands || []}
+ categories={categories || []}
+ prefixUrl={
+ router.asPath.includes('?')
+ ? `${router.asPath}`
+ : `${router.asPath}?`
+ }
+ defaultBrand={null}
+ />
</div>
-
</MobileView>
<DesktopView>
<div className='container mx-auto flex mb-3 flex-col'>
<div className='w-full pl-6'>
<h1 className='text-2xl mb-2 font-semibold'>Promo {whatPromo}</h1>
- <div className=' w-full h-full flex flex-row items-center '>
-
- <div className='detail-filter w-1/2 flex justify-start items-center mt-4'>
-
- <FilterChoicesComponent
- brandValues={brandValues}
- categoryValues={categoryValues}
- priceFrom={priceFrom}
- priceTo={priceTo}
- handleDeleteFilter={handleDeleteFilter}
- />
- </div>
- <div className='Filter w-1/2 flex flex-col'>
-
- <ProductFilterDesktop
- brands={brands || []}
- categories={categories || []}
- prefixUrl={'/shop/promo'}
- // defaultBrand={null}
- />
- </div>
- </div>
- {productSearch.isLoading ? (
- <div className='container flex justify-center my-4'>
- <LogoSpinner width={48} height={48} />
- </div>
- ) : products && products.length >= 1 ? (
- <>
+ <div className=' w-full h-full flex flex-row items-center '>
+ <div className='detail-filter w-1/2 flex justify-start items-center mt-4'>
+ <FilterChoicesComponent
+ brandValues={brandValues}
+ categoryValues={categoryValues}
+ priceFrom={priceFrom}
+ priceTo={priceTo}
+ handleDeleteFilter={handleDeleteFilter}
+ />
+ </div>
+ <div className='Filter w-1/2 flex flex-col'>
+ <ProductFilterDesktop
+ brands={brands || []}
+ categories={categories || []}
+ prefixUrl={'/shop/promo'}
+ // defaultBrand={null}
+ />
+ </div>
+ </div>
+ {productSearch.isLoading ? (
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ ) : products && products.length >= 1 ? (
+ <>
<div className='grid grid-cols-1 gap-x-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3'>
{products?.map((promotion) => (
- <div key={promotion.id} className="min-w-[400px] max-w-[400px] mb-[20px] sm:min-w-[350px] md:min-w-[380px] lg:min-w-[400px] xl:min-w-[400px] ">
- <ProductPromoCard promotion={promotion}/>
+ <div
+ key={promotion.id}
+ className='min-w-[400px] max-w-[400px] mb-[20px] sm:min-w-[350px] md:min-w-[380px] lg:min-w-[400px] xl:min-w-[400px] '
+ >
+ <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={pageCount}
- currentPage={parseInt(page)}
- url={`${prefixUrl}?${toQuery(_.omit(queryWithoutSlug, ['page']))}`}
- className='mt-6 mb-2'
+ ) : (
+ <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={pageCount}
+ currentPage={parseInt(page)}
+ url={`${prefixUrl}?${toQuery(
+ _.omit(queryWithoutSlug, ['page'])
+ )}`}
+ className='mt-6 mb-2'
+ />
+ </div>
</div>
</div>
</DesktopView>
</BasicLayout>
- )
- }
-
+ );
+}
+
const FilterChoicesComponent = ({
brandValues,
categoryValues,
priceFrom,
priceTo,
handleDeleteFilter,
- }) => (
+}) => (
<div className='flex items-center mb-4'>
<HStack spacing={2} className='flex-wrap'>
{brandValues?.map((value, index) => (
@@ -344,7 +376,7 @@ const FilterChoicesComponent = ({
borderRadius='lg'
variant='outline'
colorScheme='gray'
- >
+ >
<TagLabel>{value}</TagLabel>
<TagCloseButton onClick={() => handleDeleteFilter('brands', value)} />
</Tag>
@@ -357,11 +389,11 @@ const FilterChoicesComponent = ({
borderRadius='lg'
variant='outline'
colorScheme='gray'
- >
+ >
<TagLabel>{value}</TagLabel>
<TagCloseButton
onClick={() => handleDeleteFilter('category', value)}
- />
+ />
</Tag>
))}
{priceFrom && priceTo && (
@@ -371,7 +403,7 @@ const FilterChoicesComponent = ({
</TagLabel>
<TagCloseButton
onClick={() => handleDeleteFilter('price', priceFrom)}
- />
+ />
</Tag>
)}
{brandValues?.length > 0 ||
@@ -382,13 +414,13 @@ const FilterChoicesComponent = ({
<button
className='btn-transparent py-2 px-5 h-[40px] text-red-700'
onClick={() => handleDeleteFilter('delete')}
- >
+ >
Hapus Semua
</button>
</span>
) : (
''
- )}
+ )}
</HStack>
</div>
);