Merge version_3 into main #5
71
src/app/api/send-booking-email/route.ts
Normal file
71
src/app/api/send-booking-email/route.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import nodemailer from 'nodemailer';
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
user: process.env.HOTEL_EMAIL,
|
||||
pass: process.env.HOTEL_EMAIL_PASSWORD,
|
||||
},
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { recipientEmail, subject, htmlContent, bookingData, roomDetails } = await request.json();
|
||||
|
||||
// Validate required fields
|
||||
if (!bookingData.phone || !bookingData.email || !bookingData.age || !bookingData.roomType) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required booking information' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Send email to hotel
|
||||
await transporter.sendMail({
|
||||
from: process.env.HOTEL_EMAIL,
|
||||
to: recipientEmail,
|
||||
subject: subject,
|
||||
html: htmlContent,
|
||||
});
|
||||
|
||||
// Send confirmation email to customer
|
||||
const confirmationHtml = `
|
||||
<h2>Booking Confirmation - Hotel Shine Inn</h2>
|
||||
<p>Dear Guest,</p>
|
||||
<p>Thank you for your booking request! We have received your information and will contact you shortly to confirm your reservation.</p>
|
||||
<h3>Booking Details:</h3>
|
||||
<ul>
|
||||
<li><strong>Room Type:</strong> ${roomDetails.name}</li>
|
||||
<li><strong>Room Price:</strong> ${roomDetails.price}</li>
|
||||
<li><strong>Payment Method:</strong> ${bookingData.paymentMethod === 'online' ? 'Online Payment' : 'Pay at Counter'}</li>
|
||||
</ul>
|
||||
<p><strong>Your Contact Information:</strong></p>
|
||||
<ul>
|
||||
<li><strong>Phone:</strong> ${bookingData.phone}</li>
|
||||
<li><strong>Email:</strong> ${bookingData.email}</li>
|
||||
</ul>
|
||||
<p>If you have any questions, please don't hesitate to contact us at +91 81305 21617 or reply to this email.</p>
|
||||
<p>We look forward to hosting you at Hotel Shine Inn!</p>
|
||||
<p>Best regards,<br/>Hotel Shine Inn Team<br/>Sector 3, Rohini, Delhi</p>
|
||||
`;
|
||||
|
||||
await transporter.sendMail({
|
||||
from: process.env.HOTEL_EMAIL,
|
||||
to: bookingData.email,
|
||||
subject: 'Booking Confirmation - Hotel Shine Inn',
|
||||
html: confirmationHtml,
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: 'Booking email sent successfully' },
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Email sending error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to send booking email' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
249
src/app/page.tsx
249
src/app/page.tsx
@@ -10,13 +10,107 @@ import MetricCardThree from '@/components/sections/metrics/MetricCardThree';
|
||||
import TestimonialCardTen from '@/components/sections/testimonial/TestimonialCardTen';
|
||||
import ContactFaq from '@/components/sections/contact/ContactFaq';
|
||||
import FooterLogoEmphasis from '@/components/sections/footer/FooterLogoEmphasis';
|
||||
import { Sparkles, Star, Home, Wifi, Wind, ParkingCircle, Heart, Lock, Users, MessageCircle, Phone, TrendingUp, Award, CheckCircle } from 'lucide-react';
|
||||
import { Sparkles, Star, Home, Wifi, Wind, ParkingCircle, Heart, Lock, Users, MessageCircle, Phone, TrendingUp, Award, CheckCircle, X } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function LandingPage() {
|
||||
const [isBookingModalOpen, setIsBookingModalOpen] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
phone: '',
|
||||
email: '',
|
||||
age: '',
|
||||
roomType: 'deluxe',
|
||||
paymentMethod: 'online'
|
||||
});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitMessage, setSubmitMessage] = useState('');
|
||||
|
||||
const handleCallNow = () => {
|
||||
window.location.href = 'tel:+918130521617';
|
||||
};
|
||||
|
||||
const handleBookNowClick = () => {
|
||||
setIsBookingModalOpen(true);
|
||||
setFormData({
|
||||
phone: '',
|
||||
email: '',
|
||||
age: '',
|
||||
roomType: 'deluxe',
|
||||
paymentMethod: 'online'
|
||||
});
|
||||
setSubmitMessage('');
|
||||
};
|
||||
|
||||
const handleFormChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleFormSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setSubmitMessage('');
|
||||
|
||||
try {
|
||||
const roomDetails = {
|
||||
'deluxe': { name: 'Deluxe Couple Room', price: '₹1,950/night' },
|
||||
'standard': { name: 'Standard AC Room', price: '₹1,450/night' },
|
||||
'premium': { name: 'Premium Comfort Room', price: '₹2,250/night' }
|
||||
};
|
||||
|
||||
const selectedRoom = roomDetails[formData.roomType as keyof typeof roomDetails];
|
||||
|
||||
const emailContent = `
|
||||
<h2>New Booking Request</h2>
|
||||
<p><strong>Phone:</strong> ${formData.phone}</p>
|
||||
<p><strong>Email:</strong> ${formData.email}</p>
|
||||
<p><strong>Age:</strong> ${formData.age}</p>
|
||||
<p><strong>Room Type:</strong> ${selectedRoom.name}</p>
|
||||
<p><strong>Room Price:</strong> ${selectedRoom.price}</p>
|
||||
<p><strong>Payment Method:</strong> ${formData.paymentMethod === 'online' ? 'Online Payment' : 'Pay at Counter'}</p>
|
||||
<p><strong>Booking Date:</strong> ${new Date().toLocaleString()}</p>
|
||||
`;
|
||||
|
||||
const response = await fetch('/api/send-booking-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
recipientEmail: 'contact@hotelshineinn.com',
|
||||
subject: 'New Booking Request - Hotel Shine Inn',
|
||||
htmlContent: emailContent,
|
||||
bookingData: formData,
|
||||
roomDetails: selectedRoom
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setSubmitMessage('✓ Booking request submitted successfully! We will contact you soon.');
|
||||
setFormData({
|
||||
phone: '',
|
||||
email: '',
|
||||
age: '',
|
||||
roomType: 'deluxe',
|
||||
paymentMethod: 'online'
|
||||
});
|
||||
setTimeout(() => {
|
||||
setIsBookingModalOpen(false);
|
||||
}, 2000);
|
||||
} else {
|
||||
setSubmitMessage('✗ Failed to submit booking. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
setSubmitMessage('✗ Error submitting booking. Please try again or call us directly.');
|
||||
console.error('Booking submission error:', error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="hover-magnetic"
|
||||
@@ -40,10 +134,151 @@ export default function LandingPage() {
|
||||
{ name: "Reviews", id: "reviews" },
|
||||
{ name: "Contact", id: "contact" }
|
||||
]}
|
||||
button={{ text: "Book Room", href: "#contact" }}
|
||||
button={{ text: "Book Now", onClick: handleBookNowClick }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Booking Modal */}
|
||||
{isBookingModalOpen && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-white rounded-lg shadow-lg max-w-md w-full max-h-[90vh] overflow-y-auto">
|
||||
<div className="sticky top-0 bg-white border-b border-gray-200 p-6 flex justify-between items-center">
|
||||
<h2 className="text-2xl font-bold text-gray-900">Book Your Room</h2>
|
||||
<button
|
||||
onClick={() => setIsBookingModalOpen(false)}
|
||||
className="text-gray-500 hover:text-gray-700 transition"
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleFormSubmit} className="p-6 space-y-4">
|
||||
{/* Phone Number */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Phone Number *
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleFormChange}
|
||||
placeholder="+91 XXXXX XXXXX"
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Email Address *
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleFormChange}
|
||||
placeholder="your.email@example.com"
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Age */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Age *
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
name="age"
|
||||
value={formData.age}
|
||||
onChange={handleFormChange}
|
||||
placeholder="Enter your age"
|
||||
min="18"
|
||||
max="120"
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Room Type */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Select Room Type *
|
||||
</label>
|
||||
<select
|
||||
name="roomType"
|
||||
value={formData.roomType}
|
||||
onChange={handleFormChange}
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||||
>
|
||||
<option value="deluxe">Deluxe Couple Room - ₹1,950/night</option>
|
||||
<option value="standard">Standard AC Room - ₹1,450/night</option>
|
||||
<option value="premium">Premium Comfort Room - ₹2,250/night</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Payment Method */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Payment Method *
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentMethod"
|
||||
value="online"
|
||||
checked={formData.paymentMethod === 'online'}
|
||||
onChange={handleFormChange}
|
||||
className="w-4 h-4 text-blue-600 border-gray-300 focus:ring-blue-500"
|
||||
/>
|
||||
<span className="ml-3 text-sm text-gray-700">Online Payment</span>
|
||||
</label>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentMethod"
|
||||
value="counter"
|
||||
checked={formData.paymentMethod === 'counter'}
|
||||
onChange={handleFormChange}
|
||||
className="w-4 h-4 text-blue-600 border-gray-300 focus:ring-blue-500"
|
||||
/>
|
||||
<span className="ml-3 text-sm text-gray-700">Pay at Counter</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Submit Message */}
|
||||
{submitMessage && (
|
||||
<div className={`p-3 rounded-lg text-sm ${
|
||||
submitMessage.includes('✓')
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
{submitMessage}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-semibold py-3 rounded-lg transition duration-200"
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Confirm Booking'}
|
||||
</button>
|
||||
|
||||
<p className="text-xs text-gray-500 text-center">
|
||||
By booking, you agree to our terms and conditions
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroBillboardDashboard
|
||||
background={{ variant: "radial-gradient" }}
|
||||
@@ -53,7 +288,7 @@ export default function LandingPage() {
|
||||
title="Hotel Shine Inn – Comfortable Couple-Friendly Stay in Rohini"
|
||||
description="Affordable, comfortable and private rooms near Rohini West Metro Station. Experience modern luxury with exceptional hospitality tailored for couples and travelers."
|
||||
buttons={[
|
||||
{ text: "Book Room", href: "#contact" },
|
||||
{ text: "Book Room", onClick: handleBookNowClick },
|
||||
{ text: "Call Now", onClick: handleCallNow }
|
||||
]}
|
||||
buttonAnimation="slide-up"
|
||||
@@ -139,15 +374,15 @@ export default function LandingPage() {
|
||||
products={[
|
||||
{
|
||||
id: "1", brand: "Hotel Shine Inn", name: "Deluxe Couple Room", price: "₹1,950/night", rating: 5,
|
||||
reviewCount: "156", imageSrc: "http://img.b2bpic.net/free-photo/weekend-photo-couple-playing-with-labrador-sunny-bedroom-guy-girl-are-stroking-belly-big-dog_197531-13742.jpg", imageAlt: "Deluxe Couple Room"
|
||||
reviewCount: "156", imageSrc: "http://img.b2bpic.net/free-photo/weekend-photo-couple-playing-with-labrador-sunny-bedroom-guy-girl-are-stroking-belly-big-dog_197531-13742.jpg", imageAlt: "Deluxe Couple Room", onProductClick: handleBookNowClick
|
||||
},
|
||||
{
|
||||
id: "2", brand: "Hotel Shine Inn", name: "Standard AC Room", price: "₹1,450/night", rating: 4,
|
||||
reviewCount: "203", imageSrc: "http://img.b2bpic.net/free-photo/bed-with-armchair_1203-741.jpg", imageAlt: "Standard AC Room"
|
||||
reviewCount: "203", imageSrc: "http://img.b2bpic.net/free-photo/bed-with-armchair_1203-741.jpg", imageAlt: "Standard AC Room", onProductClick: handleBookNowClick
|
||||
},
|
||||
{
|
||||
id: "3", brand: "Hotel Shine Inn", name: "Premium Comfort Room", price: "₹2,250/night", rating: 5,
|
||||
reviewCount: "98", imageSrc: "http://img.b2bpic.net/free-photo/modern-sauna-with-panoramic-windows-wooden-design_169016-70021.jpg", imageAlt: "Premium Comfort Room"
|
||||
reviewCount: "98", imageSrc: "http://img.b2bpic.net/free-photo/modern-sauna-with-panoramic-windows-wooden-design_169016-70021.jpg", imageAlt: "Premium Comfort Room", onProductClick: handleBookNowClick
|
||||
}
|
||||
]}
|
||||
textboxLayout="default"
|
||||
@@ -267,4 +502,4 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user