3 Commits

Author SHA1 Message Date
89bcb4aa00 Update src/app/page.tsx 2026-03-05 23:00:01 +00:00
f816ce0398 Update src/app/contact/page.tsx 2026-03-05 23:00:00 +00:00
a2dda1e1fa Merge version_6 into main
Merge version_6 into main
2026-03-05 22:54:47 +00:00
2 changed files with 123 additions and 55 deletions

View File

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

View File

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