summaryrefslogtreecommitdiff
path: root/src-migrate/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate/modules')
-rw-r--r--src-migrate/modules/product-detail/components/ProductDetail.tsx55
-rw-r--r--src-migrate/modules/product-detail/components/SimilarSide.tsx74
2 files changed, 94 insertions, 35 deletions
diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 5f930117..cfe73628 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -67,6 +67,8 @@ const ProductDetail = ({ product }: Props) => {
// State Data dari Magento
const [specs, setSpecs] = useState<{ code: string; label: string; value: string }[]>([]);
const [upsellIds, setUpsellIds] = useState<number[]>([]);
+ const [relatedIds, setRelatedIds] = useState<number[]>([]);
+
const [loadingSpecs, setLoadingSpecs] = useState(false);
const [errorSpecs, setErrorSpecs] = useState(false);
@@ -109,7 +111,7 @@ const ProductDetail = ({ product }: Props) => {
}, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]);
// =========================================================================
- // LOGIC INISIALISASI VARIANT (HANDLE NAVIGASI)
+ // LOGIC INISIALISASI VARIANT (RESET SAAT NAVIGASI)
// =========================================================================
useEffect(() => {
if (typeof auth === 'object') {
@@ -121,28 +123,29 @@ const ProductDetail = ({ product }: Props) => {
setSelectedVariant(variantInit);
- // Reset data Magento saat produk berubah
+ // Reset data Magento
setSpecs([]);
setUpsellIds([]);
+ setRelatedIds([]);
}, [product, auth]);
// =========================================================================
- // LOGIC FETCH: SPECS & UPSELLS
+ // LOGIC FETCH: SPECS, UPSELLS, RELATED
// =========================================================================
useEffect(() => {
const fetchMagentoData = async () => {
- // Gunakan ID Variant (SKU Odoo)
- const idToFetch = selectedVariant?.id;
+ // Validasi kepemilikan varian
+ if (!selectedVariant?.id) return;
+ const isVariantOwner = product.variants.some(v => Number(v.id) === Number(selectedVariant.id));
+ if (!isVariantOwner) return;
- if (!idToFetch) return;
+ const idToFetch = selectedVariant.id;
setLoadingSpecs(true);
setErrorSpecs(false);
try {
- console.log("Fetching Magento data via Proxy for ID:", idToFetch);
-
const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(idToFetch))}`;
const response = await fetch(endpoint, {
@@ -151,61 +154,75 @@ const ProductDetail = ({ product }: Props) => {
});
if (!response.ok) {
- console.warn(`Magento API status: ${response.status}`);
setSpecs([]);
setUpsellIds([]);
+ setRelatedIds([]);
return;
}
const data = await response.json();
- // 1. Simpan Data Spesifikasi
+ // Double Check
+ if (Number(idToFetch) !== Number(selectedVariant.id)) return;
+
+ // 1. Specs
if (data.specs && Array.isArray(data.specs)) {
setSpecs(data.specs);
} else {
setSpecs([]);
}
- // 2. Simpan Data Up-Sells (ID)
+ // 2. Upsell
if (data.upsell_ids && Array.isArray(data.upsell_ids)) {
setUpsellIds(data.upsell_ids);
} else {
setUpsellIds([]);
}
+ // 3. Related
+ if (data.related_ids && Array.isArray(data.related_ids)) {
+ setRelatedIds(data.related_ids);
+ } else {
+ setRelatedIds([]);
+ }
+
} catch (error) {
console.error("Gagal mengambil data Magento:", error);
setErrorSpecs(true);
setSpecs([]);
setUpsellIds([]);
+ setRelatedIds([]);
} finally {
setLoadingSpecs(false);
}
};
fetchMagentoData();
- }, [selectedVariant, product.id]);
+ }, [selectedVariant, product]);
// =========================================================================
- // HELPER: RENDER SPEC VALUE (SIMPLE TEXT/HTML ONLY)
+ // HELPER: RENDER SPEC VALUE (SIMPLE - NO LINK DETECT)
// =========================================================================
const renderSpecValue = (item: { code: string; label: string; value: string }) => {
const val = item.value;
if (!val) return '-';
- // Cek apakah mengandung tag HTML sederhana (<p>, <a>, <ul>, dll)
- if (val.includes('<') && val.includes('>')) {
+ const cleanVal = val.trim();
+
+ // 1. JIKA HTML (Legacy Data)
+ // Deteksi tag HTML sederhana
+ if (cleanVal.includes('<') && cleanVal.includes('>')) {
return (
<div
className="prose prose-sm text-gray-700"
- dangerouslySetInnerHTML={{ __html: val }}
+ dangerouslySetInnerHTML={{ __html: cleanVal }}
/>
);
}
- // Default: Teks Biasa
- return val;
+ // 2. TEKS BIASA
+ return cleanVal;
};
@@ -544,7 +561,7 @@ const ProductDetail = ({ product }: Props) => {
<div className='h-6' />
<div className={style['heading']}>Produk Serupa</div>
<div className='h-4' />
- <SimilarSide product={product} />
+ <SimilarSide product={product} relatedIds={relatedIds} />
</div>
)}
diff --git a/src-migrate/modules/product-detail/components/SimilarSide.tsx b/src-migrate/modules/product-detail/components/SimilarSide.tsx
index d70a314d..51d9eff7 100644
--- a/src-migrate/modules/product-detail/components/SimilarSide.tsx
+++ b/src-migrate/modules/product-detail/components/SimilarSide.tsx
@@ -1,33 +1,75 @@
import { Skeleton } from '@chakra-ui/react'
+import { useQuery } from 'react-query'
import ProductCard from '~/modules/product-card'
-import useProductSimilar from '~/modules/product-similar/hooks/useProductSimilar'
-import { IProductDetail } from '~/types/product'
+// Import service
+import { getProductSimilar, getProductsByIds } from '~/services/product'
+// TAMBAHKAN 'IProduct' DISINI
+import { IProduct, IProductDetail } from '~/types/product'
type Props = {
product: IProductDetail
+ relatedIds?: number[]
}
-const SimilarSide = ({ product }: Props) => {
- const productSimilar = useProductSimilar({
- name: product.name,
- except: { productId: product.id, manufactureId: product.manufacture.id },
- })
+const SimilarSide = ({ product, relatedIds = [] }: Props) => {
+
+ const hasRelated = relatedIds.length > 0;
- const products = productSimilar.data?.products || []
+ // 1. Fetch Related by ID
+ const relatedQuery = useQuery({
+ queryKey: ['product-related', relatedIds],
+ queryFn: () => getProductsByIds({ ids: relatedIds }),
+ enabled: hasRelated,
+ staleTime: 1000 * 60 * 5,
+ });
+
+ // 2. Fetch Similar Biasa
+ const similarQuery = useQuery({
+ queryKey: ['product-similar-side', product.name],
+ queryFn: () => getProductSimilar({
+ name: product.name,
+ except: {
+ productId: product.id,
+ manufactureId: product.manufacture?.id
+ }
+ }),
+ enabled: !hasRelated,
+ staleTime: 1000 * 60 * 5,
+ });
+
+ // ============================================================
+ // PERBAIKAN: Definisikan tipe array secara eksplisit (IProduct[])
+ // ============================================================
+ let products: IProduct[] = [];
+ let isLoading = false;
+
+ if (hasRelated) {
+ // Cast ke any dulu jika tipe return service belum sempurna terdeteksi, lalu ambil products
+ // Atau jika getProductsByIds me-return { products: IProduct[] }, ambil .products
+ // Sesuai kode service terakhir, getProductsByIds me-return GetProductSimilarRes yg punya .products
+ products = (relatedQuery.data as any)?.products || [];
+ isLoading = relatedQuery.isLoading;
+ } else {
+ products = similarQuery.data?.products || [];
+ isLoading = similarQuery.isLoading;
+ }
+
+ if (!isLoading && products.length === 0) return null;
return (
<Skeleton
- isLoaded={!productSimilar.isLoading}
- className="h-[500px] overflow-auto grid grid-cols-1 gap-y-4 divide-y divide-gray-300 border border-gray-300 rounded-lg"
+ isLoaded={!isLoading}
+ className="h-[500px] overflow-auto grid grid-cols-1 gap-y-4 divide-y divide-gray-300 border border-gray-300 rounded-lg p-2"
rounded='lg'
>
- {products.map((product) => (
- <ProductCard
- key={product.id}
- product={product}
- layout='horizontal'
- />
+ {products.map((item) => (
+ <div key={item.id} className="pt-2 first:pt-0">
+ <ProductCard
+ product={item}
+ layout='horizontal'
+ />
+ </div>
))}
</Skeleton>
)