From c88d98f06a6301bad6dd6d2e58b4908d8562638c Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 7 Jun 2024 17:08:09 +0700 Subject: add promotion program --- .../modules/product-promo/components/Card.tsx | 144 ++++++++++++--------- src/api/promoApi.js | 12 ++ src/lib/home/components/PromotionProgram.jsx | 31 +++++ src/lib/promo/components/Promocrumb.jsx | 40 ++++++ src/pages/index.jsx | 7 + src/pages/shop/promo/[slug].jsx | 46 +++++++ src/pages/shop/promo/index.jsx | 0 7 files changed, 216 insertions(+), 64 deletions(-) create mode 100644 src/api/promoApi.js create mode 100644 src/lib/home/components/PromotionProgram.jsx create mode 100644 src/lib/promo/components/Promocrumb.jsx create mode 100644 src/pages/shop/promo/[slug].jsx create mode 100644 src/pages/shop/promo/index.jsx diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index 59110098..be7d5b6e 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -18,36 +18,47 @@ import ProductPromoCardCountdown from "./CardCountdown" type Props = { promotion: IPromotion + slug?: string } -const ProductPromoCard = ({ promotion }: Props) => { +const ProductPromoCard = ({ promotion, slug }: Props) => { const [products, setProducts] = useState([]) + const [freeProducts, setFreeProducts] = useState([]) + const [error, setError] = useState(null) useEffect(() => { const getProducts = async () => { - const datas = [] - for (const product of promotion.products) { - const res = await getVariantById(product.product_id) - res.data.qty = product.qty - datas.push(res.data) + try { + const datas = [] + for (const product of promotion.products) { + const res = await getVariantById(product.product_id) + res.data.qty = product.qty + datas.push(res.data) + } + setProducts(datas) + } catch (err) { + setError('Failed to fetch product variants.') + console.error(err) } - setProducts(datas) } getProducts() }, [promotion.products]) - const [freeProducts, setFreeProducts] = useState([]) - useEffect(() => { const getFreeProducts = async () => { - const datas = [] - for (const product of promotion.free_products) { - const res = await getVariantById(product.product_id) - res.data.qty = product.qty - datas.push(res.data) + try { + const datas = [] + for (const product of promotion.free_products) { + const res = await getVariantById(product.product_id) + res.data.qty = product.qty + datas.push(res.data) + } + setFreeProducts(datas) + } catch (err) { + setError('Failed to fetch free product variants.') + console.error(err) } - setFreeProducts(datas) } getFreeProducts() @@ -63,62 +74,67 @@ const ProductPromoCard = ({ promotion }: Props) => { const allProducts = [...products, ...freeProducts] - return ( -
- + const shouldRender = !slug || promotion.type.value === slug -
-
-
{promotion.name}
+ return ( + shouldRender && ( +
+ + +
+
+
{promotion.name}
+ + +
+ Paket {PROMO_CATEGORY[promotion.type.value].alias} + +
+
+
- -
- Paket {PROMO_CATEGORY[promotion.type.value].alias} - + 0}> + {allProducts.map((product, index) => ( + + + products.length && promotion.type.value === 'merchandise'} + // isFree={index + 1 > products.length } + /> + + + {index + 1 < allProducts.length && ( +
+ +
+ )} +
+
+ ))} +
+ +
+
+ 0}> + Rp{formatCurrency(priceTotal)} + Hemat Rp {formatCurrency(priceTotal - promotion.price)} + + +
+ Rp{formatCurrency(promotion.price)} + (Total {promotion.total_qty} barang) +
- -
- - 0}> - {allProducts.map((product, index) => ( - <> - - products.length && promotion.type.value === 'merchandise'} - /> - - - {index + 1 < allProducts.length && ( -
- -
- )} -
- - ))} -
- -
-
- 0}> - Rp{formatCurrency(priceTotal)} - Hemat Rp {formatCurrency(priceTotal - promotion.price)} - - -
- Rp{formatCurrency(promotion.price)} - (Total {promotion.total_qty} barang) +
+
-
-
- -
+
-
+ ) ) } -export default ProductPromoCard \ No newline at end of file +export default ProductPromoCard diff --git a/src/api/promoApi.js b/src/api/promoApi.js new file mode 100644 index 00000000..a4acc768 --- /dev/null +++ b/src/api/promoApi.js @@ -0,0 +1,12 @@ +// src/api/promoApi.js +import odooApi from '@/core/api/odooApi'; + +export const fetchPromoItems = async (type) => { + try { + const response = await odooApi('GET', `/api/v1/program-line?type=${type}&limit=3`); + return response.map((item) => ({ value: item.id, label: item.name, product: item.products ,price:item.price})); + } catch (error) { + console.error('Error fetching promo items:', error); + return []; + } +}; diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx new file mode 100644 index 00000000..461383a1 --- /dev/null +++ b/src/lib/home/components/PromotionProgram.jsx @@ -0,0 +1,31 @@ +import Link from '@/core/components/elements/Link/Link' +import Image from 'next/image' +import { bannerApi } from '@/api/bannerApi'; + +const { useQuery } = require('react-query') + +const BannerSection = () => { + const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); + + return ( + promotionProgram.data && + promotionProgram.data?.length > 0 && ( +
+ {promotionProgram.data?.map((banner) => ( + + {banner.name} + + ))} +
+ ) + ) +} + +export default BannerSection diff --git a/src/lib/promo/components/Promocrumb.jsx b/src/lib/promo/components/Promocrumb.jsx new file mode 100644 index 00000000..a96ec6b4 --- /dev/null +++ b/src/lib/promo/components/Promocrumb.jsx @@ -0,0 +1,40 @@ +import { Breadcrumb as ChakraBreadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react' +import Link from 'next/link' +import React from 'react' + +/** + * Renders a breadcrumb component with links to navigate through different pages. + * + * @param {Object} props - The props object containing the brand name. + * @param {string} props.brandName - The name of the brand to display in the breadcrumb. + * @return {JSX.Element} The rendered breadcrumb component. + */ +const Breadcrumb = ({ brandName }) => { + return ( +
+ + + + Shop + + + + + + Promo + + + + + {brandName} + + +
+ ) +} + +export default Breadcrumb diff --git a/src/pages/index.jsx b/src/pages/index.jsx index c097530c..ddc41cbe 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -41,6 +41,11 @@ const FlashSale = dynamic( loading: () => , } ); + +const ProgramPromotion = dynamic(() => + import('@/lib/home/components/PromotionProgram') +); + const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection') ); @@ -103,6 +108,7 @@ export default function Home() {
+ @@ -126,6 +132,7 @@ export default function Home() { + diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx new file mode 100644 index 00000000..4211ceb8 --- /dev/null +++ b/src/pages/shop/promo/[slug].jsx @@ -0,0 +1,46 @@ +import dynamic from 'next/dynamic' +import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' +import { useRouter } from 'next/router' +import _ from 'lodash' +import Seo from '@/core/components/Seo' +import Promocrumb from '@/lib/promo/components/Promocrumb' +import useBrand from '@/lib/brand/hooks/useBrand' + +const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) +const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) +const Brand = dynamic(() => import('@/lib/brand/components/Brand')) + +export default function BrandDetail() { + const router = useRouter() + const { slug = '' } = router.query + console.log("apa itu slug",slug) + const brandName = getNameFromSlug(slug) + const id = getIdFromSlug(slug) + const {brand} = useBrand({id}) + return ( + + {/* seakarang arahkan web untuk menampilkan daftar promo sesuai slug */} + + + + + + harusnya disini menampilkan barang promosimya {slug} + + + {/* + {!_.isEmpty(router.query) && ( + + )} */} + + ) +} diff --git a/src/pages/shop/promo/index.jsx b/src/pages/shop/promo/index.jsx new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 5e5b67e5b98d3183044dc5149fe67a29feeb3c41 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Mon, 10 Jun 2024 16:53:28 +0700 Subject: update promotion-program --- next.config.js | 26 ++++- src/api/promoApi.js | 43 +++++++ src/lib/home/components/PromotionProgram.jsx | 22 +++- src/pages/shop/promo/[slug].jsx | 46 -------- src/pages/shop/promo/[slug].tsx | 161 +++++++++++++++++++++++++++ src/pages/shop/promo/index.jsx | 0 6 files changed, 244 insertions(+), 54 deletions(-) delete mode 100644 src/pages/shop/promo/[slug].jsx create mode 100644 src/pages/shop/promo/[slug].tsx delete mode 100644 src/pages/shop/promo/index.jsx diff --git a/next.config.js b/next.config.js index 8e1ceda3..12aa2f3e 100644 --- a/next.config.js +++ b/next.config.js @@ -1,9 +1,9 @@ /** @type {import('next').NextConfig} */ const withPWA = require('next-pwa')({ dest: 'public', - register: true, - disable: process.env.NODE_ENV === 'development', - skipWaiting: true + register: true, + disable: process.env.NODE_ENV === 'development', + skipWaiting: true }) const nextConfig = { @@ -30,6 +30,26 @@ const nextConfig = { hostname: 'erp.indoteknik.com' } ] + }, + async rewrites() { + return [ + { + source: '/solr/:path*', + destination: 'http://34.101.189.218:8983/solr/:path*' // Proxy to Solr + } + ] + }, + async headers() { + return [ + { + source: '/solr/:path*', + headers: [ + { key: 'Access-Control-Allow-Origin', value: '*' }, + { key: 'Access-Control-Allow-Methods', value: 'GET, POST, OPTIONS, PUT, DELETE' }, + { key: 'Access-Control-Allow-Headers', value: '*' } + ] + } + ] } } diff --git a/src/api/promoApi.js b/src/api/promoApi.js index a4acc768..535df021 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -1,5 +1,6 @@ // src/api/promoApi.js import odooApi from '@/core/api/odooApi'; +// import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; export const fetchPromoItems = async (type) => { try { @@ -10,3 +11,45 @@ export const fetchPromoItems = async (type) => { return []; } }; + +export const fetchPromoItemsSolr = async (type) => { + let start = 0 + let rows = 120 + try { + const queryParams = new URLSearchParams({ q: `type_value_s:${type}` }); + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + 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, + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + }; + result.push(data); + } + return result; +}; \ No newline at end of file diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index 461383a1..a3c09a9b 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -1,16 +1,25 @@ import Link from '@/core/components/elements/Link/Link' import Image from 'next/image' import { bannerApi } from '@/api/bannerApi'; - +import useDevice from '@/core/hooks/useDevice' const { useQuery } = require('react-query') - const BannerSection = () => { const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); + const { isMobile, isDesktop } = useDevice() return ( - promotionProgram.data && +
+
+
Promo Tersedia
+ {isDesktop && ( + + Lihat Semua + + )} +
+ {promotionProgram.data && promotionProgram.data?.length > 0 && ( -
+
{promotionProgram.data?.map((banner) => ( { ))}
- ) + + )} +
+ ) } diff --git a/src/pages/shop/promo/[slug].jsx b/src/pages/shop/promo/[slug].jsx deleted file mode 100644 index 4211ceb8..00000000 --- a/src/pages/shop/promo/[slug].jsx +++ /dev/null @@ -1,46 +0,0 @@ -import dynamic from 'next/dynamic' -import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' -import { useRouter } from 'next/router' -import _ from 'lodash' -import Seo from '@/core/components/Seo' -import Promocrumb from '@/lib/promo/components/Promocrumb' -import useBrand from '@/lib/brand/hooks/useBrand' - -const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) -const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch')) -const Brand = dynamic(() => import('@/lib/brand/components/Brand')) - -export default function BrandDetail() { - const router = useRouter() - const { slug = '' } = router.query - console.log("apa itu slug",slug) - const brandName = getNameFromSlug(slug) - const id = getIdFromSlug(slug) - const {brand} = useBrand({id}) - return ( - - {/* seakarang arahkan web untuk menampilkan daftar promo sesuai slug */} - - - - - - harusnya disini menampilkan barang promosimya {slug} - - - {/* - {!_.isEmpty(router.query) && ( - - )} */} - - ) -} diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx new file mode 100644 index 00000000..cd3e93c4 --- /dev/null +++ b/src/pages/shop/promo/[slug].tsx @@ -0,0 +1,161 @@ +import dynamic from 'next/dynamic' +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 } from '../../../api/promoApi' +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 React from 'react' +import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; + + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) + +export default function PromoDetail() { + const router = useRouter() + const { slug = '' } = router.query + const [promoItems, setPromoItems] = useState([]) + const [promoData, setPromoData] = useState(null) + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); + const visiblePromotions = promoData?.slice(startIndex, endIndex); + const [loading, setLoading] = useState(true); // Menambahkan status loading + + + useEffect(() => { + const loadPromo = async () => { + try { + const items = await fetchPromoItemsSolr(Array.isArray(slug) ? slug[0] : slug) + console.log("slug sekarang ", slug) + + setPromoItems(items) + console.log("data dari promotion pakai SOLR", items) + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const promoDataPromises = items.map(async (item) => { + const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + + try { + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) + console.log("respon data ", response) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: SolrResponse = await response.json() + console.log("data promo IPromotion[]", data) + + const promotions = await map(data.response.docs) + return promotions; + } catch (fetchError) { + console.error("Error fetching promotion data:", fetchError) + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + } catch (loadError) { + console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + }, [slug]) + + useEffect(() => { + window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates + }, []); // Run only once when component mounts + + + const map = async (promotions: any[]): Promise => { + const result: IPromotion[] = [] + + for (const promotion of promotions) { + const data: IPromotion = { + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + } + + result.push(data) + } + + return result + } + + console.log("data yg dikirim ke ProductPromoCard", promoData) + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + const goToNextPage = () => { + setCurrentPage((prevPage) => prevPage + 1); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + const goToPreviousPage = () => { + setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + return ( + + + + + {loading ? ( +
+ +
+ ) : promoData && promoItems.length >= 1 ? ( + <> +
+ {visiblePromotions?.map((promotion) => ( +
+ +
+ ))} +
+
+ + +
+ + ) : ( +
+

Belum ada promo pada kategori ini

+
+ )} +
+ ) +} \ No newline at end of file diff --git a/src/pages/shop/promo/index.jsx b/src/pages/shop/promo/index.jsx deleted file mode 100644 index e69de29b..00000000 -- cgit v1.2.3 From 9565ddf794165e297acf511a108f9a9643ee615d Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 11 Jun 2024 13:40:23 +0700 Subject: update promotion program --- package.json | 5 +- .../modules/product-promo/components/Card.tsx | 4 +- src/api/promoApi.js | 4 +- src/lib/home/components/PromotionProgram.jsx | 14 +- src/pages/shop/promo/[slug].tsx | 77 +++++++-- src/pages/shop/promo/index.tsx | 188 +++++++++++++++++++++ tsconfig.json | 3 +- 7 files changed, 267 insertions(+), 28 deletions(-) create mode 100644 src/pages/shop/promo/index.tsx diff --git a/package.json b/package.json index 6b5f20d7..32c701a5 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,17 @@ "cookies-next": "^2.1.1", "flowbite": "^1.6.4", "framer-motion": "^7.10.3", + "http-proxy-middleware": "^3.0.0", "lodash-contrib": "^4.1200.1", "lucide-react": "^0.279.0", "midtrans-client": "^1.3.1", "moment": "^2.29.4", - "next": "13.0.0", + "next": "^13.5.6", "next-auth": "^4.22.3", "next-progress": "^2.2.0", "next-pwa": "^5.6.0", "next-seo": "^5.15.0", + "node-fetch": "^3.3.2", "nodemailer": "^6.8.0", "react": "18.2.0", "react-dom": "18.2.0", @@ -50,6 +52,7 @@ "react-web-share": "^2.0.2", "sharp": "^0.33.2", "snakecase-keys": "^5.5.0", + "striptags": "^3.2.0", "swiper": "^8.4.4", "tw-merge": "^0.0.1-alpha.3", "usehooks-ts": "^2.9.1", diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index be7d5b6e..0be27af2 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -77,7 +77,7 @@ const ProductPromoCard = ({ promotion, slug }: Props) => { const shouldRender = !slug || promotion.type.value === slug return ( - shouldRender && ( + // shouldRender && (
@@ -133,7 +133,7 @@ const ProductPromoCard = ({ promotion, slug }: Props) => {
- ) + // ) ) } diff --git a/src/api/promoApi.js b/src/api/promoApi.js index 535df021..ecae5080 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -13,11 +13,13 @@ export const fetchPromoItems = async (type) => { }; export const fetchPromoItemsSolr = async (type) => { + // let query = type ? `type_value_s:${type}` : '*:*'; let start = 0 let rows = 120 try { - const queryParams = new URLSearchParams({ q: `type_value_s:${type}` }); + const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); + console.log("Constructed URL SLOR:", `/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index a3c09a9b..98bc7c7f 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -9,17 +9,19 @@ const BannerSection = () => { return (
-
+
Promo Tersedia
{isDesktop && ( - - Lihat Semua - + + Lihat Semua + )}
{promotionProgram.data && promotionProgram.data?.length > 0 && ( -
+
{promotionProgram.data?.map((banner) => ( { quality={100} src={banner.image} alt={banner.name} - className='h-auto w-full rounded' + className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out' /> ))} diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index cd3e93c4..be5a715d 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -10,7 +10,6 @@ import { IPromotion } from '../../../../src-migrate/types/promotion' import React from 'react' import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; - const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { @@ -22,14 +21,15 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); - const visiblePromotions = promoData?.slice(startIndex, endIndex); + // const visiblePromotions = promoData?.slice(startIndex, endIndex); const [loading, setLoading] = useState(true); // Menambahkan status loading + const [fetchingData, setFetchingData] = useState(false) useEffect(() => { const loadPromo = async () => { try { - const items = await fetchPromoItemsSolr(Array.isArray(slug) ? slug[0] : slug) + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) console.log("slug sekarang ", slug) setPromoItems(items) @@ -112,18 +112,60 @@ export default function PromoDetail() { console.log("data yg dikirim ke ProductPromoCard", promoData) function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); + // Ganti semua tanda _ dengan spasi + string = string.replace(/_/g, ' '); + + // Kapitalisasi huruf pertama setelah spasi atau awal string + return string.replace(/(^\w|\s\w)/g, function(match) { + return match.toUpperCase(); + }); + + + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } } - const goToNextPage = () => { - setCurrentPage((prevPage) => prevPage + 1); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; + const visiblePromotions = promoData?.slice(0, currentPage * 12) + - const goToPreviousPage = () => { - setCurrentPage((prevPage) => Math.max(prevPage - 1, 1)); - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; return ( @@ -142,14 +184,15 @@ export default function PromoDetail() {
{visiblePromotions?.map((promotion) => (
- +
))}
-
- - -
+ {fetchingData && ( +
+ +
+ )} ) : (
diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx new file mode 100644 index 00000000..6f5134a3 --- /dev/null +++ b/src/pages/shop/promo/index.tsx @@ -0,0 +1,188 @@ +import dynamic from 'next/dynamic' +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 } 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"; + +const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout.jsx')) + +export default function Promo() { + const router = useRouter() + const { slug = '' } = router.query + const [promoItems, setPromoItems] = useState([]) + const [promoData, setPromoData] = useState(null) + const [loading, setLoading] = useState(true) + const [currentPage, setCurrentPage] = useState(1) + const [fetchingData, setFetchingData] = useState(false) + + useEffect(() => { + const loadPromo = async () => { + try { + const items = await fetchPromoItemsSolr(`*:*`) + console.log("slug sekarang ", slug) + + setPromoItems(items) + console.log("data dari promotion pakai SOLR", items) + + if (items.length === 0) { + setPromoData([]) + setLoading(false); + return; + } + + const promoDataPromises = items.map(async (item) => { + const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + + try { + const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) + console.log("respon data ", response) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: SolrResponse = await response.json() + console.log("data promo IPromotion[]", data) + + const promotions = await map(data.response.docs) + return promotions; + } catch (fetchError) { + console.error("Error fetching promotion data:", fetchError) + return []; + } + }); + + const promoDataArray = await Promise.all(promoDataPromises); + const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + setPromoData(mergedPromoData); + setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + } catch (loadError) { + console.error("Error loading promo items:", loadError) + setLoading(false); + } + } + + if (slug) { + loadPromo() + } + }, [slug]) + + const map = async (promotions: any[]): Promise => { + const result: IPromotion[] = [] + + for (const promotion of promotions) { + const data: IPromotion = { + 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, + total_qty: promotion.total_qty_i, + products: JSON.parse(promotion.products_s), + free_products: JSON.parse(promotion.free_products_s), + } + + result.push(data) + } + + return result + } + + console.log("data yg dikirim ke ProductPromoCard", promoData) + function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + useEffect(() => { + const handleScroll = () => { + if ( + !fetchingData && + window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight + ) { + // User has scrolled to 95% of page height + + setTimeout(() => setFetchingData(true), 120); + setCurrentPage((prevPage) => prevPage + 1) + } + } + + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [fetchingData]) + + useEffect(() => { + if (fetchingData) { + // Fetch more data + // You may need to adjust this logic according to your API + fetchMoreData() + } + }, [fetchingData]) + + const fetchMoreData = async () => { + try { + // Add a delay of approximately 150ms + setTimeout(async () => { + // Fetch more data + // Update promoData state with the new data + }, 150) + } catch (error) { + console.error('Error fetching more data:', error) + } finally { + setTimeout(() => setFetchingData(false), 120); + + } + } + + const visiblePromotions = promoData?.slice(0, currentPage * 12) + + return ( + + + {/* */} +
+
+

Semua Promo di Indoteknik

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

Belum ada promo pada kategori ini

+
+ )} +
+ ) +} diff --git a/tsconfig.json b/tsconfig.json index b2e205a3..8613c022 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,8 +32,9 @@ "next-env.d.ts", "**/*.ts", "**/*.tsx", + "**/*.jsx", ".next/types/**/*.ts" - ], +, "src/pages/shop/promo/index.tsx", "src/pages/shop/promo/[slug].jsx" ], "exclude": [ "node_modules", "src" -- cgit v1.2.3 From ce968fcd38e5c4bb69400862fe4da484934088d5 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 11 Jun 2024 16:14:07 +0700 Subject: import('../../../core/components/layouts/BasicLayout')) @@ -21,10 +24,9 @@ export default function PromoDetail() { const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); - // const visiblePromotions = promoData?.slice(startIndex, endIndex); - const [loading, setLoading] = useState(true); // Menambahkan status loading + const [loading, setLoading] = useState(true); const [fetchingData, setFetchingData] = useState(false) - + const { isMobile, isDesktop } = useDevice() useEffect(() => { const loadPromo = async () => { @@ -66,7 +68,7 @@ export default function PromoDetail() { const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); setPromoData(mergedPromoData); - setTimeout(() => setLoading(false), 120); // Menambahkan delay 200ms sebelum mengubah status loading + setTimeout(() => setLoading(false), 120); // Menambahkan delay 120ms sebelum mengubah status loading } catch (loadError) { console.error("Error loading promo items:", loadError) setLoading(false); @@ -82,7 +84,6 @@ export default function PromoDetail() { window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates }, []); // Run only once when component mounts - const map = async (promotions: any[]): Promise => { const result: IPromotion[] = [] @@ -119,8 +120,6 @@ export default function PromoDetail() { return string.replace(/(^\w|\s\w)/g, function(match) { return match.toUpperCase(); }); - - } useEffect(() => { @@ -162,11 +161,10 @@ export default function PromoDetail() { } } - + + const visiblePromotions = promoData?.slice(0, currentPage * 12) - - return ( - -
+ +
) : promoData && promoItems.length >= 1 ? ( <> -
+ +
{visiblePromotions?.map((promotion) => ( -
- -
+ +
+ +
+
))} +
- {fetchingData && ( -
- -
- )} +
) : (
-- cgit v1.2.3 From 0a87455727114468c216fbcd74266ea928eaec37 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 13 Jun 2024 09:34:24 +0700 Subject: update promotion-program --- .../modules/product-promo/components/Card.tsx | 6 +- .../product/components/ProductFilterDesktop.jsx | 10 +- src/pages/shop/promo/[slug].tsx | 243 +++++++++++++-------- 3 files changed, 165 insertions(+), 94 deletions(-) diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index 0be27af2..e927508f 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -18,10 +18,10 @@ import ProductPromoCardCountdown from "./CardCountdown" type Props = { promotion: IPromotion - slug?: string + } -const ProductPromoCard = ({ promotion, slug }: Props) => { +const ProductPromoCard = ({ promotion}: Props) => { const [products, setProducts] = useState([]) const [freeProducts, setFreeProducts] = useState([]) const [error, setError] = useState(null) @@ -74,7 +74,7 @@ const ProductPromoCard = ({ promotion, slug }: Props) => { const allProducts = [...products, ...freeProducts] - const shouldRender = !slug || promotion.type.value === slug + return ( // shouldRender && ( diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index e4a62abb..b4afebc2 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -21,6 +21,7 @@ import Image from '@/core/components/elements/Image/Image' import { formatCurrency } from '@/core/utils/formatValue' const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { + console.log("prefixUrl",prefixUrl) const router = useRouter() const { query } = router const [order, setOrder] = useState(query?.orderBy) @@ -102,7 +103,14 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu } params = _.pickBy(params, _.identity) params = toQuery(params) - router.push(`${prefixUrl}?${params}`) + + const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + + if (slug) { + router.push(`${prefixUrl}/${slug}?${params}`) + } else { + router.push(`${prefixUrl}?${params}`) + } } diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index a2b790ca..1935c61f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -3,21 +3,26 @@ 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 } from '../../../api/promoApi' +import { fetchPromoItemsSolr, fetchVariantSolr } from '../../../api/promoApi' 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 React from 'react' import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; -import { Swiper, SwiperSlide } from 'swiper/react'; +import DesktopView from '../../../core/components/views/DesktopView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' +import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +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 { cons } from 'lodash-contrib' const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { const router = useRouter() - const { slug = '' } = router.query + const { slug = '', brand, category } = router.query const [promoItems, setPromoItems] = useState([]) const [promoData, setPromoData] = useState(null) const [currentPage, setCurrentPage] = useState(1); @@ -25,42 +30,95 @@ export default function PromoDetail() { const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); const [loading, setLoading] = useState(true); - const [fetchingData, setFetchingData] = useState(false) const { isMobile, isDesktop } = useDevice() + const [brands, setBrands] = useState([]); + const [categories, setCategories] = useState([]); + + interface Brand { + brand: string; + qty: number; + } + + interface Category { + name: string; + qty: number; + } useEffect(() => { const loadPromo = async () => { + setLoading(true); + const brandsData: Brand[] = []; + const categoriesData: Category[] = []; + + try { const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`) - console.log("slug sekarang ", slug) - setPromoItems(items) - console.log("data dari promotion pakai SOLR", items) - + if (items.length === 0) { setPromoData([]) setLoading(false); return; - } - - const promoDataPromises = items.map(async (item) => { - const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + } + + const promoDataPromises = items.map(async (item) => { + // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) + console.log("produk id",item.product_id) + + try { + if(brand && category){ + const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand} && category_name :${category}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + console.log("data response2 ",response2) + return response2; + }else if(brand){ // belum bisa menangani lebih dari 1 brand + const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + console.log("data response2 ",response2) + return response2; + }else if (category){ // belum bisa menangani lebih dari 1 category + const response = await fetchVariantSolr(`id:${item.product_id} && category_name :${category}`); + const product = response.response.docs[0]; + const product_id = product.id + console.log("data brand ",brand) + console.log("data respon varian ",product) + console.log("data ID respon varian ",product_id) + const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + return response2; + }else{ + const response = await fetchPromoItemsSolr( `id:${item.id}`) + console.log("data respon",response) + return response; + } + // if(brand || category){ + // let query = `id:${item.product_id}`; + // if (brand) query += ` OR manufacture_name_s:${brand}`; + // if (category) query += ` OR category_name:${category}`; + // const response = await fetchVariantSolr(query); + // const product = response.response.docs[0]; + // const product_id = product.id + // const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + // return response2; - try { - const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) - console.log("respon data ", response) - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } + // }else{ + // const response = await fetchPromoItemsSolr( `id:${item.id}`) + // console.log("data respon",response) + // return response; + // } - const data: SolrResponse = await response.json() - console.log("data promo IPromotion[]", data) - - const promotions = await map(data.response.docs) - return promotions; + } catch (fetchError) { - console.error("Error fetching promotion data:", fetchError) + // console.error("Error fetching promotion data:", fetchError) return []; } }); @@ -68,7 +126,61 @@ export default function PromoDetail() { const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); setPromoData(mergedPromoData); - setTimeout(() => setLoading(false), 120); // Menambahkan delay 120ms sebelum mengubah status loading + + const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { + if (promoData) { + const dataBrandCategory = promoData.map(async (item) => { + // const response = await fetch(`/solr/variants/select?${queryParams2.toString()}`); + let response; + if(category){ + // response = await fetchVariantSolr(`id:${item.products[0].product_id} && manufacture_name_s:${brand}`); + response = await fetchVariantSolr(`id:${item.products[0].product_id} && category_name:${category}`); + }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); @@ -80,13 +192,9 @@ export default function PromoDetail() { } }, [slug]) - useEffect(() => { - window.scrollTo({ top: 0, behavior: 'auto' }); // Auto scroll to top when component mounts or updates - }, []); // Run only once when component mounts - const map = async (promotions: any[]): Promise => { const result: IPromotion[] = [] - + for (const promotion of promotions) { const data: IPromotion = { id: promotion.id, @@ -104,67 +212,22 @@ export default function PromoDetail() { products: JSON.parse(promotion.products_s), free_products: JSON.parse(promotion.free_products_s), } - + result.push(data) } - + return result } - console.log("data yg dikirim ke ProductPromoCard", promoData) function capitalizeFirstLetter(string) { - // Ganti semua tanda _ dengan spasi string = string.replace(/_/g, ' '); - - // Kapitalisasi huruf pertama setelah spasi atau awal string return string.replace(/(^\w|\s\w)/g, function(match) { return match.toUpperCase(); }); } - useEffect(() => { - const handleScroll = () => { - if ( - !fetchingData && - window.innerHeight + document.documentElement.scrollTop >= 0.95 * document.documentElement.offsetHeight - ) { - // User has scrolled to 95% of page height - - setTimeout(() => setFetchingData(true), 120); - setCurrentPage((prevPage) => prevPage + 1) - } - } - - window.addEventListener('scroll', handleScroll) - return () => window.removeEventListener('scroll', handleScroll) - }, [fetchingData]) - - useEffect(() => { - if (fetchingData) { - // Fetch more data - // You may need to adjust this logic according to your API - fetchMoreData() - } - }, [fetchingData]) - - const fetchMoreData = async () => { - try { - // Add a delay of approximately 150ms - setTimeout(async () => { - // Fetch more data - // Update promoData state with the new data - }, 150) - } catch (error) { - console.error('Error fetching more data:', error) - } finally { - setTimeout(() => setFetchingData(false), 120); - - } - } - - const visiblePromotions = promoData?.slice(0, currentPage * 12) - + const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; return ( - + {loading ? (
) : promoData && promoItems.length >= 1 ? ( <> - -
+
{visiblePromotions?.map((promotion) => ( - -
- -
-
+
+ +
))} -
- ) : (
@@ -199,4 +262,4 @@ export default function PromoDetail() { )} ) -} \ No newline at end of file +} -- cgit v1.2.3 From ef2d3ad6759db8535c04d986f4bc43f01da6ccd8 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:11:13 +0700 Subject: update promotion-program --- src/api/promoApi.js | 17 +- src/pages/shop/promo/[slug].tsx | 501 +++++++++++++++++++++++++++++++--------- 2 files changed, 404 insertions(+), 114 deletions(-) diff --git a/src/api/promoApi.js b/src/api/promoApi.js index ecae5080..4c386fba 100644 --- a/src/api/promoApi.js +++ b/src/api/promoApi.js @@ -1,5 +1,6 @@ // src/api/promoApi.js import odooApi from '@/core/api/odooApi'; +import { type } from 'os'; // import { SolrResponse } from "../../../../src-migrate/types/solr.ts"; export const fetchPromoItems = async (type) => { @@ -15,11 +16,10 @@ export const fetchPromoItems = async (type) => { export const fetchPromoItemsSolr = async (type) => { // let query = type ? `type_value_s:${type}` : '*:*'; let start = 0 - let rows = 120 + let rows = 100 try { const queryParams = new URLSearchParams({ q: type }); const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`); - console.log("Constructed URL SLOR:", `/solr/promotion_program_lines/select?${queryParams.toString()}&rows=${rows}&start=${start}`) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } @@ -32,6 +32,18 @@ export const fetchPromoItemsSolr = async (type) => { } }; +export const fetchVariantSolr = async(data)=>{ + try { + const queryParams = new URLSearchParams({ q: data }); + const response = await fetch(`/solr/variants/select?${queryParams.toString()}`); + const responseData = await response.json(); + return responseData; + } catch (error) { + console.error("Error fetching promotion data:", error); + return []; + } +}; + const map = async (promotions) => { const result = []; for (const promotion of promotions) { @@ -49,6 +61,7 @@ const map = async (promotions) => { price: promotion.price_f, total_qty: promotion.total_qty_i, products: JSON.parse(promotion.products_s), + product_id: promotion.product_ids[0], free_products: JSON.parse(promotion.free_products_s), }; result.push(data); diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 1935c61f..70280d1f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -1,4 +1,5 @@ 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' @@ -10,6 +11,7 @@ import { IPromotion } from '../../../../src-migrate/types/promotion' 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 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; @@ -17,22 +19,47 @@ 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 { cons } from 'lodash-contrib' +// import SideBanner from '~/modules/side-banner'; +import SideBanner from '../../../../src-migrate/modules/side-banner'; +import whatsappUrl from '../../../core/utils/whatsappUrl'; +import { toQuery } from 'lodash-contrib'; +import _ from 'lodash'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) export default function PromoDetail() { const router = useRouter() - const { slug = '', brand, category } = router.query + const { slug = '', brand ='', category='', priceFrom = '', priceTo = '', page = '1' } = router.query const [promoItems, setPromoItems] = useState([]) const [promoData, setPromoData] = useState(null) - const [currentPage, setCurrentPage] = useState(1); + const [currentPage, setCurrentPage] = useState(parseInt(page as string, 10) || 1); const itemsPerPage = 12; // Jumlah item yang ingin ditampilkan per halaman - const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, promoData?.length || 0); 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 || 'popular'); + const [spellings, setSpellings] = useState(null); + + useEffect(() => { + // Initialize brandValues based on router.query.brand + if (router.query.brand) { + const brandsArray = Array.isArray(router.query.brand) ? router.query.brand : [router.query.brand]; + setBrandValues(brandsArray); + } else { + setBrandValues([]); + } + + // Initialize categoryValues based on router.query.category + if (router.query.category) { + const categoriesArray = Array.isArray(router.query.category) ? router.query.category : [router.query.category]; + setCategoryValues(categoriesArray); + } else { + setCategoryValues([]); + } + }, [router.query.brand, router.query.category]); interface Brand { brand: string; @@ -49,11 +76,15 @@ export default function PromoDetail() { 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}`) - setPromoItems(items) + // const start = (pageNumber-1) * itemsPerPage; + const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`); + setPromoItems(items); + console.log("promoItems lastIndexOf",promoItems.length) if (items.length === 0) { setPromoData([]) @@ -61,67 +92,76 @@ export default function PromoDetail() { return; } + const brandArray = Array.isArray(brand) ? brand : brand.split(','); + const categoryArray = Array.isArray(category) ? category : category.split(','); + console.log("brandArray",brandArray) + console.log("categoryArray",categoryArray) const promoDataPromises = items.map(async (item) => { // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) console.log("produk id",item.product_id) try { - if(brand && category){ - const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand} && category_name :${category}`); - const product = response.response.docs[0]; - const product_id = product.id - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - console.log("data response2 ",response2) - return response2; - }else if(brand){ // belum bisa menangani lebih dari 1 brand - const response = await fetchVariantSolr(`id:${item.product_id} && manufacture_name_s:${brand}`); + 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; + } else if (priceFrom || priceTo) { + } + console.log("combinedQuery",combinedQuery) + + 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 - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - console.log("data response2 ",response2) + 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}`); + // const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - }else if (category){ // belum bisa menangani lebih dari 1 category - const response = await fetchVariantSolr(`id:${item.product_id} && category_name :${category}`); + }else if(combinedQuery){ + const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); const product = response.response.docs[0]; - const product_id = product.id - console.log("data brand ",brand) - console.log("data respon varian ",product) - console.log("data ID respon varian ",product_id) - const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) + const product_id = product.id; + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - }else{ - const response = await fetchPromoItemsSolr( `id:${item.id}`) - console.log("data respon",response) + } + else { + const response = await fetchPromoItemsSolr(`id:${item.id}`); return response; } - // if(brand || category){ - // let query = `id:${item.product_id}`; - // if (brand) query += ` OR manufacture_name_s:${brand}`; - // if (category) query += ` OR category_name:${category}`; - // const response = await fetchVariantSolr(query); - // const product = response.response.docs[0]; - // const product_id = product.id - // const response2 = await fetchPromoItemsSolr( `type_value_s:${Array.isArray(slug) ? slug[0] : slug} && product_ids:${product_id}`) - // return response2; - - // }else{ - // const response = await fetchPromoItemsSolr( `id:${item.id}`) - // console.log("data respon",response) - // return response; - // } - - - } catch (fetchError) { - // console.error("Error fetching promotion data:", fetchError) - return []; - } - }); + } catch (fetchError) { + return []; + } + }); const promoDataArray = await Promise.all(promoDataPromises); const mergedPromoData = promoDataArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); @@ -130,11 +170,10 @@ export default function PromoDetail() { const dataBrandCategoryPromises = promoDataArray.map(async (promoData) => { if (promoData) { const dataBrandCategory = promoData.map(async (item) => { - // const response = await fetch(`/solr/variants/select?${queryParams2.toString()}`); let response; if(category){ - // response = await fetchVariantSolr(`id:${item.products[0].product_id} && manufacture_name_s:${brand}`); - response = await fetchVariantSolr(`id:${item.products[0].product_id} && category_name:${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}`) } @@ -190,34 +229,8 @@ export default function PromoDetail() { if (slug) { loadPromo() } - }, [slug]) - - const map = async (promotions: any[]): Promise => { - const result: IPromotion[] = [] - - for (const promotion of promotions) { - const data: IPromotion = { - 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, - total_qty: promotion.total_qty_i, - products: JSON.parse(promotion.products_s), - free_products: JSON.parse(promotion.free_products_s), - } - - result.push(data) - } + },[slug, brand, category, priceFrom, priceTo, currentPage]); - return result - } function capitalizeFirstLetter(string) { string = string.replace(/_/g, ' '); @@ -226,40 +239,304 @@ export default function PromoDetail() { }); } - const visiblePromotions = promoData?.slice(0, currentPage * 12) + const handleDeleteFilter = async (source, value) => { + let params = { + q: router.query.q, + orderBy: 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 = ''; // Setel ke string kosong jika ingin menghapus nilai + params.priceTo = ''; // Setel ke string kosong jika ingin menghapus nilai + break; + case 'delete': + params = { + q: router.query.q, + orderBy: orderBy, + brand: '', + category: '', + priceFrom: '', + priceTo: '', + }; + break; + } + + handleSubmitFilter(params); + }; + const handleSubmitFilter = (params) => { + params = _.pickBy(params, _.identity); + params = toQuery(params); + router.push(`${Array.isArray(slug) ? slug[0] : slug}?${params}`); + // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); + }; + const handlePageChange = (selectedPage: number) => { + setCurrentPage(selectedPage); + router.push(`/shop/promo/${slug}?page=${selectedPage}`); + }; + + const { search } = router.query; + const prefixUrl = `/promo/${slug}`; + + console.log("halaman sekarang", currentPage) + console.log("data yang di potong", (currentPage-1) * itemsPerPage, currentPage * 12) + + const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) + // const visiblePromotions = promoData?.slice( 0, 12) const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; + const whatPromo = capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug) return ( - - - {loading ? ( -
- -
- ) : promoData && promoItems.length >= 1 ? ( - <> -
- {visiblePromotions?.map((promotion) => ( -
- + + + +
+
+ +
+ +
+
+

Promo {whatPromo}

+ + {/*
+
+ {!spellings ? ( + <> + Menampilkan  + {pageCount > 1 ? ( + <> + {productStart + 1}- + {parseInt(productStart) + parseInt(productRows) > + productFound + ? productFound + : parseInt(productStart) + parseInt(productRows)} +  dari  + + ) : ( + '' + )} + {productFound} +  produk{' '} + {query.q && ( + <> + untuk pencarian{' '} + {query.q} + + )} + + ) : ( + SpellingComponent + )} +
+
+
+ +
+
+ +
+
+
*/} + {loading ? ( +
+ +
+ ) : promoData && promoItems.length >= 1 ? ( + <> +
+ {visiblePromotions?.map((promotion) => ( +
+ +
+ ))} +
+ + ) : ( +
+

Belum ada promo pada kategori ini

+
+ )} +
+
+ +
+ + Barang yang anda cari tidak ada?{' '} + + Hubungi Kami + + +
+
+ +
- ))} +
- - ) : ( -
-

Belum ada promo pada kategori ini

- )} + {console.log("promoItems lastIndexOf",promoItems.length)} + ) -} + } + +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 ? ( + + + + ) : ( + '' + )} + +
+); + +// {loading ? ( +//
+// +//
+// ) : promoData && promoItems.length >= 1 ? ( +// <> +//
+// {visiblePromotions?.map((promotion) => ( +//
+// +//
+// ))} +//
+// +// ) : ( +//
+//

