summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-11-15 14:33:42 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-11-15 14:33:42 +0700
commite5544ace96dd9a200ca5876b8e9ba837ad0a26ac (patch)
treed0f1bb7711e2d93859e1d534551328b14a3ae78e /src/lib
parent0d3c0cf6a00ef81bfdb944490e48f16af41fc029 (diff)
parent49f2e6a5612d000c3a740513c1a54b73bb656d77 (diff)
Merge branch 'new-release' into CR/redis
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/checkout/components/Checkout.jsx27
-rw-r--r--src/lib/product/components/Product/ProductDesktopVariant.jsx400
-rw-r--r--src/lib/product/components/Product/ProductMobileVariant.jsx33
-rw-r--r--src/lib/product/components/ProductCard.jsx2
-rw-r--r--src/lib/quotation/components/Quotation.jsx5
-rw-r--r--src/lib/shipment/components/Shipments.jsx204
-rw-r--r--src/lib/transaction/components/Transaction.jsx6
-rw-r--r--src/lib/variant/components/VariantCard.jsx22
8 files changed, 460 insertions, 239 deletions
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index 0e180d9c..afbf1e6c 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -413,7 +413,12 @@ const Checkout = () => {
Math.round(parseInt(finalShippingAmt * 1.1) / 1000) * 1000;
const finalGT = GT < 0 ? 0 : GT;
setGrandTotal(finalGT);
- }, [biayaKirim, cartCheckout?.grandTotal, activeVoucher, activeVoucherShipping]);
+ }, [
+ biayaKirim,
+ cartCheckout?.grandTotal,
+ activeVoucher,
+ activeVoucherShipping,
+ ]);
const checkout = async () => {
const file = poFile.current.files[0];
@@ -442,6 +447,7 @@ const Checkout = () => {
const productOrder = products.map((product) => ({
product_id: product.id,
quantity: product.quantity,
+ available_quantity: product?.availableQuantity,
}));
let data = {
// partner_shipping_id: auth.partnerId,
@@ -483,6 +489,11 @@ const Checkout = () => {
transaction_id: isCheckouted.id,
});
+ gtag('set', 'user_data', {
+ email: auth.email,
+ phone_number: auth.mobile ?? auth.phone,
+ });
+
for (const product of products) deleteItemCart({ productId: product.id });
if (grandTotal > 0) {
const payment = await axios.post(
@@ -500,7 +511,7 @@ const Checkout = () => {
}
}
- /* const midtrans = async () => {
+ /* const midtrans = async () => {
for (const product of products) deleteItemCart({ productId: product.id });
if (grandTotal > 0) {
const payment = await axios.post(
@@ -1192,7 +1203,11 @@ const Checkout = () => {
<div className='text-gray_r-11'>
Biaya Kirim <p className='text-xs mt-1'>{etdFix}</p>
</div>
- <div>{currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000)}</div>
+ <div>
+ {currencyFormat(
+ Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000
+ )}
+ </div>
</div>
{activeVoucherShipping && voucherShippingAmt && (
<div className='flex gap-x-2 justify-between'>
@@ -1493,7 +1508,11 @@ const Checkout = () => {
Biaya Kirim
<p className='text-xs mt-1'>{etdFix}</p>
</div>
- <div>{currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000) }</div>
+ <div>
+ {currencyFormat(
+ Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000
+ )}
+ </div>
</div>
{activeVoucherShipping && voucherShippingAmt && (
<div className='flex gap-x-2 justify-between'>
diff --git a/src/lib/product/components/Product/ProductDesktopVariant.jsx b/src/lib/product/components/Product/ProductDesktopVariant.jsx
index a4cc62dd..5dfd452b 100644
--- a/src/lib/product/components/Product/ProductDesktopVariant.jsx
+++ b/src/lib/product/components/Product/ProductDesktopVariant.jsx
@@ -1,14 +1,12 @@
-import { Box, Skeleton, Tooltip } from '@chakra-ui/react';
+import { Box, Button, Skeleton, Tooltip } from '@chakra-ui/react';
import { HeartIcon } from '@heroicons/react/24/outline';
-import { Info } from 'lucide-react';
+import { Info, MessageCircleIcon, Share2Icon } from 'lucide-react';
import { useRouter } from 'next/router';
import { useCallback, useEffect, useRef, useState } from 'react';
import { toast } from 'react-hot-toast';
-import { MessageCircleIcon, Share2Icon } from 'lucide-react';
import AddToWishlist from '../../../../../src-migrate/modules/product-detail/components/AddToWishlist';
import { RWebShare } from 'react-web-share';
import LazyLoad from 'react-lazy-load';
-import { Button } from '@chakra-ui/react';
import { useProductCartContext } from '@/contexts/ProductCartContext';
import odooApi from '@/core/api/odooApi';
import Image from '@/core/components/elements/Image/Image';
@@ -21,11 +19,16 @@ import currencyFormat from '@/core/utils/currencyFormat';
import { createSlug } from '@/core/utils/slug';
import whatsappUrl from '@/core/utils/whatsappUrl';
import { getAuth } from '~/libs/auth';
-import SimilarBottom from '~/modules/product-detail/components/SimilarBottom';
+
+import ImageNext from 'next/image';
import productSimilarApi from '../../api/productSimilarApi';
import ProductCard from '../ProductCard';
import ProductSimilar from '../ProductSimilar';
+import ProductPromoSection from '~/modules/product-promo/components/Section';
+import SimilarBottom from '~/modules/product-detail/components/SimilarBottom';
+
const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST;
+
const ProductDesktopVariant = ({
product,
wishlist,
@@ -44,25 +47,20 @@ const ProductDesktopVariant = ({
const { setRefreshCart } = useProductCartContext();
- useEffect(() => {
- const createdAskUrl = whatsappUrl({
- template: 'product',
- payload: {
- manufacture: product.manufacture.name,
- productName: product.name,
- url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath,
- },
- fallbackUrl: router.asPath,
- });
+ const [quantityInput, setQuantityInput] = useState(1);
- setAskAdminUrl(createdAskUrl);
- }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]);
+ const createdAskUrl = whatsappUrl({
+ template: 'product',
+ payload: {
+ manufacture: product.manufacture.name,
+ productName: product.name,
+ url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath,
+ },
+ fallbackUrl: router.asPath,
+ });
const getLowestPrice = useCallback(() => {
const lowest = product.price;
- /* const lowest = prices.reduce((lowest, price) => {
- return price.priceDiscount < lowest.priceDiscount ? price : lowest
- }, prices[0])*/
return lowest;
}, [product]);
@@ -95,7 +93,7 @@ const ProductDesktopVariant = ({
router.push(`/login?next=/shop/product/${slug}?srsltid=${srsltid}`);
return;
}
- const quantity = variantQuantityRefs.current[product.id].value;
+ const quantity = quantityInput;
if (!validQuantity(quantity)) return;
updateItemCart({
productId: product.id,
@@ -149,6 +147,45 @@ const ProductDesktopVariant = ({
router.push(`/shop/checkout?source=buy`);
};
+ const handleButton = async (variant) => {
+ const quantity = quantityInput;
+ let isLoggedIn = typeof auth === 'object';
+
+ if (!isLoggedIn) {
+ const currentUrl = encodeURIComponent(router.asPath);
+ await router.push(`/login?next=${currentUrl}`);
+
+ // Tunggu login berhasil, misalnya dengan memantau perubahan status auth.
+ const authCheckInterval = setInterval(() => {
+ const newAuth = getAuth();
+ if (typeof newAuth === 'object') {
+ isLoggedIn = true;
+ auth = newAuth; // Update nilai auth setelah login
+ clearInterval(authCheckInterval);
+ }
+ }, 500); // Periksa status login setiap 500ms
+
+ await new Promise((resolve) => {
+ const checkLogin = setInterval(() => {
+ if (isLoggedIn) {
+ clearInterval(checkLogin);
+ resolve(null);
+ }
+ }, 500);
+ });
+ }
+ if (!validQuantity(quantity)) return;
+
+ updateItemCart({
+ productId: variant,
+ quantity,
+ programLineId: null,
+ selected: true,
+ source: 'buy',
+ });
+ router.push('/shop/quotation?source=buy');
+ };
+
const variantSectionRef = useRef(null);
const goToVariantSection = () => {
if (variantSectionRef.current) {
@@ -204,87 +241,45 @@ const ProductDesktopVariant = ({
<Image
src={product.image + '?variant=True'}
alt={product.name}
- className='h-[430px] object-contain object-center w-full border border-gray_r-4'
+ className='w-full h-[350px]'
/>
</div>
- <div className='w-7/12 px-4 py-4'>
+ <div className='w-7/12 px-6'>
<h1 className='text-title-md leading-10 font-medium'>
{product?.name}
</h1>
<div className='mt-10'>
- <div className='flex p-3'>
- <div className='w-4/12 text-gray_r-12/70'>Nomor SKU</div>
- <div className='w-8/12'>SKU-{product.id}</div>
- </div>
<div className='flex p-3 bg-gray_r-4'>
- <div className='w-4/12 text-gray_r-12/70'>Part Number</div>
- <div className='w-8/12'>{product.code || '-'}</div>
+ <div className='w-4/12 text-gray_r-12/70'>Item Code</div>
+ <div className='w-8/12'>{product.code}</div>
</div>
- <div className='flex p-3'>
+ <div className='flex p-3 items-center '>
<div className='w-4/12 text-gray_r-12/70'>Manufacture</div>
<div className='w-8/12'>
- {product.manufacture?.name ? (
- <Link
- href={createSlug(
- '/shop/brands/',
- product.manufacture?.name,
- product.manufacture?.id
- )}
- >
- {product.manufacture?.name}
- </Link>
- ) : (
- <div>-</div>
- )}
- </div>
- </div>
-
- <div className='flex p-3 items-center bg-gray_r-4'>
- <div className='w-4/12 text-gray_r-12/70'>
- Persiapan Barang
- </div>
- <div className='w-8/12'>
- {!product?.sla && <Skeleton width='20%' height='16px' />}
- {product?.sla && (
- <Tooltip
- placement='top'
- label={`Masa Persiapan Barang ${product?.sla?.slaDate}`}
- >
- <Box className='w-fit flex items-center gap-x-2'>
- {product?.sla?.slaDate}
- <Info size={16} />
- </Box>
- </Tooltip>
- )}
+ <Link
+ href={createSlug(
+ '/shop/brands/',
+ product.manufacture.name,
+ product.manufacture.id.toString()
+ )}
+ >
+ {product?.manufacture.logo ? (
+ <Image
+ width={100}
+ src={product.manufacture.logo}
+ alt={product.manufacture.name}
+ />
+ ) : (
+ <p className='font-bold text-red-500'>
+ {product.manufacture.name}
+ </p>
+ )}
+ </Link>
</div>
</div>
- <div className='flex p-3'>
- <div className='w-4/12 text-gray_r-12/70'>Stock</div>
- <div className='w-8/12'>
- {!product?.sla && <Skeleton width='10%' height='16px' />}
- {product?.sla?.qty > 0 && <span>{product?.sla?.qty}</span>}
- {product?.sla?.qty == 0 && (
- <a
- href={whatsappUrl('product', {
- name: product.name,
- manufacture: product?.manufacture?.name,
- url: createSlug(
- '/shop/product/',
- product.name,
- product.id,
- true
- ),
- })}
- className='text-danger-500 font-medium'
- >
- Tanya Admin
- </a>
- )}
- </div>
- </div>
- <div className='flex p-3 bg-gray_r-4'>
+ <div className='flex p-3 bg-gray_r-4 '>
<div className='w-4/12 text-gray_r-12/70'>Berat Barang</div>
<div className='w-8/12'>
{product?.weight > 0 && <span>{product?.weight} KG</span>}
@@ -306,58 +301,55 @@ const ProductDesktopVariant = ({
)}
</div>
</div>
- </div>
- <div className='h-6' />
- <div className='flex gap-x-5'>
- <Button
- as={Link}
- href={askAdminUrl}
- variant='link'
- target='_blank'
- colorScheme='gray'
- leftIcon={<MessageCircleIcon size={18} />}
- >
- Ask Admin
- </Button>
-
- <AddToWishlist productId={product.id} />
+ <div className='flex p-3 items-center '>
+ <div className='w-4/12 text-gray_r-12/70'>Terjual</div>
+ <div className='w-8/12'>-</div>
+ </div>
- <RWebShare
- data={{
- text: 'Check out this product',
- title: `${product.name} - Indoteknik.com`,
- url: SELF_HOST + router.asPath,
- }}
- >
- <Button
- variant='link'
- colorScheme='gray'
- leftIcon={<Share2Icon size={18} />}
- >
- Share
- </Button>
- </RWebShare>
+ <div className='flex p-3 items-center bg-gray_r-4 '>
+ <div className='w-4/12 text-gray_r-12/70'>
+ Persiapan Barang
+ </div>
+ <div className='w-8/12'>
+ {!product?.sla && <Skeleton width='20%' height='16px' />}
+ {product?.sla && (
+ <Tooltip
+ placement='top'
+ label={`Masa Persiapan Barang ${product?.sla?.slaDate}`}
+ >
+ <Box className='w-fit flex items-center gap-x-2'>
+ {product?.sla?.slaDate}
+ <Info size={16} />
+ </Box>
+ </Tooltip>
+ )}
+ </div>
+ </div>
</div>
</div>
- <div className='py-4 md:p-6 md:bg-gray-50 rounded-xl w-[99%]'>
- <h2 className='text-h-md md:text-h-lg font-medium'>
- Informasi Produk
- </h2>
- <div className='h-4' />
- <div
- className='leading-relaxed text-gray-700'
- dangerouslySetInnerHTML={{
- __html:
- !product.parent.description ||
- product.parent.description == '<p><br></p>'
- ? 'Belum ada deskripsi'
- : product.parent.description,
- }}
- />
+ <div className='p-4 md:p-6 w-full'>
+ <ProductPromoSection product={product} productId={product.id} />
+
+ <div className='p-4 md:p-6 md:bg-gray-50 rounded-xl'>
+ <h2 className='text-h-md md:text-h-lg font-medium'>
+ Informasi Produk
+ </h2>
+ <div className='h-4' />
+ <div
+ className='leading-relaxed text-gray-700'
+ dangerouslySetInnerHTML={{
+ __html:
+ !product.parent.description ||
+ product.parent.description == '<p><br></p>'
+ ? 'Belum ada deskripsi'
+ : product.parent.description,
+ }}
+ />
+ </div>
</div>
</div>
- <div className='w-[25%]'>
+ <div className='w-[33%]'>
{product?.isFlashsale > 0 &&
product?.price?.discountPercentage > 0 ? (
<>
@@ -415,27 +407,137 @@ const ProductDesktopVariant = ({
)}
</h3>
)}
- <div className='flex gap-x-3 mt-4'>
- <input
- type='number'
- className='form-input w-16 py-2 text-center bg-gray_r-1'
- ref={setVariantQuantityRef(product.id)}
- defaultValue={1}
- />
- <button
- type='button'
+ <div className='flex justify-between items-center py-5 px-3'>
+ <div className='relative flex items-center'>
+ <button
+ type='button'
+ className='absolute left-0 px-2 py-1 h-full text-gray-500'
+ onClick={() =>
+ setQuantityInput(
+ String(Math.max(1, Number(quantityInput) - 1))
+ )
+ }
+ >
+ -
+ </button>
+ <input
+ type='number'
+ id='quantity'
+ min={1}
+ value={quantityInput}
+ onChange={(e) => setQuantityInput(e.target.value)}
+ className=' w-24 h-10 text-center border border-gray-300 rounded focus:outline-none'
+ />
+ <button
+ type='button'
+ className='absolute right-0 px-2 py-1 h-full text-gray-500'
+ onClick={() =>
+ setQuantityInput(String(Number(quantityInput) + 1))
+ }
+ >
+ +
+ </button>
+ </div>
+ <div>
+ <Skeleton
+ isLoaded={!isLoadingSLA}
+ h='21px'
+ // w={16}
+ className={
+ product?.sla?.qty < 10 ? 'text-red-600 font-medium' : ''
+ }
+ >
+ Stock : {product?.sla?.qty}{' '}
+ </Skeleton>
+ </div>
+ <div>
+ {product?.sla?.qty > 0 && (
+ <Link href='/panduan-pick-up-service' className='group'>
+ <Image
+ src='/images/PICKUP-NOW.png'
+ className='group-hover:scale-105 transition-transform duration-200 w-28'
+ alt='pickup now'
+ />
+ </Link>
+ )}
+ </div>
+ </div>
+ <div className='flex gap-x-3'>
+ <Button
onClick={() => handleAddToCart(product.id)}
- className='flex-1 py-2 btn-yellow'
+ className='w-full'
+ colorScheme='yellow'
>
Keranjang
- </button>
- <button
- type='button'
+ </Button>
+ <Button
onClick={() => handleBuy(product.id)}
- className='flex-1 py-2 btn-solid-red'
+ className='w-full'
+ colorScheme='red'
>
Beli
- </button>
+ </Button>
+ </div>
+ <Button
+ onClick={() => handleButton(product.id)}
+ color={'red'}
+ colorScheme='white'
+ className='w-full border-2 p-2 gap-1 mt-2 hover:bg-slate-100 flex items-center'
+ >
+ <ImageNext
+ src='/images/writing.png'
+ alt='penawaran instan'
+ className=''
+ width={25}
+ height={25}
+ />
+ Penawaran Harga Instan
+ </Button>
+ <div className='flex py-5'>
+ <div className='flex gap-x-5 items-center justify-center'>
+ <Button
+ as={Link}
+ href={createdAskUrl}
+ variant='link'
+ target='_blank'
+ colorScheme='gray'
+ leftIcon={<MessageCircleIcon size={18} />}
+ >
+ Ask Admin
+ </Button>
+
+ <span>|</span>
+
+ <button
+ className='flex items-center gap-x-1'
+ onClick={toggleWishlist}
+ >
+ {wishlist.data?.productTotal > 0 ? (
+ <HeartIcon className='w-6 fill-danger-500 text-danger-500' />
+ ) : (
+ <HeartIcon className='w-6' />
+ )}
+ Wishlist
+ </button>
+
+ <span>|</span>
+
+ <RWebShare
+ data={{
+ text: 'Check out this product',
+ title: `${product.name} - Indoteknik.com`,
+ url: SELF_HOST + router.asPath,
+ }}
+ >
+ <Button
+ variant='link'
+ colorScheme='gray'
+ leftIcon={<Share2Icon size={18} />}
+ >
+ Share
+ </Button>
+ </RWebShare>
+ </div>
</div>
<div className='border border-gray_r-6 overflow-auto mt-4'>
<div className='font-medium text-center p-4 bg-gray_r-1 border-b border-gray_r-6 sticky top-0 z-10'>
diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx
index 790dbbe0..b87bcbc8 100644
--- a/src/lib/product/components/Product/ProductMobileVariant.jsx
+++ b/src/lib/product/components/Product/ProductMobileVariant.jsx
@@ -1,10 +1,10 @@
-import { Skeleton } from '@chakra-ui/react';
+import { Button, Skeleton } from '@chakra-ui/react';
import { HeartIcon } from '@heroicons/react/24/outline';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { toast } from 'react-hot-toast';
import LazyLoad from 'react-lazy-load';
-
+import ImageNext from 'next/image';
import odooApi from '@/core/api/odooApi';
import Divider from '@/core/components/elements/Divider/Divider';
import Image from '@/core/components/elements/Image/Image';
@@ -133,6 +133,20 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
router.push(`/shop/checkout?source=buy`);
};
+ const handleButton = (variant) => {
+ const quantity = quantityInput;
+ if (!validQuantity(quantity)) return;
+
+ updateItemCart({
+ productId: variant,
+ quantity,
+ programLineId: null,
+ selected: true,
+ source: 'buy',
+ });
+ router.push('/shop/quotation?source=buy');
+ };
+
const productSimilarQuery = [
product?.name,
`fq=-product_id_i:${product.id}`,
@@ -272,6 +286,21 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => {
Beli
</button>
</div>
+ <Button
+ onClick={() => handleButton(product.id)}
+ color={'red'}
+ colorScheme='white'
+ className='w-full border-2 p-2 gap-1 mt-2 hover:bg-slate-100 flex items-center'
+ >
+ <ImageNext
+ src='/images/writing.png'
+ alt='penawaran instan'
+ className=''
+ width={25}
+ height={25}
+ />
+ Penawaran Harga Instan
+ </Button>
</div>
<Divider />
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index a480bbdd..3e6a6913 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -148,7 +148,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
<div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'>
<div className='flex justify-between '>
{product?.manufacture?.name ? (
- <Link href={URL.manufacture} className='mb-1 mt-1'>
+ <Link href={URL.manufacture} className='mb-1 mt-1 truncate'>
{product.manufacture.name}
</Link>
) : (
diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index cf0ad41f..5a2f63a5 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -39,9 +39,12 @@ const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi');
const Quotation = () => {
const router = useRouter();
const auth = useAuth();
+ const query = router.query.source ?? null;
const { data: cartCheckout } = useQuery('cartCheckout', () =>
- getProductsCheckout()
+ getProductsCheckout({
+ source: query,
+ })
);
const { setRefreshCart } = useProductCartContext();
diff --git a/src/lib/shipment/components/Shipments.jsx b/src/lib/shipment/components/Shipments.jsx
index 115bbd3a..20dbb013 100644
--- a/src/lib/shipment/components/Shipments.jsx
+++ b/src/lib/shipment/components/Shipments.jsx
@@ -1,62 +1,83 @@
-import DesktopView from '@/core/components/views/DesktopView'
-import MobileView from '@/core/components/views/MobileView'
-import Menu from '@/lib/auth/components/Menu'
-import { EllipsisVerticalIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline'
-import ImageNext from 'next/image'
-import { useRouter } from 'next/router'
-import { useQuery } from 'react-query'
-import _, { forEach } from 'lodash-contrib'
-import Spinner from '@/core/components/elements/Spinner/Spinner'
-import Manifest from '@/lib/treckingAwb/component/Manifest'
-import { useState } from 'react'
-import Pagination from '@/core/components/elements/Pagination/Pagination'
-import Link from 'next/link'
-import TransactionStatusBadge from '@/lib/transaction/components/TransactionStatusBadge'
+import DesktopView from '@/core/components/views/DesktopView';
+import MobileView from '@/core/components/views/MobileView';
+import Menu from '@/lib/auth/components/Menu';
+import {
+ EllipsisVerticalIcon,
+ MagnifyingGlassIcon,
+} from '@heroicons/react/24/outline';
+import ImageNext from 'next/image';
+import { useEffect } from 'react';
+import { useRouter } from 'next/router';
+import { useQuery } from 'react-query';
+import _, { forEach } from 'lodash-contrib';
+import Spinner from '@/core/components/elements/Spinner/Spinner';
+import Manifest from '@/lib/treckingAwb/component/Manifest';
+import { useState } from 'react';
+import Pagination from '@/core/components/elements/Pagination/Pagination';
+import Link from 'next/link';
+import TransactionStatusBadge from '@/lib/transaction/components/TransactionStatusBadge';
-const { listShipments } = require('../api/listShipment')
+const { listShipments } = require('../api/listShipment');
const Shipments = () => {
- const router = useRouter()
- const { q = '', page = 1 } = router.query
- const [paramStatus, setParamStatus] = useState(null)
-
- const limit = 15
+ const router = useRouter();
+ const { q = '', page = 1, status = null } = router.query;
+ const [paramStatus, setParamStatus] = useState(status);
+ const limit = 15;
const query = {
q: q,
status: paramStatus,
offset: (page - 1) * limit,
- limit
- }
- const [inputQuery, setInputQuery] = useState(q)
- const queryString = _.toQuery(query)
+ limit,
+ };
+ const [inputQuery, setInputQuery] = useState(q);
+ const queryString = _.toQuery(query);
const { data: shipments } = useQuery('shipments' + queryString, () =>
listShipments({ query: queryString })
- )
- const [idAWB, setIdAWB] = useState(null)
+ );
+ const [idAWB, setIdAWB] = useState(null);
- const pageCount = Math.ceil(shipments?.pickingTotal / limit)
- let pageQuery = _.omit(query, ['limit', 'offset', 'context'])
- pageQuery = _.pickBy(pageQuery, _.identity)
- pageQuery = _.toQuery(pageQuery)
+ const pageCount = Math.ceil(shipments?.pickingTotal / limit);
+ let pageQuery = _.omit(query, ['limit', 'offset', 'context']);
+ pageQuery = _.pickBy(pageQuery, _.identity);
+ pageQuery = _.toQuery(pageQuery);
const closePopup = () => {
- setIdAWB(null)
- }
+ setIdAWB(null);
+ };
const handleSubmit = async (e) => {
- e.preventDefault()
- router.push(`${router.pathname}?q=${inputQuery}`)
- }
+ e.preventDefault();
+ router.push(`${router.pathname}?q=${inputQuery}`);
+ };
const filterStatus = async (status) => {
if (status === paramStatus) {
- setParamStatus(null)
+ setParamStatus(null);
} else {
- setParamStatus(status)
+ setParamStatus(status);
}
- }
+ };
+
+ useEffect(() => {
+ const resetQuery = () => {
+ const newQuery = {
+ status: paramStatus || undefined,
+ q: '',
+ page: 1,
+ };
+ router.push({
+ pathname: router.pathname,
+ query: newQuery,
+ });
+ };
+
+ if (paramStatus !== status) {
+ resetQuery();
+ }
+ }, [paramStatus]);
return (
<>
<MobileView>
@@ -84,7 +105,10 @@ const Shipments = () => {
</form>
{shipments?.pickings.map((shipment) => (
- <div className='p-4 shadow border border-gray_r-3 rounded-md' key={shipment.id}>
+ <div
+ className='p-4 shadow border border-gray_r-3 rounded-md'
+ key={shipment.id}
+ >
<div className='flex justify-between items-center mb-3'>
<div className='text-caption-2 text-gray_r-11'>
<p>
@@ -93,7 +117,9 @@ const Shipments = () => {
{shipment.carrierName || '-'}
</span>
</p>
- <p className='mt-2'>No. Resi : {shipment.trackingNumber || '-'}</p>
+ <p className='mt-2'>
+ No. Resi : {shipment.trackingNumber || '-'}
+ </p>
</div>
<div className='flex justify-between'>
{shipment?.status === 'completed' && (
@@ -116,11 +142,17 @@ const Shipments = () => {
<hr />
<div className='flex justify-between mt-2 items-center mb-5'>
<div>
- <span className='text-caption-2 text-gray_r-11'>No. Transaksi</span>
+ <span className='text-caption-2 text-gray_r-11'>
+ No. Transaksi
+ </span>
<Link href={`/my/transactions/${shipment.saleOrder.id}`}>
- <h2 className='text-danger-500 mt-1 mb-2'>{shipment.saleOrder.name}</h2>
+ <h2 className='text-danger-500 mt-1 mb-2'>
+ {shipment.saleOrder.name}
+ </h2>
</Link>
- <span className='text-caption-2 text-gray_r-11'>{shipment.date}</span>
+ <span className='text-caption-2 text-gray_r-11'>
+ {shipment.date}
+ </span>
</div>
<div>
<button
@@ -136,7 +168,11 @@ const Shipments = () => {
onClick={() => setIdAWB(shipment.id)}
className='flex items-center mt-1 gap-x-1 min-w-full'
>
- <ImageNext src={`/images/BOX_DELIVERY_GREEN.svg`} width={20} height={20} />
+ <ImageNext
+ src={`/images/BOX_DELIVERY_GREEN.svg`}
+ width={20}
+ height={20}
+ />
<p className='text-sm text-green-700 truncate'>
{shipment.lastManifest.description}
</p>
@@ -148,7 +184,7 @@ const Shipments = () => {
<Pagination
pageCount={pageCount}
currentPage={parseInt(page)}
- url={router.pathname + pageQuery}
+ url={`${router.pathname}${pageQuery ? '?' + pageQuery : ''}`}
className='mt-2 mb-2'
/>
</div>
@@ -176,7 +212,8 @@ const Shipments = () => {
<path d='M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z' />
</svg>
<div>
- Lacak pengiriman untuk setiap transaksi anda semakin mudah di Indoteknik.com
+ Lacak pengiriman untuk setiap transaksi anda semakin mudah di
+ Indoteknik.com
</div>
</div>
<div className='flex justify-between gap-x-5'>
@@ -190,7 +227,9 @@ const Shipments = () => {
</div>
<div className='p-4 bg-white border border-gray_r-6 rounded'>
<div className='flex mb-6 items-center justify-between'>
- <h1 className='text-title-sm font-semibold'>Detail Pengiriman</h1>
+ <h1 className='text-title-sm font-semibold'>
+ Detail Pengiriman
+ </h1>
<form className='flex gap-x-2' onSubmit={handleSubmit}>
<input
type='text'
@@ -199,7 +238,10 @@ const Shipments = () => {
value={inputQuery}
onChange={(e) => setInputQuery(e.target.value)}
/>
- <button className='btn-light bg-transparent px-3' type='submit'>
+ <button
+ className='btn-light bg-transparent px-3'
+ type='submit'
+ >
<MagnifyingGlassIcon className='w-6' />
</button>
</form>
@@ -254,7 +296,7 @@ const Shipments = () => {
<Pagination
pageCount={pageCount}
currentPage={parseInt(page)}
- url={router.pathname + pageQuery}
+ url={`${router.pathname}${pageQuery ? '?' + pageQuery : ''}`}
className='mt-2 mb-2'
/>
</div>
@@ -263,16 +305,16 @@ const Shipments = () => {
<Manifest idAWB={idAWB} closePopup={closePopup} />
</DesktopView>
</>
- )
-}
+ );
+};
const CardStatus = ({ device, paramStatus, shipments, filterStatus }) => {
- const status = [`pending`, `shipment`, `completed`]
+ const status = [`pending`, `shipment`, `completed`];
return (
<>
{status.map((value) => {
- const statusData = getStatusLabel(device, value, shipments)
+ const statusData = getStatusLabel(device, value, shipments);
if (device === 'desktop') {
return (
<div
@@ -282,13 +324,15 @@ const CardStatus = ({ device, paramStatus, shipments, filterStatus }) => {
}`}
onClick={() => filterStatus(value)}
>
- <h2 className='mb-2 text-lg font-bold tracking-tight'>{statusData.label}</h2>
+ <h2 className='mb-2 text-lg font-bold tracking-tight'>
+ {statusData.label}
+ </h2>
{statusData.image}
<h1 className='text-xl font-bold'>
{statusData.shipCount} <span className='text-sm'>Pesanan</span>
</h1>
</div>
- )
+ );
} else {
return (
<div
@@ -305,15 +349,15 @@ const CardStatus = ({ device, paramStatus, shipments, filterStatus }) => {
<span className='truncate'>{statusData.shipCount}</span> {'>'}
</h1>
</div>
- )
+ );
}
})}
</>
- )
-}
+ );
+};
const getStatusLabel = (device, status, shipments) => {
- let images = null
+ let images = null;
switch (status) {
case 'pending':
if (device === 'desktop') {
@@ -328,40 +372,48 @@ const getStatusLabel = (device, status, shipments) => {
/>
</div>
</div>
- )
+ );
} else {
images = (
<div>
<ImageNext src='/images/BOX(1).svg' width={15} height={20} />
</div>
- )
+ );
}
return {
label: 'Pending',
shipCount: shipments?.summary?.pendingCount,
- image: images
- }
+ image: images,
+ };
case 'shipment':
if (device === 'desktop') {
images = (
<div className='bg-yellow-100 border border-yellow-200 rounded-sm p-1 w-20 mb-2'>
<div>
- <ImageNext src='/images/BOX_DELIVER_(1).svg' width={30} height={20} />
+ <ImageNext
+ src='/images/BOX_DELIVER_(1).svg'
+ width={30}
+ height={20}
+ />
</div>
</div>
- )
+ );
} else {
images = (
<div>
- <ImageNext src='/images/BOX_DELIVER_(1).svg' width={18} height={20} />
+ <ImageNext
+ src='/images/BOX_DELIVER_(1).svg'
+ width={18}
+ height={20}
+ />
</div>
- )
+ );
}
return {
label: 'Pengiriman',
shipCount: shipments?.summary?.shipmentCount,
- image: images
- }
+ image: images,
+ };
case 'completed':
if (device === 'desktop') {
images = (
@@ -375,22 +427,22 @@ const getStatusLabel = (device, status, shipments) => {
/>
</div>
</div>
- )
+ );
} else {
images = (
<div>
<ImageNext src='/images/open-box(1).svg' width={16} height={20} />
</div>
- )
+ );
}
return {
label: 'Pesanan Tiba',
shipCount: shipments?.summary?.completedCount,
- image: images
- }
+ image: images,
+ };
default:
- return 'Status Tidak Dikenal'
+ return 'Status Tidak Dikenal';
}
-}
+};
-export default Shipments
+export default Shipments;
diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx
index 4d401037..d001c7f4 100644
--- a/src/lib/transaction/components/Transaction.jsx
+++ b/src/lib/transaction/components/Transaction.jsx
@@ -778,6 +778,10 @@ const Transaction = ({ id }) => {
? `| ${product?.attributes.join(', ')}`
: ''}
</div>
+ <div className='text-[10px] text-red-500 italic mt-2'>
+ {product.availableQuantity} barang ini bisa di
+ pickup maksimal pukul 16.00
+ </div>
</div>
</td>
{/* <td>
@@ -879,7 +883,7 @@ const Transaction = ({ id }) => {
</div>
</div>
</div>
- )}
+ )}
{transaction?.data?.productsRejectLine.length > 0 && (
<div className='text-h-sm font-semibold mt-10 mb-4'>
diff --git a/src/lib/variant/components/VariantCard.jsx b/src/lib/variant/components/VariantCard.jsx
index 68cdf54f..08b7a97e 100644
--- a/src/lib/variant/components/VariantCard.jsx
+++ b/src/lib/variant/components/VariantCard.jsx
@@ -103,30 +103,42 @@ const VariantCard = ({ product, openOnClick = true, buyMore = false }) => {
</div>
</div>
</div>
-
</div>
<div className='w-8/12 flex flex-col'>
- <p className='product-card__title wrap-line-ellipsis-2'>{product.parent.name}</p>
+ <p className='product-card__title wrap-line-ellipsis-2'>
+ {product.parent.name}
+ </p>
<p className='text-caption-2 text-gray_r-11 mt-1'>
{product.code || '-'}
- {product.attributes.length > 0 ? ` ・ ${product.attributes.join(', ')}` : ''}
+ {product.attributes.length > 0
+ ? ` ・ ${product.attributes.join(', ')}`
+ : ''}
</p>
<p className='text-caption-2 text-gray_r-11 mt-1'>
Berat Item : {product?.weight} Kg x {product?.quantity} Barang
</p>
+ <p className='text-[10px] text-red-500 italic mt-2'>
+ {product.availableQuantity} barang ini bisa di pickup maksimal pukul
+ 16.00
+ </p>
<div className='flex flex-wrap gap-x-1 items-center mt-auto'>
{product.hasFlashsale && (
<>
<p className='text-caption-2 text-gray_r-11 line-through'>
{currencyFormat(product.price.price)}
</p>
- <span className='badge-red'>{product.price.discountPercentage}%</span>
+ <span className='badge-red'>
+ {product.price.discountPercentage}%
+ </span>
</>
)}
</div>
<p className='text-caption-2 text-gray_r-11 mt-1'>
{product.price.priceDiscount > 0
- ? currencyFormat(product.price.priceDiscount) + ' × ' + product.quantity + ' Barang'
+ ? currencyFormat(product.price.priceDiscount) +
+ ' × ' +
+ product.quantity +
+ ' Barang'
: ''}
</p>
<p className='text-caption-2 text-gray_r-12 font-bold mt-2'>