summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-08-27 13:16:59 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-08-27 13:16:59 +0700
commit3a9a0995dad8d3deb602534814a6bb79b26afb54 (patch)
tree388e769c108edc0f05d8f3bb79b9a6ec797935e9
parent22eec2b12a2f8a079018070efa28757401de308e (diff)
<Miqdad> Push Sementara
-rw-r--r--src/lib/transaction/components/Transactions.jsx615
1 files changed, 196 insertions, 419 deletions
diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index fab9eb5c..0d7e3f2c 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -1,11 +1,10 @@
import { useRouter } from 'next/router';
-import { useEffect, useState, useRef } from 'react';
+import { useEffect, useState, useRef } 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 {
@@ -38,13 +37,11 @@ import { Navigation } from 'swiper';
import 'swiper/css';
import 'swiper/css/navigation';
import { Calendar } from 'lucide-react';
-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';
+import 'react-date-range/dist/styles.css';
+import 'react-date-range/dist/theme/default.css';
+import { fetchPaymentSummary } from '../api/regenerate';
+
const Transactions = ({ context = '' }) => {
const auth = useAuth();
const router = useRouter();
@@ -59,14 +56,8 @@ const Transactions = ({ context = '' }) => {
startDate = null,
endDate = new Date(),
} = router.query;
- const {
- productCart,
- setRefreshCart,
- setProductCart,
- refreshCart,
- isLoading,
- setIsloading,
- } = useProductCartContext();
+ const { setRefreshCart } = useProductCartContext();
+
const [inputQuery, setInputQuery] = useState(q);
const [toOthers, setToOthers] = useState(null);
const [toCancel, setToCancel] = useState(null);
@@ -75,17 +66,16 @@ 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 [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 [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
- const [currentData, setCurrentData] = useState([]); // Data yang ditampilkan
+ const [cachedAllData, setCachedAllData] = useState(null);
+ const [currentData, setCurrentData] = useState([]);
const calendarRef = useRef(null);
- const [isDateSelected, setIsDateSelected] = useState(false);
+
+ // loading id utk tombol lanjutkan transaksi
+ const [contLoadingId, setContLoadingId] = useState(null);
const parseDate = (date) => {
if (!date || date === 'null') return null;
@@ -96,7 +86,7 @@ const Transactions = ({ context = '' }) => {
const [state, setState] = useState([
{
- startDate: startDate != null || 'null' ? parseDate(startDate) : null, // Gunakan `parseDate`
+ startDate: startDate != null || 'null' ? parseDate(startDate) : null,
endDate: startDate == null ? endDate : parseDate(endDate),
key: 'selection',
},
@@ -116,6 +106,7 @@ const Transactions = ({ context = '' }) => {
site:
siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
};
+
const statuses = [
{ id: 'all', label: 'Semua' },
{ id: 'quotation', label: 'Pending Quotation' },
@@ -142,16 +133,16 @@ const Transactions = ({ context = '' }) => {
{ 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,
- });
+ const isCancelled = await cancelTransactionApi({ transaction: toCancel });
if (isCancelled) {
toast.success('Berhasil batalkan transaksi');
transactions.refetch();
@@ -172,10 +163,7 @@ const Transactions = ({ context = '' }) => {
const queryParams = {};
if (inputQuery) queryParams.q = inputQuery;
if (siteFilter) queryParams.site = siteFilter;
- router.push({
- pathname: router.pathname,
- query: queryParams,
- });
+ router.push({ pathname: router.pathname, query: queryParams });
};
const handleSiteFilterChange = (e) => {
@@ -183,10 +171,7 @@ const Transactions = ({ context = '' }) => {
const queryParams = {};
if (inputQuery) queryParams.q = inputQuery;
if (e.target.value) queryParams.site = e.target.value;
- router.push({
- pathname: router.pathname,
- query: queryParams,
- });
+ router.push({ pathname: router.pathname, query: queryParams });
};
const exportToExcel = (data, siteFilter) => {
@@ -211,9 +196,7 @@ const Transactions = ({ context = '' }) => {
Total: currencyFormat(saleOrder.amountTotal),
Status: contextLabelMap[saleOrder.status] || saleOrder.status,
};
- if (siteFilter) {
- row['Site'] = siteFilter;
- }
+ if (siteFilter) row['Site'] = siteFilter;
rowsToExport.push(row);
});
@@ -226,13 +209,30 @@ const Transactions = ({ context = '' }) => {
XLSX.writeFile(workbook, 'transactions.xlsx');
};
+ const getAllData = async () => {
+ const query = {
+ name: q,
+ offset: (pageNew - 1) * limitNew,
+ limit: limitNew,
+ context: contextNew[statusNew] || 'all',
+ sort: sortNew,
+ startDate: state[0]?.startDate
+ ? state[0].startDate.toLocaleDateString('id-ID')
+ : null,
+ endDate: state[0]?.endDate
+ ? state[0].endDate.toLocaleDateString('id-ID')
+ : null,
+ site:
+ siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
+ };
+ const queryString = toQuery(query);
+ const data = await transactionsApi({ query: queryString });
+ return data;
+ };
+
const handleExportCSV = async () => {
const dataToExport = await getAllData();
- exportToCSV(dataToExport?.saleOrders, siteFilter);
- };
-
- const exportToCSV = (data, siteFilter) => {
const fieldsToExport = [
'No. Transaksi',
'No. PO',
@@ -242,28 +242,20 @@ const Transactions = ({ context = '' }) => {
'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),
- contextLabelMap[saleOrder.status] || saleOrder.status,
- ];
-
- if (siteFilter) {
- row.push(siteFilter);
- }
-
- return row.join(',');
- });
+ const rowsToExport =
+ dataToExport?.saleOrders?.map((saleOrder) => {
+ const row = [
+ saleOrder.name,
+ saleOrder.purchaseOrderName || '-',
+ saleOrder.dateOrder || '-',
+ saleOrder.address.customer?.name || '-',
+ saleOrder.sales,
+ currencyFormat(saleOrder.amountTotal),
+ contextLabelMap[saleOrder.status] || saleOrder.status,
+ ];
+ if (siteFilter) row.push(siteFilter);
+ return row.join(',');
+ }) || [];
const csvContent =
'data:text/csv;charset=utf-8,' +
@@ -278,60 +270,25 @@ const Transactions = ({ context = '' }) => {
document.body.removeChild(link);
};
- const getAllData = async () => {
- const query = {
- name: q,
- offset: (pageNew - 1) * limitNew,
- limit: limitNew,
- context: contextNew[statusNew] || 'all',
- sort: sortNew,
- startDate: state[0]?.startDate
- ? state[0].startDate.toLocaleDateString('id-ID')
- : null,
- endDate: state[0]?.endDate
- ? state[0].endDate.toLocaleDateString('id-ID')
- : null,
- 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);
+ if (format === 'csv') handleExportCSV();
+ else if (format === 'xlsx') handleExportExcel();
setIsOpen(false);
};
- const handleExport = (format) => {
- if (format === 'csv') {
- handleExportCSV();
- } else if (format === 'xlsx') {
- handleExportExcel();
- }
- };
-
useEffect(() => {
const handleClickOutside = (event) => {
- if (
- calendarRef.current &&
- !calendarRef.current.contains(event.target)
- ) {
+ if (calendarRef.current && !calendarRef.current.contains(event.target)) {
setIsOpenCalender(false);
}
};
-
- document.addEventListener("mousedown", handleClickOutside);
- return () => {
- document.removeEventListener("mousedown", handleClickOutside);
- };
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const startItem = 1 + (pageNew - 1) * limitNew;
@@ -346,9 +303,6 @@ const Transactions = ({ context = '' }) => {
const handleBuyBack = async (products) => {
try {
- // setStatus('loading');
- console.log("Products to add:", products);
-
const results = await Promise.all(
products.map((product) =>
upsertUserCart({
@@ -359,55 +313,44 @@ const Transactions = ({ context = '' }) => {
selected: true,
source: 'add_to_cart',
qtyAppend: true,
- }).catch(error => {
- return { error, product };
- })
+ }).catch((error) => ({ error, product }))
)
);
- const failedOperations = results.filter(result => result && result.error);
- // console.log(results);
-
+ const failedOperations = results.filter((r) => r && r.error);
if (failedOperations.length > 0) {
- console.error('Some products failed to add to cart:', failedOperations);
- toast.error(`${failedOperations.length} produk gagal ditambahkan ke keranjang`);
-
- // You might want to proceed with the successful ones or handle differently
+ toast.error(
+ `${failedOperations.length} produk gagal ditambahkan ke keranjang`
+ );
if (failedOperations.length < products.length) {
- toast.success(`${products.length - failedOperations.length} produk berhasil ditambahkan ke keranjang`);
+ toast.success(
+ `${
+ products.length - failedOperations.length
+ } produk berhasil ditambahkan`
+ );
setRefreshCart(true);
router.push('/shop/cart');
}
return;
}
-
- // All operations succeeded
setRefreshCart(true);
- toast.success('Semua produk berhasil ditambahkan ke keranjang belanja');
+ toast.success('Semua produk berhasil ditambahkan ke keranjang');
router.push('/shop/cart');
-
} catch (error) {
- console.error('Gagal menambahkan produk ke keranjang:', error);
toast.error('Terjadi kesalahan saat menambahkan produk ke keranjang');
- // setStatus('error');
}
};
-
const handleStatusChange = async (status) => {
setStatusNew(status);
setPageNew(1);
if (status === 'all' && cachedAllData) {
- setCurrentData(cachedAllData);
- return;
+ setCurrentData(cachedAllData);
+ return;
}
const data = await fetchSite(status, 1);
-
- if (status === 'all') {
- setCachedAllData(data);
- }
-
+ if (status === 'all') setCachedAllData(data);
setCurrentData(data);
};
@@ -415,15 +358,8 @@ const Transactions = ({ context = '' }) => {
setCachedAllData([]);
}, []);
-
const handleReset = () => {
- setState([
- {
- startDate: null,
- endDate: new Date(),
- key: 'selection',
- },
- ]);
+ setState([{ startDate: null, endDate: new Date(), key: 'selection' }]);
setIsOpenCalender(false);
router.push(`${router.pathname}`);
};
@@ -443,13 +379,68 @@ const Transactions = ({ context = '' }) => {
'November',
'Desember',
];
-
const [day, month, year] = dateString.split('/');
return `${day} ${months[parseInt(month, 10) - 1]} ${year}`;
};
+ // ==== Lanjutkan Transaksi ====
+ const handleContinuePayment = async (saleOrder) => {
+ try {
+ const partnerId =
+ auth?.partnerId || auth?.partner_id || auth?.partner?.id || auth?.id;
+
+ setContLoadingId(saleOrder.id);
+
+ // 1) coba pakai URL yang sudah dikirim dari list
+ const existingUrl =
+ saleOrder?.paymentSummary?.redirectUrl ||
+ saleOrder?.paymentLinkMidtrans;
+
+ if (existingUrl) {
+ window.open(existingUrl, '_blank', 'noopener,noreferrer');
+ toast.success('Membuka halaman pembayaran…');
+ return;
+ }
+
+ // 2) fallback: generate baru via API
+ const res = await fetchPaymentSummary({
+ partnerId,
+ saleOrderId: saleOrder.id,
+ autogen: true,
+ });
+
+ const eligible =
+ res?.eligible_continue ??
+ res?.eligibleContinue ??
+ res?.eligible ??
+ false;
+
+ if (!eligible) {
+ toast.error('Transaksi belum memenuhi syarat untuk dilanjutkan.');
+ return;
+ }
+
+ const redirectUrl = res?.redirect_url || res?.redirectUrl;
+ if (redirectUrl) {
+ window.open(redirectUrl, '_blank', 'noopener,noreferrer');
+ toast.success('Membuka halaman pembayaran…');
+ } else {
+ toast.error('Link pembayaran belum tersedia.');
+ }
+ } catch (e) {
+ const msg =
+ e?.response?.data?.description ||
+ e?.message ||
+ 'Gagal melanjutkan transaksi';
+ toast.error(msg);
+ } finally {
+ setContLoadingId(null);
+ }
+ };
+
return (
<>
+ {/* ===== MOBILE ===== */}
<MobileView>
<div className=' flex flex-col gap-y-4'>
<div className='grid grid-cols-[40%_40%_15%] justify-between items-center gap-2 w-full '>
@@ -491,7 +482,6 @@ const Transactions = ({ context = '' }) => {
</button>
{isOpenCalender && (
<div className='absolute right-1 mt-2 bg-white p-4 rounded shadow-lg z-50'>
- {/* Tombol silang di sudut kanan atas */}
<button
onClick={() => setIsOpenCalender(false)}
className='absolute top-2 right-2 text-gray-600 hover:text-black text-xl font-bold'
@@ -508,37 +498,13 @@ const Transactions = ({ context = '' }) => {
className='w-full'
/>
<style>{`
- /* Atur container agar menjadi column */
- .rdrCalendarWrapper {
- display: flex;
- flex-direction: column;
- }
- .rdrDateRangePickerWrapper {
- display: flex;
- flex-direction: column;
- }
-
- /* Pindahkan rdrStaticRanges ke atas */
- .rdrDefinedRangesWrapper {
- order: -1;
- width: fit-content;
- }
- .rdrStaticRanges {
- flex-direction: row;
- margin-right: 2px;
- }
-
- /* Sembunyikan bagian input manual */
- .rdrInputRanges {
- display: none !important;
- }
-
- .rdrStaticRangeLabel {
- padding: 10px 10px;
- }
- .rdrMonth {
- width: -moz-available;
- }
+ .rdrCalendarWrapper{display:flex;flex-direction:column;}
+ .rdrDateRangePickerWrapper{display:flex;flex-direction:column;}
+ .rdrDefinedRangesWrapper{order:-1;width:fit-content;}
+ .rdrStaticRanges{flex-direction:row;margin-right:2px;}
+ .rdrInputRanges{display:none !important;}
+ .rdrStaticRangeLabel{padding:10px 10px;}
+ .rdrMonth{width:-moz-available;}
`}</style>
<div className='flex flex-row justify-end gap-3 mt-2'>
<button
@@ -551,67 +517,6 @@ const Transactions = ({ context = '' }) => {
</div>
)}
</div>
- {/* <div className='border border-gray-300 rounded-lg px-1 py-1 bg-white shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 text-xs'>
- <DatePicker
- closeOnScroll={(e) => 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}
- />
- </div> */}
- </div>
- <div className='flex flex-row justify-between items-center gap-2'>
- <form className='flex' onSubmit={handleSubmit}>
- <button
- className='btn-light border-r-0 rounded-r-none bg-transparent px-3'
- type='submit'
- >
- <MagnifyingGlassIcon className='w-6' />
- </button>
- <input
- type='text'
- className='form-input border-l-0 rounded-l-none text-xs'
- placeholder='Cari Transaksi...'
- value={inputQuery}
- onChange={(e) => setInputQuery(e.target.value)}
- />
- </form>
- <div className='flex flex-row gap-2 items-center justify-center text-nowrap'>
- <p className='text-xs'>
- Menampilkan {startItem}-
- {endItem
- ? endItem
- : transactions?.data?.saleOrderTotal
- ? transactions?.data?.saleOrderTotal
- : limitNew * pageNew}{' '}
- dari{' '}
- {transactions?.data?.saleOrderTotal
- ? transactions?.data?.saleOrderTotal
- : limitNew * pageNew}
- </p>
- <select
- id='limitSelect'
- value={limitNew}
- onChange={(e) => {
- setLimitNew(Number(e.target.value));
- setPageNew(1);
- }}
- className='border p-2 text-xs'
- >
- <option value={10}>10</option>
- <option value={15}>15</option>
- <option value={20}>20</option>
- </select>
- </div>
</div>
{transactions.isLoading && (
@@ -683,9 +588,9 @@ const Transactions = ({ context = '' }) => {
<div className='flex flex-row gap-1 justify-start items-center'>
{saleOrder.products
.slice(1, 4)
- .map((product, index) => (
+ .map((product, idx) => (
<Image
- key={index} // Tambahkan key untuk setiap elemen dalam map()
+ key={idx}
src={product?.parent?.image}
alt={product?.name}
className='object-contain object-center border border-gray_r-6 h-8 w-8 rounded-md'
@@ -719,6 +624,7 @@ const Transactions = ({ context = '' }) => {
</div>
</div>
<div className='col-span-2 h-[1px] w-full bg-gray-300'></div>
+
<div className='flex flex-col gap-3 text-sm'>
<div className='flex flex-col text-black'>
<p className='font-extralight'>Total Harga</p>
@@ -727,7 +633,6 @@ const Transactions = ({ context = '' }) => {
</p>
</div>
- {/* Tombol aksi: vertikal & full width, responsif */}
<div className='flex flex-col gap-2 w-full'>
<button
type='button'
@@ -741,53 +646,24 @@ const Transactions = ({ context = '' }) => {
Beli Lagi
</button>
- <button
- type='button'
- onClick={(e) => {
- e.preventDefault();
- e.stopPropagation();
- }}
- className='w-full py-2 text-center rounded-md border border-red-300 text-red-500 bg-white'
- >
- Lanjutkan Transaksi
- </button>
+ {saleOrder?.eligibleContinue && (
+ <button
+ type='button'
+ disabled={contLoadingId === saleOrder.id}
+ onClick={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ handleContinuePayment(saleOrder);
+ }}
+ className='w-full py-2 text-center rounded-md border border-red-300 text-red-500 bg-white disabled:opacity-60'
+ >
+ {contLoadingId === saleOrder.id
+ ? 'Memproses…'
+ : 'Lanjutkan Transaksi'}
+ </button>
+ )}
</div>
</div>
-
- {/* <div className='grid grid-cols-2 mt-3'>
- <div>
- <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>
- <p className='mt-1 font-medium text-gray_r-12'>
- {saleOrder.invoiceCount} Invoice
- </p>
- </div>
- </div> */}
- {/* <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>
- </div>
- <div className='text-right'>
- <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>
- </div>
- </div> */}
</Link>
</div>
))}
@@ -795,7 +671,6 @@ const Transactions = ({ context = '' }) => {
<Pagination
pageCount={pageCount}
currentPage={parseInt(pageNew)}
- // url={router.pathname + pageQuery}
url={`${router.pathname}?${toQuery(_.omit(query, ['page']))}`}
className='mt-2 mb-2'
/>
@@ -868,6 +743,7 @@ const Transactions = ({ context = '' }) => {
</div>
</MobileView>
+ {/* ===== DESKTOP ===== */}
<DesktopView>
<div className='container mx-auto flex py-10'>
<div className='w-3/12 pr-4'>
@@ -920,29 +796,7 @@ const Transactions = ({ context = '' }) => {
)}
</div>
</div>
- <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'>
- Gunakan filter status untuk mempermudah pencarian transaksi
- anda di Daftar Transaksi
- </span>
- </div>
- </div>
- </div>
+
<div className='flex flex-col gap-y-2 border rounded-lg mb-2 w-full'>
<div className='p-2'>
<div className='flex items-center space-x-3'>
@@ -950,9 +804,7 @@ const Transactions = ({ context = '' }) => {
Status
</span>
<div className='relative w-full overflow-hidden'>
- {/* Container flex: tombol prev - swiper - tombol next */}
<div className='flex items-center space-x-2'>
- {/* Prev */}
<button className='custom-prev w-8 h-8 flex-shrink-0 flex items-center justify-center bg-white border rounded-full shadow z-1'>
<svg
className='w-4 h-4 text-gray-500'
@@ -969,7 +821,6 @@ const Transactions = ({ context = '' }) => {
</svg>
</button>
- {/* Swiper container scrollable */}
<div className='w-full overflow-hidden'>
<Swiper
spaceBetween={10}
@@ -999,7 +850,6 @@ const Transactions = ({ context = '' }) => {
</Swiper>
</div>
- {/* Next */}
<button className='custom-next w-8 h-8 flex-shrink-0 flex items-center justify-center bg-white border rounded-full shadow z-10'>
<svg
className='w-4 h-4 text-gray-500'
@@ -1019,6 +869,7 @@ const Transactions = ({ context = '' }) => {
</div>
</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 ? (
@@ -1054,6 +905,7 @@ const Transactions = ({ context = '' }) => {
</button>
</form>
</div>
+
<div className='flex flex-row gap-4 items-center justify-center'>
<p>
Menampilkan {startItem}-
@@ -1083,6 +935,7 @@ const Transactions = ({ context = '' }) => {
Semua
</option>
</select>
+
<div ref={calendarRef} className='relative inline-block'>
<button
type='button'
@@ -1099,7 +952,6 @@ const Transactions = ({ context = '' }) => {
</button>
{isOpenCalender && (
<div className='absolute right-10 mt-2 bg-white p-4 rounded shadow-lg z-50'>
- {/* Tombol silang di sudut kanan atas */}
<button
onClick={() => setIsOpenCalender(false)}
className='absolute top-2 right-2 text-gray-600 hover:text-black text-xl font-bold'
@@ -1116,38 +968,14 @@ const Transactions = ({ context = '' }) => {
className='w-full'
/>
<style>{`
- /* Atur container agar menjadi column */
- .rdrCalendarWrapper {
- display: flex;
- flex-direction: column;
- }
- .rdrDateRangePickerWrapper {
- display: flex;
- flex-direction: column;
- }
-
- /* Pindahkan rdrStaticRanges ke atas */
- .rdrDefinedRangesWrapper {
- order: -1;
- width: fit-content;
- }
- .rdrStaticRanges {
- flex-direction: row;
- margin-right: 2px;
- }
-
- /* Sembunyikan bagian input manual */
- .rdrInputRanges {
- display: none !important;
- }
-
- .rdrStaticRangeLabel {
- padding: 10px 10px;
- }
- .rdrMonth {
- width: -moz-available;
- }
- `}</style>
+ .rdrCalendarWrapper{display:flex;flex-direction:column;}
+ .rdrDateRangePickerWrapper{display:flex;flex-direction:column;}
+ .rdrDefinedRangesWrapper{order:-1;width:fit-content;}
+ .rdrStaticRanges{flex-direction:row;margin-right:2px;}
+ .rdrInputRanges{display:none !important;}
+ .rdrStaticRangeLabel{padding:10px 10px;}
+ .rdrMonth{width:-moz-available;}
+ `}</style>
<div className='flex flex-row justify-end gap-3 mt-2'>
<button
className='px-4 py-1 bg-red-500 text-white rounded'
@@ -1162,6 +990,7 @@ const Transactions = ({ context = '' }) => {
</div>
</div>
</div>
+
<div className='flex justify-center items-center'>
{!transactions.isLoading &&
transactions?.data?.saleOrders?.length == 0 && (
@@ -1199,11 +1028,9 @@ const Transactions = ({ context = '' }) => {
<p className='text-red-500'>{saleOrder.name}</p>
<p className='text-black'>
Salesperson:{' '}
- {
- <span className='font-semibold'>
- {saleOrder.sales}
- </span>
- }
+ <span className='font-semibold'>
+ {saleOrder.sales}
+ </span>
</p>
</div>
<div className='text-black'>
@@ -1215,7 +1042,9 @@ const Transactions = ({ context = '' }) => {
</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-3/4 flex-col gap-2'>
<div className='flex gap-2'>
@@ -1250,9 +1079,9 @@ const Transactions = ({ context = '' }) => {
<div className='flex flex-row gap-1 justify-start items-center'>
{saleOrder.products
.slice(1, 4)
- .map((product, index) => (
+ .map((product, idx) => (
<Image
- key={index} // Tambahkan key untuk setiap elemen dalam map()
+ key={idx}
src={product?.parent?.image}
alt={product?.name}
className='object-contain object-center border border-gray_r-6 h-16 w-16 rounded-md'
@@ -1288,7 +1117,9 @@ const Transactions = ({ context = '' }) => {
</p>
</div>
</div>
+
<div className='w-[1px] h-24 bg-gray-300'></div>
+
<div className='w-1/4 flex flex-col gap-2 items-end justify-center'>
<div className='flex flex-col text-black w-full'>
<p>Total Harga</p>
@@ -1309,16 +1140,22 @@ const Transactions = ({ context = '' }) => {
Beli Lagi
</button>
- <button
- type='button'
- onClick={(e) => {
- e.preventDefault();
- e.stopPropagation();
- }}
- className='w-full py-2 btn-light text-nowrap border border-red-500 text-red-500 rounded-md'
- >
- Lanjutkan Transaksi
- </button>
+ {saleOrder?.eligibleContinue && (
+ <button
+ type='button'
+ disabled={contLoadingId === saleOrder.id}
+ onClick={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ handleContinuePayment(saleOrder);
+ }}
+ className='w-full py-2 btn-light text-nowrap border border-red-500 text-red-500 rounded-md disabled:opacity-60'
+ >
+ {contLoadingId === saleOrder.id
+ ? 'Memproses…'
+ : 'Lanjutkan Transaksi'}
+ </button>
+ )}
</div>
</div>
</Link>
@@ -1327,70 +1164,10 @@ const Transactions = ({ context = '' }) => {
</div>
)}
</div>
- {/* <table className='table-data'>
- <thead>
- <tr>
- <th>No. Transaksi</th>
- <th>No. PO</th>
- <th>Tanggal</th>
- <th>Created By</th>
- {auth?.feature?.soApproval && <th>Site</th>}
- <th className='!text-left'>Salesperson</th>
- <th className='!text-left'>Total</th>
- <th>Status</th>
- </tr>
- </thead>
- <tbody>
- {transactions.isLoading && (
- <tr>
- <td colSpan={7}>
- <div className='flex justify-center my-2'>
- <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
- </div>
- </td>
- </tr>
- )}
- {!transactions.isLoading &&
- (!transactions?.data?.saleOrders ||
- transactions?.data?.saleOrders?.length == 0) && (
- <tr>
- <td colSpan={7}>Tidak ada transaksi</td>
- </tr>
- )}
- {transactions.data?.saleOrders?.map((saleOrder) => (
- <tr key={saleOrder.id}>
- <td>
- <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>
- {auth?.feature?.soApproval && (
- <td>{saleOrder.sitePartner || '-'}</td>
- )}
- <td className='!text-left'>{saleOrder.sales}</td>
- <td className='!text-left'>
- {currencyFormat(saleOrder.amountTotal)}
- </td>
- <td>
- <div className='flex justify-center'>
- <TransactionStatusBadge status={saleOrder.status} />
- </div>
- </td>
- </tr>
- ))}
- </tbody>
- </table> */}
<Pagination
pageCount={pageCount}
currentPage={parseInt(pageNew)}
- // url={router.pathname + (pageQuery ? `?${pageQuery}` : '')}
url={`${router.pathname}?${toQuery(_.omit(query, ['page']))}`}
className='mt-2 mb-2'
/>