summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2025-02-26 16:29:27 +0700
committerit-fixcomart <it@fixcomart.co.id>2025-02-26 16:29:27 +0700
commitcd072c875c334b1140e4f797a37a9e991d53e2b5 (patch)
tree24b69fc585e2842e2e761192becf3c30ad221752 /src
parent6c4fe7aec3aec0879fd0880cffe02263b4655f29 (diff)
<iman> CR repear order
Diffstat (limited to 'src')
-rw-r--r--src/lib/transaction/components/Transactions.jsx294
1 files changed, 265 insertions, 29 deletions
diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 92bdd276..a8685105 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -4,9 +4,10 @@ import { toast } from 'react-hot-toast';
import {
EllipsisVerticalIcon,
MagnifyingGlassIcon,
+ ChevronDownIcon,
+ ChevronUpIcon,
} from '@heroicons/react/24/outline';
import useAuth from '@/core/hooks/useAuth';
-
import {
downloadPurchaseOrder,
downloadQuotation,
@@ -28,32 +29,31 @@ import Menu from '@/lib/auth/components/Menu';
import * as XLSX from 'xlsx';
import getSite from '../api/listSiteApi';
import transactionsApi from '../api/transactionsApi';
-
+import { motion } from 'framer-motion';
+import Image from '@/core/components/elements/Image/Image';
const Transactions = ({ context = '' }) => {
const auth = useAuth();
const router = useRouter();
- const { q = '', page = 1, site = null } = router.query;
-
- const limit = 15;
+ const { q = '', page = 1, site = null, limit = 15 } = router.query;
const [inputQuery, setInputQuery] = useState(q);
const [toOthers, setToOthers] = useState(null);
const [toCancel, setToCancel] = useState(null);
const [listSites, setListSites] = useState([]);
-
+ const [isOpen, setIsOpen] = useState(false);
const [siteFilter, setSiteFilter] = useState(site);
-
+ const [pageNew, setPageNew] = useState(page);
+ const [limitNew, setLimitNew] = useState(limit);
const query = {
name: q,
- offset: (page - 1) * limit,
+ offset: (pageNew - 1) * limitNew,
context,
- limit,
+ limit: limitNew,
site:
siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
};
-
const { transactions } = useTransactions({ query });
-
+ console.log('transactions', transactions);
const fetchSite = async () => {
const site = await getSite();
setListSites(site.sites);
@@ -70,7 +70,7 @@ const Transactions = ({ context = '' }) => {
setToCancel(null);
};
- const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limit);
+ const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limitNew);
let pageQuery = _.omit(query, ['limit', 'offset', 'context']);
pageQuery = _.pickBy(
pageQuery,
@@ -137,6 +137,58 @@ const Transactions = ({ context = '' }) => {
XLSX.writeFile(workbook, 'transactions.xlsx');
};
+ const handleExportCSV = async () => {
+ const dataToExport = await getAllData();
+
+ exportToCSV(dataToExport?.saleOrders, siteFilter);
+ };
+
+ const exportToCSV = (data, siteFilter) => {
+ const fieldsToExport = [
+ 'No. Transaksi',
+ 'No. PO',
+ 'Tanggal',
+ 'Created By',
+ 'Salesperson',
+ 'Total',
+ 'Status',
+ ];
+
+ if (siteFilter) {
+ fieldsToExport.push('Site');
+ }
+
+ const rowsToExport = data.map((saleOrder) => {
+ const row = [
+ saleOrder.name,
+ saleOrder.purchaseOrderName || '-',
+ saleOrder.dateOrder || '-',
+ saleOrder.address.customer?.name || '-',
+ saleOrder.sales,
+ currencyFormat(saleOrder.amountTotal),
+ saleOrder.status,
+ ];
+
+ if (siteFilter) {
+ row.push(siteFilter);
+ }
+
+ return row.join(',');
+ });
+
+ const csvContent =
+ 'data:text/csv;charset=utf-8,' +
+ [fieldsToExport.join(','), ...rowsToExport].join('\n');
+
+ const encodedUri = encodeURI(csvContent);
+ const link = document.createElement('a');
+ link.setAttribute('href', encodedUri);
+ link.setAttribute('download', 'transactions.csv');
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
+
const getAllData = async () => {
const query = {
name: q,
@@ -144,7 +196,7 @@ const Transactions = ({ context = '' }) => {
site:
siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
};
- const queryString = toQuery(query)
+ const queryString = toQuery(query);
const data = await transactionsApi({ query: queryString });
return data;
};
@@ -155,6 +207,25 @@ const Transactions = ({ context = '' }) => {
exportToExcel(dataToExport?.saleOrders, siteFilter);
};
+ const handleDownload = (format) => {
+ handleExport(format);
+ setIsOpen(false);
+ };
+
+ const handleExport = (format) => {
+ if (format === 'csv') {
+ handleExportCSV();
+ } else if (format === 'xlsx') {
+ handleExportExcel();
+ }
+ };
+
+ const startItem = 1 + (pageNew - 1) * limitNew;
+ const endItem = Math.min(
+ limitNew * pageNew,
+ transactions?.data?.saleOrderTotal
+ );
+
useEffect(() => {
fetchSite();
}, []);
@@ -328,14 +399,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-6 items-center justify-between '>
<h1 className='text-title-sm font-semibold'>
Daftar Transaksi{' '}
{transactions?.data?.saleOrders
- ? `(${transactions?.data?.saleOrders.length})`
+ ? `(${transactions?.data?.saleOrderTotal})`
: ''}
</h1>
- <div className='grid grid-cols-2 gap-2'>
+ <div className='relative inline-block text-left'>
+ <button
+ onClick={() => setIsOpen(!isOpen)}
+ type='button'
+ className='btn-light bg-slate-50 mt-3 w-full gap-2 items-center flex flex-row !text-gray_r-11 px-4 py-3 mb-2'
+ >
+ <p>Export</p>
+ <motion.div
+ animate={{ rotate: isOpen ? 180 : 0 }}
+ transition={{ duration: 0.2, ease: 'easeInOut' }}
+ >
+ <ChevronDownIcon className='w-5' />
+ </motion.div>
+ </button>
+
+ {isOpen && (
+ <motion.div
+ initial={{ opacity: 0, y: -10 }}
+ animate={{ opacity: 1, y: 0 }}
+ exit={{ opacity: 0, y: -10 }}
+ transition={{ duration: 0.2, ease: 'easeInOut' }}
+ className='absolute mt-2 w-fit py-1 bg-white border border-gray-300 rounded-md shadow-lg'
+ >
+ <button
+ onClick={() => handleDownload('csv')}
+ className='block w-full px-4 py-2 text-left hover:bg-gray-200 text-nowrap'
+ >
+ Download CSV
+ </button>
+ <button
+ onClick={() => handleDownload('xlsx')}
+ className='block w-full px-4 py-2 text-left hover:bg-gray-200 text-nowrap'
+ >
+ Download XLSX
+ </button>
+ </motion.div>
+ )}
+ </div>
+ </div>
+ <div className='flex flex-row items-center justify-between mb-2'>
+ <div className='flex flex-col gap-2 pb-2'>
{listSites?.length > 0 ? (
<select
value={siteFilter}
@@ -349,7 +460,9 @@ const Transactions = ({ context = '' }) => {
</option>
))}
</select>
- ) : (<div></div>)}
+ ) : (
+ <div></div>
+ )}
<form className='flex gap-x-1' onSubmit={handleSubmit}>
<input
@@ -367,14 +480,138 @@ const Transactions = ({ context = '' }) => {
</button>
</form>
</div>
+ <div className='flex flex-row gap-4 items-center justify-center'>
+ <p>
+ Menampilkan {startItem}-
+ {endItem ? endItem : transactions?.data?.saleOrderTotal} dari{' '}
+ {transactions?.data?.saleOrderTotal}
+ </p>
+ <select
+ id='limitSelect'
+ value={limitNew}
+ onChange={(e) => {
+ setLimitNew(Number(e.target.value));
+ setPageNew(1);
+ }}
+ className='border p-2'
+ >
+ <option value={10}>10</option>
+ <option value={15}>15</option>
+ <option value={20}>20</option>
+ </select>
+ </div>
+ </div>
+ <div className='flex'>
+ {!transactions.isLoading &&
+ (!transactions?.data?.saleOrders ||
+ transactions?.data?.saleOrders?.length == 0) && (
+ <div className='justify-center p-4'>
+ <p className='text-gray-500 text-center '>
+ Tidak Ada Transaksi
+ </p>
+ </div>
+ )}
+
+ {transactions && transactions.data?.saleOrders?.length > 0 && (
+ <div className='flex flex-col gap-4 w-full'>
+ {transactions.data.saleOrders.map((saleOrder, index) => (
+ <div
+ key={index}
+ className='border p-2 hover:border-red-500 w-full rounded-sm'
+ >
+ {/* <Link
+ href={`/my/quotations/${saleOrder?.id}`}
+ className='hover:border-red-500 block w-full'
+ > */}
+ <div className='flex flex-row justify-between items-center py-2'>
+ <div className='flex justify-center gap-3'>
+ <TransactionStatusBadge status={saleOrder.status} />
+ <p className='text-red-500'>{saleOrder.name}</p>
+ <p>
+ Salesperson:{' '}
+ {
+ <span className='font-semibold'>
+ {saleOrder.sales}
+ </span>
+ }
+ </p>
+ </div>
+ <div>
+ Tanggal Pesanan:{' '}
+ <span className='font-semibold'>
+ {saleOrder.dateOrder.split(' ')[0] || '-'}
+ </span>
+ </div>
+ </div>
+ <hr className='mt-3 mb-3 border border-gray-100' />
+ <div className='flex flex-row gap-2 justify-between items-center '>
+ <div className='flex justify-start w-4/5 flex-col gap-2'>
+ <div className='flex gap-2'>
+ <div>
+ <Image
+ src={saleOrder.products[0]?.parent?.image}
+ alt={saleOrder.products[0]?.name}
+ className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md'
+ />
+ </div>
+ <div className='flex flex-col gap-3 justify-start'>
+ <p className='flex flex-row gap-2'>
+ <span className='text-sm'>Nomor PO:</span>
+ <span className='text-sm text-red-500 font-semibold'>
+ {saleOrder.purchaseOrderName || '-'}
+ </span>
+ </p>
+ <p className='line-clamp-2 leading-6 tracking-wide opacity-90 !text-gray_r-12 font-semibold text-nowrap'>
+ {saleOrder.products[0]?.parent?.name}
+ </p>
+ <p className='opacity-85 !text-gray_r-12'>
+ {saleOrder.products[0]?.quantity} x{' '}
+ {currencyFormat(
+ saleOrder.products[0]?.price?.priceDiscount
+ )}
+ </p>
+ <div className='flex flex-row justify-start items-center'>
+ {saleOrder.products?.length > 1 && (
+ <div className='flex flex-row gap-1 justify-start items-center'>
+ {saleOrder.products
+ .slice(1)
+ .map((product, index) => (
+ <Image
+ key={index} // Tambahkan key untuk setiap elemen dalam map()
+ src={product?.parent?.image}
+ alt={product?.name}
+ className='object-contain object-center border border-gray_r-6 h-8 w-8 rounded-md'
+ />
+ ))}
+ <Link
+ href={`/my/quotations/${saleOrder?.id}`}
+ className='text-sm text-red-500 text-nowrap'
+ >
+ Lihat semua produk
+ </Link>
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+ <div className='flex flex-row w-full text-nowrap gap-2'>
+ <span className='text-sm'>
+ pesanan dibuat oleh:
+ </span>
+ <p className='text-sm font-semibold'>
+ {saleOrder.address.customer?.name || '-'}
+ </p>
+ </div>
+ </div>
+ <div className='w-[1px] h-24 bg-gray-300'></div>
+ <div className='w-1/5'>Total harga</div>
+ </div>
+ {/* </Link> */}
+ </div>
+ ))}
+ </div>
+ )}
</div>
- <button
- onClick={handleExportExcel}
- type='button'
- className='btn-solid-red px-3 py-2 mr-auto mb-2'
- >
- <span>Download</span>
- </button>
<table className='table-data'>
<thead>
<tr>
@@ -382,9 +619,7 @@ const Transactions = ({ context = '' }) => {
<th>No. PO</th>
<th>Tanggal</th>
<th>Created By</th>
- {auth?.feature?.soApproval && (
- <th>Site</th>
- )}
+ {auth?.feature?.soApproval && <th>Site</th>}
<th className='!text-left'>Salesperson</th>
<th className='!text-left'>Total</th>
<th>Status</th>
@@ -439,8 +674,9 @@ const Transactions = ({ context = '' }) => {
<Pagination
pageCount={pageCount}
- currentPage={parseInt(page)}
- url={router.pathname + (pageQuery ? `?${pageQuery}` : '')}
+ currentPage={parseInt(pageNew)}
+ // url={router.pathname + (pageQuery ? `?${pageQuery}` : '')}
+ url={`/my/transactions?${toQuery(_.omit(query, ['page']))}`}
className='mt-2 mb-2'
/>
</div>