booking
This commit is contained in:
@@ -28,6 +28,12 @@ export interface UserOrderData {
|
||||
tour_name: string;
|
||||
}[];
|
||||
total_income: string;
|
||||
awaiting_payments: string;
|
||||
awaiting_payments_count: string;
|
||||
confirmed_order: string;
|
||||
pending_confirmation: string;
|
||||
completed_order: string;
|
||||
cancelled_order: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,32 +8,177 @@ import { Button } from "@/shared/ui/button";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
AlertTriangle,
|
||||
CheckCircle,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Clock,
|
||||
CreditCard,
|
||||
DollarSign,
|
||||
Eye,
|
||||
Hotel,
|
||||
Loader2,
|
||||
MapPin,
|
||||
Plane,
|
||||
TrendingUp,
|
||||
Users,
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
type Purchase = {
|
||||
id: number;
|
||||
userName: string;
|
||||
userPhone: string;
|
||||
tourName: string;
|
||||
tourId: number;
|
||||
agencyName: string;
|
||||
agencyId: number;
|
||||
destination: string;
|
||||
travelDate: string;
|
||||
amount: number;
|
||||
paymentStatus: "paid" | "pending" | "cancelled" | "refunded";
|
||||
purchaseDate: string;
|
||||
};
|
||||
|
||||
const mockPurchases: Purchase[] = [
|
||||
{
|
||||
id: 1,
|
||||
userName: "Aziza Karimova",
|
||||
userPhone: "+998 90 123 45 67",
|
||||
tourName: "Dubai Luxury Tour",
|
||||
tourId: 1,
|
||||
agencyName: "Silk Road Travel",
|
||||
agencyId: 1,
|
||||
destination: "Dubai, UAE",
|
||||
travelDate: "2025-11-10",
|
||||
amount: 1500000,
|
||||
paymentStatus: "paid",
|
||||
purchaseDate: "2025-10-10",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
userName: "Sardor Rahimov",
|
||||
userPhone: "+998 91 234 56 78",
|
||||
tourName: "Bali Adventure Package",
|
||||
tourId: 2,
|
||||
agencyName: "Silk Road Travel",
|
||||
agencyId: 1,
|
||||
destination: "Bali, Indonesia",
|
||||
travelDate: "2025-11-15",
|
||||
amount: 1800000,
|
||||
paymentStatus: "paid",
|
||||
purchaseDate: "2025-10-12",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
userName: "Nilufar Toshmatova",
|
||||
userPhone: "+998 93 345 67 89",
|
||||
tourName: "Dubai Luxury Tour",
|
||||
tourId: 1,
|
||||
agencyName: "Silk Road Travel",
|
||||
agencyId: 1,
|
||||
destination: "Dubai, UAE",
|
||||
travelDate: "2025-11-20",
|
||||
amount: 1500000,
|
||||
paymentStatus: "pending",
|
||||
purchaseDate: "2025-10-14",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
userName: "Jamshid Alimov",
|
||||
userPhone: "+998 94 456 78 90",
|
||||
tourName: "Istanbul Express Tour",
|
||||
tourId: 3,
|
||||
agencyName: "Orient Express",
|
||||
agencyId: 3,
|
||||
destination: "Istanbul, Turkey",
|
||||
travelDate: "2025-11-05",
|
||||
amount: 1200000,
|
||||
paymentStatus: "cancelled",
|
||||
purchaseDate: "2025-10-08",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
userName: "Madina Yusupova",
|
||||
userPhone: "+998 97 567 89 01",
|
||||
tourName: "Paris Romantic Getaway",
|
||||
tourId: 4,
|
||||
agencyName: "Euro Travels",
|
||||
agencyId: 2,
|
||||
destination: "Paris, France",
|
||||
travelDate: "2025-12-01",
|
||||
amount: 2200000,
|
||||
paymentStatus: "paid",
|
||||
purchaseDate: "2025-10-16",
|
||||
},
|
||||
];
|
||||
|
||||
export default function FinancePage() {
|
||||
const { t } = useTranslation();
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [tab, setTab] = useState<"bookings" | "agencies">("bookings");
|
||||
const [filterStatus, setFilterStatus] = useState<
|
||||
"all" | "paid" | "pending" | "cancelled" | "refunded"
|
||||
>("all");
|
||||
|
||||
const { data, isLoading, isError, refetch } = useQuery({
|
||||
queryKey: ["list_order_user"],
|
||||
queryFn: () => getAllOrder({ page: 1, page_size: 10 }),
|
||||
queryKey: ["list_order_user", currentPage],
|
||||
queryFn: () => getAllOrder({ page: currentPage, page_size: 10 }),
|
||||
});
|
||||
|
||||
const stats = [
|
||||
{
|
||||
title: t("Jami daromad"),
|
||||
value: data?.data.data.results.total_income ?? "0",
|
||||
description: t("Yakunlangan bandlovlardan"),
|
||||
icon: <DollarSign className="text-green-400 w-6 h-6" />,
|
||||
color: "text-green-400",
|
||||
},
|
||||
{
|
||||
title: t("Kutilayotgan to‘lovlar"),
|
||||
value: data?.data.data.results.awaiting_payments ?? "0",
|
||||
description: t("Tasdiqlash kutilmoqda"),
|
||||
icon: <TrendingUp className="text-yellow-400 w-6 h-6" />,
|
||||
color: "text-yellow-400",
|
||||
},
|
||||
{
|
||||
title: t("Kutilayotgan to‘lovlar soni"),
|
||||
value: data?.data.data.results.awaiting_payments_count ?? "0",
|
||||
description: t("To‘lov kutilayotgan buyurtmalar soni"),
|
||||
icon: <Clock className="text-orange-400 w-6 h-6" />,
|
||||
color: "text-orange-400",
|
||||
},
|
||||
{
|
||||
title: t("Tasdiqlangan buyurtmalar"),
|
||||
value: data?.data.data.results.confirmed_order ?? "0",
|
||||
description: t("Tasdiqlangan bandlovlar soni"),
|
||||
icon: <CreditCard className="text-blue-400 w-6 h-6" />,
|
||||
color: "text-blue-400",
|
||||
},
|
||||
{
|
||||
title: t("Kutilayotgan tasdiqlar"),
|
||||
value: data?.data.data.results.pending_confirmation ?? "0",
|
||||
description: t("Hali tasdiqlanmagan bandlovlar"),
|
||||
icon: <Clock className="text-purple-400 w-6 h-6" />,
|
||||
color: "text-purple-400",
|
||||
},
|
||||
{
|
||||
title: t("Yakunlangan buyurtmalar"),
|
||||
value: data?.data.data.results.completed_order ?? "0",
|
||||
description: t("Muvaffaqiyatli yakunlangan buyurtmalar"),
|
||||
icon: <CheckCircle className="text-emerald-400 w-6 h-6" />,
|
||||
color: "text-emerald-400",
|
||||
},
|
||||
{
|
||||
title: t("Bekor qilingan buyurtmalar"),
|
||||
value: data?.data.data.results.cancelled_order ?? "0",
|
||||
description: t("Bekor qilingan bandlovlar soni"),
|
||||
icon: <XCircle className="text-red-400 w-6 h-6" />,
|
||||
color: "text-red-400",
|
||||
},
|
||||
];
|
||||
|
||||
const getStatusBadge = (status: OrderStatus["order_status"]) => {
|
||||
const base =
|
||||
"px-3 py-1 rounded-full text-sm font-medium inline-flex items-center gap-2";
|
||||
@@ -120,6 +265,26 @@ export default function FinancePage() {
|
||||
);
|
||||
}
|
||||
|
||||
const agencies = Array.from(
|
||||
new Set(mockPurchases.map((p) => p.agencyId)),
|
||||
).map((id) => {
|
||||
const agencyPurchases = mockPurchases.filter((p) => p.agencyId === id);
|
||||
return {
|
||||
id,
|
||||
name: agencyPurchases[0].agencyName,
|
||||
totalPaid: agencyPurchases
|
||||
.filter((p) => p.paymentStatus === "paid")
|
||||
.reduce((sum, p) => sum + p.amount, 0),
|
||||
pending: agencyPurchases
|
||||
.filter((p) => p.paymentStatus === "pending")
|
||||
.reduce((sum, p) => sum + p.amount, 0),
|
||||
purchaseCount: agencyPurchases.length,
|
||||
destinations: Array.from(
|
||||
new Set(agencyPurchases.map((p) => p.destination)),
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="min-h-screen w-full bg-gray-900 text-gray-100">
|
||||
<div className="w-[90%] mx-auto py-6">
|
||||
@@ -201,70 +366,24 @@ export default function FinancePage() {
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||
<div className="bg-gray-800 p-6 rounded-xl shadow flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-gray-400 font-medium">
|
||||
{t("Jami daromad")}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 mb-8">
|
||||
{stats.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-gray-800 p-6 rounded-xl shadow flex flex-col justify-between transition-all hover:scale-[1.02]"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-gray-400 font-medium">{item.title}</p>
|
||||
{item.icon}
|
||||
</div>
|
||||
<p className={`text-2xl font-bold mt-3 ${item.color}`}>
|
||||
{Number(item.value).toLocaleString()}
|
||||
</p>
|
||||
<DollarSign className="text-green-400 w-6 h-6" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-green-400 mt-3">
|
||||
{/* {formatPrice(totalRevenue, true)} */}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{t("Yakunlangan bandlovlardan")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-gray-800 p-6 rounded-xl shadow flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-gray-400 font-medium">
|
||||
{t("Kutilayotgan to‘lovlar")}
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{item.description}
|
||||
</p>
|
||||
<TrendingUp className="text-yellow-400 w-6 h-6" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-yellow-400 mt-3">
|
||||
{/* {formatPrice(pendingRevenue, true)} */}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{t("Tasdiqlash kutilmoqda")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-gray-800 p-6 rounded-xl shadow flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-gray-400 font-medium">
|
||||
{t("Tasdiqlangan bandlovlar")}
|
||||
</p>
|
||||
<CreditCard className="text-blue-400 w-6 h-6" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-blue-400 mt-3">
|
||||
{/* {
|
||||
filteredPurchases.filter((p) => p.paymentStatus === "paid")
|
||||
.length
|
||||
} */}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{t("Tasdiqlangan bandlovlar")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-gray-800 p-6 rounded-xl shadow flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-gray-400 font-medium">
|
||||
{t("Kutilayotgan bandlovlar")}
|
||||
</p>
|
||||
<Hotel className="text-purple-400 w-6 h-6" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-purple-400 mt-3">
|
||||
{/* {
|
||||
filteredPurchases.filter(
|
||||
(p) => p.paymentStatus === "pending",
|
||||
).length
|
||||
} */}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{t("Kutilayotgan to‘lovlar")}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Booking Cards */}
|
||||
@@ -321,10 +440,45 @@ export default function FinancePage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 mt-5">
|
||||
<button
|
||||
disabled={currentPage === 1}
|
||||
onClick={() => setCurrentPage((p) => Math.max(p - 1, 1))}
|
||||
className="p-2 rounded-lg border border-slate-600 text-slate-300 hover:bg-slate-700/50 disabled:opacity-50 disabled:cursor-not-allowed transition-all hover:border-slate-500"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
{[...Array(data?.data.data.total_pages)].map((_, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => setCurrentPage(i + 1)}
|
||||
className={`px-4 py-2 rounded-lg border transition-all font-medium ${
|
||||
currentPage === i + 1
|
||||
? "bg-gradient-to-r from-blue-600 to-cyan-600 border-blue-500 text-white shadow-lg shadow-cyan-500/50"
|
||||
: "border-slate-600 text-slate-300 hover:bg-slate-700/50 hover:border-slate-500"
|
||||
}`}
|
||||
>
|
||||
{i + 1}
|
||||
</button>
|
||||
))}
|
||||
|
||||
<button
|
||||
disabled={currentPage === data?.data.data.total_pages}
|
||||
onClick={() =>
|
||||
setCurrentPage((p) =>
|
||||
Math.min(p + 1, data ? data?.data.data.total_pages : 0),
|
||||
)
|
||||
}
|
||||
className="p-2 rounded-lg border border-slate-600 text-slate-300 hover:bg-slate-700/50 disabled:opacity-50 disabled:cursor-not-allowed transition-all hover:border-slate-500"
|
||||
>
|
||||
<ChevronRight className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* {tab === "agencies" && (
|
||||
{tab === "agencies" && (
|
||||
<>
|
||||
<h2 className="text-xl font-bold mb-6">Partner Agencies</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
@@ -380,7 +534,7 @@ export default function FinancePage() {
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)} */}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -61,11 +61,12 @@ export default function FinanceDetailUser() {
|
||||
};
|
||||
}) => updateDetailOrder({ body, id }),
|
||||
onSuccess: () => {
|
||||
queryClient.refetchQueries({ queryKey: ["detail_order"] });
|
||||
queryClient.refetchQueries({ queryKey: ["list_order_user"] });
|
||||
toast.success(t("Status muvaffaqiyatli yangilandi"), {
|
||||
richColors: true,
|
||||
position: "top-center",
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["detail_order"] });
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t("Statusni yangilashda xatolik yuz berdi"), {
|
||||
|
||||
@@ -89,32 +89,6 @@ const SupportTours = () => {
|
||||
});
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-slate-900 text-white gap-4 w-full">
|
||||
<Loader2 className="w-10 h-10 animate-spin text-cyan-400" />
|
||||
<p className="text-slate-400">{t("Ma'lumotlar yuklanmoqda...")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-slate-900 w-full text-center text-white gap-4">
|
||||
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||
<p className="text-lg">
|
||||
{t("Ma'lumotlarni yuklashda xatolik yuz berdi.")}
|
||||
</p>
|
||||
<Button
|
||||
onClick={() => refetch()}
|
||||
className="bg-gradient-to-r from-blue-600 to-cyan-600 text-white rounded-lg px-5 py-2 hover:opacity-90"
|
||||
>
|
||||
{t("Qayta urinish")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-900 text-gray-100 p-6 space-y-6 w-full">
|
||||
<h1 className="text-3xl font-bold tracking-tight mb-4 text-white">
|
||||
@@ -141,76 +115,100 @@ const SupportTours = () => {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="grid gap-5 sm:grid-cols-3 lg:grid-cols-3">
|
||||
{data && data.data.data.results.length === 0 ? (
|
||||
<div className="col-span-full flex flex-col items-center justify-center min-h-[50vh] w-full text-center text-white gap-4">
|
||||
<p className="text-lg">{t("Natija topilmadi")}</p>
|
||||
</div>
|
||||
) : (
|
||||
data?.data.data.results.map((req) => (
|
||||
<Card
|
||||
key={req.id}
|
||||
className="bg-gray-800/70 border border-gray-700 shadow-md hover:shadow-lg hover:bg-gray-800 transition-all duration-200 justify-between"
|
||||
>
|
||||
<CardHeader className="pb-2 flex justify-between items-center">
|
||||
<div className="flex gap-2">
|
||||
<CardTitle className="flex items-center gap-2 text-lg font-semibold text-white">
|
||||
<User className="w-5 h-5 text-blue-400" />
|
||||
{req.name}
|
||||
</CardTitle>
|
||||
{isError ? (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-slate-900 w-full text-center text-white gap-4">
|
||||
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||
<p className="text-lg">
|
||||
{t("Ma'lumotlarni yuklashda xatolik yuz berdi.")}
|
||||
</p>
|
||||
<Button
|
||||
onClick={() => refetch()}
|
||||
className="bg-gradient-to-r from-blue-600 to-cyan-600 text-white rounded-lg px-5 py-2 hover:opacity-90"
|
||||
>
|
||||
{t("Qayta urinish")}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{isLoading ? (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-slate-900 text-white gap-4 w-full">
|
||||
<Loader2 className="w-10 h-10 animate-spin text-cyan-400" />
|
||||
<p className="text-slate-400">
|
||||
{t("Ma'lumotlar yuklanmoqda...")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid gap-5 sm:grid-cols-3 lg:grid-cols-3">
|
||||
{data && data.data.data.results.length === 0 ? (
|
||||
<div className="col-span-full flex flex-col items-center justify-center min-h-[50vh] w-full text-center text-white gap-4">
|
||||
<p className="text-lg">{t("Natija topilmadi")}</p>
|
||||
</div>
|
||||
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`px-2 py-1 rounded-md text-xs font-medium ${
|
||||
req.status === "pending"
|
||||
? "bg-red-500/10 text-red-400 border-red-400/40"
|
||||
: "bg-green-500/10 text-green-400 border-green-400/40"
|
||||
}`}
|
||||
>
|
||||
{req.status === "pending" ? t("Kutilmoqda") : t("done")}
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-3 mt-1">
|
||||
{req.travel_agency !== null ? (
|
||||
<span className="text-md text-gray-400">
|
||||
{t("Agentlikka tegishli")}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-md text-gray-400">
|
||||
{t("Sayt bo'yicha")}
|
||||
</span>
|
||||
)}
|
||||
<div className="flex items-center gap-2 mt-2 text-sm text-gray-400">
|
||||
<Phone className="w-4 h-4 text-gray-400" />
|
||||
{formatPhone(req.phone_number)}
|
||||
</div>
|
||||
<div className="grid grid-cols-2 justify-end items-end gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-3 w-full border-gray-600 text-gray-200 hover:bg-gray-700 hover:text-white"
|
||||
onClick={() => setSelected(req)}
|
||||
) : (
|
||||
data?.data.data.results.map((req) => (
|
||||
<Card
|
||||
key={req.id}
|
||||
className="bg-gray-800/70 border border-gray-700 shadow-md hover:shadow-lg hover:bg-gray-800 transition-all duration-200 justify-between"
|
||||
>
|
||||
{t("Batafsil ko'rish")}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
className="flex items-center gap-1"
|
||||
onClick={() => setSelectedToDelete(req)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" /> {t("O'chirish")}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
<CardHeader className="pb-2 flex justify-between items-center">
|
||||
<div className="flex gap-2">
|
||||
<CardTitle className="flex items-center gap-2 text-lg font-semibold text-white">
|
||||
<User className="w-5 h-5 text-blue-400" />
|
||||
{req.name}
|
||||
</CardTitle>
|
||||
</div>
|
||||
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`px-2 py-1 rounded-md text-xs font-medium ${
|
||||
req.status === "pending"
|
||||
? "bg-red-500/10 text-red-400 border-red-400/40"
|
||||
: "bg-green-500/10 text-green-400 border-green-400/40"
|
||||
}`}
|
||||
>
|
||||
{req.status === "pending" ? t("Kutilmoqda") : t("done")}
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-3 mt-1">
|
||||
{req.travel_agency !== null ? (
|
||||
<span className="text-md text-gray-400">
|
||||
{t("Agentlikka tegishli")}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-md text-gray-400">
|
||||
{t("Sayt bo'yicha")}
|
||||
</span>
|
||||
)}
|
||||
<div className="flex items-center gap-2 mt-2 text-sm text-gray-400">
|
||||
<Phone className="w-4 h-4 text-gray-400" />
|
||||
{formatPhone(req.phone_number)}
|
||||
</div>
|
||||
<div className="grid grid-cols-2 justify-end items-end gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-3 w-full border-gray-600 text-gray-200 hover:bg-gray-700 hover:text-white"
|
||||
onClick={() => setSelected(req)}
|
||||
>
|
||||
{t("Batafsil ko'rish")}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
className="flex items-center gap-1"
|
||||
onClick={() => setSelectedToDelete(req)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" /> {t("O'chirish")}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Detail Modal */}
|
||||
<Dialog open={!!selected} onOpenChange={() => setSelected(null)}>
|
||||
|
||||
Reference in New Issue
Block a user