Merge version_7 into main #13

Merged
bender merged 2 commits from version_7 into main 2026-03-05 23:00:06 +00:00
2 changed files with 123 additions and 55 deletions

View File

@@ -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>

View File

@@ -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)}