aether-rides / VehicleDetailPage.tsx
lattmamb's picture
Upload 32 files (#1)
a1a9b91 verified
import { useEffect, useState } from 'react';
import { useParams, Link } from 'react-router-dom';
import { getVehicleById, Vehicle } from '@/data/vehicles';
import { ArrowLeft, Battery, Clock, Users, Zap, Check, Calendar, CreditCard } from 'lucide-react';
const VehicleDetailPage = () => {
const { id } = useParams<{ id: string }>();
const [vehicle, setVehicle] = useState<Vehicle | null>(null);
const [activeTab, setActiveTab] = useState<'overview' | 'specs' | 'features'>('overview');
const [rentalDuration, setRentalDuration] = useState(1); // days
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (id) {
const foundVehicle = getVehicleById(id);
setVehicle(foundVehicle || null);
setIsLoading(false);
}
}, [id]);
if (isLoading) {
return (
<div className="bg-[#0a0a0a] text-white min-h-screen flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
</div>
);
}
if (!vehicle) {
return (
<div className="bg-[#0a0a0a] text-white min-h-screen">
<div className="container mx-auto px-4 py-12 text-center">
<h2 className="text-2xl font-bold mb-4">Vehicle Not Found</h2>
<p className="text-gray-400 mb-6">Sorry, we couldn't find the vehicle you're looking for.</p>
<Link
to="/vehicles"
className="bg-blue-600 hover:bg-blue-700 px-5 py-2.5 rounded-md inline-flex items-center gap-2"
>
<ArrowLeft size={16} />
Back to Vehicles
</Link>
</div>
</div>
);
}
const totalRentalPrice = vehicle.price * rentalDuration;
return (
<div className="bg-[#0a0a0a] text-white min-h-screen">
<div className="container mx-auto px-4 py-12">
{/* Back navigation */}
<Link
to="/vehicles"
className="inline-flex items-center gap-2 text-gray-300 hover:text-white mb-8"
>
<ArrowLeft size={16} />
Back to Vehicles
</Link>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10">
{/* Left Column - Image */}
<div>
<div className="bg-gradient-to-br from-[#15151a] to-[#0c0c10] p-8 rounded-lg h-full flex items-center justify-center">
<img
src={vehicle.image}
alt={`${vehicle.name} ${vehicle.model}`}
className="w-full h-auto max-h-[400px] object-contain"
/>
</div>
</div>
{/* Right Column - Info */}
<div>
<div className="mb-6">
<div className="flex items-start justify-between">
<div>
<h1 className="text-3xl md:text-4xl font-bold">
{vehicle.name} {vehicle.model}
</h1>
<div className="flex items-center gap-2 mt-2">
<span className="inline-block px-2.5 py-1 bg-blue-600 text-xs font-semibold rounded-full">
{vehicle.category}
</span>
<span className="text-gray-400">Electric</span>
</div>
</div>
<div className="text-right">
<div className="text-3xl font-bold">${vehicle.price}</div>
<div className="text-gray-400 text-sm">per day</div>
</div>
</div>
<p className="text-gray-300 mt-4">{vehicle.description}</p>
</div>
{/* Tabs */}
<div className="border-b border-gray-800 mb-6">
<nav className="flex gap-6">
<button
onClick={() => setActiveTab('overview')}
className={`pb-3 px-1 relative ${
activeTab === 'overview'
? 'text-blue-500 font-medium after:absolute after:h-0.5 after:w-full after:bg-blue-500 after:bottom-0 after:left-0'
: 'text-gray-400 hover:text-white'
}`}
>
Overview
</button>
<button
onClick={() => setActiveTab('specs')}
className={`pb-3 px-1 relative ${
activeTab === 'specs'
? 'text-blue-500 font-medium after:absolute after:h-0.5 after:w-full after:bg-blue-500 after:bottom-0 after:left-0'
: 'text-gray-400 hover:text-white'
}`}
>
Specifications
</button>
<button
onClick={() => setActiveTab('features')}
className={`pb-3 px-1 relative ${
activeTab === 'features'
? 'text-blue-500 font-medium after:absolute after:h-0.5 after:w-full after:bg-blue-500 after:bottom-0 after:left-0'
: 'text-gray-400 hover:text-white'
}`}
>
Features
</button>
</nav>
</div>
{/* Tab Content */}
<div className="mb-8">
{activeTab === 'overview' && (
<div>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="bg-[#15151a] p-4 rounded-lg flex items-center gap-3">
<div className="bg-blue-600/20 p-2 rounded">
<Battery className="text-blue-500 w-5 h-5" />
</div>
<div>
<div className="text-sm text-gray-400">Range</div>
<div className="font-medium">{vehicle.specs.range}</div>
</div>
</div>
<div className="bg-[#15151a] p-4 rounded-lg flex items-center gap-3">
<div className="bg-blue-600/20 p-2 rounded">
<Zap className="text-blue-500 w-5 h-5" />
</div>
<div>
<div className="text-sm text-gray-400">Acceleration</div>
<div className="font-medium">{vehicle.specs.acceleration}</div>
</div>
</div>
<div className="bg-[#15151a] p-4 rounded-lg flex items-center gap-3">
<div className="bg-blue-600/20 p-2 rounded">
<Clock className="text-blue-500 w-5 h-5" />
</div>
<div>
<div className="text-sm text-gray-400">Top Speed</div>
<div className="font-medium">{vehicle.specs.topSpeed}</div>
</div>
</div>
<div className="bg-[#15151a] p-4 rounded-lg flex items-center gap-3">
<div className="bg-blue-600/20 p-2 rounded">
<Users className="text-blue-500 w-5 h-5" />
</div>
<div>
<div className="text-sm text-gray-400">Capacity</div>
<div className="font-medium">{vehicle.specs.capacity}</div>
</div>
</div>
</div>
<div className="mb-6">
<h3 className="text-lg font-medium mb-2">Rental Options</h3>
<div className="flex gap-4 mb-4">
<button
onClick={() => setRentalDuration(1)}
className={`flex-1 py-3 rounded-md transition-colors ${
rentalDuration === 1
? 'bg-blue-600 text-white'
: 'bg-[#15151a] text-gray-300 hover:bg-gray-800'
}`}
>
1 Day
</button>
<button
onClick={() => setRentalDuration(3)}
className={`flex-1 py-3 rounded-md transition-colors ${
rentalDuration === 3
? 'bg-blue-600 text-white'
: 'bg-[#15151a] text-gray-300 hover:bg-gray-800'
}`}
>
3 Days
</button>
<button
onClick={() => setRentalDuration(7)}
className={`flex-1 py-3 rounded-md transition-colors ${
rentalDuration === 7
? 'bg-blue-600 text-white'
: 'bg-[#15151a] text-gray-300 hover:bg-gray-800'
}`}
>
7 Days
</button>
</div>
</div>
<div className="bg-[#15151a] p-5 rounded-lg mb-6">
<div className="flex justify-between mb-3">
<span className="text-gray-300">${vehicle.price} × {rentalDuration} day{rentalDuration > 1 ? 's' : ''}</span>
<span>${totalRentalPrice}</span>
</div>
<div className="flex justify-between mb-3">
<span className="text-gray-300">Insurance</span>
<span>Included</span>
</div>
<div className="flex justify-between mb-3">
<span className="text-gray-300">Charging</span>
<span>Included</span>
</div>
<div className="border-t border-gray-800 pt-3 mt-3 flex justify-between font-bold">
<span>Total</span>
<span>${totalRentalPrice}</span>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<button className="bg-blue-600 hover:bg-blue-700 p-4 rounded-md font-medium transition-colors flex items-center justify-center gap-2">
<Calendar size={18} />
Rent Now
</button>
<button className="bg-gray-800 hover:bg-gray-700 p-4 rounded-md font-medium transition-colors flex items-center justify-center gap-2">
<CreditCard size={18} />
Subscribe for ${vehicle.pricePerMonth}/mo
</button>
</div>
</div>
)}
{activeTab === 'specs' && (
<div>
<div className="bg-[#15151a] rounded-lg overflow-hidden">
<div className="grid grid-cols-1 md:grid-cols-2">
<div className="p-4 border-b md:border-b-0 md:border-r border-gray-800">
<h3 className="font-medium mb-3">Performance</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Range</span>
<span>{vehicle.specs.range}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Top Speed</span>
<span>{vehicle.specs.topSpeed}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Acceleration</span>
<span>{vehicle.specs.acceleration}</span>
</div>
</div>
</div>
<div className="p-4">
<h3 className="font-medium mb-3">Interior</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Seating</span>
<span>{vehicle.specs.capacity}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Touchscreen</span>
<span>15" Center Display</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Sound System</span>
<span>Premium Audio</span>
</div>
</div>
</div>
</div>
<div className="border-t border-gray-800">
<div className="p-4">
<h3 className="font-medium mb-3">Technology</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Autopilot</span>
<span>Included</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Over-the-air Updates</span>
<span>Yes</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Connectivity</span>
<span>Premium Connectivity</span>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{activeTab === 'features' && (
<div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{vehicle.features.map((feature, index) => (
<div key={index} className="flex items-center gap-2">
<div className="flex-shrink-0 w-5 h-5 rounded-full bg-green-600/20 flex items-center justify-center">
<Check className="text-green-500 w-3 h-3" />
</div>
<span>{feature}</span>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
};
export default VehicleDetailPage;