summaryrefslogtreecommitdiff
path: root/src/lib/checkout/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/checkout/components')
-rw-r--r--src/lib/checkout/components/Checkout.jsx272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
new file mode 100644
index 00000000..0a3949c3
--- /dev/null
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -0,0 +1,272 @@
+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 { getItemAddress } from '@/core/utils/address'
+import addressesApi from '@/lib/address/api/addressesApi'
+import CartApi from '@/lib/cart/api/CartApi'
+import VariantCard from '@/lib/variant/components/VariantCard'
+import { ExclamationCircleIcon } from '@heroicons/react/24/outline'
+import { useEffect, useRef, useState } from 'react'
+import _ from 'lodash'
+import { getCart, getItemCart } from '@/core/utils/cart'
+import currencyFormat from '@/core/utils/currencyFormat'
+import { toast } from 'react-hot-toast'
+
+const Checkout = () => {
+ const auth = useAuth()
+ const [selectedAddress, setSelectedAddress] = useState({
+ shipping: null,
+ invoicing: null
+ })
+ const [addresses, setAddresses] = useState(null)
+
+ useEffect(() => {
+ if (!auth) return
+
+ const getAddresses = async () => {
+ const dataAddresses = await addressesApi()
+ setAddresses(dataAddresses)
+ }
+
+ getAddresses()
+ }, [auth])
+
+ useEffect(() => {
+ if (!addresses) return
+
+ const matchAddress = (key) => {
+ const addressToMatch = getItemAddress(key)
+ const foundAddress = addresses.filter((address) => address.id == addressToMatch)
+ if (foundAddress.length > 0) {
+ return foundAddress[0]
+ }
+ return addresses[0]
+ }
+
+ setSelectedAddress({
+ shipping: matchAddress('shipping'),
+ invoicing: matchAddress('invoicing')
+ })
+ }, [addresses])
+
+ 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 [selectedPayment, setSelectedPayment] = useState(null)
+
+ const poNumber = useRef('')
+ const poFile = useRef('')
+
+ const [isLoading, setIsLoading] = useState(false)
+
+ const checkout = async () => {
+ if (!selectedPayment) {
+ toast.error('Pilih metode pembayaran', { position: 'bottom-center' })
+ return
+ }
+ }
+
+ 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 />
+
+ <SectionAddress
+ label='Alamat Pengiriman'
+ url='/my/address?select=shipping'
+ address={selectedAddress.shipping}
+ />
+
+ <Divider />
+
+ <div className='p-4 flex flex-col gap-y-4'>
+ {products?.map((product) => (
+ <VariantCard product={product} openOnClick={false} key={product.id} />
+ ))}
+ </div>
+
+ <Divider />
+
+ <div className='p-4'>
+ <div className='flex justify-between items-center'>
+ <div className='font-medium'>Ringkasan Pesanan</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 />
+
+ <SectionAddress
+ label='Alamat Penagihan'
+ url='/my/address?select=invoicing'
+ address={selectedAddress.invoicing}
+ />
+
+ <Divider />
+
+ <div className='p-4'>
+ <div className='font-medium'>
+ Metode Pembayaran <span className='font-normal text-gray_r-11'>(Wajib dipilih)</span>
+ </div>
+ <div className='grid gap-y-3 mt-4'>
+ {payments.map((payment, index) => (
+ <button
+ type='button'
+ className={
+ 'text-left border border-gray_r-6 rounded-md p-3 ' +
+ (selectedPayment == payment.name && 'border-yellow_r-10 bg-yellow_r-3')
+ }
+ onClick={() => setSelectedPayment(payment.name)}
+ key={index}
+ >
+ <p>
+ {payment.name} - {payment.number}
+ </p>
+ <p className='mt-1 text-gray_r-11'>PT. Indoteknik Dotcom Gemilang</p>
+ </button>
+ ))}
+ </div>
+ </div>
+
+ <Divider />
+
+ <div className='p-4'>
+ <div className='font-medium'>Purchase Order</div>
+
+ <div className='mt-4 flex gap-x-3'>
+ <div className='w-6/12'>
+ <label className='form-label font-normal'>Dokumen PO</label>
+ <input
+ type='file'
+ className='form-input mt-2 h-12'
+ accept='image/*,application/pdf'
+ ref={poFile}
+ />
+ </div>
+ <div className='w-6/12'>
+ <label className='form-label font-normal'>Nomor PO</label>
+ <input type='text' className='form-input mt-2 h-12' ref={poNumber} />
+ </div>
+ </div>
+ <p className='text-caption-2 text-gray_r-11 mt-2'>Ukuran dokumen PO Maksimal 5MB</p>
+ </div>
+
+ <Divider />
+
+ <div className='flex gap-x-3 p-4'>
+ <button className='flex-1 btn-yellow' onClick={checkout} disabled={isLoading}>
+ {isLoading && 'Loading...'}
+ {!isLoading && 'Bayar'}
+ </button>
+ </div>
+ </>
+ )
+}
+
+const payments = [
+ { name: 'BCA', number: '8870-4000-81' },
+ { name: 'MANDIRI', number: '155-0067-6869-75' }
+]
+
+const SectionAddress = ({ address, label, url }) => (
+ <div className='p-4'>
+ <div className='flex justify-between items-center'>
+ <div className='font-medium'>{label}</div>
+ <Link className='text-caption-1' href={url}>
+ Pilih Alamat Lain
+ </Link>
+ </div>
+
+ {address && (
+ <div className='mt-4 text-caption-1'>
+ <div className='badge-red mb-2'>
+ {address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'}
+ </div>
+ <p className='font-medium'>{address.name}</p>
+ <p className='mt-2 text-gray_r-11'>{address.mobile}</p>
+ <p className='mt-1 text-gray_r-11'>
+ {address.street}, {address?.city?.name}
+ </p>
+ </div>
+ )}
+ </div>
+)
+
+export default Checkout