first commit

This commit is contained in:
Samandar Turgunboyev
2025-10-18 17:14:59 +05:00
parent edf364b389
commit 036a36ce90
92 changed files with 14614 additions and 135 deletions

View File

@@ -0,0 +1,210 @@
"use client";
import { Button } from "@/shared/ui/button";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/shared/ui/dialog";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/shared/ui/table";
import { Edit, Plane, PlusCircle, Trash2 } from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
type Tour = {
id: number;
image?: string;
tickets: string;
min_price: string;
max_price: string;
top_duration: string;
top_destinations: string;
hotel_features_by_type: string;
hotel_types: string;
hotel_amenities: string;
};
const Tours = () => {
const [tours, setTours] = useState<Tour[]>([]);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(3);
const [deleteId, setDeleteId] = useState<number | null>(null);
const navigate = useNavigate();
useEffect(() => {
const mockData: Tour[] = Array.from({ length: 10 }, (_, i) => ({
id: i + 1,
image: `/dubai-marina.jpg`,
tickets: `Bilet turi ${i + 1}`,
min_price: `${200 + i * 50}$`,
max_price: `${400 + i * 70}$`,
top_duration: `${3 + i} kun`,
top_destinations: `Shahar ${i + 1}`,
hotel_features_by_type: "Spa, Wi-Fi, Pool",
hotel_types: "5 yulduzli mehmonxona",
hotel_amenities: "Nonushta, Parking, Bar",
}));
const itemsPerPage = 6;
const start = (page - 1) * itemsPerPage;
const end = start + itemsPerPage;
setTotalPages(Math.ceil(mockData.length / itemsPerPage));
setTours(mockData.slice(start, end));
}, [page]);
const confirmDelete = () => {
if (deleteId !== null) {
setTours((prev) => prev.filter((t) => t.id !== deleteId));
setDeleteId(null);
}
};
return (
<div className="min-h-screen bg-gray-900 text-foreground py-10 px-5 w-full">
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-semibold">Turlar ro'yxati</h1>
<Button onClick={() => navigate("/tours/create")} variant="default">
<PlusCircle className="w-5 h-5 mr-2" /> Yangi tur qo'shish
</Button>
</div>
<div className="rounded-xl border overflow-x-auto">
<Table>
<TableHeader>
<TableRow className="bg-muted/50">
<TableHead className="w-[50px] text-center">#</TableHead>
<TableHead className="min-w-[150px]">Manzil</TableHead>
<TableHead className="min-w-[120px]">Davomiyligi</TableHead>
<TableHead className="min-w-[180px]">Mehmonxona</TableHead>
<TableHead className="min-w-[200px]">Narx Oralig'i</TableHead>
<TableHead className="min-w-[200px]">Imkoniyatlar</TableHead>
<TableHead className="min-w-[150px] text-center">
Amallar
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tours.map((tour, idx) => (
<TableRow key={tour.id}>
<TableCell className="font-medium text-center">
{(page - 1) * 6 + idx + 1}
</TableCell>
<TableCell>
<div className="flex items-center gap-2 font-semibold">
<Plane className="w-4 h-4 text-primary" />
{tour.top_destinations}
</div>
</TableCell>
<TableCell className="text-sm text-primary font-medium">
{tour.top_duration}
</TableCell>
<TableCell>
<div className="flex flex-col">
<span className="font-medium">{tour.hotel_types}</span>
<span className="text-xs text-muted-foreground">
{tour.tickets}
</span>
</div>
</TableCell>
<TableCell>
<span className="font-bold text-base text-green-600">
{tour.min_price} {tour.max_price}
</span>
</TableCell>
<TableCell className="text-sm">
{tour.hotel_amenities}
</TableCell>
<TableCell className="text-center">
<div className="flex gap-2 justify-center">
<Button
variant="outline"
size="icon"
onClick={() => navigate(`/tours/${tour.id}/edit`)}
>
<Edit className="w-4 h-4" />
</Button>
<Button
variant="destructive"
size="icon"
onClick={() => setDeleteId(tour.id)}
>
<Trash2 className="w-4 h-4" />
</Button>
<Button
variant="default"
size="sm"
onClick={() => navigate(`/tours/${tour.id}`)}
>
Batafsil
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{/* Delete Confirmation Dialog - Faqat bitta */}
<Dialog open={deleteId !== null} onOpenChange={() => setDeleteId(null)}>
<DialogContent className="sm:max-w-[425px] bg-gray-900">
<DialogHeader>
<DialogTitle className="text-xl">
Turni o'chirishni tasdiqlang
</DialogTitle>
</DialogHeader>
<div className="py-4">
<p className="text-muted-foreground">
Haqiqatan ham bu turni o'chirib tashlamoqchimisiz? Bu amalni ortga
qaytarib bo'lmaydi.
</p>
</div>
<DialogFooter className="gap-4 flex">
<Button variant="outline" onClick={() => setDeleteId(null)}>
Bekor qilish
</Button>
<Button variant="destructive" onClick={confirmDelete}>
<Trash2 className="w-4 h-4 mr-2" />
O'chirish
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<div className="flex justify-center mt-10 gap-3">
<Button
variant="outline"
onClick={() => setPage((p) => Math.max(1, p - 1))}
disabled={page === 1}
>
Oldingi
</Button>
<span className="text-sm flex items-center">
Sahifa {page} / {totalPages}
</span>
<Button
variant="outline"
onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
disabled={page === totalPages}
>
Keyingi
</Button>
</div>
</div>
);
};
export default Tours;