summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFIN-IT_AndriFP <it@fixcomart.co.id>2025-09-26 11:29:27 +0700
committerFIN-IT_AndriFP <it@fixcomart.co.id>2025-09-26 11:29:27 +0700
commitecd8bbcbee558893126d1f99792b9371d5b5680a (patch)
tree0c5dcf5f03f9378e1dbbd7da231a065dc3fdc767
parentcbd9208242dd3b285c7ce349674417ba6865683d (diff)
parent3aaadd0d946c303101b1fb2ef7657f48863cd548 (diff)
Merge branch 'new-release' of https://bitbucket.org/altafixco/next-indoteknik into new-release
-rw-r--r--src-migrate/modules/cart/components/CartSummaryMobile.tsx36
-rw-r--r--src-migrate/pages/shop/cart/cart.module.css14
-rw-r--r--src-migrate/pages/shop/cart/index.tsx15
-rw-r--r--src/lib/product/components/ProductSearch.jsx78
4 files changed, 95 insertions, 48 deletions
diff --git a/src-migrate/modules/cart/components/CartSummaryMobile.tsx b/src-migrate/modules/cart/components/CartSummaryMobile.tsx
index 02258204..7a334fed 100644
--- a/src-migrate/modules/cart/components/CartSummaryMobile.tsx
+++ b/src-migrate/modules/cart/components/CartSummaryMobile.tsx
@@ -29,7 +29,7 @@ const CartSummaryMobile = ({
isLoaded = false,
}: Props) => {
const [showPopup, setShowPopup] = useState(false);
- const PPN : number = process.env.NEXT_PUBLIC_PPN ? parseFloat(process.env.NEXT_PUBLIC_PPN) : 0;
+ const PPN: number = process.env.NEXT_PUBLIC_PPN ? parseFloat(process.env.NEXT_PUBLIC_PPN) : 0;
return (
<>
<BottomPopup
@@ -88,22 +88,30 @@ const CartSummaryMobile = ({
</div>
</BottomPopup>
<div className='flex flex-col gap-y-3'>
- <Skeleton isLoaded={isLoaded} className={style.line}>
- <span className={clsxm(style.label, style.grandTotal)}>
+ <Skeleton
+ isLoaded={isLoaded}
+ className={clsxm(style.line, 'flex items-center justify-between !py-2')}
+ >
+ {/* Left: label */}
+ <span className={clsxm(style.label, style.grandTotal, 'leading-tight')}>
Grand Total
</span>
- <button
- onClick={() => setShowPopup(true)}
- className='bg-gray-300 w-6 h-6 items-center justify-center cursor-pointer hover:bg-red-400 md:hidden '
- >
- <ChevronDownIcon className='h-6 w-6 text-white' />
- </button>
- </Skeleton>
- <Skeleton isLoaded={isLoaded} className={style.line}>
- <span className={style.value}>
- Rp {formatCurrency(grandTotal || 0)}
- </span>
+
+ {/* Right: amount + chevron */}
+ <div className="flex items-center gap-2">
+ <span className={clsxm(style.value, 'whitespace-nowrap tabular-nums leading-tight')}>
+ Rp {formatCurrency(grandTotal || 0)}
+ </span>
+ <button
+ onClick={() => setShowPopup(true)}
+ aria-label="Expand ringkasan"
+ className="md:hidden flex w-5 h-5 items-center justify-center rounded bg-gray-300 hover:bg-gray-400"
+ >
+ <ChevronDownIcon className="h-4 w-4 text-white" />
+ </button>
+ </div>
</Skeleton>
+
</div>
</>
);
diff --git a/src-migrate/pages/shop/cart/cart.module.css b/src-migrate/pages/shop/cart/cart.module.css
index b756fb15..af5a2abc 100644
--- a/src-migrate/pages/shop/cart/cart.module.css
+++ b/src-migrate/pages/shop/cart/cart.module.css
@@ -3,7 +3,7 @@
}
.content {
- @apply flex flex-wrap ;
+ @apply flex flex-wrap;
}
.item-wrapper {
@@ -33,3 +33,15 @@
.summary-buttons-step-approval {
@apply grid grid-cols-1 gap-y-3 mt-6;
}
+
+@media (max-width: 768px) {
+ .item-wrapper {
+ /* adjust if your bar is taller/shorter */
+ padding-bottom: calc(env(safe-area-inset-bottom) + 9rem);
+ }
+
+ .summary-wrapper {
+ @apply fixed inset-x-0 bottom-0 z-50 md:sticky w-full;
+ }
+
+} \ No newline at end of file
diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx
index 795dfa72..031aa45b 100644
--- a/src-migrate/pages/shop/cart/index.tsx
+++ b/src-migrate/pages/shop/cart/index.tsx
@@ -301,9 +301,8 @@ const CartPage: React.FC = () => {
<>
{/* Sticky Header */}
<div
- className={`${
- isTop ? 'border-b-[0px]' : 'border-b-[1px]'
- } sticky md:top-[157px] flex-col bg-white py-4 border-gray-300 z-50 sm:w-full md:w-3/4`}
+ className={`${isTop ? 'border-b-[0px]' : 'border-b-[1px]'
+ } sticky md:top-[157px] flex-col bg-white py-4 border-gray-300 z-50 sm:w-full md:w-3/4`}
>
<div className='flex items-center justify-between mb-2'>
<h1 className={style.title}>Keranjang Belanja</h1>
@@ -392,13 +391,17 @@ const CartPage: React.FC = () => {
</div>
</div>
+ <div
+ className="md:hidden"
+ style={{ height: 'calc(var(--mobile-actions-h) + var(--mobile-total-h))' }}
+ />
+
{/* Cart Summary */}
<div
- className={`${style['summary-wrapper']} ${
- device.isMobile && (!cart || cart?.product_total === 0)
+ className={`${style['summary-wrapper']} ${device.isMobile && (!cart || cart?.product_total === 0)
? 'hidden'
: ''
- }`}
+ }`}
>
<div className={style.summary}>
{device.isMobile ? (
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index 2fb3138a..850d00cc 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -1,12 +1,12 @@
import NextImage from 'next/image';
import { useRouter } from 'next/router';
-import { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState, useRef } from 'react';
import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react';
import axios from 'axios';
import _ from 'lodash';
import { toQuery } from 'lodash-contrib';
-
+import { FunnelIcon, AdjustmentsHorizontalIcon } from '@heroicons/react/24/outline';
import odooApi from '@/core/api/odooApi';
import searchSpellApi from '@/core/api/searchSpellApi';
import Link from '@/core/components/elements/Link/Link';
@@ -50,7 +50,33 @@ const ProductSearch = ({
const categoryId = getIdFromSlug(prefixUrl);
const [data, setData] = useState([]);
const [dataLob, setDataLob] = useState([]);
+ const appliedDefaultBrandOrder = useRef(false);
+
if (defaultBrand) query.brand = defaultBrand.toLowerCase();
+ useEffect(() => {
+ if (!router.isReady) return;
+
+ const onBrandsPage = router.pathname.includes('brands');
+ const hasOrder = typeof router.query?.orderBy === 'string' && router.query.orderBy !== '';
+
+ if (onBrandsPage && !hasOrder && !appliedDefaultBrandOrder.current) {
+ let params = {
+ ...router.query,
+ orderBy: 'popular',
+ };
+ params = _.pickBy(params, _.identity);
+ const qs = toQuery(params);
+
+ // ganti URL tanpa nambah history & tanpa full reload
+ router.replace(`${prefixUrl}?${qs}`, undefined, { shallow: true });
+
+ // sinkronkan state lokal
+ setOrderBy('popular');
+
+ appliedDefaultBrandOrder.current = true;
+ }
+ }, [router.isReady, router.pathname, router.query?.orderBy, prefixUrl]);
+
const dataIdCategories = [];
useEffect(() => {
if (prefixUrl.includes('category')) {
@@ -84,7 +110,7 @@ const ProductSearch = ({
if (router.asPath.includes('penawaran')) {
query = {
...query,
- fq:`flashsale_id_i:${router.query.penawaran} AND flashsale_price_f:[1 TO *]`,
+ fq: `flashsale_id_i:${router.query.penawaran} AND flashsale_price_f:[1 TO *]`,
orderBy: 'flashsale-discount-desc',
};
setFinalQuery(query);
@@ -404,9 +430,7 @@ const ProductSearch = ({
<div className='p-4 pt-0'>
{isNotReadyStockPage && isBrand && isBrand.logo && (
<div className='mb-3'>
- <h1 className='mb-2 font-semibold text-h-sm'>
- Brand Pencarian {q}
- </h1>
+ <h1 className='mb-2 font-semibold text-h-sm'>Brand Pencarian {q}</h1>
<Link
href={createSlug('/shop/brands/', isBrand.name, isBrand.id)}
className='inline'
@@ -419,7 +443,9 @@ const ProductSearch = ({
</Link>
</div>
)}
+
<h1 className='mb-2 font-semibold text-h-sm'>Produk</h1>
+
<FilterChoicesComponent
brandValues={brandValues}
categoryValues={categoryValues}
@@ -428,6 +454,7 @@ const ProductSearch = ({
handleDeleteFilter={handleDeleteFilter}
/>
+ {/* info jumlah hasil */}
<div className='mb-2 leading-6 text-gray_r-11'>
{!spellings ? (
<>
@@ -435,8 +462,7 @@ const ProductSearch = ({
{pageCount > 1 ? (
<>
{productStart + 1}-
- {parseInt(productStart) + parseInt(productRows) >
- productFound
+ {parseInt(productStart) + parseInt(productRows) > productFound
? productFound
: parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
@@ -448,8 +474,7 @@ const ProductSearch = ({
&nbsp;produk{' '}
{query.q && (
<>
- untuk pencarian{' '}
- <span className='font-semibold'>{query.q}</span>
+ untuk pencarian <span className='font-semibold'>{query.q}</span>
</>
)}
</>
@@ -457,37 +482,37 @@ const ProductSearch = ({
SpellingComponent
)}
</div>
- <LobSectionCategory categories={dataLob} />
- <CategorySection categories={dataCategories} />
{productFound > 0 && (
- <div className='flex items-center gap-x-2 mb-5 justify-between'>
+ <div className='flex items-center gap-x-2 mt-2 mb-3 justify-end'>
<div>
<button
- className='btn-light py-2 px-5 h-[40px]'
+ aria-label='Filter'
+ title='Filter'
onClick={popup.activate}
+ className='btn-light w-fit flex items-center justify-center rounded-md'
>
- Filter
+ <AdjustmentsHorizontalIcon className='w-5 h-5' />
</button>
</div>
- <div className=''>
+ <div>
<select
name='limit'
- className='form-input w-24'
+ className='form-input w-20'
value={router.query?.limit || ''}
onChange={(e) => handleLimit(e)}
>
{numRows.map((option, index) => (
<option key={index} value={option}>
- {' '}
- {option}{' '}
+ {option}
</option>
))}
</select>
</div>
</div>
)}
-
+ {!!dataLob?.length && <LobSectionCategory categories={dataLob} />}
+ {!!dataCategories?.length && <CategorySection categories={dataCategories} />}
<div className='grid grid-cols-2 gap-3'>
{products &&
products.map((product) => (
@@ -499,7 +524,6 @@ const ProductSearch = ({
pageCount={pageCount}
currentPage={parseInt(page)}
url={`${prefixUrl}?${toQuery(_.omit(query, ['page', 'fq']))}`}
- // url={prefixUrl.includes('category') || prefixUrl.includes('lob')? `${prefixUrl}?${toQuery(_.omit(finalQuery, ['page']))}` : `${prefixUrl}?${toQuery(_.omit(query, ['page']))}`}
className='mt-6 mb-2'
/>
@@ -597,7 +621,7 @@ const ProductSearch = ({
<>
{productStart + 1}-
{parseInt(productStart) + parseInt(productRows) >
- productFound
+ productFound
? productFound
: parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
@@ -673,8 +697,8 @@ const ProductSearch = ({
href={
query?.q
? whatsappUrl('productSearch', {
- name: query.q,
- })
+ name: query.q,
+ })
: whatsappUrl()
}
className='text-danger-500'
@@ -759,9 +783,9 @@ const FilterChoicesComponent = ({
</Tag>
)}
{brandValues?.length > 0 ||
- categoryValues?.length > 0 ||
- priceFrom ||
- priceTo ? (
+ categoryValues?.length > 0 ||
+ priceFrom ||
+ priceTo ? (
<span>
<button
className='btn-transparent py-2 px-5 h-[40px] text-red-700'