diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml
index c5e94da..cb53dc7 100644
--- a/.gitea/workflows/deploy.yaml
+++ b/.gitea/workflows/deploy.yaml
@@ -1,9 +1,9 @@
-name: Deploy NPM app
+name: Deploy Docker container
run-name: ${{ gitea.actor }} is deploying to PROD servers.
on: [ push, fork, pull ]
jobs:
- Deploy NPM:
+ Deploy:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
@@ -18,7 +18,7 @@ jobs:
script: |
cd /home/zouklambadabcn.com/public_html/
git pull
- npm install
- npm run build
- pm2 restart ZLB
+ docker compose down
+ docker compose up -d --build
+ docker image prune -f
- run: echo "🍏 This job's status is ${{ job.status }}."
diff --git a/src/components/MixedBookingSection.tsx b/src/components/MixedBookingSection.tsx
index 3801fe7..931600d 100644
--- a/src/components/MixedBookingSection.tsx
+++ b/src/components/MixedBookingSection.tsx
@@ -3,7 +3,7 @@ import { motion } from "framer-motion";
import { MIXED_BOOKING_PACKAGES, ROOM_TYPES, getFullPassPrice } from "@/data/event-data";
import type { RoomType } from "@/data/event-data";
import { useTranslation } from "react-i18next";
-import { Check, Star, Circle, CheckCircle2, ExternalLink } from "lucide-react";
+import { Check, Star, Circle, CheckCircle2, ExternalLink, MapPin, Calendar, Clock, Navigation } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
@@ -11,6 +11,7 @@ import { Button } from "@/components/ui/button";
const FEATURED_PASS = "full";
const NON_HOTEL_FEE = 50;
const PARTY_PRICE = 25;
+const GOOGLE_MAPS_URL = "https://www.google.com/maps/search/Sala+Vivaldi+Barcelona";
const MixedBookingSection = () => {
const { t } = useTranslation();
@@ -43,23 +44,21 @@ const MixedBookingSection = () => {
{t("mixedBooking.subtitle")}
-
- {MIXED_BOOKING_PACKAGES.map((pkg, i) => {
+
+ {MIXED_BOOKING_PACKAGES.filter(pkg => pkg.id !== "whiteparty").map((pkg, i) => {
const selectedRoom = selectedRooms[pkg.id] || "individual";
const hasHotel = wantsHotel[pkg.id] === true;
- // Use dynamic pricing for Full Pass, fixed price for Party Pass
- // Only Full Pass has the +50€ non-hotel fee
let basePrice = pkg.id === "full" ? fullPassPricing.price : PARTY_PRICE;
let roomPrice = 0;
if (hasHotel) {
roomPrice = pkg.roomPrices[selectedRoom as keyof typeof pkg.roomPrices];
}
-
+
const passPrice = pkg.id === "full"
? (hasHotel ? basePrice : basePrice + NON_HOTEL_FEE)
: basePrice;
const price = passPrice + roomPrice;
-
+
const isFeatured = pkg.id === FEATURED_PASS;
const isLastPrice = pkg.id === "full" && fullPassPricing.isLastPrice;
const showNonHotelNote = pkg.id === "full" && !hasHotel && basePrice > 0;
@@ -233,6 +232,96 @@ const MixedBookingSection = () => {
);
})}
+
+ {/* White Party Special Card */}
+
+ {/* Tropical beach background */}
+
+
+
+ {/* Content overlay */}
+
+ {/* Header */}
+
+
+
+
+ WHITE PARTY
+
+
+ {t("mixedBooking.whitepartyDescription")}
+
+
+
+
+ {/* Event details */}
+
+
+
+
+ {t("mixedBooking.whitepartyDate")}
+
+
+
+ {t("mixedBooking.whitepartyTime")}
+
+
+
+
+ Sala Vivaldi
+ C/Llança, 5
+
+
+
+
+ {/* Warning */}
+
+
+ {t("mixedBooking.whitepartyNotIncluded")}
+
+
+
+
+ {/* Features */}
+
+
+ {t("mixedBooking.whitepartyFeatures").split("|").map((feature: string, idx: number) => (
+ -
+
+ {feature.trim()}
+
+ ))}
+
+
+
+ {/* Google Maps Button */}
+
+
+
diff --git a/src/data/event-data.ts b/src/data/event-data.ts
index 0856c1d..7cfa8b4 100644
--- a/src/data/event-data.ts
+++ b/src/data/event-data.ts
@@ -280,7 +280,7 @@ export const GALLERY_IMAGES = [
// ---- PAQUETES MIXTOS (Room + Pass) ----
export type RoomType = "individual" | "double" | "suite";
-export type PassType = "full" | "party";
+export type PassType = "full" | "party" | "whiteparty";
export const ROOM_TYPES: { id: RoomType }[] = [
{ id: "individual" },
@@ -314,6 +314,7 @@ export function getFullPassPrice(): { price: number; isLastPrice: boolean; valid
export const MIXED_BOOKING_PACKAGES = [
{ id: "full" as PassType, label: "full", roomPrices: { individual: 100, double: 150, suite: 213 } },
{ id: "party" as PassType, label: "party", roomPrices: { individual: 100, double: 150, suite: 213 } },
+ { id: "whiteparty" as PassType, label: "whiteparty", roomPrices: { individual: 0, double: 0, suite: 0 } },
];
// ---- SECCIONES VISIBLES ----
diff --git a/src/locales/en.json b/src/locales/en.json
index 729bc60..45a20ea 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -147,13 +147,20 @@
},
"passTypes": {
"full": "Full Pass",
- "party": "Party Pass"
+ "party": "Party Pass",
+ "whiteparty": "White Party"
},
"fullDescription": "Full access to all workshops, socials, and festival activities",
"fullFeatures": "All workshops|All social dances|Live shows|DJ sets",
"partyDescription": "Price for each party individually, even pool parties.",
"partyFeatures": "Friday party|Saturday party|Sunday farewell party|DJ sets",
- "goToReservations": "Go to reservations"
+ "whitepartyDescription": "Closing party in Sala Vivaldi, with an elegant and exclusive atmosphere.",
+ "whitepartyFeatures": "Dress code: White|Amazing DJ",
+ "whitepartyNotIncluded": "Not included in Full Pass - Separate payment required",
+ "whitepartyTime": "21h to 1h",
+ "whitepartyDate": "Monday 7 September",
+ "goToReservations": "Go to reservations",
+ "viewOnMap": "View on Google Maps"
},
"info": {
"title": "Practical Information",
diff --git a/src/locales/es.json b/src/locales/es.json
index 267e1a8..4e32466 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -147,13 +147,20 @@
},
"passTypes": {
"full": "Full Pass",
- "party": "Party Pass"
+ "party": "Party Pass",
+ "whiteparty": "White Party"
},
"fullDescription": "Acceso completo a todos los workshops, sociales y actividades del festival",
"fullFeatures": "Todos los workshops|Todas las social dances|Shows en vivo|DJ sets",
"partyDescription": "Precio individual por cada fiesta, incluso las pool parties.",
"partyFeatures": "Fiesta del viernes|Fiesta del sábado|Fiesta despedida del domingo|DJ sets",
- "goToReservations": "Ir a reservas"
+ "whitepartyDescription": "Fiesta de clausura en la Sala Vivaldi, con un ambiente elegante y exclusivo.",
+ "whitepartyFeatures": "Código de vestimenta: Blanco|DJ Inigualable",
+ "whitepartyNotIncluded": "No incluido en Full Pass - Pago separado requerido",
+ "whitepartyTime": "21h a 1h",
+ "whitepartyDate": "Lunes 7 de Septiembre",
+ "goToReservations": "Ir a reservas",
+ "viewOnMap": "Ver en Google Maps"
},
"info": {
"title": "Información Práctica",