Files
simple-admin/src/pages/finance/ui/FinanceDetailTour.tsx
Samandar Turgunboyev 036a36ce90 first commit
2025-10-18 17:14:59 +05:00

468 lines
16 KiB
TypeScript

"use client";
import {
ArrowLeft,
Calendar,
DollarSign,
Download,
Eye,
Hotel,
MapPin,
Plane,
Share2,
Star,
TrendingUp,
Users,
} from "lucide-react";
import { useState } from "react";
import { Link } from "react-router-dom";
type TourPurchase = {
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;
rating: number;
review: string;
};
const mockTourData = {
id: 1,
name: "Dubai Luxury Tour",
destination: "Dubai, UAE",
duration: "7 days",
price: 1500000,
totalBookings: 45,
totalRevenue: 67500000,
averageRating: 4.8,
agency: "Silk Road Travel",
description:
"Experience the ultimate luxury in Dubai with 5-star accommodations, private tours, and exclusive experiences.",
inclusions: [
"5-star hotel accommodation",
"Private city tours",
"Desert safari experience",
"Burj Khalifa tickets",
"Airport transfers",
],
};
const mockTourPurchases: TourPurchase[] = [
{
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",
rating: 5,
review:
"Amazing experience! The hotel was luxurious and the tours were well organized.",
},
{
id: 2,
userName: "Sardor Rahimov",
userPhone: "+998 91 234 56 78",
tourName: "Dubai Luxury Tour",
tourId: 1,
agencyName: "Silk Road Travel",
agencyId: 1,
destination: "Dubai, UAE",
travelDate: "2025-11-15",
amount: 1500000,
paymentStatus: "paid",
purchaseDate: "2025-10-12",
rating: 4,
review:
"Great tour overall. The desert safari was the highlight of our trip.",
},
{
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",
rating: 0,
review: "",
},
];
export default function FinanceDetailTour() {
const [activeTab, setActiveTab] = useState<
"overview" | "bookings" | "reviews"
>("overview");
const getStatusBadge = (status: TourPurchase["paymentStatus"]) => {
const base =
"px-3 py-1 rounded-full text-sm font-medium inline-flex items-center gap-2";
switch (status) {
case "paid":
return (
<span
className={`${base} bg-green-900 text-green-400 border border-green-700`}
>
<div className="w-2 h-2 rounded-full bg-green-400"></div>
Paid
</span>
);
case "pending":
return (
<span
className={`${base} bg-yellow-900 text-yellow-400 border border-yellow-700`}
>
<div className="w-2 h-2 rounded-full bg-yellow-400"></div>
Pending
</span>
);
case "cancelled":
return (
<span
className={`${base} bg-red-900 text-red-400 border border-red-700`}
>
<div className="w-2 h-2 rounded-full bg-red-400"></div>
Cancelled
</span>
);
case "refunded":
return (
<span
className={`${base} bg-blue-900 text-blue-400 border border-blue-700`}
>
<div className="w-2 h-2 rounded-full bg-blue-400"></div>
Refunded
</span>
);
}
};
const renderStars = (rating: number) => {
return (
<div className="flex items-center gap-1">
{[1, 2, 3, 4, 5].map((star) => (
<Star
key={star}
className={`w-4 h-4 ${
star <= rating
? "text-yellow-400 fill-yellow-400"
: "text-gray-600"
}`}
/>
))}
</div>
);
};
const paidBookings = mockTourPurchases.filter(
(p) => p.paymentStatus === "paid",
);
const totalRevenue = paidBookings.reduce((sum, p) => sum + p.amount, 0);
const pendingRevenue = mockTourPurchases
.filter((p) => p.paymentStatus === "pending")
.reduce((sum, p) => sum + p.amount, 0);
return (
<div className="min-h-screen w-full bg-gray-900 text-gray-100">
<div className="w-[90%] mx-auto py-6">
{/* Header */}
<div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-4">
<Link
to="/finance"
className="bg-gray-800 p-2 rounded-lg hover:bg-gray-700 transition-colors"
>
<ArrowLeft className="w-5 h-5" />
</Link>
<div>
<h1 className="text-3xl font-bold">Tour Financial Details</h1>
<p className="text-gray-400 mt-1">
Financial performance for {mockTourData.name}
</p>
</div>
</div>
<div className="flex gap-3">
<button className="bg-gray-800 px-4 py-2 rounded-lg hover:bg-gray-700 transition-colors flex items-center gap-2">
<Download className="w-4 h-4" />
Export Report
</button>
<button className="bg-blue-600 px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors flex items-center gap-2">
<Share2 className="w-4 h-4" />
Share
</button>
</div>
</div>
{/* Tour Summary Cards */}
<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">
<div className="flex items-center justify-between">
<p className="text-gray-400 font-medium">Total Revenue</p>
<DollarSign className="text-green-400 w-6 h-6" />
</div>
<p className="text-2xl font-bold text-green-400 mt-3">
${(totalRevenue / 1000000).toFixed(1)}M
</p>
<p className="text-sm text-gray-500 mt-1">
From completed bookings
</p>
</div>
<div className="bg-gray-800 p-6 rounded-xl shadow">
<div className="flex items-center justify-between">
<p className="text-gray-400 font-medium">Pending Revenue</p>
<TrendingUp className="text-yellow-400 w-6 h-6" />
</div>
<p className="text-2xl font-bold text-yellow-400 mt-3">
${(pendingRevenue / 1000000).toFixed(1)}M
</p>
<p className="text-sm text-gray-500 mt-1">Awaiting payment</p>
</div>
<div className="bg-gray-800 p-6 rounded-xl shadow">
<div className="flex items-center justify-between">
<p className="text-gray-400 font-medium">Total Bookings</p>
<Users className="text-blue-400 w-6 h-6" />
</div>
<p className="text-2xl font-bold text-blue-400 mt-3">
{mockTourPurchases.length}
</p>
<p className="text-sm text-gray-500 mt-1">All bookings</p>
</div>
<div className="bg-gray-800 p-6 rounded-xl shadow">
<div className="flex items-center justify-between">
<p className="text-gray-400 font-medium">Average Rating</p>
<Star className="text-yellow-400 w-6 h-6" />
</div>
<p className="text-2xl font-bold text-yellow-400 mt-3">
{mockTourData.averageRating}/5
</p>
<p className="text-sm text-gray-500 mt-1">Customer satisfaction</p>
</div>
</div>
{/* Main Content */}
<div className="bg-gray-800 rounded-xl shadow">
{/* Tabs */}
<div className="flex border-b border-gray-700">
<button
className={`px-6 py-4 font-medium flex items-center gap-2 transition-colors ${
activeTab === "overview"
? "text-blue-400 border-b-2 border-blue-400"
: "text-gray-400 hover:text-gray-300"
}`}
onClick={() => setActiveTab("overview")}
>
<Eye className="w-4 h-4" />
Tour Overview
</button>
<button
className={`px-6 py-4 font-medium flex items-center gap-2 transition-colors ${
activeTab === "bookings"
? "text-blue-400 border-b-2 border-blue-400"
: "text-gray-400 hover:text-gray-300"
}`}
onClick={() => setActiveTab("bookings")}
>
<Users className="w-4 h-4" />
Bookings ({mockTourPurchases.length})
</button>
<button
className={`px-6 py-4 font-medium flex items-center gap-2 transition-colors ${
activeTab === "reviews"
? "text-blue-400 border-b-2 border-blue-400"
: "text-gray-400 hover:text-gray-300"
}`}
onClick={() => setActiveTab("reviews")}
>
<Star className="w-4 h-4" />
Reviews
</button>
</div>
<div className="p-6">
{activeTab === "overview" && (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Tour Information */}
<div className="lg:col-span-2">
<h3 className="text-lg font-bold mb-4">Tour Information</h3>
<div className="space-y-4">
<div className="flex items-center gap-3 p-3 bg-gray-700 rounded-lg">
<Plane className="w-5 h-5 text-blue-400" />
<div>
<p className="text-sm text-gray-400">Tour Name</p>
<p className="text-gray-100 font-medium">
{mockTourData.name}
</p>
</div>
</div>
<div className="flex items-center gap-3 p-3 bg-gray-700 rounded-lg">
<MapPin className="w-5 h-5 text-green-400" />
<div>
<p className="text-sm text-gray-400">Destination</p>
<p className="text-gray-100">
{mockTourData.destination}
</p>
</div>
</div>
<div className="flex items-center gap-3 p-3 bg-gray-700 rounded-lg">
<Calendar className="w-5 h-5 text-purple-400" />
<div>
<p className="text-sm text-gray-400">Duration</p>
<p className="text-gray-100">{mockTourData.duration}</p>
</div>
</div>
<div className="flex items-center gap-3 p-3 bg-gray-700 rounded-lg">
<Hotel className="w-5 h-5 text-yellow-400" />
<div>
<p className="text-sm text-gray-400">Agency</p>
<p className="text-gray-100">{mockTourData.agency}</p>
</div>
</div>
<div className="p-3 bg-gray-700 rounded-lg">
<p className="text-sm text-gray-400 mb-2">Description</p>
<p className="text-gray-100">
{mockTourData.description}
</p>
</div>
</div>
</div>
<div>
<h3 className="text-lg font-bold mb-4">Tour Inclusions</h3>
<div className="mt-6 p-4 bg-gray-700 rounded-lg">
<p className="text-sm text-gray-400 mb-2">Base Price</p>
<p className="text-2xl font-bold text-green-400">
${(mockTourData.price / 1000000).toFixed(1)}M
</p>
<p className="text-sm text-gray-400 mt-1">per person</p>
</div>
</div>
</div>
)}
{activeTab === "bookings" && (
<div className="space-y-6">
<h2 className="text-xl font-bold mb-4">Recent Bookings</h2>
{mockTourPurchases.map((purchase) => (
<div
key={purchase.id}
className="bg-gray-700 p-6 rounded-lg hover:bg-gray-600 transition-colors"
>
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-lg font-bold text-gray-100">
{purchase.userName}
</h3>
<p className="text-gray-400 text-sm">
{purchase.userPhone}
</p>
</div>
{getStatusBadge(purchase.paymentStatus)}
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div>
<p className="text-sm text-gray-400">Travel Date</p>
<p className="text-gray-100 font-medium">
{purchase.travelDate}
</p>
</div>
<div>
<p className="text-sm text-gray-400">Booking Date</p>
<p className="text-gray-100">{purchase.purchaseDate}</p>
</div>
<div>
<p className="text-sm text-gray-400">Amount</p>
<p className="text-green-400 font-bold">
${(purchase.amount / 1000000).toFixed(1)}M
</p>
</div>
</div>
<div className="flex justify-between items-center pt-4 border-t border-gray-600">
<div className="text-sm text-gray-400">
Agency: {purchase.agencyName}
</div>
<Link
to={`/bookings/${purchase.id}`}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
View Details
</Link>
</div>
</div>
))}
</div>
)}
{activeTab === "reviews" && (
<div className="space-y-6">
<h2 className="text-xl font-bold mb-4">Customer Reviews</h2>
{mockTourPurchases
.filter((purchase) => purchase.rating > 0)
.map((purchase) => (
<div
key={purchase.id}
className="bg-gray-700 p-6 rounded-lg hover:bg-gray-600 transition-colors"
>
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-lg font-bold text-gray-100">
{purchase.userName}
</h3>
<p className="text-gray-400 text-sm">
{purchase.travelDate}
</p>
</div>
<div className="flex items-center gap-2">
{renderStars(purchase.rating)}
<span className="text-gray-300">
{purchase.rating}.0
</span>
</div>
</div>
<p className="text-gray-100 mb-4">{purchase.review}</p>
<div className="flex justify-between items-center pt-4 border-t border-gray-600">
<div className="text-sm text-gray-400">
Booked on {purchase.purchaseDate}
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
</div>
);
}