From bc7c0d1891db37ad314bd5016e19917e0f1e63be Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 17 Jul 2024 15:38:45 +0700 Subject: update error code --- src/api/promoApi.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/api/promoApi.js b/src/api/promoApi.js index f262db8d..3f85db8e 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -13,11 +13,11 @@ export const fetchPromoItems = async (type) => { } }; -export const fetchPromoItemsSolr = async (type) => { +export const fetchPromoItemsSolr = async (type, start, rows) => { // let query = type ? `type_value_s:${type}` : '*:*'; let sort ='sort=if(exists(sequence_i),0,1) asc, sequence_i asc, if(exists(total_qty_sold_f), total_qty_sold_f, -1) desc'; - let start = 0 - let rows = 100 + // let start = 0 + // let rows = 100 // let start = 0 // let rows = 10 try { -- cgit v1.2.3 From a181665f20207db5617d794df8159483fef0c2a8 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 22 Jul 2024 11:16:47 +0700 Subject: no message --- src/lib/product/components/ProductCard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 818dbbcf..3b5fab28 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -18,7 +18,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { let voucherPastiHemat = 0; - if (product?.voucherPastiHemat.length > 0) { + if (product?.voucherPastiHemat?.length > 0) { const stringVoucher = product?.voucherPastiHemat[0]; const validJsonString = stringVoucher.replace(/'/g, '"'); voucherPastiHemat = JSON.parse(validJsonString); -- cgit v1.2.3 From aed8055fbef665984574bc98bb6223c1c54a821a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 09:42:57 +0700 Subject: marged develompent & category management --- src/lib/brand/components/BrandCard.jsx | 2 +- src/lib/category/components/Category.jsx | 79 +++++++++++++---- src/lib/home/api/categoryManagementApi.js | 8 ++ src/lib/home/components/CategoryDynamic.jsx | 65 ++++++++++++++ src/lib/home/components/CategoryDynamicMobile.jsx | 101 ++++++++++++++++++++++ src/lib/home/components/CategoryPilihan.jsx | 66 ++++++++++++++ src/lib/home/components/PreferredBrand.jsx | 42 ++++++--- src/lib/home/hooks/useCategoryManagement.js | 13 +++ src/lib/product/components/CategorySection.jsx | 84 ++++++++++++++++++ src/lib/product/components/ProductSearch.jsx | 18 ++++ src/pages/index.jsx | 35 +++++++- src/pages/shop/category/[slug].jsx | 9 +- src/styles/globals.css | 5 +- 13 files changed, 492 insertions(+), 35 deletions(-) create mode 100644 src/lib/home/api/categoryManagementApi.js create mode 100644 src/lib/home/components/CategoryDynamic.jsx create mode 100644 src/lib/home/components/CategoryDynamicMobile.jsx create mode 100644 src/lib/home/components/CategoryPilihan.jsx create mode 100644 src/lib/home/hooks/useCategoryManagement.js create mode 100644 src/lib/product/components/CategorySection.jsx (limited to 'src') diff --git a/src/lib/brand/components/BrandCard.jsx b/src/lib/brand/components/BrandCard.jsx index 731214ff..39b1aec1 100644 --- a/src/lib/brand/components/BrandCard.jsx +++ b/src/lib/brand/components/BrandCard.jsx @@ -8,7 +8,7 @@ const BrandCard = ({ brand }) => { return ( diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx index e6ea5acf..c147a3b3 100644 --- a/src/lib/category/components/Category.jsx +++ b/src/lib/category/components/Category.jsx @@ -2,10 +2,14 @@ import odooApi from '@/core/api/odooApi' import Link from '@/core/components/elements/Link/Link' import DesktopView from '@/core/components/views/DesktopView' import { createSlug } from '@/core/utils/slug' +import { ChevronRightIcon } from '@heroicons/react/24/outline' +import Image from 'next/image' import { useEffect, useState } from 'react' const Category = () => { const [categories, setCategories] = useState([]) + const [openCategories, setOpenCategory] = useState([]); + useEffect(() => { const loadCategories = async () => { @@ -31,7 +35,7 @@ const Category = () => {
{categories?.map((category) => ( -
+
{ {category.name}
-
+
{category.childs.map((child1Category) => ( -
+
{child1Category.name} -
- {child1Category.childs.map((child2Category) => ( - - {child2Category.name} - +
+ {child1Category.childs.map((child2Category, index) => ( + (index < 4) && ( + + {child2Category.name} + + ) ))} + {child1Category.childs.length > 5 && ( +
+ +

Lihat Semua

+ + +
+ )}
))}
+
+
+
+ {category.childs.map((brand, index) => ( + (index < 8 ) && ( +
+ + + +
+ ) + ))} +
+ {category.childs.length > 8 && ( +
+ +

Lihat Semua Brand

+ + +
+ )} +
+
+ +
+
))} diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js new file mode 100644 index 00000000..b70d60ce --- /dev/null +++ b/src/lib/home/api/categoryManagementApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const categoryManagementApi = async () => { + const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management') + return dataCategoryManagement +} + +export default categoryManagementApi diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx new file mode 100644 index 00000000..cac8a138 --- /dev/null +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -0,0 +1,65 @@ +import React, { useEffect, useState } from 'react'; +import useCategoryManagement from '../hooks/useCategoryManagement'; +import NextImage from 'next/image'; +import Link from "next/link" +import router from 'next/router'; +import { createSlug } from '@/core/utils/slug' + +const CategoryDynamic = () => { + const { categoryManagement } = useCategoryManagement() + + return ( +
+ {categoryManagement && categoryManagement.data?.map((category) => ( +
+
+
{category.name}
+

999 rb+ Produk tersedia

+ Lihat Semua +
+
+ {category.categories.map((index)=> ( +
+
+
+ +
+
{index.name}
+

999 rb+ Produk

+ Lihat Semua +
+
+
+ {index.childFrontendIdI.map((x)=> ( +
+ + +
+
{x.name}
+
+ +
+ ))} +
+
+
+ ))} +
+
+ ))} +
+ ); +} + +export default CategoryDynamic; diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx new file mode 100644 index 00000000..c1433a2d --- /dev/null +++ b/src/lib/home/components/CategoryDynamicMobile.jsx @@ -0,0 +1,101 @@ +import React, { useEffect, useState } from 'react'; +import useCategoryManagement from '../hooks/useCategoryManagement'; +import NextImage from 'next/image'; +import Link from "next/link"; +import { createSlug } from '@/core/utils/slug'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; + +const CategoryDynamicMobile = () => { + const { categoryManagement } = useCategoryManagement() + const [selectedCategory, setSelectedCategory] = useState({}); + + useEffect(() => { + const loadPromo = async () => { + try { + if (categoryManagement.data?.length > 0) { + const initialSelections = categoryManagement.data.reduce((acc, category) => { + if (category.categories.length > 0) { + acc[category.id] = category.categories[0].idLevel2; + } + return acc; + }, {}); + setSelectedCategory(initialSelections); + } + } catch (loadError) { + // console.error("Error loading promo items:", loadError); + } + }; + + loadPromo(); + }, [categoryManagement.data]); + + const handleCategoryLevel2Click = (categoryIdI, idLevel2) => { + setSelectedCategory(prev => ({ + ...prev, + [categoryIdI]: idLevel2 + })); + }; + + return ( +
+ {categoryManagement.data && categoryManagement.data.map((category) => ( +
+
+
{category.name}
+ Lihat Semua +
+ + {category.categories.map((index) => ( + +
handleCategoryLevel2Click(category.id, index?.idLevel2)} + className={`border flex justify-start items-center max-w-48 max-h-16 rounded ${selectedCategory[category.id] === index?.idLevel2 ? 'bg-red-50 border-red-500 text-red-500' : 'border-gray-200 text-gray-900'}`} + > +
+
+ +
+
{index.name}
+

999 rb+ Produk

+
+
+
+
+
+ ))} +
+
+
+ {category.categories.map((index) => ( + selectedCategory[category.id] === index?.idLevel2 && index.childFrontendIdI.map((x) => ( +
+ + +
+
{x.name}
+
+ +
+ )) + ))} +
+
+
+ ))} +
+ ); +}; + +export default CategoryDynamicMobile; diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx new file mode 100644 index 00000000..7b9f0094 --- /dev/null +++ b/src/lib/home/components/CategoryPilihan.jsx @@ -0,0 +1,66 @@ +import Image from 'next/image' +import useCategoryHome from '../hooks/useCategoryHome' +import Link from '@/core/components/elements/Link/Link' +import { createSlug } from '@/core/utils/slug' +import { useEffect, useState } from 'react'; +import { bannerApi } from '../../../api/bannerApi'; +const { useQuery } = require('react-query') +import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton'; + + +const CategoryPilihan = ({ id, categories }) => { + const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'index-a-1' })); + + return ( +
+
+
Kategori Pilihan
+

200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!

+
+
+ {heroBanner.data && + heroBanner.data?.length > 0 && ( +
+ {/* {heroBanner.data?.map((banner) => ( */} + + {heroBanner.data[0].name} + + {/* ))} */} +
+ + )} +
+
+ {categories.map((category) => ( +
+
+
+
+ {category?.name} +
+

{category?.name}

+
+
+
+ + Lihat semua + +
+
+ ))} +
+
+ ) +} + +export default CategoryPilihan diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx index 6b64a444..1aa9746b 100644 --- a/src/lib/home/components/PreferredBrand.jsx +++ b/src/lib/home/components/PreferredBrand.jsx @@ -1,5 +1,5 @@ -import { Swiper, SwiperSlide } from 'swiper/react' -import { useCallback, useEffect, useState } from 'react' +import { Swiper, SwiperProps, SwiperSlide } from 'swiper/react'; +import { Navigation, Pagination, Autoplay } from 'swiper'; import usePreferredBrand from '../hooks/usePreferredBrand' import PreferredBrandSkeleton from './Skeleton/PreferredBrandSkeleton' import BrandCard from '@/lib/brand/components/BrandCard' @@ -38,6 +38,22 @@ const PreferredBrand = () => { const { preferredBrands } = usePreferredBrand(query) const { isMobile, isDesktop } = useDevice() + const swiperBanner = { + modules:[Navigation, Pagination, Autoplay], + autoplay: { + delay: 4000, + disableOnInteraction: false + }, + loop: true, + className: 'h-[70px] md:h-[100px] w-full', + slidesPerView: isMobile ? 4 : 8, + spaceBetween: isMobile ? 12 : 0, + pagination: { + dynamicBullets: true, + dynamicMainBullets: isMobile ? 6 : 8, + clickable: true, + } + } return (
@@ -54,16 +70,18 @@ const PreferredBrand = () => { )}
- {manufactures.isLoading && } - {!manufactures.isLoading && ( - - {manufactures.map((manufacture) => ( - - - - ))} - - )} +
+ {preferredBrands.isLoading && } + {!preferredBrands.isLoading && ( + + {preferredBrands.data?.data.map((brand) => ( + + + + ))} + + )} +
) } diff --git a/src/lib/home/hooks/useCategoryManagement.js b/src/lib/home/hooks/useCategoryManagement.js new file mode 100644 index 00000000..c1dda585 --- /dev/null +++ b/src/lib/home/hooks/useCategoryManagement.js @@ -0,0 +1,13 @@ +import categoryManagementApi from '../api/categoryManagementApi' +import { useQuery } from 'react-query' + +const useCategoryManagement = () => { + const fetchCategoryManagement = async () => await categoryManagementApi() + const { isLoading, data } = useQuery('categoryManagementApi', fetchCategoryManagement) + + return { + categoryManagement: { data, isLoading } + } +} + +export default useCategoryManagement \ No newline at end of file diff --git a/src/lib/product/components/CategorySection.jsx b/src/lib/product/components/CategorySection.jsx new file mode 100644 index 00000000..749a56eb --- /dev/null +++ b/src/lib/product/components/CategorySection.jsx @@ -0,0 +1,84 @@ +import Image from "next/image" +import Link from 'next/link' +import { createSlug } from '@/core/utils/slug' +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import { useQuery } from 'react-query' +import { useRouter } from 'next/router' + +const CategorySection = ({ categories }) => { + const { isDesktop, isMobile } = useDevice(); + const router = useRouter() + + let teks = router.query.slug; + let hasil = teks?.match(/(\d+)$/)[0]; + + const breadcrumbs = useQuery( + `category-breadcrumbs/${hasil}`, + async () => await odooApi('GET', `/api/v1/category/${hasil}/category-breadcrumb`) + ) + + return ( +
+ {isDesktop && ( +
+ {categories.slice(0, 10).map((category) => ( + +
+
+
+ {category?.name} +

{category?.name}

+
+
+
+ + ))} +
+ )} + {isDesktop && categories.length > 10 && ( +
+ Lihat Semua + +
+ )} + + {isMobile && +
+ + {categories.slice(0, 10).map((category) => ( + + +
+
+
+ {category?.name} +

+ {category?.name} +

+
+
+
+ +
+ ))} +
+ {categories.length > 10 && ( +
+ Lihat Semua + +
+ )} +
+ } +
+ ) +} + +export default CategorySection diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index b1a5d409..34018ffe 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -26,6 +26,8 @@ import ProductSearchSkeleton from './Skeleton/ProductSearchSkeleton'; import SideBanner from '~/modules/side-banner'; import FooterBanner from '~/modules/footer-banner'; +import CategorySection from './CategorySection'; +import { getIdFromSlug } from '@/core/utils/slug' const ProductSearch = ({ query, @@ -68,6 +70,9 @@ const ProductSearch = ({ const productStart = productSearch.data?.responseHeader.params.start; const productRows = limit; const productFound = productSearch.data?.response.numFound; + const [dataCategories, setDataCategories] = useState([]) + + const categoryId = getIdFromSlug(prefixUrl) useEffect(() => { if (productFound == 0 && query.q && !spellings) { @@ -115,6 +120,16 @@ const ProductSearch = ({ checkIfBrand(); } }, [q]); + + useEffect(() => { + const loadCategories = async () => { + const getCategories = await odooApi('GET', `/api/v1/category/child?parent_id=${categoryId}`) + if(getCategories){ + setDataCategories(getCategories) + } + } + loadCategories() + }, []) const brands = []; for ( @@ -323,6 +338,7 @@ const ProductSearch = ({ SpellingComponent )}
+ {productFound > 0 && (
@@ -411,7 +427,9 @@ const ProductSearch = ({
+
+ {bannerPromotionHeader && bannerPromotionHeader?.image && (
const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId') ); + +const CategoryDynamic = dynamic(() => + import('@/lib/home/components/CategoryDynamic') +); + +const CategoryDynamicMobile = dynamic(() => + import('@/lib/home/components/CategoryDynamicMobile') +); + const CustomerReviews = dynamic(() => import('@/lib/review/components/CustomerReviews') ); const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList')); -export default function Home() { +export default function Home({categoryId}) { const bannerRef = useRef(null); const wrapperRef = useRef(null); @@ -70,6 +83,18 @@ export default function Home() { bannerRef.current?.querySelector(':first-child')?.clientHeight + 'px'; }; + const [dataCategories, setDataCategories] = useState([]) + + useEffect(() => { + const loadCategories = async () => { + const getCategories = await odooApi('GET', '/api/v1/category/child?partner_id='+{categoryId}) + if(getCategories){ + setDataCategories(getCategories) + } + } + loadCategories() + }, []) + return ( )} + + @@ -150,6 +177,10 @@ export default function Home() { + + + + diff --git a/src/pages/shop/category/[slug].jsx b/src/pages/shop/category/[slug].jsx index 1afe30bf..11840d47 100644 --- a/src/pages/shop/category/[slug].jsx +++ b/src/pages/shop/category/[slug].jsx @@ -5,6 +5,8 @@ import { useRouter } from 'next/router'; import Seo from '@/core/components/Seo'; import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug'; import Breadcrumb from '@/lib/category/components/Breadcrumb'; +import { useEffect, useState } from 'react'; +import odooApi from '@/core/api/odooApi'; const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout') @@ -12,10 +14,14 @@ const BasicLayout = dynamic(() => const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch') ); +const CategorySection = dynamic(() => + import('@/lib/product/components/CategorySection') +) export default function CategoryDetail() { const router = useRouter(); const { slug = '', page = 1 } = router.query; + const [dataCategories, setDataCategories] = useState([]) const categoryName = getNameFromSlug(slug); const categoryId = getIdFromSlug(slug); @@ -43,8 +49,9 @@ export default function CategoryDetail() { + {!_.isEmpty(router.query) && ( - + )} ); diff --git a/src/styles/globals.css b/src/styles/globals.css index f6561b00..505dcab4 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -583,12 +583,11 @@ button { @apply absolute left-[100%] top-12 - w-[40vw] bg-gray_r-1/90 backdrop-blur-md border border-gray_r-6 - p-6 + p-6 opacity-0 h-full transition-all @@ -604,6 +603,7 @@ button { transition-colors ease-linear duration-100 + w-fit font-semibold; } @@ -613,6 +613,7 @@ button { transition-colors ease-linear duration-100 + w-full font-normal; } -- cgit v1.2.3 From cf48c684d2f8da4dd70e2ed0f57623169bc5106f Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 10:01:58 +0700 Subject: update error code --- src/lib/home/components/PreferredBrand.jsx | 34 +----------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx index 1aa9746b..f822b9a0 100644 --- a/src/lib/home/components/PreferredBrand.jsx +++ b/src/lib/home/components/PreferredBrand.jsx @@ -5,37 +5,10 @@ import PreferredBrandSkeleton from './Skeleton/PreferredBrandSkeleton' import BrandCard from '@/lib/brand/components/BrandCard' import useDevice from '@/core/hooks/useDevice' import Link from '@/core/components/elements/Link/Link' -import axios from 'axios' const PreferredBrand = () => { let query = 'level_s' let params = 'prioritas' - const [isLoading, setIsLoading] = useState(true) - const [startWith, setStartWith] = useState(null) - const [manufactures, setManufactures] = useState([]) - - const loadBrand = useCallback(async () => { - setIsLoading(true) - const name = startWith ? `${startWith}*` : '' - const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=${name}`) - - setIsLoading(false) - setManufactures((manufactures) => [...result.data]) - }, [startWith]) - - const toggleStartWith = (alphabet) => { - setManufactures([]) - if (alphabet == startWith) { - setStartWith(null) - return - } - setStartWith(alphabet) - } - - useEffect(() => { - loadBrand() - }, [loadBrand]) - const { preferredBrands } = usePreferredBrand(query) const { isMobile, isDesktop } = useDevice() const swiperBanner = { @@ -64,11 +37,6 @@ const PreferredBrand = () => { Lihat Semua )} - {isMobile && ( - - Lihat Semua - - )}
{preferredBrands.isLoading && } @@ -86,4 +54,4 @@ const PreferredBrand = () => { ) } -export default PreferredBrand +export default PreferredBrand \ No newline at end of file -- cgit v1.2.3 From 1d770053ce0b75eab1d3755085d03c9d32fe3a83 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 10:07:46 +0700 Subject: update error log --- src/lib/home/components/CategoryPilihan.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx index 7b9f0094..73e42626 100644 --- a/src/lib/home/components/CategoryPilihan.jsx +++ b/src/lib/home/components/CategoryPilihan.jsx @@ -20,7 +20,7 @@ const CategoryPilihan = ({ id, categories }) => {
{heroBanner.data && heroBanner.data?.length > 0 && ( -
+
{/* {heroBanner.data?.map((banner) => ( */} {
{categories.map((category) => ( -
+
-- cgit v1.2.3 From 2fbfdb7a3d090b0ad8dae5527464b25e5df65c25 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 14:40:23 +0700 Subject: Merge branch 'Feature/category-management' into development # Conflicts: # src/lib/home/components/CategoryDynamic.jsx # src/lib/home/components/CategoryPilihan.jsx # src/lib/home/components/PreferredBrand.jsx # src/lib/product/components/CategorySection.jsx # src/pages/index.jsx --- src/pages/index.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index db868470..0f2add9a 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -64,13 +64,13 @@ const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId') ); -const CategoryDynamic = dynamic(() => - import('@/lib/home/components/CategoryDynamic') -); +// const CategoryDynamic = dynamic(() => +// import('@/lib/home/components/CategoryDynamic') +// ); -const CategoryDynamicMobile = dynamic(() => - import('@/lib/home/components/CategoryDynamicMobile') -); +// const CategoryDynamicMobile = dynamic(() => +// import('@/lib/home/components/CategoryDynamicMobile') +// ); const CategoryDynamic = dynamic(() => @@ -86,7 +86,7 @@ const CustomerReviews = dynamic(() => ); const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList')); -export default function Home({categoryId}) { + export default function Home({categoryId}) { const bannerRef = useRef(null); const wrapperRef = useRef(null); @@ -98,7 +98,7 @@ export default function Home({categoryId}) { bannerRef.current?.querySelector(':first-child')?.clientHeight + 'px'; }; - const [dataCategories, setDataCategories] = useState([]) + // const [dataCategories, setDataCategories] = useState([]) useEffect(() => { const loadCategories = async () => { -- cgit v1.2.3 From ca30fe957369a16f6833d6a3bd37df74182b2911 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 14:45:17 +0700 Subject: update error code --- src/pages/index.jsx | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 0f2add9a..c720547e 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -1,7 +1,5 @@ import dynamic from 'next/dynamic'; import { useEffect, useRef, useState } from 'react'; -import { useEffect, useRef, useState } from 'react'; - import { HeroBannerSkeleton } from '@/components/skeleton/BannerSkeleton'; import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton'; import Seo from '@/core/components/Seo'; @@ -13,15 +11,8 @@ import PreferredBrandSkeleton from '@/lib/home/components/Skeleton/PreferredBran import PromotinProgram from '@/lib/promotinProgram/components/HomePage'; import PagePopupIformation from '~/modules/popup-information'; import CategoryPilihan from '../lib/home/components/CategoryPilihan'; -// import CategoryDynamic from '../lib/home/components/CategoryDynamic'; import odooApi from '@/core/api/odooApi'; -import { getIdFromSlug } from '@/core/utils/slug' -import useProductDetail from '~/modules/product-detail/stores/useProductDetail'; import { getAuth } from '~/libs/auth'; -import CategoryPilihan from '../lib/home/components/CategoryPilihan'; -// import CategoryDynamic from '../lib/home/components/CategoryDynamic'; -import odooApi from '@/core/api/odooApi'; -import { getIdFromSlug } from '@/core/utils/slug' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout') @@ -64,15 +55,6 @@ const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId') ); -// const CategoryDynamic = dynamic(() => -// import('@/lib/home/components/CategoryDynamic') -// ); - -// const CategoryDynamicMobile = dynamic(() => -// import('@/lib/home/components/CategoryDynamicMobile') -// ); - - const CategoryDynamic = dynamic(() => import('@/lib/home/components/CategoryDynamic') ); -- cgit v1.2.3 From c36d43c9b41eeb6f0c996476eaa8a2d13fbf42d1 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 14:47:17 +0700 Subject: update error code --- src/pages/index.jsx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index c720547e..578c4e2d 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -80,8 +80,6 @@ export default function Home({categoryId}) { bannerRef.current?.querySelector(':first-child')?.clientHeight + 'px'; }; - // const [dataCategories, setDataCategories] = useState([]) - useEffect(() => { const loadCategories = async () => { const getCategories = await odooApi('GET', '/api/v1/category/child?partner_id='+{categoryId}) @@ -94,16 +92,6 @@ export default function Home({categoryId}) { const [dataCategories, setDataCategories] = useState([]) - useEffect(() => { - const loadCategories = async () => { - const getCategories = await odooApi('GET', '/api/v1/category/child?partner_id='+{categoryId}) - if(getCategories){ - setDataCategories(getCategories) - } - } - loadCategories() - }, []) - return ( ); -} +} \ No newline at end of file -- cgit v1.2.3 From 44e1ed755b6714fbf76216ef914a8dfc73bef367 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 15:21:12 +0700 Subject: merge --- src/pages/index.jsx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 578c4e2d..ad654922 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -13,6 +13,7 @@ import PagePopupIformation from '~/modules/popup-information'; import CategoryPilihan from '../lib/home/components/CategoryPilihan'; import odooApi from '@/core/api/odooApi'; import { getAuth } from '~/libs/auth'; +import { getAuth } from '~/libs/auth'; const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout') @@ -92,6 +93,8 @@ export default function Home({categoryId}) { const [dataCategories, setDataCategories] = useState([]) + const [dataCategories, setDataCategories] = useState([]) + return (
+
-- cgit v1.2.3 From 233f2501a7ad23bedb8d02b7a3e7762632108098 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 23 Jul 2024 15:23:28 +0700 Subject: update code --- src/pages/index.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index ad654922..0b2b6046 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -93,8 +93,6 @@ export default function Home({categoryId}) { const [dataCategories, setDataCategories] = useState([]) - const [dataCategories, setDataCategories] = useState([]) - return ( - -
+
@@ -184,10 +181,6 @@ export default function Home({categoryId}) { - - - - -- cgit v1.2.3 From 5214c9578aac1db612cd154cf04ee6d75750918d Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 24 Jul 2024 08:49:05 +0700 Subject: update error code --- src/pages/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 0b2b6046..110d8b17 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -13,7 +13,7 @@ import PagePopupIformation from '~/modules/popup-information'; import CategoryPilihan from '../lib/home/components/CategoryPilihan'; import odooApi from '@/core/api/odooApi'; import { getAuth } from '~/libs/auth'; -import { getAuth } from '~/libs/auth'; +// import { getAuth } from '~/libs/auth'; const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout') -- cgit v1.2.3 From a264e12c5af60e82f6e496209b6ac81d4a994a10 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 24 Jul 2024 09:06:05 +0700 Subject: merge category management to development --- src/lib/home/components/CategoryPilihan.jsx | 10 +++++----- src/pages/index.jsx | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx index 73e42626..5aa1fbcc 100644 --- a/src/lib/home/components/CategoryPilihan.jsx +++ b/src/lib/home/components/CategoryPilihan.jsx @@ -9,7 +9,7 @@ import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton' const CategoryPilihan = ({ id, categories }) => { - const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'index-a-1' })); + const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'banner-category-list' })); return (
@@ -29,7 +29,7 @@ const CategoryPilihan = ({ id, categories }) => { quality={100} src={heroBanner.data[0].image} alt={heroBanner.data[0].name} - className='h-48 object-fill w-full rounded hover:scale-105 transition duration-500 ease-in-out' + className='h-48 object-fill w-full' /> {/* ))} */} @@ -41,9 +41,9 @@ const CategoryPilihan = ({ id, categories }) => { {categories.map((category) => (
-
-
- {category?.name} +
+
+ {category?.name}

{category?.name}

diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 110d8b17..30a7ac1f 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -70,6 +70,7 @@ const CustomerReviews = dynamic(() => const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList')); + export default function Home({categoryId}) { const bannerRef = useRef(null); const wrapperRef = useRef(null); -- cgit v1.2.3 From a59ed6e73a599a82d6ef248c57ad29f2ab9cb15d Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 29 Jul 2024 15:23:01 +0700 Subject: Merge branch 'Feature/category-management' into development --- src/core/components/elements/Navbar/TopBanner.jsx | 22 ++-- src/lib/home/api/CategoryPilihanApi.js | 8 ++ src/lib/home/components/CategoryDynamic.jsx | 50 ++++++--- src/lib/home/components/CategoryPilihan.jsx | 14 +-- src/lib/home/hooks/useCategoryPilihan.js | 13 +++ src/lib/lob/components/Breadcrumb.jsx | 55 ++++++++++ src/lib/product/components/CategorySection.jsx | 11 +- src/lib/product/components/LobSectionCategory.jsx | 82 +++++++++++++++ src/lib/product/components/ProductSearch.jsx | 123 ++++++++++++++++++++-- src/pages/api/shop/product-homepage.js | 3 +- src/pages/shop/lob/[slug].jsx | 62 +++++++++++ 11 files changed, 390 insertions(+), 53 deletions(-) create mode 100644 src/lib/home/api/CategoryPilihanApi.js create mode 100644 src/lib/home/hooks/useCategoryPilihan.js create mode 100644 src/lib/lob/components/Breadcrumb.jsx create mode 100644 src/lib/product/components/LobSectionCategory.jsx create mode 100644 src/pages/shop/lob/[slug].jsx (limited to 'src') diff --git a/src/core/components/elements/Navbar/TopBanner.jsx b/src/core/components/elements/Navbar/TopBanner.jsx index 722a7501..83ef8c7a 100644 --- a/src/core/components/elements/Navbar/TopBanner.jsx +++ b/src/core/components/elements/Navbar/TopBanner.jsx @@ -4,6 +4,7 @@ import { useQuery } from 'react-query'; import odooApi from '@/core/api/odooApi'; import SmoothRender from '~/components/ui/smooth-render'; import Link from '../Link/Link'; +import { background } from '@chakra-ui/react'; const TopBanner = () => { const topBanner = useQuery({ @@ -12,7 +13,7 @@ const TopBanner = () => { refetchOnWindowFocus: false, }); - const backgroundColor = topBanner.data?.[0]?.backgroundColor || 'transparent'; + // const backgroundColor = topBanner.data?.[0]?.backgroundColor || 'transparent'; const hasData = topBanner.data?.length > 0; const data = topBanner.data?.[0] || null; @@ -22,16 +23,17 @@ const TopBanner = () => { height='36px' duration='700ms' delay='300ms' - style={{ backgroundColor }} > - - {data?.name} + ); diff --git a/src/lib/home/api/CategoryPilihanApi.js b/src/lib/home/api/CategoryPilihanApi.js new file mode 100644 index 00000000..8a0b38d3 --- /dev/null +++ b/src/lib/home/api/CategoryPilihanApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const categoryPilihanApi = async () => { + const dataCategoryPilihan = await odooApi('GET', '/api/v1/lob_homepage') + return dataCategoryPilihan +} + +export default categoryPilihanApi diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index fa1df286..6ab03ec3 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -2,38 +2,58 @@ import React, { useEffect, useState } from 'react'; import useCategoryManagement from '../hooks/useCategoryManagement'; import NextImage from 'next/image'; import Link from "next/link"; -import router from 'next/router'; import { createSlug } from '@/core/utils/slug'; +import odooApi from '@/core/api/odooApi'; const CategoryDynamic = () => { const { categoryManagement } = useCategoryManagement(); + const [categoryData, setCategoryData] = useState({}); + const [subCategoryData, setSubCategoryData] = useState({}); + + useEffect(() => { + const fetchCategoryData = async () => { + if (categoryManagement && categoryManagement.data) { + const updatedCategoryData = {}; + const updatedSubCategoryData = {}; + + for (const category of categoryManagement.data) { + // Calculate level 1 products + const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); + // console.log("countLevel1.child",countLevel1) + + updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; + + + // Calculate level 2 products for each sub-category + for (const subCategory of countLevel1.children) { + updatedSubCategoryData[subCategory.id] = subCategory.numFound; + } + } - const calculateLevel3Products = (category) => { - return category.childFrontendIdI.reduce((total, child) => total + (child.numFound || 0), 0); - }; + setCategoryData(updatedCategoryData); + setSubCategoryData(updatedSubCategoryData); + } + }; - const calculateLevel2Products = (category) => { - return category.categories.reduce((total, subCategory) => { - const level3Products = calculateLevel3Products(subCategory); - return total + (subCategory.numFound || 0) + level3Products; - }, 0); - }; + fetchCategoryData(); + }, [categoryManagement, categoryData]); + return (
{categoryManagement && categoryManagement.data?.map((category) => { - const countLevel2 = calculateLevel2Products(category); - + const countLevel1 = categoryData[category.categoryIdI] || 0; + return (
{category.name}
-

{countLevel2} Produk tersedia

+

{countLevel1} Produk tersedia

Lihat Semua
{category.categories.map((subCategory) => { - const countLevel3 = calculateLevel3Products(subCategory); + const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; return (
@@ -48,7 +68,7 @@ const CategoryDynamic = () => { />
{subCategory.name}
-

{(subCategory.numFound || 0) + countLevel3} Produk

+

{countLevel2} Produk tersedia

Lihat Semua
diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx index 5aa1fbcc..6efc1070 100644 --- a/src/lib/home/components/CategoryPilihan.jsx +++ b/src/lib/home/components/CategoryPilihan.jsx @@ -6,11 +6,11 @@ import { useEffect, useState } from 'react'; import { bannerApi } from '../../../api/bannerApi'; const { useQuery } = require('react-query') import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton'; - +import useCategoryPilihan from '../hooks/useCategoryPilihan'; const CategoryPilihan = ({ id, categories }) => { + const { categoryPilihan } = useCategoryPilihan(); const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'banner-category-list' })); - return (
@@ -38,19 +38,19 @@ const CategoryPilihan = ({ id, categories }) => { )}
- {categories.map((category) => ( -
+ {categoryPilihan?.data?.map((category) => ( +
- {category?.name} + {category?.name}
-

{category?.name}

+

{category?.industries}

Lihat semua diff --git a/src/lib/home/hooks/useCategoryPilihan.js b/src/lib/home/hooks/useCategoryPilihan.js new file mode 100644 index 00000000..12a86f7e --- /dev/null +++ b/src/lib/home/hooks/useCategoryPilihan.js @@ -0,0 +1,13 @@ +import categoryPilihanApi from '../api/CategoryPilihanApi' +import { useQuery } from 'react-query' + +const useCategoryPilihan = () => { + const fetchCategoryPilihan = async () => await categoryPilihanApi() + const { isLoading, data } = useQuery('categoryPilihanApi', fetchCategoryPilihan) + + return { + categoryPilihan: { data, isLoading } + } +} + +export default useCategoryPilihan \ No newline at end of file diff --git a/src/lib/lob/components/Breadcrumb.jsx b/src/lib/lob/components/Breadcrumb.jsx new file mode 100644 index 00000000..5722fd39 --- /dev/null +++ b/src/lib/lob/components/Breadcrumb.jsx @@ -0,0 +1,55 @@ +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( + `lob-breadcrumbs/${categoryId}`, + async () => await odooApi('GET', `/api/v1/lob_homepage/${categoryId}/category_id`) + ) + return ( +
+ + + + + Home + + + + {breadcrumbs?.data?.map((category, index) => ( + + {index === breadcrumbs.data.length - 1 ? ( + {category.industries} + ) : ( + + {category.industries} + + )} + + ))} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/lib/product/components/CategorySection.jsx b/src/lib/product/components/CategorySection.jsx index 14a39e7e..2af3db10 100644 --- a/src/lib/product/components/CategorySection.jsx +++ b/src/lib/product/components/CategorySection.jsx @@ -13,23 +13,16 @@ import { HeartIcon, } from '@heroicons/react/24/outline'; import { useState } from 'react'; // Import useState +import { getIdFromSlug } from '@/core/utils/slug' const CategorySection = ({ categories }) => { const { isDesktop, isMobile } = useDevice(); - const router = useRouter(); const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility - let teks = router.query.slug; - let hasil = teks?.match(/(\d+)$/)[0]; - - const breadcrumbs = useQuery( - `category-breadcrumbs/${hasil}`, - async () => await odooApi('GET', `/api/v1/category/${hasil}/category-breadcrumb`) - ); - const handleToggleCategories = () => { setIsOpenCategory(!isOpenCategory); }; + const displayedCategories = isOpenCategory ? categories : categories.slice(0, 10); diff --git a/src/lib/product/components/LobSectionCategory.jsx b/src/lib/product/components/LobSectionCategory.jsx new file mode 100644 index 00000000..34a09e46 --- /dev/null +++ b/src/lib/product/components/LobSectionCategory.jsx @@ -0,0 +1,82 @@ +import Image from "next/image"; +import Link from 'next/link'; +import { createSlug } from '@/core/utils/slug'; +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import { useQuery } from 'react-query'; +import { useRouter } from 'next/router'; +import { + ChevronDownIcon, + ChevronUpIcon, // Import ChevronUpIcon for toggling + DocumentCheckIcon, + HeartIcon, +} from '@heroicons/react/24/outline'; +import { useState } from 'react'; // Import useState +import { getIdFromSlug } from '@/core/utils/slug' + +const LobSectionCategory = ({ categories }) => { + const { isDesktop, isMobile } = useDevice(); + const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility + + const handleToggleCategories = () => { + setIsOpenCategory(!isOpenCategory); + }; + console.log("categories",categories[0]?.categoryIds) + + const displayedCategories = categories[0]?.categoryIds; + + return ( +
+ {isDesktop && ( +
+ {displayedCategories?.map((category) => ( + + + ))} +
+ )} + + {isMobile && ( +
+ + {displayedCategories?.map((category) => ( + + + + + ))} + + {categories.length > 10 && ( +
+ +
+ )} +
+ )} +
+ ) +} + +export default LobSectionCategory diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 34018ffe..4d510c5b 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -27,7 +27,9 @@ import ProductSearchSkeleton from './Skeleton/ProductSearchSkeleton'; import SideBanner from '~/modules/side-banner'; import FooterBanner from '~/modules/footer-banner'; import CategorySection from './CategorySection'; +import LobSectionCategory from './LobSectionCategory'; import { getIdFromSlug } from '@/core/utils/slug' +import { data } from 'autoprefixer'; const ProductSearch = ({ query, @@ -36,14 +38,105 @@ const ProductSearch = ({ brand = null, }) => { const router = useRouter(); + const { page = 1 } = query; const [q, setQ] = useState(query?.q || '*'); const [search, setSearch] = useState(query?.q || '*'); const [limit, setLimit] = useState(query?.limit || 30); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); + const [finalQuery, setFinalQuery] = useState({}); + const [queryFinal, setQueryFinal] = useState({}); + const [dataCategoriesProduct, setDataCategoriesProduct] = useState([]) + const [dataCategoriesLob, setDataCategoriesLob] = useState([]) + const categoryId = getIdFromSlug(prefixUrl) + const [data, setData] = useState([]) + const [dataLob, setDataLob] = useState([]); if (defaultBrand) query.brand = defaultBrand.toLowerCase(); + const dataIdCategories = [] + useEffect(() => { + if(prefixUrl.includes('category')){ + const loadProduct = async () => { + const getCategoriesId = await odooApi('GET', `/api/v1/category/numFound?parent_id=${categoryId}`); + if (getCategoriesId) { + setDataCategoriesProduct(getCategoriesId); + } + }; + loadProduct(); + }else if(prefixUrl.includes('lob')){ + const loadProduct = async () => { + const lobData = await odooApi('GET', `/api/v1/lob_homepage/${categoryId}/category_id`); + + if (lobData) { + setDataLob(lobData); + } + }; + loadProduct(); + + } + }, [categoryId]); + + const collectIds = (category) => { + const ids = []; + function recurse(cat) { + if (cat && cat.id) { + ids.push(cat.id); + } + if (Array.isArray(cat.children)) { + cat.children.forEach(recurse); + } + } + recurse(category); + return ids; + }; + + useEffect(() => { + if(prefixUrl.includes('category')){ + const ids = collectIds(dataCategoriesProduct); + const newQuery = { + fq: `category_id_ids:(${ids.join(' OR ')})`, + page, + brand : router.query.brand? router.query.brand : '', + category : router.query.category? router.query.category : '', + }; + setFinalQuery(newQuery); + } else if (prefixUrl.includes('lob')){ + + const fetchCategoryData = async () => { + if (dataLob[0]?.categoryIds) { + + for (const cate of dataLob[0].categoryIds) { + + dataIdCategories.push(cate.childId) + } + + + const mergedArray = dataIdCategories.flat(); + + const newQuery = { + fq: `category_id_ids:(${mergedArray.join(' OR ')})`, + page, + brand : router.query.brand? router.query.brand : '', + category : router.query.category? router.query.category : '', + }; + + setFinalQuery(newQuery); + + } + }; + fetchCategoryData(); + } + }, [dataCategoriesProduct, dataLob]); + + useEffect(() => { + if (prefixUrl.includes('category') || prefixUrl.includes('lob')) { + setQueryFinal({ ...finalQuery, q, limit, orderBy }); + } else { + setQueryFinal({ ...query, q, limit, orderBy }); + } + }, [prefixUrl,dataCategoriesProduct, query, finalQuery]); + const { productSearch } = useProductSearch({ - query: { ...query, q, limit, orderBy }, + query: queryFinal, operation: 'AND', }); const [products, setProducts] = useState(null); @@ -63,6 +156,7 @@ const ProductSearch = ({ const [categoryValues, setCategory] = useState( query?.category?.split(',') || [] ); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom || null); const [priceTo, setPriceTo] = useState(query?.priceTo || null); @@ -71,9 +165,7 @@ const ProductSearch = ({ const productRows = limit; const productFound = productSearch.data?.response.numFound; const [dataCategories, setDataCategories] = useState([]) - - const categoryId = getIdFromSlug(prefixUrl) - + useEffect(() => { if (productFound == 0 && query.q && !spellings) { searchSpellApi({ query: query.q }).then((response) => { @@ -103,7 +195,7 @@ const ProductSearch = ({ }); } }, [productFound, query, spellings]); - + let id = [] useEffect(() => { const checkIfBrand = async () => { const brand = await axios( @@ -122,15 +214,20 @@ const ProductSearch = ({ }, [q]); useEffect(() => { - const loadCategories = async () => { - const getCategories = await odooApi('GET', `/api/v1/category/child?parent_id=${categoryId}`) - if(getCategories){ - setDataCategories(getCategories) - } + if(prefixUrl.includes('category')){ + const loadCategories = async () => { + const getCategories = await odooApi('GET', `/api/v1/category/child?parent_id=${categoryId}`) + if(getCategories){ + setDataCategories(getCategories) + } + } + loadCategories() } - loadCategories() }, []) + + + const brands = []; for ( let i = 0; @@ -277,6 +374,8 @@ const ProductSearch = ({ }; const isNotReadyStockPage = router.asPath !== '/shop/search?orderBy=stock'; + + console.log("finalQuery",finalQuery) return ( <> @@ -338,6 +437,7 @@ const ProductSearch = ({ SpellingComponent )}
+ {productFound > 0 && ( @@ -429,6 +529,7 @@ const ProductSearch = ({
+ {bannerPromotionHeader && bannerPromotionHeader?.image && (
diff --git a/src/pages/api/shop/product-homepage.js b/src/pages/api/shop/product-homepage.js index 02c01ee0..61732c77 100644 --- a/src/pages/api/shop/product-homepage.js +++ b/src/pages/api/shop/product-homepage.js @@ -36,7 +36,8 @@ const respoonseMap = (productHomepage, products) => { name: productHomepage.name_s, image: productHomepage.image_s, url: productHomepage.url_s, - products: products + products: products, + categoryIds: productHomepage.category_id_ids, } return productMapped diff --git a/src/pages/shop/lob/[slug].jsx b/src/pages/shop/lob/[slug].jsx new file mode 100644 index 00000000..2153b565 --- /dev/null +++ b/src/pages/shop/lob/[slug].jsx @@ -0,0 +1,62 @@ +import _ from 'lodash'; +import dynamic from 'next/dynamic'; +import { useRouter } from 'next/router'; +import Seo from '@/core/components/Seo'; +import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug'; +import Breadcrumb from '../../../lib/lob/components/Breadcrumb'; +import { useEffect, useState } from 'react'; +import odooApi from '@/core/api/odooApi'; +import { div } from 'lodash-contrib'; + +const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')); +const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')); +const CategorySection = dynamic(() => import('@/lib/product/components/CategorySection')); + +export default function CategoryDetail() { + const router = useRouter(); + const { slug = '', page = 1 } = router.query; + const [dataLob, setDataLob] = useState([]); + const [finalQuery, setFinalQuery] = useState({}); + const [dataCategoriesProduct, setDataCategoriesProduct] = useState([]) + const [data, setData] = useState([]) + const dataIdCategories = [] + + const categoryName = getNameFromSlug(slug); + const lobId = getIdFromSlug(slug); + const q = router?.query.q || null; + const query = { + fq: `id:${lobId}`, + page, + }; + if (q) { + query.q = q; + } + + return ( + + + + +
+ {dataLob[0]?.categoryIds && ( +
+ +
+ )} +
+ + {!_.isEmpty(router.query) && ( + + )} +
+ ); +} -- cgit v1.2.3 From 53d214ef3222bcc4169b188bff3dadf6c43f6b7e Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 30 Jul 2024 14:27:23 +0700 Subject: git aMerge branch 'Feature/category-management' into development --- .../components/elements/Navbar/NavbarMobile.jsx | 4 +- src/core/components/elements/Navbar/TopBanner.jsx | 29 ++--- src/lib/home/components/CategoryPilihan.jsx | 142 ++++++++++++++------- src/pages/index.jsx | 4 +- 4 files changed, 116 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarMobile.jsx b/src/core/components/elements/Navbar/NavbarMobile.jsx index bcf45e0a..90314671 100644 --- a/src/core/components/elements/Navbar/NavbarMobile.jsx +++ b/src/core/components/elements/Navbar/NavbarMobile.jsx @@ -11,7 +11,7 @@ import Image from 'next/image'; import { useEffect, useState } from 'react'; import MobileView from '../../views/MobileView'; import Link from '../Link/Link'; -// import TopBanner from './TopBanner'; +import TopBanner from './TopBanner'; const Search = dynamic(() => import('./Search')); @@ -39,7 +39,7 @@ const NavbarMobile = () => { return ( - {/* */} +
) } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 64c880c7..d649ee17 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -61,7 +61,7 @@ const CategoryDynamic = dynamic(() => ); const CategoryDynamicMobile = dynamic(() => - import('@/lib/home/components/CategoryDynamicMobile') +import('@/lib/home/components/CategoryDynamicMobile') ); const CustomerReviews = dynamic(() => @@ -156,7 +156,7 @@ export default function Home({categoryId}) { -
+
-- cgit v1.2.3 From 7cac694f5a78f01e7e8185f7d37b758e9b7dab34 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 31 Jul 2024 14:01:48 +0700 Subject: add pop up cart --- src/lib/cart/components/Cartheader.jsx | 250 +++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 19f79bc9..a7dd621d 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -1,14 +1,21 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { getCartApi } from '../api/CartApi' +import currencyFormat from '@/core/utils/currencyFormat' +import Image from '@/core/components/elements/Image/Image' +import { createSlug } from '@/core/utils/slug' import useAuth from '@/core/hooks/useAuth' import { useRouter } from 'next/router' import odooApi from '@/core/api/odooApi' import { useProductCartContext } from '@/contexts/ProductCartContext' +import whatsappUrl from '@/core/utils/whatsappUrl' +import { AnimatePresence, motion } from 'framer-motion' +import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css' const { ShoppingCartIcon, PhotoIcon } = require('@heroicons/react/24/outline') const { default: Link } = require('next/link') const Cardheader = (cartCount) => { + const router = useRouter() const [subTotal, setSubTotal] = useState(null) const [buttonLoading, SetButtonTerapkan] = useState(false) @@ -109,6 +116,249 @@ const Cardheader = (cartCount) => {
+ + {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 && ( + <> +
    + {products && + products?.map((product, index) => ( + <> +
  • +
    +
    + {product.cartType === 'promotion' && ( + {product.name} + )} + {product.cartType === 'product' && ( + + {product?.name} + + )} +
    +
    + {product.cartType === 'promotion' && ( +

    + {product.name} +

    + )} + {product.cartType === 'product' && ( + + {' '} +

    + {product.parent.name} +

    + + )} + + {product?.hasFlashsale && ( +
    +
    + {product?.price?.discountPercentage}% +
    +
    + {currencyFormat(product?.price?.price)} +
    +
    + )} + +
    +
    + {product?.price?.priceDiscount > 0 ? ( + currencyFormat(product?.price?.priceDiscount) + ) : ( + + + Call For Price + + + )} +
    +
    +
    +
    +
    + {product.products?.map((product) => +
    + + {product?.image && {product.name}} + + +
    + + {product.displayName} + + +
    +
    + {/*
    {product.code}
    */} +
    + Berat Barang: + {product.packageWeight} Kg +
    +
    +
    +
    + +
    + )} + {product.freeProducts?.map((product) => +
    + + {product?.image && {product.name}} + + +
    + + {product.displayName} + + +
    +
    + {/*
    {product.code}
    */} +
    + Berat Barang: + {product.packageWeight} Kg +
    +
    +
    +
    + +
    + )} +
    +
  • + + ))} +
+
+ + )} +
+ {auth && products.length > 0 && !isLoading && ( + <> +
+ Subtotal Sebelum PPN : + {currencyFormat(subTotal)} +
+
+ +
+ + )} +
+
+ + )} +
+
) } -- cgit v1.2.3 From 12f581a4c0c4a3316385015622823c9e5935bb05 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 31 Jul 2024 14:13:10 +0700 Subject: update pop up cart --- src/lib/cart/components/Cartheader.jsx | 19 ++++++++++++++++--- src/lib/home/components/CategoryDynamic.jsx | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index a7dd621d..c8aa7cc3 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -26,6 +26,7 @@ const Cardheader = (cartCount) => { useProductCartContext() const [isHovered, setIsHovered] = useState(false) + const [isTop, setIsTop] = useState(true) const products = useMemo(() => { return productCart?.products || [] @@ -84,12 +85,24 @@ const Cardheader = (cartCount) => { setCountCart(cartCount.cartCount) }, [cartCount]) + useEffect(() => { + const handleScroll = () => { + setIsTop(window.scrollY === 0) + } + + window.addEventListener('scroll', handleScroll) + return () => { + window.removeEventListener('scroll', handleScroll) + } + }, []) + const handleCheckout = async () => { SetButtonTerapkan(true) let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`) router.push('/shop/checkout') } + return (
@@ -121,10 +134,10 @@ const Cardheader = (cartCount) => { <> { // Calculate level 2 products for each sub-category - for (const subCategory of countLevel1.children) { + for (const subCategory of countLevel1?.children) { updatedSubCategoryData[subCategory.id] = subCategory.numFound; } } -- cgit v1.2.3 From 6e5766739b0684919c8630580403ed279cc3a71e Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 31 Jul 2024 14:14:27 +0700 Subject: back log --- src/lib/home/components/CategoryDynamic.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index dae17c94..6ab03ec3 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -25,7 +25,7 @@ const CategoryDynamic = () => { // Calculate level 2 products for each sub-category - for (const subCategory of countLevel1?.children) { + for (const subCategory of countLevel1.children) { updatedSubCategoryData[subCategory.id] = subCategory.numFound; } } -- cgit v1.2.3 From 8a03b5a325692fd39c193f2a12b1a9aa4af1553e Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 31 Jul 2024 14:31:34 +0700 Subject: update cart pop up --- src/lib/cart/components/Cartheader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index c8aa7cc3..7d43a4da 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -290,7 +290,7 @@ const Cardheader = (cartCount) => {
-
+
{product.products?.map((product) =>
-- cgit v1.2.3 From d57ca7be5e2de9c48f4229b20a49a94bf05e88d1 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 2 Aug 2024 14:55:16 +0700 Subject: update cart pop up --- src/lib/cart/components/Cartheader.jsx | 259 ++++++++++++++++++++++++++++++++- 1 file changed, 257 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 19f79bc9..e3a5cc1f 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -4,7 +4,12 @@ import useAuth from '@/core/hooks/useAuth' import { useRouter } from 'next/router' import odooApi from '@/core/api/odooApi' import { useProductCartContext } from '@/contexts/ProductCartContext' - +import currencyFormat from '@/core/utils/currencyFormat' +import Image from '@/core/components/elements/Image/Image' +import { createSlug } from '@/core/utils/slug' +import whatsappUrl from '@/core/utils/whatsappUrl' +import { AnimatePresence, motion } from 'framer-motion' +import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css' const { ShoppingCartIcon, PhotoIcon } = require('@heroicons/react/24/outline') const { default: Link } = require('next/link') @@ -19,7 +24,7 @@ const Cardheader = (cartCount) => { useProductCartContext() const [isHovered, setIsHovered] = useState(false) - + const [isTop, setIsTop] = useState(true) const products = useMemo(() => { return productCart?.products || [] }, [productCart]) @@ -77,6 +82,16 @@ const Cardheader = (cartCount) => { setCountCart(cartCount.cartCount) }, [cartCount]) + useEffect(() => { + const handleScroll = () => { + setIsTop(window.scrollY === 0) + } + window.addEventListener('scroll', handleScroll) + return () => { + window.removeEventListener('scroll', handleScroll) + } + }, []) + const handleCheckout = async () => { SetButtonTerapkan(true) let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`) @@ -109,6 +124,246 @@ const Cardheader = (cartCount) => {
+ + {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 && ( + <> +
    + {products && + products?.map((product, index) => ( + <> +
  • +
    +
    + {product.cartType === 'promotion' && ( + {product.name} + )} + {product.cartType === 'product' && ( + + {product?.name} + + )} +
    +
    + {product.cartType === 'promotion' && ( +

    + {product.name} +

    + )} + {product.cartType === 'product' && ( + + {' '} +

    + {product.parent.name} +

    + + )} + {product?.hasFlashsale && ( +
    +
    + {product?.price?.discountPercentage}% +
    +
    + {currencyFormat(product?.price?.price)} +
    +
    + )} + +
    +
    + {product?.price?.priceDiscount > 0 ? ( + currencyFormat(product?.price?.priceDiscount) + ) : ( + + + Call For Price + + + )} +
    +
    +
    +
    +
    + {product.products?.map((product) => +
    + + {product?.image && {product.name}} + + +
    + + {product.displayName} + + +
    +
    + {/*
    {product.code}
    */} +
    + Berat Barang: + {product.packageWeight} Kg +
    +
    +
    +
    + +
    + )} + {product.freeProducts?.map((product) => +
    + + {product?.image && {product.name}} + + +
    + + {product.displayName} + + +
    +
    + {/*
    {product.code}
    */} +
    + Berat Barang: + {product.packageWeight} Kg +
    +
    +
    +
    + +
    + )} +
    +
  • + + ))} +
+
+ + )} +
+ {auth && products.length > 0 && !isLoading && ( + <> +
+ Subtotal Sebelum PPN : + {currencyFormat(subTotal)} +
+
+ +
+ + )} +
+
+ + )} +
) } -- cgit v1.2.3 From cf8a2c77f5a76a3b1dc10db6de56a4958de7b068 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Sat, 3 Aug 2024 08:41:51 +0700 Subject: update error code --- src/lib/cart/components/Cartheader.jsx | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index f76634ce..c7a8f0b8 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -1,15 +1,12 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { getCartApi } from '../api/CartApi' import currencyFormat from '@/core/utils/currencyFormat' -import Image from '@/core/components/elements/Image/Image' import { createSlug } from '@/core/utils/slug' import useAuth from '@/core/hooks/useAuth' import { useRouter } from 'next/router' import odooApi from '@/core/api/odooApi' import { useProductCartContext } from '@/contexts/ProductCartContext' -import currencyFormat from '@/core/utils/currencyFormat' import Image from '@/core/components/elements/Image/Image' -import { createSlug } from '@/core/utils/slug' import whatsappUrl from '@/core/utils/whatsappUrl' import { AnimatePresence, motion } from 'framer-motion' import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css' -- cgit v1.2.3 From 807931ee9bcb063157ceb8368e5ee0941450c6ca Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 6 Aug 2024 14:32:41 +0700 Subject: add quotation pop up --- src/contexts/ProductQuotationContext.js | 17 ++ .../components/elements/Navbar/NavbarDesktop.jsx | 58 +++++-- src/lib/quotation/components/Quotationheader.jsx | 189 +++++++++++++++++++++ 3 files changed, 249 insertions(+), 15 deletions(-) create mode 100644 src/contexts/ProductQuotationContext.js create mode 100644 src/lib/quotation/components/Quotationheader.jsx (limited to 'src') diff --git a/src/contexts/ProductQuotationContext.js b/src/contexts/ProductQuotationContext.js new file mode 100644 index 00000000..f9e17830 --- /dev/null +++ b/src/contexts/ProductQuotationContext.js @@ -0,0 +1,17 @@ +import React, { createContext, useContext, useState } from 'react'; + +const ProductQuotationContext = createContext(); + +export const useProductQuotationContext = () => useContext(ProductQuotationContext); + +export const ProductQuotationProvider = ({ children }) => { + const [productQuotation, setProductQuotation] = useState([]); + const [refreshQuotation, setRefreshQuotation] = useState(false); + const [isLoading, setIsloading] = useState(false); + + return ( + + {children} + + ); +}; diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 7d9e4264..49c4cd6e 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -5,7 +5,9 @@ import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; import IndoteknikLogo from '@/images/logo.png'; import Cardheader from '@/lib/cart/components/Cartheader'; +import Quotationheader from '@/lib/quotation/components/QuotationHeader' import Category from '@/lib/category/components/Category'; +import { useProductQuotationContext } from '@/contexts/ProductQuotationContext' import { ChevronDownIcon, DocumentCheckIcon, @@ -28,6 +30,7 @@ import { useDisclosure, } from '@chakra-ui/react'; import style from "./style/NavbarDesktop.module.css"; +import useTransactions from '@/lib/transaction/hooks/useTransactions'; const Search = dynamic(() => import('./Search'), { ssr: false }); const TopBanner = dynamic(() => import('./TopBanner'), { ssr: false }); @@ -37,6 +40,8 @@ const NavbarDesktop = () => { const auth = useAuth(); const [cartCount, setCartCount] = useState(0); + const [quotationCount, setQuotationCount] = useState(0); + // const { setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } = useProductQuotationContext() const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); @@ -47,6 +52,16 @@ const NavbarDesktop = () => { const { product } = useProductContext(); const { isOpen, onOpen, onClose } = useDisclosure(); + const query = { + context: 'quotation', + site: + (auth?.webRole === null && auth?.site ? auth.site : null), + }; + + const { transactions } = useTransactions({query}); + const pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); + + useEffect(() => { if (router.pathname === '/shop/product/[slug]') { setPayloadWa({ @@ -55,11 +70,11 @@ const NavbarDesktop = () => { url: createSlug('/shop/product/', product?.name, product?.id, true), }); setTemplateWA('product'); - + setUrlPath(router.asPath); } }, [product, router]); - + useEffect(() => { const handleCartChange = () => { const cart = async () => { @@ -69,14 +84,36 @@ const NavbarDesktop = () => { cart(); }; handleCartChange(); - + window.addEventListener('localStorageChange', handleCartChange); - + return () => { window.removeEventListener('localStorageChange', handleCartChange); }; }, []); + + // useEffect(() => { + // setProductQuotation(pendingTransactions) + // }, [transactions, ]) + // console.log("Pending Transactions", pendingTransactions); + // console.log("pendingTransactions.length", pendingTransactions.length); + + useEffect(() => { + const handleQuotationChange = () => { + const quotation = async () => { + setQuotationCount(pendingTransactions?.length); + }; + quotation(); + }; + handleQuotationChange(); + window.addEventListener('localStorageChange', handleQuotationChange); + + return () => { + window.removeEventListener('localStorageChange', handleQuotationChange); + }; + }, []); + console.log("quotationCount",quotationCount) return ( @@ -139,17 +176,8 @@ const NavbarDesktop = () => {
- - - Daftar -
- Quotation - + + diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx new file mode 100644 index 00000000..141b731e --- /dev/null +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -0,0 +1,189 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { getQuotationApi } from '../api/QuotationApi'; +import currencyFormat from '@/core/utils/currencyFormat'; +import { createSlug } from '@/core/utils/slug'; +import useAuth from '@/core/hooks/useAuth'; +import { useRouter } from 'next/router'; +import odooApi from '@/core/api/odooApi'; +import { useProductQuotationContext } from '@/contexts/ProductQuotationContext'; +import Image from '@/core/components/elements/Image/Image'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import { AnimatePresence, motion } from 'framer-motion'; +import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css'; +import useTransactions from '../../transaction/hooks/useTransactions'; +const { DocumentCheckIcon, PhotoIcon } = require('@heroicons/react/24/outline'); +const { default: Link } = require('next/link'); + +const Quotationheader = (quotationCount) => { + const auth = useAuth(); + const query = { + context: 'quotation', + site: auth?.webRole === null && auth?.site ? auth.site : null, + }; + + const router = useRouter(); + const [subTotal, setSubTotal] = useState(null); + const [buttonLoading, SetButtonTerapkan] = useState(false); + const itemLoading = [1, 2, 3]; + const [countQuotation, setCountQuotation] = useState(null); + const { productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } = + useProductQuotationContext(); + + const [isHovered, setIsHovered] = useState(false); + const [isTop, setIsTop] = useState(true); + const qotation = useMemo(() => { + return productQuotation || []; + }, [productQuotation]); + + const handleMouseEnter = () => { + setIsHovered(true); + getCart(); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + const getCart = () => { + if (!productQuotation && auth) { + refreshCartf(); + } + }; + const refreshCartf = useCallback(async () => { + setIsloading(true); + let { transactions } = await useTransactions({ query }); + let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); + setProductQuotation(pendingTransactions); + setCountQuotation(pendingTransactions.length); + setIsloading(false); + }, [setProductQuotation, setIsloading]); + + useEffect(() => { + if (refreshQuotation) { + refreshCartf(); + } + setRefreshQuotation(false); + }, [refreshQuotation, refreshCartf, setRefreshQuotation]); + + useEffect(() => { + setCountQuotation(quotationCount.cartCount); + }, [quotationCount]); + + useEffect(() => { + const handleScroll = () => { + setIsTop(window.scrollY === 0); + }; + window.addEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); + + const handleCheckout = async () => { + SetButtonTerapkan(true); + let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`); + router.push('/shop/quotation'); + }; + + return ( +
+
+ +
0 && 'mr-2'}`}> + + {countQuotation > 0 && ( + + {countQuotation} + + )} +
+ + Daftar +
+ Quotation +
+ +
+ + {isHovered && ( + <> + + + +
+
Daftar Quotation
+ + Lihat Semua + +
+
+
+ {!auth && ( +
+

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

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

+ Tidak Ada Quotation +

+
+ )} +
+
+
+ + )} +
+
+ ); +}; + +export default Quotationheader; -- cgit v1.2.3 From a63b03fffdf46ecddecf356d1d00d6582add75cf Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 6 Aug 2024 17:05:01 +0700 Subject: update cart pop up --- src/contexts/ProductCartContext.js | 4 +- src/contexts/ProductQuotationContext.js | 17 ------ .../components/elements/Navbar/NavbarDesktop.jsx | 35 +++++------ src/lib/quotation/components/Quotationheader.jsx | 67 ++++++++++++++++++---- 4 files changed, 76 insertions(+), 47 deletions(-) delete mode 100644 src/contexts/ProductQuotationContext.js (limited to 'src') diff --git a/src/contexts/ProductCartContext.js b/src/contexts/ProductCartContext.js index 06e97563..19889e07 100644 --- a/src/contexts/ProductCartContext.js +++ b/src/contexts/ProductCartContext.js @@ -4,12 +4,14 @@ const ProductCartContext = createContext() export const ProductCartProvider = ({ children }) => { const [productCart, setProductCart] = useState(null) + const [productQuotation, setProductQuotation] = useState(null) + const [refreshQuotation, setRefreshQuotation] = useState(false) const [refreshCart, setRefreshCart] = useState(false) const [isLoading, setIsloading] = useState(false) return ( {children} diff --git a/src/contexts/ProductQuotationContext.js b/src/contexts/ProductQuotationContext.js deleted file mode 100644 index f9e17830..00000000 --- a/src/contexts/ProductQuotationContext.js +++ /dev/null @@ -1,17 +0,0 @@ -import React, { createContext, useContext, useState } from 'react'; - -const ProductQuotationContext = createContext(); - -export const useProductQuotationContext = () => useContext(ProductQuotationContext); - -export const ProductQuotationProvider = ({ children }) => { - const [productQuotation, setProductQuotation] = useState([]); - const [refreshQuotation, setRefreshQuotation] = useState(false); - const [isLoading, setIsloading] = useState(false); - - return ( - - {children} - - ); -}; diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 49c4cd6e..c0e9b383 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -7,7 +7,7 @@ import IndoteknikLogo from '@/images/logo.png'; import Cardheader from '@/lib/cart/components/Cartheader'; import Quotationheader from '@/lib/quotation/components/QuotationHeader' import Category from '@/lib/category/components/Category'; -import { useProductQuotationContext } from '@/contexts/ProductQuotationContext' +import { useProductCartContext } from '@/contexts/ProductCartContext'; import { ChevronDownIcon, DocumentCheckIcon, @@ -41,8 +41,9 @@ const NavbarDesktop = () => { const [cartCount, setCartCount] = useState(0); const [quotationCount, setQuotationCount] = useState(0); - // const { setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } = useProductQuotationContext() - + const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation } = + useProductCartContext(); + const [pendingTransactions, setPendingTransactions] = useState([]) const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); const [urlPath, setUrlPath] = useState(null); @@ -51,15 +52,22 @@ const NavbarDesktop = () => { const { product } = useProductContext(); const { isOpen, onOpen, onClose } = useDisclosure(); - + const query = { context: 'quotation', site: - (auth?.webRole === null && auth?.site ? auth.site : null), + (auth?.webRole === null && auth?.site ? auth.site : null), }; - const { transactions } = useTransactions({query}); - const pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); + const { transactions } = useTransactions({ query }); + const data = transactions?.data?.saleOrders.filter( + (transaction) => transaction.status === 'draft' + ); + + useEffect(() => { + setProductQuotation(data); + setPendingTransactions(data); + }, [transactions.data]); useEffect(() => { @@ -83,7 +91,7 @@ const NavbarDesktop = () => { }; cart(); }; - handleCartChange(); + handleCartChange(); window.addEventListener('localStorageChange', handleCartChange); @@ -91,12 +99,6 @@ const NavbarDesktop = () => { window.removeEventListener('localStorageChange', handleCartChange); }; }, []); - - // useEffect(() => { - // setProductQuotation(pendingTransactions) - // }, [transactions, ]) - // console.log("Pending Transactions", pendingTransactions); - // console.log("pendingTransactions.length", pendingTransactions.length); useEffect(() => { const handleQuotationChange = () => { @@ -112,8 +114,8 @@ const NavbarDesktop = () => { return () => { window.removeEventListener('localStorageChange', handleQuotationChange); }; - }, []); - console.log("quotationCount",quotationCount) + }, [pendingTransactions]); + return ( @@ -176,7 +178,6 @@ const NavbarDesktop = () => {
- diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 141b731e..9f0f17a6 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -1,16 +1,15 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; -import { getQuotationApi } from '../api/QuotationApi'; -import currencyFormat from '@/core/utils/currencyFormat'; import { createSlug } from '@/core/utils/slug'; import useAuth from '@/core/hooks/useAuth'; import { useRouter } from 'next/router'; import odooApi from '@/core/api/odooApi'; -import { useProductQuotationContext } from '@/contexts/ProductQuotationContext'; +import { useProductCartContext } from '@/contexts/ProductCartContext'; import Image from '@/core/components/elements/Image/Image'; import whatsappUrl from '@/core/utils/whatsappUrl'; import { AnimatePresence, motion } from 'framer-motion'; import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css'; import useTransactions from '../../transaction/hooks/useTransactions'; +import currencyFormat from '@/core/utils/currencyFormat'; const { DocumentCheckIcon, PhotoIcon } = require('@heroicons/react/24/outline'); const { default: Link } = require('next/link'); @@ -20,14 +19,14 @@ const Quotationheader = (quotationCount) => { context: 'quotation', site: auth?.webRole === null && auth?.site ? auth.site : null, }; - + const router = useRouter(); const [subTotal, setSubTotal] = useState(null); const [buttonLoading, SetButtonTerapkan] = useState(false); const itemLoading = [1, 2, 3]; const [countQuotation, setCountQuotation] = useState(null); - const { productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } = - useProductQuotationContext(); + const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation } = + useProductCartContext(); const [isHovered, setIsHovered] = useState(false); const [isTop, setIsTop] = useState(true); @@ -49,12 +48,12 @@ const Quotationheader = (quotationCount) => { refreshCartf(); } }; + let { transactions } = useTransactions({ query }); const refreshCartf = useCallback(async () => { setIsloading(true); - let { transactions } = await useTransactions({ query }); let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); setProductQuotation(pendingTransactions); - setCountQuotation(pendingTransactions.length); + setCountQuotation(pendingTransactions?.length ? pendingTransactions?.length : pendingTransactions?.length); setIsloading(false); }, [setProductQuotation, setIsloading]); @@ -66,7 +65,7 @@ const Quotationheader = (quotationCount) => { }, [refreshQuotation, refreshCartf, setRefreshQuotation]); useEffect(() => { - setCountQuotation(quotationCount.cartCount); + setCountQuotation(quotationCount.quotationCount); }, [quotationCount]); useEffect(() => { @@ -85,6 +84,8 @@ const Quotationheader = (quotationCount) => { router.push('/shop/quotation'); }; + console.log("quotation",qotation) + return (
@@ -105,7 +106,7 @@ const Quotationheader = (quotationCount) => { )}
- Daftar + List
Quotation
@@ -137,7 +138,7 @@ const Quotationheader = (quotationCount) => { >
Daftar Quotation
- + Lihat Semua
@@ -150,7 +151,7 @@ const Quotationheader = (quotationCount) => { Login {' '} - Untuk Melihat Daftar Keranjang Belanja Anda + Untuk Melihat Daftar Quotation Anda

)} @@ -176,6 +177,48 @@ const Quotationheader = (quotationCount) => {

)} + {auth && qotation.length > 0 && !isLoading && ( + <> +
    + {qotation && + qotation?.map((product, index) => ( + <> +
  • +
    +
    +

    {product.dateOrder}

    +

    Pending Quotation

    +
    +
    +
    +

    + No. Transaksi +

    +

    + {product.name} +

    +
    +
    +

    + No. Purchase Order +

    +

    + {product.purchaseOrderFile} +

    +
    +
    +
    +

    Total

    +

    {currencyFormat(product.amountTotal)}

    +
    +
    +
  • + + ))} +
+
+ + )}
-- cgit v1.2.3 From a1ed8969b451acc7867622fc302b0fd2b3c970a2 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 7 Aug 2024 12:10:50 +0700 Subject: update quotation pop up --- src/lib/quotation/components/Quotationheader.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 9f0f17a6..c9686b5a 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -184,26 +184,26 @@ const Quotationheader = (quotationCount) => { qotation?.map((product, index) => ( <>
  • -
    +
    -

    {product.dateOrder}

    -

    Pending Quotation

    +

    {product.dateOrder}

    +

    Pending Quotation

    -

    +

    No. Transaksi

    -

    + {product.name} -

    +
    -

    +

    No. Purchase Order

    - {product.purchaseOrderFile} + {product.purchaseOrderFile ? product.purchaseOrderFile : '-'}

    -- cgit v1.2.3 From 86c880442fc0abbc4c356da4fa8a20bc5759aff3 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 7 Aug 2024 14:00:07 +0700 Subject: quotation update popup --- src/lib/quotation/components/Quotationheader.jsx | 54 +++++++++++++----------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index c9686b5a..79011682 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -184,33 +184,37 @@ const Quotationheader = (quotationCount) => { qotation?.map((product, index) => ( <>
  • -
    -
    -

    {product.dateOrder}

    -

    Pending Quotation

    -
    -
    -
    -

    - No. Transaksi -

    - - {product.name} - +
    + +
    +
    +

    Sales :

    +

    {product.sales}

    +
    +
    +

    Status :

    +

    Pending Quotation

    +
    -
    -

    - No. Purchase Order -

    -

    - {product.purchaseOrderFile ? product.purchaseOrderFile : '-'} -

    +
    +
    +

    No. Transaksi

    +

    {product.name}

    +
    +
    +

    No. Purchase Order

    +

    {product.purchaseOrderName ? product.purchaseOrderName : '-'}

    +
    -
    -
    -

    Total

    -

    {currencyFormat(product.amountTotal)}

    -
    +
    +
    +

    Total

    +

    {currencyFormat(product.amountTotal)}

    +
    +
  • -- cgit v1.2.3 From bad8abd263bd43c59dad8e61e2f5f35bfe5b7746 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 11:37:58 +0700 Subject: update quotation pop up --- src/lib/quotation/components/Quotation.jsx | 7 +++-- src/lib/quotation/components/Quotationheader.jsx | 38 +++++++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx index df234dc2..3fac6f29 100644 --- a/src/lib/quotation/components/Quotation.jsx +++ b/src/lib/quotation/components/Quotation.jsx @@ -9,6 +9,7 @@ import _ from 'lodash'; import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart'; import currencyFormat from '@/core/utils/currencyFormat'; import { toast } from 'react-hot-toast'; +import { useProductCartContext } from '@/contexts/ProductCartContext'; // import checkoutApi from '@/lib/checkout/api/checkoutApi' import { useRouter } from 'next/router'; import VariantGroupCard from '@/lib/variant/components/VariantGroupCard'; @@ -38,11 +39,12 @@ const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi'); const Quotation = () => { const router = useRouter(); const auth = useAuth(); - + const { data: cartCheckout } = useQuery('cartCheckout', () => getProductsCheckout() - ); +); +const { setRefreshQuotation } = useProductCartContext(); const SELF_PICKUP_ID = 32; const [products, setProducts] = useState(null); @@ -293,6 +295,7 @@ const Quotation = () => { if (isSuccess?.id) { for (const product of products) deleteItemCart({ productId: product.id }); router.push(`/shop/quotation/finish?id=${isSuccess.id}`); + setRefreshQuotation(true); return; } diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 79011682..14743fd6 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -30,6 +30,7 @@ const Quotationheader = (quotationCount) => { const [isHovered, setIsHovered] = useState(false); const [isTop, setIsTop] = useState(true); + const qotation = useMemo(() => { return productQuotation || []; }, [productQuotation]); @@ -49,6 +50,7 @@ const Quotationheader = (quotationCount) => { } }; let { transactions } = useTransactions({ query }); + const refreshCartf = useCallback(async () => { setIsloading(true); let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); @@ -57,6 +59,18 @@ const Quotationheader = (quotationCount) => { setIsloading(false); }, [setProductQuotation, setIsloading]); + useEffect(() => { + if (!qotation) return + + let calculateTotalDiscountAmount = 0 + for (const product of qotation) { + // if (qotation.quantity == '') continue + calculateTotalDiscountAmount += product.amountUntaxed + } + let subTotal = calculateTotalDiscountAmount + setSubTotal(subTotal) + }, [qotation]) + useEffect(() => { if (refreshQuotation) { refreshCartf(); @@ -84,8 +98,6 @@ const Quotationheader = (quotationCount) => { router.push('/shop/quotation'); }; - console.log("quotation",qotation) - return (
    @@ -211,8 +223,8 @@ const Quotationheader = (quotationCount) => {
    -

    Total

    -

    {currencyFormat(product.amountTotal)}

    +

    Total

    +

    {currencyFormat(product.amountUntaxed)}

    @@ -224,6 +236,24 @@ const Quotationheader = (quotationCount) => { )}
    + {auth && qotation.length > 0 && !isLoading && ( + <> +
    + Subtotal Sebelum PPN : + {currencyFormat(subTotal)} +
    +
    + +
    + + )} -- cgit v1.2.3 From 29662765048f561af5ab0dc586a37bd80068b633 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 11:45:59 +0700 Subject: update location quotationHeader --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index c0e9b383..85e77b2d 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -5,7 +5,7 @@ import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; import IndoteknikLogo from '@/images/logo.png'; import Cardheader from '@/lib/cart/components/Cartheader'; -import Quotationheader from '@/lib/quotation/components/QuotationHeader' +import Quotationheader from '../../../../../src/lib/quotation/components/QuotationHeader' import Category from '@/lib/category/components/Category'; import { useProductCartContext } from '@/contexts/ProductCartContext'; import { -- cgit v1.2.3 From 6e36b0e78c7ac56c8b7d2f27a19838e9aaa9da98 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 12:03:04 +0700 Subject: add import quotationHeader --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 85e77b2d..03335df6 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -5,7 +5,7 @@ import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; import IndoteknikLogo from '@/images/logo.png'; import Cardheader from '@/lib/cart/components/Cartheader'; -import Quotationheader from '../../../../../src/lib/quotation/components/QuotationHeader' +import Quotationheader from "../../../../../src/lib/quotation/components/Quotationheader.jsx" import Category from '@/lib/category/components/Category'; import { useProductCartContext } from '@/contexts/ProductCartContext'; import { -- cgit v1.2.3 From 079f8029445fdd243e267a4af7c7a4d5780afa24 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 14:11:32 +0700 Subject: update pop up quotation & cart --- src/contexts/ProductCartContext.js | 5 ++--- .../components/elements/Navbar/NavbarDesktop.jsx | 3 --- src/lib/cart/components/Cartheader.jsx | 1 + src/lib/quotation/components/Quotation.jsx | 4 ++-- src/lib/quotation/components/Quotationheader.jsx | 20 +++++++++----------- 5 files changed, 14 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/contexts/ProductCartContext.js b/src/contexts/ProductCartContext.js index 19889e07..3a21d2e0 100644 --- a/src/contexts/ProductCartContext.js +++ b/src/contexts/ProductCartContext.js @@ -4,14 +4,13 @@ const ProductCartContext = createContext() export const ProductCartProvider = ({ children }) => { const [productCart, setProductCart] = useState(null) - const [productQuotation, setProductQuotation] = useState(null) - const [refreshQuotation, setRefreshQuotation] = useState(false) const [refreshCart, setRefreshCart] = useState(false) const [isLoading, setIsloading] = useState(false) + const [productQuotation, setProductQuotation] = useState(null) return ( {children} diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 03335df6..2e8c982e 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -41,8 +41,6 @@ const NavbarDesktop = () => { const [cartCount, setCartCount] = useState(0); const [quotationCount, setQuotationCount] = useState(0); - const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation } = - useProductCartContext(); const [pendingTransactions, setPendingTransactions] = useState([]) const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); @@ -65,7 +63,6 @@ const NavbarDesktop = () => { ); useEffect(() => { - setProductQuotation(data); setPendingTransactions(data); }, [transactions.data]); diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index c7a8f0b8..6967d180 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -81,6 +81,7 @@ const Cardheader = (cartCount) => { useEffect(() => { setCountCart(cartCount.cartCount) + setRefreshCart(false) }, [cartCount]) useEffect(() => { diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx index 3fac6f29..0ad042de 100644 --- a/src/lib/quotation/components/Quotation.jsx +++ b/src/lib/quotation/components/Quotation.jsx @@ -44,7 +44,7 @@ const Quotation = () => { getProductsCheckout() ); -const { setRefreshQuotation } = useProductCartContext(); +const { setRefreshCart } = useProductCartContext(); const SELF_PICKUP_ID = 32; const [products, setProducts] = useState(null); @@ -295,7 +295,7 @@ const { setRefreshQuotation } = useProductCartContext(); if (isSuccess?.id) { for (const product of products) deleteItemCart({ productId: product.id }); router.push(`/shop/quotation/finish?id=${isSuccess.id}`); - setRefreshQuotation(true); + setRefreshCart(true); return; } diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 14743fd6..10e3e147 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -25,7 +25,7 @@ const Quotationheader = (quotationCount) => { const [buttonLoading, SetButtonTerapkan] = useState(false); const itemLoading = [1, 2, 3]; const [countQuotation, setCountQuotation] = useState(null); - const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation } = + const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation } = useProductCartContext(); const [isHovered, setIsHovered] = useState(false); @@ -72,11 +72,11 @@ const Quotationheader = (quotationCount) => { }, [qotation]) useEffect(() => { - if (refreshQuotation) { + if (refreshCart) { refreshCartf(); } - setRefreshQuotation(false); - }, [refreshQuotation, refreshCartf, setRefreshQuotation]); + setRefreshCart(false); + }, [ refreshCartf, setRefreshCart]); useEffect(() => { setCountQuotation(quotationCount.quotationCount); @@ -150,9 +150,6 @@ const Quotationheader = (quotationCount) => { >
    Daftar Quotation
    - - Lihat Semua -

    @@ -221,7 +218,8 @@ const Quotationheader = (quotationCount) => {

    {product.purchaseOrderName ? product.purchaseOrderName : '-'}

    -
    + {/*
    */} +

    Total

    {currencyFormat(product.amountUntaxed)}

    @@ -238,18 +236,18 @@ const Quotationheader = (quotationCount) => {
    {auth && qotation.length > 0 && !isLoading && ( <> -
    +
    Subtotal Sebelum PPN : {currencyFormat(subTotal)}
    -- cgit v1.2.3 From 64489b794a80b381d86ea226f0fe36457d5836be Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 15:06:37 +0700 Subject: update quotation pop up bug --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 2 +- src/lib/quotation/components/Quotationheader.jsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 2e8c982e..1163aff3 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -175,7 +175,7 @@ const NavbarDesktop = () => {
    - + diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 10e3e147..0bb4dfe0 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -80,6 +80,7 @@ const Quotationheader = (quotationCount) => { useEffect(() => { setCountQuotation(quotationCount.quotationCount); + setProductQuotation(quotationCount.data); }, [quotationCount]); useEffect(() => { -- cgit v1.2.3 From 3de1a412bba31b19b8b443dd91df8aff8d6eda07 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 8 Aug 2024 16:22:00 +0700 Subject: update link button --- src/lib/quotation/components/Quotationheader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx index 0bb4dfe0..4529c977 100644 --- a/src/lib/quotation/components/Quotationheader.jsx +++ b/src/lib/quotation/components/Quotationheader.jsx @@ -96,7 +96,7 @@ const Quotationheader = (quotationCount) => { const handleCheckout = async () => { SetButtonTerapkan(true); let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`); - router.push('/shop/quotation'); + router.push('/my/quotations'); }; return ( -- cgit v1.2.3 From 266d123ea9a2516913aa6f72d8c5855aea99652c Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 29 Aug 2024 15:42:22 +0700 Subject: update navbar category link & change category dynamic to slider --- .../components/elements/Navbar/NavbarDesktop.jsx | 5 +- src/lib/home/components/CategoryDynamic.jsx | 130 ++++++++++++--------- 2 files changed, 78 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 6c308f11..d3f53950 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -225,8 +225,7 @@ const NavbarDesktop = () => {
    -
    - +
    { const { categoryManagement } = useCategoryManagement(); @@ -34,6 +39,18 @@ const CategoryDynamic = () => { fetchCategoryData(); }, [categoryManagement.isLoading]); + + const swiperBanner = { + autoplay: { + delay: 6000, + disableOnInteraction: false, + }, + modules: [Pagination, Autoplay], + loop: true, + classNames:'mySwiper', + slidesPerView: 3, + spaceBetween:10, + }; return (
    @@ -42,64 +59,69 @@ const CategoryDynamic = () => { return ( -
    -
    -
    {category.name}
    - -

    {countLevel1} Produk tersedia

    -
    - Lihat Semua -
    -
    - {category.categories.map((subCategory) => { - const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; +
    +
    +
    {category.name}
    + +

    {countLevel1} Produk tersedia

    +
    + Lihat Semua +
    + + {/* Swiper for SubCategories */} + + {category.categories.map((subCategory) => { + const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; - return ( -
    -
    -
    - -
    -
    {subCategory.name}
    - -

    - {countLevel2} Produk tersedia -

    -
    - Lihat Semua -
    -
    -
    - {subCategory.childFrontendIdI.map((childCategory) => ( -
    - - -
    -
    {childCategory.name}
    + return ( + +
    +
    +
    + +
    +
    {subCategory.name}
    + +

    + {countLevel2} Produk tersedia +

    +
    + Lihat Semua +
    +
    +
    + {subCategory.childFrontendIdI.map((childCategory) => ( +
    + + +
    +
    {childCategory.name}
    +
    +
    - + ))}
    - ))} +
    -
    -
    - ); - })} + + ); + })} +
    -
    - + ); })}
    -- cgit v1.2.3 From 35c3eaad59dac0f0837dc43d5d4355c7e77803e5 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 29 Aug 2024 16:08:55 +0700 Subject: update mobile view --- src/lib/home/components/CategoryDynamicMobile.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx index c1433a2d..4d2fa0ec 100644 --- a/src/lib/home/components/CategoryDynamicMobile.jsx +++ b/src/lib/home/components/CategoryDynamicMobile.jsx @@ -59,7 +59,7 @@ const CategoryDynamicMobile = () => { alt={index.name} width={30} height={30} - className='object-' + className='' />
    {index.name}
    @@ -82,6 +82,7 @@ const CategoryDynamicMobile = () => { alt={x.name} width={40} height={40} + className='p-2' />
    {x.name}
    -- cgit v1.2.3 From 28691cd9eed9ea4480d978ae83a8a9424caf8ef4 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 29 Aug 2024 16:13:51 +0700 Subject: add pagintion --- src/lib/home/components/CategoryDynamic.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index 7f8a4135..48a60323 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -41,15 +41,15 @@ const CategoryDynamic = () => { }, [categoryManagement.isLoading]); const swiperBanner = { - autoplay: { - delay: 6000, - disableOnInteraction: false, - }, - modules: [Pagination, Autoplay], + modules: [Pagination, ], loop: true, classNames:'mySwiper', slidesPerView: 3, spaceBetween:10, + pagination: { + dynamicBullets: true, + clickable: true, + } }; return ( -- cgit v1.2.3 From cf3bcd1f3d1e0649204a786e9532a099772dad85 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Sat, 31 Aug 2024 09:42:34 +0700 Subject: update cart pop up --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 0d0e8550..ff08a4a1 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -136,7 +136,7 @@ const NavbarDesktop = () => { return () => { window.removeEventListener('localStorageChange', handleCartChange); }; - }, []); + }, [transactions.data]); useEffect(() => { const handleQuotationChange = () => { -- cgit v1.2.3 From a76376b74c02ee6875b68b6cfb59090a159df40a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Sat, 31 Aug 2024 11:44:49 +0700 Subject: update new cart pop up --- src/core/components/elements/Navbar/NavbarDesktop.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index ff08a4a1..454202df 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -32,6 +32,7 @@ import { } from '@chakra-ui/react'; import style from "./style/NavbarDesktop.module.css"; import useTransactions from '@/lib/transaction/hooks/useTransactions'; +import { useCartStore } from '~/modules/cart/stores/useCartStore'; const Search = dynamic(() => import('./Search'), { ssr: false }); const TopBanner = dynamic(() => import('./TopBanner'), { ssr: false }); @@ -46,7 +47,7 @@ const NavbarDesktop = () => { const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); const [urlPath, setUrlPath] = useState(null); - + const { loadCart, cart, summary, updateCartItem } = useCartStore(); const router = useRouter(); const { product } = useProductContext(); @@ -136,7 +137,7 @@ const NavbarDesktop = () => { return () => { window.removeEventListener('localStorageChange', handleCartChange); }; - }, [transactions.data]); + }, [transactions.data, cart]); useEffect(() => { const handleQuotationChange = () => { -- cgit v1.2.3 From 702b5d9b6e215ad812fadaff3325e1e6164d3b24 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 10:54:00 +0700 Subject: update pop up tambah keranjang --- src/lib/cart/components/Cartheader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 6967d180..ddb77c1f 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -48,7 +48,7 @@ const Cardheader = (cartCount) => { setIsloading(true) let cart = await getCartApi() setProductCart(cart) - setCountCart(cart.productTotal) + setCountCart(cart?.productTotal) setIsloading(false) }, [setProductCart, setIsloading]) -- cgit v1.2.3 From bf805f7da68891250a10d85d9206607de3cbfacf Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 13:24:07 +0700 Subject: temp save update fetch data promotion program line --- src/lib/product/api/productSearchApi.js | 2 +- src/lib/product/components/ProductSearch.jsx | 2 +- src/pages/api/shop/promo.js | 205 +++++++++++++++++++++++++++ src/pages/shop/promo/[slug].tsx | 67 ++++++--- src/utils/solrMapping.js | 29 ++++ 5 files changed, 285 insertions(+), 20 deletions(-) create mode 100644 src/pages/api/shop/promo.js (limited to 'src') diff --git a/src/lib/product/api/productSearchApi.js b/src/lib/product/api/productSearchApi.js index 1626b7b7..2f792fd4 100644 --- a/src/lib/product/api/productSearchApi.js +++ b/src/lib/product/api/productSearchApi.js @@ -3,7 +3,7 @@ import axios from 'axios' const productSearchApi = async ({ query, operation = 'AND' }) => { const dataProductSearch = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}` + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}` ) return dataProductSearch.data } diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index eaeac71a..1f083722 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -87,7 +87,7 @@ const ProductSearch = ({ recurse(category); return ids; }; - + console.log("queryFinal",queryFinal) useEffect(() => { if(prefixUrl.includes('category')){ const ids = collectIds(dataCategoriesProduct); diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js new file mode 100644 index 00000000..4b4c09b7 --- /dev/null +++ b/src/pages/api/shop/promo.js @@ -0,0 +1,205 @@ +import { map } from '@/utils/solrMapping'; +import axios from 'axios'; +import camelcaseObjectDeep from 'camelcase-object-deep'; + +export default async function handler(req, res) { + console.log("req_iman",req) + const { + q = '*', + page = 1, + brand = '', + category = '', + priceFrom = 0, + priceTo = 0, + orderBy = '', + operation = 'AND', + fq = '', + limit = 30, + } = req.query; + + let { stock = '' } = req.query; + + let paramOrderBy = ''; + switch (orderBy) { + case 'price-asc': + paramOrderBy += 'price_tier1_v2_f ASC'; + break; + case 'price-desc': + paramOrderBy += 'price_tier1_v2_f DESC'; + break; + case 'popular': + paramOrderBy += 'product_rating_f DESC, search_rank_i DESC,'; + break; + case 'popular-weekly': + paramOrderBy += 'search_rank_weekly_i DESC'; + break; + case 'stock': + paramOrderBy += 'product_rating_f DESC, stock_total_f DESC'; + break; + case 'flashsale-price-asc': + paramOrderBy += 'flashsale_price_f ASC'; + break; + default: + paramOrderBy += ''; + break; + } + + let checkQ = q.trim().split(/[\s\+\-\!\(\)\{\}\[\]\^"~\*\?:\\\/]+/); + let newQ = checkQ.length > 1 ? escapeSolrQuery(q) + '*' : escapeSolrQuery(q); + + let offset = (page - 1) * limit; + let parameter = [ + // 'facet.field=manufacture_name_s', + // 'facet.field=category_name', + 'facet=true', + 'indent=true', + // `facet.query=${escapeSolrQuery(q)}`, + `q.op=${operation}`, + `q=${newQ}`, + // 'qf=name_s', + `start=${parseInt(offset)}`, + `rows=${limit}`, + `sort=${paramOrderBy}`, + // `fq=-publish_b:false, product_rating_f:[8 TO *], price_tier1_v2_f:[1 TO *]`, + ]; + + if (priceFrom > 0 || priceTo > 0) { + parameter.push( + `fq=price_tier1_v2_f:[${priceFrom == '' ? '*' : priceFrom} TO ${ + priceTo == '' ? '*' : priceTo + }]` + ); + } + + let { auth } = req.cookies; + if (auth) { + auth = JSON.parse(auth); + if (auth.feature.onlyReadyStock) stock = true; + } + + if (brand) + parameter.push( + `fq=${brand + .split(',') + .map( + (manufacturer) => + `manufacture_name:"${encodeURIComponent(manufacturer)}"` + ) + .join(' OR ')}` + ); + if (category) + parameter.push( + `fq=${category + .split(',') + .map((cat) => `category_name:"${encodeURIComponent(cat)}"`) + .join(' OR ')}` + ); + // if (category) parameter.push(`fq=category_name:${capitalizeFirstLetter(category.replace(/,/g, ' OR '))}`) + if (stock) parameter.push(`fq=stock_total_f:{1 TO *}`); + + // Single fq in url params + if (typeof fq === 'string') parameter.push(`fq=${fq}`); + // Multi fq in url params + if (Array.isArray(fq)) + parameter = parameter.concat(fq.map((val) => `fq=${val}`)); + + console.log("parameter",parameter) + + let result = await axios( + process.env.SOLR_HOST + '/solr/promotion_program_lines/select?' + parameter.join('&') + ); + console.log("result",result) + try { + result.data.response.products = map( + result.data.response.docs, + auth?.pricelist || false + ); + result.data.responseHeader.params.start = parseInt( + result.data.responseHeader.params.start + ); + result.data.responseHeader.params.rows = parseInt( + result.data.responseHeader.params.rows + ); + delete result.data.response.docs; + result.data = camelcaseObjectDeep(result.data); + res.status(200).json(result.data); + } catch (error) { + res.status(400).json({ error: error.message }); + } +} + +const escapeSolrQuery = (query) => { + if (query == '*') return query; + + query = query.replace(/-/g, ' '); + + const specialChars = /([\+\!\(\)\{\}\[\]\^"~\*\?:\\\/])/g; + const words = query.split(/\s+/); + const escapedWords = words.map((word) => { + if (specialChars.test(word)) { + return word.replace(specialChars, '\\$1'); + } + return word; + }); + + return escapedWords.join(' '); +}; + + +/*const productResponseMap = (products, pricelist) => { + return products.map((product) => { + let price = product.price_tier1_v2_f || 0 + let priceDiscount = product.price_discount_f || 0 + let discountPercentage = product.discount_f || 0 + + if (pricelist) { + // const pricelistDiscount = product?.[`price_${pricelist}_f`] || false + // const pricelistDiscountPerc = product?.[`discount_${pricelist}_f`] || false + + // if (pricelistDiscount && pricelistDiscount > 0) priceDiscount = pricelistDiscount + // if (pricelistDiscountPerc && pricelistDiscountPerc > 0) + // discountPercentage = pricelistDiscountPerc + + price = product?.[`price_${pricelist}_f`] || 0 + } + + if (product?.flashsale_id_i > 0) { + price = product?.flashsale_base_price_f || 0 + priceDiscount = product?.flashsale_price_f || 0 + discountPercentage = product?.flashsale_discount_f || 0 + } + + let productMapped = { + id: product.product_id_i || '', + image: product.image_s || '', + code: product.default_code_s || '', + name: product.name_s || '', + lowestPrice: { price, priceDiscount, discountPercentage }, + variantTotal: product.variant_total_i || 0, + stockTotal: product.stock_total_f || 0, + weight: product.weight_f || 0, + manufacture: {}, + categories: [], + flashSale: { + id: product?.flashsale_id_i, + name: product?.product?.flashsale_name_s, + tag : product?.flashsale_tag_s || 'FLASH SALE' + } + } + + if (product.manufacture_id_i && product.manufacture_name_s) { + productMapped.manufacture = { + id: product.manufacture_id_i || '', + name: product.manufacture_name_s || '' + } + } + + productMapped.categories = [ + { + id: product.category_id_i || '', + name: product.category_name_s || '' + } + ] + return productMapped + }) +}*/ diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index aaee1249..92f5b7f8 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -2,30 +2,31 @@ 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' -import Promocrumb from '../../../lib/promo/components/Promocrumb' -import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi' +import Seo from '../../../core/components/Seo.jsx' +import Promocrumb from '../../../lib/promo/components/Promocrumb.jsx' +import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi.js' import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' -import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card' -import { IPromotion } from '../../../../src-migrate/types/promotion' +import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx' +import { IPromotion } from '../../../../src-migrate/types/promotion.ts' 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 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' -import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion'; -import ProductFilter from '../../../lib/product/components/ProductFilter'; +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'; -import { formatCurrency } from '../../../core/utils/formatValue'; -import Pagination from '../../../core/components/elements/Pagination/Pagination'; -import SideBanner from '../../../../src-migrate/modules/side-banner'; -import whatsappUrl from '../../../core/utils/whatsappUrl'; +import { formatCurrency } from '../../../core/utils/formatValue.js'; +import Pagination from '../../../core/components/elements/Pagination/Pagination.js'; +import SideBanner from '../../../../src-migrate/modules/side-banner/index.tsx'; +import whatsappUrl from '../../../core/utils/whatsappUrl.js'; import { cons, toQuery } from 'lodash-contrib'; import _ from 'lodash'; -import useActive from '../../../core/hooks/useActive'; +import useActive from '../../../core/hooks/useActive.js'; +import useProductSearch from '../../../lib/product/hooks/useProductSearch.js'; -const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) export default function PromoDetail() { const router = useRouter() @@ -40,9 +41,39 @@ export default function PromoDetail() { const [categories, setCategories] = useState([]); const [brandValues, setBrandValues] = useState([]); const [categoryValues, setCategoryValues] = useState([]); - const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); + const [orderBy, setOrderBy] = useState(router.query?.orderBy); const popup = useActive(); const prefixUrl = `/shop/promo/${slug}` + const [queryFinal, setQueryFinal] = useState({}); + const [limit, setLimit] = useState(30); + const [q, setQ] = useState('**'); + const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); + const [products, setProducts] = useState(null); + useEffect(() => { + setQueryFinal({ ...finalQuery, q, limit, orderBy }); +}, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); + useEffect(() => { + setQueryFinal({ ...finalQuery, q, limit, orderBy }); + }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); + + const { productSearch } = useProductSearch({ + query: queryFinal, + operation: 'OR', + }); + + console.log("productSearch",productSearch) + console.log("queryFinal",queryFinal) + + 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; + + useEffect(() => { + setProducts(productSearch.data?.response?.products); + }, [productSearch]); + + console.log("products",products) useEffect(() => { if (router.query.brand) { @@ -91,7 +122,7 @@ export default function PromoDetail() { setCurrentPage(pageNumber) try { - const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`,0,100); + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`,0,10); setPromoItems(items); if (items.length === 0) { diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index fee474be..e93b0b54 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -1,3 +1,31 @@ +const map = (promotions) => { + const result = []; + for (const promotion of promotions) { + const data = { + 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, + sequence: promotion.sequence_i, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + product_id: promotion.product_ids[0], + qty_sold_f:promotion.total_qty_sold_f, + free_products: JSON.parse(promotion.free_products_s), + }; + result.push(data); + } + return result; +}; + + export const productMappingSolr = (products, pricelist) => { return products.map((product) => { let price = product.price_tier1_v2_f || 0; @@ -123,3 +151,4 @@ const flashsaleTime = (endDate) => { isFlashSale: flashsaleEndDate > currentTime, }; }; + -- cgit v1.2.3 From 4710e3573a8af2f38f03f8da4a2ab9d7f3115415 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 13:38:56 +0700 Subject: delete fungsi loop --- src/lib/home/components/CategoryDynamic.jsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index 48a60323..0ab9312a 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -27,8 +27,8 @@ const CategoryDynamic = () => { updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; - for (const subCategory of countLevel1.children) { - updatedSubCategoryData[subCategory.id] = subCategory.numFound; + for (const subCategory of countLevel1?.children) { + updatedSubCategoryData[subCategory.id] = subCategory?.numFound; } } @@ -42,7 +42,6 @@ const CategoryDynamic = () => { const swiperBanner = { modules: [Pagination, ], - loop: true, classNames:'mySwiper', slidesPerView: 3, spaceBetween:10, @@ -84,10 +83,10 @@ const CategoryDynamic = () => { alt={subCategory.name} width={90} height={30} - className='object-fit' + className='object-fit p-4' />
    -
    {subCategory.name}
    +
    {subCategory?.name}

    {countLevel2} Produk tersedia -- cgit v1.2.3 From 3f384749fe51a2763e7e99351f36ce70954afb7a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 14:40:34 +0700 Subject: temp save --- src/lib/product/api/productSearchApi.js | 2 +- src/pages/api/shop/promo.js | 7 +- src/pages/shop/promo/[slug].jsx | 550 +++++++++++++++++++++++++++++++ src/pages/shop/promo/[slug].tsx | 554 -------------------------------- src/utils/solrMapping.js | 2 +- 5 files changed, 556 insertions(+), 559 deletions(-) create mode 100644 src/pages/shop/promo/[slug].jsx delete mode 100644 src/pages/shop/promo/[slug].tsx (limited to 'src') diff --git a/src/lib/product/api/productSearchApi.js b/src/lib/product/api/productSearchApi.js index 2f792fd4..670661aa 100644 --- a/src/lib/product/api/productSearchApi.js +++ b/src/lib/product/api/productSearchApi.js @@ -1,7 +1,7 @@ import _ from 'lodash-contrib' import axios from 'axios' -const productSearchApi = async ({ query, operation = 'AND' }) => { +const productSearchApi = async ({ query, operation = 'OR' }) => { const dataProductSearch = await axios( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}` ) diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js index 4b4c09b7..353ff3df 100644 --- a/src/pages/api/shop/promo.js +++ b/src/pages/api/shop/promo.js @@ -1,4 +1,4 @@ -import { map } from '@/utils/solrMapping'; +import { productMappingSolr, promoMappingSolr } from '@/utils/solrMapping'; import axios from 'axios'; import camelcaseObjectDeep from 'camelcase-object-deep'; @@ -55,7 +55,7 @@ export default async function handler(req, res) { 'indent=true', // `facet.query=${escapeSolrQuery(q)}`, `q.op=${operation}`, - `q=${newQ}`, + `q=${q}`, // 'qf=name_s', `start=${parseInt(offset)}`, `rows=${limit}`, @@ -110,7 +110,7 @@ export default async function handler(req, res) { ); console.log("result",result) try { - result.data.response.products = map( + result.data.response.products = promoMappingSolr( result.data.response.docs, auth?.pricelist || false ); @@ -121,6 +121,7 @@ export default async function handler(req, res) { result.data.responseHeader.params.rows ); delete result.data.response.docs; + console.log("result.data",result.data) result.data = camelcaseObjectDeep(result.data); res.status(200).json(result.data); } catch (error) { diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx new file mode 100644 index 00000000..544286f9 --- /dev/null +++ b/src/pages/shop/promo/[slug].jsx @@ -0,0 +1,550 @@ +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 { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi.js' +import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' +import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx' +import { IPromotion } from '../../../../src-migrate/types/promotion.ts' +import React from 'react' +import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; +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 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'; +import { formatCurrency } from '../../../core/utils/formatValue.js'; +import Pagination from '../../../core/components/elements/Pagination/Pagination.js'; +import SideBanner from '../../../../src-migrate/modules/side-banner/index.tsx'; +import whatsappUrl from '../../../core/utils/whatsappUrl.js'; +import { cons, toQuery } from 'lodash-contrib'; +import _ from 'lodash'; +import useActive from '../../../core/hooks/useActive.js'; +import useProductSearch from '../../../lib/product/hooks/useProductSearch.js'; + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) + +export default function PromoDetail() { + const router = useRouter() + const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query + const [promoItems, setPromoItems] = useState([]) + const [promoData, setPromoData] = useState(null) + const [currentPage, setCurrentPage] = useState(parseInt(10) || 1); + const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman + const [loading, setLoading] = useState(true); + const { isMobile, isDesktop } = useDevice() + const [brands, setBrands] = useState([]); + const [categories, setCategories] = useState([]); + const [brandValues, setBrandValues] = useState([]); + const [categoryValues, setCategoryValues] = useState([]); + const [orderBy, setOrderBy] = useState(router.query?.orderBy); + const popup = useActive(); + const prefixUrl = `/shop/promo/${slug}` + const [queryFinal, setQueryFinal] = useState({}); + const [limit, setLimit] = useState(30); + const [q, setQ] = useState('*'); + const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); + const [products, setProducts] = useState(null); + useEffect(() => { + setQueryFinal({ ...finalQuery, q, limit, orderBy }); +}, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); + useEffect(() => { + setQueryFinal({ ...finalQuery, q, limit, orderBy }); + }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); + + const { productSearch } = useProductSearch({ + query: queryFinal, + operation: 'OR', + }); + + console.log("productSearch",productSearch) + console.log("queryFinal",queryFinal) + + 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; + + useEffect(() => { + setProducts(productSearch.data?.response?.products); + }, [productSearch]); + + console.log("products",products) + + + + + + + + useEffect(() => { + if (router.query.brand) { + let brandsArray= []; + if (Array.isArray(router.query.brand)) { + brandsArray = router.query.brand; + } else if (typeof router.query.brand === 'string') { + brandsArray = router.query.brand.split(',').map((brand) => brand.trim()); + } + setBrandValues(brandsArray); + } else { + setBrandValues([]); + } + + if (router.query.category) { + let categoriesArray= []; + + if (Array.isArray(router.query.category)) { + categoriesArray = router.query.category; + } else if (typeof router.query.category === 'string') { + categoriesArray = router.query.category.split(',').map((category) => category.trim()); + } + setCategoryValues(categoriesArray); + } else { + setCategoryValues([]); + } + }, [router.query.brand, router.query.category]); + + useEffect(() => { + const loadPromo = async () => { + setLoading(true); + const brandsData = []; + const categoriesData= []; + + 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}`,0,10); + setPromoItems(items); + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const brandArray = Array.isArray(brand) ? brand : brand.split(','); + const categoryArray = Array.isArray(category) ? category : category.split(','); + + const promoDataPromises = items.map(async (item) => { + + try { + 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; + } + + 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; + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`,0,100); + return response2; + }else if(combinedQuery){ + const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); + const product = response.response.docs[0]; + const product_id = product.id; + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `,0,100); + return response2; + } else { + const response = await fetchPromoItemsSolr(`id:${item.id}`,0,100); + return response; + } + } catch (fetchError) { + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + + const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { + if (promoData) { + const dataBrandCategory = promoData.map(async (item) => { + let response; + if(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}`) + } + + + if (response.response?.docs?.length > 0) { + const product = response.response.docs[0]; + const manufactureNameS = product.manufacture_name; + if (Array.isArray(manufactureNameS)) { + for (let i = 0; i < manufactureNameS.length; i += 2) { + const brand = manufactureNameS[i]; + const qty = 1; + const existingBrandIndex = brandsData.findIndex(b => b.brand === brand); + if (existingBrandIndex !== -1) { + brandsData[existingBrandIndex].qty += qty; + } else { + brandsData.push({ brand, qty }); + } + } + } + + const categoryNameS = product.category_name; + if (Array.isArray(categoryNameS)) { + for (let i = 0; i < categoryNameS.length; i += 2) { + const name = categoryNameS[i]; + const qty = 1; + const existingCategoryIndex = categoriesData.findIndex(c => c.name === name); + if (existingCategoryIndex !== -1) { + categoriesData[existingCategoryIndex].qty += qty; + } else { + categoriesData.push({ name, qty }); + } + } + } + } + }); + + return Promise.all(dataBrandCategory); + } + }); + + await Promise.all(dataBrandCategoryPromises); + setBrands(brandsData); + setCategories(categoriesData); + setLoading(false); + + } catch (loadError) { + // console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + },[slug, brand, category, priceFrom, priceTo, currentPage]); + + + function capitalizeFirstLetter(string) { + string = string.replace(/_/g, ' '); + return string.replace(/(^\w|\s\w)/g, function(match) { + return match.toUpperCase(); + }); + } + + const handleDeleteFilter = async (source, value) => { + let params = { + q: router.query.q, + 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 = ''; + params.priceTo = ''; + break; + case 'delete': + params = { + q: router.query.q, + orderBy: '', + brand: '', + category: '', + priceFrom: '', + priceTo: '', + }; + break; + } + + handleSubmitFilter(params); + }; + const handleSubmitFilter = (params) => { + params = _.pickBy(params, _.identity); + params = toQuery(params); + router.push(`${slug}?${params}`); + }; + + const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) + + 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']) + const queryString = toQuery(queryWithoutSlug) + + return ( + + + + +

    +

    Promo {whatPromo}

    + + + {promoItems.length >= 1 && ( +
    +
    + +
    +
    + )} + + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {visiblePromotions?.map((promotion) => ( +
    + +
    + ))} +
    + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} + + + +
    + + + +
    +
    +

    Promo {whatPromo}

    +
    + +
    + + +
    +
    + + +
    +
    + {loading ? ( +
    + +
    + ) : promoData && promoItems.length >= 1 ? ( + <> +
    + {products?.map((promotion) => ( +
    + +
    + ))} +
    + + ) : ( +
    +

    Belum ada promo pada kategori ini

    +
    + )} +
    +
    + +
    + + Barang yang anda cari tidak ada?{' '} + + Hubungi Kami + + +
    +
    + + + + +
    + +
    +
    +
    + + ) + } + +const FilterChoicesComponent = ({ + brandValues, + categoryValues, + priceFrom, + priceTo, + handleDeleteFilter, + }) => ( +
    + + {brandValues?.map((value, index) => ( + + {value} + handleDeleteFilter('brands', value)} /> + + ))} + + {categoryValues?.map((value, index) => ( + + {value} + handleDeleteFilter('category', value)} + /> + + ))} + {priceFrom && priceTo && ( + + + {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)} + + handleDeleteFilter('price', priceFrom)} + /> + + )} + {brandValues?.length > 0 || + categoryValues?.length > 0 || + priceFrom || + priceTo ? ( + + + + ) : ( + '' + )} + +
    +); diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx deleted file mode 100644 index 92f5b7f8..00000000 --- a/src/pages/shop/promo/[slug].tsx +++ /dev/null @@ -1,554 +0,0 @@ -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 { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi.js' -import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' -import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx' -import { IPromotion } from '../../../../src-migrate/types/promotion.ts' -import React from 'react' -import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; -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 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'; -import { formatCurrency } from '../../../core/utils/formatValue.js'; -import Pagination from '../../../core/components/elements/Pagination/Pagination.js'; -import SideBanner from '../../../../src-migrate/modules/side-banner/index.tsx'; -import whatsappUrl from '../../../core/utils/whatsappUrl.js'; -import { cons, toQuery } from 'lodash-contrib'; -import _ from 'lodash'; -import useActive from '../../../core/hooks/useActive.js'; -import useProductSearch from '../../../lib/product/hooks/useProductSearch.js'; - -const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) - -export default function PromoDetail() { - const router = useRouter() - const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query - const [promoItems, setPromoItems] = useState([]) - const [promoData, setPromoData] = useState(null) - const [currentPage, setCurrentPage] = useState(parseInt(page as string, 10) || 1); - const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman - const [loading, setLoading] = useState(true); - const { isMobile, isDesktop } = useDevice() - const [brands, setBrands] = useState([]); - const [categories, setCategories] = useState([]); - const [brandValues, setBrandValues] = useState([]); - const [categoryValues, setCategoryValues] = useState([]); - const [orderBy, setOrderBy] = useState(router.query?.orderBy); - const popup = useActive(); - const prefixUrl = `/shop/promo/${slug}` - const [queryFinal, setQueryFinal] = useState({}); - const [limit, setLimit] = useState(30); - const [q, setQ] = useState('**'); - const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); - const [products, setProducts] = useState(null); - useEffect(() => { - setQueryFinal({ ...finalQuery, q, limit, orderBy }); -}, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); - useEffect(() => { - setQueryFinal({ ...finalQuery, q, limit, orderBy }); - }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); - - const { productSearch } = useProductSearch({ - query: queryFinal, - operation: 'OR', - }); - - console.log("productSearch",productSearch) - console.log("queryFinal",queryFinal) - - 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; - - useEffect(() => { - setProducts(productSearch.data?.response?.products); - }, [productSearch]); - - console.log("products",products) - - useEffect(() => { - if (router.query.brand) { - let brandsArray: string[] = []; - if (Array.isArray(router.query.brand)) { - brandsArray = router.query.brand; - } else if (typeof router.query.brand === 'string') { - brandsArray = router.query.brand.split(',').map((brand) => brand.trim()); - } - setBrandValues(brandsArray); - } else { - setBrandValues([]); - } - - if (router.query.category) { - let categoriesArray: string[] = []; - - if (Array.isArray(router.query.category)) { - categoriesArray = router.query.category; - } else if (typeof router.query.category === 'string') { - categoriesArray = router.query.category.split(',').map((category) => category.trim()); - } - setCategoryValues(categoriesArray); - } else { - setCategoryValues([]); - } - }, [router.query.brand, router.query.category]); - - interface Brand { - brand: string; - qty: number; - } - - interface Category { - name: string; - qty: number; - } - - useEffect(() => { - const loadPromo = async () => { - 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}`,0,10); - setPromoItems(items); - - if (items.length === 0) { - setPromoData([]) - setLoading(false); - return; - } - - const brandArray = Array.isArray(brand) ? brand : brand.split(','); - const categoryArray = Array.isArray(category) ? category : category.split(','); - - const promoDataPromises = items.map(async (item) => { - - try { - 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; - } - - 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; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`,0,100); - return response2; - }else if(combinedQuery){ - const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); - const product = response.response.docs[0]; - const product_id = product.id; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `,0,100); - return response2; - } else { - const response = await fetchPromoItemsSolr(`id:${item.id}`,0,100); - return response; - } - } catch (fetchError) { - return []; - } - }); - - const promoDataArray = await Promise.all(promoDataPromises); - const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); - setPromoData(mergedPromoData); - - const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { - if (promoData) { - const dataBrandCategory = promoData.map(async (item) => { - let response; - if(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}`) - } - - - if (response.response?.docs?.length > 0) { - const product = response.response.docs[0]; - const manufactureNameS = product.manufacture_name; - if (Array.isArray(manufactureNameS)) { - for (let i = 0; i < manufactureNameS.length; i += 2) { - const brand = manufactureNameS[i]; - const qty = 1; - const existingBrandIndex = brandsData.findIndex(b => b.brand === brand); - if (existingBrandIndex !== -1) { - brandsData[existingBrandIndex].qty += qty; - } else { - brandsData.push({ brand, qty }); - } - } - } - - const categoryNameS = product.category_name; - if (Array.isArray(categoryNameS)) { - for (let i = 0; i < categoryNameS.length; i += 2) { - const name = categoryNameS[i]; - const qty = 1; - const existingCategoryIndex = categoriesData.findIndex(c => c.name === name); - if (existingCategoryIndex !== -1) { - categoriesData[existingCategoryIndex].qty += qty; - } else { - categoriesData.push({ name, qty }); - } - } - } - } - }); - - return Promise.all(dataBrandCategory); - } - }); - - await Promise.all(dataBrandCategoryPromises); - setBrands(brandsData); - setCategories(categoriesData); - setLoading(false); - - } catch (loadError) { - // console.error("Error loading promo items:", loadError) - setLoading(false); - } - } - - if (slug) { - loadPromo() - } - },[slug, brand, category, priceFrom, priceTo, currentPage]); - - - function capitalizeFirstLetter(string) { - string = string.replace(/_/g, ' '); - return string.replace(/(^\w|\s\w)/g, function(match) { - return match.toUpperCase(); - }); - } - - const handleDeleteFilter = async (source, value) => { - let params = { - q: router.query.q, - 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 = ''; - params.priceTo = ''; - break; - case 'delete': - params = { - q: router.query.q, - orderBy: '', - brand: '', - category: '', - priceFrom: '', - priceTo: '', - }; - break; - } - - handleSubmitFilter(params); - }; - const handleSubmitFilter = (params) => { - params = _.pickBy(params, _.identity); - params = toQuery(params); - router.push(`${slug}?${params}`); - }; - - const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) - - 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']) - const queryString = toQuery(queryWithoutSlug) - - return ( - - - - -
    -

    Promo {whatPromo}

    - - - {promoItems.length >= 1 && ( -
    -
    - -
    -
    - )} - - {loading ? ( -
    - -
    - ) : promoData && promoItems.length >= 1 ? ( - <> -
    - {visiblePromotions?.map((promotion) => ( -
    - -
    - ))} -
    - - ) : ( -
    -

    Belum ada promo pada kategori ini

    -
    - )} - - - -
    - -
    - -
    -
    -

    Promo {whatPromo}

    -
    - -
    - - -
    -
    - - -
    -
    - {loading ? ( -
    - -
    - ) : promoData && promoItems.length >= 1 ? ( - <> -
    - {visiblePromotions?.map((promotion) => ( -
    - -
    - ))} -
    - - ) : ( -
    -

    Belum ada promo pada kategori ini

    -
    - )} -
    -
    - -
    - - Barang yang anda cari tidak ada?{' '} - - Hubungi Kami - - -
    -
    - - - - -
    - -
    -
    -
    -
    - ) - } - -const FilterChoicesComponent = ({ - brandValues, - categoryValues, - priceFrom, - priceTo, - handleDeleteFilter, - }) => ( -
    - - {brandValues?.map((value, index) => ( - - {value} - handleDeleteFilter('brands', value)} /> - - ))} - - {categoryValues?.map((value, index) => ( - - {value} - handleDeleteFilter('category', value)} - /> - - ))} - {priceFrom && priceTo && ( - - - {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)} - - handleDeleteFilter('price', priceFrom)} - /> - - )} - {brandValues?.length > 0 || - categoryValues?.length > 0 || - priceFrom || - priceTo ? ( - - - - ) : ( - '' - )} - -
    -); diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index e93b0b54..7a115753 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -1,4 +1,4 @@ -const map = (promotions) => { +export const promoMappingSolr = (promotions, pricelist) => { const result = []; for (const promotion of promotions) { const data = { -- cgit v1.2.3 From 52b6604cac87d06500597de8dd56be61eb6fad10 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 14:46:44 +0700 Subject: update category management --- src/lib/home/components/CategoryDynamic.jsx | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index 0ab9312a..c257e9f9 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -13,32 +13,32 @@ import { Navigation, Pagination, Autoplay } from 'swiper'; const CategoryDynamic = () => { const { categoryManagement } = useCategoryManagement(); - const [categoryData, setCategoryData] = useState({}); - const [subCategoryData, setSubCategoryData] = useState({}); + // const [categoryData, setCategoryData] = useState({}); + // const [subCategoryData, setSubCategoryData] = useState({}); - useEffect(() => { - const fetchCategoryData = async () => { - if (categoryManagement && categoryManagement.data) { - const updatedCategoryData = {}; - const updatedSubCategoryData = {}; + // useEffect(() => { + // const fetchCategoryData = async () => { + // if (categoryManagement && categoryManagement.data) { + // const updatedCategoryData = {}; + // const updatedSubCategoryData = {}; - for (const category of categoryManagement.data) { - const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); + // for (const category of categoryManagement.data) { + // const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); - updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; + // updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; - for (const subCategory of countLevel1?.children) { - updatedSubCategoryData[subCategory.id] = subCategory?.numFound; - } - } + // for (const subCategory of countLevel1?.children) { + // updatedSubCategoryData[subCategory.id] = subCategory?.numFound; + // } + // } - setCategoryData(updatedCategoryData); - setSubCategoryData(updatedSubCategoryData); - } - }; + // setCategoryData(updatedCategoryData); + // setSubCategoryData(updatedSubCategoryData); + // } + // }; - fetchCategoryData(); - }, [categoryManagement.isLoading]); + // fetchCategoryData(); + // }, [categoryManagement.isLoading]); const swiperBanner = { modules: [Pagination, ], @@ -54,16 +54,16 @@ const CategoryDynamic = () => { return (
    {categoryManagement && categoryManagement.data?.map((category) => { - const countLevel1 = categoryData[category.categoryIdI] || 0; + // const countLevel1 = categoryData[category.categoryIdI] || 0; return (
    {category.name}
    - + {/*

    {countLevel1} Produk tersedia

    -
    +
    */} Lihat Semua
    @@ -71,7 +71,7 @@ const CategoryDynamic = () => { {category.categories.map((subCategory) => { - const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; + // const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; return ( @@ -87,11 +87,11 @@ const CategoryDynamic = () => { />
    {subCategory?.name}
    - + {/*

    {countLevel2} Produk tersedia

    -
    +
    */} Lihat Semua
    -- cgit v1.2.3 From b30e6a53d660f9ccbc0ded640c2a1dc5df673ff2 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 16:43:25 +0700 Subject: update fetch data --- src/lib/product/api/productSearchApi.js | 2 +- src/lib/product/components/ProductSearch.jsx | 1 - src/lib/promo/api/productSearchApi.js | 12 ++++++++++++ src/lib/promo/hooks/usePromotionSearch.js | 15 +++++++++++++++ src/pages/api/shop/promo.js | 6 +++--- src/pages/shop/promo/[slug].jsx | 6 +++--- src/utils/solrMapping.js | 12 +++++------- 7 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 src/lib/promo/api/productSearchApi.js create mode 100644 src/lib/promo/hooks/usePromotionSearch.js (limited to 'src') diff --git a/src/lib/product/api/productSearchApi.js b/src/lib/product/api/productSearchApi.js index 670661aa..8ff8e57d 100644 --- a/src/lib/product/api/productSearchApi.js +++ b/src/lib/product/api/productSearchApi.js @@ -3,7 +3,7 @@ import axios from 'axios' const productSearchApi = async ({ query, operation = 'OR' }) => { const dataProductSearch = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}` + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}` ) return dataProductSearch.data } diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 1f083722..ab55cae0 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -87,7 +87,6 @@ const ProductSearch = ({ recurse(category); return ids; }; - console.log("queryFinal",queryFinal) useEffect(() => { if(prefixUrl.includes('category')){ const ids = collectIds(dataCategoriesProduct); diff --git a/src/lib/promo/api/productSearchApi.js b/src/lib/promo/api/productSearchApi.js new file mode 100644 index 00000000..582b4486 --- /dev/null +++ b/src/lib/promo/api/productSearchApi.js @@ -0,0 +1,12 @@ +import _ from 'lodash-contrib' +import axios from 'axios' + +const productSearchApi = async ({ query, operation = 'AND' }) => { + const dataProductSearch = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}` + ) + console.log("dataProductSearch.data",dataProductSearch.data) + return dataProductSearch.data +} + +export default productSearchApi diff --git a/src/lib/promo/hooks/usePromotionSearch.js b/src/lib/promo/hooks/usePromotionSearch.js new file mode 100644 index 00000000..1a194646 --- /dev/null +++ b/src/lib/promo/hooks/usePromotionSearch.js @@ -0,0 +1,15 @@ +import { useQuery } from 'react-query' +import productSearchApi from '../api/productSearchApi' +import _ from 'lodash-contrib' + +const usePromotionSearch = ({ query, operation }) => { + const queryString = _.toQuery(query) + const fetchProductSearch = async () => await productSearchApi({ query: queryString , operation : operation}) + const productSearch = useQuery(`promoSearch-${queryString}`, fetchProductSearch) + + return { + productSearch + } +} + +export default usePromotionSearch diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js index 353ff3df..e6867e89 100644 --- a/src/pages/api/shop/promo.js +++ b/src/pages/api/shop/promo.js @@ -108,12 +108,12 @@ export default async function handler(req, res) { let result = await axios( process.env.SOLR_HOST + '/solr/promotion_program_lines/select?' + parameter.join('&') ); - console.log("result",result) try { result.data.response.products = promoMappingSolr( - result.data.response.docs, - auth?.pricelist || false + result.data.response.docs ); + console.log("result.data.response.products",result.data.response.products) + result.data.responseHeader.params.start = parseInt( result.data.responseHeader.params.start ); diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx index 544286f9..ce73ebd1 100644 --- a/src/pages/shop/promo/[slug].jsx +++ b/src/pages/shop/promo/[slug].jsx @@ -24,7 +24,7 @@ import whatsappUrl from '../../../core/utils/whatsappUrl.js'; import { cons, toQuery } from 'lodash-contrib'; import _ from 'lodash'; import useActive from '../../../core/hooks/useActive.js'; -import useProductSearch from '../../../lib/product/hooks/useProductSearch.js'; +import useProductSearch from '../../../lib/promo/hooks/usePromotionSearch.js'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) @@ -45,7 +45,7 @@ export default function PromoDetail() { const popup = useActive(); const prefixUrl = `/shop/promo/${slug}` const [queryFinal, setQueryFinal] = useState({}); - const [limit, setLimit] = useState(30); + const [limit, setLimit] = useState(30); const [q, setQ] = useState('*'); const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); const [products, setProducts] = useState(null); @@ -365,7 +365,7 @@ export default function PromoDetail() { ) : promoData && promoItems.length >= 1 ? ( <>
    - {visiblePromotions?.map((promotion) => ( + {products?.map((promotion) => (
    diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index 7a115753..637d7c09 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -1,7 +1,6 @@ -export const promoMappingSolr = (promotions, pricelist) => { - const result = []; - for (const promotion of promotions) { - const data = { +export const promoMappingSolr = (promotions) => { + return promotions.map((promotion) =>{ + let productMapped = { id: promotion.id, program_id: promotion.program_id_i, name: promotion.name_s, @@ -20,9 +19,8 @@ export const promoMappingSolr = (promotions, pricelist) => { qty_sold_f:promotion.total_qty_sold_f, free_products: JSON.parse(promotion.free_products_s), }; - result.push(data); - } - return result; + return productMapped; + }) }; -- cgit v1.2.3 From 8d0e7bfbd4da7908ac5b0195185fbd574958a1cb Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 16:55:04 +0700 Subject: update mobile view --- src/lib/home/components/CategoryDynamicMobile.jsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx index 4d2fa0ec..2877a5a7 100644 --- a/src/lib/home/components/CategoryDynamicMobile.jsx +++ b/src/lib/home/components/CategoryDynamicMobile.jsx @@ -63,7 +63,6 @@ const CategoryDynamicMobile = () => { />
    {index.name}
    -

    999 rb+ Produk

    -- cgit v1.2.3 From 68ec9564aef424b86702512637c9cb738b44f215 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 2 Sep 2024 17:11:10 +0700 Subject: update search --- src/pages/api/shop/promo.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js index e6867e89..61fff4e5 100644 --- a/src/pages/api/shop/promo.js +++ b/src/pages/api/shop/promo.js @@ -122,7 +122,8 @@ export default async function handler(req, res) { ); delete result.data.response.docs; console.log("result.data",result.data) - result.data = camelcaseObjectDeep(result.data); + // result.data = camelcaseObjectDeep(result.data); + result.data = result.data; res.status(200).json(result.data); } catch (error) { res.status(400).json({ error: error.message }); -- cgit v1.2.3 From dab7f8a1ebd135d9335f1a53346c91d32a2be9f9 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 3 Sep 2024 08:46:46 +0700 Subject: update tempt --- src/pages/shop/promo/[slug].jsx | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx index ce73ebd1..71ce8344 100644 --- a/src/pages/shop/promo/[slug].jsx +++ b/src/pages/shop/promo/[slug].jsx @@ -37,7 +37,7 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const [loading, setLoading] = useState(true); const { isMobile, isDesktop } = useDevice() - const [brands, setBrands] = useState([]); + // const [brands, setBrands] = useState([]); const [categories, setCategories] = useState([]); const [brandValues, setBrandValues] = useState([]); const [categoryValues, setCategoryValues] = useState([]); @@ -75,7 +75,20 @@ export default function PromoDetail() { console.log("products",products) - + const brands = []; + for ( + let i = 0; + i < productSearch.data?.facetCounts?.facetFields?.manufactureNameS.length; + i += 2 + ) { + const brand = + productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i]; + const qty = + productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1]; + if (qty > 0) { + brands.push({ brand, qty }); + } + } @@ -403,13 +416,13 @@ export default function PromoDetail() {
    - + /> */}
    @@ -470,8 +483,8 @@ export default function PromoDetail() { -- cgit v1.2.3 From 39cf7a6066d3b7064cb57e4f5583232b4d4d2292 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 3 Sep 2024 08:53:30 +0700 Subject: delete popular brand --- src/lib/category/components/Category.jsx | 4 +- src/lib/category/components/PopularBrand.jsx | 88 ++++++++++++++-------------- 2 files changed, 46 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx index f76e6e42..91553295 100644 --- a/src/lib/category/components/Category.jsx +++ b/src/lib/category/components/Category.jsx @@ -86,14 +86,14 @@ const Category = () => {
    ))}
    -
    + {/*
    {Array.isArray(promotionProgram?.data) && promotionProgram?.data.length > 0 && promotionProgram?.data[0]?.map((banner, index) => (
    {`${banner.name}`}
    ))} -
    +
    */}
    ))} diff --git a/src/lib/category/components/PopularBrand.jsx b/src/lib/category/components/PopularBrand.jsx index 4777fded..8124b5b4 100644 --- a/src/lib/category/components/PopularBrand.jsx +++ b/src/lib/category/components/PopularBrand.jsx @@ -13,60 +13,60 @@ import { fetchPopulerProductSolr } from '../api/popularProduct' const SOLR_HOST = process.env.SOLR_HOST const PopularBrand = ({ category }) => { - const [topBrands, setTopBrands] = useState([]); + // const [topBrands, setTopBrands] = useState([]); - const fetchTopBrands = async () => { - try { - const items = await fetchPopulerProductSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`); - const getTop12UniqueBrands = (prod) => { - const brandMap = new Map(); + // const fetchTopBrands = async () => { + // try { + // const items = await fetchPopulerProductSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`); + // const getTop12UniqueBrands = (prod) => { + // const brandMap = new Map(); - for (const product of prod) { - const { manufacture_name, manufacture_id, qty_sold } = product; + // for (const product of prod) { + // const { manufacture_name, manufacture_id, qty_sold } = product; - if (brandMap.has(manufacture_name)) { - // Update the existing brand's qty_sold - brandMap.set(manufacture_name, { - name: manufacture_name, - id: manufacture_id, - qty_sold: brandMap.get(manufacture_name).qty_sold + qty_sold - }); - } else { - // Add a new brand to the map - brandMap.set(manufacture_name, { - name: manufacture_name, - id: manufacture_id, - qty_sold - }); - } - } + // if (brandMap.has(manufacture_name)) { + // // Update the existing brand's qty_sold + // brandMap.set(manufacture_name, { + // name: manufacture_name, + // id: manufacture_id, + // qty_sold: brandMap.get(manufacture_name).qty_sold + qty_sold + // }); + // } else { + // // Add a new brand to the map + // brandMap.set(manufacture_name, { + // name: manufacture_name, + // id: manufacture_id, + // qty_sold + // }); + // } + // } - // Convert the map to an array and sort by qty_sold in descending order - const sortedBrands = Array.from(brandMap.values()).sort((a, b) => b.qty_sold - a.qty_sold); + // // Convert the map to an array and sort by qty_sold in descending order + // const sortedBrands = Array.from(brandMap.values()).sort((a, b) => b.qty_sold - a.qty_sold); - // Return the top 12 brands - return sortedBrands.slice(0, 18); - }; + // // Return the top 12 brands + // return sortedBrands.slice(0, 18); + // }; - // Using the fetched products - const products = items; - const top12UniqueBrands = getTop12UniqueBrands(products); + // // Using the fetched products + // const products = items; + // const top12UniqueBrands = getTop12UniqueBrands(products); - // Set the top 12 brands to the state - setTopBrands(top12UniqueBrands); - } catch (error) { - console.error("Error fetching data from Solr", error); - throw error; - } - } + // // Set the top 12 brands to the state + // setTopBrands(top12UniqueBrands); + // } catch (error) { + // console.error("Error fetching data from Solr", error); + // throw error; + // } + // } - useEffect(() => { - fetchTopBrands(); - }, [category]); + // useEffect(() => { + // fetchTopBrands(); + // }, [category]); return (
    -
    + {/*
    {topBrands.map((brand, index) => (
    {
    ))} -
    +
    */} {/* {topBrands.length > 8 && (
    Date: Tue, 3 Sep 2024 11:01:30 +0700 Subject: fixing feedback pak iwan (point 5) --- src/lib/checkout/components/Checkout.jsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 54acdf7c..22265734 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -174,7 +174,6 @@ const Checkout = () => { } return; // Hentikan eksekusi lebih lanjut pada iterasi ini } - // Memeriksa apakah subtotal memenuhi syarat minimal pembelian if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) { SetSelisihHargaCode( @@ -191,7 +190,9 @@ const Checkout = () => { // Tambahkan voucher ke list dan set voucher aktif SetListVoucher((prevList) => [addNewLine, ...prevList]); - SetActiveVoucher(addNewLine.code); + if (addNewLine.canApply) { + SetActiveVoucher(addNewLine.code); + } } else { // Mencari voucher dalam listVoucherShippings let checkList = listVoucherShippings?.findIndex( @@ -227,7 +228,9 @@ const Checkout = () => { // Tambahkan voucher ke list pengiriman dan set voucher aktif pengiriman SetListVoucherShipping((prevList) => [addNewLine, ...prevList]); - setActiveVoucherShipping(addNewLine.code); + if (addNewLine.canApply) { + setActiveVoucherShipping(addNewLine.code); + } } }); @@ -701,7 +704,9 @@ const Checkout = () => { {listVoucherShippings && listVoucherShippings?.length > 0 && (
    -

    Promo Extra Potongan Ongkir

    +

    + Promo Extra Potongan Ongkir +

    {listVoucherShippings?.map((item) => (
    Date: Tue, 3 Sep 2024 12:19:44 +0700 Subject: update tempt --- src/pages/api/shop/promo.js | 6 ++++-- src/pages/shop/promo/[slug].jsx | 27 ++++++++++++++++++++++----- src/utils/solrMapping.js | 6 ++++-- 3 files changed, 30 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js index 61fff4e5..57635958 100644 --- a/src/pages/api/shop/promo.js +++ b/src/pages/api/shop/promo.js @@ -49,8 +49,8 @@ export default async function handler(req, res) { let offset = (page - 1) * limit; let parameter = [ - // 'facet.field=manufacture_name_s', - // 'facet.field=category_name', + 'facet.field=manufacture_name_s', + 'facet.field=category_name', 'facet=true', 'indent=true', // `facet.query=${escapeSolrQuery(q)}`, @@ -108,7 +108,9 @@ export default async function handler(req, res) { let result = await axios( process.env.SOLR_HOST + '/solr/promotion_program_lines/select?' + parameter.join('&') ); + console.log("result",result.data) try { + console.log("result.data.response.docs",result.data.response.docs) result.data.response.products = promoMappingSolr( result.data.response.docs ); diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx index 71ce8344..169ea0b5 100644 --- a/src/pages/shop/promo/[slug].jsx +++ b/src/pages/shop/promo/[slug].jsx @@ -38,14 +38,14 @@ export default function PromoDetail() { const [loading, setLoading] = useState(true); const { isMobile, isDesktop } = useDevice() // const [brands, setBrands] = useState([]); - const [categories, setCategories] = useState([]); + // const [categories, setCategories] = useState([]); const [brandValues, setBrandValues] = useState([]); const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy); const popup = useActive(); const prefixUrl = `/shop/promo/${slug}` const [queryFinal, setQueryFinal] = useState({}); - const [limit, setLimit] = useState(30); + const [limit, setLimit] = useState(22); const [q, setQ] = useState('*'); const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); const [products, setProducts] = useState(null); @@ -78,18 +78,35 @@ export default function PromoDetail() { const brands = []; for ( let i = 0; - i < productSearch.data?.facetCounts?.facetFields?.manufactureNameS.length; + i < productSearch.data?.facet_counts?.facet_fields?.manufacture_name_s.length; i += 2 ) { const brand = - productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i]; + productSearch.data?.facet_counts?.facet_fields?.manufacture_name_s[i]; const qty = - productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1]; + productSearch.data?.facet_counts?.facet_fields?.manufacture_name_s[i + 1]; if (qty > 0) { brands.push({ brand, qty }); } } + console.log("brands",brands) + + const categories = []; + for ( + let i = 0; + i < productSearch.data?.facet_counts?.facet_fields?.category_name.length; + i += 2 + ) { + 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) { + categories.push({ name, qty }); + } + } + + diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index 637d7c09..15bf3afb 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -14,11 +14,13 @@ export const promoMappingSolr = (promotions) => { price: promotion.price_f, sequence: promotion.sequence_i, total_qty: promotion.total_qty_i, - products: JSON.parse(promotion.products_s), + products: JSON.parse(promotion.products_s) || '', product_id: promotion.product_ids[0], qty_sold_f:promotion.total_qty_sold_f, - free_products: JSON.parse(promotion.free_products_s), + free_products: JSON.parse(promotion.free_products_s) }; + console.log("productMapped",productMapped) + // console.log("promotions",promotions) return productMapped; }) }; -- cgit v1.2.3 From ad168bf46919b46f708625b7d2fdc56606ec9af6 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 3 Sep 2024 14:01:02 +0700 Subject: update all promo fix --- src/lib/promo/api/productSearchApi.js | 1 - src/pages/api/shop/promo.js | 15 +- src/pages/shop/promo/[slug].jsx | 272 ++++++---------------------------- src/utils/solrMapping.js | 2 - 4 files changed, 47 insertions(+), 243 deletions(-) (limited to 'src') diff --git a/src/lib/promo/api/productSearchApi.js b/src/lib/promo/api/productSearchApi.js index 582b4486..2f792fd4 100644 --- a/src/lib/promo/api/productSearchApi.js +++ b/src/lib/promo/api/productSearchApi.js @@ -5,7 +5,6 @@ const productSearchApi = async ({ query, operation = 'AND' }) => { const dataProductSearch = await axios( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}` ) - console.log("dataProductSearch.data",dataProductSearch.data) return dataProductSearch.data } diff --git a/src/pages/api/shop/promo.js b/src/pages/api/shop/promo.js index 57635958..221a9adb 100644 --- a/src/pages/api/shop/promo.js +++ b/src/pages/api/shop/promo.js @@ -3,7 +3,6 @@ import axios from 'axios'; import camelcaseObjectDeep from 'camelcase-object-deep'; export default async function handler(req, res) { - console.log("req_iman",req) const { q = '*', page = 1, @@ -11,7 +10,7 @@ export default async function handler(req, res) { category = '', priceFrom = 0, priceTo = 0, - orderBy = '', + orderBy = 'if(exists(sequence_i),0,1) asc, sequence_i asc,', operation = 'AND', fq = '', limit = 30, @@ -19,7 +18,7 @@ export default async function handler(req, res) { let { stock = '' } = req.query; - let paramOrderBy = ''; + let paramOrderBy = 'if(exists(sequence_i),0,1) asc, sequence_i asc,'; switch (orderBy) { case 'price-asc': paramOrderBy += 'price_tier1_v2_f ASC'; @@ -60,7 +59,7 @@ export default async function handler(req, res) { `start=${parseInt(offset)}`, `rows=${limit}`, `sort=${paramOrderBy}`, - // `fq=-publish_b:false, product_rating_f:[8 TO *], price_tier1_v2_f:[1 TO *]`, + `fq=product_ids:[* TO *]`, ]; if (priceFrom > 0 || priceTo > 0) { @@ -83,7 +82,7 @@ export default async function handler(req, res) { .split(',') .map( (manufacturer) => - `manufacture_name:"${encodeURIComponent(manufacturer)}"` + `manufacture_name_s:"${encodeURIComponent(manufacturer)}"` ) .join(' OR ')}` ); @@ -102,19 +101,14 @@ export default async function handler(req, res) { // Multi fq in url params if (Array.isArray(fq)) parameter = parameter.concat(fq.map((val) => `fq=${val}`)); - - console.log("parameter",parameter) let result = await axios( process.env.SOLR_HOST + '/solr/promotion_program_lines/select?' + parameter.join('&') ); - console.log("result",result.data) try { - console.log("result.data.response.docs",result.data.response.docs) result.data.response.products = promoMappingSolr( result.data.response.docs ); - console.log("result.data.response.products",result.data.response.products) result.data.responseHeader.params.start = parseInt( result.data.responseHeader.params.start @@ -123,7 +117,6 @@ export default async function handler(req, res) { result.data.responseHeader.params.rows ); delete result.data.response.docs; - console.log("result.data",result.data) // result.data = camelcaseObjectDeep(result.data); result.data = result.data; res.status(200).json(result.data); diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx index 169ea0b5..cfb2c841 100644 --- a/src/pages/shop/promo/[slug].jsx +++ b/src/pages/shop/promo/[slug].jsx @@ -4,12 +4,9 @@ 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 { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi.js' import LogoSpinner from '../../../core/components/elements/Spinner/LogoSpinner.jsx' import ProductPromoCard from '../../../../src-migrate/modules/product-promo/components/Card.tsx' -import { IPromotion } from '../../../../src-migrate/types/promotion.ts' import React from 'react' -import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; import DesktopView from '../../../core/components/views/DesktopView.jsx'; import MobileView from '../../../core/components/views/MobileView.jsx'; import 'swiper/swiper-bundle.css'; @@ -19,9 +16,7 @@ import ProductFilter from '../../../lib/product/components/ProductFilter.jsx'; import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react'; import { formatCurrency } from '../../../core/utils/formatValue.js'; import Pagination from '../../../core/components/elements/Pagination/Pagination.js'; -import SideBanner from '../../../../src-migrate/modules/side-banner/index.tsx'; import whatsappUrl from '../../../core/utils/whatsappUrl.js'; -import { cons, toQuery } from 'lodash-contrib'; import _ from 'lodash'; import useActive from '../../../core/hooks/useActive.js'; import useProductSearch from '../../../lib/promo/hooks/usePromotionSearch.js'; @@ -30,39 +25,54 @@ const BasicLayout = dynamic(() => import('../../../core/components/layouts/Basic export default function PromoDetail() { const router = useRouter() - const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query - const [promoItems, setPromoItems] = useState([]) - const [promoData, setPromoData] = useState(null) + const { slug = '', brand ='', category='', page = '1' } = router.query const [currentPage, setCurrentPage] = useState(parseInt(10) || 1); - const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman - const [loading, setLoading] = useState(true); - const { isMobile, isDesktop } = useDevice() - // const [brands, setBrands] = useState([]); - // const [categories, setCategories] = useState([]); - const [brandValues, setBrandValues] = useState([]); - const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy); const popup = useActive(); const prefixUrl = `/shop/promo/${slug}` const [queryFinal, setQueryFinal] = useState({}); - const [limit, setLimit] = useState(22); + const [limit, setLimit] = useState(30); const [q, setQ] = useState('*'); - const [finalQuery, setFinalQuery] = useState({fq: `type_value_s:${slug}`}); + const [finalQuery, setFinalQuery] = useState({}); const [products, setProducts] = useState(null); + const [brandValues, setBrand] = useState( + !router.pathname.includes('brands') + ? router.query.brand + ? router.query.brand.split(',') + : [] + : [] + ); + + 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(() => { - setQueryFinal({ ...finalQuery, q, limit, orderBy }); + 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 : '' + }; + setFinalQuery(newQuery); }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); useEffect(() => { setQueryFinal({ ...finalQuery, q, limit, orderBy }); - }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage]); + }, [router.query, prefixUrl, slug, brand, category, priceFrom, priceTo, currentPage, finalQuery]); const { productSearch } = useProductSearch({ query: queryFinal, operation: 'OR', }); - console.log("productSearch",productSearch) - console.log("queryFinal",queryFinal) const pageCount = Math.ceil(productSearch.data?.response.numFound / limit); const productStart = productSearch.data?.responseHeader.params.start; @@ -73,8 +83,6 @@ export default function PromoDetail() { setProducts(productSearch.data?.response?.products); }, [productSearch]); - console.log("products",products) - const brands = []; for ( let i = 0; @@ -90,8 +98,6 @@ export default function PromoDetail() { } } - console.log("brands",brands) - const categories = []; for ( let i = 0; @@ -105,190 +111,6 @@ export default function PromoDetail() { categories.push({ name, qty }); } } - - - - - - - useEffect(() => { - if (router.query.brand) { - let brandsArray= []; - if (Array.isArray(router.query.brand)) { - brandsArray = router.query.brand; - } else if (typeof router.query.brand === 'string') { - brandsArray = router.query.brand.split(',').map((brand) => brand.trim()); - } - setBrandValues(brandsArray); - } else { - setBrandValues([]); - } - - if (router.query.category) { - let categoriesArray= []; - - if (Array.isArray(router.query.category)) { - categoriesArray = router.query.category; - } else if (typeof router.query.category === 'string') { - categoriesArray = router.query.category.split(',').map((category) => category.trim()); - } - setCategoryValues(categoriesArray); - } else { - setCategoryValues([]); - } - }, [router.query.brand, router.query.category]); - - useEffect(() => { - const loadPromo = async () => { - setLoading(true); - const brandsData = []; - const categoriesData= []; - - 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}`,0,10); - setPromoItems(items); - - if (items.length === 0) { - setPromoData([]) - setLoading(false); - return; - } - - const brandArray = Array.isArray(brand) ? brand : brand.split(','); - const categoryArray = Array.isArray(category) ? category : category.split(','); - - const promoDataPromises = items.map(async (item) => { - - try { - 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; - } - - 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; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`,0,100); - return response2; - }else if(combinedQuery){ - const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); - const product = response.response.docs[0]; - const product_id = product.id; - const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `,0,100); - return response2; - } else { - const response = await fetchPromoItemsSolr(`id:${item.id}`,0,100); - return response; - } - } catch (fetchError) { - return []; - } - }); - - const promoDataArray = await Promise.all(promoDataPromises); - const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); - setPromoData(mergedPromoData); - - const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { - if (promoData) { - const dataBrandCategory = promoData.map(async (item) => { - let response; - if(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}`) - } - - - if (response.response?.docs?.length > 0) { - const product = response.response.docs[0]; - const manufactureNameS = product.manufacture_name; - if (Array.isArray(manufactureNameS)) { - for (let i = 0; i < manufactureNameS.length; i += 2) { - const brand = manufactureNameS[i]; - const qty = 1; - const existingBrandIndex = brandsData.findIndex(b => b.brand === brand); - if (existingBrandIndex !== -1) { - brandsData[existingBrandIndex].qty += qty; - } else { - brandsData.push({ brand, qty }); - } - } - } - - const categoryNameS = product.category_name; - if (Array.isArray(categoryNameS)) { - for (let i = 0; i < categoryNameS.length; i += 2) { - const name = categoryNameS[i]; - const qty = 1; - const existingCategoryIndex = categoriesData.findIndex(c => c.name === name); - if (existingCategoryIndex !== -1) { - categoriesData[existingCategoryIndex].qty += qty; - } else { - categoriesData.push({ name, qty }); - } - } - } - } - }); - - return Promise.all(dataBrandCategory); - } - }); - - await Promise.all(dataBrandCategoryPromises); - setBrands(brandsData); - setCategories(categoriesData); - setLoading(false); - - } catch (loadError) { - // console.error("Error loading promo items:", loadError) - setLoading(false); - } - } - - if (slug) { - loadPromo() - } - },[slug, brand, category, priceFrom, priceTo, currentPage]); - function capitalizeFirstLetter(string) { string = string.replace(/_/g, ' '); @@ -302,7 +124,7 @@ export default function PromoDetail() { q: router.query.q, orderBy: '', brand: brandValues.join(','), - category: categoryValues.join(','), + category: categoryValues?.join(','), priceFrom: priceFrom || '', priceTo: priceTo || '', }; @@ -344,7 +166,6 @@ export default function PromoDetail() { router.push(`${slug}?${params}`); }; - const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) const toQuery = (obj) => { const str = Object.keys(obj) @@ -355,7 +176,6 @@ export default function PromoDetail() { const whatPromo = capitalizeFirstLetter(slug) const queryWithoutSlug = _.omit(router.query, ['slug']) - const queryString = toQuery(queryWithoutSlug) return ( @@ -375,7 +195,7 @@ export default function PromoDetail() { priceTo={priceTo} handleDeleteFilter={handleDeleteFilter} /> - {promoItems.length >= 1 && ( + {products?.length >= 1 && (
    )} - - {loading ? ( -
    + {productSearch.isLoading &&
    -
    - ) : promoData && promoItems.length >= 1 ? ( +
    } + {products && ( <>
    {products?.map((promotion) => ( @@ -402,15 +220,11 @@ export default function PromoDetail() { ))}
    - ) : ( -
    -

    Belum ada promo pada kategori ini

    -
    - )} + ) } @@ -433,13 +247,13 @@ export default function PromoDetail() {
    - {/* */} + />
    @@ -451,11 +265,11 @@ export default function PromoDetail() { />
    - {loading ? ( + {productSearch.isLoading ? (
    - ) : promoData && promoItems.length >= 1 ? ( + ) : products && products.length >= 1 ? ( <>
    {products?.map((promotion) => ( diff --git a/src/utils/solrMapping.js b/src/utils/solrMapping.js index 15bf3afb..0d50b99b 100644 --- a/src/utils/solrMapping.js +++ b/src/utils/solrMapping.js @@ -19,8 +19,6 @@ export const promoMappingSolr = (promotions) => { qty_sold_f:promotion.total_qty_sold_f, free_products: JSON.parse(promotion.free_products_s) }; - console.log("productMapped",productMapped) - // console.log("promotions",promotions) return productMapped; }) }; -- cgit v1.2.3 From ab0402c015fc5346eed00267d4e9b10dd77dc823 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Tue, 3 Sep 2024 14:03:05 +0700 Subject: bug fix checout mobile --- src/lib/checkout/components/Checkout.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 22265734..f5975a99 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1241,10 +1241,10 @@ const Checkout = () => { className='object-contain object-center h-6 rounded-md' /> - {activeVoucher ? ( + {activeVoucher || activeVoucherShipping ? (
    - Potongan Senilai {currencyFormat(discountVoucher)} + Potongan Senilai {currencyFormat(totalDiscountVoucher)}
    Voucher berhasil digunakan -- cgit v1.2.3 From 35850040a2e49d140d5ecf406dc1769e81badbf6 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Tue, 3 Sep 2024 15:02:19 +0700 Subject: add link wa --- src/lib/checkout/components/Checkout.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index f5975a99..913bd273 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1033,7 +1033,7 @@ const Checkout = () => {
    Jika mengalami kesulitan dalam melakukan pembelian di website - Indoteknik. Hubungi kami disini + Indoteknik. Hubungi kami disini
    -- cgit v1.2.3 From 985f29aa1d9b8cbea49d25c30099f88c86bdc13f Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 4 Sep 2024 09:10:28 +0700 Subject: noindex and nofollw in page variants --- src/pages/shop/product/variant/[slug].jsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/pages/shop/product/variant/[slug].jsx b/src/pages/shop/product/variant/[slug].jsx index cb335e0a..42f38774 100644 --- a/src/pages/shop/product/variant/[slug].jsx +++ b/src/pages/shop/product/variant/[slug].jsx @@ -69,6 +69,8 @@ export default function ProductDetail({ product }) { Date: Wed, 4 Sep 2024 15:18:38 +0700 Subject: cr sitemaps --- src/pages/sitemap/brands.xml.js | 4 ++-- src/pages/sitemap/products/[page].js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pages/sitemap/brands.xml.js b/src/pages/sitemap/brands.xml.js index c85c40e9..65a84e97 100644 --- a/src/pages/sitemap/brands.xml.js +++ b/src/pages/sitemap/brands.xml.js @@ -15,8 +15,8 @@ export async function getServerSideProps({ res }) { const url = sitemap.ele('url') url.ele('loc', createSlug(baseUrl, brand.name, brand.id)) url.ele('lastmod', date.toISOString().slice(0, 10)) - url.ele('changefreq', 'weekly') - url.ele('priority', '0.6') + url.ele('changefreq', 'daily') + url.ele('priority', '1.0') }) res.setHeader('Content-Type', 'text/xml') diff --git a/src/pages/sitemap/products/[page].js b/src/pages/sitemap/products/[page].js index 2f9c3198..e39755d6 100644 --- a/src/pages/sitemap/products/[page].js +++ b/src/pages/sitemap/products/[page].js @@ -19,7 +19,7 @@ export async function getServerSideProps({ query, res }) { const url = sitemap.ele('url') url.ele('loc', createSlug(baseUrl, product.name, product.id)) url.ele('lastmod', date.toISOString().slice(0, 10)) - url.ele('changefreq', 'weekly') + url.ele('changefreq', 'daily') url.ele('priority', '0.8') }) -- cgit v1.2.3 From e07b4470ba487c01e2420a115a285e7fd4a305ce Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 4 Sep 2024 17:12:44 +0700 Subject: fixing voucher shipping --- src/lib/checkout/components/Checkout.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 913bd273..f63ef457 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -410,7 +410,7 @@ const Checkout = () => { Math.round(parseInt(finalShippingAmt * 1.1) / 1000) * 1000; const finalGT = GT < 0 ? 0 : GT; setGrandTotal(finalGT); - }, [biayaKirim, cartCheckout?.grandTotal, activeVoucher]); + }, [biayaKirim, cartCheckout?.grandTotal, activeVoucher, activeVoucherShipping]); const checkout = async () => { const file = poFile.current.files[0]; @@ -497,7 +497,7 @@ const Checkout = () => { } } - const midtrans = async () => { + /* const midtrans = async () => { for (const product of products) deleteItemCart({ productId: product.id }); if (grandTotal > 0) { const payment = await axios.post( @@ -513,7 +513,7 @@ const Checkout = () => { '-' )}`; } - }; + };*/ }; const handlingActivateCode = async () => { @@ -1189,7 +1189,7 @@ const Checkout = () => {
    Biaya Kirim

    {etdFix}

    -
    {currencyFormat(biayaKirim)}
    +
    {currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000)}
    {activeVoucherShipping && voucherShippingAmt && (
    @@ -1490,7 +1490,7 @@ const Checkout = () => { Biaya Kirim

    {etdFix}

    -
    {currencyFormat(biayaKirim)}
    +
    {currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000) }
    {activeVoucherShipping && voucherShippingAmt && (
    -- cgit v1.2.3 From 969ca83a9adce96b3b58973654b29d3c2dd47a88 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 5 Sep 2024 17:49:57 +0700 Subject: update mapping solr --- src/lib/home/api/categoryManagementApi.js | 47 +++++++++++++++++++++++++---- src/lib/home/components/CategoryDynamic.jsx | 25 ++++++++++++++- 2 files changed, 65 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js index b70d60ce..63edd629 100644 --- a/src/lib/home/api/categoryManagementApi.js +++ b/src/lib/home/api/categoryManagementApi.js @@ -1,8 +1,43 @@ -import odooApi from '@/core/api/odooApi' +// import odooApi from '@/core/api/odooApi' -const categoryManagementApi = async () => { - const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management') - return dataCategoryManagement -} +// const categoryManagementApi = async () => { +// const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management') +// return dataCategoryManagement +// } -export default categoryManagementApi +// export default categoryManagementApi + + + +export const fetchPopulerProductSolr = async (category_id_ids) => { + let sort ='sort=qty_sold_f desc'; + try { + const queryParams = new URLSearchParams({ q: category_id_ids }); + const response = await fetch(`/solr/category_management/query?q=*:*&q.op=OR&indent=true`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + const promotions = await map(data.response.docs); + return promotions; + } catch (error) { + console.error("Error fetching promotion data:", error); + return []; + } + }; + + const map = async (promotions) => { + const result = []; + for (const promotion of promotions) { + const data = { + id: promotion.id, + name: promotion.name_s, + image: promotion.image_s, + sequence: promotion.sequence_i, + numFound: promotion.numFound_i, + categories_level_2:promotion.categories_level_2 + }; + result.push(data); + } + return result; + }; \ No newline at end of file diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index c257e9f9..11a15d6d 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -1,5 +1,6 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import useCategoryManagement from '../hooks/useCategoryManagement'; +import {fetchPopulerProductSolr} from '../api/categoryManagementApi' import NextImage from 'next/image'; import Link from "next/link"; import { createSlug } from '@/core/utils/slug'; @@ -12,6 +13,28 @@ import 'swiper/css/pagination'; import { Navigation, Pagination, Autoplay } from 'swiper'; const CategoryDynamic = () => { + + const [manufactures, setManufactures] = useState([]) + const loadBrand = useCallback(async () => { + // setIsLoading(true) + //Get brand from odoo + /*const result = await odooApi( + 'GET', + `/api/v1/manufacture?limit=0&offset=${manufactures.length}&name=${name}` + )*/ + + // Change get brands from solr + const items = await fetchPopulerProductSolr(); + + console.log("items",items) + + // setIsLoading(false) + // setManufactures((manufactures) => [...result.data]) + }, []) + + useEffect(() => { + loadBrand() + }, [loadBrand]) const { categoryManagement } = useCategoryManagement(); // const [categoryData, setCategoryData] = useState({}); // const [subCategoryData, setSubCategoryData] = useState({}); -- cgit v1.2.3