// Nueva versión ampliada del proyecto inspirada en planning.wedding
// Incluye más módulos: crear sitio completo, cronograma, presupuesto, checklist, galería,
// secciones personalizadas, RSVPs avanzados, mesas, alojamiento, transporte, módulo de regalos, etc.
// --- NOTA ---
// Este es un front-end unificado en un solo archivo para demostración. En producción debe dividirse por componentes.
import React, { useState, useEffect, useRef } from "react";
import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet";
import L from "leaflet";
import html2canvas from "html2canvas";
import "leaflet/dist/leaflet.css";
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});
// =============================
// Utilidad LocalStorage
// =============================
function useLocalStorage(key, initialValue) {
const [state, setState] = useState(() => {
try {
const v = localStorage.getItem(key);
return v ? JSON.parse(v) : initialValue;
} catch (e) { return initialValue; }
});
useEffect(() => {
try { localStorage.setItem(key, JSON.stringify(state)); } catch {}
}, [key, state]);
return [state, setState];
}
// =============================
// Constructor de Mapa
// =============================
function MapBuilder({ markers, setMarkers, center=[14.6349,-90.5068], zoom=13 }) {
function AddMarkerOnClick() {
useMapEvents({ click(e) {
const { lat, lng } = e.latlng;
const label = prompt("Nombre del punto");
if(label) setMarkers(m => [...m, { id: Date.now(), label, lat, lng }]);
}});
return null;
}
return (
{markers.map(m => (
{m.label}
))}
);
}
// =============================
// Componente principal
// =============================
export default function EventPage() {
// ---------------- Datos principales del evento ----------------
const [event, setEvent] = useLocalStorage("event_data", {
title: "Nuestra Boda",
subtitle: "Bienvenidos a nuestro sitio oficial",
date: "2026-06-12",
time: "16:00",
locationName: "Hacienda La Esperanza",
description: "Acompáñanos a celebrar este día tan especial.",
heroImage: null,
themeColor: "pink-600",
});
// ---------------- Módulos adicionales ----------------
const [markers, setMarkers] = useLocalStorage("event_markers", []);
const [guests, setGuests] = useLocalStorage("event_guests", []);
const [checklist, setChecklist] = useLocalStorage("event_checklist", []);
const [timeline, setTimeline] = useLocalStorage("event_timeline", []);
const [budget, setBudget] = useLocalStorage("event_budget", []);
const [gallery, setGallery] = useLocalStorage("event_gallery", []);
const [lodging, setLodging] = useLocalStorage("event_lodging", []);
const [transport, setTransport] = useLocalStorage("event_transport", []);
const [gifts, setGifts] = useLocalStorage("event_gifts", []);
const [adminMode, setAdminMode] = useState(false);
const inviteRef = useRef(null);
// =============================
// Funciones
// =============================
// Invitación PNG
function downloadInvitation() {
if(!inviteRef.current) return;
html2canvas(inviteRef.current, { scale: 2 }).then(canvas => {
const a = document.createElement("a");
a.download = "invitacion.png";
a.href = canvas.toDataURL();
a.click();
});
}
// Añadir elementos genéricos
function addItemTo(setter, list, item) {
setter([...list, { id: Date.now(), ...item }]);
}
function removeItemFrom(setter, list, id) {
setter(list.filter(x => x.id !== id));
}
// =============================
// UI
// =============================
return (
{/* Header */}
{event.title}
{/* Hero */}
{/* Mapa */}
{/* Invitación */}
Invitación virtual
{event.title}
{event.date} — {event.time}
{event.locationName}
{/* Módulo: Invitados */}
Invitados
{guests.map(g => (
))}
{adminMode && (
)}
{/* Checklist */}
Checklist
{checklist.map(c => (
-
{c.text}
))}
{adminMode && (
)}
{/* Cronograma */}
Cronograma del Evento
{timeline.map(t => (
{t.time} — {t.activity}
))}
{adminMode && (
)}
{/* Presupuesto */}
Presupuesto
{budget.map(b => (
{b.label}: Q{b.amount}
))}
{adminMode && (
)}
);
}
top of page
Grupo de música bailableDisco, Cumbia y Pop
bottom of page