{"index.html":{"type":"html","content":"<!DOCTYPE html>\n<html lang=\"es\" class=\"h-full bg-gray-50\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Agendar Asesoría</title>\n\n    <script src=\"https://unpkg.com/react@18/umd/react.production.min.js\" crossorigin></script>\n    <script src=\"https://unpkg.com/react-dom@18/umd/react-dom.production.min.js\" crossorigin></script>\n    <script src=\"https://unpkg.com/@babel/standalone/babel.min.js\"></script>\n    <script src=\"https://cdn.tailwindcss.com\"></script>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css\">\n\n    <script>\n        tailwind.config = {\n            theme: {\n                extend: {\n                    // Puedes añadir colores primarios o fuentes aquí si lo deseas\n                }\n            }\n        }\n    </script>\n\n<style type=\"text/tailwindcss\">\n        /* Forzar altura completa (100%) para la aplicación */\n        html, body, #root {\n            height: 100%;\n            margin: 0;\n            padding: 0;\n            overflow-x: hidden; /* Evita barras de scroll en el contenedor principal si no es necesario */\n        }\n        \n        body {\n            font-family: 'Inter', sans-serif; /* Opcional, pero se ve bien */\n        }\n    </style>\n</head>\n<body>\n    <div id=\"root\"></div>\n\n    <script type=\"text/babel\">\n        const { useState, useEffect, useRef, useCallback, useMemo } = React;\n\n        function useLocalStorageState(key, defaultValue) {\n            const [state, setState] = useState(() => {\n                try {\n                    const storedValue = window.localStorage.getItem(key);\n                    return storedValue ? JSON.parse(storedValue) : defaultValue;\n                } catch (error) {\n                    console.error(\"Error reading from localStorage\", error);\n                    return defaultValue;\n                }\n            });\n\n            useEffect(() => {\n                try {\n                    window.localStorage.setItem(key, JSON.stringify(state));\n                } catch (error) {\n                    console.error(\"Error writing to localStorage\", error);\n                }\n            }, [key, state]);\n\n            return [state, setState];\n        }\n\n        const Button = ({ children, onClick, variant = 'primary', className = '', ...props }) => {\n            const baseClasses = \"font-medium py-2 px-3 rounded-lg text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed\";\n            const variantClasses = {\n                primary: \"bg-blue-500 hover:bg-blue-600 text-white\",\n                secondary: \"bg-white hover:bg-gray-100 border border-gray-300 text-gray-800\",\n                ghost: \"hover:bg-gray-100 text-gray-600\",\n                dangerText: \"text-red-600 hover:bg-red-50\",\n            }[variant];\n\n            return (\n                <button\n                    className={`${baseClasses} ${variantClasses} ${className}`}\n                    onClick={onClick}\n                    {...props}\n                >\n                    {children}\n                </button>\n            );\n        };\n\n        const Input = ({ label, id, type = 'text', value, onChange, placeholder, error, className = '', ...props }) => (\n            <div className=\"mb-4\">\n                {label && (\n                    <label htmlFor={id} className=\"block mb-2 text-sm font-medium text-gray-700\">\n                        {label}\n                    </label>\n                )}\n                <input\n                    id={id}\n                    type={type}\n                    value={value}\n                    onChange={onChange}\n                    placeholder={placeholder}\n                    className={`bg-white border text-gray-900 text-sm rounded-lg focus:ring-2 focus:ring-blue-300 focus:border-blue-500 block w-full p-2.5 placeholder-gray-400 ${\n                        error ? 'border-red-500' : 'border-gray-300'\n                    } ${className}`}\n                    {...props}\n                />\n                {error && <p className=\"mt-1 text-sm text-red-600\">{error}</p>}\n            </div>\n        );\n\n        const Alert = ({ message, type = 'success', onClose, className = '' }) => {\n            const baseClasses = \"p-4 mb-4 text-sm rounded-lg flex justify-between items-center transition-opacity duration-300\";\n            const variantClasses = {\n                success: \"bg-green-100 text-green-800\",\n                error: \"bg-red-100 text-red-800\",\n                warning: \"bg-yellow-100 text-yellow-800\",\n                info: \"bg-blue-100 text-blue-800\",\n            }[type];\n\n            return (\n                <div className={`${baseClasses} ${variantClasses} ${className}`} role=\"alert\">\n                    <span>{message}</span>\n                    {onClose && (\n                        <Button variant=\"ghost\" onClick={onClose} className=\"!p-1\">\n                            <i className=\"fa-solid fa-xmark\"></i>\n                        </Button>\n                    )}\n                </div>\n            );\n        };\n\n        // Modal component is now unused, but kept here because it was in the original code\n        const Modal = ({ isOpen, onClose, title, children }) => {\n            if (!isOpen) return null;\n\n            return (\n                <div\n                    className=\"fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full flex justify-center items-center p-4 z-50 transition-opacity duration-200\"\n                    onClick={onClose}\n                >\n                    <div\n                        className=\"relative bg-white rounded-lg shadow-xl p-6 w-full max-w-lg mx-auto border border-gray-200 transition-transform duration-200 scale-100\"\n                        onClick={(e) => e.stopPropagation()}\n                    >\n                        <div className=\"flex justify-between items-center pb-3 border-b border-gray-200 mb-4\">\n                            <h3 className=\"text-xl font-semibold text-gray-900\">{title}</h3>\n                            <button onClick={onClose} className=\"text-gray-400 hover:text-gray-600 transition-colors\">\n                                <i className=\"fa-solid fa-xmark text-lg\"></i>\n                            </button>\n                        </div>\n                        <div>\n                            {children}\n                        </div>\n                    </div>\n                </div>\n            );\n        };\n\n        const SuccessPage = ({ onGoBack }) => (\n            <div className=\"flex flex-col items-center justify-center p-6 text-center h-full\">\n                <i className=\"fa-solid fa-circle-check text-green-500 text-6xl mb-6\"></i>\n                <h2 className=\"text-3xl font-bold text-gray-900 mb-4\">¡Asesoría Agendada Correctamente!</h2>\n                <p className=\"text-lg text-gray-700 mb-8\">\n                    Tu asesoría ha sido agendada con éxito. Recibirás un correo de confirmación con los detalles.\n                </p>\n            </div>\n        );\n\n\n        function App() {\n            const [appointments, setAppointments] = useLocalStorageState('rug_appointments', []);\n            const [occupiedSlots, setOccupiedSlots] = useState([]);\n            const [formData, setFormData] = useState({\n                name: '',\n                email: '',\n                phone: '',\n                channel: '', // New field for channel\n                date: '',\n                time: '',\n                product: '', // New field\n            });\n            const [formErrors, setFormErrors] = useState({});\n            const [alert, setAlert] = useState(null);\n            const [loading, setLoading] = useState(false);\n            const [showSuccessPage, setShowSuccessPage] = useState(false);\n            const [fetchingOccupiedSlots, setFetchingOccupiedSlots] = useState(true); // Set to true initially\n\n            const [step, setStep] = useState(1); // 1: Channel selection, 2: Contact Info, 3: Date/Time selection\n\n            const GET_OCCUPIED_SLOTS_URL = \"https://webhook.latenode.com/82751/dev/a70099cf-4ee8-4eb0-8c18-bb207ad3eaa5?action=getvalues\";\n\n\n            const getDaysInMonth = (year, month) => {\n                // month is 0-indexed where 0 is January\n                return new Date(year, month + 1, 0).getDate();\n            };\n\n            const getFirstDayOfMonth = (year, month) => {\n                // Returns 0 for Sunday, 1 for Monday, etc.\n                // We want Monday to be the first day (index 0 for our calendar grid)\n                // So, if day is 0 (Sunday), return 6. Otherwise, return day - 1.\n                const day = new Date(year, month, 1).getDay(); \n                return day === 0 ? 6 : day - 1; \n            };\n\n            const [currentDate, setCurrentDate] = useState(new Date(new Date().toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"})));\n\n            const year = currentDate.getFullYear();\n            const month = currentDate.getMonth(); \n\n            // Helper function to get date string in YYYY-MM-DD for Chile/Santiago timezone\n            const getFormattedDate = (date) => {\n                // Ensure date is a valid Date object for toLocaleDateString\n                const d = new Date(date);\n                // Use toLocaleDateString with timeZone for consistent formatting based on Santiago timezone\n                return d.toLocaleDateString('en-CA', { // 'en-CA' gives YYYY-MM-DD\n                    year: 'numeric', \n                    month: '2-digit', \n                    day: '2-digit',\n                    timeZone: 'America/Santiago'\n                });\n            };\n\n            // Get current date and time for comparison (Today in Chile/Santiago)\n            const getChileSantiagoNow = () => {\n                return new Date(new Date().toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n            };\n\n            useEffect(() => {\n                const urlParams = new URLSearchParams(window.location.search);\n                const productFromUrl = urlParams.get('producto');\n                if (productFromUrl) {\n                    setFormData(prev => ({ ...prev, product: productFromUrl }));\n                }\n            }, []); // Run once on component mount to check URL params\n\n\n            const handleInputChange = (e) => {\n                const { id, value } = e.target;\n                setFormData(prev => ({ ...prev, [id]: value }));\n                \n                if (formErrors[id]) {\n                    setFormErrors(prev => ({ ...prev, [id]: '' }));\n                }\n            };\n            \n            const handleChannelChange = (channel) => {\n                setFormData(prev => ({ ...prev, channel }));\n                setFormErrors(prev => ({ ...prev, channel: '' }));\n                setStep(2); // Move to Contact Info step after channel is chosen\n            };\n\n            const isSlotOccupied = useCallback((date, time) => {\n                const formattedDate = getFormattedDate(date); // Use formatted date\n                \n                // Check against locally stored (newly created appointments)\n                const isLocalOccupied = appointments.some(app =>\n                    getFormattedDate(app.date) === formattedDate && app.time === time\n                );\n                // Check against fetched occupied slots\n                const isFetchedOccupied = occupiedSlots.some(slot =>\n                    slot.date === formattedDate && slot.time === time\n                );\n                return isLocalOccupied || isFetchedOccupied;\n            }, [appointments, occupiedSlots]);\n\n            const validateStep1 = () => {\n                let errors = {};\n                if (!formData.channel) errors.channel = 'Debe seleccionar un canal.';\n                setFormErrors(errors);\n                return Object.keys(errors).length === 0;\n            };\n\n            const validateStep2 = () => {\n                let errors = {};\n                if (!formData.name.trim()) errors.name = 'El nombre es obligatorio.';\n                if (!formData.email.trim()) {\n                    errors.email = 'El correo es obligatorio.';\n                } else if (!/\\S+@\\S+\\.\\S+/.test(formData.email)) {\n                    errors.email = 'El correo no es válido.';\n                }\n                if (!formData.phone.trim()) {\n                    errors.phone = 'El teléfono es obligatorio.';\n                } else if (!/^\\+?[0-9\\s-]{7,20}$/.test(formData.phone)) {\n                    errors.phone = 'El teléfono no es válido.';\n                }\n                setFormErrors(errors);\n                return Object.keys(errors).length === 0;\n            };\n\n            const validateStep3 = () => {\n                let errors = {};\n                if (!formData.date) errors.date = 'Debe seleccionar una fecha.';\n                if (!formData.time) errors.time = 'Debe seleccionar un horario.';\n                \n                if (formData.date && formData.time && isSlotOccupied(new Date(formData.date), formData.time)) {\n                    errors.time = 'Este horario ya está reservado para la fecha seleccionada.';\n                }\n                \n                // New validation for maximum 4 hours before\n                if (formData.date && formData.time) {\n                    const nowInSantiago = getChileSantiagoNow();\n                    const [selectedYear, selectedMonth, selectedDay] = formData.date.split('-').map(Number);\n                    const [timeStartHour, timeStartMinute] = formData.time.split(' - ')[0].split(':').map(Number);\n                \n                    const selectedDateTime = new Date(selectedYear, selectedMonth - 1, selectedDay, timeStartHour, timeStartMinute);\n                    \n                    const fourHoursLater = new Date(nowInSantiago.getTime() + 4 * 60 * 60 * 1000); // 4 hours in milliseconds\n\n                    if (selectedDateTime < fourHoursLater) {\n                        errors.time = 'Solo se pueden agendar visitas con al menos 4 horas de anticipación.';\n                    }\n                }\n\n                setFormErrors(errors);\n                return Object.keys(errors).length === 0;\n            };\n\n            const WEBHOOK_URL = \"https://webhook.latenode.com/82751/dev/a70099cf-4ee8-4eb0-8c18-bb207ad3eaa5?action=postdata\";\n\n            const handleNewAppointment = async (e) => {\n                e.preventDefault();\n                setLoading(true);\n                setAlert(null);\n\n                if (!validateStep1() || !validateStep2() || !validateStep3()) {\n                    setLoading(false);\n                    setAlert({ message: 'Por favor, corrige los errores en el formulario.', type: 'error' });\n                    return;\n                }\n\n                const newAppointment = {\n                    id: Date.now(),\n                    name: formData.name,\n                    email: formData.email,\n                    phone: formData.phone,\n                    channel: formData.channel, // Include new channel field\n                    date: formData.date, // Already formatted YYYY-MM-DD\n                    time: formData.time,\n                    product: formData.product, // Include new field\n                    createdAt: new Date().toISOString(),\n                };\n\n                try {\n                    // Post data to webhook\n                    const response = await fetch(WEBHOOK_URL, {\n                        method: 'POST',\n                        headers: {\n                            'Content-Type': 'application/json',\n                        },\n                        body: JSON.stringify(newAppointment),\n                    });\n\n                    if (!response.ok) {\n                        throw new Error(`HTTP error! status: ${response.status}`);\n                    }\n\n                    // If webhook post is successful, save to local storage and show success page\n                    setAppointments(prev => [...prev, newAppointment]);\n                    setLoading(false);\n                    resetForm();\n                    setShowSuccessPage(true);\n                    \n                    // Re-fetch occupied slots to reflect the new booking\n                    fetchOccupiedSlots(); \n                } catch (error) {\n                    console.error(\"Error submitting form or sending to webhook:\", error);\n                    setAlert({ message: 'Hubo un error al agendar tu visita. Por favor, inténtalo de nuevo.', type: 'error' });\n                    setLoading(false);\n                }\n            };\n\n            const resetForm = () => {\n                setFormData(prev => ({\n                    ...prev,\n                    name: '',\n                    email: '',\n                    phone: '',\n                    channel: '',\n                    date: '',\n                    time: '',\n                    // product will retain its value if from URL parameter, otherwise stays empty string\n                    // product: '', // If you want to clear product on reset as well, uncomment this line\n                }));\n                setFormErrors({});\n                setStep(1); // Reset to channel selection step\n            };\n\n            const goToPreviousMonth = () => {\n                setCurrentDate(prev => {\n                    const newDate = new Date(prev.getFullYear(), prev.getMonth() - 1, 1);\n                    return new Date(newDate.toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n                });\n            };\n\n            const goToNextMonth = () => {\n                setCurrentDate(prev => {\n                    const newDate = new Date(prev.getFullYear(), prev.getMonth() + 1, 1);\n                    return new Date(newDate.toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n                });\n            };\n\n            const isTimeSlotAllowed = useCallback((dayOfWeek, time) => {\n                const [hour, minute] = time.split(':').map(Number);\n            \n                // Monday to Friday (1-5)\n                if (dayOfWeek >= 1 && dayOfWeek <= 5) { \n                    const timeInMinutes = hour * 60 + minute;\n                    // 10:30 (630) to 14:00 (840)\n                    const block1Start = 10 * 60 + 30;\n                    const block1End = 14 * 60 + 0;\n                    // 15:00 (900) to 18:00 (1080)\n                    const block2Start = 15 * 60 + 0;\n                    const block2End = 18 * 60 + 0;\n\n                    return (timeInMinutes >= block1Start && timeInMinutes < block1End) || // Changed to < for 30 min slots\n                           (timeInMinutes >= block2Start && timeInMinutes < block2End); // Changed to < for 30 min slots\n                }\n                // Saturday (6)\n                else if (dayOfWeek === 6) { \n                    const timeInMinutes = hour * 60 + minute;\n                    // 10:00 (600) to 14:00 (840)\n                    const block3Start = 10 * 60 + 0;\n                    const block3End = 14 * 60 + 0;\n                    return timeInMinutes >= block3Start && timeInMinutes < block3End; // Changed to < for 30 min slots\n                }\n                // Sunday (0) or any other day not explicitly allowed\n                return false;\n            }, []);\n\n            const generateTimeSlotsForDay = useCallback((dayOfWeek, selectedDate) => {\n                const slots = [];\n                const nowInSantiago = getChileSantiagoNow();\n                const fourHoursLater = new Date(nowInSantiago.getTime() + 4 * 60 * 60 * 1000); \n\n                for (let h = 0; h < 24; h++) {\n                    for (let m = 0; m < 60; m += 30) {\n                        const startTime = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n                        // Calculate end time for the 30-minute slot\n                        const endHour = h + Math.floor((m + 30) / 60);\n                        const endMinute = (m + 30) % 60;\n                        const endTime = `${String(endHour).padStart(2, '0')}:${String(endMinute).padStart(2, '0')}`;\n\n                        if (isTimeSlotAllowed(dayOfWeek, startTime)) {\n                            // Check if the slot is at least 4 hours in the future\n                            const slotDateTime = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate(), h, m);\n\n                            if (slotDateTime >= fourHoursLater) {\n                                slots.push(`${startTime} - ${endTime}`);\n                            }\n                        }\n                    }\n                }\n                return slots;\n            }, [isTimeSlotAllowed]);\n\n\n            const handleDateSelection = (day) => {\n                const todayInSantiago = getChileSantiagoNow(); // Now includes time, important for 4-hour rule\n                todayInSantiago.setHours(0,0,0,0); // Normalize to start of day for past day comparison\n                \n                // Create a specific date object for the selected day in Santiago timezone\n                const selectedDate = new Date(year, month, day);\n                // Adjust to Santiago timezone to compare its day of week and its date value effectively\n                const chileSantiagoSelectedDate = new Date(selectedDate.toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n                chileSantiagoSelectedDate.setHours(0,0,0,0); // Normalize to start of day for comparison\n\n                // If selected date is in the past, disallow selection\n                if (chileSantiagoSelectedDate < todayInSantiago) {\n                    setAlert({ message: 'No puedes agendar citas en el pasado.', type: 'warning' });\n                    setFormData(prev => ({ ...prev, date: '', time: '' })); \n                    return;\n                }\n                \n                const formattedSelectedDate = getFormattedDate(chileSantiagoSelectedDate); \n                setFormData(prev => ({ ...prev, date: formattedSelectedDate, time: '' })); \n                setFormErrors(prev => ({ ...prev, date: '', time: '' })); \n            };\n\n            const fetchOccupiedSlots = async () => {\n                setFetchingOccupiedSlots(true);\n                try {\n                    const response = await fetch(GET_OCCUPIED_SLOTS_URL);\n                    if (!response.ok) {\n                        throw new Error(`HTTP error! status: ${response.status}`);\n                    }\n                    const data = await response.json();\n                    \n                    if (data.length > 1) {\n                        const headers = data[0];\n                        const dateIndex = headers.indexOf('date');\n                        const timeIndex = headers.indexOf('time');\n\n                        if (dateIndex !== -1 && timeIndex !== -1) {\n                            const parsedSlots = data.slice(1).map(row => {\n                                let dateValue = row[dateIndex];\n                                let timeValue = row[timeIndex];\n\n                                // Extract YYYY-MM-DD from '2025-11-05T04:06:00.266Z' if present\n                                if (dateValue && typeof dateValue === 'string' && dateValue.includes('T')) {\n                                    dateValue = dateValue.split('T')[0];\n                                }\n                                \n                                // Format time as HH:MM if necessary or ensure it's a string\n                                // If the stored format is 'HH:MM - HH:MM', extract the start time 'HH:MM'\n                                if (timeValue && typeof timeValue === 'string' && timeValue.includes(' - ')) {\n                                    timeValue = timeValue.split(' - ')[0];\n                                } else if (timeValue && typeof timeValue !== 'string') {\n                                    timeValue = String(timeValue);\n                                }\n\n\n                                return {\n                                    date: dateValue,\n                                    time: timeValue,\n                                };\n                            }).filter(slot => slot.date && slot.time); // Filter out invalid entries\n\n                            setOccupiedSlots(parsedSlots);\n                        } else {\n                            console.warn(\"Date or time column not found in webhook response headers.\");\n                            setOccupiedSlots([]);\n                        }\n                    } else {\n                        setOccupiedSlots([]);\n                    }\n                } catch (error) {\n                    console.error(\"Error fetching occupied slots:\", error);\n                    setAlert({ message: 'Hubo un error al cargar los horarios ocupados.', type: 'error' });\n                    setOccupiedSlots([]); // Clear any previous occupied slots on error\n                } finally {\n                    setFetchingOccupiedSlots(false);\n                }\n            };\n\n            useEffect(() => {\n                fetchOccupiedSlots();\n            }, []); // Fetch on initial load\n\n            useEffect(() => {\n                if (alert && alert.message) {\n                    const timer = setTimeout(() => {\n                        setAlert(null);\n                    }, 3000);\n                    return () => clearTimeout(timer);\n                }\n            }, [alert]);\n\n            const handleGoBackToForm = () => {\n                setShowSuccessPage(false);\n                resetForm(); // Reset form when going back from success page\n                fetchOccupiedSlots(); // Re-fetch slots in case local storage or other bookings changed\n            };\n            \n            const currentMonthName = useMemo(() => {\n                const dateOptions = { month: 'long', timeZone: 'America/Santiago' };\n                // Creating a date for the 1st of the current month ensures it's interpreted correctly in Santiago time\n                return new Date(year, month, 1).toLocaleDateString('es-ES', dateOptions);\n            }, [year, month]);\n\n            const todayInSantiagoForCalendar = getChileSantiagoNow(); // Use this for calendar day comparison\n            todayInSantiagoForCalendar.setHours(0,0,0,0); // Normalize to start of day\n\n            const daysInMonth = getDaysInMonth(year, month);\n            const firstDay = getFirstDayOfMonth(year, month); \n\n            // Derived state for the currently selected day's available times\n            const currentDayAvailableTimes = useMemo(() => {\n                if (!formData.date) return [];\n                const [y, m, d] = formData.date.split('-').map(Number);\n                const selectedDate = new Date(y, m - 1, d); // Month is 0-indexed\n                const chileSantiagoSelectedDate = new Date(selectedDate.toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n                const dayOfWeek = chileSantiagoSelectedDate.getDay(); // 0 for Sunday, 1 for Monday...\n\n                return generateTimeSlotsForDay(dayOfWeek, selectedDate);\n            }, [formData.date, generateTimeSlotsForDay]);\n\n\n            return (\n                <div className=\"p-4 sm:p-8 max-w-4xl mx-auto min-h-screen flex flex-col justify-start\">\n                    {alert && <Alert message={alert.message} type={alert.type} onClose={() => setAlert(null)} />}\n\n                    <header className=\"flex justify-between items-center mb-6\">\n                    </header>\n\n                    <div className=\"bg-white rounded-lg shadow-xl p-6 w-full max-w-lg mx-auto border border-gray-200\">\n                        {showSuccessPage ? (\n                            <SuccessPage onGoBack={handleGoBackToForm} />\n                        ) : (\n                            <>\n                                <h3 className=\"text-xl font-semibold text-gray-900 pb-3 border-b border-gray-200 mb-4\">Agendar Asesoría Personalizada</h3>\n                                <p className=\"text-base text-gray-700 mb-4\">\n                                    Ingresa tus datos y selecciona un canal, fecha y horario para que un vendedor te acompañe.\n                                </p>\n                                <form onSubmit={handleNewAppointment}>\n                                    {/* Ocultar input de producto para el cliente */}\n                                    <input\n                                        id=\"product\"\n                                        type=\"hidden\" // Hace que el input no sea visible\n                                        value={formData.product}\n                                        onChange={handleInputChange}\n                                    />\n\n                                    {step === 1 && (\n                                        <div className=\"mb-4\">\n                                            <h4 className=\"text-lg font-medium text-gray-800 mb-3\">Paso 1: Selecciona el Canal de Asesoría</h4>\n                                            <div className=\"flex gap-4\">\n                                                <Button\n                                                    type=\"button\"\n                                                    variant={formData.channel === 'online' ? 'primary' : 'secondary'}\n                                                    onClick={() => handleChannelChange('online')}\n                                                    disabled={loading || fetchingOccupiedSlots}\n                                                    className=\"flex-1\"\n                                                >\n                                                    <i className=\"fa-solid fa-video mr-2\"></i> Online\n                                                </Button>\n                                                <Button\n                                                    type=\"button\"\n                                                    variant={formData.channel === 'presencial' ? 'primary' : 'secondary'}\n                                                    onClick={() => handleChannelChange('presencial')}\n                                                    disabled={loading || fetchingOccupiedSlots}\n                                                    className=\"flex-1\"\n                                                >\n                                                    <i className=\"fa-solid fa-store mr-2\"></i> Presencial\n                                                </Button>\n                                            </div>\n                                            {formErrors.channel && <p className=\"mt-2 text-sm text-red-600\">{formErrors.channel}</p>}\n                                            <div className=\"mt-6 flex justify-end\">\n                                                <Button\n                                                    type=\"button\"\n                                                    variant=\"primary\"\n                                                    onClick={() => {\n                                                        if (validateStep1()) setStep(2);\n                                                    }}\n                                                    disabled={loading || fetchingOccupiedSlots || !formData.channel}\n                                                >\n                                                    Siguiente Paso\n                                                </Button>\n                                            </div>\n                                        </div>\n                                    )}\n\n                                    {step === 2 && (\n                                        <div className=\"mb-4\">\n                                            <h4 className=\"text-lg font-medium text-gray-800 mb-3\">Paso 2: Datos de Contacto</h4>\n                                            <Input\n                                                id=\"name\"\n                                                label=\"Nombre Completo\"\n                                                value={formData.name}\n                                                onChange={handleInputChange}\n                                                placeholder=\"Tu nombre...\"\n                                                error={formErrors.name}\n                                                disabled={loading || fetchingOccupiedSlots}\n                                            />\n                                            <Input\n                                                id=\"email\"\n                                                label=\"Correo Electrónico\"\n                                                type=\"email\"\n                                                value={formData.email}\n                                                onChange={handleInputChange}\n                                                placeholder=\"tu@email.com\"\n                                                error={formErrors.email}\n                                                disabled={loading || fetchingOccupiedSlots}\n                                            />\n                                            <Input\n                                                id=\"phone\"\n                                                label=\"Teléfono\"\n                                                type=\"tel\"\n                                                value={formData.phone}\n                                                onChange={handleInputChange}\n                                                placeholder=\"+56912345678\"\n                                                error={formErrors.phone}\n                                                disabled={loading || fetchingOccupiedSlots}\n                                            />\n                                            <div className=\"mt-6 flex justify-between gap-3\">\n                                                <Button\n                                                    type=\"button\"\n                                                    variant=\"secondary\"\n                                                    onClick={() => setStep(1)}\n                                                    disabled={loading || fetchingOccupiedSlots}\n                                                >\n                                                    Paso Anterior\n                                                </Button>\n                                                <Button\n                                                    type=\"button\"\n                                                    variant=\"primary\"\n                                                    onClick={() => {\n                                                        if (validateStep2()) setStep(3);\n                                                    }}\n                                                    disabled={loading || fetchingOccupiedSlots || !formData.name || !formData.email || !formData.phone}\n                                                >\n                                                    Siguiente Paso\n                                                </Button>\n                                            </div>\n                                        </div>\n                                    )}\n\n                                    {step === 3 && (\n                                        <div className=\"mb-4\">\n                                            <h4 className=\"text-lg font-medium text-gray-800 mb-3\">Paso 3: Seleccionar Fecha y Hora</h4>\n                                            {formErrors.date && <p className=\"mt-1 text-sm text-red-600 mb-2\">{formErrors.date}</p>}\n\n                                            <div className=\"p-4 border border-gray-200 rounded-lg\">\n                                                <div className=\"flex justify-between items-center mb-4\">\n                                                    <Button type=\"button\" variant=\"ghost\" onClick={goToPreviousMonth} disabled={loading || fetchingOccupiedSlots || (year === todayInSantiagoForCalendar.getFullYear() && month === todayInSantiagoForCalendar.getMonth())}>\n                                                        <i className=\"fa-solid fa-chevron-left\"></i>\n                                                    </Button>\n                                                    <h4 className=\"text-lg font-medium capitalize\">\n                                                        {currentMonthName} {year}\n                                                    </h4>\n                                                    <Button type=\"button\" variant=\"ghost\" onClick={goToNextMonth} disabled={loading || fetchingOccupiedSlots}>\n                                                        <i className=\"fa-solid fa-chevron-right\"></i>\n                                                    </Button>\n                                                </div>\n                                                <div className=\"grid grid-cols-7 gap-2 text-center text-sm\">\n                                                    {['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'].map(day => (\n                                                        <div key={day} className=\"font-medium text-gray-500\">{day}</div>\n                                                    ))}\n                                                    {Array.from({ length: firstDay }).map((_, i) => ( \n                                                        <div key={`empty-${i}`} className=\"p-2\"></div>\n                                                    ))}\n                                                    { fetchingOccupiedSlots ? (\n                                                        // Loading state for calendar days\n                                                        Array.from({ length: daysInMonth }).map((_, i) => (\n                                                            <div key={`loading-${i}`} className=\"p-2 animate-pulse rounded-md bg-gray-100\"></div>\n                                                        ))\n                                                    ) : (\n                                                        Array.from({ length: daysInMonth }).map((_, i) => {\n                                                            const day = i + 1;\n                                                            // Create date object for the current day in Santiago timezone\n                                                            const dayDateUTC = new Date(year, month, day); \n                                                            const chileSantiagoDayDate = new Date(dayDateUTC.toLocaleString(\"en-US\", {timeZone: \"America/Santiago\"}));\n                                                            chileSantiagoDayDate.setHours(0,0,0,0); // Normalize for comparison\n\n                                                            // getDay() returns 0 for Sunday, 1 for Monday... 6 for Saturday (in the local timezone of the Date object)\n                                                            const dayOfWeek = chileSantiagoDayDate.getDay(); \n                                                            const isPastDay = chileSantiagoDayDate < todayInSantiagoForCalendar;\n                                                            const formattedDayDate = getFormattedDate(chileSantiagoDayDate);\n                                                            const isSelected = formData.date === formattedDayDate;\n                                                            \n                                                            // Pass chileSantiagoDayDate to generateTimeSlotsForDay to check the 4-hour rule\n                                                            const allowedTimesForDay = generateTimeSlotsForDay(dayOfWeek, chileSantiagoDayDate);\n\n                                                            // Check if ALL allowed time slots for this day are occupied\n                                                            const isDayFullyOccupied = allowedTimesForDay.length > 0 && allowedTimesForDay.every(timeSlot => {\n                                                                const startTimeStr = timeSlot.split(' - ')[0]; // Extract only the start time for the check\n                                                                return isSlotOccupied(chileSantiagoDayDate, startTimeStr);\n                                                            });\n\n                                                            // Determine if the day is selectable (not past, has allowed slots, and not fully occupied)\n                                                            const isSelectable = !isPastDay && allowedTimesForDay.length > 0 && !isDayFullyOccupied;\n\n                                                            return (\n                                                                <div\n                                                                    key={day}\n                                                                    className={`relative p-2 rounded-md transition-colors\n                                                                        ${!isSelectable ? 'cursor-not-allowed bg-gray-50 text-gray-400' : 'cursor-pointer'}\n                                                                        ${isSelectable && !isSelected ? 'text-gray-800 hover:bg-blue-50' : ''}\n                                                                        ${isSelected ? 'bg-blue-500 text-white hover:bg-blue-600' : ''}\n                                                                    `}\n                                                                    onClick={() => isSelectable && handleDateSelection(day)}\n                                                                >\n                                                                    {day}\n                                                                </div>\n                                                            );\n                                                        })\n                                                    )}\n                                                </div>\n                                                {fetchingOccupiedSlots ? (\n                                                    <div className=\"mt-4 animate-pulse\">\n                                                        <p className=\"mb-2 text-sm font-medium text-gray-700\">Cargando horarios disponibles...</p>\n                                                        <div className=\"flex flex-wrap gap-2\">\n                                                            <div className=\"h-8 w-20 bg-gray-100 rounded-lg\"></div>\n                                                            <div className=\"h-8 w-20 bg-gray-100 rounded-lg\"></div>\n                                                            <div className=\"h-8 w-20 bg-gray-100 rounded-lg\"></div>\n                                                        </div>\n                                                    </div>\n                                                ) : formData.date && (\n                                                    <div className=\"mt-4\">\n                                                        <p className=\"mb-2 text-sm font-medium text-gray-700\">Selecciona un horario para el {formData.date}:</p>\n                                                        <div className=\"flex flex-wrap gap-2\">\n                                                            {currentDayAvailableTimes.length > 0 ? (\n                                                                currentDayAvailableTimes.map(timeSlot => {\n                                                                    const startTimeStr = timeSlot.split(' - ')[0]; // Extract the start time for checking occupied slots\n                                                                    // Create a Date object from formData.date for accurate comparison\n                                                                    const [y, m, d] = formData.date.split('-').map(Number);\n                                                                    const selectedDateForTime = new Date(y, m - 1, d); // Month is 0-indexed\n                                                                    const isBooked = isSlotOccupied(selectedDateForTime, startTimeStr);\n                                                                    const isSelectedTime = formData.time === timeSlot;\n\n                                                                    return (\n                                                                        <Button\n                                                                            key={timeSlot}\n                                                                            type=\"button\"\n                                                                            variant={isSelectedTime ? 'primary' : 'secondary'}\n                                                                            className={`min-w-[80px] ${isBooked && !isSelectedTime ? 'cursor-not-allowed border-red-300 bg-red-50 text-red-700 opacity-70' : ''}`}\n                                                                            onClick={() => {\n                                                                                if (!isBooked) {\n                                                                                    setFormData(prev => ({ ...prev, time: timeSlot }));\n                                                                                    setFormErrors(prev => ({ ...prev, time: '' }));\n                                                                                }\n                                                                            }}\n                                                                            disabled={loading || isBooked}\n                                                                        >\n                                                                            {timeSlot} {isBooked && <i className=\"fa-solid fa-ban ml-1\"></i>}\n                                                                        </Button>\n                                                                    );\n                                                                })\n                                                            ) : (\n                                                                <p className=\"text-sm text-gray-500\">No hay horarios disponibles para el día seleccionado que cumplan con la anticipación mínima de 4 horas.</p>\n                                                            )}\n                                                        </div>\n                                                        {formErrors.time && <p className=\"mt-2 text-sm text-red-600\">{formErrors.time}</p>}\n                                                    </div>\n                                                )}\n                                            </div>\n                                            <div className=\"mt-6 flex justify-between gap-3\">\n                                                <Button\n                                                    type=\"button\"\n                                                    variant=\"secondary\"\n                                                    onClick={() => setStep(2)}\n                                                    disabled={loading || fetchingOccupiedSlots}\n                                                >\n                                                    Paso Anterior\n                                                </Button>\n                                                <Button\n                                                    type=\"submit\"\n                                                    variant=\"primary\"\n                                                    disabled={loading || fetchingOccupiedSlots || !formData.date || !formData.time}\n                                                >\n                                                    {loading ? <i className=\"fa-solid fa-spinner fa-spin mr-2\"></i> : null}\n                                                    Agendar Asesoría\n                                                </Button>\n                                            </div>\n                                        </div>\n                                    )}\n                                </form>\n                            </>\n                        )}\n                    </div>\n                </div>\n            );\n        }\n\n        const root = ReactDOM.createRoot(document.getElementById('root'));\n        root.render(<App />);\n    </script>\n</body>\n</html>"}}