status order
This commit is contained in:
@@ -11,7 +11,7 @@ import Currency from './pages/Currency';
|
|||||||
import Employees from './pages/Employees';
|
import Employees from './pages/Employees';
|
||||||
import Login from './pages/Login';
|
import Login from './pages/Login';
|
||||||
import Payments from './pages/Payments';
|
import Payments from './pages/Payments';
|
||||||
import Permissions from './pages/Permissions'; // Yangi sahifa
|
import Permissions from './pages/Permissions';
|
||||||
import Reference from './pages/Reference';
|
import Reference from './pages/Reference';
|
||||||
import Warhouses from './pages/Warhouses';
|
import Warhouses from './pages/Warhouses';
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
import { Search } from 'lucide-react';
|
import { Search } from 'lucide-react';
|
||||||
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
|
||||||
const Searchs = ({ searchTerm, loading, setSearchTerm, placeholder = 'Ism, telefon yoki manzil bo‘yicha qidirish...' }) => {
|
interface Props {
|
||||||
|
searchTerm: string;
|
||||||
|
loading: boolean;
|
||||||
|
setSearchTerm: Dispatch<SetStateAction<string>>;
|
||||||
|
placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Searchs = ({ searchTerm, loading, setSearchTerm, placeholder = 'Qidirish' }: Props) => {
|
||||||
return (
|
return (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label htmlFor="search" className="sr-only">
|
<label htmlFor="search" className="sr-only">
|
||||||
Qidiruv
|
Qidiruv
|
||||||
</label>
|
</label>
|
||||||
<div className="relative max-w-md">
|
<div className="relative max-w-md">
|
||||||
<input type="text" id="search" placeholder={placeholder} value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} className="w-full border border-slate-300 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]" disabled={loading} />
|
<input
|
||||||
|
type="text"
|
||||||
|
id="search"
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
className="w-full border border-slate-300 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
|
||||||
|
disabled={loading}
|
||||||
|
/>
|
||||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|||||||
import { Edit, Trash2, Users } from 'lucide-react';
|
import { Edit, Trash2, Users } from 'lucide-react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import axiosInstance from '../../api/axiosInstance';
|
import axiosInstance from '../../api/axiosInstance';
|
||||||
import Searchs from '../../components/Searchs';
|
|
||||||
import Pagination from '../Pagination';
|
import Pagination from '../Pagination';
|
||||||
|
import Searchs from '../Searchs';
|
||||||
|
|
||||||
const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
||||||
const client = useQueryClient();
|
const client = useQueryClient();
|
||||||
@@ -24,7 +24,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
axiosInstance.get('/clients/list', {
|
axiosInstance.get('/clients/list', {
|
||||||
params: {
|
params: {
|
||||||
page: currentPage,
|
page: currentPage,
|
||||||
sort: 'id',
|
sort: 'active',
|
||||||
clientName: searchTerm,
|
clientName: searchTerm,
|
||||||
direction: 'desc',
|
direction: 'desc',
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { mutate: deleteClient, isPending: deleteLoad } = useMutation({
|
const { mutate: deleteClient, isPending: deleteLoad } = useMutation({
|
||||||
mutationFn: (id: number) => axiosInstance.delete(`/users/delete/${id}`),
|
mutationFn: (id) => axiosInstance.delete(`/users/delete/${id}`),
|
||||||
mutationKey: ['clientsDelete'],
|
mutationKey: ['clientsDelete'],
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
client.invalidateQueries({ queryKey: ['clients'] });
|
client.invalidateQueries({ queryKey: ['clients'] });
|
||||||
@@ -57,7 +57,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page) => {
|
||||||
setCurrentPage(page);
|
setCurrentPage(page);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +81,10 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
<th className="text-left p-4">Passport seriyasi</th>
|
<th className="text-left p-4">Passport seriyasi</th>
|
||||||
<th className="text-left p-4">PNFL</th>
|
<th className="text-left p-4">PNFL</th>
|
||||||
<th className="text-left p-4">Tug'ilgan sana</th>
|
<th className="text-left p-4">Tug'ilgan sana</th>
|
||||||
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && <th className="text-left p-4">Amallar</th>}
|
<th className="text-left p-4">Holati</th>
|
||||||
|
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
||||||
|
<th className="text-left p-4">Amallar</th>
|
||||||
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-slate-200">
|
<tbody className="divide-y divide-slate-200">
|
||||||
@@ -95,14 +98,32 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
<td className="p-4">{client.passportSeries}</td>
|
<td className="p-4">{client.passportSeries}</td>
|
||||||
<td className="p-4">{client.pinfl}</td>
|
<td className="p-4">{client.pinfl}</td>
|
||||||
<td className="p-4">{client.dateOfBirth}</td>
|
<td className="p-4">{client.dateOfBirth}</td>
|
||||||
|
{/* <label className="relative inline-flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="sr-only peer"
|
||||||
|
checked={client.active}
|
||||||
|
onChange={handleActive}
|
||||||
|
/>
|
||||||
|
<div className="w-11 h-6 bg-gray-300 rounded-full peer peer-checked:bg-blue-600 peer-focus:ring-2 peer-focus:ring-blue-400 transition-colors duration-300"></div>
|
||||||
|
<div className="absolute left-1 top-1 w-4 h-4 bg-white rounded-full transition-transform duration-300 peer-checked:translate-x-5"></div>
|
||||||
|
</label> */}
|
||||||
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
||||||
<td className="p-4">
|
<td className="p-4">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button onClick={() => handleEdit(client.id, client.aviaCargoId)} className="flex items-center gap-1 border border-yellow-300 text-yellow-700 hover:bg-yellow-50 px-3 py-1 rounded-lg" disabled={isLoading}>
|
<button
|
||||||
|
onClick={() => handleEdit(client.id, client.aviaCargoId)}
|
||||||
|
className="flex items-center gap-1 border border-yellow-300 text-yellow-700 hover:bg-yellow-50 px-3 py-1 rounded-lg"
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
<Edit className="h-4 w-4" />
|
<Edit className="h-4 w-4" />
|
||||||
<span className="hidden sm:inline">Tahrirlash</span>
|
<span className="hidden sm:inline">Tahrirlash</span>
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => deleteClient(client.id)} className="flex items-center gap-1 border border-red-300 text-red-700 hover:bg-red-50 px-3 py-1 rounded-lg" disabled={deleteLoad}>
|
<button
|
||||||
|
onClick={() => deleteClient(client.id)}
|
||||||
|
className="flex items-center gap-1 border border-red-300 text-red-700 hover:bg-red-50 px-3 py-1 rounded-lg"
|
||||||
|
disabled={deleteLoad}
|
||||||
|
>
|
||||||
<Trash2 className="h-4 w-4" />
|
<Trash2 className="h-4 w-4" />
|
||||||
<span className="hidden sm:inline">O'chirish</span>
|
<span className="hidden sm:inline">O'chirish</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -116,7 +137,13 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-end mt-5 justify-end">
|
<div className="flex items-end mt-5 justify-end">
|
||||||
<Pagination currentPage={currentPage} totalPages={data?.totalPages || 1} totalElements={data?.totalElements || 0} onPageChange={handlePageChange} isLoading={isLoading} />
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
totalPages={data?.totalPages || 1}
|
||||||
|
totalElements={data?.totalElements || 0}
|
||||||
|
onPageChange={handlePageChange}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -80,7 +80,7 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
const { data: client, refetch: clientRef } = useQuery({
|
const { data: client, refetch: clientRef } = useQuery({
|
||||||
queryKey: ['client_one'],
|
queryKey: ['client_one'],
|
||||||
queryFn: async () => axiosInstance.get('/clients/list', { params: { cargoId } }),
|
queryFn: async () => axiosInstance.get('/clients/list', { params: { cargoId } }),
|
||||||
select: (data) => data.data.data as { data: any[] },
|
select: (data) => data.data.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, refetch } = useQuery({
|
const { data, refetch } = useQuery({
|
||||||
@@ -102,23 +102,24 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
phone: c.phone,
|
phone: c.phone,
|
||||||
pinfl: c.pinfl,
|
pinfl: c.pinfl,
|
||||||
});
|
});
|
||||||
|
setActive(c.active);
|
||||||
}
|
}
|
||||||
clientRef();
|
clientRef();
|
||||||
refetch();
|
refetch();
|
||||||
}, [cargoId, client, refetch, clientRef]);
|
}, [cargoId, client, refetch, clientRef]);
|
||||||
|
|
||||||
// useEffect(() => {
|
useEffect(() => {
|
||||||
// if (currentPassport) {
|
if (currentPassport) {
|
||||||
// setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
// ...prev,
|
...prev,
|
||||||
// fullName: currentPassport.fullName || '',
|
fullName: currentPassport.fullName || '',
|
||||||
// passportSeries: currentPassport.passportSeries || '',
|
passportSeries: currentPassport.passportSeries || '',
|
||||||
// pinfl: currentPassport.passportPin || '',
|
pinfl: currentPassport.passportPin || '',
|
||||||
// dateOfBirth: formatDate(currentPassport.birthDate),
|
dateOfBirth: formatDate(currentPassport.birthDate),
|
||||||
// }));
|
}));
|
||||||
// setActive(currentPassport.active);
|
setActive(currentPassport.active);
|
||||||
// }
|
}
|
||||||
// }, [currentPassport]);
|
}, [currentPassport]);
|
||||||
|
|
||||||
const { mutate: createMutate } = useMutation({
|
const { mutate: createMutate } = useMutation({
|
||||||
mutationFn: async (params: any) => {
|
mutationFn: async (params: any) => {
|
||||||
@@ -202,6 +203,8 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
setAlert({ type: 'success', message: "Passport ma'lumotlari yangilandi." });
|
setAlert({ type: 'success', message: "Passport ma'lumotlari yangilandi." });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(active);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
||||||
@@ -211,7 +214,15 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
{clients ? 'Mijozni tahrirlash' : "Yangi mijoz qo'shish"}
|
{clients ? 'Mijozni tahrirlash' : "Yangi mijoz qo'shish"}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{clients && data && data.length > 0 && <PassportCarousel passports={data} onUpdate={handlePassportUpdate} setTargetImage={setTargetImage} setOpenModal={setOpenModal} setCurrentPassport={setCurrentPassport} />}
|
{clients && data && data.length > 0 && (
|
||||||
|
<PassportCarousel
|
||||||
|
passports={data}
|
||||||
|
onUpdate={handlePassportUpdate}
|
||||||
|
setTargetImage={setTargetImage}
|
||||||
|
setOpenModal={setOpenModal}
|
||||||
|
setCurrentPassport={setCurrentPassport}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<form className="space-y-6" onSubmit={onSubmit}>
|
<form className="space-y-6" onSubmit={onSubmit}>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mt-10">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mt-10">
|
||||||
@@ -225,13 +236,24 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
].map((field) => (
|
].map((field) => (
|
||||||
<div key={field.name}>
|
<div key={field.name}>
|
||||||
<label className="block text-sm font-medium mb-1">{field.label}</label>
|
<label className="block text-sm font-medium mb-1">{field.label}</label>
|
||||||
<input type={field.type} name={field.name} value={formData[field.name as keyof FormData]} onChange={handleChange} className="w-full border border-slate-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]" />
|
<input
|
||||||
|
type={field.type}
|
||||||
|
name={field.name}
|
||||||
|
value={formData[field.name as keyof FormData]}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full border border-slate-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{clients && currentPassport && (
|
{clients && currentPassport && (
|
||||||
<label className="relative inline-flex items-center cursor-pointer">
|
<label className="relative inline-flex items-center cursor-pointer">
|
||||||
<input type="checkbox" className="sr-only peer" checked={active} onChange={handleActive} />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="sr-only peer"
|
||||||
|
checked={active}
|
||||||
|
onChange={handleActive}
|
||||||
|
/>
|
||||||
<div className="w-11 h-6 bg-gray-300 rounded-full peer peer-checked:bg-blue-600 peer-focus:ring-2 peer-focus:ring-blue-400 transition-colors duration-300"></div>
|
<div className="w-11 h-6 bg-gray-300 rounded-full peer peer-checked:bg-blue-600 peer-focus:ring-2 peer-focus:ring-blue-400 transition-colors duration-300"></div>
|
||||||
<div className="absolute left-1 top-1 w-4 h-4 bg-white rounded-full transition-transform duration-300 peer-checked:translate-x-5"></div>
|
<div className="absolute left-1 top-1 w-4 h-4 bg-white rounded-full transition-transform duration-300 peer-checked:translate-x-5"></div>
|
||||||
</label>
|
</label>
|
||||||
@@ -239,22 +261,42 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-3 pt-4">
|
<div className="flex flex-col sm:flex-row gap-3 pt-4">
|
||||||
<button type="submit" className="bg-[#3489e3] hover:bg-blue-500 text-white px-6 py-2 rounded-lg disabled:opacity-60">
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="bg-[#3489e3] hover:bg-blue-500 text-white px-6 py-2 rounded-lg disabled:opacity-60"
|
||||||
|
>
|
||||||
{clients ? 'Yangilash' : "Qo'shish"}
|
{clients ? 'Yangilash' : "Qo'shish"}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="border border-slate-300 text-slate-700 hover:bg-slate-50 px-6 py-2 rounded-lg">
|
<button
|
||||||
|
type="button"
|
||||||
|
className="border border-slate-300 text-slate-700 hover:bg-slate-50 px-6 py-2 rounded-lg"
|
||||||
|
>
|
||||||
Bekor qilish
|
Bekor qilish
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{tagetIamge && opneModal && <ModalIamge image={tagetIamge} setTargetImage={setTargetImage} setOpenModal={setOpenModal} />}
|
{tagetIamge && opneModal && (
|
||||||
|
<ModalIamge
|
||||||
|
image={tagetIamge}
|
||||||
|
setTargetImage={setTargetImage}
|
||||||
|
setOpenModal={setOpenModal}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModalIamge = ({ image, setTargetImage, setOpenModal }: { image: string; setTargetImage: (img: string | null) => void; setOpenModal: (open: boolean) => void }) => {
|
const ModalIamge = ({
|
||||||
|
image,
|
||||||
|
setTargetImage,
|
||||||
|
setOpenModal,
|
||||||
|
}: {
|
||||||
|
image: string;
|
||||||
|
setTargetImage: (img: string | null) => void;
|
||||||
|
setOpenModal: (open: boolean) => void;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-screen bg-black/60 fixed top-0 bottom-0 left-0 z-50 overflow-hidden">
|
<div className="w-full h-screen bg-black/60 fixed top-0 bottom-0 left-0 z-50 overflow-hidden">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { AlertCircle, CheckCircle, Clock, CreditCard, Package, Phone, User, X, XCircle } from 'lucide-react';
|
import {
|
||||||
|
AlertCircle,
|
||||||
|
CheckCircle,
|
||||||
|
Clock,
|
||||||
|
CreditCard,
|
||||||
|
Package,
|
||||||
|
Phone,
|
||||||
|
User,
|
||||||
|
X,
|
||||||
|
XCircle,
|
||||||
|
} from 'lucide-react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import axiosInstance from '../../api/axiosInstance';
|
import axiosInstance from '../../api/axiosInstance';
|
||||||
import { cn } from '../../lib/utils';
|
import { cn } from '../../lib/utils';
|
||||||
@@ -71,7 +81,9 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
return new Intl.NumberFormat('uz-UZ').format(amount) + " so'm";
|
return new Intl.NumberFormat('uz-UZ').format(amount) + " so'm";
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentStatus = data ? paymentStatuses.find((status) => status.value === data.paymentStatus) : paymentStatuses[0];
|
const currentStatus = data
|
||||||
|
? paymentStatuses.find((status) => status.value === data.paymentStatus)
|
||||||
|
: paymentStatuses[0];
|
||||||
const CurrentIcon = currentStatus ? currentStatus.icon : paymentStatuses[0];
|
const CurrentIcon = currentStatus ? currentStatus.icon : paymentStatuses[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -80,7 +92,10 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
<div className="relative bg-white rounded-xl shadow-2xl w-[800px] max-w-[95vw] max-h-[90vh] overflow-hidden">
|
<div className="relative bg-white rounded-xl shadow-2xl w-[800px] max-w-[95vw] max-h-[90vh] overflow-hidden">
|
||||||
<div className="flex items-center justify-between p-6 border-b border-gray-200">
|
<div className="flex items-center justify-between p-6 border-b border-gray-200">
|
||||||
<h2 className="text-xl font-semibold text-gray-900">To'lov ma'lumotlari</h2>
|
<h2 className="text-xl font-semibold text-gray-900">To'lov ma'lumotlari</h2>
|
||||||
<button onClick={onClose} className="p-2 rounded-full hover:bg-gray-100 transition-colors">
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="p-2 rounded-full hover:bg-gray-100 transition-colors"
|
||||||
|
>
|
||||||
<X className="w-5 h-5 text-gray-500" />
|
<X className="w-5 h-5 text-gray-500" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,7 +105,10 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
<div className="flex flex-col items-center justify-center py-12">
|
<div className="flex flex-col items-center justify-center py-12">
|
||||||
<XCircle className="w-12 h-12 text-red-400 mb-3" />
|
<XCircle className="w-12 h-12 text-red-400 mb-3" />
|
||||||
<p className="text-red-600 text-center">Ma'lumotlarni yuklashda xatolik yuz berdi</p>
|
<p className="text-red-600 text-center">Ma'lumotlarni yuklashda xatolik yuz berdi</p>
|
||||||
<button onClick={() => refetch()} className="mt-3 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
|
<button
|
||||||
|
onClick={() => refetch()}
|
||||||
|
className="mt-3 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
|
>
|
||||||
Qayta urinish
|
Qayta urinish
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,7 +143,14 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<span className="font-medium text-lg text-gray-600">To'lov holati:</span>
|
<span className="font-medium text-lg text-gray-600">To'lov holati:</span>
|
||||||
<button className={cn('inline-flex w-fit items-center gap-1 px-2 py-1 rounded-full font-medium text-lg', currentStatus.bgColor, currentStatus.borderColor, currentStatus.color)}>
|
<button
|
||||||
|
className={cn(
|
||||||
|
'inline-flex w-fit items-center gap-1 px-2 py-1 rounded-full font-medium text-lg',
|
||||||
|
currentStatus.bgColor,
|
||||||
|
currentStatus.borderColor,
|
||||||
|
currentStatus.color
|
||||||
|
)}
|
||||||
|
>
|
||||||
<CurrentIcon className="h-4 w-4" />
|
<CurrentIcon className="h-4 w-4" />
|
||||||
<span className="font-medium">{currentStatus.label}</span>
|
<span className="font-medium">{currentStatus.label}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -162,11 +187,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
<button
|
<button
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex w-fit items-center gap-1 px-2 py-1 rounded-full font-medium text-lg',
|
'inline-flex w-fit items-center gap-1 px-2 py-1 rounded-full font-medium text-lg',
|
||||||
data.paymentType === null ? 'bg-red-50 text-red-600 border-red-200' : data.paymentType === 'CASH' ? 'bg-green-50 text-green-600 border-green-200' : 'bg-green-50 text-green-600 border-green-200'
|
data.paymentType === null
|
||||||
|
? 'bg-red-50 text-red-600 border-red-200'
|
||||||
|
: data.paymentType === 'CASH'
|
||||||
|
? 'bg-green-50 text-green-600 border-green-200'
|
||||||
|
: 'bg-green-50 text-green-600 border-green-200'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CurrentIcon className="h-4 w-4" />
|
<CurrentIcon className="h-4 w-4" />
|
||||||
<span className="font-medium">{data.paymentType === null ? "To'lanmagan" : data.paymentType === 'CASH' ? 'Naqd' : data.paymentType}</span>
|
<span className="font-medium">
|
||||||
|
{data.paymentType === null
|
||||||
|
? "To'lanmagan"
|
||||||
|
: data.paymentType === 'CASH'
|
||||||
|
? 'Naqd'
|
||||||
|
: data.paymentType}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -183,16 +218,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
{data.clickTransactions.map((transaction, index) => (
|
{data.clickTransactions.map((transaction, index) => (
|
||||||
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
|
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<span className="font-medium text-lg text-gray-900">ID: {transaction.transactionId}</span>
|
<span className="font-medium text-lg text-gray-900">
|
||||||
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg ${getStatusColor(transaction.status)}`}>
|
ID: {transaction.transactionId}
|
||||||
{getStatusIcon(transaction.status)}
|
</span>
|
||||||
|
<span
|
||||||
|
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg`}
|
||||||
|
>
|
||||||
{transaction.status}
|
{transaction.status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Summa:</span>
|
<span className="font-medium text-lg text-gray-600">Summa:</span>
|
||||||
<p className="text-gray-900 font-semibold">{formatAmount(transaction.amount)}</p>
|
<p className="text-gray-900 font-semibold">
|
||||||
|
{formatAmount(transaction.amount)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Provayder:</span>
|
<span className="font-medium text-lg text-gray-600">Provayder:</span>
|
||||||
@@ -204,13 +244,19 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
</div>
|
</div>
|
||||||
{transaction.completeTime && (
|
{transaction.completeTime && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Tugallangan:</span>
|
<span className="font-medium text-lg text-gray-600">
|
||||||
<p className="text-gray-900">{formatDate(transaction.completeTime)}</p>
|
Tugallangan:
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-900">
|
||||||
|
{formatDate(transaction.completeTime)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{transaction.cancelTime && (
|
{transaction.cancelTime && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Bekor qilingan:</span>
|
<span className="font-medium text-lg text-gray-600">
|
||||||
|
Bekor qilingan:
|
||||||
|
</span>
|
||||||
<p className="text-gray-900">{formatDate(transaction.cancelTime)}</p>
|
<p className="text-gray-900">{formatDate(transaction.cancelTime)}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -239,16 +285,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
{data.paymeTransactions.map((transaction, index) => (
|
{data.paymeTransactions.map((transaction, index) => (
|
||||||
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
|
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<span className="font-medium text-lg text-gray-900">ID: {transaction.transactionId}</span>
|
<span className="font-medium text-lg text-gray-900">
|
||||||
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg ${getStatusColor(transaction.status)}`}>
|
ID: {transaction.transactionId}
|
||||||
{getStatusIcon(transaction.status)}
|
</span>
|
||||||
|
<span
|
||||||
|
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg`}
|
||||||
|
>
|
||||||
{transaction.status}
|
{transaction.status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Summa:</span>
|
<span className="font-medium text-lg text-gray-600">Summa:</span>
|
||||||
<p className="text-gray-900 font-semibold">{formatAmount(transaction.amount)}</p>
|
<p className="text-gray-900 font-semibold">
|
||||||
|
{formatAmount(transaction.amount)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Provayder:</span>
|
<span className="font-medium text-lg text-gray-600">Provayder:</span>
|
||||||
@@ -260,13 +311,19 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
</div>
|
</div>
|
||||||
{transaction.completeTime && (
|
{transaction.completeTime && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Tugallangan:</span>
|
<span className="font-medium text-lg text-gray-600">
|
||||||
<p className="text-gray-900">{formatDate(transaction.completeTime)}</p>
|
Tugallangan:
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-900">
|
||||||
|
{formatDate(transaction.completeTime)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{transaction.cancelTime && (
|
{transaction.cancelTime && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-lg text-gray-600">Bekor qilingan:</span>
|
<span className="font-medium text-lg text-gray-600">
|
||||||
|
Bekor qilingan:
|
||||||
|
</span>
|
||||||
<p className="text-gray-900">{formatDate(transaction.cancelTime)}</p>
|
<p className="text-gray-900">{formatDate(transaction.cancelTime)}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -285,12 +342,16 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(!data.clickTransactions || data.clickTransactions.length === 0) && (!data.paymeTransactions || data.paymeTransactions.length === 0) && !(['PAYED', 'PENDING'].includes(data.paymentStatus) && data.paymentType === 'CASH') && (
|
{(!data.clickTransactions || data.clickTransactions.length === 0) &&
|
||||||
<div className="text-center py-8">
|
(!data.paymeTransactions || data.paymeTransactions.length === 0) &&
|
||||||
<Clock className="w-12 h-12 text-gray-400 mx-auto mb-3" />
|
!(
|
||||||
<p className="text-gray-500">Hozircha tranzaksiyalar mavjud emas</p>
|
['PAYED', 'PENDING'].includes(data.paymentStatus) && data.paymentType === 'CASH'
|
||||||
</div>
|
) && (
|
||||||
)}
|
<div className="text-center py-8">
|
||||||
|
<Clock className="w-12 h-12 text-gray-400 mx-auto mb-3" />
|
||||||
|
<p className="text-gray-500">Hozircha tranzaksiyalar mavjud emas</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center justify-center py-12">
|
<div className="flex items-center justify-center py-12">
|
||||||
|
|||||||
@@ -40,18 +40,14 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
|
|||||||
const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });
|
const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });
|
||||||
const buttonRef = useRef(null);
|
const buttonRef = useRef(null);
|
||||||
|
|
||||||
const currentStatus = paymentStatuses.find((status) => status.value === value) || paymentStatuses[0];
|
const currentStatus =
|
||||||
|
paymentStatuses.find((status) => status.value === value) || paymentStatuses[0];
|
||||||
const CurrentIcon = currentStatus.icon;
|
const CurrentIcon = currentStatus.icon;
|
||||||
|
|
||||||
const handleSelect = (statusValue) => {
|
const handleSelect = (statusValue) => {
|
||||||
if (statusValue === 'PAID' && (value === 'UNPAID' || value === 'PENDING')) {
|
// Faqat PAYED holatiga o'tkazish
|
||||||
|
if (statusValue === 'PAYED' && value !== 'PAYED') {
|
||||||
onChange('PAYED');
|
onChange('PAYED');
|
||||||
} else if (statusValue === 'PAID' && value === 'PAID') {
|
|
||||||
// Already paid, do nothing
|
|
||||||
return;
|
|
||||||
} else if (statusValue !== 'PAID') {
|
|
||||||
// Show warning for non-PAID status changes
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
};
|
};
|
||||||
@@ -88,17 +84,18 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
|
|||||||
<CurrentIcon className="h-4 w-4" />
|
<CurrentIcon className="h-4 w-4" />
|
||||||
<span className="font-medium">{currentStatus.label}</span>
|
<span className="font-medium">{currentStatus.label}</span>
|
||||||
</div>
|
</div>
|
||||||
{!disabled && <ChevronDown className={cn('h-4 w-4 transition-transform duration-200', isOpen && 'rotate-180')} />}
|
{!disabled && (
|
||||||
|
<ChevronDown
|
||||||
|
className={cn('h-4 w-4 transition-transform duration-200', isOpen && 'rotate-180')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Options (portal) */}
|
{/* Options (portal) */}
|
||||||
{isOpen &&
|
{isOpen &&
|
||||||
createPortal(
|
createPortal(
|
||||||
<>
|
<>
|
||||||
{/* Backdrop */}
|
|
||||||
<div className="fixed inset-0 z-40" onClick={() => setIsOpen(false)} />
|
<div className="fixed inset-0 z-40" onClick={() => setIsOpen(false)} />
|
||||||
|
|
||||||
{/* Dropdown */}
|
|
||||||
<div
|
<div
|
||||||
className="absolute bg-white border border-slate-200 rounded-lg shadow-lg z-50 overflow-hidden"
|
className="absolute bg-white border border-slate-200 rounded-lg shadow-lg z-50 overflow-hidden"
|
||||||
style={{
|
style={{
|
||||||
@@ -111,17 +108,24 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
|
|||||||
{paymentStatuses.map((status) => {
|
{paymentStatuses.map((status) => {
|
||||||
const StatusIcon = status.icon;
|
const StatusIcon = status.icon;
|
||||||
const isSelected = status.value === value;
|
const isSelected = status.value === value;
|
||||||
const isDisabled = status.value !== 'PAID' || value === 'PAID';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={status.value}
|
key={status.value}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => !isDisabled && handleSelect(status.value)}
|
onClick={() => handleSelect(status.value)}
|
||||||
disabled={isDisabled}
|
className={cn(
|
||||||
className={cn('flex items-center gap-3 w-full px-3 py-2.5 text-sm transition-colors duration-150', isDisabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-slate-50 focus:bg-slate-50 focus:outline-none cursor-pointer', isSelected && 'bg-slate-100')}
|
'flex items-center gap-3 w-full px-3 py-2.5 text-sm hover:bg-slate-50 transition-colors duration-150'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className={cn('flex items-center justify-center w-6 h-6 rounded-full', status.bgColor, status.borderColor, 'border')}>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex items-center justify-center w-6 h-6 rounded-full',
|
||||||
|
status.bgColor,
|
||||||
|
status.borderColor,
|
||||||
|
'border'
|
||||||
|
)}
|
||||||
|
>
|
||||||
<StatusIcon className={cn('h-3 w-3', status.color)} />
|
<StatusIcon className={cn('h-3 w-3', status.color)} />
|
||||||
</div>
|
</div>
|
||||||
<span className={cn('font-medium', status.color)}>{status.label}</span>
|
<span className={cn('font-medium', status.color)}>{status.label}</span>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { QrCode, Search, Users } from 'lucide-react';
|
import { QrCode, Search, Users } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import axiosInstance from '../../api/axiosInstance';
|
import axiosInstance from '../../api/axiosInstance';
|
||||||
import Pagination from '../Pagination';
|
import Pagination from '../Pagination';
|
||||||
import ModalPayment from './ModalPayment';
|
import ModalPayment from './ModalPayment';
|
||||||
@@ -17,15 +17,17 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
const [isPaymentModalOpen, setIsPaymentModalOpen] = useState(false);
|
const [isPaymentModalOpen, setIsPaymentModalOpen] = useState(false);
|
||||||
const [scannedResult, setScannedResult] = useState(null);
|
const [scannedResult, setScannedResult] = useState(null);
|
||||||
const [packetid, setPacketId] = useState();
|
const [packetid, setPacketId] = useState();
|
||||||
|
const [userRole, setUserRole] = useState('');
|
||||||
|
|
||||||
const userRole = (() => {
|
useEffect(() => {
|
||||||
try {
|
const storedUser = localStorage.getItem('user');
|
||||||
const storedUser = localStorage.getItem('user');
|
if (storedUser) {
|
||||||
return storedUser ? JSON.parse(storedUser).user.role : null;
|
const parsed = JSON.parse(storedUser);
|
||||||
} catch {
|
setUserRole(parsed.user?.role || null);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
})();
|
}, []);
|
||||||
|
|
||||||
|
console.log(userRole);
|
||||||
|
|
||||||
const { data, isLoading, refetch } = useQuery({
|
const { data, isLoading, refetch } = useQuery({
|
||||||
queryKey: ['payments_list', currentPage, searchTerm, cargoType],
|
queryKey: ['payments_list', currentPage, searchTerm, cargoType],
|
||||||
@@ -36,6 +38,7 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
cargoType,
|
cargoType,
|
||||||
size: 30,
|
size: 30,
|
||||||
search: searchTerm,
|
search: searchTerm,
|
||||||
|
sort: 'paymentStatus',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
select(data) {
|
select(data) {
|
||||||
@@ -86,7 +89,11 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
refetch();
|
refetch();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ModalPayment packetId={packetid} isOpen={isPaymentModalOpen} onClose={() => setIsPaymentModalOpen(false)} />
|
<ModalPayment
|
||||||
|
packetId={packetid}
|
||||||
|
isOpen={isPaymentModalOpen}
|
||||||
|
onClose={() => setIsPaymentModalOpen(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="relative flex gap-4">
|
<div className="relative flex gap-4">
|
||||||
<div className="mb-4 w-[90%]">
|
<div className="mb-4 w-[90%]">
|
||||||
@@ -97,7 +104,7 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="search"
|
id="search"
|
||||||
placeholder={"Cargo Ids, Partiya nomi, Paket nomi bo'yicha qidirish"}
|
placeholder={"Cargo Ids, Paket nomi bo'yicha qidirish"}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="w-full border border-slate-300 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
|
className="w-full border border-slate-300 rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
|
||||||
@@ -106,7 +113,11 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 w-[10%]">
|
<div className="mb-4 w-[10%]">
|
||||||
<select name="role" className="w-full border border-slate-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]" onChange={(e) => setCargoType(e.target.value)}>
|
<select
|
||||||
|
name="role"
|
||||||
|
className="w-full border border-slate-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
|
||||||
|
onChange={(e) => setCargoType(e.target.value)}
|
||||||
|
>
|
||||||
<option value="">Barchasi</option>
|
<option value="">Barchasi</option>
|
||||||
<option value="AVIA">AVIA</option>
|
<option value="AVIA">AVIA</option>
|
||||||
<option value="AUTO">AUTO</option>
|
<option value="AUTO">AUTO</option>
|
||||||
@@ -115,7 +126,10 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end mb-4">
|
<div className="flex justify-end mb-4">
|
||||||
<button className="bg-[#28A7E8] rounded-md p-2 cursor-pointer hover:bg-[#2196d3] transition-colors" onClick={() => setIsQrModalOpen(true)}>
|
<button
|
||||||
|
className="bg-[#28A7E8] rounded-md p-2 cursor-pointer hover:bg-[#2196d3] transition-colors"
|
||||||
|
onClick={() => setIsQrModalOpen(true)}
|
||||||
|
>
|
||||||
<QrCode className="size-6 text-white" />
|
<QrCode className="size-6 text-white" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -162,10 +176,20 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
<td className="p-4">{client.cargoId}</td>
|
<td className="p-4">{client.cargoId}</td>
|
||||||
<td className="p-4">{client.partyName}</td>
|
<td className="p-4">{client.partyName}</td>
|
||||||
<td className="p-4 max-w-3xs">{client.packetName}</td>
|
<td className="p-4 max-w-3xs">{client.packetName}</td>
|
||||||
{client.paymentType === null ? <td className="p-4 text-red-500">To'lanmagan</td> : <td className="p-4 text-green-600">{client.paymentType === 'CASH' ? 'Naxt' : client.paymentType}</td>}
|
{client.paymentType === null ? (
|
||||||
|
<td className="p-4 text-red-500">To'lanmagan</td>
|
||||||
|
) : (
|
||||||
|
<td className="p-4 text-green-600">
|
||||||
|
{client.paymentType === 'CASH' ? 'Naxt' : client.paymentType}
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
|
||||||
<td className="p-4">
|
<td className="p-4">
|
||||||
<PaymentStatusSelector value={client.paymentStatus || 'NEW'} onChange={(value) => handlePaymentStatusChange(client.packetId, value)} disabled={client.paymentStatus === 'PAYED'} />
|
<PaymentStatusSelector
|
||||||
|
value={client.paymentStatus || 'NEW'}
|
||||||
|
onChange={(value) => handlePaymentStatusChange(client.packetId, value)}
|
||||||
|
disabled={client.paymentStatus === 'PAYED'}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
<td className="p-4">
|
<td className="p-4">
|
||||||
@@ -187,7 +211,13 @@ const PaymentsList = ({ setAlert }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-end mt-5 justify-end">
|
<div className="flex items-end mt-5 justify-end">
|
||||||
<Pagination currentPage={currentPage} totalPages={data?.totalPages || 1} totalElements={data?.totalElements || 0} onPageChange={handlePageChange} isLoading={isLoading} />
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
totalPages={data?.totalPages || 1}
|
||||||
|
totalElements={data?.totalElements || 0}
|
||||||
|
onPageChange={handlePageChange}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user