diff options
| -rw-r--r-- | src/core/components/layouts/AnimationLayout.jsx | 2 | ||||
| -rw-r--r-- | src/lib/quotation/components/Quotation.jsx | 167 | ||||
| -rw-r--r-- | src/pages/shop/quotation/finish.jsx | 41 | ||||
| -rw-r--r-- | src/pages/shop/quotation/index.jsx | 10 |
4 files changed, 219 insertions, 1 deletions
diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index 357187b2..c4dee606 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -3,7 +3,7 @@ import { motion } from 'framer-motion' const AnimationLayout = ({ children, ...props }) => { const transition = { ease: 'easeIn', - duration: 0.3 + duration: 0.2 } return ( diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx new file mode 100644 index 00000000..b6e276a3 --- /dev/null +++ b/src/lib/quotation/components/Quotation.jsx @@ -0,0 +1,167 @@ +import Alert from '@/core/components/elements/Alert/Alert' +import Divider from '@/core/components/elements/Divider/Divider' +import Link from '@/core/components/elements/Link/Link' +import useAuth from '@/core/hooks/useAuth' +import CartApi from '@/lib/cart/api/CartApi' +import { ExclamationCircleIcon } from '@heroicons/react/24/outline' +import { useEffect, useState } from 'react' +import _ from 'lodash' +import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart' +import currencyFormat from '@/core/utils/currencyFormat' +import { toast } from 'react-hot-toast' +import checkoutApi from '@/lib/checkout/api/checkoutApi' +import { useRouter } from 'next/router' +import VariantGroupCard from '@/lib/variant/components/VariantGroupCard' + +const Quotation = () => { + const router = useRouter() + const auth = useAuth() + + const [products, setProducts] = useState(null) + const [totalAmount, setTotalAmount] = useState(0) + const [totalDiscountAmount, setTotalDiscountAmount] = useState(0) + + useEffect(() => { + const loadProducts = async () => { + const cart = getCart() + const variantIds = _.filter(cart, (o) => o.selected == true) + .map((o) => o.productId) + .join(',') + const dataProducts = await CartApi({ variantIds }) + const dataProductsQuantity = _.map(dataProducts, (o) => ({ + ...o, + quantity: getItemCart({ productId: o.id }).quantity + })) + setProducts(dataProductsQuantity) + } + loadProducts() + }, []) + + useEffect(() => { + if (products) { + let calculateTotalAmount = 0 + let calculateTotalDiscountAmount = 0 + products.forEach((product) => { + calculateTotalAmount += product.price.price * product.quantity + calculateTotalDiscountAmount += + (product.price.price - product.price.priceDiscount) * product.quantity + }) + setTotalAmount(calculateTotalAmount) + setTotalDiscountAmount(calculateTotalDiscountAmount) + } + }, [products]) + + const [isLoading, setIsLoading] = useState(false) + + const checkout = async () => { + if (!products || products.length == 0) return + setIsLoading(true) + const productOrder = products.map((product) => ({ + product_id: product.id, + quantity: product.quantity + })) + let data = { + partner_shipping_id: auth.partnerId, + partner_invoice_id: auth.partnerId, + order_line: JSON.stringify(productOrder) + } + const isSuccess = await checkoutApi({ data }) + setIsLoading(false) + if (isSuccess?.id) { + for (const product of products) deleteItemCart({ productId: product.id }) + router.push(`/shop/quotation/finish?id=${isSuccess.id}`) + return + } + toast.error('Gagal melakukan transaksi, terjadi kesalahan internal') + } + + return ( + <> + <div className='p-4'> + <Alert + type='info' + className='text-caption-2 flex gap-x-3' + > + <div> + <ExclamationCircleIcon className='w-7 text-blue-700' /> + </div> + <span className='leading-5'> + Jika mengalami kesulitan dalam melakukan pembelian di website Indoteknik. Hubungi kami + disini + </span> + </Alert> + </div> + + <Divider /> + + <div className='p-4 flex flex-col gap-y-4'> + {products && ( + <VariantGroupCard + openOnClick={false} + variants={products} + /> + )} + </div> + + <Divider /> + + <div className='p-4'> + <div className='flex justify-between items-center'> + <div className='font-medium'>Ringkasan Penawaran</div> + <div className='text-gray_r-11 text-caption-1'>{products?.length} Barang</div> + </div> + <hr className='my-4 border-gray_r-6' /> + <div className='flex flex-col gap-y-4'> + <div className='flex gap-x-2 justify-between'> + <div className='text-gray_r-11'>Total Belanja</div> + <div>{currencyFormat(totalAmount)}</div> + </div> + <div className='flex gap-x-2 justify-between'> + <div className='text-gray_r-11'>Total Diskon</div> + <div className='text-red_r-11'>- {currencyFormat(totalDiscountAmount)}</div> + </div> + <div className='flex gap-x-2 justify-between'> + <div className='text-gray_r-11'>Subtotal</div> + <div>{currencyFormat(totalAmount - totalDiscountAmount)}</div> + </div> + <div className='flex gap-x-2 justify-between'> + <div className='text-gray_r-11'>PPN 11% (Incl.)</div> + <div>{currencyFormat((totalAmount - totalDiscountAmount) * 0.11)}</div> + </div> + </div> + <hr className='my-4 border-gray_r-6' /> + <div className='flex gap-x-2 justify-between mb-4'> + <div>Grand Total</div> + <div className='font-semibold text-gray_r-12'> + {currencyFormat(totalAmount - totalDiscountAmount)} + </div> + </div> + <p className='text-caption-2 text-gray_r-10 mb-2'>*) Belum termasuk biaya pengiriman</p> + <p className='text-caption-2 text-gray_r-10 leading-5'> + Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '} + <Link + href='/' + className='inline font-normal' + > + Syarat & Ketentuan + </Link>{' '} + yang berlaku + </p> + </div> + + <Divider /> + + <div className='flex gap-x-3 p-4'> + <button + className='flex-1 btn-yellow' + onClick={checkout} + disabled={isLoading} + > + {isLoading ? 'Loading...' : 'Quotation'} + </button> + </div> + </> + ) +} + +export default Quotation diff --git a/src/pages/shop/quotation/finish.jsx b/src/pages/shop/quotation/finish.jsx new file mode 100644 index 00000000..98ffeec2 --- /dev/null +++ b/src/pages/shop/quotation/finish.jsx @@ -0,0 +1,41 @@ +import Link from '@/core/components/elements/Link/Link' +import BasicLayout from '@/core/components/layouts/BasicLayout' +import useAuth from '@/core/hooks/useAuth' +import { EnvelopeIcon } from '@heroicons/react/24/outline' +import { useRouter } from 'next/router' + +export default function FinishQuotation() { + const auth = useAuth() + const router = useRouter() + const { id } = router.query + return ( + <BasicLayout> + <div className='m-4 px-4 py-6 shadow-md border border-gray_r-3'> + <div className='flex'> + <span className='p-3 mx-auto bg-yellow_r-3 border border-yellow_r-6 rounded'> + <EnvelopeIcon className='w-8 text-yellow_r-11' /> + </span> + </div> + <p className='h2 text-center mt-6'>Terima Kasih {auth?.name}</p> + <p className='text-center mt-3 leading-6 text-gray_r-11'> + Penawaran harga kamu di Indoteknik.com berhasil dikirimkan, tim kami akan segera menghubungi + anda. + </p> + {id && ( + <Link + href={`/my/transaction/${id}`} + className='btn-yellow !text-gray_r-12 mt-6 w-full' + > + Lihat Penawaran + </Link> + )} + <Link + href='/' + className='btn-light !text-gray_r-12 mt-2 w-full' + > + Ke Halaman Utama + </Link> + </div> + </BasicLayout> + ) +} diff --git a/src/pages/shop/quotation/index.jsx b/src/pages/shop/quotation/index.jsx new file mode 100644 index 00000000..744b75fe --- /dev/null +++ b/src/pages/shop/quotation/index.jsx @@ -0,0 +1,10 @@ +import AppLayout from '@/core/components/layouts/AppLayout' +import QuotationComponent from '@/lib/quotation/components/Quotation' + +export default function Quotation() { + return ( + <AppLayout title='Quotation'> + <QuotationComponent /> + </AppLayout> + ) +} |
