summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-11-04 17:18:05 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-11-04 17:18:05 +0700
commit491d609e0e52998c024d634e759eca3275ce7943 (patch)
tree262a1aa3fce1e8b46c4e57cde3b4d6b608e3b3ad
parent7c188f31373cd647db96d209b1ca2359de640037 (diff)
<Miqdad> cr renca & scale manufacture product detail
-rw-r--r--src-migrate/modules/product-detail/components/Information.tsx7
-rw-r--r--src-migrate/modules/product-detail/components/PriceAction.tsx168
-rw-r--r--src-migrate/modules/product-detail/components/ProductDetail.tsx3
-rw-r--r--src-migrate/modules/product-detail/styles/price-action.module.css2
4 files changed, 141 insertions, 39 deletions
diff --git a/src-migrate/modules/product-detail/components/Information.tsx b/src-migrate/modules/product-detail/components/Information.tsx
index a7a58cbc..fd73d8b6 100644
--- a/src-migrate/modules/product-detail/components/Information.tsx
+++ b/src-migrate/modules/product-detail/components/Information.tsx
@@ -66,14 +66,13 @@ const Information = ({ product }: Props) => {
}, [selectedVariant]);
useEffect(() => {
- if (isLoading){
+ if (isLoading) {
setSla(null);
}
if (slaVariant) {
setSla(slaVariant);
}
}, [slaVariant, isLoading]);
-
const handleOnChange = (vals: any) => {
setDisableFilter(true);
@@ -188,7 +187,7 @@ const Information = ({ product }: Props) => {
<div className={style['value']}>{selectedVariant?.code}</div>
</div>
<div className={style['row']}>
- <div className={style['label']}>Manufacture</div>
+ <div className={`${style['label']} items-center `}>Manufacture</div>
<div className={style['value']}>
{!!product.manufacture.name ? (
<Link
@@ -204,7 +203,7 @@ const Information = ({ product }: Props) => {
width={100}
src={product.manufacture.logo}
alt={product.manufacture.name}
- className='h-8 object-fit'
+ className='object-fit object-contain items-center'
/>
) : (
<p className='font-bold text-red-500'>
diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx
index 6cc2f0bf..a84fa134 100644
--- a/src-migrate/modules/product-detail/components/PriceAction.tsx
+++ b/src-migrate/modules/product-detail/components/PriceAction.tsx
@@ -14,6 +14,7 @@ import odooApi from '~/libs/odooApi';
import { Button, Skeleton } from '@chakra-ui/react';
import DesktopView from '@/core/components/views/DesktopView';
import MobileView from '@/core/components/views/MobileView';
+import { TicketIcon } from '@heroicons/react/24/solid';
type Props = {
product: IProductDetail;
@@ -70,6 +71,20 @@ const PriceAction = ({ product }: Props) => {
const pricedigit = String(Math.floor(price)).length;
const fontSize = pricedigit >= 9 ? '20px' : undefined;
+ // voucher hanya diterapkan kalau TIDAK ada discount_percentage (bukan flash/price rule)
+ let voucherCut = 0;
+
+ // apply voucher only when NOT a flash/price rule
+ if (activePrice && !(activePrice.discount_percentage > 0)) {
+ voucherCut = getVoucherCut(product, activePrice);
+ }
+
+ const basePriceForDisplay =
+ Number(activePrice?.price_discount ?? 0) || Number(activePrice?.price ?? 0);
+
+ const finalAfterVoucher = Math.max(basePriceForDisplay - voucherCut, 0);
+ const hasVoucherApplied = voucherCut > 0 && !activePrice?.discount_percentage;
+
// let voucherPastiHemat = 0;
// if (
@@ -82,6 +97,51 @@ const PriceAction = ({ product }: Props) => {
// voucherPastiHemat = JSON.parse(validJsonString);
// }
+ // --- (1) helper: hitung potongan voucher berdasar product-level voucher + harga variant aktif
+ function getVoucherCut(
+ product: IProductDetail,
+ activePrice?: { price?: number; price_discount?: number }
+ ) {
+ try {
+ const raw = Array.isArray((product as any)?.new_voucher_pasti_hemat)
+ ? (product as any).new_voucher_pasti_hemat[0]
+ : (product as any)?.new_voucher_pasti_hemat;
+
+ if (!raw) return 0;
+
+ const discount_type = String(
+ raw.discount_type ?? raw.discountType ?? ''
+ ).toLowerCase();
+ const discount_amount = Number(
+ raw.discount_amount ?? raw.discountAmount ?? 0
+ );
+ const max_discount = Number(raw.max_discount ?? raw.maxDiscount ?? 0);
+ const min_purchase = Number(raw.min_purchase ?? raw.minPurchase ?? 0);
+
+ // base price ambil price_discount dulu, kalau kosong pakai price
+ const base =
+ Number(activePrice?.price_discount ?? 0) ||
+ Number(activePrice?.price ?? 0);
+ if (!base) return 0;
+ if (min_purchase > 0 && base < min_purchase) return 0;
+
+ let cut = 0;
+ if (discount_type.startsWith('percent')) {
+ // support nilai 0..1 atau 0..100
+ const pct =
+ discount_amount <= 1 ? discount_amount * 100 : discount_amount;
+ cut = Math.floor(base * (pct / 100));
+ } else {
+ cut = Math.floor(discount_amount || 0);
+ }
+
+ if (max_discount > 0) cut = Math.min(cut, max_discount);
+ return Math.max(0, cut);
+ } catch {
+ return 0;
+ }
+ }
+
return (
<div
className={`block md:sticky md:top-[150px] md:py-6 fixed bottom-0 left-0 right-0 bg-white p-2 z-10 ${
@@ -94,36 +154,57 @@ const PriceAction = ({ product }: Props) => {
<>
<DesktopView>
<div className='flex items-end gap-x-2'>
- {activePrice.discount_percentage > 0 && (
- <div className={style['disc-badge']}>
- {Math.floor(activePrice.discount_percentage)}%
- </div>
- )}
- <div
- className={style['main-price']}
- style={fontSize ? { fontSize } : undefined}
- >
- Rp{' '}
- {formatCurrency(
- activePrice.discount_percentage > 0
- ? activePrice.price_discount || 0
- : activePrice.price || 0
- )}
- </div>
- {activePrice.discount_percentage > 0 && (
- <div className={style['disc-price']}>
- Rp {formatCurrency(activePrice.price || 0)}
+ {/* Jika ada discount_percentage (flash/price rule) → pakai UI lama */}
+ {activePrice.discount_percentage > 0 ? (
+ <>
+ <div className={style['disc-badge']}>
+ {Math.floor(activePrice.discount_percentage)}%
+ </div>
+ <div
+ className={style['main-price']}
+ style={fontSize ? { fontSize } : undefined}
+ >
+ Rp {formatCurrency(activePrice.price_discount || 0)}
+ </div>
+ <div className={style['disc-price']}>
+ Rp {formatCurrency(activePrice.price || 0)}
+ </div>
+ </>
+ ) : hasVoucherApplied ? (
+ // Tidak ada discount bawaan, tapi ada voucher → tampilkan harga setelah voucher
+ <>
+ <div
+ className={`${style['main-price']} inline-flex items-center gap-2 leading-none bg-red-100 px-2 py-0.5 rounded-sm`}
+ style={fontSize ? { fontSize } : undefined}
+ >
+ <TicketIcon className='w-5 h-5 shrink-0' aria-hidden />
+ Rp {formatCurrency(finalAfterVoucher)}
+ </div>
+ <div className={style['disc-price']}>
+ Rp {formatCurrency(basePriceForDisplay)}
+ </div>
+ </>
+ ) : (
+ // Normal tanpa disc & tanpa voucher
+ <div
+ className={style['main-price']}
+ style={fontSize ? { fontSize } : undefined}
+ >
+ Rp {formatCurrency(basePriceForDisplay)}
</div>
)}
</div>
+
<div className='h-1' />
<div className={style['secondary-text']}>
Termasuk PPN: Rp{' '}
{formatCurrency(
Math.round(
(activePrice.discount_percentage > 0
- ? activePrice.price_discount
- : activePrice.price) * PPN
+ ? Number(activePrice.price_discount || 0)
+ : hasVoucherApplied
+ ? finalAfterVoucher
+ : basePriceForDisplay) * PPN
)
)}
</div>
@@ -131,33 +212,58 @@ const PriceAction = ({ product }: Props) => {
<MobileView>
<div className='flex items-end gap-x-2'>
+ {/* Jika ada discount_percentage (flash/price rule) → pakai UI lama */}
{activePrice.discount_percentage > 0 ? (
<>
<div className={style['disc-badge']}>
{Math.floor(activePrice.discount_percentage)}%
</div>
-
- {/* harga setelah diskon (main-price) di kiri */}
- <div className={style['main-price']}>
+ <div
+ className={style['main-price']}
+ style={fontSize ? { fontSize } : undefined}
+ >
Rp {formatCurrency(activePrice.price_discount || 0)}
</div>
-
- {/* harga coret di kanan */}
<div className={style['disc-price']}>
Rp {formatCurrency(activePrice.price || 0)}
</div>
</>
+ ) : hasVoucherApplied ? (
+ // Tidak ada discount bawaan, tapi ada voucher → tampilkan harga setelah voucher
+ <>
+ <div
+ className={style['main-price']}
+ style={fontSize ? { fontSize } : undefined}
+ >
+ Rp {formatCurrency(finalAfterVoucher)}
+ </div>
+ <div className={style['disc-price']}>
+ Rp {formatCurrency(basePriceForDisplay)}
+ </div>
+ </>
) : (
- // kalau tidak ada diskon, tampilkan harga normal saja
- <div className={style['main-price']}>
- Rp {formatCurrency(activePrice.price || 0)}
+ // Normal tanpa disc & tanpa voucher
+ <div
+ className={style['main-price']}
+ style={fontSize ? { fontSize } : undefined}
+ >
+ Rp {formatCurrency(basePriceForDisplay)}
</div>
)}
</div>
- <div className='text-md text-gray-500 shadow-0'>
+ <div className='h-1' />
+ <div className={style['secondary-text']}>
Termasuk PPN: Rp{' '}
- {formatCurrency(Math.round(activePrice.price_discount * PPN))}
+ {formatCurrency(
+ Math.round(
+ (activePrice.discount_percentage > 0
+ ? Number(activePrice.price_discount || 0)
+ : hasVoucherApplied
+ ? finalAfterVoucher
+ : basePriceForDisplay) * PPN
+ )
+ )}
</div>
</MobileView>
</>
diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 4c75c61b..17cd03ca 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -204,9 +204,6 @@ const ProductDetail = ({ product }: Props) => {
setVoucherDiscount(cut);
}, [product, selectedVariant]);
- console.log(discount);
- console.log(selectedVariant);
-
return (
<>
<div className='md:flex md:flex-wrap'>
diff --git a/src-migrate/modules/product-detail/styles/price-action.module.css b/src-migrate/modules/product-detail/styles/price-action.module.css
index 88acdfc5..b94c33f7 100644
--- a/src-migrate/modules/product-detail/styles/price-action.module.css
+++ b/src-migrate/modules/product-detail/styles/price-action.module.css
@@ -2,7 +2,7 @@
@apply font-medium text-gray-500;
}
.main-price {
- @apply font-medium text-danger-500 text-title-md;
+ @apply font-medium text-danger-500 text-title-sm;
}
.action-wrapper {
@apply flex gap-x-2.5;