From 22eec2b12a2f8a079018070efa28757401de308e Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Wed, 27 Aug 2025 10:35:35 +0700
Subject: <Miqdad> Button

---
 src/lib/transaction/components/Transactions.jsx | 260 ++++++++++++++----------
 1 file changed, 158 insertions(+), 102 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 7efa773a..fab9eb5c 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -475,21 +475,21 @@ const Transactions = ({ context = '' }) => {
                 </option>
               ))}
             </select>
-            <div ref={calendarRef} className="relative inline-block">
-                <button
-                  type='button'
-                  className='p-1 w-full h-auto cursor-pointer border hover:bg-gray-100 rounded transition duration-150 ease-in-out flex items-center justify-center'
-                  onClick={() => setIsOpenCalender((prev) => !prev)}
-                >
-                  <span className='text-nowrap px-1 truncate flex items-center gap-1'>
-                      {state[0]?.startDate ? (
-                        `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
-                      ) : (
-                        <Calendar size={20} className="text-gray-500" />
-                      )}
-                  </span>
-                </button>
-                {isOpenCalender && (
+            <div ref={calendarRef} className='relative inline-block'>
+              <button
+                type='button'
+                className='p-1 w-full h-auto cursor-pointer border hover:bg-gray-100 rounded transition duration-150 ease-in-out flex items-center justify-center'
+                onClick={() => setIsOpenCalender((prev) => !prev)}
+              >
+                <span className='text-nowrap px-1 truncate flex items-center gap-1'>
+                  {state[0]?.startDate ? (
+                    `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
+                  ) : (
+                    <Calendar size={20} className='text-gray-500' />
+                  )}
+                </span>
+              </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
@@ -549,8 +549,8 @@ const Transactions = ({ context = '' }) => {
                     </button>
                   </div>
                 </div>
-                )}
-              </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}
@@ -634,7 +634,9 @@ const Transactions = ({ context = '' }) => {
             >
               <div className='flex flex-row justify-between items-start'>
                 <Link href={`${router.pathname}/${saleOrder.id}`}>
-                  <h2 className='text-danger-500 text-base'>{saleOrder.name}</h2>
+                  <h2 className='text-danger-500 text-base'>
+                    {saleOrder.name}
+                  </h2>
                   <span className='font-medium text-black opacity-75'>
                     {formatDate(saleOrder.dateOrder.split(' ')[0]) || '-'}
                   </span>
@@ -690,20 +692,21 @@ const Transactions = ({ context = '' }) => {
                               />
                             ))}
                           {saleOrder.products.length > 4 ? (
-                              <Link
-                                href={`${router.pathname}/${saleOrder?.id}`}
-                                className='text-red-500 text-nowrap'
-                              >
-                                +{saleOrder.products.length - 4} lihat semua produk
-                              </Link>
-                            ) : (
-                              <Link
-                                href={`${router.pathname}/${saleOrder?.id}`}
-                                className='text-red-500 text-nowrap'
-                              >
-                                Lihat semua produk
-                              </Link>
-                            )}
+                            <Link
+                              href={`${router.pathname}/${saleOrder?.id}`}
+                              className='text-red-500 text-nowrap'
+                            >
+                              +{saleOrder.products.length - 4} lihat semua
+                              produk
+                            </Link>
+                          ) : (
+                            <Link
+                              href={`${router.pathname}/${saleOrder?.id}`}
+                              className='text-red-500 text-nowrap'
+                            >
+                              Lihat semua produk
+                            </Link>
+                          )}
                         </div>
                       )}
                     </div>
