Initial commit from remix

This commit is contained in:
gpt-engineer-app[bot]
2025-09-25 16:01:00 +00:00
commit 5ddc52658d
149 changed files with 32798 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
import { useLocation, useNavigate } from 'react-router-dom';
import { useState } from 'react';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import {
Star,
Heart,
Phone,
MapPin,
ExternalLink,
Expand,
Calendar,
User,
Video,
Fan,
Waves,
Wifi,
Car,
Utensils,
Shield,
Coffee
} from 'lucide-react';
export function ListingDetails() {
const location = useLocation();
const navigate = useNavigate();
const { listing } = location.state || {};
const [isBookmarked, setIsBookmarked] = useState(false);
if (!listing) {
return (
<div className="min-h-screen bg-background">
<Header />
<div className="container mx-auto px-4 py-8">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Listing not found</h1>
<Button onClick={() => navigate('/explore')}>
Back to Explore
</Button>
</div>
</div>
<Footer />
</div>
);
}
const amenities = [
{ icon: Video, name: "Security cameras" },
{ icon: Fan, name: "Garden" },
{ icon: Waves, name: "Jacuzzi" },
{ icon: Wifi, name: "Free WiFi" },
{ icon: Car, name: "Parking" },
{ icon: Utensils, name: "Restaurant" },
{ icon: Shield, name: "24/7 Security" },
{ icon: Coffee, name: "Breakfast" }
];
const galleryImages = [
"https://themes.easital.com/html/liston/v2.3/assets/images/listing-details/gallery/08.jpg",
"https://themes.easital.com/html/liston/v2.3/assets/images/listing-details/gallery/09.jpg",
"https://themes.easital.com/html/liston/v2.3/assets/images/listing-details/gallery/10.jpg"
];
return (
<div className="min-h-screen bg-background">
<Header />
{/* Details Header */}
<div className="py-6 bg-white border-b">
<div className="container mx-auto px-4">
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4">
<div className="flex-1">
<h1 className="text-3xl font-semibold mb-2">
{listing.title || 'Chuijhal Hotel And Restaurant'}
</h1>
<ul className="flex flex-wrap items-center gap-4 mb-2 text-sm">
<li>
<a href="#" className="font-medium text-primary flex items-center gap-1">
{listing.location || 'Chuijhal'}
<ExternalLink className="h-4 w-4" />
</a>
</li>
<li>
<div className="flex items-center gap-2">
<div className="flex text-primary">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`h-4 w-4 ${
i < Math.floor(listing.rating || 4.5) ? 'fill-current' : 'text-muted'
}`}
/>
))}
</div>
<span className="font-medium text-primary">
<span className="text-base font-semibold">({listing.rating || 4.5})</span>
<small className="ml-1">{listing.reviews || '2,391'} reviews</small>
</span>
</div>
</li>
</ul>
<ul className="flex flex-wrap items-center gap-4 text-sm text-muted-foreground font-medium">
<li>Posted 7 hours ago</li>
<li>1123 Fictional St, San Francisco</li>
<li>Full time</li>
</ul>
</div>
<div className="lg:text-right">
<div className="mb-2">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
checked={isBookmarked}
onChange={(e) => setIsBookmarked(e.target.checked)}
className="hidden"
/>
<Button
variant={isBookmarked ? "default" : "outline"}
className="gap-2"
>
<Heart className={`h-4 w-4 ${isBookmarked ? 'fill-current' : ''}`} />
{isBookmarked ? 'Saved' : 'Save this listing'}
</Button>
</label>
</div>
<div className="text-sm text-muted-foreground">
46 people bookmarked this place
</div>
</div>
</div>
</div>
</div>
{/* Gallery */}
<div className="container mx-auto px-4 py-6">
<div className="rounded-xl overflow-hidden">
<div className="grid grid-cols-1 md:grid-cols-4 gap-2 h-96">
<div className="md:col-span-3 relative">
<img
src={listing.image || galleryImages[0]}
alt="Main gallery image"
className="w-full h-full object-cover"
/>
<Button
variant="secondary"
size="sm"
className="absolute bottom-3 right-3 md:hidden gap-2"
>
<Expand className="h-4 w-4" />
View photos
</Button>
</div>
<div className="hidden md:flex md:flex-col gap-2">
<div className="flex-1 relative">
<img
src={galleryImages[1]}
alt="Gallery image"
className="w-full h-full object-cover"
/>
</div>
<div className="flex-1 relative">
<img
src={galleryImages[2]}
alt="Gallery image"
className="w-full h-full object-cover"
/>
<Button
variant="secondary"
size="sm"
className="absolute bottom-3 right-3 gap-2"
>
<Expand className="h-4 w-4" />
View photos
</Button>
</div>
</div>
</div>
</div>
<div className="flex justify-end mt-2">
<div className="text-sm">
<span className="font-semibold text-gray-800">Published:</span>
<span className="ml-2 text-muted-foreground">November 21, 2023</span>
</div>
</div>
</div>
{/* Main Content */}
<div className="container mx-auto px-4 py-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2">
{/* Description */}
<div className="mb-8">
<h4 className="text-2xl font-semibold mb-4">
Latest Property <span className="text-primary">Reviews</span>
</h4>
<div className="prose max-w-none">
<p className="text-muted-foreground mb-4">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book. It is a long established fact that a reader will be distracted
by the readable content of a page when looking at its layout.
</p>
<p className="text-muted-foreground">
It has survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum.
</p>
</div>
</div>
{/* Amenities */}
<div className="mb-8">
<h4 className="text-2xl font-semibold mb-4">
Amenities <span className="text-primary">Available</span>
</h4>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{amenities.map((amenity, index) => (
<div key={index} className="flex items-center gap-3 text-gray-800">
<div className="flex-shrink-0">
<amenity.icon className="h-5 w-5 text-primary" />
</div>
<div className="font-medium">{amenity.name}</div>
</div>
))}
</div>
</div>
</div>
{/* Sidebar */}
<div className="lg:col-span-1">
<Card className="sticky top-4">
<CardContent className="p-6">
<div className="text-center mb-6">
<div className="text-3xl font-bold text-primary mb-2">
${listing.priceRange?.min || 12} - ${listing.priceRange?.max || 40}
</div>
<p className="text-muted-foreground">per night</p>
</div>
<div className="space-y-4 mb-6">
<Button className="w-full" size="lg">
<Calendar className="h-4 w-4 mr-2" />
Book Now
</Button>
<Button variant="outline" className="w-full" size="lg">
<Phone className="h-4 w-4 mr-2" />
Call Now
</Button>
<Button variant="outline" className="w-full" size="lg">
<User className="h-4 w-4 mr-2" />
Contact Owner
</Button>
</div>
<div className="border-t pt-4 space-y-3">
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">Response rate:</span>
<span className="font-medium">100%</span>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">Response time:</span>
<span className="font-medium">Within an hour</span>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">Last seen:</span>
<span className="font-medium">Online now</span>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
<Footer />
</div>
);
}