From cd51b64b48b0c898c6ff901c1bfa23c70cd9cf1a Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 16:12:21 +0700 Subject: sementara --- .../product-detail/components/AddToCart.tsx | 9 ++++++- .../product-detail/components/PriceAction.tsx | 1 + src-migrate/pages/shop/product/[slug].tsx | 2 +- src/pages/api/shop/product-detail.js | 30 +++++++++++++--------- src/pages/api/shop/search.js | 2 +- src/pages/google_merchant/products/[page].js | 4 ++- src/pages/google_merchant/products/index.js | 4 ++- src/pages/sitemap/products/[page].js | 6 ++--- 8 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src-migrate/modules/product-detail/components/AddToCart.tsx b/src-migrate/modules/product-detail/components/AddToCart.tsx index 147fd6d2..0dc39c1c 100644 --- a/src-migrate/modules/product-detail/components/AddToCart.tsx +++ b/src-migrate/modules/product-detail/components/AddToCart.tsx @@ -66,6 +66,8 @@ const AddToCart = ({ weight: '', isFlashSale: false, }); + const hasPrice = + !!product?.lowest_price && Number(product.lowest_price.price) > 0; useEffect(() => { const fetchData = async () => { @@ -183,6 +185,7 @@ const AddToCart = ({ colorScheme={btnConfig[source].colorScheme} variant={btnConfig[source].variant} className='w-full' + isDisabled={!hasPrice || status === 'loading'} > {btnConfig[source].text} @@ -194,6 +197,7 @@ const AddToCart = ({ colorScheme={btnConfig[source].colorScheme} variant={btnConfig[source].variant} className='w-full' + isDisabled={!hasPrice || status === 'loading'} > {btnConfig[source].text} @@ -208,7 +212,10 @@ const AddToCart = ({ {/* ===== MOBILE LAYOUT: konten scroll + footer fixed di dalam popup ===== */}
{/* area scroll */} -
+
{/* HEADER ITEM */}
diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx index ffc9ba40..a329d2cc 100644 --- a/src-migrate/modules/product-detail/components/PriceAction.tsx +++ b/src-migrate/modules/product-detail/components/PriceAction.tsx @@ -37,6 +37,7 @@ const PriceAction = ({ product }: Props) => { } = useProductDetail(); const [qtyPickUp, setQtyPickUp] = useState(0); const { isDesktop, isMobile } = useDevice(); + useEffect(() => { setActive(selectedVariant); if (product.variants.length > 2 && product.variants[0].price.price === 0) { diff --git a/src-migrate/pages/shop/product/[slug].tsx b/src-migrate/pages/shop/product/[slug].tsx index 058e4832..8d6558b1 100644 --- a/src-migrate/pages/shop/product/[slug].tsx +++ b/src-migrate/pages/shop/product/[slug].tsx @@ -49,7 +49,7 @@ export const getServerSideProps: GetServerSideProps = async ( Array.isArray(product.variants) && product.variants.some((v) => (v?.price?.price ?? 0) > 0); - if (!hasValidVariant) return { notFound: true }; + // if (!hasValidVariant) return { notFound: true }; // bikin canonical path yang BERSIH dan KONSISTEN dari data produk, // bukan dari URL request user (jadi gak ikut ?utm_source, ?ref=, dsb) diff --git a/src/pages/api/shop/product-detail.js b/src/pages/api/shop/product-detail.js index faa96028..504f9dd6 100644 --- a/src/pages/api/shop/product-detail.js +++ b/src/pages/api/shop/product-detail.js @@ -1,26 +1,32 @@ -import { productMappingSolr, variantsMappingSolr } from '@/utils/solrMapping' -import axios from 'axios' +import { productMappingSolr, variantsMappingSolr } from '@/utils/solrMapping'; +import axios from 'axios'; export default async function handler(req, res) { try { let productTemplate = await axios( - process.env.SOLR_HOST + `/solr/product/select?q=id:${req.query.id}&q.op=OR&indent=true` - ) + process.env.SOLR_HOST + + `/solr/product/select?q=id:${req.query.id}&q.op=OR&indent=true` + ); let productVariants = await axios( process.env.SOLR_HOST + - `/solr/variants/select?q=template_id_i:${req.query.id}&q.op=OR&indent=true&rows=100&fq=-publish_b:false AND price_tier1_v2_f:[1 TO *]` - ) - let auth = req.query.auth === 'false' ? JSON.parse(req.query.auth) : req.query.auth - let result = productMappingSolr(productTemplate.data.response.docs, auth || false) + `/solr/variants/select?q=template_id_i:${req.query.id}&q.op=OR&indent=true&rows=100` + // `/solr/variants/select?q=template_id_i:${req.query.id}&q.op=OR&indent=true&rows=100&fq=-publish_b:false AND price_tier1_v2_f:[1 TO *]` + ); + let auth = + req.query.auth === 'false' ? JSON.parse(req.query.auth) : req.query.auth; + let result = productMappingSolr( + productTemplate.data.response.docs, + auth || false + ); result[0].variants = variantsMappingSolr( productTemplate.data.response.docs[0], productVariants.data.response.docs, auth || false - ) - res.status(200).json(result) + ); + res.status(200).json(result); } catch (error) { - console.error('Error fetching data from Solr:', error) - res.status(500).json({ error: 'Internal Server Error' }) + console.error('Error fetching data from Solr:', error); + res.status(500).json({ error: 'Internal Server Error' }); } } diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 8c9782cb..a3e1b3a3 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -83,7 +83,7 @@ export default async function handler(req, res) { : `${checkQ.length}`; const filterQueries = [ - '-publish_b:false', + // '-publish_b:false', 'product_rating_f:[8 TO *]', 'price_tier1_v2_f:[1 TO *]', ]; diff --git a/src/pages/google_merchant/products/[page].js b/src/pages/google_merchant/products/[page].js index 161b6aec..2a53f7c0 100644 --- a/src/pages/google_merchant/products/[page].js +++ b/src/pages/google_merchant/products/[page].js @@ -18,7 +18,9 @@ export async function getServerSideProps({ res, query }) { page: page.replace('.xml', ''), priceFrom: 1, orderBy: 'popular', - fq: ['image_s:["" TO *] AND publish_b:true'], + fq: ['image_s:["" TO *] AND publish_b:true AND price_tier1_v2_f:[1 TO *]'], + // product_rating_f: '[8 TO *]', + // price_tier1_v2_f: '[1 TO *]', }; const products = await variantSearchApi({ query: _.toQuery(queries) }); diff --git a/src/pages/google_merchant/products/index.js b/src/pages/google_merchant/products/index.js index b6c7bfef..d6ef413a 100644 --- a/src/pages/google_merchant/products/index.js +++ b/src/pages/google_merchant/products/index.js @@ -8,7 +8,9 @@ export async function getServerSideProps() { const queries = { limit: 1, priceFrom: 1, - fq: 'image_s:["" TO *] AND publish_b:true', + fq: 'image_s:["" TO *] AND publish_b:true AND price_tier1_v2_f:[1 TO *]', + // product_rating_f: '[8 TO *]', + // price_tier1_v2_f: '[1 TO *]', }; const products = await variantSearchApi({ query: _.toQuery(queries) }); const { numFound } = products.response; diff --git a/src/pages/sitemap/products/[page].js b/src/pages/sitemap/products/[page].js index 421c08e3..ebb6aef7 100644 --- a/src/pages/sitemap/products/[page].js +++ b/src/pages/sitemap/products/[page].js @@ -10,9 +10,9 @@ export async function getServerSideProps({ query, res }) { const queries = { limit, page: page.replace('.xml', ''), - '-publish_b': false, - product_rating_f: '[8 TO *]', - price_tier1_v2_f: '[1 TO *]', + // '-publish_b': false, + // product_rating_f: '[8 TO *]', + // price_tier1_v2_f: '[1 TO *]', }; const products = await productSearchApi({ query: _.toQuery(queries) }); const sitemap = create('urlset', { encoding: 'utf-8' }).att( -- cgit v1.2.3 From 7cf105a01a814c5f76dd6b407df284a44026cabf Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 17:14:37 +0700 Subject: done product detail --- .../product-detail/components/AddToQuotation.tsx | 20 ++++++- .../product-detail/components/PriceAction.tsx | 26 ++++++--- .../product-detail/components/ProductDetail.tsx | 67 +++++++++++++++------- 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src-migrate/modules/product-detail/components/AddToQuotation.tsx b/src-migrate/modules/product-detail/components/AddToQuotation.tsx index ebfcef32..3e811330 100644 --- a/src-migrate/modules/product-detail/components/AddToQuotation.tsx +++ b/src-migrate/modules/product-detail/components/AddToQuotation.tsx @@ -60,6 +60,8 @@ const AddToQuotation = ({ `fq=-manufacture_id_i:${product.manufacture?.id || 0}`, ].join('&'); const [addCartAlert, setAddCartAlert] = useState(false); + const hasPrice = + !!product?.lowest_price && Number(product.lowest_price.price) > 0; const handleButton = async () => { if (typeof auth !== 'object') { @@ -124,9 +126,10 @@ const AddToQuotation = ({ color={'red'} colorScheme='white' className='w-full border-2 p-2 gap-1 hover:bg-slate-100 flex items-center' + isDisabled={!hasPrice} > )} - {!!product.lowest_price && product.lowest_price.price === 0 && ( + {(!!product.lowest_price && product.lowest_price.price === 0) || + product.lowest_price.price < 0 ? ( + + Hubungi kami untuk dapatkan harga terbaik,{' '} + + klik disini + + + ) : ( Hubungi kami untuk dapatkan harga terbaik,{' '} { const validJsonString = stringVoucher.replace(/'/g, '"'); voucherPastiHemat = JSON.parse(validJsonString); } + const hasPrice = Number(product?.lowest_price?.price) > 0; return (
{ )} - {!!activePrice && activePrice.price === 0 && ( + {/* {!!activePrice && activePrice.price === 0 && ( Hubungi kami untuk dapatkan harga terbaik,{' '} { klik disini - )} + )} */}
@@ -165,27 +166,32 @@ const PriceAction = ({ product }: Props) => {
+ setQuantityInput(e.target.value)} - className={style['quantity-input']} + className={`${style['quantity-input']} disabled:bg-gray-100 disabled:text-gray-400`} + disabled={!hasPrice} /> + @@ -196,9 +202,11 @@ const PriceAction = ({ product }: Props) => { - Stock : {sla?.qty}{' '} + Stock : {hasPrice ? sla?.qty : 'Habis'}
@@ -219,9 +227,9 @@ const PriceAction = ({ product }: Props) => { )}
- + {/* * {qtyPickUp} barang bisa di pickup - + */} {/* ===== MOBILE: grid kiri-kanan, kanan hanya qty ===== */} diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index f32bb38e..c8c03300 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -5,7 +5,12 @@ import { useRouter } from 'next/router'; import { useEffect, useRef, useState, UIEvent } from 'react'; import { Button } from '@chakra-ui/react'; -import { MessageCircleIcon, Share2Icon } from 'lucide-react'; +import { + AlertCircle, + AlertTriangle, + MessageCircleIcon, + Share2Icon, +} from 'lucide-react'; import { LazyLoadComponent } from 'react-lazy-load-image-component'; import useDevice from '@/core/hooks/useDevice'; @@ -23,7 +28,6 @@ import SimilarBottom from './SimilarBottom'; import SimilarSide from './SimilarSide'; import dynamic from 'next/dynamic'; - import { gtagProductDetail } from '@/core/utils/googleTag'; type Props = { @@ -31,7 +35,7 @@ type Props = { }; const RWebShare = dynamic( - () => import('react-web-share').then(m => m.RWebShare), + () => import('react-web-share').then((m) => m.RWebShare), { ssr: false } ); @@ -42,7 +46,9 @@ const ProductDetail = ({ product }: Props) => { const router = useRouter(); const [auth, setAuth] = useState(null); useEffect(() => { - try { setAuth(getAuth() ?? null); } catch { } + try { + setAuth(getAuth() ?? null); + } catch {} }, []); const canShare = @@ -87,7 +93,6 @@ const ProductDetail = ({ product }: Props) => { setSelectedVariant(selectedVariant); }, []); - const allImages = (() => { const arr: string[] = []; if (product?.image) arr.push(product.image); @@ -95,7 +100,6 @@ const ProductDetail = ({ product }: Props) => { Array.isArray(product?.image_carousel) && product.image_carousel.length ) { - const set = new Set(arr); for (const img of product.image_carousel) { if (!set.has(img)) { @@ -108,15 +112,14 @@ const ProductDetail = ({ product }: Props) => { })(); const [mainImage, setMainImage] = useState(allImages[0] || ''); + const hasPrice = Number(product?.lowest_price?.price) > 0; useEffect(() => { - if (!allImages.includes(mainImage)) { setMainImage(allImages[0] || ''); } }, [allImages]); - const sliderRef = useRef(null); const [currentIdx, setCurrentIdx] = useState(0); @@ -138,7 +141,6 @@ const ProductDetail = ({ product }: Props) => { setMainImage(allImages[i] || ''); }; - return ( <>
@@ -165,7 +167,6 @@ const ProductDetail = ({ product }: Props) => { > {allImages.length > 0 ? ( allImages.map((img, i) => ( -
{ | - +
+ +
| @@ -317,10 +335,17 @@ const ProductDetail = ({ product }: Props) => { data={{ text: 'Check out this product', title: `${product.name} - Indoteknik.com`, - url: (process.env.NEXT_PUBLIC_SELF_HOST || '') + (router?.asPath || '/'), + url: + (process.env.NEXT_PUBLIC_SELF_HOST || '') + + (router?.asPath || '/'), }} > - @@ -350,8 +375,6 @@ const ProductDetail = ({ product }: Props) => {
); - - }; export default ProductDetail; -- cgit v1.2.3 From 0eedef242e76673e6882ec11b87a9371d6ec5164 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 17:22:46 +0700 Subject: mobile --- src-migrate/modules/product-detail/components/PriceAction.tsx | 7 +++++-- src-migrate/modules/product-detail/components/ProductDetail.tsx | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx index 510dd6a9..d73ab5f6 100644 --- a/src-migrate/modules/product-detail/components/PriceAction.tsx +++ b/src-migrate/modules/product-detail/components/PriceAction.tsx @@ -264,11 +264,11 @@ const PriceAction = ({ product }: Props) => { )}
- {qtyPickUp > 0 && ( + {/* {qtyPickUp > 0 && (
* {qtyPickUp} barang bisa di pickup
- )} + )} */}
{/* Kanan: hanya qty, rata kanan */} @@ -283,6 +283,7 @@ const PriceAction = ({ product }: Props) => { ) } aria-label='Kurangi' + disabled={!hasPrice} > @@ -297,6 +298,7 @@ const PriceAction = ({ product }: Props) => { [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none' + disabled={!hasPrice} /> diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index c8c03300..76fa8298 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -252,7 +252,7 @@ const ProductDetail = ({ product }: Props) => { {/* ===== Kolom kanan: info ===== */}
{!hasPrice && ( -
+
Date: Wed, 12 Nov 2025 17:56:28 +0700 Subject: fix label desktop and mobile --- .../product-detail/components/ProductDetail.tsx | 68 ++++++++++++++++------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 76fa8298..354889e5 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -143,6 +143,16 @@ const ProductDetail = ({ product }: Props) => { return ( <> + {/* WATERMARK OVERLAY jika produk tidak punya harga */} + {!hasPrice && ( +
+ Produk tidak tersedia +
+ )}
@@ -250,24 +260,46 @@ const ProductDetail = ({ product }: Props) => { {/* <<=== TUTUP kolom kiri */} {/* ===== Kolom kanan: info ===== */} -
- {!hasPrice && ( -
- -

- Maaf untuk saat ini Produk yang anda cari tidak tersedia -

-
- )} -
-

{product.name}

-
- -
-
+ {isDesktop && ( +
+ {!hasPrice && ( +
+ +

+ Maaf untuk saat ini Produk yang anda cari tidak tersedia +

+
+ )} +
+

{product.name}

+
+ +
+
+ )} + {isMobile && ( +
+ {!hasPrice && ( +
+ +

+ Maaf untuk saat ini Produk yang anda cari tidak tersedia +

+
+ )} +
+

{product.name}

+
+ +
+
+ )}
-- cgit v1.2.3 From d292f00640a5b0cf68019eedebcdbb87ecb27270 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 18:18:03 +0700 Subject: watermark produk tidak tersedia --- public/images/produk_tidak_tersedia.svg | 91 ++++++++++++++++++++++ .../product-detail/components/ProductDetail.tsx | 11 ++- 2 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 public/images/produk_tidak_tersedia.svg diff --git a/public/images/produk_tidak_tersedia.svg b/public/images/produk_tidak_tersedia.svg new file mode 100644 index 00000000..69fe214b --- /dev/null +++ b/public/images/produk_tidak_tersedia.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 354889e5..388d2248 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -143,16 +143,16 @@ const ProductDetail = ({ product }: Props) => { return ( <> - {/* WATERMARK OVERLAY jika produk tidak punya harga */} - {!hasPrice && ( -
+ {isDesktop && !hasPrice && ( +
Produk tidak tersedia
)} +
@@ -293,7 +293,6 @@ const ProductDetail = ({ product }: Props) => {
)} -

{product.name}

-- cgit v1.2.3 From deaa4c5417bfb8b41d00b523e63e1b9b24a6ff76 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 18:26:25 +0700 Subject: hide whatsapp --- src/core/components/layouts/BasicLayout.jsx | 101 +++++++++++++++------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx index 81f8b41f..b13e807d 100644 --- a/src/core/components/layouts/BasicLayout.jsx +++ b/src/core/components/layouts/BasicLayout.jsx @@ -33,6 +33,10 @@ const BasicLayout = ({ children }) => { const { product } = useProductContext(); + const hasPrice = + product && + Number(product?.lowest_price?.price || product?.price?.price) > 0; + useEffect(() => { if ( router.pathname === '/shop/product/[slug]' || @@ -54,8 +58,7 @@ const BasicLayout = ({ children }) => { useEffect(() => { const handleMouseOut = (event) => { - - if (!buttonRef.current) return; + if (!buttonRef.current) return; const rect = buttonRef.current.getBoundingClientRect(); if (event.clientY <= 0) { setButtonPosition(rect); @@ -114,56 +117,58 @@ const BasicLayout = ({ children }) => { onAnimationEnd={() => setHighlight(false)} /> )} - + {children} -
- + )} -- cgit v1.2.3 From ff27a8752df545554fcee1beb8acbb24011a040b Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 18:33:30 +0700 Subject: mobile watermark --- src-migrate/modules/product-detail/components/ProductDetail.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 388d2248..48270dee 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -152,6 +152,15 @@ const ProductDetail = ({ product }: Props) => { />
)} + {isMobile && !hasPrice && ( +
+ Produk tidak tersedia +
+ )}
-- cgit v1.2.3 From 31a0644d72475279b16cd646ab5d2f60facc0b24 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Wed, 12 Nov 2025 18:45:54 +0700 Subject: balikin --- src/pages/api/shop/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index a3e1b3a3..8c9782cb 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -83,7 +83,7 @@ export default async function handler(req, res) { : `${checkQ.length}`; const filterQueries = [ - // '-publish_b:false', + '-publish_b:false', 'product_rating_f:[8 TO *]', 'price_tier1_v2_f:[1 TO *]', ]; -- cgit v1.2.3 From a19ab70ca8f3f20c845ddeed0a5281d2abc29f03 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 15:48:26 +0700 Subject: update robots & last mod --- public/robots.txt | 4 ---- src/pages/sitemap/blogs.xml.js | 4 ++-- src/pages/sitemap/brands.xml.js | 4 ++-- src/pages/sitemap/categories-brand.xml.js | 4 ++-- src/pages/sitemap/categories-brand/[page].js | 4 ++-- src/pages/sitemap/categories.xml.js | 4 ++-- src/pages/sitemap/products.xml.js | 4 ++-- src/pages/sitemap/products/[page].js | 4 ++-- 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/public/robots.txt b/public/robots.txt index 1520dbb4..f9caa9bf 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -17,15 +17,11 @@ Disallow: /shop/search/* Disallow: /promo/* Disallow: /shop/brands/*?* Disallow: /shop/category/*?* -Disallow: /shop/product/*?* User-agent: Adsbot-Google Allow: /my/* Allow: /shop/search/* -User-agent: * -Disallow: sentral.indoteknik.com/* -Disallow: erp.indoteknik.com/* Sitemap: https://indoteknik.com/sitemap/products.xml Sitemap: https://indoteknik.com/sitemap/brands.xml diff --git a/src/pages/sitemap/blogs.xml.js b/src/pages/sitemap/blogs.xml.js index 628dc710..3b6969b8 100644 --- a/src/pages/sitemap/blogs.xml.js +++ b/src/pages/sitemap/blogs.xml.js @@ -10,8 +10,8 @@ export async function getServerSideProps({ res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; blogs.blogs.forEach((blog) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, blog.title, blog.id)); diff --git a/src/pages/sitemap/brands.xml.js b/src/pages/sitemap/brands.xml.js index c2199d85..3c7f1ade 100644 --- a/src/pages/sitemap/brands.xml.js +++ b/src/pages/sitemap/brands.xml.js @@ -10,8 +10,8 @@ export async function getServerSideProps({ res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; brands.manufactures.forEach((brand) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, brand.name, brand.id)); diff --git a/src/pages/sitemap/categories-brand.xml.js b/src/pages/sitemap/categories-brand.xml.js index faf67b9f..f3f2b33f 100644 --- a/src/pages/sitemap/categories-brand.xml.js +++ b/src/pages/sitemap/categories-brand.xml.js @@ -16,8 +16,8 @@ export async function getServerSideProps({ res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; pages.forEach((page) => { const sitemap = sitemapIndex.ele('sitemap'); sitemap.ele('loc', `${baseUrl}/${page}.xml`); diff --git a/src/pages/sitemap/categories-brand/[page].js b/src/pages/sitemap/categories-brand/[page].js index 4d28ab04..3b81aaea 100644 --- a/src/pages/sitemap/categories-brand/[page].js +++ b/src/pages/sitemap/categories-brand/[page].js @@ -22,8 +22,8 @@ export async function getServerSideProps({ query, res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; categories.data.response.docs.forEach((product) => { const url = sitemap.ele('url'); const loc = product.url_s; diff --git a/src/pages/sitemap/categories.xml.js b/src/pages/sitemap/categories.xml.js index 357a2072..61fe42d1 100644 --- a/src/pages/sitemap/categories.xml.js +++ b/src/pages/sitemap/categories.xml.js @@ -28,8 +28,8 @@ export async function getServerSideProps({ res }) { function addUrlToSitemap(sitemap, name, id) { const baseUrl = process.env.SELF_HOST + '/shop/category/'; - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, name, id)); url.ele('lastmod', date); diff --git a/src/pages/sitemap/products.xml.js b/src/pages/sitemap/products.xml.js index 0269ec59..221a024a 100644 --- a/src/pages/sitemap/products.xml.js +++ b/src/pages/sitemap/products.xml.js @@ -14,8 +14,8 @@ export async function getServerSideProps({ res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; pages.forEach((page) => { const sitemap = sitemapIndex.ele('sitemap'); sitemap.ele('loc', `${baseUrl}/${page}.xml`); diff --git a/src/pages/sitemap/products/[page].js b/src/pages/sitemap/products/[page].js index ebb6aef7..f9fba72b 100644 --- a/src/pages/sitemap/products/[page].js +++ b/src/pages/sitemap/products/[page].js @@ -20,8 +20,8 @@ export async function getServerSideProps({ query, res }) { 'http://www.sitemaps.org/schemas/sitemap/0.9' ); - // const date = new Date() - const date = '2025-10-30'; + const date = new Date(); + // const date = '2025-10-30'; products.response.products.forEach((product) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, product.name, product.id)); -- cgit v1.2.3 From 8ed66318c1e94d4c744984f2aab25ff993d5de4d Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 15:59:08 +0700 Subject: cr watermark --- .../product-detail/components/ProductDetail.tsx | 41 ++++++++++++---------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 48270dee..e4ba2b2f 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -143,24 +143,29 @@ const ProductDetail = ({ product }: Props) => { return ( <> - {isDesktop && !hasPrice && ( -
- Produk tidak tersedia -
- )} - {isMobile && !hasPrice && ( -
- Produk tidak tersedia -
- )} +
+ {isDesktop && !hasPrice && ( +
+ Produk tidak tersedia +
+ )} +
+ +
+ {isMobile && !hasPrice && ( +
+ Produk tidak tersedia +
+ )} +
-- cgit v1.2.3 From d793056d1645c221d02fb821e34ab2c435c387d0 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 16:20:23 +0700 Subject: product variant --- .../components/Product/ProductDesktopVariant.jsx | 151 ++++++----- .../components/Product/ProductMobileVariant.jsx | 281 +++++++++++---------- 2 files changed, 231 insertions(+), 201 deletions(-) diff --git a/src/lib/product/components/Product/ProductDesktopVariant.jsx b/src/lib/product/components/Product/ProductDesktopVariant.jsx index 44ae04bd..6b4ab1e1 100644 --- a/src/lib/product/components/Product/ProductDesktopVariant.jsx +++ b/src/lib/product/components/Product/ProductDesktopVariant.jsx @@ -1,3 +1,4 @@ +import { AlertTriangle } from 'lucide-react'; import { Box, Button, Skeleton, Tooltip } from '@chakra-ui/react'; import { HeartIcon } from '@heroicons/react/24/outline'; import { Info, MessageCircleIcon, Share2Icon } from 'lucide-react'; @@ -249,6 +250,7 @@ const ProductDesktopVariant = ({ }); router.push('/shop/quotation?source=buy'); }; + const hasPrice = Number(product?.price?.price) > 0; const variantSectionRef = useRef(null); const goToVariantSection = () => { @@ -314,6 +316,17 @@ const ProductDesktopVariant = ({ return ( +
+ {!hasPrice && ( +
+ Produk tidak tersedia +
+ )} +
@@ -326,9 +339,21 @@ const ProductDesktopVariant = ({
+ {!hasPrice && ( +
+ +

+ Maaf untuk saat ini Produk yang anda cari tidak tersedia +

+
+ )}

{product?.name}

+
Item Code
@@ -430,73 +455,55 @@ const ProductDesktopVariant = ({
- {product?.isFlashsale > 0 && - product?.price?.discountPercentage > 0 ? ( + {product?.price?.price > 0 && ( <> -
-
- {product?.price?.discountPercentage}% -
-
- {currencyFormat(product?.price?.price)} -
-
- {currencyFormat(product?.price?.priceDiscount)} -
-
-
- Termasuk PPN:{' '} - {currencyFormat( - product?.price?.priceDiscount * process.env.NEXT_PUBLIC_PPN - )} -
- - ) : ( -

- {product?.price?.price > 0 ? ( + {product?.isFlashsale > 0 && + product?.price?.discountPercentage > 0 ? ( <> - {currencyFormat(product?.price?.price)} +
+
+ {product?.price?.discountPercentage}% +
+
+ {currencyFormat(product?.price?.price)} +
+
+ {currencyFormat(product?.price?.priceDiscount)} +
+
Termasuk PPN:{' '} {currencyFormat( - product?.price?.price * process.env.NEXT_PUBLIC_PPN + product?.price?.priceDiscount * + process.env.NEXT_PUBLIC_PPN )}
) : ( - - Hubungi kami untuk dapatkan harga terbaik,  - - klik disini - - +

+ {currencyFormat(product?.price?.price)} +
+ Termasuk PPN:{' '} + {currencyFormat( + product?.price?.price * process.env.NEXT_PUBLIC_PPN + )} +
+

)} - + )} +
@@ -518,43 +525,40 @@ const ProductDesktopVariant = ({ if (['e', 'E', '+', '-', '.'].includes(e.key)) e.preventDefault(); }} - className='w-24 h-10 text-center border border-gray-300 rounded focus:outline-none' + className='w-24 h-10 text-center border border-gray-300 rounded focus:outline-none disabled:bg-gray-100 disabled:text-gray-400' + disabled={!hasPrice} />
- {/* - Stock : {product?.sla?.qty}{' '} - */} - - Stock : {fakeStock}{' '} + Stock : {hasPrice ? fakeStock : 'Habis'}
+
- {qtyPickUp > 0 && ( + {qtyPickUp > 0 && hasPrice && (
- {qtyPickUp > 0 && ( + {/* {qtyPickUp > 0 && ( <>
* {qtyPickUp} barang bisa di pickup
- )} + )} */}
@@ -586,6 +593,9 @@ const ProductDesktopVariant = ({ onClick={() => handleBuy(product.id)} className='w-full' colorScheme='red' + isDisabled={ + !product?.price?.price || product?.price?.price <= 0 + } > Beli @@ -595,6 +605,7 @@ const ProductDesktopVariant = ({ color={'red'} colorScheme='white' className='w-full border-2 p-2 gap-1 mt-2 hover:bg-slate-100 flex items-center' + isDisabled={!product?.price?.price || product?.price?.price <= 0} > + {/* Watermark jika produk nonaktif */} + {/* {(!product?.price?.price || product?.price?.price <= 0) && ( +
+ + NONAKTIF + +
+ )} */}
{product.name} diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx index 4cfc63ca..e6c2204b 100644 --- a/src/lib/product/components/Product/ProductMobileVariant.jsx +++ b/src/lib/product/components/Product/ProductMobileVariant.jsx @@ -183,10 +183,20 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { return ( - {/* PRICE & ACTIONS: tetap punyamu, hanya hapus input number lama */} - {/* ===== BAR BAWAH (fixed) ===== */} +
+ {!product.price.price > 0 && ( +
+ Produk tidak tersedia +
+ )} +
+ {/* ===== BAR BAWAH ===== */}
- {/* HARGA & PPN (logikamu tetap) */} + {/* HARGA & PPN */} {activeVariant.isFlashSale && activeVariant?.price?.discountPercentage > 0 ? ( <> @@ -220,80 +230,65 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { )}
- ) : ( - - Hubungi kami untuk dapatkan harga terbaik,  - - klik disini - - - )} + ) : null}
)} - {/* ⬇️ TAMBAHKAN BLOK INI DI DALAM BAR: STOK & STEPPER */}
-
-
- {/* Stock : {activeVariant?.stock ?? 0} */} - Stock : {fakeStock}{' '} -
- {qtyPickUp > 0 && ( -
- * {qtyPickUp} barang bisa di pickup + {product?.price?.price > 0 && ( +
+
+ {/* Stock : {activeVariant?.stock ?? 0} */} + Stock : {fakeStock}{' '}
- )} -
+ {qtyPickUp > 0 && ( +
+ * {qtyPickUp} barang bisa di pickup +
+ )} +
+ )}
-
- - setQuantityInput(e.target.value)} - className='h-10 w-16 text-center text-lg outline-none border-x + {product?.price?.price > 0 && ( +
+ + setQuantityInput(e.target.value)} + className='h-10 w-16 text-center text-lg outline-none border-x [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none' - /> - -
+ /> + +
+ )}
@@ -306,6 +301,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { className='flex items-center justify-center p-2 border-2 hover:bg-slate-100' variant='outline' title='Lihat Dokumen' + isDisabled={product?.price?.price <= 0} > { className='flex-1' colorScheme='red' variant='outline' - isDisabled={product.stock === 0} + isDisabled={product?.price?.price <= 0} > Keranjang @@ -333,7 +329,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { } className='flex-1' colorScheme='red' - isDisabled={product.stock === 0} + isDisabled={product?.price?.price <= 0} > Beli @@ -396,87 +392,92 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { active={informationTab == 'specification'} className='rounded border border-gray_r-6 divide-y divide-gray_r-6' > - - - {isLoadingSLA ? ( - - ) : product?.sla?.slaDate != '-' ? ( -
-
- -
- - ) : ( - '-' - )} - - + {product?.sla?.slaDate} +
+
+ +
+ + ) : ( + '-' + )} + + + )} + SKU-{product?.id} {activeVariant?.code || '-'} - - {activeVariant?.stock > 0 && ( - -
Ready Stock
-
- {activeVariant?.stock > 5 ? '> 5' : '< 5'} -
-
- )} - {activeVariant?.stock == 0 && ( - - Tanya Stok - - )} -
+ {product?.price?.price > 0 && ( + + {activeVariant?.stock > 0 && ( + +
Ready Stock
+
+ {activeVariant?.stock > 5 ? '> 5' : '< 5'} +
+
+ )} + {activeVariant?.stock == 0 && ( + + Tanya Stok + + )} +
+ )} - {activeVariant?.weight > 0 && ( + {activeVariant?.weight > -1 && ( {activeVariant?.weight} KG )} - {activeVariant?.weight == 0 && ( + {activeVariant?.weight == -1 && ( { true ), })} - className='text-danger-500 font-medium' + className={`text-danger-501 font-medium ${ + !product?.price?.price || product?.price?.price <= 0 + ? 'pointer-events-none opacity-50 cursor-default' + : '' + }`} > Tanya Berat -- cgit v1.2.3 From fba96afd46d37e9cac4f480dac7c6a8fba36ae9a Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 16:28:01 +0700 Subject: fix xml date --- src/pages/sitemap/blogs.xml.js | 2 +- src/pages/sitemap/brands.xml.js | 2 +- src/pages/sitemap/categories-brand.xml.js | 2 +- src/pages/sitemap/categories-brand/[page].js | 2 +- src/pages/sitemap/categories.xml.js | 2 +- src/pages/sitemap/products.xml.js | 2 +- src/pages/sitemap/products/[page].js | 8 ++++---- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/sitemap/blogs.xml.js b/src/pages/sitemap/blogs.xml.js index 3b6969b8..1125ad1c 100644 --- a/src/pages/sitemap/blogs.xml.js +++ b/src/pages/sitemap/blogs.xml.js @@ -15,7 +15,7 @@ export async function getServerSideProps({ res }) { blogs.blogs.forEach((blog) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, blog.title, blog.id)); - url.ele('lastmod', date); + url.ele('lastmod', date.toISOString().slice(0, 10)); url.ele('changefreq', 'weekly'); url.ele('priority', '0.6'); }); diff --git a/src/pages/sitemap/brands.xml.js b/src/pages/sitemap/brands.xml.js index 3c7f1ade..dc92419c 100644 --- a/src/pages/sitemap/brands.xml.js +++ b/src/pages/sitemap/brands.xml.js @@ -15,7 +15,7 @@ export async function getServerSideProps({ res }) { brands.manufactures.forEach((brand) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, brand.name, brand.id)); - url.ele('lastmod', date); + url.ele('lastmod', date.toISOString().slice(0, 10)); url.ele('changefreq', 'daily'); url.ele('priority', '1.0'); }); diff --git a/src/pages/sitemap/categories-brand.xml.js b/src/pages/sitemap/categories-brand.xml.js index f3f2b33f..8dfd3a32 100644 --- a/src/pages/sitemap/categories-brand.xml.js +++ b/src/pages/sitemap/categories-brand.xml.js @@ -21,7 +21,7 @@ export async function getServerSideProps({ res }) { pages.forEach((page) => { const sitemap = sitemapIndex.ele('sitemap'); sitemap.ele('loc', `${baseUrl}/${page}.xml`); - sitemap.ele('lastmod', date); + sitemap.ele('lastmod', date.toISOString().slice(0, 10)); }); res.setHeader('Content-Type', 'text/xml'); diff --git a/src/pages/sitemap/categories-brand/[page].js b/src/pages/sitemap/categories-brand/[page].js index 3b81aaea..e7f264ee 100644 --- a/src/pages/sitemap/categories-brand/[page].js +++ b/src/pages/sitemap/categories-brand/[page].js @@ -28,7 +28,7 @@ export async function getServerSideProps({ query, res }) { const url = sitemap.ele('url'); const loc = product.url_s; url.ele('loc', loc); - url.ele('lastmod', date); + url.ele('lastmod', date.toISOString().slice(0, 10)); url.ele('changefreq', 'daily'); url.ele('priority', '0.8'); }); diff --git a/src/pages/sitemap/categories.xml.js b/src/pages/sitemap/categories.xml.js index 61fe42d1..18c8a8f3 100644 --- a/src/pages/sitemap/categories.xml.js +++ b/src/pages/sitemap/categories.xml.js @@ -32,7 +32,7 @@ function addUrlToSitemap(sitemap, name, id) { // const date = '2025-10-30'; const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, name, id)); - url.ele('lastmod', date); + url.ele('lastmod', date.toISOString().slice(0, 10)); url.ele('changefreq', 'weekly'); url.ele('priority', '0.6'); } diff --git a/src/pages/sitemap/products.xml.js b/src/pages/sitemap/products.xml.js index 221a024a..5ed6b759 100644 --- a/src/pages/sitemap/products.xml.js +++ b/src/pages/sitemap/products.xml.js @@ -19,7 +19,7 @@ export async function getServerSideProps({ res }) { pages.forEach((page) => { const sitemap = sitemapIndex.ele('sitemap'); sitemap.ele('loc', `${baseUrl}/${page}.xml`); - sitemap.ele('lastmod', date); + sitemap.ele('lastmod', date.toISOString().slice(0, 10)); }); res.setHeader('Content-Type', 'text/xml'); diff --git a/src/pages/sitemap/products/[page].js b/src/pages/sitemap/products/[page].js index f9fba72b..316ad33d 100644 --- a/src/pages/sitemap/products/[page].js +++ b/src/pages/sitemap/products/[page].js @@ -10,9 +10,9 @@ export async function getServerSideProps({ query, res }) { const queries = { limit, page: page.replace('.xml', ''), - // '-publish_b': false, - // product_rating_f: '[8 TO *]', - // price_tier1_v2_f: '[1 TO *]', + '-publish_b': false, + product_rating_f: '[8 TO *]', + price_tier1_v2_f: '[1 TO *]', }; const products = await productSearchApi({ query: _.toQuery(queries) }); const sitemap = create('urlset', { encoding: 'utf-8' }).att( @@ -25,7 +25,7 @@ export async function getServerSideProps({ query, res }) { products.response.products.forEach((product) => { const url = sitemap.ele('url'); url.ele('loc', createSlug(baseUrl, product.name, product.id)); - url.ele('lastmod', date); + url.ele('lastmod', date.toISOString().slice(0, 10)); url.ele('changefreq', 'daily'); url.ele('priority', '0.8'); }); -- cgit v1.2.3 From d925332714b809c4ec60aea9eeb902a2ea2ad7f4 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 16:29:09 +0700 Subject: remove query in product page sitemap --- src/pages/sitemap/products/[page].js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/sitemap/products/[page].js b/src/pages/sitemap/products/[page].js index 316ad33d..3603d64c 100644 --- a/src/pages/sitemap/products/[page].js +++ b/src/pages/sitemap/products/[page].js @@ -10,9 +10,9 @@ export async function getServerSideProps({ query, res }) { const queries = { limit, page: page.replace('.xml', ''), - '-publish_b': false, - product_rating_f: '[8 TO *]', - price_tier1_v2_f: '[1 TO *]', + // '-publish_b': false, + // product_rating_f: '[8 TO *]', + // price_tier1_v2_f: '[1 TO *]', }; const products = await productSearchApi({ query: _.toQuery(queries) }); const sitemap = create('urlset', { encoding: 'utf-8' }).att( -- cgit v1.2.3 From 48c1110541a30bb33726a6f46737615b98f1d9c5 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Thu, 13 Nov 2025 17:13:53 +0700 Subject: Fix eror --- .../components/Product/ProductMobileVariant.jsx | 2 +- src/pages/shop/product/variant/[slug].jsx | 46 +++++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx index e6c2204b..0f4953df 100644 --- a/src/lib/product/components/Product/ProductMobileVariant.jsx +++ b/src/lib/product/components/Product/ProductMobileVariant.jsx @@ -189,7 +189,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { Produk tidak tersedia
)} diff --git a/src/pages/shop/product/variant/[slug].jsx b/src/pages/shop/product/variant/[slug].jsx index 2c0dd64b..32c00a35 100644 --- a/src/pages/shop/product/variant/[slug].jsx +++ b/src/pages/shop/product/variant/[slug].jsx @@ -25,23 +25,39 @@ export async function getServerSideProps(context) { const tier = auth.pricelist ? auth.pricelist : false; const authToken = auth?.token || ''; - let response = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/variant-detail?id=` + - getIdFromSlug(slug) + - '&auth=' + - tier - ); - let product = response.data; + try { + const response = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/variant-detail?id=` + + getIdFromSlug(slug) + + '&auth=' + + tier + ); - if (product?.length == 1) { - product = product[0]; - } else { - product = null; - } + let product = response.data; - return { - props: { product }, - }; + if (product?.length == 1) { + product = product[0]; + } else { + product = null; + } + + return { + props: { product }, + }; + } catch (error) { + // kalau status 500 → tampilkan halaman 404 + if (error.response && error.response.status === 500) { + return { notFound: true }; + } + + // kalau 404 dari API juga langsung 404 + if (error.response && error.response.status === 404) { + return { notFound: true }; + } + + // kalau error lain, lempar agar bisa dilihat di console log server + throw error; + } } export default function ProductDetail({ product }) { -- cgit v1.2.3