Belum ada promo pada kategori ini

+//
+// )} \ No newline at end of file -- cgit v1.2.3 From e3e3fe8d87130fcd1872046de0160272b6ea9763 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:15:30 +0700 Subject: update promotion-program --- .env | 43 ++++++++++++++++++++++ .../modules/product-promo/components/Section.tsx | 2 +- src/api/bannerApi.js | 3 ++ src/lib/product/components/ProductSearch.jsx | 2 + src/pages/shop/promo/index.tsx | 4 +- 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..a9aa1cf9 --- /dev/null +++ b/.env @@ -0,0 +1,43 @@ +SELF_HOST=http://localhost:2100 +# SELF_HOST=http://192.168.23.178:2100 +# ODOO_API_HOST=http://192.168.23.191:8069 +# ODOO_API_HOST=http://192.168.23.251:8069 +# ODOO_API_HOST=http://192.168.23.73:8069 +ODOO_API_HOST=https://erp.indoteknik.com +SOLR_HOST=http://34.101.189.218:8983 +# SOLR_HOST=http://192.168.23.5:8983 + +RAJA_ONGKIR_HOST='https://pro.rajaongkir.com' +RAJA_ONGKIR_KEY='7ac9883688da043b50cc32f0e3070bb6' + +MAIL_PORT=465 +MAIL_HOST=smtp.gmail.com +MAIL_USER=sales@indoteknik.com +MAIL_PASS=#&Win*%a3C%^FF + +MIDTRANS_HOST=https://api.sandbox.midtrans.com +MIDTRANS_ENV=development +MIDTRANS_SERVER_KEY=SB-Mid-server-n-V7d2c2ZB0SVED29OyCWVYp +MIDTRANS_CLIENT_KEY=SB-Mid-client-IsVHHv5mzPqNV7bs + +RECAPTCHA_GOOGLE=6LdajH0lAAAAAI6kCVHjR9rHuD22Pf-X7XakSQ_P + +NEXTAUTH_URL=http://localhost:2100 + +PPN=1.11 + +# GOOGLE_CLIENT_ID="396438712998-308hckshgeekr34phr5jskj1f6qltfvk.apps.googleusercontent.com" +# GOOGLE_CLIENT_SECRET=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 +GOOGLE_CLIENT_ID="140590317805-5k5v3pjb7gcv4rcefgt8udgmn3hllv0q.apps.googleusercontent.com" +GOOGLE_CLIENT_SECRET=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 + +JWT_SECRET=NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c + +NEXT_PUBLIC_SELF_HOST=$SELF_HOST +NEXT_PUBLIC_ODOO_API_HOST=$ODOO_API_HOST +NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY +NEXT_PUBLIC_RECAPTCHA_GOOGLE=$RECAPTCHA_GOOGLE +NEXT_PUBLIC_RAJA_ONGKIR_HOST=$RAJA_ONGKIR_HOST +NEXT_PUBLIC_RAJA_ONGKIR_KEY=$RAJA_ONGKIR_KEY +NEXT_PUBLIC_ODOO_HOST=$ODOO_API_HOST +NEXT_PUBLIC_PPN=$PPN \ No newline at end of file diff --git a/src-migrate/modules/product-promo/components/Section.tsx b/src-migrate/modules/product-promo/components/Section.tsx index 5fc0da4c..4e8a7dd5 100644 --- a/src-migrate/modules/product-promo/components/Section.tsx +++ b/src-migrate/modules/product-promo/components/Section.tsx @@ -50,7 +50,7 @@ const ProductPromoSection = ({ productId }: Props) => { > {promotions?.data.map((promotion) => (
- +
))} diff --git a/src/api/bannerApi.js b/src/api/bannerApi.js index 8bae131d..431225a5 100644 --- a/src/api/bannerApi.js +++ b/src/api/bannerApi.js @@ -3,3 +3,6 @@ import odooApi from '@/core/api/odooApi' export const bannerApi = ({ type }) => { return async () => await odooApi('GET', `/api/v1/banner?type=${type}`) } + +// ubah ke SOLR + diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 08b64c13..ec0077c2 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -130,6 +130,7 @@ const ProductSearch = ({ brands.push({ brand, qty }); } } + console.log("daftar brand",brands) const categories = []; for ( @@ -144,6 +145,7 @@ const ProductSearch = ({ categories.push({ name, qty }); } } + console.log("daftar kategori",categories) const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx index 6f5134a3..89e88e29 100644 --- a/src/pages/shop/promo/index.tsx +++ b/src/pages/shop/promo/index.tsx @@ -101,9 +101,7 @@ export default function Promo() { } console.log("data yg dikirim ke ProductPromoCard", promoData) - function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); - } + useEffect(() => { const handleScroll = () => { -- cgit v1.2.3 From 7c45b1c564db183868b3b99011dd3a090818a285 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 15:46:41 +0700 Subject: update promotion program --- src/pages/shop/promo/[slug].tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 70280d1f..4f223aed 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -24,6 +24,7 @@ import SideBanner from '../../../../src-migrate/modules/side-banner'; import whatsappUrl from '../../../core/utils/whatsappUrl'; import { toQuery } from 'lodash-contrib'; import _ from 'lodash'; +import { Query } from 'react-query'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) @@ -283,13 +284,10 @@ export default function PromoDetail() { const handleSubmitFilter = (params) => { params = _.pickBy(params, _.identity); params = toQuery(params); - router.push(`${Array.isArray(slug) ? slug[0] : slug}?${params}`); + router.push(`${slug}?${params}`); // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); }; - const handlePageChange = (selectedPage: number) => { - setCurrentPage(selectedPage); - router.push(`/shop/promo/${slug}?page=${selectedPage}`); - }; + const { search } = router.query; const prefixUrl = `/promo/${slug}`; @@ -300,7 +298,7 @@ export default function PromoDetail() { const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) // const visiblePromotions = promoData?.slice( 0, 12) const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; - const whatPromo = capitalizeFirstLetter(Array.isArray(slug) ? slug[0] : slug) + const whatPromo = capitalizeFirstLetter(slug) return ( + />
-- cgit v1.2.3 From 518a2d89d91775ceffd06f8d7aca7050526310da Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 16:41:13 +0700 Subject: update add mobile view promotion-program --- src/pages/shop/promo/[slug].tsx | 182 ++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 112 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 4f223aed..c53bcf0e 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -15,16 +15,15 @@ import MobileView from '../../../core/components/views/MobileView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +import ProductFilter from '../../../lib/product/components/ProductFilter'; 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 { cons } from 'lodash-contrib' -// import SideBanner from '~/modules/side-banner'; import SideBanner from '../../../../src-migrate/modules/side-banner'; import whatsappUrl from '../../../core/utils/whatsappUrl'; import { toQuery } from 'lodash-contrib'; import _ from 'lodash'; -import { Query } from 'react-query'; +import useActive from '../../../core/hooks/useActive'; const BasicLayout = dynamic(() => import('../../../core/components/layouts/BasicLayout')) @@ -43,6 +42,7 @@ export default function PromoDetail() { const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); const [spellings, setSpellings] = useState(null); + const popup = useActive(); useEffect(() => { // Initialize brandValues based on router.query.brand @@ -82,10 +82,8 @@ export default function PromoDetail() { setCurrentPage(pageNumber) try { - // const start = (pageNumber-1) * itemsPerPage; const items = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug}`); setPromoItems(items); - console.log("promoItems lastIndexOf",promoItems.length) if (items.length === 0) { setPromoData([]) @@ -95,11 +93,8 @@ export default function PromoDetail() { const brandArray = Array.isArray(brand) ? brand : brand.split(','); const categoryArray = Array.isArray(category) ? category : category.split(','); - console.log("brandArray",brandArray) - console.log("categoryArray",categoryArray) + const promoDataPromises = items.map(async (item) => { - // const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("produk id",item.product_id) try { let brandQuery = ''; @@ -137,16 +132,13 @@ export default function PromoDetail() { combinedQuery = brandQuery; } else if (category) { combinedQuery = categoryQuery; - } else if (priceFrom || priceTo) { } - console.log("combinedQuery",combinedQuery) 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}`); - // const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); + const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} AND ${combinedQueryPrice}`); return response2; }else if(combinedQuery){ const response = await fetchVariantSolr(`id:${item.product_id} AND ${combinedQuery}`); @@ -154,8 +146,7 @@ export default function PromoDetail() { const product_id = product.id; const response2 = await fetchPromoItemsSolr(`type_value_s:${Array.isArray(slug) ? slug[0] : slug} AND product_ids:${product_id} `); return response2; - } - else { + } else { const response = await fetchPromoItemsSolr(`id:${item.id}`); return response; } @@ -222,7 +213,7 @@ export default function PromoDetail() { setLoading(false); } catch (loadError) { - console.error("Error loading promo items:", loadError) + // console.error("Error loading promo items:", loadError) setLoading(false); } } @@ -264,8 +255,8 @@ export default function PromoDetail() { await setCategoryValues(catagories); break; case 'price': - params.priceFrom = ''; // Setel ke string kosong jika ingin menghapus nilai - params.priceTo = ''; // Setel ke string kosong jika ingin menghapus nilai + params.priceFrom = ''; + params.priceTo = ''; break; case 'delete': params = { @@ -285,19 +276,10 @@ export default function PromoDetail() { params = _.pickBy(params, _.identity); params = toQuery(params); router.push(`${slug}?${params}`); - // router.push(`${Array.isArray(slug) ? slug[0] : slug}`); }; - - const { search } = router.query; - const prefixUrl = `/promo/${slug}`; - - console.log("halaman sekarang", currentPage) - console.log("data yang di potong", (currentPage-1) * itemsPerPage, currentPage * 12) - const visiblePromotions = promoData?.slice( (currentPage-1) * itemsPerPage, currentPage * 12) - // const visiblePromotions = promoData?.slice( 0, 12) - const isNotReadyStockPage = router.asPath !== '/shop/promo?orderBy=stock'; + const whatPromo = capitalizeFirstLetter(slug) return ( @@ -306,7 +288,67 @@ export default function PromoDetail() { description='B2B Marketplace MRO & Industri dengan Layanan Pembayaran Tempo, Faktur Pajak, Online Quotation, Garansi Resmi & Harga Kompetitif' /> + +
+

