feat: Add basic styling
This commit is contained in:
@@ -1,9 +1,195 @@
|
||||
import { TripDetails } from "../../../trip-planner/types";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function AccommodationsList({
|
||||
tripDetails,
|
||||
}: {
|
||||
tripDetails: TripDetails;
|
||||
}) {
|
||||
return <div>Accommodations list for {JSON.stringify(tripDetails)}</div>;
|
||||
console.log("tripDetails", tripDetails);
|
||||
// Placeholder data - ideally would come from props
|
||||
const [accommodations] = useState([
|
||||
{
|
||||
id: "1",
|
||||
name: "Grand Hotel",
|
||||
type: "Hotel",
|
||||
price: "$150/night",
|
||||
rating: 4.8,
|
||||
amenities: ["WiFi", "Pool", "Breakfast"],
|
||||
image: "https://placehold.co/300x200?text=Hotel",
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Cozy Apartment",
|
||||
type: "Apartment",
|
||||
price: "$120/night",
|
||||
rating: 4.5,
|
||||
amenities: ["WiFi", "Kitchen", "Washing Machine"],
|
||||
image: "https://placehold.co/300x200?text=Apartment",
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Beachside Villa",
|
||||
type: "Villa",
|
||||
price: "$300/night",
|
||||
rating: 4.9,
|
||||
amenities: ["WiFi", "Private Pool", "Ocean View"],
|
||||
image: "https://placehold.co/300x200?text=Villa",
|
||||
available: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
|
||||
const selectedAccommodation = accommodations.find(
|
||||
(acc) => acc.id === selectedId,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className="bg-blue-600 px-4 py-3">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-white font-medium">
|
||||
Accommodations in {tripDetails.location}
|
||||
</h3>
|
||||
{selectedId && (
|
||||
<button
|
||||
onClick={() => setSelectedId(null)}
|
||||
className="text-white text-sm bg-blue-700 hover:bg-blue-800 px-2 py-1 rounded"
|
||||
>
|
||||
Back to list
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-blue-100 text-xs">
|
||||
{new Date(tripDetails.startDate).toLocaleDateString()} -{" "}
|
||||
{new Date(tripDetails.endDate).toLocaleDateString()} ·{" "}
|
||||
{tripDetails.numberOfGuests} guests
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
{!selectedId ? (
|
||||
<div className="space-y-3">
|
||||
{accommodations.map((accommodation) => (
|
||||
<div
|
||||
key={accommodation.id}
|
||||
onClick={() => setSelectedId(accommodation.id)}
|
||||
className={`flex border rounded-lg p-3 cursor-pointer transition-all ${
|
||||
accommodation.available
|
||||
? "hover:border-blue-300 hover:shadow-md"
|
||||
: "opacity-60"
|
||||
}`}
|
||||
>
|
||||
<div className="w-20 h-20 bg-gray-200 rounded-md flex-shrink-0 overflow-hidden">
|
||||
<img
|
||||
src={accommodation.image}
|
||||
alt={accommodation.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 flex-1">
|
||||
<div className="flex justify-between">
|
||||
<h4 className="font-medium text-gray-900">
|
||||
{accommodation.name}
|
||||
</h4>
|
||||
<span className="text-sm font-semibold text-blue-600">
|
||||
{accommodation.price}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">{accommodation.type}</p>
|
||||
<div className="flex items-center mt-1">
|
||||
<svg
|
||||
className="w-4 h-4 text-yellow-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||||
</svg>
|
||||
<span className="text-xs text-gray-500 ml-1">
|
||||
{accommodation.rating}
|
||||
</span>
|
||||
</div>
|
||||
{!accommodation.available && (
|
||||
<span className="text-xs text-red-500 font-medium">
|
||||
Unavailable for your dates
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{selectedAccommodation && (
|
||||
<>
|
||||
<div className="w-full h-40 bg-gray-200 rounded-lg overflow-hidden">
|
||||
<img
|
||||
src={selectedAccommodation.image}
|
||||
alt={selectedAccommodation.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between items-start">
|
||||
<h3 className="font-medium text-lg text-gray-900">
|
||||
{selectedAccommodation.name}
|
||||
</h3>
|
||||
<span className="font-semibold text-blue-600">
|
||||
{selectedAccommodation.price}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center mt-1">
|
||||
<svg
|
||||
className="w-4 h-4 text-yellow-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||||
</svg>
|
||||
<span className="text-sm text-gray-500 ml-1">
|
||||
{selectedAccommodation.rating}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-2">
|
||||
Perfect accommodation in {tripDetails.location} for your{" "}
|
||||
{tripDetails.numberOfGuests} guests.
|
||||
</p>
|
||||
<div className="mt-3">
|
||||
<h4 className="text-sm font-medium text-gray-700">
|
||||
Amenities:
|
||||
</h4>
|
||||
<div className="flex flex-wrap gap-1 mt-1">
|
||||
{selectedAccommodation.amenities.map((amenity) => (
|
||||
<span
|
||||
key={amenity}
|
||||
className="text-xs bg-gray-100 px-2 py-1 rounded"
|
||||
>
|
||||
{amenity}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className={`w-full mt-4 py-2 rounded-md text-white font-medium ${
|
||||
selectedAccommodation.available
|
||||
? "bg-blue-600 hover:bg-blue-700"
|
||||
: "bg-gray-400 cursor-not-allowed"
|
||||
}`}
|
||||
disabled={!selectedAccommodation.available}
|
||||
>
|
||||
{selectedAccommodation.available
|
||||
? "Book Now"
|
||||
: "Unavailable"}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TripDetails } from "../../../trip-planner/types";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function BookAccommodation({
|
||||
tripDetails,
|
||||
@@ -7,9 +8,395 @@ export default function BookAccommodation({
|
||||
tripDetails: TripDetails;
|
||||
accommodationName: string;
|
||||
}) {
|
||||
// Placeholder data - ideally would come from props
|
||||
const [accommodation] = useState({
|
||||
name: accommodationName,
|
||||
type: "Hotel",
|
||||
price: "$150/night",
|
||||
rating: 4.8,
|
||||
totalPrice:
|
||||
"$" +
|
||||
150 *
|
||||
Math.ceil(
|
||||
(new Date(tripDetails.endDate).getTime() -
|
||||
new Date(tripDetails.startDate).getTime()) /
|
||||
(1000 * 60 * 60 * 24),
|
||||
),
|
||||
image: "https://placehold.co/300x200?text=Accommodation",
|
||||
roomTypes: ["Standard", "Deluxe", "Suite"],
|
||||
checkInTime: "3:00 PM",
|
||||
checkOutTime: "11:00 AM",
|
||||
});
|
||||
|
||||
const [selectedRoom, setSelectedRoom] = useState("Standard");
|
||||
const [bookingStep, setBookingStep] = useState<
|
||||
"details" | "payment" | "confirmed"
|
||||
>("details");
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
specialRequests: "",
|
||||
});
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setBookingStep("payment");
|
||||
};
|
||||
|
||||
const handlePayment = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setBookingStep("confirmed");
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
Book accommodation {accommodationName} for {JSON.stringify(tripDetails)}
|
||||
<div className="w-full max-w-md bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className="bg-blue-600 px-4 py-3">
|
||||
<h3 className="text-white font-medium">Book {accommodation.name}</h3>
|
||||
<p className="text-blue-100 text-xs">
|
||||
{new Date(tripDetails.startDate).toLocaleDateString()} -{" "}
|
||||
{new Date(tripDetails.endDate).toLocaleDateString()} ·{" "}
|
||||
{tripDetails.numberOfGuests} guests
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
{bookingStep === "details" && (
|
||||
<>
|
||||
<div className="flex items-center space-x-3 mb-4">
|
||||
<div className="flex-shrink-0 w-16 h-16 bg-gray-200 rounded-md overflow-hidden">
|
||||
<img
|
||||
src={accommodation.image}
|
||||
alt={accommodation.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">
|
||||
{accommodation.name}
|
||||
</h4>
|
||||
<div className="flex items-center mt-1">
|
||||
<svg
|
||||
className="w-4 h-4 text-yellow-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||||
</svg>
|
||||
<span className="text-xs text-gray-500 ml-1">
|
||||
{accommodation.rating}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-1">
|
||||
<span className="text-sm text-gray-500">
|
||||
{accommodation.type}
|
||||
</span>
|
||||
<span className="text-sm font-semibold text-blue-600">
|
||||
{accommodation.price}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-b py-3 mb-4">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-gray-600">Check-in</span>
|
||||
<span className="font-medium">
|
||||
{new Date(tripDetails.startDate).toLocaleDateString()} (
|
||||
{accommodation.checkInTime})
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm mt-2">
|
||||
<span className="text-gray-600">Check-out</span>
|
||||
<span className="font-medium">
|
||||
{new Date(tripDetails.endDate).toLocaleDateString()} (
|
||||
{accommodation.checkOutTime})
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm mt-2">
|
||||
<span className="text-gray-600">Guests</span>
|
||||
<span className="font-medium">
|
||||
{tripDetails.numberOfGuests}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Room Type
|
||||
</label>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{accommodation.roomTypes.map((room) => (
|
||||
<button
|
||||
key={room}
|
||||
type="button"
|
||||
onClick={() => setSelectedRoom(room)}
|
||||
className={`text-sm py-2 px-3 rounded-md border transition-colors ${
|
||||
selectedRoom === room
|
||||
? "border-blue-500 bg-blue-50 text-blue-700"
|
||||
: "border-gray-300 text-gray-700 hover:border-gray-400"
|
||||
}`}
|
||||
>
|
||||
{room}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-3">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Full Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Phone
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
id="phone"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="specialRequests"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Special Requests
|
||||
</label>
|
||||
<textarea
|
||||
id="specialRequests"
|
||||
name="specialRequests"
|
||||
value={formData.specialRequests}
|
||||
onChange={handleInputChange}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-3 mt-4">
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<span className="text-gray-600 text-sm">Total Price:</span>
|
||||
<span className="font-semibold text-lg">
|
||||
{accommodation.totalPrice}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors"
|
||||
>
|
||||
Continue to Payment
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
)}
|
||||
|
||||
{bookingStep === "payment" && (
|
||||
<form onSubmit={handlePayment} className="space-y-3">
|
||||
<h4 className="font-medium text-lg text-gray-900 mb-3">
|
||||
Payment Details
|
||||
</h4>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="cardName"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Name on Card
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="cardName"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="cardNumber"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Card Number
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="cardNumber"
|
||||
placeholder="XXXX XXXX XXXX XXXX"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="expiry"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Expiry Date
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="expiry"
|
||||
placeholder="MM/YY"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="cvc"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
CVC
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="cvc"
|
||||
placeholder="XXX"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-3 mt-4">
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<span className="text-gray-600 text-sm">Total Amount:</span>
|
||||
<span className="font-semibold text-lg">
|
||||
{accommodation.totalPrice}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors"
|
||||
>
|
||||
Complete Booking
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBookingStep("details")}
|
||||
className="w-full mt-2 bg-white border border-gray-300 text-gray-700 font-medium py-2 px-4 rounded-md hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{bookingStep === "confirmed" && (
|
||||
<div className="text-center py-6">
|
||||
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100 mb-3">
|
||||
<svg
|
||||
className="h-6 w-6 text-green-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900">
|
||||
Booking Confirmed!
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
Your booking at {accommodation.name} has been confirmed. You'll
|
||||
receive a confirmation email shortly at {formData.email}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-4 p-3 bg-gray-50 rounded-lg text-left">
|
||||
<h4 className="font-medium text-sm text-gray-700">
|
||||
Booking Summary
|
||||
</h4>
|
||||
<ul className="mt-2 space-y-1 text-xs text-gray-600">
|
||||
<li className="flex justify-between">
|
||||
<span>Check-in:</span>
|
||||
<span className="font-medium">
|
||||
{new Date(tripDetails.startDate).toLocaleDateString()}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Check-out:</span>
|
||||
<span className="font-medium">
|
||||
{new Date(tripDetails.endDate).toLocaleDateString()}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Room type:</span>
|
||||
<span className="font-medium">{selectedRoom}</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Guests:</span>
|
||||
<span className="font-medium">
|
||||
{tripDetails.numberOfGuests}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex justify-between pt-1 mt-1 border-t">
|
||||
<span>Total paid:</span>
|
||||
<span className="font-medium">
|
||||
{accommodation.totalPrice}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TripDetails } from "../../../trip-planner/types";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function BookRestaurant({
|
||||
tripDetails,
|
||||
@@ -7,9 +8,342 @@ export default function BookRestaurant({
|
||||
tripDetails: TripDetails;
|
||||
restaurantName: string;
|
||||
}) {
|
||||
// Placeholder data - ideally would come from props
|
||||
const [restaurant] = useState({
|
||||
name: restaurantName,
|
||||
cuisine: "Contemporary",
|
||||
priceRange: "$$",
|
||||
rating: 4.7,
|
||||
image: "https://placehold.co/300x200?text=Restaurant",
|
||||
openingHours: "5:00 PM - 10:00 PM",
|
||||
address: "123 Main St, " + tripDetails.location,
|
||||
availableTimes: ["6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM"],
|
||||
});
|
||||
|
||||
const [reservationStep, setReservationStep] = useState<
|
||||
"selection" | "details" | "confirmed"
|
||||
>("selection");
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(
|
||||
new Date(tripDetails.startDate),
|
||||
);
|
||||
const [selectedTime, setSelectedTime] = useState<string | null>(null);
|
||||
const [guests, setGuests] = useState(Math.min(tripDetails.numberOfGuests, 8));
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
specialRequests: "",
|
||||
});
|
||||
|
||||
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const date = new Date(e.target.value);
|
||||
setSelectedDate(date);
|
||||
};
|
||||
|
||||
const handleGuestsChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
setGuests(Number(e.target.value));
|
||||
};
|
||||
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const handleTimeSelection = (time: string) => {
|
||||
setSelectedTime(time);
|
||||
};
|
||||
|
||||
const handleContinue = () => {
|
||||
if (selectedTime) {
|
||||
setReservationStep("details");
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setReservationStep("confirmed");
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return date.toISOString().split("T")[0];
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
Book restaurant {restaurantName} for {JSON.stringify(tripDetails)}
|
||||
<div className="w-full max-w-md bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className="bg-orange-600 px-4 py-3">
|
||||
<h3 className="text-white font-medium">Reserve at {restaurant.name}</h3>
|
||||
<p className="text-orange-100 text-xs">
|
||||
{restaurant.cuisine} • {restaurant.priceRange} • {restaurant.rating}★
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
{reservationStep === "selection" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-3 mb-4">
|
||||
<div className="flex-shrink-0 w-16 h-16 bg-gray-200 rounded-md overflow-hidden">
|
||||
<img
|
||||
src={restaurant.image}
|
||||
alt={restaurant.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">{restaurant.name}</h4>
|
||||
<p className="text-sm text-gray-500">{restaurant.address}</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{restaurant.openingHours}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="date"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Date
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
min={formatDate(new Date(tripDetails.startDate))}
|
||||
max={formatDate(new Date(tripDetails.endDate))}
|
||||
value={formatDate(selectedDate)}
|
||||
onChange={handleDateChange}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="guests"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Guests
|
||||
</label>
|
||||
<select
|
||||
id="guests"
|
||||
value={guests}
|
||||
onChange={handleGuestsChange}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
>
|
||||
{Array.from({ length: 8 }, (_, i) => i + 1).map((num) => (
|
||||
<option key={num} value={num}>
|
||||
{num} {num === 1 ? "person" : "people"}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Available Times
|
||||
</label>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{restaurant.availableTimes.map((time) => (
|
||||
<button
|
||||
key={time}
|
||||
type="button"
|
||||
onClick={() => handleTimeSelection(time)}
|
||||
className={`text-sm py-2 px-3 rounded-md border transition-colors ${
|
||||
selectedTime === time
|
||||
? "border-orange-500 bg-orange-50 text-orange-700"
|
||||
: "border-gray-300 text-gray-700 hover:border-gray-400"
|
||||
}`}
|
||||
>
|
||||
{time}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleContinue}
|
||||
disabled={!selectedTime}
|
||||
className={`w-full py-2 rounded-md text-white font-medium ${
|
||||
selectedTime
|
||||
? "bg-orange-600 hover:bg-orange-700"
|
||||
: "bg-gray-400 cursor-not-allowed"
|
||||
}`}
|
||||
>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{reservationStep === "details" && (
|
||||
<form onSubmit={handleSubmit} className="space-y-3">
|
||||
<div className="border-b pb-3 mb-1">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-gray-600">Date & Time</span>
|
||||
<span className="font-medium">
|
||||
{selectedDate.toLocaleDateString()} at {selectedTime}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm mt-1">
|
||||
<span className="text-gray-600">Party Size</span>
|
||||
<span className="font-medium">
|
||||
{guests} {guests === 1 ? "person" : "people"}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setReservationStep("selection")}
|
||||
className="text-orange-600 text-xs hover:underline mt-2"
|
||||
>
|
||||
Change
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Full Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Phone
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
id="phone"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="specialRequests"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Special Requests
|
||||
</label>
|
||||
<textarea
|
||||
id="specialRequests"
|
||||
name="specialRequests"
|
||||
value={formData.specialRequests}
|
||||
onChange={handleInputChange}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-orange-500 focus:border-orange-500 text-sm"
|
||||
placeholder="Allergies, special occasions, seating preferences..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-orange-600 hover:bg-orange-700 text-white font-medium py-2 px-4 rounded-md transition-colors"
|
||||
>
|
||||
Confirm Reservation
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{reservationStep === "confirmed" && (
|
||||
<div className="text-center py-6">
|
||||
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100 mb-3">
|
||||
<svg
|
||||
className="h-6 w-6 text-green-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900">
|
||||
Reservation Confirmed!
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
Your table at {restaurant.name} has been reserved. You'll
|
||||
receive a confirmation email shortly at {formData.email}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-4 p-3 bg-gray-50 rounded-lg text-left">
|
||||
<h4 className="font-medium text-sm text-gray-700">
|
||||
Reservation Details
|
||||
</h4>
|
||||
<ul className="mt-2 space-y-1 text-xs text-gray-600">
|
||||
<li className="flex justify-between">
|
||||
<span>Restaurant:</span>
|
||||
<span className="font-medium">{restaurant.name}</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Date:</span>
|
||||
<span className="font-medium">
|
||||
{selectedDate.toLocaleDateString()}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Time:</span>
|
||||
<span className="font-medium">{selectedTime}</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Party Size:</span>
|
||||
<span className="font-medium">
|
||||
{guests} {guests === 1 ? "person" : "people"}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex justify-between">
|
||||
<span>Reservation Name:</span>
|
||||
<span className="font-medium">{formData.name}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p className="mt-3 text-xs text-gray-500">
|
||||
Need to cancel or modify? Please call the restaurant directly at
|
||||
(123) 456-7890.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,249 @@
|
||||
import { TripDetails } from "../../../trip-planner/types";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function RestaurantsList({
|
||||
tripDetails,
|
||||
}: {
|
||||
tripDetails: TripDetails;
|
||||
}) {
|
||||
return <div>Restaurants list for {JSON.stringify(tripDetails)}</div>;
|
||||
// Placeholder data - ideally would come from props
|
||||
const [restaurants] = useState([
|
||||
{
|
||||
id: "1",
|
||||
name: "The Local Grill",
|
||||
cuisine: "Steakhouse",
|
||||
priceRange: "$$",
|
||||
rating: 4.7,
|
||||
distance: "0.5 miles from center",
|
||||
image: "https://placehold.co/300x200?text=Restaurant1",
|
||||
openingHours: "5:00 PM - 10:00 PM",
|
||||
popular: true,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Ocean Breeze",
|
||||
cuisine: "Seafood",
|
||||
priceRange: "$$$",
|
||||
rating: 4.9,
|
||||
distance: "0.8 miles from center",
|
||||
image: "https://placehold.co/300x200?text=Restaurant2",
|
||||
openingHours: "12:00 PM - 11:00 PM",
|
||||
popular: true,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Pasta Paradise",
|
||||
cuisine: "Italian",
|
||||
priceRange: "$$",
|
||||
rating: 4.5,
|
||||
distance: "1.2 miles from center",
|
||||
image: "https://placehold.co/300x200?text=Restaurant3",
|
||||
openingHours: "11:30 AM - 9:30 PM",
|
||||
popular: false,
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "Spice Garden",
|
||||
cuisine: "Indian",
|
||||
priceRange: "$$",
|
||||
rating: 4.6,
|
||||
distance: "0.7 miles from center",
|
||||
image: "https://placehold.co/300x200?text=Restaurant4",
|
||||
openingHours: "12:00 PM - 10:00 PM",
|
||||
popular: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
const [filter, setFilter] = useState<string | null>(null);
|
||||
|
||||
const selectedRestaurant = restaurants.find((r) => r.id === selectedId);
|
||||
|
||||
const filteredRestaurants = filter
|
||||
? restaurants.filter((r) => r.cuisine === filter)
|
||||
: restaurants;
|
||||
|
||||
const cuisines = Array.from(new Set(restaurants.map((r) => r.cuisine)));
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className="bg-orange-600 px-4 py-3">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-white font-medium">
|
||||
Restaurants in {tripDetails.location}
|
||||
</h3>
|
||||
{selectedId && (
|
||||
<button
|
||||
onClick={() => setSelectedId(null)}
|
||||
className="text-white text-sm bg-orange-700 hover:bg-orange-800 px-2 py-1 rounded"
|
||||
>
|
||||
Back to list
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-orange-100 text-xs">
|
||||
For your trip {new Date(tripDetails.startDate).toLocaleDateString()} -{" "}
|
||||
{new Date(tripDetails.endDate).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{!selectedId ? (
|
||||
<div className="p-4">
|
||||
<div className="mb-3">
|
||||
<div className="flex flex-wrap gap-1 mb-1">
|
||||
<button
|
||||
onClick={() => setFilter(null)}
|
||||
className={`px-2 py-1 text-xs rounded-full ${
|
||||
filter === null
|
||||
? "bg-orange-600 text-white"
|
||||
: "bg-gray-100 text-gray-800 hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
All
|
||||
</button>
|
||||
{cuisines.map((cuisine) => (
|
||||
<button
|
||||
key={cuisine}
|
||||
onClick={() => setFilter(cuisine)}
|
||||
className={`px-2 py-1 text-xs rounded-full ${
|
||||
filter === cuisine
|
||||
? "bg-orange-600 text-white"
|
||||
: "bg-gray-100 text-gray-800 hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
{cuisine}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">
|
||||
Showing {filteredRestaurants.length} restaurants{" "}
|
||||
{filter ? `in ${filter}` : ""}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{filteredRestaurants.map((restaurant) => (
|
||||
<div
|
||||
key={restaurant.id}
|
||||
onClick={() => setSelectedId(restaurant.id)}
|
||||
className="border rounded-lg p-3 cursor-pointer hover:border-orange-300 hover:shadow-md transition-all"
|
||||
>
|
||||
<div className="flex">
|
||||
<div className="w-20 h-20 bg-gray-200 rounded-md flex-shrink-0 overflow-hidden">
|
||||
<img
|
||||
src={restaurant.image}
|
||||
alt={restaurant.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 flex-1">
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">
|
||||
{restaurant.name}
|
||||
</h4>
|
||||
<p className="text-sm text-gray-500">
|
||||
{restaurant.cuisine}
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-sm text-gray-700">
|
||||
{restaurant.priceRange}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center mt-1">
|
||||
<svg
|
||||
className="w-4 h-4 text-yellow-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||||
</svg>
|
||||
<span className="text-xs text-gray-500 ml-1">
|
||||
{restaurant.rating}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center mt-1">
|
||||
<span className="text-xs text-gray-500">
|
||||
{restaurant.distance}
|
||||
</span>
|
||||
{restaurant.popular && (
|
||||
<span className="text-xs bg-orange-100 text-orange-800 px-1.5 py-0.5 rounded-sm">
|
||||
Popular
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-4">
|
||||
{selectedRestaurant && (
|
||||
<div className="space-y-4">
|
||||
<div className="w-full h-40 bg-gray-200 rounded-lg overflow-hidden">
|
||||
<img
|
||||
src={selectedRestaurant.image}
|
||||
alt={selectedRestaurant.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<h3 className="font-medium text-lg text-gray-900">
|
||||
{selectedRestaurant.name}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600">
|
||||
{selectedRestaurant.cuisine}
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-gray-700 font-medium">
|
||||
{selectedRestaurant.priceRange}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
className="w-4 h-4 text-yellow-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||||
</svg>
|
||||
<span className="text-sm text-gray-600 ml-1">
|
||||
{selectedRestaurant.rating} rating
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center text-sm text-gray-600 space-x-4">
|
||||
<span>{selectedRestaurant.distance}</span>
|
||||
<span>•</span>
|
||||
<span>{selectedRestaurant.openingHours}</span>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-gray-600 pt-2 border-t">
|
||||
{selectedRestaurant.name} offers a wonderful dining experience
|
||||
in {tripDetails.location}. Perfect for a group of{" "}
|
||||
{tripDetails.numberOfGuests} guests. Enjoy authentic{" "}
|
||||
{selectedRestaurant.cuisine} cuisine in a relaxed atmosphere.
|
||||
</p>
|
||||
|
||||
<div className="pt-3 flex flex-col space-y-2">
|
||||
<button className="w-full bg-orange-600 hover:bg-orange-700 text-white font-medium py-2 px-4 rounded-md transition-colors">
|
||||
Reserve a Table
|
||||
</button>
|
||||
<button className="w-full bg-white border border-gray-300 text-gray-700 font-medium py-2 px-4 rounded-md hover:bg-gray-50 transition-colors">
|
||||
View Menu
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user