summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/components/elements/Footer/BasicFooter.jsx88
-rw-r--r--src/core/components/elements/Popup/BottomPopup.jsx55
-rw-r--r--src/lib/cart/components/Cart.jsx218
-rw-r--r--src/lib/checkout/components/Checkout.jsx449
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx2
-rw-r--r--src/lib/quotation/components/Quotation.jsx273
-rw-r--r--src/pages/shop/checkout/index.jsx17
-rw-r--r--src/pages/shop/quotation/index.jsx17
-rw-r--r--src/styles/globals.css38
9 files changed, 847 insertions, 310 deletions
diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx
index 8819b87b..25f8f552 100644
--- a/src/core/components/elements/Footer/BasicFooter.jsx
+++ b/src/core/components/elements/Footer/BasicFooter.jsx
@@ -7,36 +7,70 @@ import {
} from '@heroicons/react/24/outline'
import Link from '../Link/Link'
import MobileView from '../../views/MobileView'
+import DesktopView from '../../views/DesktopView'
const BasicFooter = () => {
return (
- <MobileView>
- <footer className='flex flex-wrap p-4 bg-gray_r-3 text-caption-1'>
- <div className='w-1/2 flex flex-col gap-y-4 pr-1.5'>
- <div>
- <NextImage src={IndoteknikLogo} alt='Logo Indoteknik' width={90} height={30} />
+ <>
+ <MobileView>
+ <footer className='flex flex-wrap p-4 bg-gray_r-3 text-caption-1'>
+ <div className='w-1/2 flex flex-col gap-y-4 pr-1.5'>
+ <div>
+ <NextImage src={IndoteknikLogo} alt='Logo Indoteknik' width={90} height={30} />
+
+ <div className='font-semibold mt-2'>PT. Indoteknik Dotcom Gemilang</div>
+ </div>
+
+ <OfficeLocation />
+ <WarehouseLocation />
+ <InformationCenter />
+ <OpenHours />
+ <SocialMedias />
+ </div>
- <div className='font-semibold mt-2'>PT. Indoteknik Dotcom Gemilang</div>
+ <div className='w-1/2 flex flex-col gap-y-4 pl-1.5'>
+ <AboutUs />
+ <CustomerGuide />
+ <Payments />
</div>
- <OfficeLocation />
- <WarehouseLocation />
- <InformationCenter />
- <OpenHours />
- <SocialMedias />
- </div>
-
- <div className='w-1/2 flex flex-col gap-y-4 pl-1.5'>
- <AboutUs />
- <CustomerGuide />
- <Payments />
- </div>
-
- <div className='w-full mt-4 leading-5 text-caption-2 text-gray_r-12/80'>
- Copyright © 2007 - 2022, PT. Indoteknik Dotcom Gemilang
- </div>
- </footer>
- </MobileView>
+ <div className='w-full mt-4 leading-5 text-caption-2 text-gray_r-12/80'>
+ Copyright © 2007 - {new Date().getFullYear()}, PT. Indoteknik Dotcom Gemilang
+ </div>
+ </footer>
+ </MobileView>
+
+ <DesktopView>
+ <footer className='bg-gray_r-3 py-6'>
+ <div className='container mx-auto flex flex-wrap justify-between'>
+ <div className='w-3/12'>
+ <NextImage src={IndoteknikLogo} alt='Logo Indoteknik' width={180} height={60} />
+ <div className='font-semibold mt-2 mb-4'>PT. Indoteknik Dotcom Gemilang</div>
+ <InformationCenter />
+ </div>
+ <CustomerGuide />
+ <AboutUs />
+ <div className='w-3/12'>
+ <div className='grid grid-cols-1 gap-y-4'>
+ <OfficeLocation />
+ <WarehouseLocation />
+ <OpenHours />
+ <Payments />
+ </div>
+ </div>
+ <hr className='w-full my-4 border-gray_r-7' />
+ <div className='w-full flex justify-between items-center'>
+ <div className='text-caption-1'>
+ Copyright © 2007 - {new Date().getFullYear()}, PT. Indoteknik Dotcom Gemilang
+ </div>
+ <div>
+ <SocialMedias />
+ </div>
+ </div>
+ </div>
+ </footer>
+ </DesktopView>
+ </>
)
}
@@ -154,11 +188,11 @@ const OpenHours = () => (
<div>
<div className={headerClassName}>Jam Operasional</div>
<ul className='flex flex-col gap-y-1'>
- <li>
+ <li className='block md:flex md:gap-x-2'>
<div className='text-gray_r-12'>Senin - Jumat:</div>
<div className='text-gray_r-12/80'>08:30 - 17:00</div>
</li>
- <li>
+ <li className='block md:flex md:gap-x-2'>
<div className='text-gray_r-12'>Sabtu:</div>
<div className='text-gray_r-12/80'>08:30 - 14:00</div>
</li>
@@ -168,7 +202,7 @@ const OpenHours = () => (
const SocialMedias = () => (
<div>
- <div className={headerClassName}>Temukan Kami</div>
+ <div className={headerClassName + 'block md:hidden'}>Temukan Kami</div>
<div className='flex flex-wrap gap-2'>
<NextImage src='/images/socials/Whatsapp.png' alt='Whatsapp Logo' width={24} height={24} />
<NextImage src='/images/socials/Facebook.png' alt='Facebook Logo' width={24} height={24} />
diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx
index 24366802..95c75473 100644
--- a/src/core/components/elements/Popup/BottomPopup.jsx
+++ b/src/core/components/elements/Popup/BottomPopup.jsx
@@ -1,6 +1,8 @@
import { XMarkIcon } from '@heroicons/react/24/outline'
import { AnimatePresence, motion } from 'framer-motion'
import { useEffect } from 'react'
+import MobileView from '../../views/MobileView'
+import DesktopView from '../../views/DesktopView'
const transition = { ease: 'linear', duration: 0.2 }
@@ -26,24 +28,41 @@ const BottomPopup = ({ children, active = false, title, close }) => {
transition={transition}
onClick={close}
/>
- <motion.div
- initial={{ bottom: '-100%' }}
- animate={{ bottom: 0 }}
- exit={{ bottom: '-100%' }}
- transition={transition}
- className='fixed left-0 w-full border-t border-gray_r-6 rounded-t-xl z-[60] p-4 pt-0 bg-white'
- >
- <div className='flex justify-between py-4'>
- <div className='font-semibold text-h-sm'>{title}</div>
- <button
- type='button'
- onClick={close}
- >
- <XMarkIcon className='w-5 stroke-2' />
- </button>
- </div>
- {children}
- </motion.div>
+ <MobileView>
+ <motion.div
+ initial={{ bottom: '-100%' }}
+ animate={{ bottom: 0 }}
+ exit={{ bottom: '-100%' }}
+ transition={transition}
+ className='fixed left-0 w-full border-t border-gray_r-6 rounded-t-xl z-[60] p-4 pt-0 bg-white'
+ >
+ <div className='flex justify-between py-4'>
+ <div className='font-semibold text-h-sm'>{title}</div>
+ <button type='button' onClick={close}>
+ <XMarkIcon className='w-5 stroke-2' />
+ </button>
+ </div>
+ {children}
+ </motion.div>
+ </MobileView>
+
+ <DesktopView>
+ <motion.div
+ initial={{ bottom: '35%', opacity: 0 }}
+ animate={{ bottom: '50%', opacity: 1 }}
+ exit={{ bottom: '35%', opacity: 0 }}
+ transition={transition}
+ className='fixed left-1/2 -translate-x-1/2 w-2/5 border border-gray_r-6 rounded-xl z-[60] p-4 pt-0 bg-white'
+ >
+ <div className='flex justify-between py-4'>
+ <div className='font-semibold text-h-sm'>{title}</div>
+ <button type='button' onClick={close}>
+ <XMarkIcon className='w-5 stroke-2' />
+ </button>
+ </div>
+ {children}
+ </motion.div>
+ </DesktopView>
</>
)}
</AnimatePresence>
diff --git a/src/lib/cart/components/Cart.jsx b/src/lib/cart/components/Cart.jsx
index b48b41fc..8bd9e362 100644
--- a/src/lib/cart/components/Cart.jsx
+++ b/src/lib/cart/components/Cart.jsx
@@ -1,6 +1,7 @@
import Link from '@/core/components/elements/Link/Link'
import useCart from '../hooks/useCart'
import Image from '@/core/components/elements/Image/Image'
+import NextImage from 'next/image'
import currencyFormat from '@/core/utils/currencyFormat'
import { useEffect, useState } from 'react'
import { deleteItemCart, getItemCart, updateItemCart } from '@/core/utils/cart'
@@ -118,6 +119,33 @@ const Cart = () => {
return (
<>
+ <BottomPopup
+ active={deleteConfirmation}
+ close={() => setDeleteConfirmation(null)}
+ title='Hapus dari Keranjang'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Apakah anda yakin menghapus barang{' '}
+ <span className='underline'>{deleteConfirmation?.name}</span> dari keranjang?
+ </div>
+ <div className='flex mt-6 gap-x-4'>
+ <button
+ className='btn-solid-red flex-1'
+ type='button'
+ onClick={() => deleteProduct(deleteConfirmation?.id)}
+ >
+ Ya, Hapus
+ </button>
+ <button
+ className='btn-light flex-1'
+ type='button'
+ onClick={() => setDeleteConfirmation(null)}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+
<MobileView>
<div className='pt-4'>
<div className='flex justify-between mb-4 px-4'>
@@ -255,41 +283,169 @@ const Cart = () => {
</div>
</div>
</div>
-
- <BottomPopup
- active={deleteConfirmation}
- close={() => setDeleteConfirmation(null)}
- title='Hapus dari Keranjang'
- >
- <div className='leading-7 text-gray_r-12/80'>
- Apakah anda yakin menghapus barang{' '}
- <span className='underline'>{deleteConfirmation?.name}</span> dari keranjang?
- </div>
- <div className='flex mt-6 gap-x-4'>
- <button
- className='btn-solid-red flex-1'
- type='button'
- onClick={() => deleteProduct(deleteConfirmation?.id)}
- >
- Ya, Hapus
- </button>
- <button
- className='btn-light flex-1'
- type='button'
- onClick={() => setDeleteConfirmation(null)}
- >
- Batal
- </button>
- </div>
- </BottomPopup>
</div>
</MobileView>
<DesktopView>
- <div className='container mx-auto pt-10'>
- <div className='flex'>
- <div className='w-9/12'>
- <h1 className='text-title-sm font-semibold'>Daftar Produk Belanja</h1>
+ <div className='container mx-auto py-10 flex'>
+ <div className='w-9/12 border border-gray_r-6 rounded bg-white p-4'>
+ <h1 className='text-title-sm font-semibold mb-6'>Daftar Produk Belanja</h1>
+
+ <table className='table-cart'>
+ <thead>
+ <tr>
+ <th colSpan={2}>Nama Produk</th>
+ <th>Jumlah</th>
+ <th>Harga</th>
+ <th>Subtotal</th>
+ <th>Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ {!cart.isLoading && (!products || products?.length == 0) && (
+ <tr>
+ <td colSpan={6}>Keranjang belanja anda masih kosong</td>
+ </tr>
+ )}
+ {products?.map((product) => (
+ <tr key={product.id}>
+ <td>
+ <button
+ type='button'
+ className='flex items-center mr-2'
+ onClick={() => toggleSelected(product.id)}
+ >
+ {!product?.selected && (
+ <div className='w-5 h-5 border border-gray_r-11 rounded' />
+ )}
+ {product?.selected && (
+ <CheckIcon className='border bg-red_r-10 w-5 text-white' />
+ )}
+ </button>
+ </td>
+ <td className='flex'>
+ <Link
+ href={createSlug(
+ '/shop/product/',
+ product?.parent.name,
+ product?.parent.id
+ )}
+ className='w-[30%] flex-shrink-0'
+ >
+ <Image
+ src={product?.parent?.image}
+ alt={product?.name}
+ className='object-contain object-center border border-gray_r-6 h-40 w-full rounded-md'
+ />
+ </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>
+ </td>
+ <td>
+ <input
+ className='form-input w-16 py-2 text-center bg-gray_r-1'
+ type='number'
+ value={product?.quantity}
+ onChange={(e) => updateQuantity(e.target.value, product?.id)}
+ onBlur={(e) => updateQuantity(e.target.value, product?.id, 'BLUR')}
+ />
+ </td>
+ <td>
+ {product?.price?.discountPercentage > 0 && (
+ <div className='flex gap-x-1 items-center justify-center mt-3'>
+ <div className='text-gray_r-11 line-through text-caption-1'>
+ {currencyFormat(product?.price?.price)}
+ </div>
+ <div className='badge-solid-red'>
+ {product?.price?.discountPercentage}%
+ </div>
+ </div>
+ )}
+ <div className='font-normal mt-1'>
+ {currencyFormat(product?.price?.priceDiscount)}
+ </div>
+ </td>
+ <td>
+ <div className='text-red_r-11 font-medium'>
+ {currencyFormat(product?.price?.priceDiscount * product?.quantity)}
+ </div>
+ </td>
+ <td>
+ <div className='flex justify-center items-center h-full'>
+ <button
+ className='btn-red p-1 ml-1'
+ onClick={() => setDeleteConfirmation(product)}
+ >
+ <TrashIcon className='w-4' />
+ </button>
+ </div>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ <div className='pt-2 pb-6 flex items-center gap-x-3'>
+ <NextImage
+ src='/images/logo-question.png'
+ alt='Logo Question Indoteknik'
+ width={60}
+ height={60}
+ />
+ <div className='text-gray_r-12/90'>
+ Tanya stock untuk pembelian anda sebelum melanjutkan pembayaran!
+ </div>
+ </div>
+ </div>
+
+ <div className='w-3/12 pl-4'>
+ <div className='sticky top-32 w-full p-4 rounded border border-gray_r-6 bg-white'>
+ <h1 className='text-title-sm font-semibold mb-6'>Ringkasan Belanja</h1>
+ <div className='flex justify-between mb-4'>
+ <div className='text-gray_r-11'>
+ Total:
+ <span className='text-red_r-11 font-semibold'>
+ &nbsp;
+ {selectedProduct().length > 0
+ ? currencyFormat(totalPriceBeforeTax - totalDiscountAmount + totalTaxAmount)
+ : '-'}
+ </span>
+ </div>
+ </div>
+ <div className='flex gap-x-3'>
+ <button
+ type='button'
+ className='btn-yellow flex-1'
+ disabled={selectedProduct().length == 0}
+ onClick={() => router.push('/shop/quotation')}
+ >
+ Quotation
+ </button>
+ <button
+ type='button'
+ className='btn-solid-red flex-1'
+ disabled={selectedProduct().length == 0}
+ onClick={() => router.push('/shop/checkout')}
+ >
+ Checkout
+ </button>
+ </div>
</div>
</div>
</div>
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index ef0b1d54..57d217a7 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -16,8 +16,9 @@ import checkoutApi from '../api/checkoutApi'
import { useRouter } from 'next/router'
import VariantGroupCard from '@/lib/variant/components/VariantGroupCard'
import axios from 'axios'
-import Script from 'next/script'
import Image from '@/core/components/elements/Image/Image'
+import MobileView from '@/core/components/views/MobileView'
+import DesktopView from '@/core/components/views/DesktopView'
const Checkout = () => {
const router = useRouter()
@@ -99,17 +100,12 @@ const Checkout = () => {
}
}, [products])
- const poNumber = useRef('')
- const poFile = useRef('')
+ const poNumber = useRef(null)
+ const poFile = useRef(null)
const [isLoading, setIsLoading] = useState(false)
const checkout = async () => {
- if (!paymentMethod) {
- toast.error('Metode pembayaran harus dipilih', { 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' })
@@ -130,179 +126,331 @@ const Checkout = () => {
if (typeof file !== 'undefined') data.po_file = await getFileBase64(file)
const isCheckouted = await checkoutApi({ data })
- setIsLoading(false)
if (!isCheckouted?.id) {
toast.error('Gagal melakukan transaksi, terjadi kesalahan internal')
return
}
for (const product of products) deleteItemCart({ productId: product.id })
- if (paymentMethod == 'midtrans') {
- const payment = await axios.post(
- `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/midtrans-payment?transactionId=${isCheckouted.id}`
- )
- window.location.href = payment.data.redirectUrl
- } else {
- router.push(`/shop/checkout/finish?order_id=${isCheckouted.name}`)
- }
+ 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
}
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>
+ <MobileView>
+ <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 />
+ <Divider />
- <SectionAddress
- label='Alamat Pengiriman'
- url='/my/address?select=shipping'
- address={selectedAddress.shipping}
- />
+ <SectionAddress
+ label='Alamat Pengiriman'
+ url='/my/address?select=shipping'
+ address={selectedAddress.shipping}
+ />
- <Divider />
+ <Divider />
- <div className='p-4 flex flex-col gap-y-4'>
- {products && (
- <VariantGroupCard
- openOnClick={false}
- variants={products}
- />
- )}
- </div>
+ <div className='p-4 flex flex-col gap-y-4'>
+ {products && <VariantGroupCard openOnClick={false} variants={products} />}
+ </div>
- <Divider />
+ <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 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>
- <div className='flex gap-x-2 justify-between'>
- <div className='text-gray_r-11'>Subtotal</div>
- <div>{currencyFormat(totalAmount - totalDiscountAmount)}</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>
- <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>
+ <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>
- <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)}
+
+ <Divider />
+
+ <SectionAddress
+ label='Alamat Penagihan'
+ url='/my/address?select=invoicing'
+ address={selectedAddress.invoicing}
+ />
+
+ <Divider />
+
+ <div className='p-4'>
+ <div className='font-medium mb-4'>Metode Pembayaran</div>
+ <div className='flex flex-col gap-y-3'>
+ <div
+ className={`p-2 idt-transition border rounded text-gray_r-12/80 ${
+ paymentMethod == 'manual' ? 'border-yellow_r-8 bg-yellow_r-2' : 'border-gray_r-6'
+ }`}
+ onClick={() => setPaymentMethod('manual')}
+ >
+ Bank BCA (PT. Indoteknik Dotcom)
+ <div className='mt-1'>8870-4000-81</div>
+ </div>
+ <div
+ className={`p-2 idt-transition border rounded ${
+ paymentMethod == 'midtrans' ? 'border-yellow_r-8 bg-yellow_r-2' : 'border-gray_r-6'
+ }`}
+ onClick={() => setPaymentMethod('midtrans')}
+ >
+ <Image src='/images/payments/midtrans.jpg' alt='Midtrans Payment' />
+ </div>
</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'>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 />
+ <Divider />
- <div className='p-4'>
- <div className='font-medium mb-4'>Metode Pembayaran</div>
- <div className='flex flex-col gap-y-3'>
- <div
- className={`p-2 idt-transition border rounded text-gray_r-12/80 ${
- paymentMethod == 'manual' ? 'border-yellow_r-8 bg-yellow_r-2' : 'border-gray_r-6'
- }`}
- onClick={() => setPaymentMethod('manual')}
- >
- Bank BCA (PT. Indoteknik Dotcom)
- <div className='mt-1'>8870-4000-81</div>
- </div>
- <div
- className={`p-2 idt-transition border rounded ${
- paymentMethod == 'midtrans' ? 'border-yellow_r-8 bg-yellow_r-2' : 'border-gray_r-6'
- }`}
- onClick={() => setPaymentMethod('midtrans')}
+ <div className='flex gap-x-3 p-4'>
+ <button
+ className='flex-1 btn-yellow'
+ onClick={checkout}
+ disabled={isLoading || !products || products?.length == 0}
>
- <Image
- src='/images/payments/midtrans.jpg'
- alt='Midtrans Payment'
- />
- </div>
+ {isLoading ? 'Loading...' : 'Bayar'}
+ </button>
</div>
- </div>
-
- <Divider />
+ </MobileView>
+
+ <DesktopView>
+ <div className='container mx-auto py-10 flex'>
+ <div className='w-3/4 border border-gray_r-6 rounded bg-white'>
+ <SectionAddress
+ label='Alamat Pengiriman'
+ url='/my/address?select=shipping'
+ address={selectedAddress.shipping}
+ />
- <div className='p-4'>
- <div className='font-medium'>Purchase Order</div>
+ <Divider />
- <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}
+ <SectionAddress
+ label='Alamat Penagihan'
+ url='/my/address?select=invoicing'
+ address={selectedAddress.invoicing}
/>
+
+ <Divider />
+
+ <div className='p-4'>
+ <div className='font-medium'>Detail Pesanan</div>
+ <table className='table-checkout'>
+ <thead>
+ <tr>
+ <th>Nama Produk</th>
+ <th>Jumlah</th>
+ <th>Harga</th>
+ <th>Subtotal</th>
+ </tr>
+ </thead>
+ <tbody>
+ {products?.map((product) => (
+ <tr key={product.id}>
+ <td className='flex'>
+ <div className='w-[30%] flex-shrink-0'>
+ <Image
+ src={product?.parent?.image}
+ alt={product?.name}
+ className='object-contain object-center border border-gray_r-6 h-40 w-full rounded-md'
+ />
+ </div>
+ <div className='px-2 text-left'>
+ <div className='line-clamp-2 leading-6 !text-gray_r-12 font-normal'>
+ {product?.parent?.name}
+ </div>
+ <div className='text-gray_r-11 mt-2'>
+ {product?.code}{' '}
+ {product?.attributes.length > 0
+ ? `| ${product?.attributes.join(', ')}`
+ : ''}
+ </div>
+ </div>
+ </td>
+ <td>
+ <input
+ className='form-input w-16 py-2 text-center bg-gray_r-1'
+ type='number'
+ value={product?.quantity}
+ disabled
+ />
+ </td>
+ <td>
+ {product?.price?.discountPercentage > 0 && (
+ <div className='flex gap-x-1 items-center justify-center mt-3'>
+ <div className='text-gray_r-11 line-through text-caption-1'>
+ {currencyFormat(product?.price?.price)}
+ </div>
+ <div className='badge-solid-red'>
+ {product?.price?.discountPercentage}%
+ </div>
+ </div>
+ )}
+ <div className='font-normal mt-1'>
+ {currencyFormat(product?.price?.priceDiscount)}
+ </div>
+ </td>
+ <td>
+ <div className='text-red_r-11 font-medium'>
+ {currencyFormat(product?.price?.priceDiscount * product?.quantity)}
+ </div>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
</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 className='w-1/4 pl-4'>
+ <div className='border border-gray_r-6 bg-white rounded 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-11 mb-2'>
+ *) Belum termasuk biaya pengiriman
+ </p>
+ <p className='text-caption-2 text-gray_r-11 leading-5'>
+ Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '}
+ <Link href='/' className='inline font-normal'>
+ Syarat & Ketentuan
+ </Link>{' '}
+ yang berlaku
+ </p>
+
+ <hr className='my-4 border-gray_r-6' />
+
+ <div className='font-medium mt-4'>
+ Purchase Order <span className='font-normal text-gray_r-11'>(Opsional)</span>
+ </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>
+
+ <hr className='my-4 border-gray_r-6' />
+
+ <button
+ className='w-full btn-yellow mt-4'
+ onClick={checkout}
+ disabled={isLoading || !products || products?.length == 0}
+ >
+ {isLoading ? 'Loading...' : 'Lanjut Pembayaran'}
+ </button>
+ </div>
</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 || !products || products?.length == 0}
- >
- {isLoading ? 'Loading...' : 'Bayar'}
- </button>
- </div>
+ </DesktopView>
</>
)
}
@@ -311,10 +459,7 @@ 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}
- >
+ <Link className='text-caption-1' href={url}>
Pilih Alamat Lain
</Link>
</div>
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index ac17ec6e..98b40400 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -154,6 +154,7 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => {
<thead>
<tr>
<th>Part Number</th>
+ <th>Varian</th>
<th>Harga</th>
<th>Jumlah</th>
<th>Action</th>
@@ -163,6 +164,7 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => {
{product.variants.map((variant) => (
<tr key={variant.id}>
<td>{variant.code}</td>
+ <td>{variant.attributes.join(', ')}</td>
<td>
{variant.price.discountPercentage > 0 && (
<>
diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index b6e276a3..3054616c 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -12,6 +12,9 @@ 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'
+import MobileView from '@/core/components/views/MobileView'
+import DesktopView from '@/core/components/views/DesktopView'
+import Image from '@/core/components/elements/Image/Image'
const Quotation = () => {
const router = useRouter()
@@ -77,89 +80,207 @@ const Quotation = () => {
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>
+ <MobileView>
+ <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>
- <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>
+
+ <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>
- <div className='flex gap-x-2 justify-between'>
- <div className='text-gray_r-11'>Subtotal</div>
- <div>{currencyFormat(totalAmount - totalDiscountAmount)}</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>
- <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>
+ <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>
- <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)}
+ </MobileView>
+
+ <DesktopView>
+ <div className='container mx-auto py-10 flex'>
+ <div className='w-3/4 border border-gray_r-6 rounded bg-white p-4'>
+ <div className='font-medium'>Detail Barang</div>
+ <table className='table-checkout'>
+ <thead>
+ <tr>
+ <th>Nama Produk</th>
+ <th>Jumlah</th>
+ <th>Harga</th>
+ <th>Subtotal</th>
+ </tr>
+ </thead>
+ <tbody>
+ {products?.map((product) => (
+ <tr key={product.id}>
+ <td className='flex'>
+ <div className='w-[30%] flex-shrink-0'>
+ <Image
+ src={product?.parent?.image}
+ alt={product?.name}
+ className='object-contain object-center border border-gray_r-6 h-40 w-full rounded-md'
+ />
+ </div>
+ <div className='px-2 text-left'>
+ <div className='line-clamp-2 leading-6 !text-gray_r-12 font-normal'>
+ {product?.parent?.name}
+ </div>
+ <div className='text-gray_r-11 mt-2'>
+ {product?.code}{' '}
+ {product?.attributes.length > 0
+ ? `| ${product?.attributes.join(', ')}`
+ : ''}
+ </div>
+ </div>
+ </td>
+ <td>
+ <input
+ className='form-input w-16 py-2 text-center bg-gray_r-1'
+ type='number'
+ value={product?.quantity}
+ disabled
+ />
+ </td>
+ <td>
+ {product?.price?.discountPercentage > 0 && (
+ <div className='flex gap-x-1 items-center justify-center mt-3'>
+ <div className='text-gray_r-11 line-through text-caption-1'>
+ {currencyFormat(product?.price?.price)}
+ </div>
+ <div className='badge-solid-red'>
+ {product?.price?.discountPercentage}%
+ </div>
+ </div>
+ )}
+ <div className='font-normal mt-1'>
+ {currencyFormat(product?.price?.priceDiscount)}
+ </div>
+ </td>
+ <td>
+ <div className='text-red_r-11 font-medium'>
+ {currencyFormat(product?.price?.priceDiscount * product?.quantity)}
+ </div>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+
+ <div className='w-1/4 pl-4'>
+ <div className='border border-gray_r-6 bg-white rounded 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-11 mb-2'>
+ *) Belum termasuk biaya pengiriman
+ </p>
+ <p className='text-caption-2 text-gray_r-11 leading-5'>
+ Dengan melakukan pembelian melalui website Indoteknik, saya menyetujui{' '}
+ <Link href='/' className='inline font-normal'>
+ Syarat & Ketentuan
+ </Link>{' '}
+ yang berlaku
+ </p>
+
+ <hr className='my-4 border-gray_r-6' />
+
+ <button
+ className='w-full btn-yellow mt-4'
+ onClick={checkout}
+ disabled={isLoading || !products || products?.length == 0}
+ >
+ {isLoading ? 'Loading...' : 'Buat Quotation'}
+ </button>
+ </div>
</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>
+ </DesktopView>
</>
)
}
diff --git a/src/pages/shop/checkout/index.jsx b/src/pages/shop/checkout/index.jsx
index 015a11b3..30d2c730 100644
--- a/src/pages/shop/checkout/index.jsx
+++ b/src/pages/shop/checkout/index.jsx
@@ -1,13 +1,24 @@
import AppLayout from '@/core/components/layouts/AppLayout'
+import BasicLayout from '@/core/components/layouts/BasicLayout'
+import DesktopView from '@/core/components/views/DesktopView'
+import MobileView from '@/core/components/views/MobileView'
import IsAuth from '@/lib/auth/components/IsAuth'
import CheckoutComponent from '@/lib/checkout/components/Checkout'
export default function Checkout() {
return (
<IsAuth>
- <AppLayout title='Checkout'>
- <CheckoutComponent />
- </AppLayout>
+ <MobileView>
+ <AppLayout title='Checkout'>
+ <CheckoutComponent />
+ </AppLayout>
+ </MobileView>
+
+ <DesktopView>
+ <BasicLayout>
+ <CheckoutComponent />
+ </BasicLayout>
+ </DesktopView>
</IsAuth>
)
}
diff --git a/src/pages/shop/quotation/index.jsx b/src/pages/shop/quotation/index.jsx
index ff8b8644..efb35db9 100644
--- a/src/pages/shop/quotation/index.jsx
+++ b/src/pages/shop/quotation/index.jsx
@@ -1,13 +1,24 @@
import AppLayout from '@/core/components/layouts/AppLayout'
+import BasicLayout from '@/core/components/layouts/BasicLayout'
+import DesktopView from '@/core/components/views/DesktopView'
+import MobileView from '@/core/components/views/MobileView'
import IsAuth from '@/lib/auth/components/IsAuth'
import QuotationComponent from '@/lib/quotation/components/Quotation'
export default function Quotation() {
return (
<IsAuth>
- <AppLayout title='Quotation'>
- <QuotationComponent />
- </AppLayout>
+ <MobileView>
+ <AppLayout title='Quotation'>
+ <QuotationComponent />
+ </AppLayout>
+ </MobileView>
+
+ <DesktopView>
+ <BasicLayout>
+ <QuotationComponent />
+ </BasicLayout>
+ </DesktopView>
</IsAuth>
)
}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 6e4d46e4..90761309 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -394,6 +394,10 @@ button {
@apply !border-yellow_r-9;
}
+nav:has(> div.overlay) {
+ @apply z-0;
+}
+
.table-specification {
@apply max-h-[500px] overflow-y-auto border border-gray_r-6;
}
@@ -425,6 +429,40 @@ button {
@apply odd:bg-gray_r-3 even:bg-gray_r-1;
}
+.table-cart,
+.table-checkout {
+ @apply w-full
+ table-auto
+ border-collapse;
+}
+
+.table-cart tr,
+.table-checkout tr {
+ @apply border-y
+ border-gray_r-6
+ first:border-t-0;
+}
+
+.table-cart th,
+.table-cart td,
+.table-checkout th,
+.table-checkout td {
+ @apply py-4
+ px-3
+ text-center
+ text-gray_r-12/90;
+}
+
+.table-cart th,
+.table-cart td {
+ @apply first:w-12;
+}
+
+.table-cart th,
+.table-checkout th {
+ @apply font-medium;
+}
+
.navbar-user-dropdown-button {
@apply flex-1
flex