Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89bcb4aa00 | |||
| f816ce0398 | |||
| a2dda1e1fa |
@@ -24,10 +24,10 @@ export default function ContactPage() {
|
|||||||
<NavbarStyleApple
|
<NavbarStyleApple
|
||||||
brandName="Rage Room Vienna"
|
brandName="Rage Room Vienna"
|
||||||
navItems={[
|
navItems={[
|
||||||
{ name: "Packages", id: "/" },
|
{ name: "Packages", id: "pricing" },
|
||||||
{ name: "Experience", id: "/" },
|
{ name: "Experience", id: "about" },
|
||||||
{ name: "FAQ", id: "/" },
|
{ name: "FAQ", id: "faq" },
|
||||||
{ name: "Contact", id: "/contact" },
|
{ name: "Contact", id: "contact" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
170
src/app/page.tsx
170
src/app/page.tsx
@@ -9,7 +9,7 @@ import MetricCardThree from '@/components/sections/metrics/MetricCardThree';
|
|||||||
import FaqSplitText from '@/components/sections/faq/FaqSplitText';
|
import FaqSplitText from '@/components/sections/faq/FaqSplitText';
|
||||||
import ContactCTA from '@/components/sections/contact/ContactCTA';
|
import ContactCTA from '@/components/sections/contact/ContactCTA';
|
||||||
import FooterMedia from '@/components/sections/footer/FooterMedia';
|
import FooterMedia from '@/components/sections/footer/FooterMedia';
|
||||||
import { Zap, Flame, Sparkles, Crown, Users, Star, Clock, TrendingUp, Mail, Calendar, X, CheckCircle } from 'lucide-react';
|
import { Zap, Flame, Sparkles, Crown, Users, Star, Clock, TrendingUp, Mail, Calendar, X, CheckCircle, AlertCircle } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
export default function LandingPage() {
|
export default function LandingPage() {
|
||||||
@@ -20,6 +20,9 @@ export default function LandingPage() {
|
|||||||
const [selectedDate, setSelectedDate] = useState('');
|
const [selectedDate, setSelectedDate] = useState('');
|
||||||
const [selectedTime, setSelectedTime] = useState('');
|
const [selectedTime, setSelectedTime] = useState('');
|
||||||
const [selectedAddOns, setSelectedAddOns] = useState<string[]>([]);
|
const [selectedAddOns, setSelectedAddOns] = useState<string[]>([]);
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [phone, setPhone] = useState('');
|
||||||
const [bookedSlots, setBookedSlots] = useState<string[]>([
|
const [bookedSlots, setBookedSlots] = useState<string[]>([
|
||||||
'2025-01-16T17:00',
|
'2025-01-16T17:00',
|
||||||
'2025-01-16T19:00',
|
'2025-01-16T19:00',
|
||||||
@@ -52,6 +55,9 @@ export default function LandingPage() {
|
|||||||
setSelectedPackage(packageId);
|
setSelectedPackage(packageId);
|
||||||
setGroupSize(1);
|
setGroupSize(1);
|
||||||
setSelectedAddOns([]);
|
setSelectedAddOns([]);
|
||||||
|
setName('');
|
||||||
|
setEmail('');
|
||||||
|
setPhone('');
|
||||||
setShowBookingModal(true);
|
setShowBookingModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,6 +68,9 @@ export default function LandingPage() {
|
|||||||
setSelectedDate('');
|
setSelectedDate('');
|
||||||
setSelectedTime('');
|
setSelectedTime('');
|
||||||
setSelectedAddOns([]);
|
setSelectedAddOns([]);
|
||||||
|
setName('');
|
||||||
|
setEmail('');
|
||||||
|
setPhone('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddOnChange = (addOnId: string) => {
|
const handleAddOnChange = (addOnId: string) => {
|
||||||
@@ -84,7 +93,7 @@ export default function LandingPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleBooking = async () => {
|
const handleBooking = async () => {
|
||||||
if (selectedPackage && selectedDate && selectedTime) {
|
if (selectedPackage && selectedDate && selectedTime && name && email) {
|
||||||
if (groupSize > 4) {
|
if (groupSize > 4) {
|
||||||
alert(`Group size exceeds maximum of 4 people. Please contact us for custom group bookings at bookings@rageroomvienna.local or call our team.`);
|
alert(`Group size exceeds maximum of 4 people. Please contact us for custom group bookings at bookings@rageroomvienna.local or call our team.`);
|
||||||
return;
|
return;
|
||||||
@@ -105,6 +114,9 @@ export default function LandingPage() {
|
|||||||
const totalPrice = packageTotal + addOnsTotal;
|
const totalPrice = packageTotal + addOnsTotal;
|
||||||
|
|
||||||
const bookingData = {
|
const bookingData = {
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
phone,
|
||||||
package: selectedPackage,
|
package: selectedPackage,
|
||||||
groupSize,
|
groupSize,
|
||||||
date: selectedDate,
|
date: selectedDate,
|
||||||
@@ -118,7 +130,6 @@ export default function LandingPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Save booking data to database
|
|
||||||
const response = await fetch('/api/bookings', {
|
const response = await fetch('/api/bookings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@@ -126,7 +137,6 @@ export default function LandingPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// Add to booked slots
|
|
||||||
setBookedSlots([...bookedSlots, slotKey]);
|
setBookedSlots([...bookedSlots, slotKey]);
|
||||||
setLastBooking(bookingData);
|
setLastBooking(bookingData);
|
||||||
setShowSuccessPopup(true);
|
setShowSuccessPopup(true);
|
||||||
@@ -136,7 +146,6 @@ export default function LandingPage() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Booking error:', error);
|
console.error('Booking error:', error);
|
||||||
// Still show success for demo purposes
|
|
||||||
setBookedSlots([...bookedSlots, slotKey]);
|
setBookedSlots([...bookedSlots, slotKey]);
|
||||||
setLastBooking(bookingData);
|
setLastBooking(bookingData);
|
||||||
setShowSuccessPopup(true);
|
setShowSuccessPopup(true);
|
||||||
@@ -154,22 +163,18 @@ export default function LandingPage() {
|
|||||||
const dayOfWeek = dateObj.getDay();
|
const dayOfWeek = dateObj.getDay();
|
||||||
const [hours] = time.split(':').map(Number);
|
const [hours] = time.split(':').map(Number);
|
||||||
|
|
||||||
// Monday (1) to Wednesday (3) - not bookable
|
|
||||||
if (dayOfWeek >= 1 && dayOfWeek <= 3) {
|
if (dayOfWeek >= 1 && dayOfWeek <= 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thursday (4): 17:00-22:00
|
|
||||||
if (dayOfWeek === 4) {
|
if (dayOfWeek === 4) {
|
||||||
return hours >= 17 && hours < 22;
|
return hours >= 17 && hours < 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Friday (5): 14:00-24:00
|
|
||||||
if (dayOfWeek === 5) {
|
if (dayOfWeek === 5) {
|
||||||
return hours >= 14 && hours < 24;
|
return hours >= 14 && hours < 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saturday (6) and Sunday (0): 12:00-24:00
|
|
||||||
if (dayOfWeek === 6 || dayOfWeek === 0) {
|
if (dayOfWeek === 6 || dayOfWeek === 0) {
|
||||||
return hours >= 12 && hours < 24;
|
return hours >= 12 && hours < 24;
|
||||||
}
|
}
|
||||||
@@ -205,7 +210,6 @@ export default function LandingPage() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out booked slots
|
|
||||||
return availableTimes.filter(time => !bookedSlots.includes(`${date}T${time}`));
|
return availableTimes.filter(time => !bookedSlots.includes(`${date}T${time}`));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,45 +306,62 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="pricing" data-section="pricing">
|
<div id="pricing" data-section="pricing">
|
||||||
<PricingCardEight
|
<div className="w-full bg-background py-16 md:py-24">
|
||||||
title="Choose Your Explosion"
|
<div className="flex items-center justify-center w-full">
|
||||||
description="Three fury-fueled packages designed to match your rage level. All include protective gear, tools, and unlimited smashing. Groups of 4+ get special pricing: €40/person maximum!"
|
<div className="w-full max-w-6xl px-6 md:px-8">
|
||||||
tag="Pricing"
|
<div className="mb-12 bg-amber-50 border-l-4 border-amber-500 p-6 rounded-r-lg">
|
||||||
tagIcon={Zap}
|
<div className="flex items-start gap-4">
|
||||||
tagAnimation="slide-up"
|
<AlertCircle className="w-6 h-6 text-amber-600 flex-shrink-0 mt-0.5" />
|
||||||
plans={[
|
<div>
|
||||||
{
|
<h3 className="text-xl font-bold text-amber-900 mb-2">💰 Group Discount Alert!</h3>
|
||||||
id: "basic", badge: "Beginner", badgeIcon: Flame,
|
<p className="text-amber-800 text-lg font-semibold">Book for 4+ people and get €40 per person – our best rate!</p>
|
||||||
price: "€49", subtitle: "Perfect First Strike – 30 Minutes", buttons: [
|
<p className="text-amber-700 text-sm mt-1">Save up to 49% on individual pricing. Perfect for team building, celebrations, and group events.</p>
|
||||||
{ text: "Book Package", onClick: () => openBookingModal('basic') },
|
</div>
|
||||||
],
|
</div>
|
||||||
features: [
|
</div>
|
||||||
"30 minutes of pure destruction", "All safety gear included", "Glass and ceramics", "Solo or duo session", "Perfect for first-timers", "Group price: €40/person (max 4 people)"
|
|
||||||
],
|
<PricingCardEight
|
||||||
},
|
title="Choose Your Explosion"
|
||||||
{
|
description="Three fury-fueled packages designed to match your rage level. All include protective gear, tools, and unlimited smashing."
|
||||||
id: "destroyer", badge: "Most Popular", badgeIcon: Sparkles,
|
tag="Pricing"
|
||||||
price: "€79", subtitle: "Best Value – 60 Minutes", buttons: [
|
tagIcon={Zap}
|
||||||
{ text: "Book Now", onClick: () => openBookingModal('destroyer') },
|
tagAnimation="slide-up"
|
||||||
],
|
plans={[
|
||||||
features: [
|
{
|
||||||
"60 minutes of maximum chaos", "Premium safety equipment", "Glass, ceramics & electronics", "Doubles or small group", "Most items to smash", "Best value experience", "Group price: €40/person (max 4 people)"
|
id: "basic", badge: "Beginner", badgeIcon: Flame,
|
||||||
],
|
price: "€49", subtitle: "Perfect First Strike – 30 Minutes", buttons: [
|
||||||
},
|
{ text: "Book Package", onClick: () => openBookingModal('basic') },
|
||||||
{
|
],
|
||||||
id: "elite", badge: "Ultimate", badgeIcon: Crown,
|
features: [
|
||||||
price: "€129", subtitle: "Total Annihilation – 90 Minutes", buttons: [
|
"30 minutes of pure destruction", "All safety gear included", "Glass and ceramics", "Solo or duo session", "Perfect for first-timers", "Group price: €40/person (max 4 people)"
|
||||||
{ text: "Reserve Elite", onClick: () => openBookingModal('elite') },
|
],
|
||||||
],
|
},
|
||||||
features: [
|
{
|
||||||
"90 minutes unlimited destruction", "VIP treatment & priorities", "All destruction categories", "Small group packages", "Premium room setup", "Professional photos included", "Group price: €40/person (max 4 people)"
|
id: "destroyer", badge: "Most Popular", badgeIcon: Sparkles,
|
||||||
],
|
price: "€79", subtitle: "Best Value – 60 Minutes", buttons: [
|
||||||
},
|
{ text: "Book Now", onClick: () => openBookingModal('destroyer') },
|
||||||
]}
|
],
|
||||||
animationType="slide-up"
|
features: [
|
||||||
textboxLayout="default"
|
"60 minutes of maximum chaos", "Premium safety equipment", "Glass, ceramics & electronics", "Doubles or small group", "Most items to smash", "Best value experience", "Group price: €40/person (max 4 people)"
|
||||||
useInvertedBackground={false}
|
],
|
||||||
/>
|
},
|
||||||
|
{
|
||||||
|
id: "elite", badge: "Ultimate", badgeIcon: Crown,
|
||||||
|
price: "€129", subtitle: "Total Annihilation – 90 Minutes", buttons: [
|
||||||
|
{ text: "Reserve Elite", onClick: () => openBookingModal('elite') },
|
||||||
|
],
|
||||||
|
features: [
|
||||||
|
"90 minutes unlimited destruction", "VIP treatment & priorities", "All destruction categories", "Small group packages", "Premium room setup", "Professional photos included", "Group price: €40/person (max 4 people)"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
animationType="slide-up"
|
||||||
|
textboxLayout="default"
|
||||||
|
useInvertedBackground={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="metrics" data-section="metrics">
|
<div id="metrics" data-section="metrics">
|
||||||
@@ -485,6 +506,39 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-6 space-y-6">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-2">Name *</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
placeholder="Your full name"
|
||||||
|
className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-2">Email *</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
placeholder="your@email.com"
|
||||||
|
className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-2">Phone Number (Optional)</label>
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
value={phone}
|
||||||
|
onChange={(e) => setPhone(e.target.value)}
|
||||||
|
placeholder="+43 1 234 56789"
|
||||||
|
className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium mb-2">Package</label>
|
<label className="block text-sm font-medium mb-2">Package</label>
|
||||||
<select
|
<select
|
||||||
@@ -595,7 +649,7 @@ export default function LandingPage() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleBooking}
|
onClick={handleBooking}
|
||||||
disabled={!selectedPackage || !selectedDate || !selectedTime || groupSize > 4}
|
disabled={!selectedPackage || !selectedDate || !selectedTime || groupSize > 4 || !name || !email}
|
||||||
className="w-full bg-blue-600 text-white py-3 rounded-lg font-semibold hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
|
className="w-full bg-blue-600 text-white py-3 rounded-lg font-semibold hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Confirm Booking
|
Confirm Booking
|
||||||
@@ -618,6 +672,20 @@ export default function LandingPage() {
|
|||||||
|
|
||||||
<div className="bg-gray-50 rounded-lg p-4 text-left space-y-2 mb-6">
|
<div className="bg-gray-50 rounded-lg p-4 text-left space-y-2 mb-6">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
|
<span className="font-medium">Name:</span>
|
||||||
|
<span>{lastBooking.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="font-medium">Email:</span>
|
||||||
|
<span>{lastBooking.email}</span>
|
||||||
|
</div>
|
||||||
|
{lastBooking.phone && (
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="font-medium">Phone:</span>
|
||||||
|
<span>{lastBooking.phone}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex justify-between border-t pt-2 mt-2">
|
||||||
<span className="font-medium">Package:</span>
|
<span className="font-medium">Package:</span>
|
||||||
<span className="capitalize">{lastBooking.package}</span>
|
<span className="capitalize">{lastBooking.package}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -650,7 +718,7 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-gray-600 mb-6">A confirmation email has been sent to your registered email address. Get ready to destroy!</p>
|
<p className="text-sm text-gray-600 mb-6">A confirmation email has been sent to {lastBooking.email}. Get ready to destroy!</p>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowSuccessPopup(false)}
|
onClick={() => setShowSuccessPopup(false)}
|
||||||
|
|||||||
Reference in New Issue
Block a user