diff options
| author | FIN-IT_AndriFP <it@fixcomart.co.id> | 2025-09-26 11:29:27 +0700 |
|---|---|---|
| committer | FIN-IT_AndriFP <it@fixcomart.co.id> | 2025-09-26 11:29:27 +0700 |
| commit | ecd8bbcbee558893126d1f99792b9371d5b5680a (patch) | |
| tree | 0c5dcf5f03f9378e1dbbd7da231a065dc3fdc767 | |
| parent | cbd9208242dd3b285c7ce349674417ba6865683d (diff) | |
| parent | 3aaadd0d946c303101b1fb2ef7657f48863cd548 (diff) | |
Merge branch 'new-release' of https://bitbucket.org/altafixco/next-indoteknik into new-release
| -rw-r--r-- | src-migrate/modules/cart/components/CartSummaryMobile.tsx | 36 | ||||
| -rw-r--r-- | src-migrate/pages/shop/cart/cart.module.css | 14 | ||||
| -rw-r--r-- | src-migrate/pages/shop/cart/index.tsx | 15 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSearch.jsx | 78 |
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)} dari @@ -448,8 +474,7 @@ const ProductSearch = ({ 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)} dari @@ -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' |
