summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-11-13 16:46:14 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-11-13 16:46:14 +0700
commit9622bff4d4902fcef81214236cc7ff035163e5e7 (patch)
tree666a57d246533aa2b9f547ef306d1293adc5efad /src
parentc873a401f0ea13e1881278e7977d4013d3a87394 (diff)
<iman> pengajuan tempo
Diffstat (limited to 'src')
-rw-r--r--src/core/components/elements/Navbar/NavbarUserDropdown.jsx1
-rw-r--r--src/lib/auth/components/Menu.jsx91
-rw-r--r--src/lib/tempo/components/Tempo.jsx277
-rw-r--r--src/pages/my/menu.jsx104
-rw-r--r--src/pages/my/tempo/index.jsx27
5 files changed, 450 insertions, 50 deletions
diff --git a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
index c0698b6e..83bf4a66 100644
--- a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
+++ b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
@@ -22,6 +22,7 @@ const NavbarUserDropdown = () => {
<Link href='/my/transactions'>Daftar Transaksi</Link>
<Link href='/my/shipments'>Daftar Pengiriman</Link>
<Link href='/my/invoices'>Invoice & Faktur Pajak</Link>
+ <Link href='/my/tempo'>Pembayaran Tempo</Link>
<Link href='/my/wishlist'>Wishlist</Link>
<Link href='/my/address'>Daftar Alamat</Link>
{!atuh?.external && (
diff --git a/src/lib/auth/components/Menu.jsx b/src/lib/auth/components/Menu.jsx
index f475db1f..b288eae9 100644
--- a/src/lib/auth/components/Menu.jsx
+++ b/src/lib/auth/components/Menu.jsx
@@ -1,76 +1,125 @@
-import Link from '@/core/components/elements/Link/Link'
-import { useRouter } from 'next/router'
-import ImageNext from 'next/image'
-import whatsappUrl from '@/core/utils/whatsappUrl'
+import Link from '@/core/components/elements/Link/Link';
+import { useRouter } from 'next/router';
+import ImageNext from 'next/image';
+import whatsappUrl from '@/core/utils/whatsappUrl';
const Menu = () => {
- const router = useRouter()
+ const router = useRouter();
- const routeStartWith = (route) => router.pathname.startsWith(route)
+ const routeStartWith = (route) => router.pathname.startsWith(route);
return (
<div className='grid grid-cols-1 bg-white border border-gray_r-6 rounded py-2 px-4 sticky top-48'>
<div className='mt-4 mb-1 font-medium'>Menu</div>
<LinkItem href='/my/quotations' active={routeStartWith('/my/quotations')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_quotation.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Quotation</p>
</div>
</LinkItem>
- <LinkItem href='/my/transactions' active={routeStartWith('/my/transactions')}>
+ <LinkItem
+ href='/my/transactions'
+ active={routeStartWith('/my/transactions')}
+ >
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_transaksi.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Transaksi</p>
</div>
</LinkItem>
<LinkItem href='/my/shipments' active={routeStartWith('/my/shipments')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_pengiriman.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Pengiriman</p>
</div>
</LinkItem>
<LinkItem href='/my/invoices' active={routeStartWith('/my/invoices')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_invoice.svg'
+ width={18}
+ height={20}
+ />
<p>Invoice & Faktur Pajak</p>
</div>
</LinkItem>
+ <LinkItem href='/my/tempo' active={routeStartWith('/my/tempo')}>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_tempo.svg' width={18} height={20} />
+ <p>Pembayaran Tempo</p>
+ </div>
+ </LinkItem>
<LinkItem href='/my/wishlist' active={routeStartWith('/my/wishlist')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_wishlist.svg'
+ width={18}
+ height={20}
+ />
<p>Wishlist</p>
</div>
</LinkItem>
<div className='mt-4 mb-1 font-medium'>Pusat Bantuan</div>
- <LinkItem href={whatsappUrl('', '', '')} rel='noopener noreferrer' target='_blank'>
+ <LinkItem
+ href={whatsappUrl('', '', '')}
+ rel='noopener noreferrer'
+ target='_blank'
+ >
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_layanan_pelanggan.svg'
+ width={18}
+ height={20}
+ />
<p>Layanan Pelanggan</p>
</div>
</LinkItem>
<div className='mt-4 mb-1 font-medium'>Pengaturan Akun</div>
<LinkItem href='/my/address' active={routeStartWith('/my/address')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_alamat.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Alamat</p>
</div>
</LinkItem>
<LinkItem href='/my/profile' active={routeStartWith('/my/profile')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_profile.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_profile.svg'
+ width={18}
+ height={20}
+ />
<p>Profil Saya</p>
</div>
</LinkItem>
<button type='button' className='text-gray_r-12/80 p-2 text-left'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_logout.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_logout.svg'
+ width={18}
+ height={20}
+ />
<p>Keluar Akun</p>
</div>
</button>
</div>
- )
-}
+ );
+};
const LinkItem = ({ children, ...props }) => (
<Link
@@ -81,6 +130,6 @@ const LinkItem = ({ children, ...props }) => (
>
{children}
</Link>
-)
+);
-export default Menu
+export default Menu;
diff --git a/src/lib/tempo/components/Tempo.jsx b/src/lib/tempo/components/Tempo.jsx
new file mode 100644
index 00000000..9b68251c
--- /dev/null
+++ b/src/lib/tempo/components/Tempo.jsx
@@ -0,0 +1,277 @@
+import {
+ CheckIcon,
+ ClockIcon,
+ EllipsisVerticalIcon,
+ MagnifyingGlassIcon,
+} from '@heroicons/react/24/outline';
+import { toQuery } from 'lodash-contrib';
+import _ from 'lodash';
+import { useRouter } from 'next/router';
+import { useState } from 'react';
+import useInvoices from '../hooks/useInvoices';
+import Spinner from '@/core/components/elements/Spinner/Spinner';
+import Alert from '@/core/components/elements/Alert/Alert';
+import Pagination from '@/core/components/elements/Pagination/Pagination';
+import Link from '@/core/components/elements/Link/Link';
+import currencyFormat from '@/core/utils/currencyFormat';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import { downloadInvoice, downloadTaxInvoice } from '../utils/invoices';
+import MobileView from '@/core/components/views/MobileView';
+import DesktopView from '@/core/components/views/DesktopView';
+import Menu from '@/lib/auth/components/Menu';
+
+const Tempo = () => {
+ const router = useRouter();
+ const { q = '', page = 1 } = router.query;
+
+ const limit = 15;
+
+ const query = {
+ name: q,
+ offset: (page - 1) * limit,
+ limit,
+ };
+ const { invoices } = useInvoices({ query });
+
+ const [inputQuery, setInputQuery] = useState(q);
+ const [toOthers, setToOthers] = useState(null);
+
+ const pageCount = Math.ceil(invoices?.data?.invoiceTotal / limit);
+ let pageQuery = _.omit(query, ['limit', 'offset']);
+ pageQuery = _.pickBy(pageQuery, _.identity);
+ pageQuery = toQuery(pageQuery);
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ router.push(`/my/invoices?q=${inputQuery}`);
+ };
+
+ return (
+ <>
+ <MobileView>
+ <div className='p-4 flex flex-col gap-y-4'>
+ <form className='flex gap-x-3' onSubmit={handleSubmit}>
+ <input
+ type='text'
+ className='form-input'
+ placeholder='Cari Invoice...'
+ value={inputQuery}
+ onChange={(e) => setInputQuery(e.target.value)}
+ />
+ <button className='btn-light bg-transparent px-3' type='submit'>
+ <MagnifyingGlassIcon className='w-6' />
+ </button>
+ </form>
+
+ {invoices.isLoading && (
+ <div className='flex justify-center my-4'>
+ <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
+ </div>
+ )}
+
+ {!invoices.isLoading && invoices.data?.invoices?.length === 0 && (
+ <Alert type='info' className='text-center'>
+ Tidak ada invoice
+ </Alert>
+ )}
+
+ {invoices.data?.invoices?.map((invoice, index) => (
+ <div
+ className='p-4 shadow border border-gray_r-3 rounded-md'
+ key={index}
+ >
+ <div className='grid grid-cols-2'>
+ <Link href={`${router.pathname}/${invoice.id}`}>
+ <span className='text-caption-2 text-gray_r-11'>
+ No. Invoice
+ </span>
+ <h2 className='text-danger-500 mt-1'>{invoice.name}</h2>
+ </Link>
+ <div className='flex gap-x-1 justify-end'>
+ {invoice.amountResidual > 0 ? (
+ <div className='badge-solid-red h-fit ml-auto'>
+ Belum Lunas
+ </div>
+ ) : (
+ <div className='badge-solid-green h-fit ml-auto'>Lunas</div>
+ )}
+ <EllipsisVerticalIcon
+ className='w-5 h-5'
+ onClick={() => setToOthers(invoice)}
+ />
+ </div>
+ </div>
+ <Link href={`${router.pathname}/${invoice.id}`}>
+ <div className='grid grid-cols-2 text-caption-2 text-gray_r-11 mt-2 font-normal'>
+ <p>{invoice.invoiceDate}</p>
+ <p className='text-right'>{invoice.paymentTerm}</p>
+ </div>
+ <hr className='my-3' />
+ <div className='grid grid-cols-2'>
+ <div>
+ <span className='text-caption-2 text-gray_r-11'>
+ No. Purchase Order
+ </span>
+ <p className='mt-1 font-medium text-gray_r-12'>
+ {invoice.purchaseOrderName || '-'}
+ </p>
+ </div>
+ <div className='text-right'>
+ <span className='text-caption-2 text-gray_r-11'>
+ Total Invoice
+ </span>
+ <p className='mt-1 font-medium text-gray_r-12'>
+ {currencyFormat(invoice.amountTotal)}
+ </p>
+ </div>
+ </div>
+ </Link>
+ {invoice.efaktur ? (
+ <div className='badge-green h-fit mt-3 ml-auto flex items-center gap-x-0.5'>
+ <CheckIcon className='w-4 stroke-2' />
+ Faktur Pajak
+ </div>
+ ) : (
+ <div className='badge-red h-fit mt-3 ml-auto flex items-center gap-x-0.5'>
+ <ClockIcon className='w-4 stroke-2' />
+ Faktur Pajak
+ </div>
+ )}
+ </div>
+ ))}
+
+ <Pagination
+ pageCount={pageCount}
+ currentPage={parseInt(page)}
+ url={`/my/invoices${pageQuery}`}
+ className='mt-2 mb-2'
+ />
+
+ <BottomPopup
+ title='Lainnya'
+ active={toOthers}
+ close={() => setToOthers(null)}
+ >
+ <div className='flex flex-col gap-y-4 mt-2'>
+ <button
+ className='text-left disabled:opacity-60'
+ onClick={() => {
+ downloadInvoice(toOthers);
+ setToOthers(null);
+ }}
+ >
+ Download Invoice
+ </button>
+ <button
+ className='text-left disabled:opacity-60'
+ disabled={!toOthers?.efaktur}
+ onClick={() => {
+ downloadTaxInvoice(toOthers);
+ setToOthers(null);
+ }}
+ >
+ Download Faktur Pajak
+ </button>
+ </div>
+ </BottomPopup>
+ </div>
+ </MobileView>
+
+ <DesktopView>
+ <div className='container mx-auto flex py-10'>
+ <div className='w-3/12 pr-4'>
+ <Menu />
+ </div>
+ <div className='w-9/12 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'>
+ Invoice & Faktur Pajak{' '}
+ {invoices?.data?.invoices
+ ? `(${invoices?.data?.invoices.length})`
+ : ''}
+ </h1>
+ <form className='flex gap-x-2' onSubmit={handleSubmit}>
+ <input
+ type='text'
+ className='form-input'
+ placeholder='Cari Invoice...'
+ value={inputQuery}
+ onChange={(e) => setInputQuery(e.target.value)}
+ />
+ <button className='btn-light bg-transparent px-3' type='submit'>
+ <MagnifyingGlassIcon className='w-6' />
+ </button>
+ </form>
+ </div>
+
+ <table className='table-data'>
+ <thead>
+ <tr>
+ <th>No. Invoice</th>
+ <th>No. PO</th>
+ <th>Tanggal</th>
+ <th className='!text-left'>Salesperson</th>
+ <th>Status</th>
+ <th className='!text-left'>Total</th>
+ </tr>
+ </thead>
+ <tbody>
+ {invoices.isLoading && (
+ <tr>
+ <td colSpan={6}>
+ <div className='flex justify-center my-2'>
+ <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
+ </div>
+ </td>
+ </tr>
+ )}
+ {!invoices.isLoading &&
+ (!invoices?.data?.invoices ||
+ invoices?.data?.invoices?.length == 0) && (
+ <tr>
+ <td colSpan={6}>Tidak ada invoice</td>
+ </tr>
+ )}
+ {invoices.data?.invoices?.map((invoice) => (
+ <tr key={invoice.id}>
+ <td>
+ <Link href={`${router.pathname}/${invoice.id}`}>
+ {invoice.name}
+ </Link>
+ </td>
+ <td>{invoice.purchaseOrderName || '-'}</td>
+ <td>{invoice.invoiceDate}</td>
+ <td className='!text-left'>{invoice.sales}</td>
+ <td>
+ {invoice.amountResidual > 0 ? (
+ <div className='badge-solid-red h-fit mx-auto'>
+ Belum Lunas
+ </div>
+ ) : (
+ <div className='badge-solid-green h-fit mx-auto'>
+ Lunas
+ </div>
+ )}
+ </td>
+ <td className='!text-left'>
+ {currencyFormat(invoice.amountTotal)}
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ <Pagination
+ pageCount={pageCount}
+ currentPage={parseInt(page)}
+ url={`/my/invoices${pageQuery}`}
+ className='mt-2 mb-2'
+ />
+ </div>
+ </div>
+ </DesktopView>
+ </>
+ );
+};
+
+export default Tempo;
diff --git a/src/pages/my/menu.jsx b/src/pages/my/menu.jsx
index a0ce223e..63b4d35c 100644
--- a/src/pages/my/menu.jsx
+++ b/src/pages/my/menu.jsx
@@ -1,24 +1,24 @@
-import Divider from '@/core/components/elements/Divider/Divider'
-import Link from '@/core/components/elements/Link/Link'
-import AppLayout from '@/core/components/layouts/AppLayout'
-import useAuth from '@/core/hooks/useAuth'
-import { deleteAuth } from '@/core/utils/auth'
-import IsAuth from '@/lib/auth/components/IsAuth'
-import { ChevronRightIcon, UserIcon } from '@heroicons/react/24/solid'
-import { signOut, useSession } from 'next-auth/react'
-import { useRouter } from 'next/router'
-import ImageNext from 'next/image'
+import Divider from '@/core/components/elements/Divider/Divider';
+import Link from '@/core/components/elements/Link/Link';
+import AppLayout from '@/core/components/layouts/AppLayout';
+import useAuth from '@/core/hooks/useAuth';
+import { deleteAuth } from '@/core/utils/auth';
+import IsAuth from '@/lib/auth/components/IsAuth';
+import { ChevronRightIcon, UserIcon } from '@heroicons/react/24/solid';
+import { signOut, useSession } from 'next-auth/react';
+import { useRouter } from 'next/router';
+import ImageNext from 'next/image';
export default function Menu() {
- const auth = useAuth()
- const router = useRouter()
- const { data: session } = useSession()
+ const auth = useAuth();
+ const router = useRouter();
+ const { data: session } = useSession();
const logout = () => {
deleteAuth().then(() => {
- router.push('/login')
- })
- }
+ router.push('/login');
+ });
+ };
return (
<IsAuth>
@@ -29,8 +29,12 @@ export default function Menu() {
</div>
<div className='ml-4'>
<div className='font-semibold text-gray_r-12'>{auth?.name}</div>
- {auth?.company && <div className='badge-solid-red mt-1'>Akun Bisnis</div>}
- {!auth?.company && <div className='badge-gray mt-1'>Akun Individu</div>}
+ {auth?.company && (
+ <div className='badge-solid-red mt-1'>Akun Bisnis</div>
+ )}
+ {!auth?.company && (
+ <div className='badge-gray mt-1'>Akun Individu</div>
+ )}
</div>
<div className='ml-auto !text-gray_r-12'>
<ChevronRightIcon className='w-6' />
@@ -47,32 +51,63 @@ export default function Menu() {
<LinkItem href='/my/quotations'>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_quotation.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Quotation</p>
</div>
</LinkItem>
<LinkItem href='/my/transactions'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_transaksi.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Transaksi</p>
</div>
</LinkItem>
<LinkItem href='/my/shipments'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_pengiriman.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Pengiriman</p>
</div>
</LinkItem>
<LinkItem href='/my/invoices'>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_invoice.svg'
+ width={18}
+ height={20}
+ />
<p>Invoice & Faktur Pajak</p>
</div>
</LinkItem>
+ <LinkItem href='/my/tempo'>
+ {' '}
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext
+ src='/images/icon/icon_tempo.svg'
+ width={18}
+ height={20}
+ />
+ <p>Pembayaran Tempo</p>
+ </div>
+ </LinkItem>
<LinkItem href='/my/wishlist'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_wishlist.svg'
+ width={18}
+ height={20}
+ />
<p>Wishlist</p>
</div>
</LinkItem>
@@ -86,7 +121,11 @@ export default function Menu() {
<LinkItem href='/'>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_layanan_pelanggan.svg'
+ width={18}
+ height={20}
+ />
<p>Layanan Pelanggan</p>
</div>
</LinkItem>
@@ -99,7 +138,11 @@ export default function Menu() {
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
<LinkItem href='/my/address'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_alamat.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Alamat</p>
</div>
</LinkItem>
@@ -112,20 +155,23 @@ export default function Menu() {
</div>
</AppLayout>
</IsAuth>
- )
+ );
}
const MenuHeader = ({ children, ...props }) => (
<div {...props} className='font-medium px-4 flex'>
{children}
</div>
-)
+);
const LinkItem = ({ children, ...props }) => (
- <Link {...props} className='!text-gray_r-12/70 !font-normal p-4 flex items-center'>
+ <Link
+ {...props}
+ className='!text-gray_r-12/70 !font-normal p-4 flex items-center'
+ >
{children}
<div className='ml-auto !text-gray_r-11'>
<ChevronRightIcon className='w-5' />
</div>
</Link>
-)
+);
diff --git a/src/pages/my/tempo/index.jsx b/src/pages/my/tempo/index.jsx
new file mode 100644
index 00000000..e540fbda
--- /dev/null
+++ b/src/pages/my/tempo/index.jsx
@@ -0,0 +1,27 @@
+import Seo from '@/core/components/Seo';
+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 InvoicesComponent from '@/lib/invoice/components/Invoices';
+
+export default function MyTempo() {
+ return (
+ <IsAuth>
+ <Seo title='Tempo - Indoteknik.com' />
+
+ <MobileView>
+ <AppLayout title='Pembayaran Tempo'>
+ <InvoicesComponent />
+ </AppLayout>
+ </MobileView>
+
+ <DesktopView>
+ <BasicLayout>
+ <InvoicesComponent />
+ </BasicLayout>
+ </DesktopView>
+ </IsAuth>
+ );
+}