From 9836f109c38d7f02c587329795e80e15ff33aafa Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 10 Oct 2023 17:09:23 +0700 Subject: add qty di nenu brang , filter ready stock, filter haga fix di page search --- .../product/components/ProductFilterDesktop.jsx | 77 ++++++++++++++++++++-- src/lib/product/components/ProductSearch.jsx | 19 +++++- src/pages/api/shop/search.js | 6 +- 3 files changed, 92 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index b64349c7..08766e07 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -26,6 +26,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu const [categoryValues, setCategory] = useState(query?.category?.split(',') || []) const [priceFrom, setPriceFrom] = useState(query?.priceFrom) const [priceTo, setPriceTo] = useState(query?.priceTo) + const [stock, setStock] = useState(query?.stock) const handleCategoriesChange = (event) => { const value = event.target.value @@ -46,6 +47,38 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu } } + const handleReadyStockChange = (event) => { + const value = event.target.value + const isChecked = event.target.checked + if (isChecked) { + setStock(value) + } else { + setStock(null) + } + } + + const handlePriceFromChange = async (type) => { + let priceFrom = null + let priceTo = null + switch (type) { + case(1): + priceFrom = 100000 + priceFrom = 200000 + break; + case(2): + priceFrom = 100000 + priceFrom = 200000 + break; + case(1): + priceFrom = 100000 + priceFrom = 200000 + break; + } + await setPriceFrom(priceFrom) + await setPriceTo(priceTo) + handleSubmit() + } + const handleSubmit = () => { let params = { q: router.query.q, @@ -53,7 +86,8 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu brand: brandValues.join(','), category: categoryValues.join(','), priceFrom, - priceTo + priceTo, + stock : stock } params = _.pickBy(params, _.identity) params = toQuery(params) @@ -74,14 +108,19 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu {brands.map((brand, index) => ( -
+
- {brand} +
+ {brand.brand} +
+ {brand.qty > 99 ? '99+' : brand.qty} +
+
))} @@ -143,9 +182,37 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu onChange={(e) => setPriceTo(e.target.value)} /> +
+ + +
+
+ + +
+ + + + + Ketersedian Stok + + + + + + + Ketersedian Stock + + + - -
-
- - +
+ {priceRange.map((price, i) => ( + + ))}
-- cgit v1.2.3 From f1d9a308f61e67f4c896608e73ac8413f61fa8af Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 11 Oct 2023 10:22:11 +0700 Subject: Add breadcrumb on detail product, search, brand, category page --- src/lib/brand/components/Brand.jsx | 4 +- src/lib/brand/components/Breadcrumb.jsx | 40 ++++++++++++ src/lib/category/components/Breadcrumb.jsx | 56 +++++++++++++++++ src/lib/category/components/Category.jsx | 2 +- src/lib/product/components/Product/Breadcrumb.jsx | 69 +++++++++++++++++++++ src/lib/product/components/Product/Product.jsx | 38 +++++------- .../product/components/Product/ProductDesktop.jsx | 71 +++++++++++----------- .../product/components/Product/ProductMobile.jsx | 2 + src/lib/product/components/ProductSearch.jsx | 4 +- .../promotinProgram/components/PromotionType.jsx | 2 +- src/pages/shop/brands/[slug].jsx | 3 + src/pages/shop/cart.jsx | 15 +++++ src/pages/shop/category/[slug].jsx | 4 ++ src/pages/shop/search.jsx | 20 ++++++ 14 files changed, 267 insertions(+), 63 deletions(-) create mode 100644 src/lib/brand/components/Breadcrumb.jsx create mode 100644 src/lib/category/components/Breadcrumb.jsx create mode 100644 src/lib/product/components/Product/Breadcrumb.jsx (limited to 'src') diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx index 3c411969..3985b888 100644 --- a/src/lib/brand/components/Brand.jsx +++ b/src/lib/brand/components/Brand.jsx @@ -84,7 +84,7 @@ const Brand = ({ id }) => { -
+
{brand.isLoading && } {brand.data?.banners?.length == 0 && ( @@ -117,6 +117,7 @@ const Brand = ({ id }) => { ))} +
Produk dari brand:
{brand?.data?.logo && ( @@ -137,7 +138,6 @@ const Brand = ({ id }) => { )}
-
diff --git a/src/lib/brand/components/Breadcrumb.jsx b/src/lib/brand/components/Breadcrumb.jsx new file mode 100644 index 00000000..0fec2dad --- /dev/null +++ b/src/lib/brand/components/Breadcrumb.jsx @@ -0,0 +1,40 @@ +import { Breadcrumb as ChakraBreadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' + +/** + * Renders a breadcrumb component with links to navigate through different pages. + * + * @param {Object} props - The props object containing the brand name. + * @param {string} props.brandName - The name of the brand to display in the breadcrumb. + * @return {JSX.Element} The rendered breadcrumb component. + */ +const Breadcrumb = ({ brandName }) => { + return ( +
+ + + + Home + + + + + + Brands + + + + + {brandName} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/lib/category/components/Breadcrumb.jsx b/src/lib/category/components/Breadcrumb.jsx new file mode 100644 index 00000000..127904ee --- /dev/null +++ b/src/lib/category/components/Breadcrumb.jsx @@ -0,0 +1,56 @@ +import odooApi from '@/core/api/odooApi' +import { createSlug } from '@/core/utils/slug' +import { + Breadcrumb as ChakraBreadcrumb, + BreadcrumbItem, + BreadcrumbLink, + Skeleton +} from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' +import { useQuery } from 'react-query' + +/** + * Render a breadcrumb component. + * + * @param {object} categoryId - The ID of the category. + * @return {JSX.Element} The breadcrumb component. + */ +const Breadcrumb = ({ categoryId }) => { + const breadcrumbs = useQuery( + `category-breadcrumbs/${categoryId}`, + async () => await odooApi('GET', `/api/v1/category/${categoryId}/category-breadcrumb`) + ) + + return ( +
+ + + + + Home + + + + {breadcrumbs.data?.map((category, index) => ( + + {index === breadcrumbs.data.length - 1 ? ( + {category.name} + ) : ( + + {category.name} + + )} + + ))} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx index af696d42..e6ea5acf 100644 --- a/src/lib/category/components/Category.jsx +++ b/src/lib/category/components/Category.jsx @@ -30,7 +30,7 @@ const Category = () => { return (
- {categories.map((category) => ( + {categories?.map((category) => (
{ + const categories = useQuery( + `detail/categories/${productId}`, + async () => await odooApi('GET', `/api/v1/product/${productId}/category-breadcrumb`), + { + enabled: !!productId + } + ) + + return ( + + + + + Home + + + + {categories.data?.map((category) => ( + + + {category.name} + + + ))} + + + {productName} + + + + ) +} + +export default Breadcrumb diff --git a/src/lib/product/components/Product/Product.jsx b/src/lib/product/components/Product/Product.jsx index 54490c26..6e983c2e 100644 --- a/src/lib/product/components/Product/Product.jsx +++ b/src/lib/product/components/Product/Product.jsx @@ -36,29 +36,21 @@ const Product = ({ product, isVariant = false }) => { } }, [product, isVariant]) - if (isVariant == true) { - return ( - <> - - - - ) - } else { - return ( - <> - - - - ) - } + return isVariant == true ? ( + <> + + + + ) : ( + <> + + + + ) } export default Product diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 47e98c1a..ceb0cad7 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -24,6 +24,7 @@ import ColumnsSLA from './ColumnsSLA' import { useProductCartContext } from '@/contexts/ProductCartContext' import { Box, Skeleton, Tooltip } from '@chakra-ui/react' import { Info } from 'lucide-react' +import Breadcrumb from './Breadcrumb' const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const router = useRouter() @@ -199,47 +200,49 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { return (
+
- {product?.flashSale?.remainingTime > 0 && lowestPrice?.price.discountPercentage > 0 && ( -
-
- -
-
-
-
- - {Math.floor(product.lowestPrice.discountPercentage)}% - -
-
- - - {product?.flashSale?.tag != 'false' || product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - -
-
- + {product?.flashSale?.remainingTime > 0 && + lowestPrice?.price.discountPercentage > 0 && ( +
+
+ +
+
+
+
+ + {Math.floor(product.lowestPrice.discountPercentage)}% + +
+
+ + + {product?.flashSale?.tag != 'false' || product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + +
+
+ +
-
- )} + )} {product.name} { const router = useRouter() @@ -160,6 +161,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return ( +
{product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && (
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index df9aa91b..f6987051 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -117,7 +117,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { <> {productSearch.isLoading && } -
+

Produk

@@ -178,7 +178,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { -
+
{ const programs = await getPromotionProgram({ id }) - if (programs.length > 0) { + if (programs?.length > 0) { setPromotionList(programs) setActiveTitle(programs?.[0].type.value) } diff --git a/src/pages/shop/brands/[slug].jsx b/src/pages/shop/brands/[slug].jsx index 88f19bc0..d75475b7 100644 --- a/src/pages/shop/brands/[slug].jsx +++ b/src/pages/shop/brands/[slug].jsx @@ -3,6 +3,7 @@ import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' import { useRouter } from 'next/router' import _ from 'lodash' import Seo from '@/core/components/Seo' +import Breadcrumb from '@/lib/brand/components/Breadcrumb' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -26,6 +27,8 @@ export default function BrandDetail() { ]} /> + + {!_.isEmpty(router.query) && ( import('@/core/components/layouts/AppLayout')) const CartComponent = dynamic(() => import('@/lib/cart/components/Cart')) @@ -22,6 +24,19 @@ export default function Cart() { +
+ + + + Home + + + + + Keranjang + + +
diff --git a/src/pages/shop/category/[slug].jsx b/src/pages/shop/category/[slug].jsx index dbc17c06..e3650235 100644 --- a/src/pages/shop/category/[slug].jsx +++ b/src/pages/shop/category/[slug].jsx @@ -3,6 +3,7 @@ import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' import { useRouter } from 'next/router' import _ from 'lodash' import Seo from '@/core/components/Seo' +import Breadcrumb from '@/lib/category/components/Breadcrumb' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -16,6 +17,7 @@ export default function CategoryDetail() { const query = { fq: `manufacture_id_i:${categoryId}` } + return ( + + {!_.isEmpty(router.query) && ( )} diff --git a/src/pages/shop/search.jsx b/src/pages/shop/search.jsx index 907465b7..db3b449a 100644 --- a/src/pages/shop/search.jsx +++ b/src/pages/shop/search.jsx @@ -2,6 +2,8 @@ import dynamic from 'next/dynamic' import { useRouter } from 'next/router' import _ from 'lodash-contrib' import Seo from '@/core/components/Seo' +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) @@ -13,6 +15,24 @@ export default function Search() { +
+ {router.query?.q && ( + + + + Home + + + + + + Cari: {router.query.q || ''} + + + + )} +
+ {!_.isEmpty(router.query) && }
) -- cgit v1.2.3 From f4fb8d1f93024cfe907a5783215cf9c939dd59bc Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 11 Oct 2023 11:02:04 +0700 Subject: filter by limit rows --- src/lib/product/components/ProductFilter.jsx | 4 +-- src/lib/product/components/ProductSearch.jsx | 40 +++++++++++++++++++++++----- src/pages/api/shop/search.js | 2 +- 3 files changed, 37 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 34357526..7dadc39e 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -48,8 +48,8 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr > {brands.map((brand, index) => ( - ))} diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 3c3dbfd2..c79e355e 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -20,17 +20,20 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const router = useRouter() const { page = 1 } = query const [q, setQ] = useState(query?.q || '*') + const [limit, setLimit] = useState(query?.limit || 30) if (defaultBrand) query.brand = defaultBrand.toLowerCase() - const { productSearch } = useProductSearch({ query: { ...query, q } }) + const { productSearch } = useProductSearch({ query: { ...query, q, limit } }) const [products, setProducts] = useState(null) const [spellings, setSpellings] = useState(null) const popup = useActive() + const numRows = [30, 50, 80, 100] + console.log('ini product search', productSearch.data) const pageCount = Math.ceil( - productSearch.data?.response.numFound / productSearch.data?.responseHeader.params.rows + productSearch.data?.response.numFound / limit ) const productStart = productSearch.data?.responseHeader.params.start - const productRows = productSearch.data?.responseHeader.params.rows + const productRows = limit const productFound = productSearch.data?.response.numFound useEffect(() => { @@ -101,7 +104,17 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const handleOrderBy = (e) => { let params = { ...router.query, - orderBy: e.target.value + orderBy: e.target.value, + } + params = _.pickBy(params, _.identity) + params = toQuery(params) + router.push(`${prefixUrl}?${params}`) + } + + const handleLimit = (e) => { + let params = { + ...router.query, + limit: e.target.value, } params = _.pickBy(params, _.identity) params = toQuery(params) @@ -210,9 +223,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { {pageCount > 1 ? ( <> {productStart + 1}- - {productStart + productRows > productFound + {parseInt(productStart) + parseInt(productRows) > productFound ? productFound - : productStart + productRows} + : parseInt(productStart) + parseInt(productRows)}  dari  ) : ( @@ -247,6 +260,21 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { ))}
+
+ +
{productSearch.isLoading && } diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 0c79831b..874431e0 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -13,7 +13,7 @@ export default async function handler(req, res) { orderBy = '', operation = 'AND', fq = '', - limit = 30, + limit = '', stock = '' } = req.query -- cgit v1.2.3 From cff358b2a7bb310e2b65cba5d843e9ffdda0f699 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 11 Oct 2023 14:07:58 +0700 Subject: Fix description and brand banner skeleton --- src/lib/brand/components/Brand.jsx | 121 ++++++++++++--------- .../product/components/Product/ProductDesktop.jsx | 2 +- src/pages/shop/product/[slug].jsx | 7 +- 3 files changed, 69 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx index 3985b888..4afbcb3e 100644 --- a/src/lib/brand/components/Brand.jsx +++ b/src/lib/brand/components/Brand.jsx @@ -6,10 +6,10 @@ import { Pagination, Autoplay } from 'swiper' import 'swiper/css' import 'swiper/css/pagination' import 'swiper/css/autoplay' -import Divider from '@/core/components/elements/Divider/Divider' -import ImageSkeleton from '@/core/components/elements/Skeleton/ImageSkeleton' import MobileView from '@/core/components/views/MobileView' import DesktopView from '@/core/components/views/DesktopView' +import { Skeleton } from '@chakra-ui/react' +import classNames from 'classnames' const swiperBanner = { pagination: { dynamicBullets: true }, @@ -28,65 +28,77 @@ const Brand = ({ id }) => { <>
- {brand.isLoading && } - {brand.data?.banners?.length == 0 && ( - Brand - Indoteknik - )} - {brand.data && ( - <> - - {brand.data?.banners?.map((banner, index) => ( - + + {brand.data?.banners?.length == 0 && ( + Brand - Indoteknik + )} + + {brand.data && ( + <> + + {brand.data?.banners?.map((banner, index) => ( + + {`Brand + + ))} + +
+
Produk dari brand:
+ {brand?.data?.logo && ( {`Brand - - ))} - -
-
Produk dari brand:
- {brand?.data?.logo && ( - {brand?.data?.name} - )} - {!brand?.data?.logo && ( -
- {brand?.data?.name} -
- )} -
- - )} + )} + {!brand?.data?.logo && ( +
+ {brand?.data?.name} +
+ )} +
+ + )} +
-
-
- {brand.isLoading && } + {brand.data?.banners?.length == 0 && ( { className='w-full h-auto' /> )} + {brand.data && ( <> {
)} -
+
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index ceb0cad7..855c9f75 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -393,7 +393,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { ))}
-
+
]+)>)/gi - const regexHtmlTagsExceptP = /<\/?(?!p\b)[^>]*>/g - product.description = product.description - .replace(regexHtmlTagsExceptP, ' ') - .replace(regexHtmlTags, ' ') - .trim() } else { product = null } @@ -45,6 +39,7 @@ export async function getServerSideProps(context) { } export default function ProductDetail({ product }) { + console.log(product); const router = useRouter() const { setProduct } = useProductContext() -- cgit v1.2.3 From de61c739202db29270d4ffd9215091f0219aba8c Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 11 Oct 2023 14:37:47 +0700 Subject: filter di web mobile --- src/lib/product/components/ProductFilter.jsx | 81 +++++++++++++++++++++- .../product/components/ProductFilterDesktop.jsx | 8 +-- src/lib/product/components/ProductSearch.jsx | 38 +++++++--- 3 files changed, 109 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 7dadc39e..20c66a1f 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -3,6 +3,7 @@ import { useRouter } from 'next/router' import { useState } from 'react' import _ from 'lodash' import { toQuery } from 'lodash-contrib' +import { Checkbox } from '@chakra-ui/react' const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, @@ -20,6 +21,45 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr const [priceFrom, setPriceFrom] = useState(query?.priceFrom) const [priceTo, setPriceTo] = useState(query?.priceTo) + const [stock, setStock] = useState(query?.stock) + + const [activeRange, setActiveRange] = useState(null) + + const priceRange = [ + { + priceFrom: 100000, + priceTo: 200000 + }, + { + priceFrom: 200000, + priceTo: 300000 + }, + { + priceFrom: 300000, + priceTo: 400000 + }, + { + priceFrom: 400000, + priceTo: 500000 + } + ] + + const handlePriceFromChange = async (priceFromr, priceTor, index) => { + await setPriceFrom(priceFromr) + await setPriceTo(priceTor) + setActiveRange(index) + } + + const handleReadyStockChange = (event) => { + const value = event.target.value + const isChecked = event.target.checked + if (isChecked) { + setStock(value) + } else { + setStock(null) + } + } + const handleSubmit = () => { let params = { q: router.query.q, @@ -27,13 +67,23 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr brand, category, priceFrom, - priceTo + priceTo, + stock: stock } params = _.pickBy(params, _.identity) params = toQuery(params) router.push(`${prefixUrl}?${params}`) } + const formatCurrency = (value) => { + if (value >= 1000) { + const thousands = Math.floor(value / 1000) // Menghitung ribuan + return `Rp${thousands}k` + } else { + return `Rp${value}` + } + } + return (
@@ -49,7 +99,7 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr {brands.map((brand, index) => ( ))} @@ -106,6 +156,33 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr onChange={(e) => setPriceTo(e.target.value)} />
+
+ {priceRange.map((price, i) => ( + + ))} +
+
+
+ +
+ + Ketersedian Stok + +
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index c79e355e..ef4580d6 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -28,10 +28,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const popup = useActive() const numRows = [30, 50, 80, 100] - console.log('ini product search', productSearch.data) - const pageCount = Math.ceil( - productSearch.data?.response.numFound / limit - ) + const pageCount = Math.ceil(productSearch.data?.response.numFound / limit) const productStart = productSearch.data?.responseHeader.params.start const productRows = limit const productFound = productSearch.data?.response.numFound @@ -104,7 +101,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const handleOrderBy = (e) => { let params = { ...router.query, - orderBy: e.target.value, + orderBy: e.target.value } params = _.pickBy(params, _.identity) params = toQuery(params) @@ -114,7 +111,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const handleLimit = (e) => { let params = { ...router.query, - limit: e.target.value, + limit: e.target.value } params = _.pickBy(params, _.identity) params = toQuery(params) @@ -153,9 +150,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { {pageCount > 1 ? ( <> {productStart + 1}- - {productStart + productRows > productFound + {parseInt(productStart) + parseInt(productRows) > productFound ? productFound - : productStart + productRows} + : parseInt(productStart) + parseInt(productRows)}  dari  ) : ( @@ -175,9 +172,28 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
{productFound > 0 && ( - +
+
+ +
+
+ +
+
)}
-- cgit v1.2.3 From e4bce35fe6ec891bb8841bbfad981e97f5bb2aa8 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Wed, 11 Oct 2023 15:08:29 +0700 Subject: filter page brand --- src/lib/product/components/ProductFilter.jsx | 39 +++++++------- .../product/components/ProductFilterDesktop.jsx | 60 ++++++++++++---------- 2 files changed, 53 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 20c66a1f..40bfc824 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -87,24 +87,27 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr return (
- {!defaultBrand && ( -
- - -
- )} + {!router.pathname.includes('brands') && + !defaultBrand && ( +
+ + +
+ ) + } +
setSelectedExpedisi(e.target.value)} - required - > - - - {checkWeigth != true && - listExpedisi.map((expedisi) => ( - - ))} - + + + )} + +
{checkoutValidation && ( *silahkan pilih expedisi )} @@ -1459,7 +1486,7 @@ const SectionListService = ({ listserviceExpedisi, setSelectedServiceType }) => <>
-
Service Type Expedisi :
+
Tipe Layanan Ekspedisi:
+ + + + )} + setQuery(e.target.value)} diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 874431e0..fd7a215a 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -13,7 +13,7 @@ export default async function handler(req, res) { orderBy = '', operation = 'AND', fq = '', - limit = '', + limit = 0, stock = '' } = req.query diff --git a/src/pages/shop/category/[slug].jsx b/src/pages/shop/category/[slug].jsx index e3650235..6d3985a8 100644 --- a/src/pages/shop/category/[slug].jsx +++ b/src/pages/shop/category/[slug].jsx @@ -14,8 +14,12 @@ export default function CategoryDetail() { const categoryName = getNameFromSlug(slug) const categoryId = getIdFromSlug(slug) + const q = router?.query.q || null const query = { - fq: `manufacture_id_i:${categoryId}` + fq: `category_id_i:${categoryId}` + } + if (q) { + query.q = q } return ( -- cgit v1.2.3 From 094c341e35376ee2c20e12031830c3020ffb251d Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Sat, 14 Oct 2023 09:13:50 +0700 Subject: delete brand and category 0, & add product found in category filter --- src/lib/product/components/ProductFilter.jsx | 44 +++++++++++----------- .../product/components/ProductFilterDesktop.jsx | 9 +++-- src/lib/product/components/ProductSearch.jsx | 17 +++++++-- 3 files changed, 41 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 40bfc824..38e2d2c3 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -87,27 +87,25 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr return (
- {!router.pathname.includes('brands') && - !defaultBrand && ( -
- - -
- ) - } - + {!router.pathname.includes('brands') && !defaultBrand && ( +
+ + +
+ )} +
diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index cdfd85e8..582dabea 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -156,12 +156,15 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu {categories.map((category, index) => (
- {category} +
+ {category.name} + ({category.qty}) +
))} diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 3c954548..fd75d587 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -75,7 +75,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { ) { const brand = productSearch.data?.facetCounts?.facetFields?.manufactureName[i] const qty = productSearch.data?.facetCounts?.facetFields?.manufactureName[i + 1] - brands.push({ brand, qty }) + if (qty > 0) { + brands.push({ brand, qty }) + } } /*const brandsList = productSearch.data?.facetCounts?.facetFields?.manufactureName?.filter( (value, index) => { @@ -87,13 +89,22 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { } )*/ - const categories = productSearch.data?.facetCounts?.facetFields?.categoryName?.filter( + const categories = [] + for (let i = 0; i < productSearch.data?.facetCounts?.facetFields?.categoryName.length; i += 2) { + const name = productSearch.data?.facetCounts?.facetFields?.categoryName[i] + const qty = productSearch.data?.facetCounts?.facetFields?.categoryName[i + 1] + if (qty > 0) { + categories.push({ name, qty }) + } + } + + /*const categories = productSearch.data?.facetCounts?.facetFields?.categoryName?.filter( (value, index) => { if (index % 2 === 0) { return true } } - ) + )*/ const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, -- cgit v1.2.3 From 43e59b8c7f8b742e5781a8a8b991afcf9aabb90e Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Sat, 14 Oct 2023 11:08:42 +0700 Subject: add information label if brand and categories in empty --- src/lib/product/components/ProductFilter.jsx | 36 ++++++++---- .../product/components/ProductFilterDesktop.jsx | 67 ++++++++++++---------- 2 files changed, 61 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 38e2d2c3..14eef0ba 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -96,12 +96,18 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr value={brand} onChange={(e) => setBrand(e.target.value)} > - - {brands.map((brand, index) => ( - - ))} + {brands.length > 0 ? ( + <> + + {brands.map((brand, index) => ( + + ))} + + ) : ( + + )}
)} @@ -114,12 +120,18 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr value={category} onChange={(e) => setCategory(e.target.value)} > - - {categories.map((category, index) => ( - - ))} + {categories.length > 0 ? ( + <> + + {categories.map((category, index) => ( + + ))} + + ) : ( + + )}
diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index 582dabea..e84d6526 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -111,7 +111,6 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu return ( <> - {!router.pathname.includes('brands') && ( @@ -123,21 +122,25 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu - {brands.map((brand, index) => ( -
- -
- {brand.brand} - ({brand.qty}) -
-
-
- ))} + {brands && brands.length > 0 ? ( + brands.map((brand, index) => ( +
+ +
+ {brand.brand} + ({brand.qty}) +
+
+
+ )) + ) : ( +
Brands tidak tersedia
+ )}
@@ -153,21 +156,25 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu - {categories.map((category, index) => ( -
- -
+ {categories && categories.length > 0 ? ( + categories.map((category, index) => ( +
+ +
{category.name} ({category.qty})
-
-
- ))} + +
+ )) + ) : ( +
Kategori tidak tersedia
+ )} @@ -218,7 +225,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu - + {/* Ketersedian Stok @@ -236,7 +243,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu Ketersedian Stock
- + */}
+
-
-
-
-
-
Keranjang Belanja
- - Lihat Semua - -
-
-
- {!auth && ( -
-

- Silahkan{' '} - - Login - {' '} - Untuk Melihat Daftar Keranjang Belanja Anda -

-
- )} - {isLoading && - itemLoading.map((item) => ( -
-
-
- + + + {isHovered && ( + <> + + + + +
+
Keranjang Belanja
+ + Lihat Semua + +
+
+
+ {!auth && ( +
+

+ Silahkan{' '} + + Login + {' '} + Untuk Melihat Daftar Keranjang Belanja Anda +

-
-
-
-
+ )} + {isLoading && + itemLoading.map((item) => ( +
+
+
+ +
+
+
+
+
+
+
+
+ ))} + {auth && products.length === 0 && !isLoading && ( +
+

+ Tidak Ada Produk di Keranjang Belanja Anda +

-
-
- ))} - {auth && products.length === 0 && !isLoading && ( -
-

- Tidak Ada Produk di Keranjang Belanja Anda -

-
- )} - {auth && products.length > 0 && !isLoading && ( - <> -
    - {products && - products?.map((product, index) => ( - <> -
  • -
    -
    - - {product?.name} - -
    -
    - - {' '} -

    - {product.parent.name} -

    - - - {product?.hasFlashsale && ( -
    -
    - {product?.price?.discountPercentage}% + )} + {auth && products.length > 0 && !isLoading && ( + <> +
      + {products && + products?.map((product, index) => ( + <> +
    • +
      +
      + + {product?.name} +
      -
      - {currencyFormat(product?.price?.price)} +
      + + {' '} +

      + {product.parent.name} +

      + + + {product?.hasFlashsale && ( +
      +
      + {product?.price?.discountPercentage}% +
      +
      + {currencyFormat(product?.price?.price)} +
      +
      + )} +
      +
      + {product?.price?.priceDiscount > 0 ? ( + currencyFormat(product?.price?.priceDiscount) + ) : ( + + + Call For Price + + + )} +
      +
      - )} -
      -
      - {product?.price?.priceDiscount > 0 ? ( - currencyFormat(product?.price?.priceDiscount) - ) : ( - - - Call For Price - - - )} -
      -
      -
      -
    -
  • - - ))} -
-
- - )} -
- {auth && products.length > 0 && !isLoading && ( - <> -
- Subtotal Sebelum PPN : - {currencyFormat(subTotal)} -
-
- -
- - )} -
-
+ + + ))} + +
+ + )} +
+ {auth && products.length > 0 && !isLoading && ( + <> +
+ Subtotal Sebelum PPN : + {currencyFormat(subTotal)} +
+
+ +
+ + )} + + + + )} +
) } diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 35236e79..511fcdba 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -5,7 +5,6 @@ import useAuth from '@/core/hooks/useAuth' import { getItemAddress } from '@/core/utils/address' import addressesApi from '@/lib/address/api/addressesApi' import { - ArrowLongLeftIcon, BanknotesIcon, ChevronLeftIcon, ClockIcon, @@ -17,17 +16,14 @@ import { deleteItemCart, getCartApi } from '@/core/utils/cart' import currencyFormat from '@/core/utils/currencyFormat' import { toast } from 'react-hot-toast' import getFileBase64 from '@/core/utils/getFileBase64' -// import checkoutApi from '../api/checkoutApi' import { useRouter } from 'next/router' import VariantGroupCard from '@/lib/variant/components/VariantGroupCard' import axios from 'axios' import Image from '@/core/components/elements/Image/Image' -import imageNext from 'next/image' import MobileView from '@/core/components/views/MobileView' import DesktopView from '@/core/components/views/DesktopView' import ExpedisiList from '../api/ExpedisiList' import whatsappUrl from '@/core/utils/whatsappUrl' -import { createSlug } from '@/core/utils/slug' import BottomPopup from '@/core/components/elements/Popup/BottomPopup' import { useQuery } from 'react-query' import { gtagPurchase } from '@/core/utils/googleTag' diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 855c9f75..701750b2 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -90,38 +90,38 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { } const updateCart = (variantId, quantity, source) => { - let dataUpdate + let dataUpdate = { + productId: variantId, + quantity, + selected: true, + source: source === 'buy' ? 'buy' : null + } + if (product.variants.length > 1) { let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) - dataUpdate = { - productId: variantId, - quantity, - programLineId: product.variants[variantIndex].programActive, - selected: true, - source: source === 'buy' ? 'buy' : null - } + dataUpdate['programLineId'] = product.variants[variantIndex].programActive } else { - dataUpdate = { - productId: variantId, - quantity, - programLineId: promotionActiveId, - selected: true, - source: source === 'buy' ? 'buy' : null - } + dataUpdate['programLineId'] = promotionActiveId } + updateItemCart(dataUpdate) } - const handleAddToCart = (variantId) => { - if (!auth) { - router.push(`/login?next=/shop/product/${slug}`) - return - } + const redirectToLogin = (action, variantId, quantity) => { + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}` + router.push(`/login?next=${encodeURIComponent(nextURL)}`) + return true + } + const handleAddToCart = (variantId) => { const quantity = variantQuantityRefs.current[variantId].value if (!validQuantity(quantity)) return + if (!auth) { + return redirectToLogin('add_to_cart', variantId, quantity) + } + let source = 'cart' updateCart(variantId, quantity, source) setRefreshCart(true) @@ -141,6 +141,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const quantity = variantQuantityRefs.current[variant].value if (!validQuantity(quantity)) return + if (!auth) { + return redirectToLogin('buy', variant, quantity) + } + let source = 'buy' updateCart(variant, quantity, source) router.push(`/shop/checkout?source=buy`) diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index 402490f7..70ac1cbc 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -20,9 +20,12 @@ import odooApi from '@/core/api/odooApi' import ImageNext from 'next/image' import CountDown2 from '@/core/components/elements/CountDown/CountDown2' import Breadcrumb from './Breadcrumb' +import useAuth from '@/core/hooks/useAuth' const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() + const auth = useAuth() + const { slug } = router.query const [quantity, setQuantity] = useState('1') const [selectedVariant, setSelectedVariant] = useState(null) @@ -128,9 +131,20 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return isValid } + const redirectToLogin = (action) => { + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}` + router.push(`/login?next=${encodeURIComponent(nextURL)}`) + return true + } + const handleClickCart = () => { if (!validAction()) return gtagAddToCart(activeVariant, quantity) + + if (!auth) { + return redirectToLogin('add_to_cart') + } + updateItemCart({ productId: activeVariant.id, quantity, @@ -143,6 +157,10 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const handleClickBuy = () => { if (!validAction()) return + if (!auth) { + return redirectToLogin('buy') + } + updateItemCart({ productId: activeVariant.id, quantity, diff --git a/src/pages/shop/product/[slug].jsx b/src/pages/shop/product/[slug].jsx index 4c17ab37..d8366d3c 100644 --- a/src/pages/shop/product/[slug].jsx +++ b/src/pages/shop/product/[slug].jsx @@ -9,6 +9,7 @@ import cookie from 'cookie' import axios from 'axios' import { useProductContext } from '@/contexts/ProductContext' import { useEffect } from 'react' +import { updateItemCart } from '@/core/utils/cart' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) const Product = dynamic(() => import('@/lib/product/components/Product/Product')) @@ -22,7 +23,10 @@ export async function getServerSideProps(context) { const authToken = auth?.token || '' let response = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/product-detail?id=` + getIdFromSlug(slug) +'&auth=' + tier + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/product-detail?id=` + + getIdFromSlug(slug) + + '&auth=' + + tier ) let product = response.data // let productSolr = await productApi({ id: getIdFromSlug(slug), headers: { Token: authToken } }) @@ -39,7 +43,6 @@ export async function getServerSideProps(context) { } export default function ProductDetail({ product }) { - console.log(product); const router = useRouter() const { setProduct } = useProductContext() @@ -49,6 +52,27 @@ export default function ProductDetail({ product }) { } }, [product, setProduct]) + useEffect(() => { + const { action, variantId, qty } = router.query + const addToCart = async () => { + const data = { + productId: variantId, + quantity: qty, + selected: true, + programLineId: null, + source: action + } + console.log('data dr test', data) + await updateItemCart(data) + const redirectURL = action === 'buy' ? '/shop/checkout?source=buy' : '/shop/cart' + router.push(redirectURL) + } + + if (action && variantId && qty) { + addToCart() + } + }, [router]) + if (!product) return return ( -- cgit v1.2.3 From ca445ab4e089b98fb67b004a6cb4a8968f471ae4 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Mon, 16 Oct 2023 11:28:13 +0700 Subject: active price range --- .../product/components/ProductFilterDesktop.jsx | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index e84d6526..6118ed6b 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -29,6 +29,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu const [priceTo, setPriceTo] = useState(query?.priceTo) const [stock, setStock] = useState(query?.stock) const [activeRange, setActiveRange] = useState(null) + const [activeIndeces, setActiveIndeces] = useState([]) const priceRange = [ { @@ -49,6 +50,10 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu } ] + const indexRange = priceRange.findIndex((range) => { + return range.priceFrom === parseInt(priceFrom) && range.priceTo == parseInt(priceTo) + }) + const handleCategoriesChange = (event) => { const value = event.target.value const isChecked = event.target.checked @@ -108,6 +113,26 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu } } + /*const handleIndexAccordion = async () => { + if (brandValues) { + await setActiveIndeces([...activeIndeces, 0]) + } + if (categoryValues) { + await setActiveIndeces([...activeIndeces, !router.pathname.includes('brands') ? 1 : 0]) + } + if (priceRange) { + await setActiveIndeces([...activeIndeces, !router.pathname.includes('brands') ? 2 : 1]) + } + if (stock) { + await setActiveIndeces([...activeIndeces, !router.pathname.includes('brands') ? 3 : 2]) + } + }*/ + + useEffect(() => { + setActiveRange(indexRange) + }, []) + + return ( <> -- cgit v1.2.3 From 6bd88bdb765c1ecc0518abeca77eca25bde2857b Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 17 Oct 2023 14:57:48 +0700 Subject: add lebel product terjual di product card dan product detail, bugfix queri solr untuk filter brand --- src/core/utils/formatValue.js | 10 ++++++++++ .../product/components/Product/ProductDesktop.jsx | 9 +++++++-- .../product/components/Product/ProductMobile.jsx | 11 ++++++++--- src/lib/product/components/ProductCard.jsx | 23 +++++++++++----------- src/lib/product/components/ProductSearch.jsx | 6 +++--- src/pages/api/shop/search.js | 6 +++--- src/utils/solrMapping.js | 6 ++++-- 7 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 src/core/utils/formatValue.js (limited to 'src') diff --git a/src/core/utils/formatValue.js b/src/core/utils/formatValue.js new file mode 100644 index 00000000..dc78df5b --- /dev/null +++ b/src/core/utils/formatValue.js @@ -0,0 +1,10 @@ +const sellingProductFormat = (value) => { + if (value > 1000) { + const formattedValue = (value / 1000).toFixed(1).replace('.', ',') + return `${formattedValue.replace(/\.0$/, '')}rb+` + } else { + return value.toString() + } +} + +export { sellingProductFormat } diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 701750b2..ab4943eb 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -25,6 +25,7 @@ import { useProductCartContext } from '@/contexts/ProductCartContext' import { Box, Skeleton, Tooltip } from '@chakra-ui/react' import { Info } from 'lucide-react' import Breadcrumb from './Breadcrumb' +import { sellingProductFormat } from '@/core/utils/formatValue' const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const router = useRouter() @@ -418,7 +419,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
-
+
{product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && (
Harga mulai dari:
)} @@ -447,7 +448,11 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { )}
)} */} - + {product?.qtySold > 0 && ( +
+ {sellingProductFormat(product?.qtySold) + ' Terjual'} +
+ )} {lowestPrice?.isFlashsale && lowestPrice?.price.discountPercentage > 0 ? ( <>
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index 70ac1cbc..ef2c0002 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -21,6 +21,7 @@ import ImageNext from 'next/image' import CountDown2 from '@/core/components/elements/CountDown/CountDown2' import Breadcrumb from './Breadcrumb' import useAuth from '@/core/hooks/useAuth' +import { sellingProductFormat } from '@/core/utils/formatValue' const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() @@ -62,7 +63,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { price: getLowestPrice(), stock: product.stockTotal, weight: product.weight, - hasProgram: false + hasProgram: false, + qtySold: product.qtySold }) const variantOptions = product.variants?.map((variant) => { @@ -105,7 +107,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { stock: variant.stock, weight: variant.weight, hasProgram: variant.hasProgram, - isFlashsale: variant.isFlashsale + isFlashsale: variant.isFlashsale, + qtySold: variant.qtySold } setActiveVariant(newActiveVariant) @@ -245,7 +248,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {

{activeVariant?.name}

- + {product?.qtySold > 0 && ( +
{sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}
+ )} {product.variants.length > 1 && activeVariant.price.priceDiscount > 0 && !selectedVariant && ( diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 3b96ac32..72a3260e 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -1,6 +1,7 @@ import Image from '@/core/components/elements/Image/Image' import Link from '@/core/components/elements/Link/Link' import currencyFormat from '@/core/utils/currencyFormat' +import { sellingProductFormat } from '@/core/utils/formatValue' import { createSlug } from '@/core/utils/slug' import whatsappUrl from '@/core/utils/whatsappUrl' import ImageNext from 'next/image' @@ -123,12 +124,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)} - {product?.stockTotal > 0 && ( -
-
Ready Stock
-
{product?.stockTotal > 5 ? '> 5' : '< 5'}
-
- )} +
+ {product?.stockTotal > 0 &&
Ready Stock
} + {/*
{product?.stockTotal > 5 ? '> 5' : '< 5'}
*/} + {product?.qtySold > 0 &&
{sellingProductFormat(product?.qtySold) + ' Terjual'}
} +
) @@ -229,12 +229,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)} - {product?.stockTotal > 0 && ( -
-
Ready Stock
-
{product?.stockTotal > 5 ? '> 5' : '< 5'}
-
- )} +
+ {product?.stockTotal > 0 &&
Ready Stock
} + {/*
{product?.stockTotal > 5 ? '> 5' : '< 5'}
*/} + {product?.qtySold > 0 &&
{sellingProductFormat(product?.qtySold) + ' Terjual'}
} +
) diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index fd75d587..dc9796f2 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -70,11 +70,11 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const brands = [] for ( let i = 0; - i < productSearch.data?.facetCounts?.facetFields?.manufactureName.length; + i < productSearch.data?.facetCounts?.facetFields?.manufactureNameS.length; i += 2 ) { - const brand = productSearch.data?.facetCounts?.facetFields?.manufactureName[i] - const qty = productSearch.data?.facetCounts?.facetFields?.manufactureName[i + 1] + const brand = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i] + const qty = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1] if (qty > 0) { brands.push({ brand, qty }) } diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index fd7a215a..31497c51 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -13,7 +13,7 @@ export default async function handler(req, res) { orderBy = '', operation = 'AND', fq = '', - limit = 0, + limit = 30, stock = '' } = req.query @@ -41,7 +41,7 @@ export default async function handler(req, res) { let offset = (page - 1) * limit let parameter = [ - 'facet.field=manufacture_name', + 'facet.field=manufacture_name_s', 'facet.field=category_name', 'facet=true', 'indent=true', @@ -49,7 +49,7 @@ export default async function handler(req, res) { `q.op=${operation}`, `q=${escapeSolrQuery(q)}`, 'qf=name_s', - `start=${offset}`, + `start=${parseInt(offset)}`, `rows=${limit}`, `sort=${paramOrderBy}`, `fq=-publish_b:false` diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index 61816cf8..41d24b53 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -32,7 +32,8 @@ export const productMappingSolr = (products, pricelist) => { remainingTime: flashsaleTime(product?.flashsale_end_date_s)?.remainingTime, name: product?.product?.flashsale_name_s, tag: product?.flashsale_tag_s || 'FLASH SALE' - } + }, + qtySold : product?.qty_sold_f || 0 } if (product.manufacture_id_i && product.manufacture_name_s) { @@ -85,7 +86,8 @@ export const variantsMappingSolr = (parent, products, pricelist) => { stockTotal: product.stock_total_f || 0, weight: product.weight_f || 0, manufacture: {}, - parent: {} + parent: {}, + qtySold : product?.qty_sold_f || 0 } if (product.manufacture_id_i && product.manufacture_name_s) { -- cgit v1.2.3 From f03be42400890aaa4b5a8480b9f1da9c2004a6fc Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 17 Oct 2023 15:03:14 +0700 Subject: Cr title line jadi max 3 --- src/lib/product/components/ProductCard.jsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 72a3260e..c60e4f87 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -83,9 +83,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { )} {product?.name} @@ -186,9 +184,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { )} {product?.name} -- cgit v1.2.3 From f20d4bdf0cf4acc65ae634eb3a58ecd976275c77 Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 17 Oct 2023 15:26:51 +0700 Subject: handle arrow back browser di page checkout --- src/lib/checkout/components/Checkout.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 511fcdba..c78757a0 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -168,6 +168,16 @@ const Checkout = () => { setExpedisi(dataExpedisi) } loadExpedisi() + + const handlePopState = () => { + router.push('/shop/cart') + } + + window.onpopstate = handlePopState + + return () => { + window.onpopstate = null + } // voucher() }, []) -- cgit v1.2.3 From b29f07808f52d0b9b6ad9c76b182a6ccebb82c5e Mon Sep 17 00:00:00 2001 From: "HATEC\\SPVDEV001" Date: Tue, 17 Oct 2023 15:38:56 +0700 Subject: default filter by popular --- src/lib/product/components/ProductFilter.jsx | 2 +- src/lib/product/components/ProductSearch.jsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 14eef0ba..69738b33 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -15,7 +15,7 @@ const orderOptions = [ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBrand = null }) => { const router = useRouter() const { query } = router - const [order, setOrder] = useState(query?.orderBy) + const [order, setOrder] = useState(query?.orderBy || 'popular') const [brand, setBrand] = useState(query?.brand) const [category, setCategory] = useState(query?.category) const [priceFrom, setPriceFrom] = useState(query?.priceFrom) diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index dc9796f2..9d59b305 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -23,8 +23,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const { page = 1 } = query const [q, setQ] = useState(query?.q || '*') const [limit, setLimit] = useState(query?.limit || 30) + const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular') if (defaultBrand) query.brand = defaultBrand.toLowerCase() - const { productSearch } = useProductSearch({ query: { ...query, q, limit } }) + const { productSearch } = useProductSearch({ query: { ...query, q, limit, orderBy } }) const [products, setProducts] = useState(null) const [spellings, setSpellings] = useState(null) const [bannerPromotionHeader, setBannerPromotionHeader] = useState(null) @@ -303,10 +304,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {