import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; 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, } 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'; import getSite from '../api/listSiteApi'; import transactionsApi from '../api/transactionsApi'; import { motion } from 'framer-motion'; import Image from '@/core/components/elements/Image/Image'; import { upsertUserCart } from '~/services/cart'; import { useProductCartContext } from '@/contexts/ProductCartContext'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import { DateRangePicker } from 'react-date-range'; import { addDays } from 'date-fns'; import 'react-date-range/dist/styles.css'; // main style file import 'react-date-range/dist/theme/default.css'; // theme css file import { Popover } from '@headlessui/react'; const Transactions = ({ context = '' }) => { const auth = useAuth(); const router = useRouter(); const { q = '', page = 1, site = null, limit = 15, status = 'all', sort = 'none', startDate = null, endDate = new Date(), } = router.query; const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading, } = useProductCartContext(); 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 [status, setStatus] = useState('idle'); const [statusNew, setStatusNew] = useState(status); const [sortNew, setSortNew] = useState(sort); const [contextNew, setcontextNew] = useState(router.query.context || context); const [dateRange, setDateRange] = useState([null, null]); // const [startDate, endDate] = dateRange; const [isOpenCalender, setIsOpenCalender] = useState(false); const parseDate = (date) => { if (null || 'null') return null; if (!date) return null; if (date instanceof Date) return date; // Jika sudah Date, langsung return const [day, month, year] = date.split('/').map(Number); return new Date(year, month - 1, day); }; const [state, setState] = useState([ { startDate: startDate != null || 'null' ? parseDate(startDate) : null, // Gunakan `parseDate` endDate: startDate == null ? endDate : parseDate(endDate), key: 'selection', }, ]); const query = { name: q, offset: (pageNew - 1) * limitNew, context: contextNew, limit: limitNew, status: statusNew, sort: sortNew, startDate: state[0].startDate ? state[0].startDate.toLocaleDateString('id-ID') : state[0].startDate, endDate: state[0]?.endDate?.toLocaleDateString('id-ID'), site: siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null), }; const statuses = [ { id: 'all', label: 'Semua' }, { id: 'quotation', label: 'Pending Quotation' }, { id: 'diterima', label: 'Pesanan Diterima' }, { id: 'diproses', label: 'Pesanan Diproses' }, { id: 'dikirim', label: 'Pesanan Dikirim' }, { id: 'selesai', label: 'Pesanan Selesai' }, { id: 'cancel', label: 'Pesanan Dibatalkan' }, ]; const sortes = [ { id: 'none', label: 'Urutkan' }, { id: 'asc', label: 'dari yang terkecil' }, { id: 'desc', label: 'dari yang terbesar' }, ]; const { transactions } = useTransactions({ query }); const fetchSite = async () => { const site = await getSite(); setListSites(site.sites); }; const submitCancelTransaction = async () => { const isCancelled = await cancelTransactionApi({ transaction: toCancel, }); if (isCancelled) { toast.success('Berhasil batalkan transaksi'); transactions.refetch(); } setToCancel(null); }; const pageCount = Math.ceil(transactions?.data?.saleOrderTotal / limitNew); 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(); 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 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, context, site: siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null), }; const queryString = toQuery(query); const data = await transactionsApi({ query: queryString }); return data; }; const handleExportExcel = async () => { const dataToExport = await getAllData(); 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(); }, []); const handleBuyBack = async (products) => { // if (status === 'success') return; try { // setStatus('loading'); const results = await Promise.all( products.map((product) => upsertUserCart({ userId: auth.id, type: 'product', id: product.id, qty: product.quantity, selected: true, source: 'buy', // Tetap gunakan 'buy' agar bisa masuk ke halaman pembelian qtyAppend: false, }) ) ); // ✅ Panggil setRefreshCart(true) setiap kali satu produk berhasil ditambahkan setRefreshCart(true); // setStatus('idle'); toast.success('Semua produk berhasil ditambahkan ke keranjang belanja'); // Tampilkan notifikasi // toast({ // title: 'Tambah ke keranjang', // description: 'Semua produk berhasil ditambahkan ke keranjang belanja', // status: 'success', // duration: 3000, // isClosable: true, // position: 'top', // }); // Redirect ke halaman checkout router.push('/shop/checkout?source=buy'); } catch (error) { console.error('Gagal menambahkan produk ke keranjang:', error); // setStatus('error'); } }; const handleStatusChange = (status) => { setStatusNew(status); if (['quotation', 'cancel', 'diterima', ''].includes(status)) { setcontextNew('quotation'); } else { setcontextNew(''); } if (status === 'all') { router.push(`${router.pathname}`); } else { setPageNew(1); } }; const handleReset = () => { setState([ { startDate: null, endDate: new Date(), key: 'selection', }, ]); setIsOpenCalender(false); router.push(`${router.pathname}`); }; const formatDate = (dateString) => { const months = [ 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember', ]; const [day, month, year] = dateString.split('/'); return `${day} ${months[parseInt(month, 10) - 1]} ${year}`; }; return ( <>
setIsOpenCalender(true)} > {state[0]?.startDate ? `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}` : 'Semua Tanggal'}
{isOpenCalender && (
setState([item.selection])} showSelectionPreview={true} maxDate={new Date()} moveRangeOnFirstSelection={false} months={1} ranges={state} direction='horizontal' className='w-full' />
)}
{/*
e.target === document} selectsRange={true} startDate={startDate} endDate={endDate} dateFormat='dd/MM' className='w-full' maxDate={new Date()} placeholderText='Semua Tanggal' onChange={(update) => { setDateRange(update); }} withPortal isClearable={true} />
*/}
setInputQuery(e.target.value)} />

