diff options
Diffstat (limited to 'src/lib/transaction/components/Transactions.jsx')
| -rw-r--r-- | src/lib/transaction/components/Transactions.jsx | 299 |
1 files changed, 219 insertions, 80 deletions
diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx index be63effd..9485449d 100644 --- a/src/lib/transaction/components/Transactions.jsx +++ b/src/lib/transaction/components/Transactions.jsx @@ -1,63 +1,139 @@ -import { useRouter } from 'next/router' -import { useState } from 'react' -import { toast } from 'react-hot-toast' -import { EllipsisVerticalIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline' +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-hot-toast'; +import { + EllipsisVerticalIcon, + MagnifyingGlassIcon, +} from '@heroicons/react/24/outline'; +import useAuth from '@/core/hooks/useAuth'; -import { downloadPurchaseOrder, downloadQuotation } from '../utils/transactions' -import useTransactions from '../hooks/useTransactions' -import currencyFormat from '@/core/utils/currencyFormat' -import cancelTransactionApi from '../api/cancelTransactionApi' -import TransactionStatusBadge from './TransactionStatusBadge' -import Spinner from '@/core/components/elements/Spinner/Spinner' -import Link from '@/core/components/elements/Link/Link' -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import Pagination from '@/core/components/elements/Pagination/Pagination' -import { toQuery } from 'lodash-contrib' -import _ from 'lodash' -import Alert from '@/core/components/elements/Alert/Alert' -import MobileView from '@/core/components/views/MobileView' -import DesktopView from '@/core/components/views/DesktopView' -import Menu from '@/lib/auth/components/Menu' +import { + downloadPurchaseOrder, + downloadQuotation, +} from '../utils/transactions'; +import useTransactions from '../hooks/useTransactions'; +import currencyFormat from '@/core/utils/currencyFormat'; +import cancelTransactionApi from '../api/cancelTransactionApi'; +import TransactionStatusBadge from './TransactionStatusBadge'; +import Spinner from '@/core/components/elements/Spinner/Spinner'; +import Link from '@/core/components/elements/Link/Link'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Pagination from '@/core/components/elements/Pagination/Pagination'; +import { toQuery } from 'lodash-contrib'; +import _ from 'lodash'; +import Alert from '@/core/components/elements/Alert/Alert'; +import MobileView from '@/core/components/views/MobileView'; +import DesktopView from '@/core/components/views/DesktopView'; +import Menu from '@/lib/auth/components/Menu'; +import * as XLSX from 'xlsx'; const Transactions = ({ context = '' }) => { - const router = useRouter() - const { q = '', page = 1 } = router.query + const auth = useAuth(); + const router = useRouter(); + const { q = '', page = 1, site = null } = router.query; - const limit = 15 + const limit = 15; + + const [inputQuery, setInputQuery] = useState(q); + const [toOthers, setToOthers] = useState(null); + const [toCancel, setToCancel] = useState(null); + + const [siteFilter, setSiteFilter] = useState(site); const query = { name: q, offset: (page - 1) * limit, context, - limit - } - const { transactions } = useTransactions({ query }) + limit, + site: + siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null), + }; - const [inputQuery, setInputQuery] = useState(q) - const [toOthers, setToOthers] = useState(null) - const [toCancel, setToCancel] = useState(null) + const { transactions } = useTransactions({ query }); const submitCancelTransaction = async () => { const isCancelled = await cancelTransactionApi({ - transaction: toCancel - }) + transaction: toCancel, + }); if (isCancelled) { - toast.success('Berhasil batalkan transaksi') - transactions.refetch() + toast.success('Berhasil batalkan transaksi'); + transactions.refetch(); } - setToCancel(null) - } + setToCancel(null); + }; - const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limit) - let pageQuery = _.omit(query, ['limit', 'offset', 'context']) - pageQuery = _.pickBy(pageQuery, _.identity) - pageQuery = toQuery(pageQuery) + const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limit); + let pageQuery = _.omit(query, ['limit', 'offset', 'context']); + pageQuery = _.pickBy( + pageQuery, + (value, key) => value !== '' && !(key === 'page' && value === '1') + ); + pageQuery = toQuery(pageQuery); const handleSubmit = (e) => { - e.preventDefault() - router.push(`${router.pathname}?q=${inputQuery}`) - } + e.preventDefault(); + const queryParams = {}; + if (inputQuery) queryParams.q = inputQuery; + if (siteFilter) queryParams.site = siteFilter; + router.push({ + pathname: router.pathname, + query: queryParams, + }); + }; + + const handleSiteFilterChange = (e) => { + setSiteFilter(e.target.value); + const queryParams = {}; + if (inputQuery) queryParams.q = inputQuery; + if (e.target.value) queryParams.site = e.target.value; + router.push({ + pathname: router.pathname, + query: queryParams, + }); + }; + + const exportToExcel = (data, siteFilter) => { + const fieldsToExport = [ + 'No. Transaksi', + 'No. PO', + 'Tanggal', + 'Created By', + 'Salesperson', + 'Total', + 'Status', + ]; + const rowsToExport = []; + + data.forEach((saleOrder) => { + const row = { + 'No. Transaksi': saleOrder.name, + 'No. PO': saleOrder.purchaseOrderName || '-', + 'Tanggal': saleOrder.dateOrder || '-', + 'Created By': saleOrder.address.customer?.name || '-', + 'Salesperson': saleOrder.sales, + 'Total': currencyFormat(saleOrder.amountTotal), + 'Status': saleOrder.status, + }; + if(siteFilter){ + row['Site'] = siteFilter; + } + rowsToExport.push(row); + }); + const worksheet = XLSX.utils.json_to_sheet(rowsToExport, { + header: fieldsToExport, + }); + + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + XLSX.writeFile(workbook, 'transactions.xlsx'); + }; + + const handleExportExcel = () => { + const dataToExport = transactions.data.saleOrders; + + exportToExcel(dataToExport, siteFilter); + }; return ( <> <MobileView> @@ -81,17 +157,23 @@ const Transactions = ({ context = '' }) => { </div> )} - {!transactions.isLoading && transactions.data?.saleOrders?.length === 0 && ( - <Alert type='info' className='text-center'> - Tidak ada transaksi - </Alert> - )} + {!transactions.isLoading && + transactions.data?.saleOrders?.length === 0 && ( + <Alert type='info' className='text-center'> + Tidak ada transaksi + </Alert> + )} {transactions.data?.saleOrders?.map((saleOrder, index) => ( - <div className='p-4 shadow border border-gray_r-3 rounded-md' key={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}/${saleOrder.id}`}> - <span className='text-caption-2 text-gray_r-11'>No. Transaksi</span> + <span className='text-caption-2 text-gray_r-11'> + No. Transaksi + </span> <h2 className='text-danger-500 mt-1'>{saleOrder.name}</h2> </Link> <div className='flex gap-x-1 justify-end'> @@ -105,13 +187,17 @@ const Transactions = ({ context = '' }) => { <Link href={`${router.pathname}/${saleOrder.id}`}> <div className='grid grid-cols-2 mt-3'> <div> - <span className='text-caption-2 text-gray_r-11'>No. Purchase Order</span> + <span className='text-caption-2 text-gray_r-11'> + No. Purchase Order + </span> <p className='mt-1 font-medium text-gray_r-12'> {saleOrder.purchaseOrderName || '-'} </p> </div> <div className='text-right'> - <span className='text-caption-2 text-gray_r-11'>Total Invoice</span> + <span className='text-caption-2 text-gray_r-11'> + Total Invoice + </span> <p className='mt-1 font-medium text-gray_r-12'> {saleOrder.invoiceCount} Invoice </p> @@ -120,10 +206,14 @@ const Transactions = ({ context = '' }) => { <div className='grid grid-cols-2 mt-3'> <div> <span className='text-caption-2 text-gray_r-11'>Sales</span> - <p className='mt-1 font-medium text-gray_r-12'>{saleOrder.sales}</p> + <p className='mt-1 font-medium text-gray_r-12'> + {saleOrder.sales} + </p> </div> <div className='text-right'> - <span className='text-caption-2 text-gray_r-11'>Total Harga</span> + <span className='text-caption-2 text-gray_r-11'> + Total Harga + </span> <p className='mt-1 font-medium text-gray_r-12'> {currencyFormat(saleOrder.amountTotal)} </p> @@ -140,14 +230,18 @@ const Transactions = ({ context = '' }) => { className='mt-2 mb-2' /> - <BottomPopup title='Lainnya' active={toOthers} close={() => setToOthers(null)}> + <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' disabled={!toOthers?.purchaseOrderFile} onClick={() => { - downloadPurchaseOrder(toOthers) - setToOthers(null) + downloadPurchaseOrder(toOthers); + setToOthers(null); }} > Download PO @@ -156,8 +250,8 @@ const Transactions = ({ context = '' }) => { className='text-left disabled:opacity-60' disabled={toOthers?.status != 'draft'} onClick={() => { - downloadQuotation(toOthers) - setToOthers(null) + downloadQuotation(toOthers); + setToOthers(null); }} > Download Quotation @@ -166,8 +260,8 @@ const Transactions = ({ context = '' }) => { className='text-left disabled:opacity-60' disabled={toOthers?.status != 'waiting'} onClick={() => { - setToCancel(toOthers) - setToOthers(null) + setToCancel(toOthers); + setToOthers(null); }} > Batalkan Transaksi @@ -175,7 +269,11 @@ const Transactions = ({ context = '' }) => { </div> </BottomPopup> - <BottomPopup active={toCancel} close={() => setToCancel(null)} title='Batalkan Transaksi'> + <BottomPopup + active={toCancel} + close={() => setToCancel(null)} + title='Batalkan Transaksi' + > <div className='leading-7 text-gray_r-12/80'> Apakah anda yakin membatalkan transaksi{' '} <span className='underline'>{toCancel?.name}</span>? @@ -188,7 +286,11 @@ const Transactions = ({ context = '' }) => { > Ya, Batalkan </button> - <button className='btn-light flex-1' type='button' onClick={() => setToCancel(null)}> + <button + className='btn-light flex-1' + type='button' + onClick={() => setToCancel(null)} + > Batal </button> </div> @@ -202,24 +304,54 @@ const Transactions = ({ context = '' }) => { <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'> + <div className='flex mb-2 items-center justify-between'> <h1 className='text-title-sm font-semibold'> Daftar Transaksi{' '} - {transactions?.data?.saleOrders ? `(${transactions?.data?.saleOrders.length})` : ''} + {transactions?.data?.saleOrders + ? `(${transactions?.data?.saleOrders.length})` + : ''} </h1> - <form className='flex gap-x-2' onSubmit={handleSubmit}> - <input - type='text' + <div className='grid grid-cols-2 gap-2'> + <select + value={siteFilter} + onChange={handleSiteFilterChange} className='form-input' - placeholder='Cari Transaksi...' - value={inputQuery} - onChange={(e) => setInputQuery(e.target.value)} - /> - <button className='btn-light bg-transparent px-3' type='submit'> - <MagnifyingGlassIcon className='w-6' /> - </button> - </form> + > + <option value=''>Semua</option> + <option value='Depok'>Depok</option> + <option value='Padang'>Padang</option> + <option value='berau'>Berau</option> + </select> + <form className='flex gap-x-1' onSubmit={handleSubmit}> + <input + type='text' + className='form-input' + placeholder='Cari Transaksi...' + 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> </div> + <button + onClick={handleExportExcel} + className='hover:text-blue-400 rounded inline-flex items-center mb-2' + > + <svg + class='fill-current w-4 h-4 mr-2' + xmlns='http://www.w3.org/2000/svg' + viewBox='0 0 20 20' + > + <path d='M13 8V2H7v6H2l8 8 8-8h-5zM0 18h20v2H0v-2z' /> + </svg> + <span>Export</span> + </button> <table className='table-data'> <thead> <tr> @@ -252,13 +384,20 @@ const Transactions = ({ context = '' }) => { {transactions.data?.saleOrders?.map((saleOrder) => ( <tr key={saleOrder.id}> <td> - <Link className='whitespace-nowrap' href={`${router.pathname}/${saleOrder.id}`}>{saleOrder.name}</Link> + <Link + className='whitespace-nowrap' + href={`${router.pathname}/${saleOrder.id}`} + > + {saleOrder.name} + </Link> </td> <td>{saleOrder.purchaseOrderName || '-'}</td> <td>{saleOrder.dateOrder || '-'}</td> <td>{saleOrder.address.customer?.name || '-'}</td> <td className='!text-left'>{saleOrder.sales}</td> - <td className='!text-left'>{currencyFormat(saleOrder.amountTotal)}</td> + <td className='!text-left'> + {currencyFormat(saleOrder.amountTotal)} + </td> <td> <div className='flex justify-center'> <TransactionStatusBadge status={saleOrder.status} /> @@ -272,14 +411,14 @@ const Transactions = ({ context = '' }) => { <Pagination pageCount={pageCount} currentPage={parseInt(page)} - url={router.pathname + pageQuery} + url={router.pathname + (pageQuery ? `?${pageQuery}` : '')} className='mt-2 mb-2' /> </div> </div> </DesktopView> </> - ) -} + ); +}; -export default Transactions +export default Transactions; |
