status order

This commit is contained in:
Samandar Turgunboyev
2025-11-04 11:51:52 +05:00
parent 3481d49bb9
commit 89e4189850
7 changed files with 270 additions and 90 deletions

View File

@@ -11,7 +11,7 @@ import Currency from './pages/Currency';
import Employees from './pages/Employees';
import Login from './pages/Login';
import Payments from './pages/Payments';
import Permissions from './pages/Permissions'; // Yangi sahifa
import Permissions from './pages/Permissions';
import Reference from './pages/Reference';
import Warhouses from './pages/Warhouses';

View File

@@ -1,13 +1,29 @@
import { Search } from 'lucide-react';
import { Dispatch, SetStateAction } from 'react';
const Searchs = ({ searchTerm, loading, setSearchTerm, placeholder = 'Ism, telefon yoki manzil boyicha qidirish...' }) => {
interface Props {
searchTerm: string;
loading: boolean;
setSearchTerm: Dispatch<SetStateAction<string>>;
placeholder: string;
}
const Searchs = ({ searchTerm, loading, setSearchTerm, placeholder = 'Qidirish' }: Props) => {
return (
<div className="mb-4">
<label htmlFor="search" className="sr-only">
Qidiruv
</label>
<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" />
</div>
</div>

View File

@@ -2,8 +2,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Edit, Trash2, Users } from 'lucide-react';
import { useEffect, useState } from 'react';
import axiosInstance from '../../api/axiosInstance';
import Searchs from '../../components/Searchs';
import Pagination from '../Pagination';
import Searchs from '../Searchs';
const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
const client = useQueryClient();
@@ -24,7 +24,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
axiosInstance.get('/clients/list', {
params: {
page: currentPage,
sort: 'id',
sort: 'active',
clientName: searchTerm,
direction: 'desc',
},
@@ -44,7 +44,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
};
const { mutate: deleteClient, isPending: deleteLoad } = useMutation({
mutationFn: (id: number) => axiosInstance.delete(`/users/delete/${id}`),
mutationFn: (id) => axiosInstance.delete(`/users/delete/${id}`),
mutationKey: ['clientsDelete'],
onSuccess: () => {
client.invalidateQueries({ queryKey: ['clients'] });
@@ -57,7 +57,7 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
},
});
const handlePageChange = (page: number) => {
const handlePageChange = (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">PNFL</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>
</thead>
<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.pinfl}</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') && (
<td className="p-4">
<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" />
<span className="hidden sm:inline">Tahrirlash</span>
</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" />
<span className="hidden sm:inline">O'chirish</span>
</button>
@@ -116,7 +137,13 @@ const ClientList = ({ alert, setAlert, setClients, setCargoId }) => {
</div>
</div>
<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>
</>
);

View File

@@ -80,7 +80,7 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
const { data: client, refetch: clientRef } = useQuery({
queryKey: ['client_one'],
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({
@@ -102,23 +102,24 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
phone: c.phone,
pinfl: c.pinfl,
});
setActive(c.active);
}
clientRef();
refetch();
}, [cargoId, client, refetch, clientRef]);
// useEffect(() => {
// if (currentPassport) {
// setFormData((prev) => ({
// ...prev,
// fullName: currentPassport.fullName || '',
// passportSeries: currentPassport.passportSeries || '',
// pinfl: currentPassport.passportPin || '',
// dateOfBirth: formatDate(currentPassport.birthDate),
// }));
// setActive(currentPassport.active);
// }
// }, [currentPassport]);
useEffect(() => {
if (currentPassport) {
setFormData((prev) => ({
...prev,
fullName: currentPassport.fullName || '',
passportSeries: currentPassport.passportSeries || '',
pinfl: currentPassport.passportPin || '',
dateOfBirth: formatDate(currentPassport.birthDate),
}));
setActive(currentPassport.active);
}
}, [currentPassport]);
const { mutate: createMutate } = useMutation({
mutationFn: async (params: any) => {
@@ -202,6 +203,8 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
setAlert({ type: 'success', message: "Passport ma'lumotlari yangilandi." });
};
console.log(active);
return (
<div>
{(userRole === 'ADMIN' || userRole === 'SUPER_ADMIN') && (
@@ -211,7 +214,15 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
{clients ? 'Mijozni tahrirlash' : "Yangi mijoz qo'shish"}
</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}>
<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) => (
<div key={field.name}>
<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>
))}
{clients && currentPassport && (
<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="absolute left-1 top-1 w-4 h-4 bg-white rounded-full transition-transform duration-300 peer-checked:translate-x-5"></div>
</label>
@@ -239,22 +261,42 @@ const CreateClient = ({ clients, setAlert, cargoId }: CreateClientProps) => {
</div>
<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"}
</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
</button>
</div>
</form>
</div>
)}
{tagetIamge && opneModal && <ModalIamge image={tagetIamge} setTargetImage={setTargetImage} setOpenModal={setOpenModal} />}
{tagetIamge && opneModal && (
<ModalIamge
image={tagetIamge}
setTargetImage={setTargetImage}
setOpenModal={setOpenModal}
/>
)}
</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 (
<div className="w-full h-screen bg-black/60 fixed top-0 bottom-0 left-0 z-50 overflow-hidden">
<button

View File

@@ -1,7 +1,17 @@
'use client';
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 axiosInstance from '../../api/axiosInstance';
import { cn } from '../../lib/utils';
@@ -71,7 +81,9 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
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];
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="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>
<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" />
</button>
</div>
@@ -90,7 +105,10 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
<div className="flex flex-col items-center justify-center py-12">
<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>
<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
</button>
</div>
@@ -125,7 +143,14 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
</div>
<div className="flex flex-col gap-4">
<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" />
<span className="font-medium">{currentStatus.label}</span>
</button>
@@ -162,11 +187,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
<button
className={cn(
'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" />
<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>
</div>
</div>
@@ -183,16 +218,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
{data.clickTransactions.map((transaction, index) => (
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
<div className="flex items-center justify-between mb-3">
<span className="font-medium text-lg text-gray-900">ID: {transaction.transactionId}</span>
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg ${getStatusColor(transaction.status)}`}>
{getStatusIcon(transaction.status)}
<span className="font-medium text-lg text-gray-900">
ID: {transaction.transactionId}
</span>
<span
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg`}
>
{transaction.status}
</span>
</div>
<div className="grid grid-cols-2 gap-3 text-sm">
<div>
<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>
<span className="font-medium text-lg text-gray-600">Provayder:</span>
@@ -204,13 +244,19 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
</div>
{transaction.completeTime && (
<div>
<span className="font-medium text-lg text-gray-600">Tugallangan:</span>
<p className="text-gray-900">{formatDate(transaction.completeTime)}</p>
<span className="font-medium text-lg text-gray-600">
Tugallangan:
</span>
<p className="text-gray-900">
{formatDate(transaction.completeTime)}
</p>
</div>
)}
{transaction.cancelTime && (
<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>
</div>
)}
@@ -239,16 +285,21 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
{data.paymeTransactions.map((transaction, index) => (
<div key={index} className="border border-gray-200 rounded-lg p-4 bg-white">
<div className="flex items-center justify-between mb-3">
<span className="font-medium text-lg text-gray-900">ID: {transaction.transactionId}</span>
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg ${getStatusColor(transaction.status)}`}>
{getStatusIcon(transaction.status)}
<span className="font-medium text-lg text-gray-900">
ID: {transaction.transactionId}
</span>
<span
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full font-medium text-lg`}
>
{transaction.status}
</span>
</div>
<div className="grid grid-cols-2 gap-3 text-sm">
<div>
<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>
<span className="font-medium text-lg text-gray-600">Provayder:</span>
@@ -260,13 +311,19 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
</div>
{transaction.completeTime && (
<div>
<span className="font-medium text-lg text-gray-600">Tugallangan:</span>
<p className="text-gray-900">{formatDate(transaction.completeTime)}</p>
<span className="font-medium text-lg text-gray-600">
Tugallangan:
</span>
<p className="text-gray-900">
{formatDate(transaction.completeTime)}
</p>
</div>
)}
{transaction.cancelTime && (
<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>
</div>
)}
@@ -285,7 +342,11 @@ const ModalPayment = ({ isOpen, onClose, packetId }) => {
</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) &&
(!data.paymeTransactions || data.paymeTransactions.length === 0) &&
!(
['PAYED', 'PENDING'].includes(data.paymentStatus) && data.paymentType === 'CASH'
) && (
<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>

View File

@@ -40,18 +40,14 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });
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 handleSelect = (statusValue) => {
if (statusValue === 'PAID' && (value === 'UNPAID' || value === 'PENDING')) {
// Faqat PAYED holatiga o'tkazish
if (statusValue === 'PAYED' && value !== '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);
};
@@ -88,17 +84,18 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
<CurrentIcon className="h-4 w-4" />
<span className="font-medium">{currentStatus.label}</span>
</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>
{/* Options (portal) */}
{isOpen &&
createPortal(
<>
{/* Backdrop */}
<div className="fixed inset-0 z-40" onClick={() => setIsOpen(false)} />
{/* Dropdown */}
<div
className="absolute bg-white border border-slate-200 rounded-lg shadow-lg z-50 overflow-hidden"
style={{
@@ -111,17 +108,24 @@ const PaymentStatusSelector = ({ value, onChange, disabled = false }) => {
{paymentStatuses.map((status) => {
const StatusIcon = status.icon;
const isSelected = status.value === value;
const isDisabled = status.value !== 'PAID' || value === 'PAID';
return (
<button
key={status.value}
type="button"
onClick={() => !isDisabled && handleSelect(status.value)}
disabled={isDisabled}
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')}
onClick={() => handleSelect(status.value)}
className={cn(
'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)} />
</div>
<span className={cn('font-medium', status.color)}>{status.label}</span>

View File

@@ -2,7 +2,7 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import { QrCode, Search, Users } from 'lucide-react';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import axiosInstance from '../../api/axiosInstance';
import Pagination from '../Pagination';
import ModalPayment from './ModalPayment';
@@ -17,15 +17,17 @@ const PaymentsList = ({ setAlert }) => {
const [isPaymentModalOpen, setIsPaymentModalOpen] = useState(false);
const [scannedResult, setScannedResult] = useState(null);
const [packetid, setPacketId] = useState();
const [userRole, setUserRole] = useState('');
const userRole = (() => {
try {
useEffect(() => {
const storedUser = localStorage.getItem('user');
return storedUser ? JSON.parse(storedUser).user.role : null;
} catch {
return null;
if (storedUser) {
const parsed = JSON.parse(storedUser);
setUserRole(parsed.user?.role || null);
}
})();
}, []);
console.log(userRole);
const { data, isLoading, refetch } = useQuery({
queryKey: ['payments_list', currentPage, searchTerm, cargoType],
@@ -36,6 +38,7 @@ const PaymentsList = ({ setAlert }) => {
cargoType,
size: 30,
search: searchTerm,
sort: 'paymentStatus',
},
}),
select(data) {
@@ -86,7 +89,11 @@ const PaymentsList = ({ setAlert }) => {
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="mb-4 w-[90%]">
@@ -97,7 +104,7 @@ const PaymentsList = ({ setAlert }) => {
<input
type="text"
id="search"
placeholder={"Cargo Ids, Partiya nomi, Paket nomi bo'yicha qidirish"}
placeholder={"Cargo Ids, Paket nomi bo'yicha qidirish"}
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]"
@@ -106,7 +113,11 @@ const PaymentsList = ({ setAlert }) => {
</div>
</div>
<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="AVIA">AVIA</option>
<option value="AUTO">AUTO</option>
@@ -115,7 +126,10 @@ const PaymentsList = ({ setAlert }) => {
</div>
<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" />
</button>
</div>
@@ -162,10 +176,20 @@ const PaymentsList = ({ setAlert }) => {
<td className="p-4">{client.cargoId}</td>
<td className="p-4">{client.partyName}</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') && (
<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 className="p-4">
@@ -187,7 +211,13 @@ const PaymentsList = ({ setAlert }) => {
</div>
<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>
</>
);