Menampilkan {startItem}- {endItem ? endItem : transactions?.data?.saleOrderTotal ? transactions?.data?.saleOrderTotal : limitNew * pageNew}{' '} dari{' '} {transactions?.data?.saleOrderTotal ? transactions?.data?.saleOrderTotal : limitNew * pageNew}

{transactions.isLoading && (
)} {!transactions.isLoading && transactions.data?.saleOrders?.length === 0 && ( Tidak ada transaksi )} {transactions.data?.saleOrders?.map((saleOrder, index) => (

{saleOrder.name}

{formatDate(saleOrder.dateOrder.split(' ')[0]) || '-'}
setToOthers(saleOrder)} />
{saleOrder.products[0]?.name}

Nomor PO: {saleOrder.purchaseOrderName || '-'}

{saleOrder.products[0]?.parent?.name}

{saleOrder.products[0]?.quantity} x{' '} {currencyFormat( saleOrder.products[0]?.price?.priceDiscount )}

{saleOrder.products?.length > 1 && (
{saleOrder.products .slice(1, 6) .map((product, index) => ( {product?.name} ))} {saleOrder.products?.length > 6 ? 'Lihat ' + (saleOrder.products?.length - 6) + ' produk lainnya' : 'Lihat semua produk'}
)}
Pesanan dibuat oleh:

{saleOrder.address.customer?.name || '-'}

Total Harga

{currencyFormat(saleOrder.amountTotal)}

{/*
No. Purchase Order

{saleOrder.purchaseOrderName || '-'}

Total Invoice

{saleOrder.invoiceCount} Invoice

*/} {/*
Sales

{saleOrder.sales}

Total Harga

{currencyFormat(saleOrder.amountTotal)}

*/}
))} setToOthers(null)} >
setToCancel(null)} title='Batalkan Transaksi' >
Apakah anda yakin membatalkan transaksi{' '} {toCancel?.name}?

Daftar Transaksi{' '} {transactions?.data?.saleOrders ? `(${transactions?.data?.saleOrderTotal})` : ''}

{isOpen && ( )}
Status {statuses.map((status) => ( ))}
{listSites?.length > 0 ? ( ) : (
)}
setInputQuery(e.target.value)} />

Menampilkan {startItem}- {endItem ? endItem : transactions?.data?.saleOrderTotal ? transactions?.data?.saleOrderTotal : limitNew * pageNew}{' '} dari{' '} {transactions?.data?.saleOrderTotal ? transactions?.data?.saleOrderTotal : limitNew * pageNew}

{!transactions.isLoading && transactions?.data?.saleOrders?.length == 0 && (

Tidak Ada Transaksi

)} {transactions.isLoading && (
)} {!transactions.isLoading && transactions && transactions.data?.saleOrders?.length > 0 && (
{transactions.data.saleOrders.map((saleOrder, index) => (

{saleOrder.name}

Salesperson:{' '} { {saleOrder.sales} }

Tanggal Pesanan:{' '} {formatDate( saleOrder.dateOrder.split(' ')[0] ) || '-'}

{saleOrder.products[0]?.name}

Nomor PO: {saleOrder.purchaseOrderName || '-'}

{saleOrder.products[0]?.parent?.name}

{saleOrder.products[0]?.quantity} x{' '} {currencyFormat( saleOrder.products[0]?.price ?.priceDiscount )}

{saleOrder.products?.length > 1 && (
{saleOrder.products .slice(1, 6) .map((product, index) => ( {product?.name} ))} {saleOrder.products?.length > 6 ? 'Lihat ' + (saleOrder.products?.length - 6) + ' produk lainnya' : 'Lihat semua produk'}
)}
Pesanan dibuat oleh:

{saleOrder.address.customer?.name || '-'}

Total Harga

{currencyFormat(saleOrder.amountTotal)}

))}
)}
{/* {auth?.feature?.soApproval && } {transactions.isLoading && ( )} {!transactions.isLoading && (!transactions?.data?.saleOrders || transactions?.data?.saleOrders?.length == 0) && ( )} {transactions.data?.saleOrders?.map((saleOrder) => ( {auth?.feature?.soApproval && ( )} ))}
No. Transaksi No. PO Tanggal Created BySiteSalesperson Total Status
Tidak ada transaksi
{saleOrder.name} {saleOrder.purchaseOrderName || '-'} {saleOrder.dateOrder || '-'} {saleOrder.address.customer?.name || '-'}{saleOrder.sitePartner || '-'}{saleOrder.sales} {currencyFormat(saleOrder.amountTotal)}
*/}
); }; export default Transactions;