Merge version_7 into main #13
@@ -24,10 +24,10 @@ export default function ContactPage() {
|
||||
<NavbarStyleApple
|
||||
brandName="Rage Room Vienna"
|
||||
navItems={[
|
||||
{ name: "Packages", id: "/" },
|
||||
{ name: "Experience", id: "/" },
|
||||
{ name: "FAQ", id: "/" },
|
||||
{ name: "Contact", id: "/contact" },
|
||||
{ name: "Packages", id: "pricing" },
|
||||
{ name: "Experience", id: "about" },
|
||||
{ name: "FAQ", id: "faq" },
|
||||
{ name: "Contact", id: "contact" },
|
||||
]}
|
||||
/>
|
||||
</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 ContactCTA from '@/components/sections/contact/ContactCTA';
|
||||
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';
|
||||
|
||||
export default function LandingPage() {
|
||||
@@ -20,6 +20,9 @@ export default function LandingPage() {
|
||||
const [selectedDate, setSelectedDate] = useState('');
|
||||
const [selectedTime, setSelectedTime] = useState('');
|
||||
const [selectedAddOns, setSelectedAddOns] = useState<string[]>([]);
|
||||
const [name, setName] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [phone, setPhone] = useState('');
|
||||
const [bookedSlots, setBookedSlots] = useState<string[]>([
|
||||
'2025-01-16T17:00',
|
||||
'2025-01-16T19:00',
|
||||
@@ -52,6 +55,9 @@ export default function LandingPage() {
|
||||
setSelectedPackage(packageId);
|
||||
setGroupSize(1);
|
||||
setSelectedAddOns([]);
|
||||
setName('');
|
||||
setEmail('');
|
||||
setPhone('');
|
||||
setShowBookingModal(true);
|
||||
};
|
||||
|
||||
@@ -62,6 +68,9 @@ export default function LandingPage() {
|
||||
setSelectedDate('');
|
||||
setSelectedTime('');
|
||||
setSelectedAddOns([]);
|
||||
setName('');
|
||||
setEmail('');
|
||||
setPhone('');
|
||||
};
|
||||
|
||||
const handleAddOnChange = (addOnId: string) => {
|
||||
@@ -84,7 +93,7 @@ export default function LandingPage() {
|
||||
};
|
||||
|
||||
const handleBooking = async () => {
|
||||
if (selectedPackage && selectedDate && selectedTime) {
|
||||
if (selectedPackage && selectedDate && selectedTime && name && email) {
|
||||
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.`);
|
||||
return;
|
||||
@@ -105,6 +114,9 @@ export default function LandingPage() {
|
||||
const totalPrice = packageTotal + addOnsTotal;
|
||||
|
||||
const bookingData = {
|
||||
name,
|
||||
email,
|
||||
phone,
|
||||
package: selectedPackage,
|
||||
groupSize,
|
||||
date: selectedDate,
|
||||
@@ -118,7 +130,6 @@ export default function LandingPage() {
|
||||
};
|
||||
|
||||
try {
|
||||
// Save booking data to database
|
||||
const response = await fetch('/api/bookings', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -126,7 +137,6 @@ export default function LandingPage() {
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// Add to booked slots
|
||||
setBookedSlots([...bookedSlots, slotKey]);
|
||||
setLastBooking(bookingData);
|
||||
setShowSuccessPopup(true);
|
||||
@@ -136,7 +146,6 @@ export default function LandingPage() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Booking error:', error);
|
||||
// Still show success for demo purposes
|
||||
setBookedSlots([...bookedSlots, slotKey]);
|
||||
setLastBooking(bookingData);
|
||||
setShowSuccessPopup(true);
|
||||
@@ -154,22 +163,18 @@ export default function LandingPage() {
|
||||
const dayOfWeek = dateObj.getDay();
|
||||
const [hours] = time.split(':').map(Number);
|
||||
|
||||
// Monday (1) to Wednesday (3) - not bookable
|
||||
if (dayOfWeek >= 1 && dayOfWeek <= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thursday (4): 17:00-22:00
|
||||
if (dayOfWeek === 4) {
|
||||
return hours >= 17 && hours < 22;
|
||||
}
|
||||
|
||||
// Friday (5): 14:00-24:00
|
||||
if (dayOfWeek === 5) {
|
||||
return hours >= 14 && hours < 24;
|
||||
}
|
||||
|
||||
// Saturday (6) and Sunday (0): 12:00-24:00
|
||||
if (dayOfWeek === 6 || dayOfWeek === 0) {
|
||||
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}`));
|
||||
};
|
||||
|
||||
@@ -302,45 +306,62 @@ export default function LandingPage() {
|
||||
</div>
|
||||
|
||||
<div id="pricing" data-section="pricing">
|
||||
<PricingCardEight
|
||||
title="Choose Your Explosion"
|
||||
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!"
|
||||
tag="Pricing"
|
||||
tagIcon={Zap}
|
||||
tagAnimation="slide-up"
|
||||
plans={[
|
||||
{
|
||||
id: "basic", badge: "Beginner", badgeIcon: Flame,
|
||||
price: "€49", subtitle: "Perfect First Strike – 30 Minutes", buttons: [
|
||||
{ text: "Book Package", onClick: () => openBookingModal('basic') },
|
||||
],
|
||||
features: [
|
||||
"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)"
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "destroyer", badge: "Most Popular", badgeIcon: Sparkles,
|
||||
price: "€79", subtitle: "Best Value – 60 Minutes", buttons: [
|
||||
{ text: "Book Now", onClick: () => openBookingModal('destroyer') },
|
||||
],
|
||||
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: "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 className="w-full bg-background py-16 md:py-24">
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<div className="w-full max-w-6xl px-6 md:px-8">
|
||||
<div className="mb-12 bg-amber-50 border-l-4 border-amber-500 p-6 rounded-r-lg">
|
||||
<div className="flex items-start gap-4">
|
||||
<AlertCircle className="w-6 h-6 text-amber-600 flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<h3 className="text-xl font-bold text-amber-900 mb-2">💰 Group Discount Alert!</h3>
|
||||
<p className="text-amber-800 text-lg font-semibold">Book for 4+ people and get €40 per person – our best rate!</p>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PricingCardEight
|
||||
title="Choose Your Explosion"
|
||||
description="Three fury-fueled packages designed to match your rage level. All include protective gear, tools, and unlimited smashing."
|
||||
tag="Pricing"
|
||||
tagIcon={Zap}
|
||||
tagAnimation="slide-up"
|
||||
plans={[
|
||||
{
|
||||
id: "basic", badge: "Beginner", badgeIcon: Flame,
|
||||
price: "€49", subtitle: "Perfect First Strike – 30 Minutes", buttons: [
|
||||
{ text: "Book Package", onClick: () => openBookingModal('basic') },
|
||||
],
|
||||
features: [
|
||||
"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)"
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "destroyer", badge: "Most Popular", badgeIcon: Sparkles,
|
||||
price: "€79", subtitle: "Best Value – 60 Minutes", buttons: [
|
||||
{ text: "Book Now", onClick: () => openBookingModal('destroyer') },
|
||||
],
|
||||
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: "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 id="metrics" data-section="metrics">
|
||||
@@ -485,6 +506,39 @@ export default function LandingPage() {
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<label className="block text-sm font-medium mb-2">Package</label>
|
||||
<select
|
||||
@@ -595,7 +649,7 @@ export default function LandingPage() {
|
||||
|
||||
<button
|
||||
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"
|
||||
>
|
||||
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="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="capitalize">{lastBooking.package}</span>
|
||||
</div>
|
||||
@@ -650,7 +718,7 @@ export default function LandingPage() {
|
||||
</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
|
||||
onClick={() => setShowSuccessPopup(false)}
|
||||
|
||||
Reference in New Issue
Block a user