Promo {whatPromo}

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

Belum ada promo pada kategori ini

+
+ )} + + + +
+
@@ -328,69 +370,6 @@ export default function PromoDetail() { priceTo={priceTo} handleDeleteFilter={handleDeleteFilter} /> - {/*
-
- {!spellings ? ( - <> - Menampilkan  - {pageCount > 1 ? ( - <> - {productStart + 1}- - {parseInt(productStart) + parseInt(productRows) > - productFound - ? productFound - : parseInt(productStart) + parseInt(productRows)} -  dari  - - ) : ( - '' - )} - {productFound} -  produk{' '} - {query.q && ( - <> - untuk pencarian{' '} - {query.q} - - )} - - ) : ( - SpellingComponent - )} -
-
-
- -
-
- -
-
-
*/} {loading ? (
@@ -447,7 +426,6 @@ export default function PromoDetail() {
- {console.log("promoItems lastIndexOf",promoItems.length)} ) @@ -517,23 +495,3 @@ const FilterChoicesComponent = ({
); - -// {loading ? ( -//
-// -//
-// ) : promoData && promoItems.length >= 1 ? ( -// <> -//
-// {visiblePromotions?.map((promotion) => ( -//
-// -//
-// ))} -//
-// -// ) : ( -//
-//

Belum ada promo pada kategori ini

-//
-// )} \ No newline at end of file -- cgit v1.2.3 From 55f4e2dc6e25dd425ad0a2b8763f8b8de0305e70 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 14 Jun 2024 17:08:42 +0700 Subject: update promotion-program --- src/pages/shop/promo/[slug].tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index c53bcf0e..1248ba35 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -45,17 +45,26 @@ export default function PromoDetail() { const popup = useActive(); useEffect(() => { - // Initialize brandValues based on router.query.brand if (router.query.brand) { - const brandsArray = Array.isArray(router.query.brand) ? router.query.brand : [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([]); } - // Initialize categoryValues based on router.query.category if (router.query.category) { - const categoriesArray = Array.isArray(router.query.category) ? router.query.category : [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([]); @@ -467,6 +476,7 @@ const FilterChoicesComponent = ({ /> ))} + {console.log("categoryValues",categoryValues)} {priceFrom && priceTo && ( -- cgit v1.2.3 From e786215b1be4b88e1b43efb2beae15073d6f81db Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 08:32:37 +0700 Subject: update promotion program (handleSubmitFilter) --- src/pages/shop/promo/[slug].tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 1248ba35..da720b16 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -41,7 +41,6 @@ export default function PromoDetail() { const [brandValues, setBrandValues] = useState([]); const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); - const [spellings, setSpellings] = useState(null); const popup = useActive(); useEffect(() => { @@ -243,7 +242,7 @@ export default function PromoDetail() { const handleDeleteFilter = async (source, value) => { let params = { q: router.query.q, - orderBy: orderBy, + orderBy: '', brand: brandValues.join(','), category: categoryValues.join(','), priceFrom: priceFrom || '', @@ -270,7 +269,7 @@ export default function PromoDetail() { case 'delete': params = { q: router.query.q, - orderBy: orderBy, + orderBy: '', brand: '', category: '', priceFrom: '', @@ -353,6 +352,7 @@ export default function PromoDetail() { brands={brands || []} categories={categories || []} prefixUrl={router.asPath.includes('?') ? `${router.asPath}` : `${router.asPath}?`} + // prefixUrl={`${router.query}?`} defaultBrand={null} />
-- cgit v1.2.3 From 4f4729440befed9899661a5c9a7bc9b57c16cc6e Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 10:20:30 +0700 Subject: update grid-cols promotion program --- src/pages/shop/promo/[slug].tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index da720b16..19592f6e 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -328,7 +328,7 @@ export default function PromoDetail() { <>
{visiblePromotions?.map((promotion) => ( -
+
))} @@ -385,7 +385,7 @@ export default function PromoDetail() {
) : promoData && promoItems.length >= 1 ? ( <> -
+
{visiblePromotions?.map((promotion) => (
-- cgit v1.2.3 From 72f1101ff077864ac202cc03679662bfd7904f19 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 13:15:44 +0700 Subject: remove env --- .env | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index a9aa1cf9..00000000 --- a/.env +++ /dev/null @@ -1,43 +0,0 @@ -SELF_HOST=http://localhost:2100 -# SELF_HOST=http://192.168.23.178:2100 -# ODOO_API_HOST=http://192.168.23.191:8069 -# ODOO_API_HOST=http://192.168.23.251:8069 -# ODOO_API_HOST=http://192.168.23.73:8069 -ODOO_API_HOST=https://erp.indoteknik.com -SOLR_HOST=http://34.101.189.218:8983 -# SOLR_HOST=http://192.168.23.5:8983 - -RAJA_ONGKIR_HOST='https://pro.rajaongkir.com' -RAJA_ONGKIR_KEY='7ac9883688da043b50cc32f0e3070bb6' - -MAIL_PORT=465 -MAIL_HOST=smtp.gmail.com -MAIL_USER=sales@indoteknik.com -MAIL_PASS=#&Win*%a3C%^FF - -MIDTRANS_HOST=https://api.sandbox.midtrans.com -MIDTRANS_ENV=development -MIDTRANS_SERVER_KEY=SB-Mid-server-n-V7d2c2ZB0SVED29OyCWVYp -MIDTRANS_CLIENT_KEY=SB-Mid-client-IsVHHv5mzPqNV7bs - -RECAPTCHA_GOOGLE=6LdajH0lAAAAAI6kCVHjR9rHuD22Pf-X7XakSQ_P - -NEXTAUTH_URL=http://localhost:2100 - -PPN=1.11 - -# GOOGLE_CLIENT_ID="396438712998-308hckshgeekr34phr5jskj1f6qltfvk.apps.googleusercontent.com" -# GOOGLE_CLIENT_SECRET=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 -GOOGLE_CLIENT_ID="140590317805-5k5v3pjb7gcv4rcefgt8udgmn3hllv0q.apps.googleusercontent.com" -GOOGLE_CLIENT_SECRET=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 - -JWT_SECRET=NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c - -NEXT_PUBLIC_SELF_HOST=$SELF_HOST -NEXT_PUBLIC_ODOO_API_HOST=$ODOO_API_HOST -NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY -NEXT_PUBLIC_RECAPTCHA_GOOGLE=$RECAPTCHA_GOOGLE -NEXT_PUBLIC_RAJA_ONGKIR_HOST=$RAJA_ONGKIR_HOST -NEXT_PUBLIC_RAJA_ONGKIR_KEY=$RAJA_ONGKIR_KEY -NEXT_PUBLIC_ODOO_HOST=$ODOO_API_HOST -NEXT_PUBLIC_PPN=$PPN \ No newline at end of file -- cgit v1.2.3 From 78575ef59454214f61f77b1a826af30497cfdc5f Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Tue, 18 Jun 2024 14:23:16 +0700 Subject: update url page promotion program --- src/pages/shop/promo/[slug].tsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 19592f6e..667a26ce 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -21,7 +21,7 @@ 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 { toQuery } from 'lodash-contrib'; +import { cons, toQuery } from 'lodash-contrib'; import _ from 'lodash'; import useActive from '../../../core/hooks/useActive'; @@ -42,6 +42,7 @@ export default function PromoDetail() { const [categoryValues, setCategoryValues] = useState([]); const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular'); const popup = useActive(); + const prefixUrl = `/shop/promo/${slug}` useEffect(() => { if (router.query.brand) { @@ -287,8 +288,18 @@ export default function PromoDetail() { }; 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 (
{visiblePromotions?.map((promotion) => ( -
+
))} @@ -343,7 +354,7 @@ export default function PromoDetail() {
@@ -425,10 +435,12 @@ export default function PromoDetail() {
+ +
-- cgit v1.2.3 From ba84659f27c84d0d2c0cc3275e211a865e416bf7 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 11:31:02 +0700 Subject: update responsive promotion program --- .../modules/product-promo/components/AddToCart.tsx | 52 ++++++++++++----- .../modules/product-promo/components/Card.tsx | 68 +++++++++++++++++++++- .../modules/product-promo/styles/card.module.css | 12 ++++ src/pages/shop/promo/[slug].tsx | 6 +- 4 files changed, 120 insertions(+), 18 deletions(-) diff --git a/src-migrate/modules/product-promo/components/AddToCart.tsx b/src-migrate/modules/product-promo/components/AddToCart.tsx index 192dd231..87017c14 100644 --- a/src-migrate/modules/product-promo/components/AddToCart.tsx +++ b/src-migrate/modules/product-promo/components/AddToCart.tsx @@ -7,6 +7,9 @@ import { getAuth } from '~/libs/auth' import { upsertUserCart } from '~/services/cart' import { IPromotion } from '~/types/promotion' +import DesktopView from '../../../../src/core/components/views/DesktopView'; +import MobileView from '../../../../src/core/components/views/MobileView'; + type Props = { promotion: IPromotion } @@ -55,21 +58,42 @@ const ProductPromoAddToCart = ({ promotion }: Props) => { }, [status]) return ( - + + + + {status === 'success' && Berhasil} + {status !== 'success' && Keranjang} + + +
) } diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index e927508f..56e29e38 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -16,6 +16,9 @@ import ProductPromoItem from './Item' import ProductPromoAddToCart from "./AddToCart" import ProductPromoCardCountdown from "./CardCountdown" +import MobileView from '../../../../src/core/components/views/MobileView'; +import DesktopView from '../../../../src/core/components/views/DesktopView'; + type Props = { promotion: IPromotion @@ -77,7 +80,66 @@ const ProductPromoCard = ({ promotion}: Props) => { return ( - // shouldRender && ( +
+ +
+ + +
+
+
{promotion.name}
+ + + {/*
*/} + {/* Paket {PROMO_CATEGORY[promotion.type.value].alias} */} + + {/*
*/} +
+
+ + 0}> + {allProducts.map((product, index) => ( + + + products.length && promotion.type.value === 'merchandise'} + // isFree={index + 1 > products.length } + /> + + + {index + 1 < allProducts.length && ( +
+ +
+ )} +
+
+ ))} +
+ +
+
+ 0}> + Rp{formatCurrency(priceTotal)} + Hemat Rp {formatCurrency(priceTotal - promotion.price)} + + +
+ Rp{formatCurrency(promotion.price)} + (Total {promotion.total_qty} barang) +
+ +
+
+ +
+ +
+
+
+
+
@@ -133,6 +195,10 @@ const ProductPromoCard = ({ promotion}: Props) => {
+ +
+ // shouldRender && ( + // ) ) } diff --git a/src-migrate/modules/product-promo/styles/card.module.css b/src-migrate/modules/product-promo/styles/card.module.css index a2ad9af6..29db13f3 100644 --- a/src-migrate/modules/product-promo/styles/card.module.css +++ b/src-migrate/modules/product-promo/styles/card.module.css @@ -44,3 +44,15 @@ .totalItems { @apply text-gray_r-9; } + +/* @media only screen and (max-width: 384px) { + .basePrice { + @apply text-[13px]; + } + .price{ + @apply text-[15px]; + } + .totalItems{ + @apply text-[11px]; + } + } */ diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 667a26ce..6e18101f 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -339,7 +339,7 @@ export default function PromoDetail() { <>
{visiblePromotions?.map((promotion) => ( -
+
))} @@ -395,9 +395,9 @@ export default function PromoDetail() {
) : promoData && promoItems.length >= 1 ? ( <> -
+
{visiblePromotions?.map((promotion) => ( -
+
))} -- cgit v1.2.3 From 2de8d24f2d9850ae7578e5bf40f50c8157093625 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 11:35:11 +0700 Subject: update responsive promotion program --- src-migrate/modules/product-promo/styles/card.module.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-migrate/modules/product-promo/styles/card.module.css b/src-migrate/modules/product-promo/styles/card.module.css index 29db13f3..faa3b370 100644 --- a/src-migrate/modules/product-promo/styles/card.module.css +++ b/src-migrate/modules/product-promo/styles/card.module.css @@ -45,7 +45,7 @@ @apply text-gray_r-9; } -/* @media only screen and (max-width: 384px) { +@media only screen and (max-width: 384px) { .basePrice { @apply text-[13px]; } @@ -55,4 +55,4 @@ .totalItems{ @apply text-[11px]; } - } */ + } \ No newline at end of file -- cgit v1.2.3 From 198cb9c9ecb8a682ba751ba32fadf68c523368a1 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 11:40:05 +0700 Subject: update responsive promotion program --- .env | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..306e85ad --- /dev/null +++ b/.env @@ -0,0 +1,43 @@ +SELF_HOST=http://localhost:2100 +# SELF_HOST=http://192.168.23.178:2100 +# ODOO_API_HOST=http://192.168.23.191:8069 +ODOO_API_HOST=http://192.168.23.251:8069 +# ODOO_API_HOST=http://192.168.23.73:8069 +# ODOO_API_HOST=https://erp.indoteknik.com +SOLR_HOST=http://34.101.189.218:8983 +# SOLR_HOST=http://192.168.23.5:8983 + +RAJA_ONGKIR_HOST='https://pro.rajaongkir.com' +RAJA_ONGKIR_KEY='7ac9883688da043b50cc32f0e3070bb6' + +MAIL_PORT=465 +MAIL_HOST=smtp.gmail.com +MAIL_USER=sales@indoteknik.com +MAIL_PASS=#&Win*%a3C%^FF + +MIDTRANS_HOST=https://api.sandbox.midtrans.com +MIDTRANS_ENV=development +MIDTRANS_SERVER_KEY=SB-Mid-server-n-V7d2c2ZB0SVED29OyCWVYp +MIDTRANS_CLIENT_KEY=SB-Mid-client-IsVHHv5mzPqNV7bs + +RECAPTCHA_GOOGLE=6LdajH0lAAAAAI6kCVHjR9rHuD22Pf-X7XakSQ_P + +NEXTAUTH_URL=http://localhost:2100 + +PPN=1.11 + +# GOOGLE_CLIENT_ID="396438712998-308hckshgeekr34phr5jskj1f6qltfvk.apps.googleusercontent.com" +# GOOGLE_CLIENT_SECRET=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 +GOOGLE_CLIENT_ID="140590317805-5k5v3pjb7gcv4rcefgt8udgmn3hllv0q.apps.googleusercontent.com" +GOOGLE_CLIENT_SECRET=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 + +JWT_SECRET=NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c + +NEXT_PUBLIC_SELF_HOST=$SELF_HOST +NEXT_PUBLIC_ODOO_API_HOST=$ODOO_API_HOST +NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY +NEXT_PUBLIC_RECAPTCHA_GOOGLE=$RECAPTCHA_GOOGLE +NEXT_PUBLIC_RAJA_ONGKIR_HOST=$RAJA_ONGKIR_HOST +NEXT_PUBLIC_RAJA_ONGKIR_KEY=$RAJA_ONGKIR_KEY +NEXT_PUBLIC_ODOO_HOST=$ODOO_API_HOST +NEXT_PUBLIC_PPN=$PPN \ No newline at end of file -- cgit v1.2.3 From ced37d32aa345fc288483716771422e7b7c0913a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 19 Jun 2024 17:10:24 +0700 Subject: update tampilan promotion program --- package.json | 4 +- .../components/ProductFilterDesktopPromotion.jsx | 98 ++++++++++++++++++++++ src/pages/index.jsx | 4 +- src/pages/shop/promo/[slug].tsx | 29 +++---- 4 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 src/lib/product/components/ProductFilterDesktopPromotion.jsx diff --git a/package.json b/package.json index 32c701a5..054a30e4 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "next-seo": "^5.15.0", "node-fetch": "^3.3.2", "nodemailer": "^6.8.0", + "primereact": "^10.6.6", "react": "18.2.0", "react-dom": "18.2.0", "react-google-recaptcha": "^2.1.0", @@ -47,8 +48,9 @@ "react-lazy-load": "^4.0.1", "react-lazy-load-image-component": "^1.5.5", "react-loading-skeleton": "^3.3.1", + "react-multi-select-component": "^4.3.4", "react-query": "^3.39.3", - "react-select": "^5.7.0", + "react-select": "^5.8.0", "react-web-share": "^2.0.2", "sharp": "^0.33.2", "snakecase-keys": "^5.5.0", diff --git a/src/lib/product/components/ProductFilterDesktopPromotion.jsx b/src/lib/product/components/ProductFilterDesktopPromotion.jsx new file mode 100644 index 00000000..332d2374 --- /dev/null +++ b/src/lib/product/components/ProductFilterDesktopPromotion.jsx @@ -0,0 +1,98 @@ +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import _ from 'lodash' +import { toQuery } from 'lodash-contrib' +import { Button } from '@chakra-ui/react' +import { MultiSelect } from 'primereact/multiselect'; + +const ProductFilterDesktop = ({ brands, categories, prefixUrl }) => { + const router = useRouter() + const { query } = router + + const [selectedBrand, setSelectedBrand] = useState(null); + const [selectedCategory, setSelectedCategory] = useState(null); + + const handleSubmit = () => { + let params = { + q: router.query.q, + orderBy: query?.orderBy, + brand: selectedBrand ? selectedBrand.map(b => b.code).join(',') : '', + category: query?.category, + priceFrom: query?.priceFrom, + priceTo: query?.priceTo, + stock: query?.stock + } + params = _.pickBy(params, _.identity) + params = toQuery(params) + + const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + + if (slug) { + router.push(`${prefixUrl}/${slug}?${params}`) + } else { + router.push(`${prefixUrl}?${params}`) + } + } + + const countryTemplate = (option) => { + return ( +
+
{option.name}
+
+ ); + }; + + const brandOptions = brands.map(brand => ({ + name: `${brand.brand} (${brand.qty})`, + code: brand.brand + })); + + const categoryOptions = categories.map(category => ({ + name: `${category.name} (${category.qty})`, + code: category.name + })); + + const panelFooterTemplate = () => { + return ( + + ); + }; + + return ( +
+
+ + setSelectedBrand(e.value)} + optionLabel="name" + placeholder="Pilih Brand" + itemTemplate={countryTemplate} + panelFooterTemplate={panelFooterTemplate} + className="w-full" + display="chip" + /> +
+ +
+ + setSelectedCategory(e.value)} + optionLabel="name" + placeholder="Pilih Kategori" + itemTemplate={countryTemplate} + panelFooterTemplate={panelFooterTemplate} + className="w-full" + display="chip" + /> +
+
+ ) +} + +export default ProductFilterDesktop diff --git a/src/pages/index.jsx b/src/pages/index.jsx index ddc41cbe..80e9ef0e 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -102,13 +102,13 @@ export default function Home() {
-
+
- + diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 6e18101f..7fea10ff 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -14,7 +14,7 @@ import DesktopView from '../../../core/components/views/DesktopView'; import MobileView from '../../../core/components/views/MobileView'; import 'swiper/swiper-bundle.css'; import useDevice from '../../../core/hooks/useDevice' -import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktop'; +import ProductFilterDesktop from '../../../lib/product/components/ProductFilterDesktopPromotion'; import ProductFilter from '../../../lib/product/components/ProductFilter'; import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react'; import { formatCurrency } from '../../../core/utils/formatValue'; @@ -369,19 +369,17 @@ export default function PromoDetail() { -
-
- -
- -
-
+
+

Promo {whatPromo}

+
+ +
) : promoData && promoItems.length >= 1 ? ( <> -
+
{visiblePromotions?.map((promotion) => ( -
+
))} @@ -488,7 +486,6 @@ const FilterChoicesComponent = ({ /> ))} - {console.log("categoryValues",categoryValues)} {priceFrom && priceTo && ( -- cgit v1.2.3 From fd96f81bdf1ad6bfe8c7a60571eb9ea70f432ff8 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 20 Jun 2024 11:54:11 +0700 Subject: update filter promotion-program --- .../components/ProductFilterDesktopPromotion.jsx | 186 ++++++++++++--------- src/pages/shop/promo/[slug].tsx | 4 +- 2 files changed, 112 insertions(+), 78 deletions(-) diff --git a/src/lib/product/components/ProductFilterDesktopPromotion.jsx b/src/lib/product/components/ProductFilterDesktopPromotion.jsx index 332d2374..0815b881 100644 --- a/src/lib/product/components/ProductFilterDesktopPromotion.jsx +++ b/src/lib/product/components/ProductFilterDesktopPromotion.jsx @@ -1,98 +1,132 @@ -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' -import { Button } from '@chakra-ui/react' -import { MultiSelect } from 'primereact/multiselect'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import _ from 'lodash'; +import { toQuery } from 'lodash-contrib'; +import { Button } from '@chakra-ui/react'; +import { MultiSelect } from 'react-multi-select-component'; const ProductFilterDesktop = ({ brands, categories, prefixUrl }) => { - const router = useRouter() - const { query } = router + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy); + const [brandValues, setBrand] = useState([]); + const [categoryValues, setCategory] = useState([]); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom); + const [priceTo, setPriceTo] = useState(query?.priceTo); + const [stock, setStock] = useState(query?.stock); + const [activeRange, setActiveRange] = useState(null); + const [isBrandDropdownClicked, setIsBrandDropdownClicked] = useState(false); + const [isCategoryDropdownClicked, setIsCategoryDropdownClicked] = useState(false); - const [selectedBrand, setSelectedBrand] = useState(null); - const [selectedCategory, setSelectedCategory] = useState(null); + // Effect to set brandValues from query parameter 'brand' + useEffect(() => { + const brandParam = query?.brand; + if (brandParam) { + const brandsArray = brandParam.split(',').map((b) => ({ + label: b, + value: b, + })); + setBrand(brandsArray); + } + + }, [query.brand]); // Trigger effect whenever query.brand changes + + useEffect(() => { + const categoryParam = query?.category; + if (categoryParam) { + const categoriesArray = categoryParam.split(',').map((c) => ({ + label: c, + value: c, + })); + setCategory(categoriesArray); + } + }, [query.category]); // Trigger effect whenever query.category changes const handleSubmit = () => { let params = { q: router.query.q, - orderBy: query?.orderBy, - brand: selectedBrand ? selectedBrand.map(b => b.code).join(',') : '', - category: query?.category, - priceFrom: query?.priceFrom, - priceTo: query?.priceTo, - stock: query?.stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) + orderBy: order, + brand: brandValues.map((b) => b.value).join(','), + category: categoryValues.map((c) => c.value).join(','), + priceFrom, + priceTo, + stock: stock, + }; + params = _.pickBy(params, _.identity); + params = toQuery(params); - const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + const slug = Array.isArray(router.query.slug) + ? router.query.slug[0] + : router.query.slug; if (slug) { - router.push(`${prefixUrl}/${slug}?${params}`) + router.push(`${prefixUrl}/${slug}?${params}`); } else { - router.push(`${prefixUrl}?${params}`) + router.push(`${prefixUrl}?${params}`); } - } - - const countryTemplate = (option) => { - return ( -
-
{option.name}
-
- ); }; - const brandOptions = brands.map(brand => ({ - name: `${brand.brand} (${brand.qty})`, - code: brand.brand - })); - const categoryOptions = categories.map(category => ({ - name: `${category.name} (${category.qty})`, - code: category.name + const brandOptions = brands.map((brand) => ({ + label: `${brand.brand} (${brand.qty})`, + value: brand.brand, })); - const panelFooterTemplate = () => { - return ( - - ); - }; + const categoryOptions = categories.map((category) => ({ + label: `${category.name} (${category.qty})`, + value: category.name, + })); return ( -
-
- - setSelectedBrand(e.value)} - optionLabel="name" - placeholder="Pilih Brand" - itemTemplate={countryTemplate} - panelFooterTemplate={panelFooterTemplate} - className="w-full" - display="chip" - /> -
+ <> +
+ {/* Brand MultiSelect */} +
+
+ +
+ setIsBrandDropdownClicked(isOpen)} + hasSelectAll={false} + /> +
+
+
+ + {/* Category MultiSelect */} +
+
+ +
+ + setIsCategoryDropdownClicked(!isCategoryDropdownClicked) + } + hasSelectAll={false} + /> +
+
+
-
- - setSelectedCategory(e.value)} - optionLabel="name" - placeholder="Pilih Kategori" - itemTemplate={countryTemplate} - panelFooterTemplate={panelFooterTemplate} - className="w-full" - display="chip" - /> + {/* Apply Button */} +
+
+ +
+
-
- ) -} + + ); +}; -export default ProductFilterDesktop +export default ProductFilterDesktop; diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index 7fea10ff..dbf8d908 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -372,7 +372,7 @@ export default function PromoDetail() {

Promo {whatPromo}

-
+
( -
+
{brandValues?.map((value, index) => ( Date: Thu, 20 Jun 2024 13:47:05 +0700 Subject: remove env --- .env | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 306e85ad..00000000 --- a/.env +++ /dev/null @@ -1,43 +0,0 @@ -SELF_HOST=http://localhost:2100 -# SELF_HOST=http://192.168.23.178:2100 -# ODOO_API_HOST=http://192.168.23.191:8069 -ODOO_API_HOST=http://192.168.23.251:8069 -# ODOO_API_HOST=http://192.168.23.73:8069 -# ODOO_API_HOST=https://erp.indoteknik.com -SOLR_HOST=http://34.101.189.218:8983 -# SOLR_HOST=http://192.168.23.5:8983 - -RAJA_ONGKIR_HOST='https://pro.rajaongkir.com' -RAJA_ONGKIR_KEY='7ac9883688da043b50cc32f0e3070bb6' - -MAIL_PORT=465 -MAIL_HOST=smtp.gmail.com -MAIL_USER=sales@indoteknik.com -MAIL_PASS=#&Win*%a3C%^FF - -MIDTRANS_HOST=https://api.sandbox.midtrans.com -MIDTRANS_ENV=development -MIDTRANS_SERVER_KEY=SB-Mid-server-n-V7d2c2ZB0SVED29OyCWVYp -MIDTRANS_CLIENT_KEY=SB-Mid-client-IsVHHv5mzPqNV7bs - -RECAPTCHA_GOOGLE=6LdajH0lAAAAAI6kCVHjR9rHuD22Pf-X7XakSQ_P - -NEXTAUTH_URL=http://localhost:2100 - -PPN=1.11 - -# GOOGLE_CLIENT_ID="396438712998-308hckshgeekr34phr5jskj1f6qltfvk.apps.googleusercontent.com" -# GOOGLE_CLIENT_SECRET=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 -GOOGLE_CLIENT_ID="140590317805-5k5v3pjb7gcv4rcefgt8udgmn3hllv0q.apps.googleusercontent.com" -GOOGLE_CLIENT_SECRET=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 - -JWT_SECRET=NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c - -NEXT_PUBLIC_SELF_HOST=$SELF_HOST -NEXT_PUBLIC_ODOO_API_HOST=$ODOO_API_HOST -NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY -NEXT_PUBLIC_RECAPTCHA_GOOGLE=$RECAPTCHA_GOOGLE -NEXT_PUBLIC_RAJA_ONGKIR_HOST=$RAJA_ONGKIR_HOST -NEXT_PUBLIC_RAJA_ONGKIR_KEY=$RAJA_ONGKIR_KEY -NEXT_PUBLIC_ODOO_HOST=$ODOO_API_HOST -NEXT_PUBLIC_PPN=$PPN \ No newline at end of file -- cgit v1.2.3 From 1cf754b4d8da1aa28700ffc3dad67081f6daf9a5 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 20 Jun 2024 15:23:58 +0700 Subject: update filter promotion-program --- src/pages/shop/promo/[slug].tsx | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/pages/shop/promo/[slug].tsx b/src/pages/shop/promo/[slug].tsx index dbf8d908..bd69c071 100644 --- a/src/pages/shop/promo/[slug].tsx +++ b/src/pages/shop/promo/[slug].tsx @@ -372,21 +372,28 @@ export default function PromoDetail() {

Promo {whatPromo}

-
- +
+ +
+ + +
+
+ + +
- {loading ? (
-- cgit v1.2.3 From cac51e393df3adfbb2ea971be9a26daf78e6ef90 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 28 Jun 2024 10:13:16 +0700 Subject: update button lihat semua --- src/lib/home/components/PromotionProgram.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index 98bc7c7f..66216d19 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -12,9 +12,7 @@ const BannerSection = () => {
Promo Tersedia
{isDesktop && ( - + Lihat Semua )} -- cgit v1.2.3 From 936f7f9fb1c6951e02dd8a5f7e85fb8d39cc7e6a Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Fri, 28 Jun 2024 10:23:57 +0700 Subject: delete console.log --- src/lib/product/components/ProductFilterDesktop.jsx | 2 +- src/lib/product/components/ProductSearch.jsx | 4 ++-- src/pages/shop/promo/index.tsx | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index b4afebc2..a8073036 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -21,7 +21,7 @@ import Image from '@/core/components/elements/Image/Image' import { formatCurrency } from '@/core/utils/formatValue' const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { - console.log("prefixUrl",prefixUrl) + const router = useRouter() const { query } = router const [order, setOrder] = useState(query?.orderBy) diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index ec0077c2..b1a5d409 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -130,7 +130,7 @@ const ProductSearch = ({ brands.push({ brand, qty }); } } - console.log("daftar brand",brands) + const categories = []; for ( @@ -145,7 +145,7 @@ const ProductSearch = ({ categories.push({ name, qty }); } } - console.log("daftar kategori",categories) + const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, diff --git a/src/pages/shop/promo/index.tsx b/src/pages/shop/promo/index.tsx index 89e88e29..7ec4f6b0 100644 --- a/src/pages/shop/promo/index.tsx +++ b/src/pages/shop/promo/index.tsx @@ -25,10 +25,10 @@ export default function Promo() { const loadPromo = async () => { try { const items = await fetchPromoItemsSolr(`*:*`) - console.log("slug sekarang ", slug) + setPromoItems(items) - console.log("data dari promotion pakai SOLR", items) + if (items.length === 0) { setPromoData([]) @@ -38,17 +38,17 @@ export default function Promo() { const promoDataPromises = items.map(async (item) => { const queryParams = new URLSearchParams({ q: `id:${item.id}` }) - console.log("Constructed URL:", `/solr/promotion_program_lines/select?${queryParams.toString()}`) + try { const response = await fetch(`/solr/promotion_program_lines/select?${queryParams.toString()}`) - console.log("respon data ", response) + if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } const data: SolrResponse = await response.json() - console.log("data promo IPromotion[]", data) + const promotions = await map(data.response.docs) return promotions; @@ -100,7 +100,7 @@ export default function Promo() { return result } - console.log("data yg dikirim ke ProductPromoCard", promoData) + useEffect(() => { -- cgit v1.2.3