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.jsx323
-rw-r--r--src/lib/checkout/components/FinishCheckout.jsx30
2 files changed, 353 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..f6170b13
--- /dev/null
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -0,0 +1,323 @@
+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 { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart'
+import currencyFormat from '@/core/utils/currencyFormat'
+import { toast } from 'react-hot-toast'
+import getFileBase64 from '@/core/utils/getFileBase64'
+import checkoutApi from '../api/checkoutApi'
+import { useRouter } from 'next/router'
+import VariantGroupCard from '@/lib/variant/components/VariantGroupCard'
+
+const Checkout = () => {
+ const router = useRouter()
+ 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
+ }
+ const file = poFile.current.files[0]
+ if (typeof file !== 'undefined' && file.size > 5000000) {
+ toast.error('Maksimal ukuran file adalah 5MB', { position: 'bottom-center' })
+ return
+ }
+ setIsLoading(true)
+ const productOrder = products.map((product) => ({
+ product_id: product.id,
+ quantity: product.quantity
+ }))
+ let data = {
+ partner_shipping_id: selectedAddress.shipping.id,
+ partner_invoice_id: selectedAddress.invoicing.id,
+ order_line: JSON.stringify(productOrder),
+ type: 'sale_order'
+ }
+ if (poNumber.current.value) data.po_number = poNumber.current.value
+ if (typeof file !== 'undefined') data.po_file = await getFileBase64(file)
+
+ const isCheckouted = await checkoutApi({ data })
+ setIsLoading(false)
+ if (isCheckouted?.id) {
+ for (const product of products) deleteItemCart({ productId: product.id })
+ router.push(`/shop/checkout/finish?id=${isCheckouted.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 />
+
+ <SectionAddress
+ label='Alamat Pengiriman'
+ url='/my/address?select=shipping'
+ address={selectedAddress.shipping}
+ />
+
+ <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 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...' : '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
diff --git a/src/lib/checkout/components/FinishCheckout.jsx b/src/lib/checkout/components/FinishCheckout.jsx
new file mode 100644
index 00000000..a7d65dd0
--- /dev/null
+++ b/src/lib/checkout/components/FinishCheckout.jsx
@@ -0,0 +1,30 @@
+import Link from '@/core/components/elements/Link/Link'
+import useTransaction from '@/lib/transaction/hooks/useTransaction'
+
+const FinishCheckout = ({ id }) => {
+ const { transaction } = useTransaction({ id })
+
+ return (
+ <div className='p-4'>
+ <div className='rounded-xl bg-yellow_r-4 text-center border border-yellow_r-7'>
+ <div className='px-4 py-6 text-yellow_r-12'>
+ <p className='font-semibold mb-2'>Terima Kasih atas Pembelian Anda</p>
+ <p className='text-yellow_r-11 mb-4 leading-6'>
+ Rincian belanja sudah kami kirimkan ke email anda. Mohon dicek kembali. jika tidak
+ menerima email, anda dapat menghubungi kami disini.
+ </p>
+ <p className='mb-2 font-medium'>{transaction.data?.name}</p>
+ <p className='text-caption-2 text-yellow_r-11'>No. Transaksi</p>
+ </div>
+ <Link
+ href={transaction.data?.id ? `/my/transaction/${transaction.data.id}` : '/'}
+ className='bg-yellow_r-6 text-yellow_r-12 rounded-b-xl py-4 block'
+ >
+ Lihat detail pembelian Anda disini
+ </Link>
+ </div>
+ </div>
+ )
+}
+
+export default FinishCheckout