@@ -716,21 +719,38 @@ const Transactions = ({ context = '' }) => {
                   </div>
                 </div>
                 <div className='col-span-2 h-[1px] w-full bg-gray-300'></div>
-                <div className='flex flex-row gap-3 justify-between items-center text-sm'>
-                  <div className='flex flex-col text-black text-xs'>
-                    <p className='font-extralight text-sm'>Total Harga</p>
+                <div className='flex flex-col gap-3 text-sm'>
+                  <div className='flex flex-col text-black'>
+                    <p className='font-extralight'>Total Harga</p>
                     <p className='font-semibold text-lg'>
                       {currencyFormat(saleOrder.amountTotal)}
                     </p>
                   </div>
-                  <div>
+
+                  {/* Tombol aksi: vertikal & full width, responsif */}
+                  <div className='flex flex-col gap-2 w-full'>
                     <button
                       type='button'
-                      onClick={() => handleBuyBack(saleOrder.products)}
-                      className='flex-1 py-2 btn-solid-red text-nowrap'
+                      onClick={(e) => {
+                        e.preventDefault();
+                        e.stopPropagation();
+                        handleBuyBack(saleOrder.products);
+                      }}
+                      className='w-full py-2 btn-solid-red text-center rounded-md'
                     >
                       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>
                   </div>
                 </div>
 
@@ -917,7 +937,8 @@ const Transactions = ({ context = '' }) => {
                 <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
+                    Gunakan filter status untuk mempermudah pencarian transaksi
+                    anda di Daftar Transaksi
                   </span>
                 </div>
               </div>
@@ -928,23 +949,32 @@ const Transactions = ({ context = '' }) => {
                   <span className='text-base font-semibold text-gray-600'>
                     Status
                   </span>
-                  <div className="relative w-full overflow-hidden">
+                  <div className='relative w-full overflow-hidden'>
                     {/* Container flex: tombol prev - swiper - tombol next */}
-                    <div className="flex items-center space-x-2">
-                      
+                    <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" fill="none" stroke="currentColor" viewBox="0 0 24 24">
-                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
+                      <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'
+                          fill='none'
+                          stroke='currentColor'
+                          viewBox='0 0 24 24'
+                        >
+                          <path
+                            strokeLinecap='round'
+                            strokeLinejoin='round'
+                            strokeWidth={2}
+                            d='M15 19l-7-7 7-7'
+                          />
                         </svg>
                       </button>
 
                       {/* Swiper container scrollable */}
-                      <div className="w-full overflow-hidden">
+                      <div className='w-full overflow-hidden'>
                         <Swiper
                           spaceBetween={10}
-                          slidesPerView="auto"
-                          className="status-swiper"
+                          slidesPerView='auto'
+                          className='status-swiper'
                           modules={[Navigation]}
                           navigation={{
                             nextEl: '.custom-next',
@@ -952,12 +982,13 @@ const Transactions = ({ context = '' }) => {
                           }}
                         >
                           {statuses.map((status) => (
-                            <SwiperSlide key={status.id} className="!w-auto">
+                            <SwiperSlide key={status.id} className='!w-auto'>
                               <button
                                 className={`px-4 py-1 text-sm font-medium border rounded-lg transition whitespace-nowrap
-                                  ${statusNew === status.id
-                                    ? 'border-red-500 text-red-500 bg-white'
-                                    : 'border-gray-300 text-gray-400 bg-gray-100 hover:bg-gray-200'
+                                  ${
+                                    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)}
                               >
@@ -969,9 +1000,19 @@ const Transactions = ({ context = '' }) => {
                       </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" fill="none" stroke="currentColor" viewBox="0 0 24 24">
-                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
+                      <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'
+                          fill='none'
+                          stroke='currentColor'
+                          viewBox='0 0 24 24'
+                        >
+                          <path
+                            strokeLinecap='round'
+                            strokeLinejoin='round'
+                            strokeWidth={2}
+                            d='M9 5l7 7-7 7'
+                          />
                         </svg>
                       </button>
                     </div>
@@ -1038,41 +1079,43 @@ const Transactions = ({ context = '' }) => {
                     <option value={10}>10</option>
                     <option value={15}>15</option>
                     <option value={20}>20</option>
-                    <option value={transactions?.data?.saleOrderTotal}>Semua</option>
+                    <option value={transactions?.data?.saleOrderTotal}>
+                      Semua
+                    </option>
                   </select>
-                  <div ref={calendarRef} className="relative inline-block">
+                  <div ref={calendarRef} className='relative inline-block'>
                     <button
                       type='button'
                       className='p-2 w-auto h-auto cursor-pointer border hover:bg-gray-100 rounded transition duration-150 ease-in-out flex items-center justify-center'
                       onClick={() => setIsOpenCalender((prev) => !prev)}
                     >
                       <span className='text-nowrap px-1 truncate flex items-center gap-1'>
-                          {state[0]?.startDate ? (
-                            `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
-                          ) : (
-                            <Calendar size={16} className="text-gray-500" />
-                          )}
+                        {state[0]?.startDate ? (
+                          `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
+                        ) : (
+                          <Calendar size={16} className='text-gray-500' />
+                        )}
                       </span>
                     </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'
-                      >
-                        &times;
-                      </button>
-                      <DateRangePicker
-                        onChange={(item) => setState([item.selection])}
-                        showSelectionPreview={false}
-                        maxDate={new Date()}
-                        moveRangeOnFirstSelection={false}
-                        months={1}
-                        ranges={state}
-                        className='w-full'
-                      />
-                      <style>{`
+                      <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'
+                        >
+                          &times;
+                        </button>
+                        <DateRangePicker
+                          onChange={(item) => setState([item.selection])}
+                          showSelectionPreview={false}
+                          maxDate={new Date()}
+                          moveRangeOnFirstSelection={false}
+                          months={1}
+                          ranges={state}
+                          className='w-full'
+                        />
+                        <style>{`
                         /* Atur container agar menjadi column */
                         .rdrCalendarWrapper {
                           display: flex;
@@ -1105,15 +1148,15 @@ const Transactions = ({ context = '' }) => {
                           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'
-                          onClick={handleReset}
-                        >
-                          Reset
-                        </button>
+                        <div className='flex flex-row justify-end gap-3 mt-2'>
+                          <button
+                            className='px-4 py-1 bg-red-500 text-white rounded'
+                            onClick={handleReset}
+                          >
+                            Reset
+                          </button>
+                        </div>
                       </div>
-                    </div>
                     )}
                   </div>
                 </div>
@@ -1220,7 +1263,8 @@ const Transactions = ({ context = '' }) => {
                                             href={`${router.pathname}/${saleOrder?.id}`}
                                             className='text-red-500 text-nowrap'
                                           >
-                                            +{saleOrder.products.length - 4} lihat semua produk
+                                            +{saleOrder.products.length - 4}{' '}
+                                            lihat semua produk
                                           </Link>
                                         ) : (
                                           <Link
@@ -1245,24 +1289,36 @@ const Transactions = ({ context = '' }) => {
                               </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'>
+                            <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>
                                 <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>
+
+                              <button
+                                type='button'
+                                onClick={(e) => {
+                                  e.preventDefault();
+                                  e.stopPropagation();
+                                  handleBuyBack(saleOrder.products);
+                                }}
+                                className='w-full py-2 btn-solid-red text-nowrap rounded-md'
+                              >
+                                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>
                             </div>
                           </div>
                         </Link>
-- 
cgit v1.2.3


From 3a9a0995dad8d3deb602534814a6bb79b26afb54 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Wed, 27 Aug 2025 13:16:59 +0700
Subject: <Miqdad> Push Sementara

---
 src/lib/transaction/components/Transactions.jsx | 615 ++++++++----------------
 1 file changed, 196 insertions(+), 419 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

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'
             />
-- 
cgit v1.2.3


From a0e32b6a8af5a57ef9d0222f8ecefc69a4f92294 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 08:11:07 +0700
Subject: <Miqdad> Change String

---
 src/lib/transaction/components/Transactions.jsx | 145 +++++++++++++++---------
 1 file changed, 90 insertions(+), 55 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 0d7e3f2c..826d88ac 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -40,7 +40,7 @@ import { Calendar } from 'lucide-react';
 import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
-import { fetchPaymentSummary } from '../api/regenerate';
+// import { fetchPaymentSummary } from '../api/regenerate';
 
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
@@ -73,8 +73,49 @@ const Transactions = ({ context = '' }) => {
   const [cachedAllData, setCachedAllData] = useState(null);
   const [currentData, setCurrentData] = useState([]);
   const calendarRef = useRef(null);
+  // --- helpers aturan regenerate ---
+  const getApproval = (so) =>
+    (so?.approvalStatus || so?.approval_status || '').toLowerCase();
+
+  const isApprovalPending = (so) =>
+    ['pengajuan1', 'pengajuan2'].includes(getApproval(so));
+
+  const isWebSource = (so) => {
+    const code = (so?.source || so?.sourceCode || '').toLowerCase();
+    const id = so?.sourceId ?? so?.source_id;
+    return code === 'website' || code === 'web' || id === 59; // sesuaikan id sumber web kamu
+  };
+
+  const getPaymentStatus = (so) =>
+    (
+      so?.paymentSummary?.paymentStatus ||
+      so?.paymentSummary?.status ||
+      so?.paymentStatus ||
+      ''
+    ).toLowerCase();
+
+  // kosong | expire | belum settlement → boleh regenerate
+  const isPaymentUnsettled = (so) => {
+    const ps = getPaymentStatus(so);
+    if (!ps) return true; // kosong
+    if (['expire', 'expired'].includes(ps)) return true;
+    // dianggap “belum settlement” jika bukan status paid/settled
+    return !['settlement', 'paid', 'capture', 'success', 'settled'].includes(
+      ps
+    );
+  };
+
+  // WAJIB semua true
+  const canRegeneratePayment = (so) =>
+    isApprovalPending(so) && isWebSource(so) && isPaymentUnsettled(so);
+
+  // Jika backend sudah kirim flag eligibleContinue, tetap wajib lolos aturan front-end
+  const eligibleToShow = (so) => {
+    const backend =
+      typeof so?.eligibleContinue === 'boolean' ? so.eligibleContinue : true;
+    return backend && canRegeneratePayment(so);
+  };
 
-  // loading id utk tombol lanjutkan transaksi
   const [contLoadingId, setContLoadingId] = useState(null);
 
   const parseDate = (date) => {
@@ -364,6 +405,7 @@ const Transactions = ({ context = '' }) => {
     router.push(`${router.pathname}`);
   };
 
+
   const formatDate = (dateString) => {
     const months = [
       'Januari',
@@ -383,60 +425,53 @@ const Transactions = ({ context = '' }) => {
     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;
+const handleContinuePayment = async (saleOrder) => {
+  try {
+    if (!canRegeneratePayment(saleOrder)) {
+      toast.error(
+        'Tidak memenuhi syarat: approval belum pengajuan1/2, sumber bukan web, atau pembayaran sudah settle.'
+      );
+      return;
+    }
+    const partnerId =
+      auth?.partnerId || auth?.partner_id || auth?.partner?.id || auth?.id;
+    setContLoadingId(saleOrder.id);
 
-      setContLoadingId(saleOrder.id);
+    // pakai URL yang sudah ada dulu
+    const existingUrl =
+      saleOrder?.paymentSummary?.redirectUrl || saleOrder?.paymentLinkMidtrans;
 
-      // 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;
+    }
 
-      if (existingUrl) {
-        window.open(existingUrl, '_blank', 'noopener,noreferrer');
-        toast.success('Membuka halaman pembayaran…');
-        return;
-      }
+    // fallback autogen
+    const res = await fetchPaymentSummary({
+      partnerId,
+      saleOrderId: saleOrder.id,
+      autogen: true,
+    });
+    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);
+  }
+};
 
-      // 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 (
     <>
@@ -646,7 +681,7 @@ const Transactions = ({ context = '' }) => {
                       Beli Lagi
                     </button>
 
-                    {saleOrder?.eligibleContinue && (
+                    {eligibleToShow(saleOrder) && (
                       <button
                         type='button'
                         disabled={contLoadingId === saleOrder.id}
@@ -659,7 +694,7 @@ const Transactions = ({ context = '' }) => {
                       >
                         {contLoadingId === saleOrder.id
                           ? 'Memproses…'
-                          : 'Lanjutkan Transaksi'}
+                          : 'Lanjutkan Pembayaran'}
                       </button>
                     )}
                   </div>
@@ -1140,7 +1175,7 @@ const Transactions = ({ context = '' }) => {
                                 Beli Lagi
                               </button>
 
-                              {saleOrder?.eligibleContinue && (
+                              {eligibleToShow(saleOrder) && (
                                 <button
                                   type='button'
                                   disabled={contLoadingId === saleOrder.id}
@@ -1153,7 +1188,7 @@ const Transactions = ({ context = '' }) => {
                                 >
                                   {contLoadingId === saleOrder.id
                                     ? 'Memproses…'
-                                    : 'Lanjutkan Transaksi'}
+                                    : 'Lanjutkan Pembayaran'}
                                 </button>
                               )}
                             </div>
-- 
cgit v1.2.3


From 1269c53959f81babc9ba14b57429cb49c1c0aba2 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 09:58:51 +0700
Subject: <Miqdad> push

---
 src/lib/transaction/components/Transactions.jsx | 204 +++++++++---------------
 1 file changed, 75 insertions(+), 129 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 826d88ac..7df1f0ff 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -40,12 +40,10 @@ import { Calendar } from 'lucide-react';
 import { DateRangePicker } from 'react-date-range';
 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();
-  const swiperRef = useRef(null);
   const {
     q = '',
     page = 1,
@@ -70,52 +68,9 @@ const Transactions = ({ context = '' }) => {
   const [sortNew, setSortNew] = useState(sort);
   const [contextNew, setcontextNew] = useState(router.query.context || context);
   const [isOpenCalender, setIsOpenCalender] = useState(false);
-  const [cachedAllData, setCachedAllData] = useState(null);
-  const [currentData, setCurrentData] = useState([]);
   const calendarRef = useRef(null);
-  // --- helpers aturan regenerate ---
-  const getApproval = (so) =>
-    (so?.approvalStatus || so?.approval_status || '').toLowerCase();
-
-  const isApprovalPending = (so) =>
-    ['pengajuan1', 'pengajuan2'].includes(getApproval(so));
-
-  const isWebSource = (so) => {
-    const code = (so?.source || so?.sourceCode || '').toLowerCase();
-    const id = so?.sourceId ?? so?.source_id;
-    return code === 'website' || code === 'web' || id === 59; // sesuaikan id sumber web kamu
-  };
-
-  const getPaymentStatus = (so) =>
-    (
-      so?.paymentSummary?.paymentStatus ||
-      so?.paymentSummary?.status ||
-      so?.paymentStatus ||
-      ''
-    ).toLowerCase();
-
-  // kosong | expire | belum settlement → boleh regenerate
-  const isPaymentUnsettled = (so) => {
-    const ps = getPaymentStatus(so);
-    if (!ps) return true; // kosong
-    if (['expire', 'expired'].includes(ps)) return true;
-    // dianggap “belum settlement” jika bukan status paid/settled
-    return !['settlement', 'paid', 'capture', 'success', 'settled'].includes(
-      ps
-    );
-  };
-
-  // WAJIB semua true
-  const canRegeneratePayment = (so) =>
-    isApprovalPending(so) && isWebSource(so) && isPaymentUnsettled(so);
-
-  // Jika backend sudah kirim flag eligibleContinue, tetap wajib lolos aturan front-end
-  const eligibleToShow = (so) => {
-    const backend =
-      typeof so?.eligibleContinue === 'boolean' ? so.eligibleContinue : true;
-    return backend && canRegeneratePayment(so);
-  };
 
+  // loading id utk tombol lanjutkan transaksi
   const [contLoadingId, setContLoadingId] = useState(null);
 
   const parseDate = (date) => {
@@ -191,13 +146,9 @@ const Transactions = ({ context = '' }) => {
     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')
+  const pageCount = Math.ceil(
+    (transactions?.data?.saleOrderTotal || 0) / (limitNew || 1)
   );
-  pageQuery = toQuery(pageQuery);
 
   const handleSubmit = (e) => {
     e.preventDefault();
@@ -227,12 +178,12 @@ const Transactions = ({ context = '' }) => {
     ];
     const rowsToExport = [];
 
-    data.forEach((saleOrder) => {
+    (data || []).forEach((saleOrder) => {
       const row = {
         'No. Transaksi': saleOrder.name,
         'No. PO': saleOrder.purchaseOrderName || '-',
         Tanggal: saleOrder.dateOrder || '-',
-        'Created By': saleOrder.address.customer?.name || '-',
+        'Created By': saleOrder.address?.customer?.name || '-',
         Salesperson: saleOrder.sales,
         Total: currencyFormat(saleOrder.amountTotal),
         Status: contextLabelMap[saleOrder.status] || saleOrder.status,
@@ -251,7 +202,7 @@ const Transactions = ({ context = '' }) => {
   };
 
   const getAllData = async () => {
-    const query = {
+    const qobj = {
       name: q,
       offset: (pageNew - 1) * limitNew,
       limit: limitNew,
@@ -266,7 +217,7 @@ const Transactions = ({ context = '' }) => {
       site:
         siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
     };
-    const queryString = toQuery(query);
+    const queryString = toQuery(qobj);
     const data = await transactionsApi({ query: queryString });
     return data;
   };
@@ -289,12 +240,15 @@ const Transactions = ({ context = '' }) => {
           saleOrder.name,
           saleOrder.purchaseOrderName || '-',
           saleOrder.dateOrder || '-',
-          saleOrder.address.customer?.name || '-',
+          saleOrder.address?.customer?.name || '-',
           saleOrder.sales,
           currencyFormat(saleOrder.amountTotal),
-          contextLabelMap[saleOrder.status] || saleOrder.status,
+          (contextLabelMap[saleOrder.status] || saleOrder.status || '').replace(
+            /,/g,
+            ' '
+          ),
         ];
-        if (siteFilter) row.push(siteFilter);
+        if (siteFilter) row.push((siteFilter || '').replace(/,/g, ' '));
         return row.join(',');
       }) || [];
 
@@ -335,7 +289,7 @@ const Transactions = ({ context = '' }) => {
   const startItem = 1 + (pageNew - 1) * limitNew;
   const endItem = Math.min(
     limitNew * pageNew,
-    transactions?.data?.saleOrderTotal
+    transactions?.data?.saleOrderTotal || 0
   );
 
   useEffect(() => {
@@ -345,7 +299,7 @@ const Transactions = ({ context = '' }) => {
   const handleBuyBack = async (products) => {
     try {
       const results = await Promise.all(
-        products.map((product) =>
+        (products || []).map((product) =>
           upsertUserCart({
             userId: auth.id,
             type: 'product',
@@ -358,15 +312,13 @@ const Transactions = ({ context = '' }) => {
         )
       );
 
-      const failedOperations = results.filter((r) => r && r.error);
-      if (failedOperations.length > 0) {
-        toast.error(
-          `${failedOperations.length} produk gagal ditambahkan ke keranjang`
-        );
-        if (failedOperations.length < products.length) {
+      const failed = results.filter((r) => r && r.error);
+      if (failed.length > 0) {
+        toast.error(`${failed.length} produk gagal ditambahkan ke keranjang`);
+        if (failed.length < (products || []).length) {
           toast.success(
             `${
-              products.length - failedOperations.length
+              (products || []).length - failed.length
             } produk berhasil ditambahkan`
           );
           setRefreshCart(true);
@@ -377,26 +329,24 @@ const Transactions = ({ context = '' }) => {
       setRefreshCart(true);
       toast.success('Semua produk berhasil ditambahkan ke keranjang');
       router.push('/shop/cart');
-    } catch (error) {
+    } catch {
       toast.error('Terjadi kesalahan saat menambahkan produk ke keranjang');
     }
   };
 
-  const handleStatusChange = async (status) => {
+  const handleStatusChange = (status) => {
     setStatusNew(status);
     setPageNew(1);
-
-    if (status === 'all' && cachedAllData) {
-      setCurrentData(cachedAllData);
-      return;
-    }
-    const data = await fetchSite(status, 1);
-    if (status === 'all') setCachedAllData(data);
-    setCurrentData(data);
+    // opsional: sinkronkan ke URL
+    router.push({
+      pathname: router.pathname,
+      query: { ...router.query, status },
+    });
   };
 
   useEffect(() => {
-    setCachedAllData([]);
+    // bersihkan cache lama jika perlu (saat first mount)
+    // (sengaja kosong; tidak pakai cached data di versi ini)
   }, []);
 
   const handleReset = () => {
@@ -405,7 +355,6 @@ const Transactions = ({ context = '' }) => {
     router.push(`${router.pathname}`);
   };
 
-
   const formatDate = (dateString) => {
     const months = [
       'Januari',
@@ -421,57 +370,54 @@ const Transactions = ({ context = '' }) => {
       'November',
       'Desember',
     ];
-    const [day, month, year] = dateString.split('/');
+    const [day, month, year] = (dateString || '').split('/');
+    if (!day || !month || !year) return dateString || '-';
     return `${day} ${months[parseInt(month, 10) - 1]} ${year}`;
   };
 
-const handleContinuePayment = async (saleOrder) => {
-  try {
-    if (!canRegeneratePayment(saleOrder)) {
-      toast.error(
-        'Tidak memenuhi syarat: approval belum pengajuan1/2, sumber bukan web, atau pembayaran sudah settle.'
-      );
-      return;
-    }
-    const partnerId =
-      auth?.partnerId || auth?.partner_id || auth?.partner?.id || auth?.id;
-    setContLoadingId(saleOrder.id);
-
-    // pakai URL yang sudah ada dulu
-    const existingUrl =
-      saleOrder?.paymentSummary?.redirectUrl || saleOrder?.paymentLinkMidtrans;
-
-    if (existingUrl) {
-      window.open(existingUrl, '_blank', 'noopener,noreferrer');
-      toast.success('Membuka halaman pembayaran…');
-      return;
-    }
+  // ==== Lanjutkan Transaksi (tanpa endpoint baru) ====
+  const handleContinuePayment = async (saleOrder) => {
+    try {
+      setContLoadingId(saleOrder.id);
 
-    // fallback autogen
-    const res = await fetchPaymentSummary({
-      partnerId,
-      saleOrderId: saleOrder.id,
-      autogen: true,
-    });
-    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);
-  }
-};
+      // 1) pakai URL yang dikirim server di list
+      const existingUrl =
+        saleOrder?.paymentSummary?.redirectUrl ||
+        saleOrder?.paymentLinkMidtrans ||
+        '';
 
+      if (existingUrl) {
+        window.open(existingUrl, '_blank', 'noopener,noreferrer');
+        toast.success('Membuka halaman pembayaran…');
+        return;
+      }
 
+      // 2) kalau masih kosong, refetch list (server bisa auto-generate saat list)
+      await transactions.refetch();
+      const updated =
+        transactions?.data?.saleOrders?.find((s) => s.id === saleOrder.id) ||
+        null;
+      const updatedUrl =
+        updated?.paymentSummary?.redirectUrl ||
+        updated?.paymentLinkMidtrans ||
+        '';
+
+      if (updatedUrl) {
+        window.open(updatedUrl, '_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 (
     <>
@@ -681,7 +627,7 @@ const handleContinuePayment = async (saleOrder) => {
                       Beli Lagi
                     </button>
 
-                    {eligibleToShow(saleOrder) && (
+                    {saleOrder?.eligibleContinue && (
                       <button
                         type='button'
                         disabled={contLoadingId === saleOrder.id}
@@ -694,7 +640,7 @@ const handleContinuePayment = async (saleOrder) => {
                       >
                         {contLoadingId === saleOrder.id
                           ? 'Memproses…'
-                          : 'Lanjutkan Pembayaran'}
+                          : 'Lanjutkan Transaksi'}
                       </button>
                     )}
                   </div>
@@ -1175,7 +1121,7 @@ const handleContinuePayment = async (saleOrder) => {
                                 Beli Lagi
                               </button>
 
-                              {eligibleToShow(saleOrder) && (
+                              {saleOrder?.eligibleContinue && (
                                 <button
                                   type='button'
                                   disabled={contLoadingId === saleOrder.id}
@@ -1188,7 +1134,7 @@ const handleContinuePayment = async (saleOrder) => {
                                 >
                                   {contLoadingId === saleOrder.id
                                     ? 'Memproses…'
-                                    : 'Lanjutkan Pembayaran'}
+                                    : 'Lanjutkan Transaksi'}
                                 </button>
                               )}
                             </div>
-- 
cgit v1.2.3


From 2ac24291d27c3093f813391265ae4fe75d291e84 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 11:19:36 +0700
Subject: <Miqdad>posisi harag

---
 src/lib/transaction/components/Transactions.jsx | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 7df1f0ff..e06d1927 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -640,7 +640,7 @@ const Transactions = ({ context = '' }) => {
                       >
                         {contLoadingId === saleOrder.id
                           ? 'Memproses…'
-                          : 'Lanjutkan Transaksi'}
+                          : 'Bayar Sekarang'}
                       </button>
                     )}
                   </div>
@@ -1101,10 +1101,10 @@ const Transactions = ({ context = '' }) => {
 
                             <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>
-                                <p className='font-bold'>
+                            <div className='w-1/4 flex flex-col gap-2 items-center justify-center text-center pl-5'>
+                              <div className='flex flex-col text-black'>
+                                <p className='text-sm'>Total Harga</p>
+                                <p className='font-bold text-lg'>
                                   {currencyFormat(saleOrder.amountTotal)}
                                 </p>
                               </div>
@@ -1134,7 +1134,7 @@ const Transactions = ({ context = '' }) => {
                                 >
                                   {contLoadingId === saleOrder.id
                                     ? 'Memproses…'
-                                    : 'Lanjutkan Transaksi'}
+                                    : 'Bayar Sekarang'}
                                 </button>
                               )}
                             </div>
-- 
cgit v1.2.3


From 1b7d4dd7e26e8b249adf49b86dea85968eeb6653 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 13:40:22 +0700
Subject: <Miqdad> Add new badge

---
 src/lib/transaction/components/Transactions.jsx | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index e06d1927..dd927dfa 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -106,6 +106,7 @@ const Transactions = ({ context = '' }) => {
   const statuses = [
     { id: 'all', label: 'Semua' },
     { id: 'quotation', label: 'Pending Quotation' },
+    { id: 'belum_bayar', label: 'Belum Bayar' },
     { id: 'diproses', label: 'Pesanan Diproses' },
     { id: 'dikemas', label: 'Pesanan Dikemas' },
     { id: 'partial', label: 'Dikirim Sebagian' },
@@ -122,6 +123,7 @@ const Transactions = ({ context = '' }) => {
     shipping: 'Pesanan Dikirim',
     done: 'Pesanan Selesai',
     cancel: 'Pesanan Dibatalkan',
+    belum_bayar: 'Belum Bayar',
   };
 
   const sortes = [
-- 
cgit v1.2.3


From b7833ad1d13772ea1dd7a6af6716a2c4b575132a Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 17:08:20 +0700
Subject: <Miqdad>Hide Beli lagi

---
 src/lib/transaction/components/Transactions.jsx | 55 +++++++++++++++----------
 1 file changed, 33 insertions(+), 22 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index dd927dfa..bb24f717 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -69,6 +69,10 @@ const Transactions = ({ context = '' }) => {
   const [contextNew, setcontextNew] = useState(router.query.context || context);
   const [isOpenCalender, setIsOpenCalender] = useState(false);
   const calendarRef = useRef(null);
+  const isUnpaid = (s) =>
+    ['belum_bayar'].includes(
+      String(s || '').toLowerCase()
+    );
 
   // loading id utk tombol lanjutkan transaksi
   const [contLoadingId, setContLoadingId] = useState(null);
@@ -617,18 +621,22 @@ const Transactions = ({ context = '' }) => {
                   </div>
 
                   <div className='flex flex-col gap-2 w-full'>
-                    <button
-                      type='button'
-                      onClick={(e) => {
-                        e.preventDefault();
-                        e.stopPropagation();
-                        handleBuyBack(saleOrder.products);
-                      }}
-                      className='w-full py-2 btn-solid-red text-center rounded-md'
-                    >
-                      Beli Lagi
-                    </button>
+                    {/* Beli Lagi hanya muncul jika status bukan unpaid */}
+                    {!isUnpaid(saleOrder.status) && (
+                      <button
+                        type='button'
+                        onClick={(e) => {
+                          e.preventDefault();
+                          e.stopPropagation();
+                          handleBuyBack(saleOrder.products);
+                        }}
+                        className='w-full py-2 btn-solid-red text-center rounded-md'
+                      >
+                        Beli Lagi
+                      </button>
+                    )}
 
+                    {/* Bayar Sekarang hanya kalau eligible */}
                     {saleOrder?.eligibleContinue && (
                       <button
                         type='button'
@@ -1111,18 +1119,21 @@ const Transactions = ({ context = '' }) => {
                                 </p>
                               </div>
 
-                              <button
-                                type='button'
-                                onClick={(e) => {
-                                  e.preventDefault();
-                                  e.stopPropagation();
-                                  handleBuyBack(saleOrder.products);
-                                }}
-                                className='w-full py-2 btn-solid-red text-nowrap rounded-md'
-                              >
-                                Beli Lagi
-                              </button>
+                              {!isUnpaid(saleOrder.status) && (
+                                <button
+                                  type='button'
+                                  onClick={(e) => {
+                                    e.preventDefault();
+                                    e.stopPropagation();
+                                    handleBuyBack(saleOrder.products);
+                                  }}
+                                  className='w-full py-2 btn-solid-red text-nowrap rounded-md'
+                                >
+                                  Beli Lagi
+                                </button>
+                              )}
 
+                              {/* Bayar Sekarang: hanya kalau eligible */}
                               {saleOrder?.eligibleContinue && (
                                 <button
                                   type='button'
-- 
cgit v1.2.3


From 321bd5214ba00867d38866e401146bcc79157cec Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 28 Aug 2025 17:18:39 +0700
Subject: <Miqdad> minor fix

---
 src/lib/transaction/components/Transactions.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index bb24f717..79ccdcb4 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -1143,7 +1143,7 @@ const Transactions = ({ context = '' }) => {
                                     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'
+                                  className='w-full py-2 text-nowrap border border-red-500 text-red-500 rounded-md disabled:opacity-60'
                                 >
                                   {contLoadingId === saleOrder.id
                                     ? 'Memproses…'
-- 
cgit v1.2.3


From 308563b3f45255450206decc03329dcc64c4bc50 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Fri, 29 Aug 2025 10:42:05 +0700
Subject: <MIqdad> Fix payment

---
 src/lib/transaction/components/Transactions.jsx | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 79ccdcb4..e22cd490 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -70,9 +70,7 @@ const Transactions = ({ context = '' }) => {
   const [isOpenCalender, setIsOpenCalender] = useState(false);
   const calendarRef = useRef(null);
   const isUnpaid = (s) =>
-    ['belum_bayar'].includes(
-      String(s || '').toLowerCase()
-    );
+    ['belum_bayar'].includes(String(s || '').toLowerCase());
 
   // loading id utk tombol lanjutkan transaksi
   const [contLoadingId, setContLoadingId] = useState(null);
@@ -381,13 +379,22 @@ const Transactions = ({ context = '' }) => {
     return `${day} ${months[parseInt(month, 10) - 1]} ${year}`;
   };
 
-  // ==== Lanjutkan Transaksi (tanpa endpoint baru) ====
   const handleContinuePayment = async (saleOrder) => {
     try {
       setContLoadingId(saleOrder.id);
 
-      // 1) pakai URL yang dikirim server di list
+      // (0) Minta backend pastikan/generate link terbaru
+      let ensuredUrl = '';
+      try {
+        const { data } = await axios.post(
+          `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/so-payment-link?soId=${saleOrder.id}`
+        );
+        ensuredUrl = data?.redirectUrl || '';
+      } catch (e) {
+      }
+
       const existingUrl =
+        ensuredUrl ||
         saleOrder?.paymentSummary?.redirectUrl ||
         saleOrder?.paymentLinkMidtrans ||
         '';
@@ -398,12 +405,13 @@ const Transactions = ({ context = '' }) => {
         return;
       }
 
-      // 2) kalau masih kosong, refetch list (server bisa auto-generate saat list)
+      // (2) Fallback: refetch list (kalau backend auto-generate saat list)
       await transactions.refetch();
       const updated =
         transactions?.data?.saleOrders?.find((s) => s.id === saleOrder.id) ||
         null;
       const updatedUrl =
+        ensuredUrl || // kalau step (0) akhirnya sukses
         updated?.paymentSummary?.redirectUrl ||
         updated?.paymentLinkMidtrans ||
         '';
-- 
cgit v1.2.3


From 2710d13d4d417bfa17d6eeaa7493f06d8ae06aa8 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Fri, 29 Aug 2025 17:05:44 +0700
Subject: <Miqdad> No reload on status change

---
 src/lib/transaction/components/Transactions.jsx | 26 +++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index e22cd490..5466466c 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -41,6 +41,7 @@ import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
 
+
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
   const router = useRouter();
@@ -56,6 +57,8 @@ const Transactions = ({ context = '' }) => {
   } = router.query;
   const { setRefreshCart } = useProductCartContext();
 
+  const [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
+  const [currentData, setCurrentData] = useState([]); 
   const [inputQuery, setInputQuery] = useState(q);
   const [toOthers, setToOthers] = useState(null);
   const [toCancel, setToCancel] = useState(null);
@@ -338,16 +341,27 @@ const Transactions = ({ context = '' }) => {
     }
   };
 
-  const handleStatusChange = (status) => {
+  const handleStatusChange = async (status) => {
     setStatusNew(status);
     setPageNew(1);
-    // opsional: sinkronkan ke URL
-    router.push({
-      pathname: router.pathname,
-      query: { ...router.query, status },
-    });
+
+    if (status === 'all' && cachedAllData) {
+      setCurrentData(cachedAllData);
+      return;
+    }
+    const data = await fetchSite(status, 1);
+
+    if (status === 'all') {
+      setCachedAllData(data);
+    }
+
+    setCurrentData(data);
   };
 
+  useEffect(() => {
+    setCachedAllData([]);
+  }, []);
+
   useEffect(() => {
     // bersihkan cache lama jika perlu (saat first mount)
     // (sengaja kosong; tidak pakai cached data di versi ini)
-- 
cgit v1.2.3


From 90c4cde3981450cf20172fb938cd18c0943a57c6 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Sat, 30 Aug 2025 08:05:33 +0700
Subject: <Miqdad> temp

---
 src/lib/transaction/components/Transactions.jsx | 30 ++++++++++++++-----------
 1 file changed, 17 insertions(+), 13 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 5466466c..064471d5 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -40,7 +40,7 @@ import { Calendar } from 'lucide-react';
 import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
-
+import axios from 'axios';
 
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
@@ -58,7 +58,7 @@ const Transactions = ({ context = '' }) => {
   const { setRefreshCart } = useProductCartContext();
 
   const [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
-  const [currentData, setCurrentData] = useState([]); 
+  const [currentData, setCurrentData] = useState([]);
   const [inputQuery, setInputQuery] = useState(q);
   const [toOthers, setToOthers] = useState(null);
   const [toCancel, setToCancel] = useState(null);
@@ -397,39 +397,43 @@ const Transactions = ({ context = '' }) => {
     try {
       setContLoadingId(saleOrder.id);
 
-      // (0) Minta backend pastikan/generate link terbaru
-      let ensuredUrl = '';
+      // 1) Selalu coba generate link baru via Next API dulu
+      const base = (process.env.NEXT_PUBLIC_SELF_HOST || '').replace(/\/$/, '');
       try {
         const { data } = await axios.post(
-          `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/so-payment-link?soId=${saleOrder.id}`
+          `${base}/api/shop/midtrans-payment`,
+          null,
+          { params: { transactionId: saleOrder.id } }
         );
-        ensuredUrl = data?.redirectUrl || '';
-      } catch (e) {
+        if (data?.redirectUrl) {
+          window.open(data.redirectUrl, '_blank', 'noopener,noreferrer');
+          toast.success('Membuka halaman pembayaran…');
+          return;
+        }
+      } catch (err) {
+        // biarkan fail, lanjut fallback
       }
 
+      // 2) Fallback: pakai link yang sudah ada di list (mungkin masih valid)
       const existingUrl =
-        ensuredUrl ||
         saleOrder?.paymentSummary?.redirectUrl ||
         saleOrder?.paymentLinkMidtrans ||
         '';
-
       if (existingUrl) {
         window.open(existingUrl, '_blank', 'noopener,noreferrer');
-        toast.success('Membuka halaman pembayaran…');
+        toast('Membuka link pembayaran yang sudah ada');
         return;
       }
 
-      // (2) Fallback: refetch list (kalau backend auto-generate saat list)
+      // 3) Fallback terakhir: refetch list
       await transactions.refetch();
       const updated =
         transactions?.data?.saleOrders?.find((s) => s.id === saleOrder.id) ||
         null;
       const updatedUrl =
-        ensuredUrl || // kalau step (0) akhirnya sukses
         updated?.paymentSummary?.redirectUrl ||
         updated?.paymentLinkMidtrans ||
         '';
-
       if (updatedUrl) {
         window.open(updatedUrl, '_blank', 'noopener,noreferrer');
         toast.success('Membuka halaman pembayaran…');
-- 
cgit v1.2.3


From 016b9f1e9b234f546a0354b818fd33712379a803 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Sun, 31 Aug 2025 12:18:14 +0700
Subject: <Miqdad> oke

---
 src/lib/transaction/components/Transactions.jsx | 72 ++++++++++++-------------
 1 file changed, 36 insertions(+), 36 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 064471d5..287451ef 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -1,3 +1,4 @@
+import axios from 'axios';
 import { useRouter } from 'next/router';
 import { useEffect, useState, useRef } from 'react';
 import { toast } from 'react-hot-toast';
@@ -40,7 +41,6 @@ import { Calendar } from 'lucide-react';
 import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
-import axios from 'axios';
 
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
@@ -57,8 +57,6 @@ const Transactions = ({ context = '' }) => {
   } = router.query;
   const { setRefreshCart } = useProductCartContext();
 
-  const [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
-  const [currentData, setCurrentData] = useState([]);
   const [inputQuery, setInputQuery] = useState(q);
   const [toOthers, setToOthers] = useState(null);
   const [toCancel, setToCancel] = useState(null);
@@ -341,27 +339,16 @@ const Transactions = ({ context = '' }) => {
     }
   };
 
-  const handleStatusChange = async (status) => {
+  const handleStatusChange = (status) => {
     setStatusNew(status);
     setPageNew(1);
-
-    if (status === 'all' && cachedAllData) {
-      setCurrentData(cachedAllData);
-      return;
-    }
-    const data = await fetchSite(status, 1);
-
-    if (status === 'all') {
-      setCachedAllData(data);
-    }
-
-    setCurrentData(data);
+    // opsional: sinkronkan ke URL
+    router.push({
+      pathname: router.pathname,
+      query: { ...router.query, status },
+    });
   };
 
-  useEffect(() => {
-    setCachedAllData([]);
-  }, []);
-
   useEffect(() => {
     // bersihkan cache lama jika perlu (saat first mount)
     // (sengaja kosong; tidak pakai cached data di versi ini)
@@ -393,39 +380,51 @@ const Transactions = ({ context = '' }) => {
     return `${day} ${months[parseInt(month, 10) - 1]} ${year}`;
   };
 
+  // ==== Lanjutkan Transaksi (tanpa endpoint baru) ====
   const handleContinuePayment = async (saleOrder) => {
     try {
       setContLoadingId(saleOrder.id);
 
-      // 1) Selalu coba generate link baru via Next API dulu
-      const base = (process.env.NEXT_PUBLIC_SELF_HOST || '').replace(/\/$/, '');
+      const base = (process.env.NEXT_PUBLIC_ODOO_API_HOST || '').replace(
+        /\/$/,
+        ''
+      );
+      const token = auth?.token;
+      const partnerId = auth?.partnerId;
+
+      // (1) Minta Odoo ensure (generate hanya jika kosong/expire/cancel)
+      let ensuredUrl = '';
       try {
-        const { data } = await axios.post(
-          `${base}/api/shop/midtrans-payment`,
-          null,
-          { params: { transactionId: saleOrder.id } }
+        const { data: resp } = await axios.get(
+          `${base}/api/v1/partner/${partnerId}/sale_order/${saleOrder.id}`,
+          {
+            params: { ensure_payment_link: 1, ts: Date.now() },
+            headers: { Token: token },
+          }
         );
-        if (data?.redirectUrl) {
-          window.open(data.redirectUrl, '_blank', 'noopener,noreferrer');
-          toast.success('Membuka halaman pembayaran…');
-          return;
-        }
-      } catch (err) {
-        // biarkan fail, lanjut fallback
+        const payload = resp?.data || resp;
+        ensuredUrl =
+          payload?.payment_summary?.redirect_url ||
+          payload?.paymentLinkMidtrans ||
+          '';
+      } catch (_) {
+        /* biarkan lanjut ke fallback */
       }
 
-      // 2) Fallback: pakai link yang sudah ada di list (mungkin masih valid)
+      // (2) Pakai link hasil ensure atau yang sudah ada di list
       const existingUrl =
+        ensuredUrl ||
         saleOrder?.paymentSummary?.redirectUrl ||
         saleOrder?.paymentLinkMidtrans ||
         '';
+
       if (existingUrl) {
         window.open(existingUrl, '_blank', 'noopener,noreferrer');
-        toast('Membuka link pembayaran yang sudah ada');
+        toast.success('Membuka halaman pembayaran…');
         return;
       }
 
-      // 3) Fallback terakhir: refetch list
+      // (3) Fallback terakhir: refetch list (agar link yang disimpan Odoo ikut terambil)
       await transactions.refetch();
       const updated =
         transactions?.data?.saleOrders?.find((s) => s.id === saleOrder.id) ||
@@ -434,6 +433,7 @@ const Transactions = ({ context = '' }) => {
         updated?.paymentSummary?.redirectUrl ||
         updated?.paymentLinkMidtrans ||
         '';
+
       if (updatedUrl) {
         window.open(updatedUrl, '_blank', 'noopener,noreferrer');
         toast.success('Membuka halaman pembayaran…');
-- 
cgit v1.2.3


From 93f99f867afde7c61530da85ef2e26280a1d18df Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 1 Sep 2025 15:25:16 +0700
Subject: <Miqdad> No reload

---
 src/lib/transaction/components/Transactions.jsx | 27 +++++++++++++++----------
 1 file changed, 16 insertions(+), 11 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 287451ef..4572a7b5 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -42,6 +42,7 @@ import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
 
+
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
   const router = useRouter();
@@ -58,6 +59,8 @@ const Transactions = ({ context = '' }) => {
   const { setRefreshCart } = useProductCartContext();
 
   const [inputQuery, setInputQuery] = useState(q);
+  const [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
+  const [currentData, setCurrentData] = useState([]); // Data yang ditampilkan
   const [toOthers, setToOthers] = useState(null);
   const [toCancel, setToCancel] = useState(null);
   const [listSites, setListSites] = useState([]);
@@ -339,20 +342,22 @@ const Transactions = ({ context = '' }) => {
     }
   };
 
-  const handleStatusChange = (status) => {
+  const handleStatusChange = async (status) => {
     setStatusNew(status);
     setPageNew(1);
-    // opsional: sinkronkan ke URL
-    router.push({
-      pathname: router.pathname,
-      query: { ...router.query, status },
-    });
-  };
 
-  useEffect(() => {
-    // bersihkan cache lama jika perlu (saat first mount)
-    // (sengaja kosong; tidak pakai cached data di versi ini)
-  }, []);
+    if (status === 'all' && cachedAllData) {
+      setCurrentData(cachedAllData);
+      return;
+    }
+    const data = await fetchSite(status, 1);
+
+    if (status === 'all') {
+      setCachedAllData(data);
+    }
+
+    setCurrentData(data);
+  };
 
   const handleReset = () => {
     setState([{ startDate: null, endDate: new Date(), key: 'selection' }]);
-- 
cgit v1.2.3


From 306122977320b7ec7c8516a3cda1978ed2de7060 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Sat, 6 Sep 2025 20:41:31 +0700
Subject: <Miqdad> fix transactions

---
 src/lib/transaction/components/Transactions.jsx | 142 +++++++++++++++++-------
 1 file changed, 103 insertions(+), 39 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 4572a7b5..cdac4036 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -42,7 +42,6 @@ import { DateRangePicker } from 'react-date-range';
 import 'react-date-range/dist/styles.css';
 import 'react-date-range/dist/theme/default.css';
 
-
 const Transactions = ({ context = '' }) => {
   const auth = useAuth();
   const router = useRouter();
@@ -389,6 +388,7 @@ const Transactions = ({ context = '' }) => {
   const handleContinuePayment = async (saleOrder) => {
     try {
       setContLoadingId(saleOrder.id);
+      console.log('🚀 START PAYMENT PROCESS');
 
       const base = (process.env.NEXT_PUBLIC_ODOO_API_HOST || '').replace(
         /\/$/,
@@ -397,61 +397,125 @@ const Transactions = ({ context = '' }) => {
       const token = auth?.token;
       const partnerId = auth?.partnerId;
 
-      // (1) Minta Odoo ensure (generate hanya jika kosong/expire/cancel)
-      let ensuredUrl = '';
+      // 1. TRIGGER GENERATE + GET URL SEKALIGUS
+      console.log('🔹 Step 1: Trigger generate + get URL');
+      const { data: response } = await axios.get(
+        `${base}/api/v1/partner/${partnerId}/sale_order/${saleOrder.id}`,
+        {
+          params: {
+            ensure_payment_link: 1,
+            ts: Date.now(),
+          },
+          headers: {
+            Token: token,
+            'Cache-Control': 'no-cache',
+          },
+          timeout: 10000, // 10 second timeout
+        }
+      );
+
+      console.log('📦 Full API Response:', response);
+
+      // 2. EKSTRAK URL DENGAN CARA YANG BENAR
+      let paymentUrl = '';
+
+      // Cara 1: Langsung dari response.result
+      if (response?.result?.payment_summary?.redirect_url) {
+        paymentUrl = response.result.payment_summary.redirect_url;
+        console.log('✅ URL found in response.result');
+      }
+      // Cara 2: Mungkin nested di data.result
+      else if (response?.data?.result?.payment_summary?.redirect_url) {
+        paymentUrl = response.data.result.payment_summary.redirect_url;
+        console.log('✅ URL found in response.data.result');
+      }
+      // Cara 3: Coba variasi lain
+      else {
+        console.log(
+          '❌ URL not found in usual places, checking all possibilities...'
+        );
+
+        // Debug: Log semua keys yang ada
+        console.log('🔍 Response keys:', Object.keys(response));
+        if (response.result)
+          console.log('🔍 Result keys:', Object.keys(response.result));
+
+        // Manual search untuk redirect_url
+        const searchForUrl = (obj) => {
+          for (const key in obj) {
+            if (
+              key.toLowerCase().includes('redirect') &&
+              typeof obj[key] === 'string' &&
+              obj[key].includes('http')
+            ) {
+              return obj[key];
+            }
+            if (typeof obj[key] === 'object' && obj[key] !== null) {
+              const found = searchForUrl(obj[key]);
+              if (found) return found;
+            }
+          }
+          return null;
+        };
+
+        paymentUrl = searchForUrl(response);
+        console.log('🔍 Manual search result:', paymentUrl);
+      }
+
+      // 3. JIKA DAPAT URL, BUKA
+      if (paymentUrl) {
+        console.log('🎯 Opening URL:', paymentUrl);
+        window.open(paymentUrl, '_blank', 'noopener,noreferrer');
+        toast.success('Membuka halaman pembayaran…');
+        return;
+      }
+
+      // 4. FALLBACK: COBA LAGI TANPA ensure_payment_link
+      console.log('🔹 Step 2: Fallback - try without ensure');
       try {
-        const { data: resp } = await axios.get(
+        const { data: fallbackResponse } = await axios.get(
           `${base}/api/v1/partner/${partnerId}/sale_order/${saleOrder.id}`,
           {
-            params: { ensure_payment_link: 1, ts: Date.now() },
             headers: { Token: token },
+            timeout: 5000,
           }
         );
-        const payload = resp?.data || resp;
-        ensuredUrl =
-          payload?.payment_summary?.redirect_url ||
-          payload?.paymentLinkMidtrans ||
-          '';
-      } catch (_) {
-        /* biarkan lanjut ke fallback */
+
+        const fallbackUrl =
+          fallbackResponse?.result?.payment_summary?.redirect_url ||
+          fallbackResponse?.data?.result?.payment_summary?.redirect_url;
+
+        if (fallbackUrl) {
+          console.log('✅ Fallback URL found:', fallbackUrl);
+          window.open(fallbackUrl, '_blank', 'noopener,noreferrer');
+          toast.success('Membuka halaman pembayaran…');
+          return;
+        }
+      } catch (fallbackError) {
+        console.error('Fallback error:', fallbackError);
       }
 
-      // (2) Pakai link hasil ensure atau yang sudah ada di list
+      // 5. ULTIMATE FALLBACK: PAKAI URL DARI DATA LAMA
+      console.log('🔹 Step 3: Ultimate fallback - use existing data');
       const existingUrl =
-        ensuredUrl ||
         saleOrder?.paymentSummary?.redirectUrl ||
-        saleOrder?.paymentLinkMidtrans ||
-        '';
+        saleOrder?.payment_summary?.redirect_url;
 
       if (existingUrl) {
+        console.log('✅ Using existing URL:', existingUrl);
         window.open(existingUrl, '_blank', 'noopener,noreferrer');
         toast.success('Membuka halaman pembayaran…');
-        return;
-      }
-
-      // (3) Fallback terakhir: refetch list (agar link yang disimpan Odoo ikut terambil)
-      await transactions.refetch();
-      const updated =
-        transactions?.data?.saleOrders?.find((s) => s.id === saleOrder.id) ||
-        null;
-      const updatedUrl =
-        updated?.paymentSummary?.redirectUrl ||
-        updated?.paymentLinkMidtrans ||
-        '';
-
-      if (updatedUrl) {
-        window.open(updatedUrl, '_blank', 'noopener,noreferrer');
-        toast.success('Membuka halaman pembayaran…');
       } else {
-        toast.error('Link pembayaran belum tersedia.');
+        console.error('❌ No URL found in any method');
+        toast.error('Link pembayaran tidak ditemukan. Silakan coba lagi.');
       }
-    } catch (e) {
-      const msg =
-        e?.response?.data?.description ||
-        e?.message ||
-        'Gagal melanjutkan transaksi';
-      toast.error(msg);
+    } catch (error) {
+      console.error('💥 Payment error:', error);
+      toast.error(
+        error.response?.data?.description || 'Gagal memproses pembayaran'
+      );
     } finally {
+      console.log('🏁 END PAYMENT PROCESS');
       setContLoadingId(null);
     }
   };
-- 
cgit v1.2.3


From 800b527bc0661255d1f9ec07d4bb365b23dab610 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Sat, 6 Sep 2025 21:09:05 +0700
Subject: <Miqdad> Fix detail transaction and no open new tab

---
 src/lib/transaction/components/Transactions.jsx | 88 ++++---------------------
 1 file changed, 13 insertions(+), 75 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index cdac4036..2e3eaaa2 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -388,7 +388,6 @@ const Transactions = ({ context = '' }) => {
   const handleContinuePayment = async (saleOrder) => {
     try {
       setContLoadingId(saleOrder.id);
-      console.log('🚀 START PAYMENT PROCESS');
 
       const base = (process.env.NEXT_PUBLIC_ODOO_API_HOST || '').replace(
         /\/$/,
@@ -397,88 +396,33 @@ const Transactions = ({ context = '' }) => {
       const token = auth?.token;
       const partnerId = auth?.partnerId;
 
-      // 1. TRIGGER GENERATE + GET URL SEKALIGUS
-      console.log('🔹 Step 1: Trigger generate + get URL');
+      // 1. TRIGGER GENERATE + GET URL
       const { data: response } = await axios.get(
         `${base}/api/v1/partner/${partnerId}/sale_order/${saleOrder.id}`,
         {
-          params: {
-            ensure_payment_link: 1,
-            ts: Date.now(),
-          },
-          headers: {
-            Token: token,
-            'Cache-Control': 'no-cache',
-          },
-          timeout: 10000, // 10 second timeout
+          params: { ensure_payment_link: 1, ts: Date.now() },
+          headers: { Token: token, 'Cache-Control': 'no-cache' },
+          timeout: 10000,
         }
       );
 
-      console.log('📦 Full API Response:', response);
-
-      // 2. EKSTRAK URL DENGAN CARA YANG BENAR
-      let paymentUrl = '';
-
-      // Cara 1: Langsung dari response.result
-      if (response?.result?.payment_summary?.redirect_url) {
-        paymentUrl = response.result.payment_summary.redirect_url;
-        console.log('✅ URL found in response.result');
-      }
-      // Cara 2: Mungkin nested di data.result
-      else if (response?.data?.result?.payment_summary?.redirect_url) {
-        paymentUrl = response.data.result.payment_summary.redirect_url;
-        console.log('✅ URL found in response.data.result');
-      }
-      // Cara 3: Coba variasi lain
-      else {
-        console.log(
-          '❌ URL not found in usual places, checking all possibilities...'
-        );
-
-        // Debug: Log semua keys yang ada
-        console.log('🔍 Response keys:', Object.keys(response));
-        if (response.result)
-          console.log('🔍 Result keys:', Object.keys(response.result));
-
-        // Manual search untuk redirect_url
-        const searchForUrl = (obj) => {
-          for (const key in obj) {
-            if (
-              key.toLowerCase().includes('redirect') &&
-              typeof obj[key] === 'string' &&
-              obj[key].includes('http')
-            ) {
-              return obj[key];
-            }
-            if (typeof obj[key] === 'object' && obj[key] !== null) {
-              const found = searchForUrl(obj[key]);
-              if (found) return found;
-            }
-          }
-          return null;
-        };
-
-        paymentUrl = searchForUrl(response);
-        console.log('🔍 Manual search result:', paymentUrl);
-      }
+      // 2. EKSTRAK URL
+      let paymentUrl =
+        response?.result?.payment_summary?.redirect_url ||
+        response?.data?.result?.payment_summary?.redirect_url;
 
       // 3. JIKA DAPAT URL, BUKA
       if (paymentUrl) {
-        console.log('🎯 Opening URL:', paymentUrl);
-        window.open(paymentUrl, '_blank', 'noopener,noreferrer');
+        window.location.href = paymentUrl;
         toast.success('Membuka halaman pembayaran…');
         return;
       }
 
-      // 4. FALLBACK: COBA LAGI TANPA ensure_payment_link
-      console.log('🔹 Step 2: Fallback - try without ensure');
+      // 4. FALLBACK: COBA TANPA ensure_payment_link
       try {
         const { data: fallbackResponse } = await axios.get(
           `${base}/api/v1/partner/${partnerId}/sale_order/${saleOrder.id}`,
-          {
-            headers: { Token: token },
-            timeout: 5000,
-          }
+          { headers: { Token: token }, timeout: 5000 }
         );
 
         const fallbackUrl =
@@ -486,36 +430,30 @@ const Transactions = ({ context = '' }) => {
           fallbackResponse?.data?.result?.payment_summary?.redirect_url;
 
         if (fallbackUrl) {
-          console.log('✅ Fallback URL found:', fallbackUrl);
-          window.open(fallbackUrl, '_blank', 'noopener,noreferrer');
+          window.location.href = fallbackUrl;
           toast.success('Membuka halaman pembayaran…');
           return;
         }
       } catch (fallbackError) {
-        console.error('Fallback error:', fallbackError);
+        // Continue to next fallback
       }
 
       // 5. ULTIMATE FALLBACK: PAKAI URL DARI DATA LAMA
-      console.log('🔹 Step 3: Ultimate fallback - use existing data');
       const existingUrl =
         saleOrder?.paymentSummary?.redirectUrl ||
         saleOrder?.payment_summary?.redirect_url;
 
       if (existingUrl) {
-        console.log('✅ Using existing URL:', existingUrl);
         window.open(existingUrl, '_blank', 'noopener,noreferrer');
         toast.success('Membuka halaman pembayaran…');
       } else {
-        console.error('❌ No URL found in any method');
         toast.error('Link pembayaran tidak ditemukan. Silakan coba lagi.');
       }
     } catch (error) {
-      console.error('💥 Payment error:', error);
       toast.error(
         error.response?.data?.description || 'Gagal memproses pembayaran'
       );
     } finally {
-      console.log('🏁 END PAYMENT PROCESS');
       setContLoadingId(null);
     }
   };
-- 
cgit v1.2.3


From 57ace93dc3090a54d65d3b84ae50e8a9249eb314 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 8 Sep 2025 14:58:30 +0700
Subject: <Miqdad> Sip

---
 src/lib/transaction/components/Transactions.jsx | 44 ++++++++++++++-----------
 1 file changed, 24 insertions(+), 20 deletions(-)

(limited to 'src/lib/transaction/components/Transactions.jsx')

diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index 2e3eaaa2..600518fa 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -704,6 +704,30 @@ const Transactions = ({ context = '' }) => {
             active={toOthers}
             close={() => setToOthers(null)}
           >
+            {transactions.data?.status === 'draft' && (
+              <>
+                <button
+                  className='text-left disabled:opacity-60'
+                  disabled={toOthers?.status != 'draft'}
+                  onClick={() => {
+                    downloadQuotation(toOthers);
+                    setToOthers(null);
+                  }}
+                >
+                  Download Quotation
+                </button>
+                <button
+                  className='text-left disabled:opacity-60'
+                  disabled={toOthers?.status != 'waiting'}
+                  onClick={() => {
+                    setToCancel(toOthers);
+                    setToOthers(null);
+                  }}
+                >
+                  Batalkan Transaksi
+                </button>
+              </>
+            )}
             <div className='flex flex-col gap-y-4 mt-2'>
               <button
                 className='text-left disabled:opacity-60'
@@ -715,26 +739,6 @@ const Transactions = ({ context = '' }) => {
               >
                 Download PO
               </button>
-              <button
-                className='text-left disabled:opacity-60'
-                disabled={toOthers?.status != 'draft'}
-                onClick={() => {
-                  downloadQuotation(toOthers);
-                  setToOthers(null);
-                }}
-              >
-                Download Quotation
-              </button>
-              <button
-                className='text-left disabled:opacity-60'
-                disabled={toOthers?.status != 'waiting'}
-                onClick={() => {
-                  setToCancel(toOthers);
-                  setToOthers(null);
-                }}
-              >
-                Batalkan Transaksi
-              </button>
             </div>
           </BottomPopup>
 
-- 
cgit v1.2.3

