From a5e695f82e03577cc85c4a1dded9f6021f0235fc Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Fri, 28 Nov 2025 09:36:15 +0700 Subject: (andri) try get detail product from magento --- .../product-detail/components/ProductDetail.tsx | 114 ++++++++++++++++++--- src/pages/api/magento-product.ts | 114 +++++++++++++++++++++ 2 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 src/pages/api/magento-product.ts diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 1bacd2e2..b0950194 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -4,7 +4,7 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; import { useEffect, useRef, useState, UIEvent } from 'react'; -// Import komponen Chakra UI yang dibutuhkan +// Import komponen Chakra UI import { Button, Tabs, @@ -16,7 +16,10 @@ import { Tbody, Tr, Td, - Box + Box, + Spinner, + Center, + Text } from '@chakra-ui/react'; import { @@ -58,6 +61,12 @@ const ProductDetail = ({ product }: Props) => { const { isDesktop, isMobile } = useDevice(); const router = useRouter(); const [auth, setAuth] = useState(null); + + // State untuk Spesifikasi dari Magento + const [specs, setSpecs] = useState<{ label: string; value: string }[]>([]); + const [loadingSpecs, setLoadingSpecs] = useState(false); + const [errorSpecs, setErrorSpecs] = useState(false); + useEffect(() => { try { setAuth(getAuth() ?? null); @@ -74,6 +83,7 @@ const ProductDetail = ({ product }: Props) => { activeVariantId, setIsApproval, isApproval, + selectedVariant, setSelectedVariant, } = useProductDetail(); @@ -99,12 +109,65 @@ const ProductDetail = ({ product }: Props) => { if (typeof auth === 'object') { setIsApproval(auth?.feature?.soApproval); } - const selectedVariant = + const variantInit = product?.variants?.find((variant) => variant.is_in_bu) || product?.variants?.[0]; - setSelectedVariant(selectedVariant); + setSelectedVariant(variantInit); }, []); + // ========================================================================= + // LOGIC FETCH: MENGGUNAKAN ID VARIANT + // ========================================================================= + useEffect(() => { + const fetchMagentoSpecs = async () => { + // MENGGUNAKAN ID VARIANT SESUAI REQUEST + const skuToFetch = selectedVariant?.id; + + if (!skuToFetch) return; + + setLoadingSpecs(true); + setErrorSpecs(false); + + try { + console.log("Fetching Magento specs via Proxy for Variant ID:", skuToFetch); + + // Pastikan dikonversi ke string + const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(skuToFetch))}`; + + const response = await fetch(endpoint, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }); + + if (!response.ok) { + console.warn(`Spec API status: ${response.status}`); + setSpecs([]); + return; + } + + const data = await response.json(); + + if (data.specs && Array.isArray(data.specs)) { + setSpecs(data.specs); + } else { + setSpecs([]); + } + + } catch (error) { + console.error("Gagal mengambil data spesifikasi:", error); + setErrorSpecs(true); + setSpecs([]); + } finally { + setLoadingSpecs(false); + } + }; + + fetchMagentoSpecs(); + }, [selectedVariant]); + + const allImages = (() => { const arr: string[] = []; if (product?.image) arr.push(product.image); @@ -154,9 +217,6 @@ const ProductDetail = ({ product }: Props) => { setMainImage(allImages[i] || ''); }; - console.log('detail product render'); - console.log('product: ', product); - return ( <>
@@ -192,7 +252,7 @@ const ProductDetail = ({ product }: Props) => {
{/* ===== Kolom kiri: gambar ===== */}
- {/* === MOBILE: Slider swipeable, tanpa thumbnail carousel === */} + {/* === MOBILE: Slider swipeable === */} {isMobile ? (
{ )}
+ {/* Dots indicator */} {allImages.length > 1 && (
{allImages.map((_, i) => ( @@ -250,7 +311,7 @@ const ProductDetail = ({ product }: Props) => {
) : ( <> - {/* === DESKTOP: Tetap seperti sebelumnya === */} + {/* === DESKTOP === */} {allImages.length > 0 && (
@@ -414,9 +475,38 @@ const ProductDetail = ({ product }: Props) => {
- {/* PANEL 2: SPESIFIKASI (Sesuai Gambar) */} - -

Informasi tambahan belum tersedia.

+ {/* PANEL 2: SPESIFIKASI DARI MAGENTO */} + + + {loadingSpecs ? ( +
+ +
+ ) : errorSpecs ? ( + + Gagal memuat data spesifikasi. Silakan coba lagi nanti. + + ) : specs.length > 0 ? ( + + + {specs.map((item, index) => ( + + + + + ))} + +
+ {item.label} + + {item.value} +
+ ) : ( + + Spesifikasi teknis belum tersedia untuk varian ID: {selectedVariant?.id} + + )} +
{/* PANEL 3: DETAIL LAINNYA */} diff --git a/src/pages/api/magento-product.ts b/src/pages/api/magento-product.ts new file mode 100644 index 00000000..c906079e --- /dev/null +++ b/src/pages/api/magento-product.ts @@ -0,0 +1,114 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const { sku } = req.query; + + if (!sku) { + return res.status(400).json({ error: 'SKU is required' }); + } + + // Token Magento + const token = 'vxrtcjvztv1icgjzsui45de9kmwlz0lf'; + const baseUrl = 'https://pimdev.1211.my.id/rest/V1/products'; + + try { + // 1. Pastikan SKU menjadi string dan hapus spasi kiri/kanan + const cleanSku = String(sku).trim(); + + // 2. Encode SKU + const encodedSku = encodeURIComponent(cleanSku); + + // 3. Bentuk URL Final + const finalUrl = `${baseUrl}/${encodedSku}`; + + // --- DEBUGGING LOG --- + console.log('Fetching URL:', finalUrl); + + // Request ke Product Endpoint + const response = await fetch(finalUrl, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}`, + }, + }); + + if (!response.ok) { + console.error(`Magento Error: ${response.status} ${response.statusText}`); + return res.status(response.status).json({ + error: 'Failed to fetch from Magento', + magentoStatus: response.status, + checkedUrl: finalUrl + }); + } + + const data = await response.json(); + + // ===================================================================== + // TAMBAHAN: FETCH LABEL ATRIBUT (z_*) + // ===================================================================== + + let specsWithLabels: any[] = []; + + // Cek apakah ada custom_attributes + if (data.custom_attributes) { + // Filter atribut yang kodenya dimulai dengan 'z' + const zAttributes = data.custom_attributes.filter((attr: any) => + attr.attribute_code.startsWith('z') + ); + + // Fetch detail label untuk setiap atribut secara paralel + specsWithLabels = await Promise.all( + zAttributes.map(async (attr: any) => { + try { + // Endpoint untuk ambil detail atribut (Label): /V1/products/attributes/{attributeCode} + const attrUrl = `${baseUrl}/attributes/${attr.attribute_code}`; + + const attrRes = await fetch(attrUrl, { + method: 'GET', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + } + }); + + if (attrRes.ok) { + const attrData = await attrRes.json(); + // AMBIL NILAI 'default_frontend_label' + return { + label: attrData.default_frontend_label || attr.attribute_code, + value: attr.value + }; + } + } catch (err) { + console.error(`Failed to fetch label for ${attr.attribute_code}`); + } + + // Fallback: Jika gagal ambil label, format manual dari kode + const fallbackLabel = attr.attribute_code + .substring(1).replace(/_/g, ' ').trim(); // z_size_ml -> size ml + + return { + label: fallbackLabel, + value: attr.value + }; + }) + ); + } + + // Gabungkan data asli dengan data specs yang sudah ada labelnya + const responseData = { + ...data, + specs: specsWithLabels // Frontend tinggal pakai field ini + }; + + res.status(200).json(responseData); + + } catch (error) { + console.error('Proxy Server Error:', error); + res.status(500).json({ error: 'Internal Server Error' }); + } +} \ No newline at end of file -- cgit v1.2.3