Newer section and modular view
All checks were successful
Deploy NPM app / Deploy NPM (push) Successful in 1m14s

This commit is contained in:
Ichitux
2026-04-14 15:48:44 +02:00
parent 7a65e7a1f4
commit 823ca68119
7 changed files with 264 additions and 21 deletions

View File

@@ -3,6 +3,7 @@ import { motion, AnimatePresence } from "framer-motion";
import { useState, useEffect } from "react";
import { ChevronUp } from "lucide-react";
import { useTranslation } from "react-i18next";
import { SECTIONS } from "@/data/event-data";
/** Botón flotante de reserva + scroll to top */
const FloatingButton = () => {
@@ -30,7 +31,7 @@ const FloatingButton = () => {
className="animate-pulse-glow rounded-full px-6 shadow-elevated"
asChild
>
<a href="#booking" className="inline-flex items-center gap-2">
<a href={SECTIONS.booking ? "#booking" : "#mixed-booking"} className="inline-flex items-center gap-2">
{/* Inline SVG: dancing couple icon */}
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
import { useTranslation } from "react-i18next";
import { EVENT_INFO } from "@/data/event-data";
import { EVENT_INFO, SECTIONS } from "@/data/event-data";
import heroBg from "@/assets/hero-bg.jpg";
/** Calcula diferencia entre ahora y la fecha del evento */
@@ -116,7 +116,7 @@ const HeroSection = () => {
transition={{ delay: 1 }}
>
<Button variant="hero" size="lg" className="text-lg px-10 py-6" asChild>
<a href="#booking">{t('hero.bookYourPass')}</a>
<a href={SECTIONS.booking ? "#booking" : "#mixed-booking"}>{t('hero.bookYourPass')}</a>
</Button>
</motion.div>
</div>

View File

@@ -0,0 +1,145 @@
import { useState } from "react";
import { motion } from "framer-motion";
import { MIXED_BOOKING_PACKAGES, ROOM_TYPES } from "@/data/event-data";
import type { RoomType } from "@/data/event-data";
import { useTranslation } from "react-i18next";
import { Check, Star } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Label } from "@/components/ui/label";
const FEATURED_PASS = "full";
const MixedBookingSection = () => {
const { t } = useTranslation();
const [selectedRooms, setSelectedRooms] = useState<Record<string, RoomType>>({
full: "individual",
party: "individual",
single: "individual",
});
return (
<section
id="mixed-booking"
className="section-padding bg-background scroll-mt-24 relative z-10 -mt-[40px] pt-[120px]"
style={{ borderRadius: "0 100% 0 0 / 0 120px 0 0" }}
>
<div className="container mx-auto">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, amount: 0.15 }}
className="text-center mb-12"
>
<h2 className="font-display text-4xl md:text-5xl lg:text-7xl break-words font-bold pt-4 pb-10 leading-[1.8] text-gradient">
{t("mixedBooking.title")}
</h2>
<p className="text-muted-foreground max-w-2xl mx-auto">{t("mixedBooking.subtitle")}</p>
</motion.div>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto items-stretch">
{MIXED_BOOKING_PACKAGES.map((pkg, i) => {
const selectedRoom = selectedRooms[pkg.id] || "individual";
const price = pkg.roomPrices[selectedRoom];
const isFeatured = pkg.id === FEATURED_PASS;
const features = t(`mixedBooking.${pkg.id}Features`).split("|").map((f: string) => f.trim());
return (
<motion.div
key={pkg.id}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, amount: 0.15 }}
transition={{ delay: i * 0.1 }}
className={`relative flex h-full min-h-[520px] flex-col rounded-2xl overflow-hidden transition-shadow duration-300 ${
isFeatured
? "shadow-elevated border-2 border-primary/30"
: "shadow-card hover:shadow-elevated border border-border"
}`}
>
{isFeatured && (
<div className="absolute top-4 right-4 z-10">
<span className="inline-flex items-center gap-1 bg-gradient-tropical text-primary-foreground text-xs font-bold px-3 py-1 rounded-full shadow-md">
<Star className="w-3 h-3 fill-current" />
{t("mixedBooking.popular")}
</span>
</div>
)}
<div className={`px-6 pt-8 pb-4 text-center min-h-[160px] flex flex-col justify-between ${
isFeatured ? "bg-gradient-tropical" : "bg-secondary/10"
}`}>
<div>
<h3 className={`font-display text-2xl md:text-3xl font-bold mb-1 ${
isFeatured ? "text-primary-foreground" : "text-foreground"
}`}>
{t(`mixedBooking.passTypes.${pkg.id}`)}
</h3>
<p className={`text-sm ${
isFeatured ? "text-primary-foreground/80" : "text-muted-foreground"
}`}>
{t(`mixedBooking.${pkg.id}Description`)}
</p>
</div>
</div>
<div className="px-6 pt-6 pb-4 text-center bg-card">
<p className="text-4xl md:text-5xl font-bold text-primary">
{price > 0 ? `${price}` : t("mixedBooking.priceTBD")}
</p>
<p className="text-xs text-muted-foreground mt-1">
{t("mixedBooking.perPerson")}
</p>
</div>
<div className="px-6 pt-4 pb-2 bg-card">
<Label className="block text-sm font-medium text-foreground mb-2">
{t("mixedBooking.selectRoom")}
</Label>
<Select
value={selectedRoom}
onValueChange={(value) =>
setSelectedRooms((prev) => ({
...prev,
[pkg.id]: value as RoomType,
}))
}
>
<SelectTrigger className={`w-full rounded-xl border px-4 py-3 text-sm text-foreground shadow-sm transition-colors duration-200 ${
isFeatured
? "border-primary/30 bg-primary/5 hover:border-primary/50"
: "border-input bg-background hover:border-primary/30"
}`}>
<SelectValue placeholder={t("mixedBooking.selectRoom")} />
</SelectTrigger>
<SelectContent>
{ROOM_TYPES.map((room) => (
<SelectItem key={room.id} value={room.id}>
{t(`mixedBooking.roomTypes.${room.id}`)}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="px-6 pt-4 pb-6 flex-1 flex flex-col justify-between bg-card">
<ul className="space-y-2.5 mb-6">
{features.map((feature: string, idx: number) => (
<li key={idx} className="flex items-start gap-2.5 text-sm text-foreground/80">
<Check className={`w-4 h-4 mt-0.5 flex-shrink-0 ${
isFeatured ? "text-primary" : "text-secondary"
}`} />
<span>{feature}</span>
</li>
))}
</ul>
</div>
</motion.div>
);
})}
</div>
</div>
</section>
);
};
export default MixedBookingSection;