// 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 */}
{event.heroImage && }

{event.subtitle}

{event.description}

{adminMode && (
setEvent({...event,title:e.target.value})} /> setEvent({...event,subtitle:e.target.value})} /> setEvent({...event,date:e.target.value})} /> setEvent({...event,time:e.target.value})} />