diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-11-13 16:46:14 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-11-13 16:46:14 +0700 |
| commit | 9622bff4d4902fcef81214236cc7ff035163e5e7 (patch) | |
| tree | 666a57d246533aa2b9f547ef306d1293adc5efad /src | |
| parent | c873a401f0ea13e1881278e7977d4013d3a87394 (diff) | |
<iman> pengajuan tempo
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/components/elements/Navbar/NavbarUserDropdown.jsx | 1 | ||||
| -rw-r--r-- | src/lib/auth/components/Menu.jsx | 91 | ||||
| -rw-r--r-- | src/lib/tempo/components/Tempo.jsx | 277 | ||||
| -rw-r--r-- | src/pages/my/menu.jsx | 104 | ||||
| -rw-r--r-- | src/pages/my/tempo/index.jsx | 27 |
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> + ); +} |
