diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2025-03-03 16:38:10 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2025-03-03 16:38:10 +0700 |
| commit | faf6403595602d78b502acfacc721923addbf4a8 (patch) | |
| tree | bb0ce17c3a8d4fe36f9ebc547b33354156673ae7 /src/lib/transaction/components | |
| parent | cd072c875c334b1140e4f797a37a9e991d53e2b5 (diff) | |
<iman> update code
Diffstat (limited to 'src/lib/transaction/components')
| -rw-r--r-- | src/lib/transaction/components/Transactions.jsx | 487 |
1 files changed, 337 insertions, 150 deletions
diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx index a8685105..64ae9393 100644 --- a/src/lib/transaction/components/Transactions.jsx +++ b/src/lib/transaction/components/Transactions.jsx @@ -31,11 +31,30 @@ 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'; const Transactions = ({ context = '' }) => { const auth = useAuth(); const router = useRouter(); - const { q = '', page = 1, site = null, limit = 15 } = router.query; - + const { + q = '', + page = 1, + site = null, + limit = 15, + status = 'all', + } = router.query; + const { + productCart, + setRefreshCart, + setProductCart, + refreshCart, + isLoading, + setIsloading, + } = useProductCartContext(); + console.log('context', context); + console.log('router.query', router.query); const [inputQuery, setInputQuery] = useState(q); const [toOthers, setToOthers] = useState(null); const [toCancel, setToCancel] = useState(null); @@ -44,16 +63,32 @@ const Transactions = ({ context = '' }) => { 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 [contextNew, setcontextNew] = useState(router.query.context || context); const query = { name: q, offset: (pageNew - 1) * limitNew, - context, + context: contextNew, limit: limitNew, + status: statusNew, 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' }, + ]; + + console.log('query', query); const { transactions } = useTransactions({ query }); - console.log('transactions', transactions); + // console.log('transactions', transactions); const fetchSite = async () => { const site = await getSite(); setListSites(site.sites); @@ -229,6 +264,67 @@ const Transactions = ({ context = '' }) => { 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, + }) + ) + ); + + // console.log(`Produk berhasil dimasukkan ke dalam cart`, results); + + // ✅ 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('/my/transactions'); + } + }; + return ( <> <MobileView> @@ -445,66 +541,126 @@ const Transactions = ({ context = '' }) => { )} </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} - onChange={handleSiteFilterChange} - className='form-input' + <div className=''> + <div + class='flex items-center p-4 mb-4 text-sm border border-yellow-500 text-yellow-800 rounded-lg bg-yellow-50' + role='alert' + > + <svg + class='flex-shrink-0 inline w-5 h-5 mr-2' + aria-hidden='true' + fill='currentColor' + viewBox='0 0 20 20' + > + <path d='M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z' /> + </svg> + <span class='sr-only'>Info</span> + <div className='text-justify flex flex-col gap-1'> + <p className='font-bold text-black'>Info Transaksi</p> + <span className='text-black'> + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut labore et dolore magna + aliqua. + </span> + </div> + </div> + </div> + <div className='flex flex-col gap-y-2 border rounded mb-2'> + <div className='p-2'> + <div className='flex items-center space-x-3'> + <span className='text-sm font-medium text-gray-600'> + Status + </span> + <Swiper + spaceBetween={10} + slidesPerView={5.25} + className='w-full h-8' > - <option value=''>Pilih Site</option> - {listSites.map((site) => ( - <option value={site} key={site}> - {site} - </option> + {statuses.map((status) => ( + <SwiperSlide key={status.id} className='w-auto'> + <button + className={`px-4 py-1 text-sm font-medium border rounded-lg transition whitespace-nowrap min-w-40 + ${ + statusNew === status.id + ? 'border-red-500 text-red-500 bg-white' + : 'border-gray-300 text-gray-400 bg-gray-100 hover:bg-gray-200' + }`} + onClick={() => handleStatusChange(status.id)} + > + {status.label} + </button> + </SwiperSlide> ))} - </select> - ) : ( - <div></div> - )} + </Swiper> + </div> + </div> + <div className='flex flex-row items-center justify-between mb-2 p-2'> + <div className='flex flex-col gap-2 pb-2'> + {listSites?.length > 0 ? ( + <select + value={siteFilter} + onChange={handleSiteFilterChange} + className='form-input' + > + <option value=''>Pilih Site</option> + {listSites.map((site) => ( + <option value={site} key={site}> + {site} + </option> + ))} + </select> + ) : ( + <div></div> + )} - <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' + <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 className='flex flex-row gap-4 items-center justify-center'> + <p> + Menampilkan {startItem}- + {endItem + ? endItem + : transactions?.data?.saleOrderTotal + ? transactions?.data?.saleOrderTotal + : limitNew}{' '} + dari{' '} + {transactions?.data?.saleOrderTotal + ? transactions?.data?.saleOrderTotal + : limitNew} + </p> + <select + id='limitSelect' + value={limitNew} + onChange={(e) => { + setLimitNew(Number(e.target.value)); + setPageNew(1); + }} + className='border p-2' > - <MagnifyingGlassIcon className='w-6' /> - </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> + <option value={10}>10</option> + <option value={15}>15</option> + <option value={20}>20</option> + </select> + </div> </div> </div> - <div className='flex'> + <div className='flex justify-center items-center'> {!transactions.isLoading && - (!transactions?.data?.saleOrders || - transactions?.data?.saleOrders?.length == 0) && ( + transactions?.data?.saleOrders?.length == 0 && ( <div className='justify-center p-4'> <p className='text-gray-500 text-center '> Tidak Ada Transaksi @@ -512,107 +668,138 @@ const Transactions = ({ context = '' }) => { </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:{' '} - { + {transactions.isLoading && ( + <div className='flex justify-center items-center my-2'> + <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' /> + </div> + )} + + {!transactions.isLoading && + 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 className='text-black'> + Salesperson:{' '} + { + <span className='font-semibold'> + {saleOrder.sales} + </span> + } + </p> + </div> + <div className='text-black'> + Tanggal Pesanan:{' '} <span className='font-semibold'> - {saleOrder.sales} + {saleOrder.dateOrder.split(' ')[0] || '-'} </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> + <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-3/4 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 text-black'> + 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, 6) + .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 text-black'> + <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/4 flex flex-row gap-3 justify-center items-center'> + <div className='flex flex-col text-black'> + <p>Total Harga</p> + <p className='font-bold'> + {currencyFormat(saleOrder.amountTotal)} + </p> + </div> + <div> + <button + type='button' + onClick={() => + handleBuyBack(saleOrder.products) + } + className='flex-1 py-2 btn-solid-red text-nowrap' + > + Beli Lagi + </button> </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> + </Link> </div> - {/* </Link> */} - </div> - ))} - </div> - )} + ))} + </div> + )} </div> - <table className='table-data'> + {/* <table className='table-data'> <thead> <tr> <th>No. Transaksi</th> @@ -670,7 +857,7 @@ const Transactions = ({ context = '' }) => { </tr> ))} </tbody> - </table> + </table> */} <Pagination pageCount={pageCount} |
