/* global React, ReactDOM */ const { useState, useEffect } = React; // ===== Envío de formularios al correo de TURIS ===== // Los formularios entregan los datos a turiscleaningandservices@gmail.com vía Web3Forms // (sin servidor). PARA ACTIVAR: entra en https://web3forms.com, registra el correo // turiscleaningandservices@gmail.com, copia el "Access Key" y pégalo abajo. // Mientras la clave sea el placeholder, el formulario muestra el mensaje de éxito // (modo demo) pero NO entrega el email. const WEB3FORMS_ACCESS_KEY = "REEMPLAZAR-CON-ACCESS-KEY-DE-WEB3FORMS"; const TURIS_EMAIL = "turiscleaningandservices@gmail.com"; async function sendToTuris({ subject, fields }) { // Devuelve true si se entregó de verdad; false si está en modo demo o falló. if (!WEB3FORMS_ACCESS_KEY || WEB3FORMS_ACCESS_KEY.startsWith("REEMPLAZAR")) { return false; // modo demo: sin clave configurada } try { const res = await fetch("https://api.web3forms.com/submit", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify({ access_key: WEB3FORMS_ACCESS_KEY, subject, from_name: "Web TURIS Cleaning", ...fields, }), }); const j = await res.json(); return !!j.success; } catch { return false; } } // ===== Icons (Lucide-style, stroke 1.5) ===== const I = { arrow: (p) => ( ), whatsapp: (p) => ( ), phone: (p) => ( ), mail: (p) => ( ), menu: (p) => ( ), close: (p) => ( ), // Service icons (stroke 1.5) bed: (p) => ( ), shirt: (p) => ( ), package: (p) => ( ), camera: (p) => ( ), car: (p) => ( ), sparkle: (p) => ( ), wrench: (p) => ( ), brush: (p) => ( ), sofa: (p) => ( ), flame: (p) => ( ), pin: (p) => ( ), check: (p) => ( ), }; // ===== Reveal hook ===== function useReveal() { useEffect(() => { if (typeof IntersectionObserver === "undefined") { document.querySelectorAll(".reveal").forEach(el => el.classList.add("in")); return; } const obs = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); obs.unobserve(e.target); } }); }, { threshold: 0.12 }); const watch = () => document.querySelectorAll(".reveal:not(.in)").forEach((el) => obs.observe(el)); watch(); // Re-renders (p.ej. pantallas exito/error del formulario) crean nodos .reveal // nuevos que el observer inicial no conoce: sin esto quedan en opacity 0. const mo = new MutationObserver(watch); mo.observe(document.getElementById("root"), { childList: true, subtree: true }); return () => { obs.disconnect(); mo.disconnect(); }; }, []); } // ===== Brand ===== function Brand() { return ( TURIS Cleaning Services TURISCleaning Services ); } // ===== Navigation model — solo landing pages separadas ===== function navLinks(page) { return [ { href: "servicios.html", label: "Servicios", active: page === "servicios" }, { href: "casas.html", label: "Casas", active: page === "casas" }, { href: "zonas.html", label: "Zonas", active: page === "zonas" }, { href: "contacto.html", label: "Contacto", active: page === "contacto" }, ]; } // ===== Header ===== function Header({ onOpenMenu, page }) { const links = navLinks(page); return (
644 363 973
); } function Drawer({ open, onClose, page }) { const links = navLinks(page); return (
Pedir presupuesto Escribir por WhatsApp
); } // ===== Window cleaning animation (replaces hero photo) ===== function WindowScene() { return (