summaryrefslogtreecommitdiff
path: root/src/lib/transaction/components
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2025-07-31 15:55:05 +0700
committerit-fixcomart <it@fixcomart.co.id>2025-07-31 15:55:05 +0700
commit04961a55929017f77ee6801d2b7ada4c05689821 (patch)
tree5c519ac632391b34e1cc2bb31d011be37bb2d779 /src/lib/transaction/components
parent077467cf53b46d8049df8b812577cd1a03011eba (diff)
<hafid> fix repeat order
Diffstat (limited to 'src/lib/transaction/components')
-rw-r--r--src/lib/transaction/components/TransactionStatusBadge.jsx4
-rw-r--r--src/lib/transaction/components/Transactions.jsx461
2 files changed, 260 insertions, 205 deletions
diff --git a/src/lib/transaction/components/TransactionStatusBadge.jsx b/src/lib/transaction/components/TransactionStatusBadge.jsx
index e061587c..cb8cbcd9 100644
--- a/src/lib/transaction/components/TransactionStatusBadge.jsx
+++ b/src/lib/transaction/components/TransactionStatusBadge.jsx
@@ -14,11 +14,11 @@ const TransactionStatusBadge = ({ status }) => {
break
case 'waiting':
badgeProps.className.push('badge-yellow')
- badgeProps.text = 'Pesanan Diterima'
+ badgeProps.text = 'Pesanan Diproses'
break
case 'sale':
badgeProps.className.push('badge-yellow')
- badgeProps.text = 'Pesanan Diproses'
+ badgeProps.text = 'Pesanan Dikemas'
break
case 'shipping':
badgeProps.className.push('badge-green')
diff --git a/src/lib/transaction/components/Transactions.jsx b/src/lib/transaction/components/Transactions.jsx
index c4651119..acb925da 100644
--- a/src/lib/transaction/components/Transactions.jsx
+++ b/src/lib/transaction/components/Transactions.jsx
@@ -1,5 +1,5 @@
import { useRouter } from 'next/router';
-import { useEffect, useState } from 'react';
+import { useEffect, useState, useRef } from 'react';
import { toast } from 'react-hot-toast';
import {
EllipsisVerticalIcon,
@@ -34,7 +34,10 @@ import Image from '@/core/components/elements/Image/Image';
import { upsertUserCart } from '~/services/cart';
import { useProductCartContext } from '@/contexts/ProductCartContext';
import { Swiper, SwiperSlide } from 'swiper/react';
+import { 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';
@@ -45,6 +48,7 @@ import { Popover } from '@headlessui/react';
const Transactions = ({ context = '' }) => {
const auth = useAuth();
const router = useRouter();
+ const swiperRef = useRef(null);
const {
q = '',
page = 1,
@@ -80,11 +84,12 @@ const Transactions = ({ context = '' }) => {
const [isOpenCalender, setIsOpenCalender] = useState(false);
const [cachedAllData, setCachedAllData] = useState(null); // Simpan data "All"
const [currentData, setCurrentData] = useState([]); // Data yang ditampilkan
+ const calendarRef = useRef(null);
+ const [isDateSelected, setIsDateSelected] = useState(false);
const parseDate = (date) => {
- if (null || 'null') return null;
- if (!date) return null;
- if (date instanceof Date) return date; // Jika sudah Date, langsung return
+ if (!date || date === 'null') return null;
+ if (date instanceof Date) return date;
const [day, month, year] = date.split('/').map(Number);
return new Date(year, month - 1, day);
};
@@ -106,7 +111,7 @@ const Transactions = ({ context = '' }) => {
sort: sortNew,
startDate: state[0].startDate
? state[0].startDate.toLocaleDateString('id-ID')
- : state[0].startDate,
+ : null,
endDate: state[0]?.endDate?.toLocaleDateString('id-ID'),
site:
siteFilter || (auth?.webRole === null && auth?.site ? auth.site : null),
@@ -114,8 +119,9 @@ const Transactions = ({ context = '' }) => {
const statuses = [
{ id: 'all', label: 'Semua' },
{ id: 'quotation', label: 'Pending Quotation' },
- { id: 'diterima', label: 'Pesanan Diterima' },
{ id: 'diproses', label: 'Pesanan Diproses' },
+ { id: 'dikemas', label: 'Pesanan Dikemas' },
+ { id: 'partial', label: 'Dikirim Sebagian' },
{ id: 'dikirim', label: 'Pesanan Dikirim' },
{ id: 'selesai', label: 'Pesanan Selesai' },
{ id: 'cancel', label: 'Pesanan Dibatalkan' },
@@ -302,6 +308,22 @@ const Transactions = ({ context = '' }) => {
}
};
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (
+ calendarRef.current &&
+ !calendarRef.current.contains(event.target)
+ ) {
+ setIsOpenCalender(false);
+ }
+ };
+
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, []);
+
const startItem = 1 + (pageNew - 1) * limitNew;
const endItem = Math.min(
limitNew * pageNew,
@@ -438,82 +460,82 @@ const Transactions = ({ context = '' }) => {
</option>
))}
</select>
- <div className='relative w-full text-xs'>
- <div
- className='border border-gray-300 rounded-lg bg-white shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 w-full px-2 py-1 flex items-center justify-between cursor-pointer'
- onClick={() => setIsOpenCalender(true)}
- >
- <span className='text-nowrap px-1 truncate'>
- {state[0]?.startDate
- ? `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
- : 'Semua Tanggal'}
- </span>
- </div>
-
- {isOpenCalender && (
- <div className='fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50'>
- <div className='calendar-container bg-white shadow-lg border rounded-lg p-4 w-full'>
- <DateRangePicker
- onChange={(item) => setState([item.selection])}
- showSelectionPreview={true}
- maxDate={new Date()}
- moveRangeOnFirstSelection={false}
- months={1}
- ranges={state}
- direction='horizontal'
- 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>
- <div className='flex flex-row justify-end gap-3 mt-2'>
- <button
- className='px-4 py-1 bg-gray-500 text-white rounded'
- onClick={() => setIsOpenCalender(false)}
- >
- Done
- </button>
- <button
- className='px-4 py-1 bg-red-500 text-white rounded'
- onClick={handleReset}
- >
- Reset
- </button>
- </div>
+ <div ref={calendarRef} className="relative inline-block">
+ <button
+ type='button'
+ className='p-2 w-auto h-auto cursor-pointer 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" />
+ )}
+ </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
+ 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;
+ 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>
+ <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 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}
@@ -643,7 +665,7 @@ const Transactions = ({ context = '' }) => {
{saleOrder.products?.length > 1 && (
<div className='flex flex-row gap-1 justify-start items-center'>
{saleOrder.products
- .slice(1, 6)
+ .slice(1, 4)
.map((product, index) => (
<Image
key={index} // Tambahkan key untuk setiap elemen dalam map()
@@ -652,16 +674,21 @@ const Transactions = ({ context = '' }) => {
className='object-contain object-center border border-gray_r-6 h-8 w-8 rounded-md'
/>
))}
- <Link
- href={`${router.pathname}/${saleOrder?.id}`}
- className=' text-red-500 text-nowrap'
- >
- {saleOrder.products?.length > 6
- ? 'Lihat ' +
- (saleOrder.products?.length - 6) +
- ' produk lainnya'
- : 'Lihat semua produk'}
- </Link>
+ {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>
+ )}
</div>
)}
</div>
@@ -880,33 +907,60 @@ const Transactions = ({ context = '' }) => {
</div>
</div>
</div>
- <div className='flex flex-col gap-y-2 border rounded-lg mb-2'>
+ <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'>
<span className='text-base font-semibold text-gray-600'>
Status
</span>
- <Swiper
- spaceBetween={10}
- slidesPerView={5.8}
- className='w-full h-8'
- >
- {statuses.map((status) => (
- <SwiperSlide key={status.id} className='w-auto'>
- <button
- className={`px-4 py-1 text-sm font-medium border rounded-lg transition whitespace-nowrap min-w-40
- ${
- statusNew === status.id
- ? 'border-red-500 text-red-500 bg-white'
- : 'border-gray-300 text-gray-400 bg-gray-100 hover:bg-gray-200'
- }`}
- onClick={() => handleStatusChange(status.id)}
+ <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" 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">
+ <Swiper
+ spaceBetween={10}
+ slidesPerView="auto"
+ className="status-swiper"
+ modules={[Navigation]}
+ navigation={{
+ nextEl: '.custom-next',
+ prevEl: '.custom-prev',
+ }}
>
- {status.label}
- </button>
- </SwiperSlide>
- ))}
- </Swiper>
+ {statuses.map((status) => (
+ <SwiperSlide key={status.id} className="!w-auto">
+ <button
+ className={`px-4 py-1 text-sm font-medium border rounded-lg transition whitespace-nowrap
+ ${statusNew === status.id
+ ? 'border-red-500 text-red-500 bg-white'
+ : 'border-gray-300 text-gray-400 bg-gray-100 hover:bg-gray-200'
+ }`}
+ onClick={() => handleStatusChange(status.id)}
+ >
+ {status.label}
+ </button>
+ </SwiperSlide>
+ ))}
+ </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" 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>
+ </div>
</div>
</div>
<div className='flex flex-row items-center justify-between mb-2 p-2'>
@@ -944,86 +998,6 @@ const Transactions = ({ context = '' }) => {
</button>
</form>
</div>
- <div className='flex flex-col gap-2 pb-2'>
- <button
- type='button'
- className='form-input btn py-4 mt-1 cursor-pointer hover:bg-gray-100 rounded transition duration-150 ease-in-out text-left w-full'
- onClick={() => setIsOpenCalender(true)}
- >
- <span className='text-nowrap px-1 truncate'>
- {state[0]?.startDate
- ? `${state[0].startDate.toLocaleDateString()} - ${state[0].endDate.toLocaleDateString()}`
- : 'Filter By Tanggal'}
- </span>
- </button>
- {isOpenCalender && (
- <div className='absolute mt-2 bg-white p-4 rounded shadow-lg'>
- {/* 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={true}
- maxDate={new Date()}
- moveRangeOnFirstSelection={false}
- months={1}
- ranges={state}
- 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>
- <div className='flex flex-row justify-end gap-3 mt-2'>
- <button
- className='px-4 py-1 bg-gray-500 text-white rounded'
- onClick={() => setIsOpenCalender(false)}
- >
- Done
- </button>
- <button
- className='px-4 py-1 bg-red-500 text-white rounded'
- onClick={handleReset}
- >
- Reset
- </button>
- </div>
- </div>
- )}
- </div>
<div className='flex flex-row gap-4 items-center justify-center'>
<p>
Menampilkan {startItem}-
@@ -1050,6 +1024,82 @@ const Transactions = ({ context = '' }) => {
<option value={15}>15</option>
<option value={20}>20</option>
</select>
+ <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" />
+ )}
+ </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>{`
+ /* 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>
+ <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>
</div>
@@ -1140,7 +1190,7 @@ const Transactions = ({ context = '' }) => {
{saleOrder.products?.length > 1 && (
<div className='flex flex-row gap-1 justify-start items-center'>
{saleOrder.products
- .slice(1, 6)
+ .slice(1, 4)
.map((product, index) => (
<Image
key={index} // Tambahkan key untuk setiap elemen dalam map()
@@ -1149,16 +1199,21 @@ const Transactions = ({ context = '' }) => {
className='object-contain object-center border border-gray_r-6 h-16 w-16 rounded-md'
/>
))}
- <Link
- href={`${router.pathname}/${saleOrder?.id}`}
- className='text-sm text-red-500 text-nowrap'
- >
- {saleOrder.products?.length > 6
- ? 'Lihat ' +
- (saleOrder.products?.length - 6) +
- ' produk lainnya'
- : 'Lihat semua produk'}
- </Link>
+ {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>
+ )}
</div>
)}
</div>