Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab0327e6e2 | |||
| 6bbdc7e9de | |||
| 94a2704229 | |||
| dc4788879a |
88
src/app/api/send-booking-email/route.ts
Normal file
88
src/app/api/send-booking-email/route.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
const transporter = {
|
||||||
|
sendMail: async (mailOptions: { from?: string; to: string; subject: string; html: string }) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('https://api.resend.com/emails', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${process.env.RESEND_API_KEY}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
from: mailOptions.from || process.env.HOTEL_EMAIL,
|
||||||
|
to: mailOptions.to,
|
||||||
|
subject: mailOptions.subject,
|
||||||
|
html: mailOptions.html,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to send email');
|
||||||
|
}
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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 TestimonialCardTen from '@/components/sections/testimonial/TestimonialCardTen';
|
||||||
import ContactFaq from '@/components/sections/contact/ContactFaq';
|
import ContactFaq from '@/components/sections/contact/ContactFaq';
|
||||||
import FooterLogoEmphasis from '@/components/sections/footer/FooterLogoEmphasis';
|
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() {
|
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 = () => {
|
const handleCallNow = () => {
|
||||||
window.location.href = 'tel:+918130521617';
|
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 (
|
return (
|
||||||
<ThemeProvider
|
<ThemeProvider
|
||||||
defaultButtonVariant="hover-magnetic"
|
defaultButtonVariant="hover-magnetic"
|
||||||
@@ -40,10 +134,151 @@ export default function LandingPage() {
|
|||||||
{ name: "Reviews", id: "reviews" },
|
{ name: "Reviews", id: "reviews" },
|
||||||
{ name: "Contact", id: "contact" }
|
{ name: "Contact", id: "contact" }
|
||||||
]}
|
]}
|
||||||
button={{ text: "Book Room", href: "#contact" }}
|
button={{ text: "Book Now", onClick: handleBookNowClick }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<div id="hero" data-section="hero">
|
||||||
<HeroBillboardDashboard
|
<HeroBillboardDashboard
|
||||||
background={{ variant: "radial-gradient" }}
|
background={{ variant: "radial-gradient" }}
|
||||||
@@ -53,7 +288,7 @@ export default function LandingPage() {
|
|||||||
title="Hotel Shine Inn – Comfortable Couple-Friendly Stay in Rohini"
|
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."
|
description="Affordable, comfortable and private rooms near Rohini West Metro Station. Experience modern luxury with exceptional hospitality tailored for couples and travelers."
|
||||||
buttons={[
|
buttons={[
|
||||||
{ text: "Book Room", href: "#contact" },
|
{ text: "Book Room", onClick: handleBookNowClick },
|
||||||
{ text: "Call Now", onClick: handleCallNow }
|
{ text: "Call Now", onClick: handleCallNow }
|
||||||
]}
|
]}
|
||||||
buttonAnimation="slide-up"
|
buttonAnimation="slide-up"
|
||||||
@@ -139,15 +374,15 @@ export default function LandingPage() {
|
|||||||
products={[
|
products={[
|
||||||
{
|
{
|
||||||
id: "1", brand: "Hotel Shine Inn", name: "Deluxe Couple Room", price: "₹1,950/night", rating: 5,
|
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,
|
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,
|
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"
|
textboxLayout="default"
|
||||||
@@ -267,4 +502,4 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user