summaryrefslogtreecommitdiff
path: root/src-migrate/modules/product-detail/components/Information.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate/modules/product-detail/components/Information.tsx')
-rw-r--r--src-migrate/modules/product-detail/components/Information.tsx386
1 files changed, 312 insertions, 74 deletions
diff --git a/src-migrate/modules/product-detail/components/Information.tsx b/src-migrate/modules/product-detail/components/Information.tsx
index 813b6bf5..236a03af 100644
--- a/src-migrate/modules/product-detail/components/Information.tsx
+++ b/src-migrate/modules/product-detail/components/Information.tsx
@@ -9,19 +9,35 @@ import style from '../styles/information.module.css';
import dynamic from 'next/dynamic';
import Link from 'next/link';
import { useEffect, useRef, useState } from 'react';
+import axios from 'axios';
import currencyFormat from '@/core/utils/currencyFormat';
-import { InputGroup, InputRightElement } from '@chakra-ui/react';
+import {
+ InputGroup,
+ InputRightElement,
+ SimpleGrid,
+ Flex,
+ Text,
+ Box,
+ Center,
+ Icon,
+} from '@chakra-ui/react';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
-import Image from 'next/image';
+import ImageNext from 'next/image';
import { formatToShortText } from '~/libs/formatNumber';
import { createSlug } from '~/libs/slug';
import { IProductDetail } from '~/types/product';
import { useProductDetail } from '../stores/useProductDetail';
import useVariant from '../hook/useVariant';
+// Import View Components
+import MobileView from '@/core/components/views/MobileView'; // Pastikan path import benar
+
+// Import Modal Compare
+import ProductComparisonModal from './ProductComparisonModal';
+
const Skeleton = dynamic(() =>
- import('@chakra-ui/react').then((mod) => mod.Skeleton)
+ import('@chakra-ui/react').then((mod) => mod.Skeleton),
);
type Props = {
@@ -37,14 +53,46 @@ const Information = ({ product }: Props) => {
const inputRef = useRef<HTMLInputElement>(null);
// source of truth
- const variantOptions = product.variants;
+ // const variantOptions = product.variants;
+ const [variantOptions, setVariantOptions] = useState<any[]>(
+ product?.variants,
+ );
const variantId = selectedVariant?.id;
const { slaVariant, isLoading } = useVariant({ variantId });
- /* ======================
- * Sync input text
- * ====================== */
+ const [warranties, setWarranties] = useState<Record<string, string>>({});
+ const [loadingWarranty, setLoadingWarranty] = useState(false);
+
+ // State untuk Modal Compare
+ const [isCompareOpen, setIsCompareOpen] = useState(false);
+
+ useEffect(() => {
+ const fetchWarrantyDirectly = async () => {
+ if (!product?.variants || product.variants.length === 0) return;
+
+ setLoadingWarranty(true);
+ try {
+ const skus = product.variants.map((v) => v.id).join(',');
+ const mainSku = product.variants[0].id;
+
+ const res = await axios.get('/api/magento-product', {
+ params: { skus, main_sku: mainSku },
+ });
+
+ if (res.data && res.data.warranties) {
+ setWarranties(res.data.warranties);
+ }
+ } catch (error) {
+ // console.error("Gagal ambil garansi:", error);
+ } finally {
+ setLoadingWarranty(false);
+ }
+ };
+
+ fetchWarrantyDirectly();
+ }, [product]);
+
useEffect(() => {
if (!selectedVariant) return;
@@ -52,7 +100,7 @@ const Information = ({ product }: Props) => {
selectedVariant.code +
(selectedVariant.attributes?.[0]
? ` - ${selectedVariant.attributes[0]}`
- : '')
+ : ''),
);
}, [selectedVariant]);
@@ -72,14 +120,19 @@ const Information = ({ product }: Props) => {
/* ======================
* Handlers
* ====================== */
- const handleOnChange = (value: string) => {
+ const handleOnChange = (vals: any) => {
setDisableFilter(true);
+ let code = vals.replace(/\s-\s.*$/, '').trim();
+ let variant = product?.variants.find((item) => item.code === code);
- const variant = variantOptions.find((item) => String(item.id) === value);
-
- if (!variant) return;
-
- setSelectedVariant(variant);
+ if (variant) {
+ setSelectedVariant(variant);
+ setInputValue(
+ variant?.code +
+ (variant?.attributes[0] ? ' - ' + variant?.attributes[0] : ''),
+ );
+ setVariantOptions(product?.variants);
+ }
};
const handleOnKeyUp = (e: any) => {
@@ -87,6 +140,14 @@ const Information = ({ product }: Props) => {
setInputValue(e.target.value);
};
+ const rowStyle = {
+ backgroundColor: '#ffffff',
+ fontSize: '13px',
+ borderBottom: '1px dashed #e2e8f0',
+ padding: '8px 0',
+ marginBottom: '0px',
+ };
+
return (
<div className={style['wrapper']}>
{/* ===== Variant Selector ===== */}
@@ -120,70 +181,133 @@ const Information = ({ product }: Props) => {
</InputGroup>
<AutoCompleteList>
- {variantOptions.map((option) => (
- <AutoCompleteItem
- key={option.id}
- value={String(option.id)}
- _selected={
- option.id === selectedVariant?.id
- ? { bg: 'gray.300' }
- : undefined
- }
- >
- <div className='flex gap-x-2 w-full justify-between px-3 items-center p-2'>
- <div className='text-small'>
- {option.code}
- {option.attributes?.[0] ? ` - ${option.attributes[0]}` : ''}
- </div>
-
- <div
- className={
- option.price?.discount_percentage
- ? 'flex gap-x-4 items-center'
- : ''
- }
- >
- {option.price?.discount_percentage > 0 && (
- <>
- <div className='badge-solid-red text-xs'>
- {Math.floor(option.price.discount_percentage)}%
- </div>
- <div className='min-w-16 sm:min-w-24 text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
- {currencyFormat(option.price.price)}
- </div>
- </>
- )}
- <div className='min-w-20 sm:min-w-28 text-danger-500 font-semibold'>
- {currencyFormat(option.price.price_discount)}
+ {variantOptions
+ .sort((a: any, b: any) => {
+ return a.code.localeCompare(b.code, undefined, {
+ numeric: true,
+ sensitivity: 'base',
+ });
+ })
+ .map((option, cid) => (
+ <AutoCompleteItem
+ key={option.id}
+ // value={String(option.id)}
+ value={
+ option.code +
+ (option.attributes?.[0] ? ` - ${option.attributes[0]}` : '')
+ }
+ _selected={
+ option.id === selectedVariant?.id
+ ? { bg: 'gray.300' }
+ : undefined
+ }
+ >
+ <div className='flex gap-x-2 w-full justify-between px-3 items-center p-2'>
+ <div className='text-small'>
+ {option.code}
+ {option.attributes?.[0]
+ ? ` - ${option.attributes[0]}`
+ : ''}
+ </div>
+ <div
+ className={
+ option?.price?.discount_percentage
+ ? 'flex gap-x-4 items-center justify-between'
+ : ''
+ }
+ >
+ {option?.price?.discount_percentage > 0 && (
+ <>
+ <div className='badge-solid-red text-xs'>
+ {Math.floor(option.price.discount_percentage)}%
+ </div>
+ <div className='min-w-16 sm:min-w-24 text-gray_r-11 line-through text-[11px] sm:text-caption-2'>
+ {currencyFormat(option.price.price)}
+ </div>
+ </>
+ )}
+ <div className='min-w-20 sm:min-w-28 text-danger-500 font-semibold'>
+ {currencyFormat(option.price.price_discount)}
+ </div>
</div>
</div>
- </div>
- </AutoCompleteItem>
- ))}
+ </AutoCompleteItem>
+ ))}
</AutoCompleteList>
</AutoComplete>
+
+ {/* === TOMBOL BANDINGKAN PRODUK (HANYA MOBILE) === */}
+ <MobileView>
+ <div
+ className='w-full flex items-center justify-between py-3 px-1 mt-3 bg-white border-t border-b border-black-100 cursor-pointer hover:bg-gray-50 transition-colors group'
+ onClick={() => setIsCompareOpen(true)}
+ >
+ <div className='flex items-center gap-3'>
+ <div className='bg-red-50 p-2 rounded-full group-hover:bg-red-100 transition-colors'>
+ <ImageNext
+ src='/images/logo-bandingkan.svg'
+ width={15}
+ height={15}
+ alt='bandingkan'
+ />
+ </div>
+ <div className='flex flex-col'>
+ <span className='text-sm font-bold text-gray-800'>
+ Bandingkan Produk
+ </span>
+ <span className='text-xs text-gray-500'>
+ Coba bandingkan dengan produk lainnya
+ </span>
+ </div>
+ </div>
+ <div className='flex items-center gap-2'>
+ <span className='bg-red-600 text-white text-[10px] font-bold px-2 py-0.5 rounded-full'>
+ Baru
+ </span>
+ <Icon
+ as={ChevronDownIcon}
+ className='w-4 h-4 text-gray-400 transform -rotate-90'
+ />
+ </div>
+ </div>
+ </MobileView>
+
+ {/* Render Modal (Logic open/close ada di dalam component) */}
+ {isCompareOpen && (
+ <ProductComparisonModal
+ isOpen={isCompareOpen}
+ onClose={() => setIsCompareOpen(false)}
+ mainProduct={product}
+ selectedVariant={selectedVariant}
+ />
+ )}
</div>
- {/* ===== Info Rows ===== */}
- <div className={style['row']}>
- <div className={style['label']}>Item Code</div>
+ {/* ITEM CODE */}
+ <div className={style['row']} style={rowStyle}>
+ <div className={style['label']} style={{ color: '#6b7280' }}>
+ Item Code
+ </div>
<div className={style['value']}>{selectedVariant?.code}</div>
</div>
- <div className={style['row']}>
- <div className={style['label']}>Manufacture</div>
+ {/* MANUFACTURE */}
+ <div className={style['row']} style={rowStyle}>
+ <div className={style['label']} style={{ color: '#6b7280' }}>
+ Manufacture
+ </div>
<div className={style['value']}>
{!!product.manufacture.name ? (
<Link
href={createSlug(
'/shop/brands/',
product.manufacture.name,
- product.manufacture.id.toString()
+ product.manufacture.id.toString(),
)}
>
- {product.manufacture.logo ? (
- <Image
- height={50}
+ {product?.manufacture.logo ? (
+ <ImageNext
+ height={100}
width={100}
src={product.manufacture.logo}
alt={product.manufacture.name}
@@ -201,29 +325,143 @@ const Information = ({ product }: Props) => {
</div>
</div>
- <div className={style['row']}>
- <div className={style['label']}>Berat Barang</div>
+ {/* BERAT BARANG */}
+ <div className={style['row']} style={rowStyle}>
+ <div className={style['label']} style={{ color: '#6b7280' }}>
+ Berat Barang
+ </div>
<div className={style['value']}>
{selectedVariant?.weight > 0 ? `${selectedVariant.weight} Kg` : '-'}
</div>
</div>
- <div className={style['row']}>
- <div className={style['label']}>Terjual</div>
+ {/* TERJUAL */}
+ <div
+ className={style['row']}
+ style={{ ...rowStyle, borderBottom: 'none' }}
+ >
+ <div className={style['label']} style={{ color: '#6b7280' }}>
+ Terjual
+ </div>
<div className={style['value']}>
{product.qty_sold > 0 ? formatToShortText(product.qty_sold) : '-'}
</div>
</div>
- <div className={style['row']}>
- <div className={style['label']}>Persiapan Barang</div>
- {isLoading ? (
- <div className={style['value']}>
- <Skeleton height={5} width={100} />
- </div>
- ) : (
- <div className={style['value']}>{sla?.sla_date}</div>
- )}
+ {/* === DETAIL INFORMASI PRODUK === */}
+ <div className='mt-6 border-t pt-4'>
+ <h2 className='hidden md:block font-bold text-gray-800 text-sm mb-4'>
+ Detail Informasi Produk
+ </h2>
+
+ <SimpleGrid columns={{ base: 3, md: 3 }} spacing={{ base: 2, md: 10 }}>
+ <Flex
+ direction={{ base: 'column', md: 'row' }}
+ align='center'
+ textAlign={{ base: 'center', md: 'left' }}
+ gap={{ base: 2, md: 3 }}
+ >
+ <img
+ src='/images/produk_asli.svg'
+ alt='Distributor Resmi'
+ className='w-8 h-8 md:w-10 md:h-10 shrink-0'
+ />
+ <Box>
+ <Text
+ fontSize={{ base: '10px', md: '11px' }}
+ color='gray.500'
+ lineHeight='short'
+ mb='1px'
+ >
+ Distributor Resmi
+ </Text>
+ <Text
+ fontSize={{ base: '10px', md: '12px' }}
+ fontWeight='bold'
+ color='gray.800'
+ lineHeight='1.2'
+ >
+ Jaminan Produk Asli
+ </Text>
+ </Box>
+ </Flex>
+
+ <Flex
+ direction={{ base: 'column', md: 'row' }}
+ align='center'
+ textAlign={{ base: 'center', md: 'left' }}
+ gap={{ base: 2, md: 3 }}
+ >
+ <img
+ src='/images/estimasi.svg'
+ alt='Estimasi Penyiapan'
+ className='w-8 h-8 md:w-9 md:h-9 shrink-0'
+ />
+ <Box>
+ <Text
+ fontSize={{ base: '10px', md: '11px' }}
+ color='gray.500'
+ lineHeight='short'
+ mb='1px'
+ >
+ Estimasi Penyiapan
+ </Text>
+ {isLoading ? (
+ <Center>
+ <Skeleton height='10px' width='50px' mt='2px' />
+ </Center>
+ ) : (
+ <Text
+ fontSize={{ base: '10px', md: '12px' }}
+ fontWeight='bold'
+ color='gray.800'
+ lineHeight='1.2'
+ >
+ {sla?.sla_date || '-'}
+ </Text>
+ )}
+ </Box>
+ </Flex>
+
+ <Flex
+ direction={{ base: 'column', md: 'row' }}
+ align='center'
+ textAlign={{ base: 'center', md: 'left' }}
+ gap={{ base: 2, md: 3 }}
+ >
+ <img
+ src='/images/garansi.svg'
+ alt='Garansi Produk'
+ className='w-8 h-8 md:w-10 md:h-10 shrink-0'
+ />
+ <Box>
+ <Text
+ fontSize={{ base: '10px', md: '11px' }}
+ color='gray.500'
+ lineHeight='short'
+ mb='1px'
+ >
+ Garansi Produk
+ </Text>
+ {loadingWarranty ? (
+ <Center>
+ <Skeleton height='10px' width='50px' mt='2px' />
+ </Center>
+ ) : (
+ <Text
+ fontSize={{ base: '10px', md: '12px' }}
+ fontWeight='bold'
+ color='gray.800'
+ lineHeight='1.2'
+ >
+ {selectedVariant && warranties[selectedVariant.id]
+ ? warranties[selectedVariant.id]
+ : '-'}
+ </Text>
+ )}
+ </Box>
+ </Flex>
+ </SimpleGrid>
</div>
</div>
);