summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-08-31 09:25:53 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-08-31 09:25:53 +0700
commit6a0c477de3df773f2a818b904029624c212f083f (patch)
treee1f7a09eb83509de594fe7dbb015a71dd18cec26 /src/lib
parent3de1a412bba31b19b8b443dd91df8aff8d6eda07 (diff)
parentc6e970598c6c23f0606d1bc19036f0decd57cc05 (diff)
Merge branch 'release' into Feature/new-cart-popup
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/category/api/popularProduct.js32
-rw-r--r--src/lib/category/components/Category.jsx47
-rw-r--r--src/lib/category/components/PopularBrand.jsx96
-rw-r--r--src/lib/checkout/components/Checkout.jsx242
-rw-r--r--src/lib/home/components/CategoryDynamic.jsx4
-rw-r--r--src/lib/home/components/CategoryPilihan.jsx3
-rw-r--r--src/lib/home/components/PreferredBrand.jsx2
-rw-r--r--src/lib/home/components/PromotionProgram.jsx5
-rw-r--r--src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx16
-rw-r--r--src/lib/product/components/CategorySection.jsx2
-rw-r--r--src/lib/product/components/LobSectionCategory.jsx1
-rw-r--r--src/lib/product/components/ProductCard.jsx36
-rw-r--r--src/lib/product/components/ProductFilterDesktop.jsx1
-rw-r--r--src/lib/product/components/ProductSearch.jsx3
-rw-r--r--src/lib/tracking-order/api/trackingOrder.js8
-rw-r--r--src/lib/tracking-order/component/TrackingOrder.jsx139
-rw-r--r--src/lib/transaction/components/Transaction.jsx400
-rw-r--r--src/lib/treckingAwb/component/Manifest.jsx16
18 files changed, 747 insertions, 306 deletions
diff --git a/src/lib/category/api/popularProduct.js b/src/lib/category/api/popularProduct.js
new file mode 100644
index 00000000..3fdfc41c
--- /dev/null
+++ b/src/lib/category/api/popularProduct.js
@@ -0,0 +1,32 @@
+
+export const fetchPopulerProductSolr = async (category_id_ids) => {
+ let sort ='sort=qty_sold_f desc';
+ try {
+ const queryParams = new URLSearchParams({ q: category_id_ids });
+ const response = await fetch(`/solr/product/select?${queryParams.toString()}&rows=2000&fl=manufacture_name_s,manufacture_id_i,id,display_name_s,qty_sold_f,qty_sold_f&${sort}`);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ const promotions = await map(data.response.docs);
+ return promotions;
+ } catch (error) {
+ console.error("Error fetching promotion data:", error);
+ return [];
+ }
+ };
+
+ const map = async (promotions) => {
+ const result = [];
+ for (const promotion of promotions) {
+ const data = {
+ id: promotion.id,
+ name: promotion.display_name_s,
+ manufacture_name: promotion.manufacture_name_s,
+ manufacture_id: promotion.manufacture_id_i,
+ qty_sold: promotion.qty_sold_f,
+ };
+ result.push(data);
+ }
+ return result;
+ }; \ No newline at end of file
diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx
index c147a3b3..f76e6e42 100644
--- a/src/lib/category/components/Category.jsx
+++ b/src/lib/category/components/Category.jsx
@@ -5,12 +5,17 @@ import { createSlug } from '@/core/utils/slug'
import { ChevronRightIcon } from '@heroicons/react/24/outline'
import Image from 'next/image'
import { useEffect, useState } from 'react'
+import PopularBrand from './PopularBrand'
+import { bannerApi } from '@/api/bannerApi';
+const { useQuery } = require('react-query')
const Category = () => {
const [categories, setCategories] = useState([])
const [openCategories, setOpenCategory] = useState([]);
-
+ const [banner, setBanner] = useState([]);
+ const promotionProgram = useQuery('banner-promo-category-card', bannerApi({ type: 'banner-promo-category-card' }));
+
useEffect(() => {
const loadCategories = async () => {
let dataCategories = await odooApi('GET', '/api/v1/category/tree')
@@ -30,7 +35,6 @@ const Category = () => {
}
loadCategories()
}, [])
-
return (
<DesktopView>
<div className='category-mega-box'>
@@ -38,8 +42,11 @@ const Category = () => {
<div key={category.id} className='flex'>
<Link
href={createSlug('/shop/category/', category.name, category.id)}
- className='category-mega-box__parent'
+ className='category-mega-box__parent flex items-center'
>
+ <div className='mr-2 flex justify-center items-center'>
+ <Image src={category.image} alt='' width={25} height={25} />
+ </div>
{category.name}
</Link>
<div className='category-mega-box__child-wrapper'>
@@ -80,36 +87,12 @@ const Category = () => {
))}
</div>
<div className='category-mega-box__child-wrapper !w-[260px] !flex !flex-col !gap-4'>
- <div className='flex flex-col'>
- <div className='grid grid-cols-2 max-h-full w-full gap-2'>
- {category.childs.map((brand, index) => (
- (index < 8 ) && (
- <div key={brand.id} className='w-full flex items-center justify-center pb-2'>
- <Link
- href={createSlug('/shop/category/', brand.name, brand.id)}
- className='category-mega-box__child-one w-fit h-full flex items-center justify-center '
- >
- <Image src='https://erp.indoteknik.com/api/image/x_manufactures/x_logo_manufacture/661' alt='' width={104} height={44} objectFit='cover' />
- </Link>
- </div>
- )
- ))}
- </div>
- {category.childs.length > 8 && (
- <div className='flex hover:bg-gray_r-8/35 rounded-10'>
- <Link
- href={createSlug('/shop/category/', category.name, category.id)}
- className='category-mega-box__child-one flex items-center gap-4 font-bold hover:ml-4'
- >
- <p className='mt-2 mb-0 text-danger-500 font-semibold'>Lihat Semua Brand</p>
- <ChevronRightIcon className='w-4 text-danger-500 font-bold' />
- </Link>
- </div>
- )}
- </div>
- <div className='flex w-60 h-20 object-cover'>
- <Image src='https://erp.indoteknik.com/api/image/x_banner.banner/x_banner_image/397' alt='' width={275} height={4} />
+ <PopularBrand category={category} />
+ {Array.isArray(promotionProgram?.data) && promotionProgram?.data.length > 0 && promotionProgram?.data[0]?.map((banner, index) => (
+ <div key={index} className='flex w-60 h-20 object-cover'>
+ <Image src={`${banner.image}`} alt={`${banner.name}`} width={275} height={4} />
</div>
+ ))}
</div>
</div>
</div>
diff --git a/src/lib/category/components/PopularBrand.jsx b/src/lib/category/components/PopularBrand.jsx
new file mode 100644
index 00000000..4777fded
--- /dev/null
+++ b/src/lib/category/components/PopularBrand.jsx
@@ -0,0 +1,96 @@
+import odooApi from '@/core/api/odooApi'
+import React, { useEffect, useState } from 'react'
+import axios from 'axios';
+import { useQuery } from 'react-query'
+import Link from '@/core/components/elements/Link/Link'
+import { createSlug } from '@/core/utils/slug'
+import Image from 'next/image'
+import { ChevronRightIcon } from '@heroicons/react/24/outline'
+import useProductSearch from '../../../lib/product/hooks/useProductSearch';
+import { SolrResponse } from "~/types/solr";
+import { fetchPopulerProductSolr } from '../api/popularProduct'
+
+const SOLR_HOST = process.env.SOLR_HOST
+
+const PopularBrand = ({ category }) => {
+ const [topBrands, setTopBrands] = useState([]);
+
+ const fetchTopBrands = async () => {
+ try {
+ const items = await fetchPopulerProductSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`);
+ const getTop12UniqueBrands = (prod) => {
+ const brandMap = new Map();
+
+ for (const product of prod) {
+ const { manufacture_name, manufacture_id, qty_sold } = product;
+
+ if (brandMap.has(manufacture_name)) {
+ // Update the existing brand's qty_sold
+ brandMap.set(manufacture_name, {
+ name: manufacture_name,
+ id: manufacture_id,
+ qty_sold: brandMap.get(manufacture_name).qty_sold + qty_sold
+ });
+ } else {
+ // Add a new brand to the map
+ brandMap.set(manufacture_name, {
+ name: manufacture_name,
+ id: manufacture_id,
+ qty_sold
+ });
+ }
+ }
+
+ // Convert the map to an array and sort by qty_sold in descending order
+ const sortedBrands = Array.from(brandMap.values()).sort((a, b) => b.qty_sold - a.qty_sold);
+
+ // Return the top 12 brands
+ return sortedBrands.slice(0, 18);
+ };
+
+ // Using the fetched products
+ const products = items;
+ const top12UniqueBrands = getTop12UniqueBrands(products);
+
+ // Set the top 12 brands to the state
+ setTopBrands(top12UniqueBrands);
+ } catch (error) {
+ console.error("Error fetching data from Solr", error);
+ throw error;
+ }
+ }
+
+ useEffect(() => {
+ fetchTopBrands();
+ }, [category]);
+
+ return (
+ <div className='flex flex-col'>
+ <div className='grid grid-cols-3 max-h-full w-full gap-2'>
+ {topBrands.map((brand, index) => (
+ <div key={index} className='w-full flex items-center justify-center pb-2'>
+ <Link
+ href={createSlug('/shop/brands/', brand.name, brand.id)}
+ className='category-mega-box__child-one w-8 h-full flex items-center justify-center '
+ >
+ <Image src={`https://erp.indoteknik.com/api/image/x_manufactures/x_logo_manufacture/${brand.id}` } alt={`${brand.name}`} width={104} height={44} objectFit='cover' />
+ </Link>
+ </div>
+ ))}
+ </div>
+ {/* {topBrands.length > 8 && (
+ <div className='flex hover:bg-gray_r-8/35 rounded-10'>
+ <Link
+ href={createSlug('/shop/category/', category.name, category.id)}
+ className='category-mega-box__child-one flex items-center gap-4 font-bold hover:ml-4'
+ >
+ <p className='mt-2 mb-0 text-danger-500 font-semibold'>Lihat Semua Brand</p>
+ <ChevronRightIcon className='w-4 text-danger-500 font-bold' />
+ </Link>
+ </div>
+ )} */}
+ </div>
+ )
+}
+
+export default PopularBrand;
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index 09a791ee..54acdf7c 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -131,6 +131,7 @@ const Checkout = () => {
setLoadingVoucher(true);
let dataVoucher = await getVoucher(auth?.id, {
source: query,
+ type: 'all,brand',
});
SetListVoucher(dataVoucher);
@@ -146,40 +147,91 @@ const Checkout = () => {
};
const VoucherCode = async (code) => {
- const source = 'code=' + code + '&source=' + query;
// let dataVoucher = await findVoucher(code, auth.id, query);
- let dataVoucher = await getVoucherNew(source);
+ let dataVoucher = await getVoucher(auth?.id, {
+ source: query,
+ code: code,
+ });
if (dataVoucher.length <= 0) {
SetFindVoucher(1);
return;
}
- let addNewLine = dataVoucher[0];
- let checkList = listVouchers?.findIndex(
- (voucher) => voucher.code == addNewLine.code
- );
- if (checkList >= 0) {
- if (listVouchers[checkList].canApply) {
- ToggleSwitch(code);
- SetCodeVoucher(null);
+ dataVoucher.forEach((addNewLine) => {
+ if (addNewLine.applyType !== 'shipping') {
+ // Mencari voucher dalam listVouchers
+ let checkList = listVouchers?.findIndex(
+ (voucher) => voucher.code === addNewLine.code
+ );
+
+ if (checkList >= 0) {
+ if (listVouchers[checkList].canApply) {
+ ToggleSwitch(addNewLine.code); // Perbaikan: Gunakan code voucher yang benar
+ SetCodeVoucher(null);
+ } else {
+ SetSelisihHargaCode(listVouchers[checkList].differenceToApply);
+ SetFindVoucher(2);
+ }
+ return; // Hentikan eksekusi lebih lanjut pada iterasi ini
+ }
+
+ // Memeriksa apakah subtotal memenuhi syarat minimal pembelian
+ if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) {
+ SetSelisihHargaCode(
+ currencyFormat(
+ addNewLine.minPurchaseAmount - cartCheckout?.subtotal
+ )
+ );
+ SetFindVoucher(2);
+ return;
+ } else {
+ SetFindVoucher(3);
+ SetButtonTerapkan(true);
+ }
+
+ // Tambahkan voucher ke list dan set voucher aktif
+ SetListVoucher((prevList) => [addNewLine, ...prevList]);
+ SetActiveVoucher(addNewLine.code);
} else {
- SetSelisihHargaCode(listVouchers[checkList].differenceToApply);
- SetFindVoucher(2);
+ // Mencari voucher dalam listVoucherShippings
+ let checkList = listVoucherShippings?.findIndex(
+ (voucher) => voucher.code === addNewLine.code
+ );
+
+ if (checkList >= 0) {
+ if (listVoucherShippings[checkList].canApply) {
+ ToggleSwitch(addNewLine.code); // Perbaikan: Gunakan code voucher yang benar
+ SetCodeVoucher(null);
+ } else {
+ SetSelisihHargaCode(
+ listVoucherShippings[checkList].differenceToApply
+ );
+ SetFindVoucher(2);
+ }
+ return; // Hentikan eksekusi lebih lanjut pada iterasi ini
+ }
+
+ // Memeriksa apakah subtotal memenuhi syarat minimal pembelian
+ if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) {
+ SetSelisihHargaCode(
+ currencyFormat(
+ addNewLine.minPurchaseAmount - cartCheckout?.subtotal
+ )
+ );
+ SetFindVoucher(2);
+ return;
+ } else {
+ SetFindVoucher(3);
+ SetButtonTerapkan(true);
+ }
+
+ // Tambahkan voucher ke list pengiriman dan set voucher aktif pengiriman
+ SetListVoucherShipping((prevList) => [addNewLine, ...prevList]);
+ setActiveVoucherShipping(addNewLine.code);
}
- return;
- }
- if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) {
- SetSelisihHargaCode(
- currencyFormat(addNewLine.minPurchaseAmount - cartCheckout?.subtotal)
- );
- SetFindVoucher(2);
- return;
- } else {
- SetFindVoucher(3);
- SetButtonTerapkan(true);
- }
- SetListVoucher((prevList) => [addNewLine, ...prevList]);
- SetActiveVoucher(addNewLine.code);
+ });
+
+ // let addNewLine = dataVoucher[0];
};
useEffect(() => {
@@ -187,7 +239,7 @@ const Checkout = () => {
}, [bottomPopup]);
useEffect(() => {
- voucher();
+ // voucher();
const loadExpedisi = async () => {
let dataExpedisi = await ExpedisiList();
dataExpedisi = dataExpedisi.map((expedisi) => ({
@@ -210,13 +262,23 @@ const Checkout = () => {
};
}, []);
- const hitungDiscountVoucher = (code) => {
- let dataVoucherIndex = listVouchers.findIndex(
- (voucher) => voucher.code == code
- );
- let dataActiveVoucher = listVouchers[dataVoucherIndex];
+ const hitungDiscountVoucher = (code, source) => {
+ let countDiscount = 0;
+ if (source === 'voucher') {
+ let dataVoucherIndex = listVouchers.findIndex(
+ (voucher) => voucher.code == code
+ );
+ let dataActiveVoucher = listVouchers[dataVoucherIndex];
+
+ countDiscount = dataActiveVoucher.discountVoucher;
+ } else {
+ let dataVoucherIndex = listVoucherShippings.findIndex(
+ (voucher) => voucher.code == code
+ );
+ let dataActiveVoucher = listVoucherShippings[dataVoucherIndex];
- let countDiscount = dataActiveVoucher.discountVoucher;
+ countDiscount = dataActiveVoucher.discountVoucher;
+ }
/*if (dataActiveVoucher.discountType === 'percentage') {
countDiscount = cartCheckout?.subtotal * (dataActiveVoucher.discountAmount / 100)
@@ -233,14 +295,24 @@ const Checkout = () => {
return countDiscount;
};
- useEffect(() => {
- if (!listVouchers) return;
- if (!activeVoucher) return;
+ // useEffect(() => {
+ // if (!listVouchers) return;
+ // if (!activeVoucher) return;
+
+ // console.log('voucher')
+ // const countDiscount = hitungDiscountVoucher(activeVoucher, 'voucher');
- const countDiscount = hitungDiscountVoucher(activeVoucher);
+ // SetDiscountVoucher(countDiscount);
+ // }, [activeVoucher, listVouchers]);
- SetDiscountVoucher(countDiscount);
- }, [activeVoucher, listVouchers]);
+ // useEffect(() => {
+ // if (!listVoucherShippings) return;
+ // if (!activeVoucherShipping) return;
+
+ // const countDiscount = hitungDiscountVoucher(activeVoucherShipping, 'voucher_shipping');
+
+ // SetDiscountVoucherOngkir(countDiscount);
+ // }, [activeVoucherShipping, listVoucherShippings]);
useEffect(() => {
if (qVoucher === 'PASTIHEMAT' && listVouchers) {
@@ -389,12 +461,38 @@ const Checkout = () => {
if (typeof file !== 'undefined') data.po_file = await getFileBase64(file);
const isCheckouted = await checkoutApi({ data });
+
if (!isCheckouted?.id) {
toast.error('Gagal melakukan transaksi, terjadi kesalahan internal');
return;
- }
+ } else {
+ gtagPurchase(products, biayaKirim, isCheckouted.name);
+
+ gtag('event', 'conversion', {
+ send_to: 'AW-954540379/nDymCL3BhaQYENvClMcD',
+ value:
+ cartCheckout?.grandTotal +
+ Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000,
+ currency: 'IDR',
+ transaction_id: isCheckouted.id,
+ });
- gtagPurchase(products, biayaKirim, isCheckouted.name);
+ for (const product of products) deleteItemCart({ productId: product.id });
+ if (grandTotal > 0) {
+ const payment = await axios.post(
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/midtrans-payment?transactionId=${isCheckouted.id}`
+ );
+ setIsLoading(false);
+ window.location.href = payment.data.redirectUrl;
+ } else {
+ window.location.href = `${
+ process.env.NEXT_PUBLIC_SELF_HOST
+ }/shop/checkout/success?order_id=${isCheckouted.name.replace(
+ /\//g,
+ '-'
+ )}`;
+ }
+ }
const midtrans = async () => {
for (const product of products) deleteItemCart({ productId: product.id });
@@ -413,16 +511,6 @@ const Checkout = () => {
)}`;
}
};
-
- gtag('event', 'conversion', {
- send_to: 'AW-954540379/nDymCL3BhaQYENvClMcD',
- value:
- cartCheckout?.grandTotal +
- Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000,
- currency: 'IDR',
- transaction_id: isCheckouted.id,
- event_callback: midtrans,
- });
};
const handlingActivateCode = async () => {
@@ -483,6 +571,10 @@ const Checkout = () => {
const finalShippingAmt = biayaKirim - discShippingAmt;
+ const totalDiscountVoucher =
+ cartCheckout?.discountVoucher +
+ (cartCheckout?.discountVoucherShipping || 0);
+
return (
<>
<BottomPopup
@@ -593,10 +685,23 @@ const Checkout = () => {
)}
<hr className='mt-8 mb-4 border-gray_r-8' />
+ {/* {!loadingVoucher &&
+ listVouchers?.length === 1 &&
+ listVoucherShippings?.length === 1}
+ {
+ <div className='flex items-center justify-center mt-4 mb-4'>
+ <div className='text-center'>
+ <h1 className='font-bold mb-4'>Tidak ada voucher tersedia</h1>
+ <p className='text-gray-500'>
+ Maaf, saat ini tidak ada voucher yang tersedia.
+ </p>
+ </div>
+ </div>
+ } */}
{listVoucherShippings && listVoucherShippings?.length > 0 && (
<div>
- <h3 className='font-semibold mb-4'>Promo Gratis Ongkir</h3>
+ <h3 className='font-semibold mb-4'>Promo Extra Potongan Ongkir</h3>
{listVoucherShippings?.map((item) => (
<div key={item.id} className='relative'>
<div
@@ -731,16 +836,7 @@ const Checkout = () => {
<hr className='mt-8 mb-4 border-gray_r-8' />
<div>
- {!loadingVoucher && listVouchers?.length === 0 ? (
- <div className='flex items-center justify-center mt-4 mb-4'>
- <div className='text-center'>
- <h1 className='font-bold mb-4'>Tidak ada voucher tersedia</h1>
- <p className='text-gray-500'>
- Maaf, saat ini tidak ada voucher yang tersedia.
- </p>
- </div>
- </div>
- ) : (
+ {!loadingVoucher && listVouchers?.length > 0 && (
<h3 className='font-semibold mb-4'>
Promo Khusus Untuk {auth?.name}
</h3>
@@ -1004,7 +1100,12 @@ const Checkout = () => {
<div className='p-4 flex flex-col gap-y-4'>
{!!products &&
snakecaseKeys(products).map((item, index) => (
- <CartItem key={index} item={item} editable={false} />
+ <CartItem
+ key={index}
+ item={item}
+ editable={false}
+ selfPicking={selectedExpedisi === '1,32' ? true : false}
+ />
))}
</div>
@@ -1067,7 +1168,7 @@ const Checkout = () => {
<div className='flex gap-x-2 justify-between'>
<div className='text-gray_r-11'>Diskon Voucher</div>
<div className='text-danger-500'>
- - {currencyFormat(discountVoucher)}
+ - {currencyFormat(cartCheckout?.discountVoucher)}
</div>
</div>
)}
@@ -1295,7 +1396,12 @@ const Checkout = () => {
<div className='flex flex-col gap-y-8 border-t border-gray-300 pt-8'>
{!!products &&
snakecaseKeys(products).map((item, index) => (
- <CartItem key={index} item={item} editable={false} />
+ <CartItem
+ key={index}
+ item={item}
+ editable={false}
+ selfPicking={selectedExpedisi === '1,32' ? true : false}
+ />
))}
</div>
</div>
@@ -1362,7 +1468,7 @@ const Checkout = () => {
<div className='flex gap-x-2 justify-between'>
<div className='text-gray_r-11'>Diskon Voucher</div>
<div className='text-danger-500'>
- - {currencyFormat(discountVoucher)}
+ - {currencyFormat(cartCheckout?.discountVoucher)}
</div>
</div>
)}
@@ -1431,10 +1537,10 @@ const Checkout = () => {
className='object-contain object-center h-6 w-full rounded-md'
/>
</span>
- {activeVoucher ? (
+ {activeVoucher || activeVoucherShipping ? (
<div className=''>
<div className='text-left text-sm text-black font-semibold'>
- Hemat {currencyFormat(discountVoucher)}
+ Hemat {currencyFormat(totalDiscountVoucher)}
</div>
<div className='text-left mt-1 text-green-600 text-xs'>
Voucher berhasil digunakan
diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx
index f2d1a16f..b7798a24 100644
--- a/src/lib/home/components/CategoryDynamic.jsx
+++ b/src/lib/home/components/CategoryDynamic.jsx
@@ -33,9 +33,8 @@ const CategoryDynamic = () => {
};
fetchCategoryData();
- }, [categoryManagement, categoryData]);
+ }, [categoryManagement.isLoading]);
-
return (
<div>
{categoryManagement && categoryManagement.data?.map((category) => {
@@ -83,6 +82,7 @@ const CategoryDynamic = () => {
<NextImage
src={childCategory.image ? childCategory.image : "/images/noimage.jpeg"}
alt={childCategory.name}
+ className='p-2 ml-1'
width={40}
height={40}
/>
diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx
index 6568621c..6dbf771e 100644
--- a/src/lib/home/components/CategoryPilihan.jsx
+++ b/src/lib/home/components/CategoryPilihan.jsx
@@ -16,6 +16,7 @@ const CategoryPilihan = ({ id, categories }) => {
const { categoryPilihan } = useCategoryPilihan();
const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'banner-category-list' }));
return (
+ categoryPilihan.length > 0 && (
<section>
{isDesktop && (
<div>
@@ -114,6 +115,8 @@ const CategoryPilihan = ({ id, categories }) => {
</div>
)}
</section>
+
+ )
)
}
diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx
index ae12505d..b30fa5c9 100644
--- a/src/lib/home/components/PreferredBrand.jsx
+++ b/src/lib/home/components/PreferredBrand.jsx
@@ -66,7 +66,7 @@ const PreferredBrand = () => {
</Link>
)}
</div>
- <div className='border rounded border-gray_r-6'>
+ <div className=''>
{manufactures.isLoading && <PreferredBrandSkeleton />}
{!manufactures.isLoading && (
<Swiper {...swiperBanner}>
diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx
index 99258d94..c2f76069 100644
--- a/src/lib/home/components/PromotionProgram.jsx
+++ b/src/lib/home/components/PromotionProgram.jsx
@@ -3,11 +3,16 @@ import Image from 'next/image'
import { bannerApi } from '@/api/bannerApi';
import useDevice from '@/core/hooks/useDevice'
import { Swiper, SwiperSlide } from 'swiper/react';
+import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton';
const { useQuery } = require('react-query')
const BannerSection = () => {
const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' }));
const { isMobile, isDesktop } = useDevice()
+ if (promotionProgram.isLoading) {
+ return <BannerPromoSkeleton />;
+ }
+
return (
<div className='px-4 sm:px-0'>
<div className='flex justify-between items-center mb-4 '>
diff --git a/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx b/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx
new file mode 100644
index 00000000..c5f39f19
--- /dev/null
+++ b/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx
@@ -0,0 +1,16 @@
+import useDevice from '@/core/hooks/useDevice'
+import Skeleton from 'react-loading-skeleton'
+
+const BannerPromoSkeleton = () => {
+ const { isDesktop } = useDevice()
+
+ return (
+ <div className='grid grid-cols-1 md:grid-cols-3 gap-x-3'>
+ {Array.from({ length: isDesktop ? 3 : 1.2 }, (_, index) => (
+ <Skeleton count={1} height={isDesktop ? 60 : 36} key={index} />
+ ))}
+ </div>
+ )
+}
+
+export default BannerPromoSkeleton
diff --git a/src/lib/product/components/CategorySection.jsx b/src/lib/product/components/CategorySection.jsx
index 2af3db10..e8ebb095 100644
--- a/src/lib/product/components/CategorySection.jsx
+++ b/src/lib/product/components/CategorySection.jsx
@@ -35,7 +35,7 @@ const CategorySection = ({ categories }) => {
<div className="group transition-colors duration-300 ">
<div className="KartuInti h-12 w-26 max-w-sm lg:max-w-full flex flex-col border-[2px] border-gray-200 group-hover:border-red-400 rounded relative ">
<div className="flex items-center justify-start h-full px-1 flex-row ">
- <Image className="h-full" src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} width={56} height={48} alt={category?.name} />
+ <Image className="h-full p-1" src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} width={56} height={48} alt={category?.name} />
<h2 className="text-gray-700 group-hover:text-[#E20613] line-clamp-2 content-center h-fit w-60 px-1 font-semibold text-sm text-start">{category?.name}</h2>
</div>
</div>
diff --git a/src/lib/product/components/LobSectionCategory.jsx b/src/lib/product/components/LobSectionCategory.jsx
index 03d6e8c0..5cd467e9 100644
--- a/src/lib/product/components/LobSectionCategory.jsx
+++ b/src/lib/product/components/LobSectionCategory.jsx
@@ -24,7 +24,6 @@ const LobSectionCategory = ({ categories }) => {
};
const displayedCategories = categories[0]?.categoryIds;
-
return (
<section>
{isDesktop && (
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index 94db144d..22ce0533 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -17,8 +17,8 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
const [discount, setDiscount] = useState(0);
let voucherPastiHemat = 0;
-
- if (product?.voucherPastiHemat?.length > 0) {
+
+ if (product?.voucherPastiHemat ? product?.voucherPastiHemat.length : voucherPastiHemat > 0) {
const stringVoucher = product?.voucherPastiHemat[0];
const validJsonString = stringVoucher.replace(/'/g, '"');
voucherPastiHemat = JSON.parse(validJsonString);
@@ -146,13 +146,22 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
</Link>
<div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'>
- {product?.manufacture?.name ? (
- <Link href={URL.manufacture} className='mb-1'>
- {product.manufacture.name}
+ <div className='flex justify-between '>
+ {product?.manufacture?.name ? (
+ <Link href={URL.manufacture} className='mb-1 mt-1'>
+ {product.manufacture.name}
+ </Link>
+ ) : (
+ <div>-</div>
+ )}
+ {product?.isInBu && (
+ <Link href='/panduan-pick-up-service' className='group'>
+ <Image src='/images/PICKUP-NOW.png' className='group-hover:scale-105 transition-transform duration-200' alt='pickup now' width={90} height={12} />
</Link>
- ) : (
- <div>-</div>
- )}
+
+
+ )}
+ </div>
<Link
href={URL.product}
className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`}
@@ -292,9 +301,18 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
</div>
)}
{product?.manufacture?.name ? (
- <Link href={URL.manufacture} className='mb-1'>
+ <div className='flex justify-between'>
+ <Link href={URL.manufacture} className='mb-1'>
{product.manufacture.name}
</Link>
+ {/* {product?.is_in_bu && (
+ <div className='bg-red-500 rounded'>
+ <span className='p-[6px] text-xs text-white'>
+ Click & Pickup
+ </span>
+ </div>
+ )} */}
+ </div>
) : (
<div>-</div>
)}
diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx
index 1933c5f0..73fecab5 100644
--- a/src/lib/product/components/ProductFilterDesktop.jsx
+++ b/src/lib/product/components/ProductFilterDesktop.jsx
@@ -22,6 +22,7 @@ import { formatCurrency } from '@/core/utils/formatValue'
const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => {
+
const router = useRouter()
const { query } = router
const [order, setOrder] = useState(query?.orderBy)
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index 09534a5d..eaeac71a 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -42,7 +42,7 @@ const ProductSearch = ({
const [q, setQ] = useState(query?.q || '*');
const [search, setSearch] = useState(query?.q || '*');
const [limit, setLimit] = useState(router.query?.limit || 30);
- const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular');
+ const [orderBy, setOrderBy] = useState(router.query?.orderBy);
const [finalQuery, setFinalQuery] = useState({});
const [queryFinal, setQueryFinal] = useState({});
const [dataCategoriesProduct, setDataCategoriesProduct] = useState([])
@@ -267,6 +267,7 @@ const ProductSearch = ({
const orderOptions = [
+ { value: '', label: 'Pilih Filter' },
{ value: 'price-asc', label: 'Harga Terendah' },
{ value: 'price-desc', label: 'Harga Tertinggi' },
{ value: 'popular', label: 'Populer' },
diff --git a/src/lib/tracking-order/api/trackingOrder.js b/src/lib/tracking-order/api/trackingOrder.js
new file mode 100644
index 00000000..cc48c40c
--- /dev/null
+++ b/src/lib/tracking-order/api/trackingOrder.js
@@ -0,0 +1,8 @@
+import odooApi from "@/core/api/odooApi";
+
+export const trackingOrder = async ({query}) => {
+ const params = new URLSearchParams(query).toString();
+ const list = await odooApi('GET', `/api/v1/tracking_order?${params}`)
+
+ return list;
+}
diff --git a/src/lib/tracking-order/component/TrackingOrder.jsx b/src/lib/tracking-order/component/TrackingOrder.jsx
new file mode 100644
index 00000000..394979c1
--- /dev/null
+++ b/src/lib/tracking-order/component/TrackingOrder.jsx
@@ -0,0 +1,139 @@
+import { yupResolver } from '@hookform/resolvers/yup'
+import React, { useEffect, useState } from 'react'
+import { useForm } from 'react-hook-form'
+import * as Yup from 'yup'
+import Manifest from '@/lib/treckingAwb/component/Manifest'
+import { trackingOrder } from '../api/trackingOrder'
+import { useQuery } from 'react-query'
+import { Spinner } from '@chakra-ui/react';
+import { Search } from 'lucide-react';
+import whatsappUrl from '@/core/utils/whatsappUrl';
+import Link from 'next/link'
+
+const TrackingOrder = () => {
+ const [idAWB, setIdAWB] = useState(null)
+ const [inputQuery, setInputQuery] = useState(null)
+ const [buttonClick, setButtonClick] = useState(false)
+ const [apiError, setApiError] = useState(null) // State to store API error message
+
+ const closePopup = () => {
+ setIdAWB(null)
+ setButtonClick(false)
+ setInputQuery(null)
+ setApiError(null) // Reset error message on close
+ }
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ control,
+ reset
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues
+ })
+
+ const query = {
+ email: inputQuery?.email,
+ so: inputQuery?.id
+ }
+
+ const { data: tracking, isLoading, isError, error } = useQuery(
+ ['tracking', query],
+ () => trackingOrder({ query: query }),
+ {
+ enabled: !!query.email && !!query.so,
+ onSuccess: (data) => {
+ if (buttonClick) {
+ if (data?.code === 403 || data?.code === 400 || data?.code === 404) {
+ setApiError(data?.description);
+ } else if (data?.pickings?.length > 0) {
+ setIdAWB(data.pickings[0]?.id);
+ } else {
+ setApiError('No pickings data available');
+ }
+ setButtonClick(false);
+ setInputQuery(null);
+ }
+ },
+ }
+ );
+
+ const onSubmitHandler = async (values) => {
+ setInputQuery(values)
+ setButtonClick(true)
+ }
+
+ return (
+ <div className='container mx-auto flex py-10 flex-col'>
+ <h1 className='text-h-sm md:text-title-sm font-semibold mb-6'>Tracking Order</h1>
+ <div className='flex justify-start items-start'>
+ <span className='text-base w-full'>
+ {`Untuk melacak pesanan Anda, masukkan Nomor Transaksi di kotak bawah ini dan masukkan Email login anda lalu tekan tombol "Lacak". Nomor Transaksi ini dapat Anda lihat dalam menu `}
+ <Link href='/my/transactions' className='text-red-500'>
+ Daftar Transaksi
+ </Link>
+ {`. Jika mengalami kesulitan `}
+ <Link href='https://wa.me/6281717181922' target='_blank' rel='noreferrer' className='text-red-500'>
+ hubungi kami
+ </Link>
+ {`.`}
+ </span>
+ </div>
+ <div>
+ <form onSubmit={handleSubmit(onSubmitHandler)} className='flex mt-4 flex-row w-full '>
+ <div className='w-[90%] grid grid-cols-2 gap-4'>
+ <div className='flex flex-col '>
+ <label className='form-label mb-2'>ID Pesanan*</label>
+ <input
+ {...register('id')}
+ placeholder='dapat dilihat pada email konfirmasi anda'
+ type='text'
+ className='form-input mb-2'
+ aria-invalid={errors.id?.message}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>{errors.id?.message}</div>
+ </div>
+ <div className='flex flex-col '>
+ <label className='form-label mb-2'>Email Penagihan*</label>
+ <input
+ {...register('email')}
+ placeholder='Email yang anda gunakan saat pembayaran'
+ type='text'
+ className='form-input'
+ aria-invalid={errors.email?.message}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
+ </div>
+ </div>
+ <div className={` ${errors.id?.message ? 'mt-2' : 'mt-5'} flex items-center ml-4`}>
+ <button
+ type='submit'
+ className='bg-red-600 border border-red-600 rounded-md text-sm text-white w-24 h-11 mb-1 content-center flex flex-row justify-center items-center'
+ >
+ {isLoading && <Spinner size='xs' className='mr-2'/>}
+ {!isLoading && <Search size={16} strokeWidth={1} className='mr-2'/>}
+ <p>Lacak</p>
+ </button>
+ </div>
+ </form>
+ {/* Display the API error message */}
+ {apiError && <div className='text-danger-500 mt-4'>{apiError}</div>}
+ <Manifest idAWB={idAWB} closePopup={closePopup} />
+ </div>
+ </div>
+ )
+}
+
+const validationSchema = Yup.object().shape({
+ email: Yup.string().email('Format harus seperti contoh@email.com').required('Harus di-isi'),
+ id: Yup.string().required('Harus di-isi'),
+})
+
+const defaultValues = {
+ email: '',
+ id: ''
+}
+
+export default TrackingOrder
diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx
index 9bef895a..4d401037 100644
--- a/src/lib/transaction/components/Transaction.jsx
+++ b/src/lib/transaction/components/Transaction.jsx
@@ -1,6 +1,6 @@
import Spinner from '@/core/components/elements/Spinner/Spinner';
import NextImage from 'next/image';
-import rejectImage from "../../../../public/images/reject.png"
+import rejectImage from '../../../../public/images/reject.png';
import useTransaction from '../hooks/useTransaction';
import TransactionStatusBadge from './TransactionStatusBadge';
import Divider from '@/core/components/elements/Divider/Divider';
@@ -40,7 +40,7 @@ import rejectProductApi from '../api/rejectProductApi';
import { useRouter } from 'next/router';
const Transaction = ({ id }) => {
- const router = useRouter()
+ const router = useRouter();
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedProduct, setSelectedProduct] = useState(null);
const [reason, setReason] = useState('');
@@ -152,7 +152,10 @@ const Transaction = ({ id }) => {
const memoizeVariantGroupCardReject = useMemo(
() => (
<div className='p-4 pt-0 flex flex-col gap-y-3'>
- <VariantGroupCard variants={transaction.data?.productsRejectLine} buyMore />
+ <VariantGroupCard
+ variants={transaction.data?.productsRejectLine}
+ buyMore
+ />
</div>
),
[transaction.data]
@@ -182,26 +185,25 @@ const Transaction = ({ id }) => {
};
const handleRejectProduct = async () => {
- try{
+ try {
if (!reason.trim()) {
toast.error('Masukkan alasan terlebih dahulu');
return;
- }else{
- let idSo = transaction?.data.id
- let idProduct = selectedProduct?.id
- await rejectProductApi({ idSo, idProduct, reason});
+ } else {
+ let idSo = transaction?.data.id;
+ let idProduct = selectedProduct?.id;
+ await rejectProductApi({ idSo, idProduct, reason });
closeModal();
- toast.success("Produk berhasil di reject")
+ toast.success('Produk berhasil di reject');
setTimeout(() => {
window.location.reload();
- }, 1500);
+ }, 1500);
}
- }catch(error){
+ } catch (error) {
toast.error('Gagal reject produk. Silakan coba lagi.');
}
};
-
return (
transaction.data?.name && (
<>
@@ -390,14 +392,20 @@ const Transaction = ({ id }) => {
<p className='text-gray_r-11 leading-none'>Dokumen PO</p>
<button
type='button'
- className='btn-light py-1.5 px-3 ml-auto'
+ className='inline-block text-danger-500'
onClick={
transaction.data?.purchaseOrderFile
? () => downloadPurchaseOrder(transaction.data)
- : openUploadPo
+ : transaction?.data.invoices.length < 1
+ ? openUploadPo
+ : ''
}
>
- {transaction.data?.purchaseOrderFile ? 'Download' : 'Upload'}
+ {transaction?.data?.purchaseOrderFile
+ ? 'Download'
+ : transaction?.data.invoices.length < 1
+ ? 'Upload'
+ : '-'}
</button>
</div>
</div>
@@ -406,13 +414,13 @@ const Transaction = ({ id }) => {
<Divider />
<div className='font-medium p-4'>Detail Produk</div>
- {transaction?.data?.products.length > 0? (
- <div>
- {memoizeVariantGroupCard}
- </div>
+ {transaction?.data?.products.length > 0 ? (
+ <div>{memoizeVariantGroupCard}</div>
) : (
- <div className='badge-red text-sm px-2 ml-4'>Semua produk telah di reject</div>
- )}
+ <div className='badge-red text-sm px-2 ml-4'>
+ Semua produk telah di reject
+ </div>
+ )}
{transaction?.data?.productsRejectLine.length > 0 && (
<div>
@@ -594,12 +602,16 @@ const Transaction = ({ id }) => {
onClick={
transaction.data?.purchaseOrderFile
? () => downloadPurchaseOrder(transaction.data)
- : openUploadPo
+ : transaction?.data.invoices.length < 1
+ ? openUploadPo
+ : ''
}
>
{transaction?.data?.purchaseOrderFile
? 'Download'
- : 'Upload'}
+ : transaction?.data.invoices.length < 1
+ ? 'Upload'
+ : '-'}
</button>
</div>
</>
@@ -628,9 +640,11 @@ const Transaction = ({ id }) => {
<div className='text-h-sm font-semibold mt-10 mb-4'>
Pengiriman
</div>
- {transaction?.data?.pickings.length == 0 && (
- <div className='badge-red text-sm'>Belum ada pengiriman</div>
- )}
+ {transaction?.data?.pickings.length == 0 && (
+ <div className='badge-red text-sm'>
+ Belum ada pengiriman
+ </div>
+ )}
<div className='grid grid-cols-1 gap-1 w-2/3'>
{transaction?.data?.pickings?.map((airway) => (
<button
@@ -646,7 +660,9 @@ const Transaction = ({ id }) => {
</div>
<div className='flex gap-x-2'>
<div className='text-sm text-gray-600 badge-green leading-[1.5] mt-1'>
- {airway?.delivered ? 'Pesanan Tiba' : 'Sedang Dikirim'}
+ {airway?.delivered
+ ? 'Pesanan Tiba'
+ : 'Sedang Dikirim'}
</div>
<ChevronRightIcon className='w-5 stroke-2' />
</div>
@@ -655,51 +671,53 @@ const Transaction = ({ id }) => {
</div>
</div>
<div className='invoice w-1/2 '>
- <div className='text-h-sm font-semibold mt-10 mb-4 '>Invoice</div>
- {transaction.data?.invoices?.length === 0 && (
- <div className='badge-red text-sm'>Belum ada invoice</div>
- )}
- <div className='grid grid-cols-1 gap-1 w-2/3 '>
- {transaction.data?.invoices?.map((invoice, index) => (
- <Link href={`/my/invoices/${invoice.id}`} key={index}>
- <div className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between'>
- <div>
- <p className='mb-1'>{invoice?.name}</p>
- <div className='flex items-center gap-x-1'>
- {invoice.amountResidual > 0 ? (
- <div className='badge-red'>Belum Lunas</div>
- ) : (
- <div className='badge-green'>Lunas</div>
- )}
- <p className='text-caption-2 text-gray_r-11'>
- {currencyFormat(invoice.amountTotal)}
- </p>
- </div>
+ <div className='text-h-sm font-semibold mt-10 mb-4 '>
+ Invoice
+ </div>
+ {transaction.data?.invoices?.length === 0 && (
+ <div className='badge-red text-sm'>Belum ada invoice</div>
+ )}
+ <div className='grid grid-cols-1 gap-1 w-2/3 '>
+ {transaction.data?.invoices?.map((invoice, index) => (
+ <Link href={`/my/invoices/${invoice.id}`} key={index}>
+ <div className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between'>
+ <div>
+ <p className='mb-1'>{invoice?.name}</p>
+ <div className='flex items-center gap-x-1'>
+ {invoice.amountResidual > 0 ? (
+ <div className='badge-red'>Belum Lunas</div>
+ ) : (
+ <div className='badge-green'>Lunas</div>
+ )}
+ <p className='text-caption-2 text-gray_r-11'>
+ {currencyFormat(invoice.amountTotal)}
+ </p>
</div>
- <ChevronRightIcon className='w-5 stroke-2' />
</div>
- </Link>
- ))}
- </div>
+ <ChevronRightIcon className='w-5 stroke-2' />
+ </div>
+ </Link>
+ ))}
+ </div>
</div>
</div>
<div className='text-h-sm font-semibold mt-4 mb-4'>
Rincian Pembelian
</div>
- {transaction?.data?.products?.length > 0? (
- <table className='table-data'>
- <thead>
- <tr>
- <th>Nama Produk</th>
- {/* <th>Diskon</th> */}
- <th>Jumlah</th>
- <th>Harga</th>
- <th>Subtotal</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
+ {transaction?.data?.products?.length > 0 ? (
+ <table className='table-data'>
+ <thead>
+ <tr>
+ <th>Nama Produk</th>
+ {/* <th>Diskon</th> */}
+ <th>Jumlah</th>
+ <th>Harga</th>
+ <th>Subtotal</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
{transaction?.data?.products?.map((product) => (
<tr key={product.id}>
<td className='flex'>
@@ -711,37 +729,37 @@ const Transaction = ({ id }) => {
)}
className='w-[20%] flex-shrink-0'
>
- <div className='relative'>
+ <div className='relative'>
<Image
src={product?.parent?.image}
alt={product?.name}
className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md'
/>
- <div className='absolute top-0 right-4 flex mt-3'>
- <div className='gambarB '>
- {product.isSni && (
- <ImageNext
- src='/images/sni-logo.png'
- alt='SNI Logo'
- className='w-2 h-4 object-contain object-top sm:h-4'
- width={50}
- height={50}
- />
- )}
- </div>
- <div className='gambarC '>
- {product.isTkdn && (
- <ImageNext
- src='/images/TKDN.png'
- alt='TKDN'
- className='w-5 h-4 object-contain object-top ml-1 sm:h-4'
- width={50}
- height={50}
- />
- )}
+ <div className='absolute top-0 right-4 flex mt-3'>
+ <div className='gambarB '>
+ {product.isSni && (
+ <ImageNext
+ src='/images/sni-logo.png'
+ alt='SNI Logo'
+ className='w-2 h-4 object-contain object-top sm:h-4'
+ width={50}
+ height={50}
+ />
+ )}
+ </div>
+ <div className='gambarC '>
+ {product.isTkdn && (
+ <ImageNext
+ src='/images/TKDN.png'
+ alt='TKDN'
+ className='w-5 h-4 object-contain object-top ml-1 sm:h-4'
+ width={50}
+ height={50}
+ />
+ )}
+ </div>
</div>
</div>
- </div>
</Link>
<div className='px-2 text-left'>
<Link
@@ -774,33 +792,42 @@ const Transaction = ({ id }) => {
{currencyFormat(product.price.price)}
</div>
)} */}
- <div>{currencyFormat(product.price.priceDiscount)}</div>
+ <div>
+ {currencyFormat(product.price.priceDiscount)}
+ </div>
</td>
<td>{currencyFormat(product.price.subtotal)}</td>
{/* {auth?.feature.soApproval && (auth.webRole == 2 || auth.webRole == 3) && (transaction.data.isReaject == false) && ( */}
- {auth?.feature.soApproval && (auth.webRole == 2 || auth.webRole == 3) && (router.asPath.includes("/my/quotations/")) && transaction.data?.status == 'draft' && (
- <td>
- <button
- className="bg-red-500 text-white py-1 px-3 rounded"
- onClick={() => openModal(product)}
- >
- Reject
- </button>
- </td>
- )}
+ {auth?.feature.soApproval &&
+ (auth.webRole == 2 || auth.webRole == 3) &&
+ router.asPath.includes('/my/quotations/') &&
+ transaction.data?.status == 'draft' && (
+ <td>
+ <button
+ className='bg-red-500 text-white py-1 px-3 rounded'
+ onClick={() => openModal(product)}
+ >
+ Reject
+ </button>
+ </td>
+ )}
</tr>
))}
</tbody>
</table>
) : (
- <div className='badge-red text-sm'>Semua produk telah di reject</div>
+ <div className='badge-red text-sm'>
+ Semua produk telah di reject
+ </div>
)}
-
+
{isModalOpen && (
<div className='fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center'>
- <div className='bg-white p-4 rounded w-96
+ <div
+ className='bg-white p-4 rounded w-96
ease-in-out opacity-100
- transform transition-transform duration-300 scale-100'>
+ transform transition-transform duration-300 scale-100'
+ >
<h2 className='text-lg mb-2'>Berikan Alasan</h2>
<textarea
value={reason}
@@ -826,117 +853,116 @@ const Transaction = ({ id }) => {
</div>
)}
- {transaction?.data?.products?.map((product) => (
- <div className='flex justify-end mt-4' key={product.id}>
- <div className='w-1/4 grid grid-cols-2 gap-y-3 text-gray_r-12/80'>
- <div className='text-right'>Subtotal</div>
- <div className='text-right font-medium'>
- {currencyFormat(transaction.data?.amountUntaxed)}
- </div>
+ {transaction?.data?.products?.length > 0 && (
+ <div className='flex justify-end mt-4'>
+ <div className='w-1/4 grid grid-cols-2 gap-y-3 text-gray_r-12/80'>
+ <div className='text-right'>Subtotal</div>
+ <div className='text-right font-medium'>
+ {currencyFormat(transaction.data?.amountUntaxed)}
+ </div>
- <div className='text-right'>PPN 11%</div>
- <div className='text-right font-medium'>
- {currencyFormat(transaction.data?.amountTax)}
- </div>
+ <div className='text-right'>PPN 11%</div>
+ <div className='text-right font-medium'>
+ {currencyFormat(transaction.data?.amountTax)}
+ </div>
- <div className='text-right whitespace-nowrap'>
- Biaya Pengiriman
- </div>
- <div className='text-right font-medium'>
- {currencyFormat(transaction.data?.deliveryAmount)}
- </div>
+ <div className='text-right whitespace-nowrap'>
+ Biaya Pengiriman
+ </div>
+ <div className='text-right font-medium'>
+ {currencyFormat(transaction.data?.deliveryAmount)}
+ </div>
- <div className='text-right'>Grand Total</div>
- <div className='text-right font-medium text-gray_r-12'>
- {currencyFormat(transaction.data?.amountTotal)}
+ <div className='text-right'>Grand Total</div>
+ <div className='text-right font-medium text-gray_r-12'>
+ {currencyFormat(transaction.data?.amountTotal)}
+ </div>
</div>
</div>
- </div>
- ))}
-
-
+ )}
{transaction?.data?.productsRejectLine.length > 0 && (
- <div className='text-h-sm font-semibold mt-10 mb-4'>
- Rincian Produk Reject
- </div>
+ <div className='text-h-sm font-semibold mt-10 mb-4'>
+ Rincian Produk Reject
+ </div>
)}
{transaction?.data?.productsRejectLine.length > 0 && (
- <table className='table-data'>
- <thead>
- <tr>
- <th>Nama Produk</th>
- {/* <th>Diskon</th> */}
- <th>Jumlah</th>
- <th>Harga</th>
- <th>Subtotal</th>
- </tr>
- </thead>
- <tbody>
- {transaction?.data?.productsRejectLine?.map((product) => (
- <tr key={product.id}>
- <td className='flex'>
+ <table className='table-data'>
+ <thead>
+ <tr>
+ <th>Nama Produk</th>
+ {/* <th>Diskon</th> */}
+ <th>Jumlah</th>
+ <th>Harga</th>
+ <th>Subtotal</th>
+ </tr>
+ </thead>
+ <tbody>
+ {transaction?.data?.productsRejectLine?.map((product) => (
+ <tr key={product.id}>
+ <td className='flex'>
+ <Link
+ href={createSlug(
+ '/shop/product/',
+ product?.parent.name,
+ product?.parent.id
+ )}
+ className='w-[20%] flex-shrink-0'
+ >
+ <Image
+ src={product?.parent?.image}
+ alt={product?.name}
+ className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md'
+ />
+ </Link>
+ <div className='px-2 text-left'>
<Link
href={createSlug(
'/shop/product/',
product?.parent.name,
product?.parent.id
)}
- className='w-[20%] flex-shrink-0'
+ className='line-clamp-2 leading-6 !text-gray_r-12 font-normal'
>
- <Image
- src={product?.parent?.image}
- alt={product?.name}
- className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md'
- />
+ {product?.parent?.name}
</Link>
- <div className='px-2 text-left'>
- <Link
- href={createSlug(
- '/shop/product/',
- product?.parent.name,
- product?.parent.id
- )}
- className='line-clamp-2 leading-6 !text-gray_r-12 font-normal'
- >
- {product?.parent?.name}
- </Link>
- <div className='text-gray_r-11 mt-2'>
- {product?.code}{' '}
- {product?.attributes.length > 0
- ? `| ${product?.attributes.join(', ')}`
- : ''}
- </div>
+ <div className='text-gray_r-11 mt-2'>
+ {product?.code}{' '}
+ {product?.attributes.length > 0
+ ? `| ${product?.attributes.join(', ')}`
+ : ''}
</div>
- </td>
- {/* <td>
+ </div>
+ </td>
+ {/* <td>
{product.price.discountPercentage > 0
? `${product.price.discountPercentage}%`
: ''}
</td> */}
- <td>{product.quantity}</td>
- <td>
- {/* {product.price.discountPercentage > 0 && (
+ <td>{product.quantity}</td>
+ <td>
+ {/* {product.price.discountPercentage > 0 && (
<div className='line-through mb-1 text-caption-1 text-gray_r-12/70'>
{currencyFormat(product.price.price)}
</div>
)} */}
- <div>{currencyFormat(product.price.priceDiscount)}</div>
- </td>
- <td className='flex justify-center'>
- <NextImage
- src={rejectImage}
- alt='Reject'
- width={90}
- height={30}
- />
- </td>
- </tr>
- ))}
- </tbody>
- </table>
+ <div>
+ {currencyFormat(product.price.priceDiscount)}
+ </div>
+ </td>
+ <td className='flex justify-center'>
+ <NextImage
+ src={rejectImage}
+ alt='Reject'
+ width={90}
+ height={30}
+ />
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
)}
-
</div>
</div>
</DesktopView>
diff --git a/src/lib/treckingAwb/component/Manifest.jsx b/src/lib/treckingAwb/component/Manifest.jsx
index cf2fa4ed..fbc95702 100644
--- a/src/lib/treckingAwb/component/Manifest.jsx
+++ b/src/lib/treckingAwb/component/Manifest.jsx
@@ -40,10 +40,18 @@ const Manifest = ({ idAWB, closePopup }) => {
const getManifest = async () => {
setIsLoading(true)
const auth = getAuth()
- const list = await odooApi(
- 'GET',
- `/api/v1/partner/${auth.partnerId}/stock-picking/${idAWB}/tracking`
- )
+ let list
+ if(auth){
+ list = await odooApi(
+ 'GET',
+ `/api/v1/partner/${auth.partnerId}/stock-picking/${idAWB}/tracking`
+ )
+ }else{
+ list = await odooApi(
+ 'GET',
+ `/api/v1/stock-picking/${idAWB}/tracking`
+ )
+ }
setManifests(list)
setIsLoading(false)
}