716 lines
26 KiB
PHP
716 lines
26 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SkyBalloons | Asistente de Reservas</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
/* Estilos mejorados con micro-interacciones */
|
|
:root {
|
|
--primary: #0ea5e9;
|
|
--primary-dark: #0284c7;
|
|
--bg-dark: #0f172a;
|
|
--bg-card: #1e293b;
|
|
--bot-msg: #334155;
|
|
--text-light: #e2e8f0;
|
|
--text-muted: #94a3b8;
|
|
--border-light: rgba(255,255,255,0.1);
|
|
--success: #10b981;
|
|
--error: #ef4444;
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
font-family: 'Inter', sans-serif;
|
|
}
|
|
|
|
body {
|
|
height: 100vh;
|
|
background: linear-gradient(135deg, #0b1121, #1a2639);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.chat-container {
|
|
width: 100%;
|
|
max-width: 500px;
|
|
height: 92vh;
|
|
background: rgba(30, 41, 59, 0.98);
|
|
backdrop-filter: blur(12px);
|
|
border-radius: 28px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.7);
|
|
border: 1px solid var(--border-light);
|
|
}
|
|
|
|
.chat-header {
|
|
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
|
|
padding: 20px 22px;
|
|
text-align: center;
|
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
}
|
|
|
|
.chat-header img {
|
|
height: 42px;
|
|
filter: brightness(1.1);
|
|
}
|
|
|
|
.chat-header h2 {
|
|
color: white;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
margin-top: 6px;
|
|
opacity: 0.9;
|
|
letter-spacing: 0.3px;
|
|
}
|
|
|
|
.chat-messages {
|
|
flex: 1;
|
|
padding: 24px 20px;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
.message {
|
|
max-width: 85%;
|
|
padding: 14px 18px;
|
|
border-radius: 22px;
|
|
font-size: 14.5px;
|
|
line-height: 1.5;
|
|
animation: slideIn 0.3s cubic-bezier(0.2, 0.9, 0.3, 1);
|
|
word-break: break-word;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.bot {
|
|
background: var(--bot-msg);
|
|
color: var(--text-light);
|
|
align-self: flex-start;
|
|
border-bottom-left-radius: 6px;
|
|
border: 1px solid rgba(255,255,255,0.05);
|
|
}
|
|
|
|
.user {
|
|
background: var(--primary);
|
|
color: white;
|
|
align-self: flex-end;
|
|
border-bottom-right-radius: 6px;
|
|
}
|
|
|
|
.system-message {
|
|
background: rgba(16, 185, 129, 0.2);
|
|
color: var(--success);
|
|
align-self: center;
|
|
font-size: 12px;
|
|
padding: 8px 16px;
|
|
border-radius: 30px;
|
|
border: 1px solid rgba(16, 185, 129, 0.3);
|
|
max-width: 90%;
|
|
}
|
|
|
|
.error-message {
|
|
background: rgba(239, 68, 68, 0.2);
|
|
color: var(--error);
|
|
align-self: center;
|
|
font-size: 12px;
|
|
padding: 8px 16px;
|
|
border-radius: 30px;
|
|
border: 1px solid rgba(239, 68, 68, 0.3);
|
|
max-width: 90%;
|
|
}
|
|
|
|
.chat-input {
|
|
padding: 18px 16px;
|
|
background: var(--bg-card);
|
|
display: flex;
|
|
gap: 12px;
|
|
border-top: 1px solid var(--border-light);
|
|
}
|
|
|
|
.chat-input input {
|
|
flex: 1;
|
|
padding: 14px 18px;
|
|
border: none;
|
|
border-radius: 30px;
|
|
background: #0f172a;
|
|
color: white;
|
|
outline: none;
|
|
font-size: 14.5px;
|
|
transition: all 0.2s;
|
|
border: 1px solid transparent;
|
|
}
|
|
|
|
.chat-input input:focus {
|
|
border-color: var(--primary);
|
|
background: #1a2538;
|
|
}
|
|
|
|
.chat-input input::placeholder {
|
|
color: #64748b;
|
|
}
|
|
|
|
.chat-input input.error {
|
|
border-color: var(--error);
|
|
animation: shake 0.3s ease-in-out;
|
|
}
|
|
|
|
.chat-input button {
|
|
padding: 14px 24px;
|
|
border: none;
|
|
border-radius: 30px;
|
|
background: var(--primary);
|
|
color: white;
|
|
cursor: pointer;
|
|
transition: 0.2s;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
letter-spacing: 0.3px;
|
|
box-shadow: 0 4px 10px rgba(14, 165, 233, 0.3);
|
|
}
|
|
|
|
.chat-input button:hover:not(:disabled) {
|
|
background: var(--primary-dark);
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
.chat-input button:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.status {
|
|
text-align: center;
|
|
font-size: 12px;
|
|
padding: 8px;
|
|
color: var(--text-muted);
|
|
background: #0f172a;
|
|
border-top: 1px solid var(--border-light);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.loader {
|
|
width: 20px;
|
|
height: 20px;
|
|
border: 3px solid rgba(255,255,255,0.3);
|
|
border-top: 3px solid white;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin: 5px 0;
|
|
}
|
|
|
|
.date-picker-container {
|
|
position: fixed;
|
|
bottom: 90px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 90%;
|
|
max-width: 450px;
|
|
background: var(--bg-card);
|
|
border-radius: 20px;
|
|
padding: 20px;
|
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
|
border: 1px solid var(--border-light);
|
|
z-index: 1000;
|
|
display: none;
|
|
animation: slideUp 0.3s ease;
|
|
}
|
|
|
|
.date-picker-container.show {
|
|
display: block;
|
|
}
|
|
|
|
.date-picker-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
color: var(--text-light);
|
|
}
|
|
|
|
.date-picker-header h3 {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.date-picker-header button {
|
|
background: none;
|
|
border: none;
|
|
color: var(--text-muted);
|
|
font-size: 20px;
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
}
|
|
|
|
.date-picker-header button:hover {
|
|
color: var(--text-light);
|
|
}
|
|
|
|
.date-inputs {
|
|
display: flex;
|
|
gap: 10px;
|
|
justify-content: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.date-inputs select {
|
|
background: #0f172a;
|
|
color: white;
|
|
border: 1px solid var(--border-light);
|
|
border-radius: 12px;
|
|
padding: 12px;
|
|
font-size: 16px;
|
|
outline: none;
|
|
cursor: pointer;
|
|
flex: 1;
|
|
}
|
|
|
|
.date-inputs select:focus {
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.date-inputs select.error {
|
|
border-color: var(--error);
|
|
}
|
|
|
|
.confirm-date-btn {
|
|
width: 100%;
|
|
padding: 14px;
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 30px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: 0.2s;
|
|
}
|
|
|
|
.confirm-date-btn:hover {
|
|
background: var(--primary-dark);
|
|
}
|
|
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
|
|
@keyframes slideIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes slideUp {
|
|
from { opacity: 0; transform: translate(-50%, 20px); }
|
|
to { opacity: 1; transform: translate(-50%, 0); }
|
|
}
|
|
|
|
@keyframes shake {
|
|
0%, 100% { transform: translateX(0); }
|
|
25% { transform: translateX(-5px); }
|
|
75% { transform: translateX(5px); }
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
.chat-container {
|
|
height: 100vh;
|
|
border-radius: 0;
|
|
}
|
|
|
|
.date-picker-container {
|
|
width: 95%;
|
|
bottom: 80px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="chat-container">
|
|
<div class="chat-header">
|
|
<img src="https://www.skyballoons.mx/assets/images/logo-original-blanco.png" alt="SkyBalloons">
|
|
<h2>Asistente Oficial de Reservas</h2>
|
|
</div>
|
|
<div class="chat-messages" id="chatMessages"></div>
|
|
<div class="status" id="statusBar">🟢 Conectado</div>
|
|
<div class="chat-input">
|
|
<input type="text" id="messageInput" placeholder="Escribe tu mensaje..." autocomplete="off">
|
|
<button id="sendButton">Enviar</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Selector de fecha mejorado -->
|
|
<div class="date-picker-container" id="datePickerContainer">
|
|
<div class="date-picker-header">
|
|
<h3>📅 Selecciona tu fecha de nacimiento</h3>
|
|
<button id="closeDatePicker">✕</button>
|
|
</div>
|
|
<div class="date-inputs">
|
|
<select id="daySelect" aria-label="Día">
|
|
<option value="">Día</option>
|
|
</select>
|
|
<select id="monthSelect" aria-label="Mes">
|
|
<option value="">Mes</option>
|
|
<option value="1">Enero</option>
|
|
<option value="2">Febrero</option>
|
|
<option value="3">Marzo</option>
|
|
<option value="4">Abril</option>
|
|
<option value="5">Mayo</option>
|
|
<option value="6">Junio</option>
|
|
<option value="7">Julio</option>
|
|
<option value="8">Agosto</option>
|
|
<option value="9">Septiembre</option>
|
|
<option value="10">Octubre</option>
|
|
<option value="11">Noviembre</option>
|
|
<option value="12">Diciembre</option>
|
|
</select>
|
|
<select id="yearSelect" aria-label="Año">
|
|
<option value="">Año</option>
|
|
</select>
|
|
</div>
|
|
<button class="confirm-date-btn" id="confirmDateBtn">Confirmar fecha</button>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
// Configuración
|
|
const API_URL = "https://n8n.skyballoons.cloud/webhook/sky-recopilador-72/chat";
|
|
|
|
// Generar o recuperar sessionId
|
|
let sessionId = localStorage.getItem("skySession");
|
|
if (!sessionId) {
|
|
sessionId = crypto.randomUUID ? crypto.randomUUID() : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
const r = Math.random() * 16 | 0;
|
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
return v.toString(16);
|
|
});
|
|
localStorage.setItem("skySession", sessionId);
|
|
}
|
|
|
|
// Elementos DOM
|
|
const chatMessages = document.getElementById("chatMessages");
|
|
const messageInput = document.getElementById("messageInput");
|
|
const sendButton = document.getElementById("sendButton");
|
|
const statusBar = document.getElementById("statusBar");
|
|
const datePickerContainer = document.getElementById("datePickerContainer");
|
|
const closeDatePicker = document.getElementById("closeDatePicker");
|
|
const daySelect = document.getElementById("daySelect");
|
|
const monthSelect = document.getElementById("monthSelect");
|
|
const yearSelect = document.getElementById("yearSelect");
|
|
const confirmDateBtn = document.getElementById("confirmDateBtn");
|
|
|
|
// Estado
|
|
let isLoading = false;
|
|
let awaitingDate = false;
|
|
let dateValidationCallback = null;
|
|
let currentContext = null; // Para saber qué campo estamos solicitando
|
|
|
|
// Validaciones
|
|
const validators = {
|
|
nombre: (text) => {
|
|
const nameRegex = /^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]{3,50}$/;
|
|
return nameRegex.test(text.trim()) ? null : "Por favor, ingresa un nombre válido (solo letras, mínimo 3 caracteres)";
|
|
},
|
|
email: (text) => {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(text.trim()) ? null : "Por favor, ingresa un correo electrónico válido";
|
|
},
|
|
telefono: (text) => {
|
|
const phoneRegex = /^[0-9]{10}$/;
|
|
return phoneRegex.test(text.replace(/\D/g, '')) ? null : "Por favor, ingresa un teléfono válido de 10 dígitos";
|
|
},
|
|
fecha: (text) => {
|
|
const dateRegex = /^\d{2}\/\d{2}\/\d{4}$/;
|
|
if (!dateRegex.test(text)) return "Formato inválido. Usa DD/MM/AAAA";
|
|
|
|
const [day, month, year] = text.split('/').map(Number);
|
|
const date = new Date(year, month - 1, day);
|
|
const isValid = date.getDate() === day && date.getMonth() === month - 1;
|
|
|
|
if (!isValid) return "Fecha inválida";
|
|
|
|
const today = new Date();
|
|
const minDate = new Date(today.getFullYear() - 100, today.getMonth(), today.getDate());
|
|
const maxDate = new Date(today.getFullYear() - 18, today.getMonth(), today.getDate());
|
|
|
|
if (date > maxDate) return "Debes ser mayor de 18 años";
|
|
if (date < minDate) return "Fecha de nacimiento no válida";
|
|
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Detectar contexto del último mensaje del bot
|
|
function detectContext(botMessage) {
|
|
if (!botMessage) return null;
|
|
const lowerMsg = botMessage.toLowerCase();
|
|
if (lowerMsg.includes("nombre") || lowerMsg.includes("nombre completo")) return "nombre";
|
|
if (lowerMsg.includes("correo") || lowerMsg.includes("email")) return "email";
|
|
if (lowerMsg.includes("teléfono") || lowerMsg.includes("telefono") || lowerMsg.includes("celular")) return "telefono";
|
|
if (lowerMsg.includes("fecha de nacimiento") || lowerMsg.includes("fecha nacimiento")) return "fecha";
|
|
return null;
|
|
}
|
|
|
|
// Inicializar selects de fecha
|
|
function initializeDatePicker() {
|
|
// Limpiar selects
|
|
daySelect.innerHTML = '<option value="">Día</option>';
|
|
yearSelect.innerHTML = '<option value="">Año</option>';
|
|
|
|
// Llenar días (1-31)
|
|
for (let i = 1; i <= 31; i++) {
|
|
const option = document.createElement('option');
|
|
option.value = i;
|
|
option.textContent = i.toString().padStart(2, '0');
|
|
daySelect.appendChild(option);
|
|
}
|
|
|
|
// Llenar años (últimos 100 años)
|
|
const currentYear = new Date().getFullYear();
|
|
for (let i = currentYear - 18; i >= currentYear - 100; i--) {
|
|
const option = document.createElement('option');
|
|
option.value = i;
|
|
option.textContent = i;
|
|
yearSelect.appendChild(option);
|
|
}
|
|
}
|
|
|
|
// Mostrar selector de fecha
|
|
function showDatePicker(callback) {
|
|
dateValidationCallback = callback;
|
|
awaitingDate = true;
|
|
datePickerContainer.classList.add('show');
|
|
messageInput.disabled = true;
|
|
sendButton.disabled = true;
|
|
|
|
// Resetear selects
|
|
daySelect.value = '';
|
|
monthSelect.value = '';
|
|
yearSelect.value = '';
|
|
[daySelect, monthSelect, yearSelect].forEach(select => {
|
|
select.classList.remove('error');
|
|
});
|
|
}
|
|
|
|
// Ocultar selector de fecha
|
|
function hideDatePicker() {
|
|
datePickerContainer.classList.remove('show');
|
|
awaitingDate = false;
|
|
dateValidationCallback = null;
|
|
messageInput.disabled = false;
|
|
sendButton.disabled = false;
|
|
messageInput.focus();
|
|
}
|
|
|
|
// Validar fecha seleccionada
|
|
function validateSelectedDate() {
|
|
const day = daySelect.value;
|
|
const month = monthSelect.value;
|
|
const year = yearSelect.value;
|
|
|
|
if (!day || !month || !year) {
|
|
[daySelect, monthSelect, yearSelect].forEach(select => {
|
|
if (!select.value) select.classList.add('error');
|
|
});
|
|
addSystemMessage("Por favor, selecciona día, mes y año", "error");
|
|
return false;
|
|
}
|
|
|
|
// Validar días por mes
|
|
const daysInMonth = new Date(year, month, 0).getDate();
|
|
if (day > daysInMonth) {
|
|
daySelect.classList.add('error');
|
|
addSystemMessage(`El mes seleccionado solo tiene ${daysInMonth} días`, "error");
|
|
return false;
|
|
}
|
|
|
|
// Validar edad mínima (18 años)
|
|
const selectedDate = new Date(year, month - 1, day);
|
|
const today = new Date();
|
|
const minAgeDate = new Date(today.getFullYear() - 18, today.getMonth(), today.getDate());
|
|
|
|
if (selectedDate > minAgeDate) {
|
|
addSystemMessage("Debes ser mayor de 18 años para continuar", "error");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Funciones UI
|
|
function addMessage(text, type) {
|
|
const msgDiv = document.createElement("div");
|
|
msgDiv.className = `message ${type}`;
|
|
const formattedText = text
|
|
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
.replace(/\n/g, '<br>');
|
|
msgDiv.innerHTML = formattedText;
|
|
chatMessages.appendChild(msgDiv);
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
}
|
|
|
|
function addSystemMessage(text, type = "system") {
|
|
const msgDiv = document.createElement("div");
|
|
msgDiv.className = type === "error" ? "error-message" : "system-message";
|
|
msgDiv.textContent = text;
|
|
chatMessages.appendChild(msgDiv);
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
}
|
|
|
|
function showLoadingIndicator() {
|
|
if (isLoading) return;
|
|
isLoading = true;
|
|
const loaderDiv = document.createElement("div");
|
|
loaderDiv.className = "message bot";
|
|
loaderDiv.id = "loadingIndicator";
|
|
loaderDiv.innerHTML = '<div class="loader"></div>';
|
|
chatMessages.appendChild(loaderDiv);
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
statusBar.innerText = "✍️ Escribiendo...";
|
|
sendButton.disabled = true;
|
|
messageInput.disabled = true;
|
|
}
|
|
|
|
function removeLoadingIndicator() {
|
|
const loader = document.getElementById("loadingIndicator");
|
|
if (loader) loader.remove();
|
|
isLoading = false;
|
|
if (!awaitingDate) {
|
|
statusBar.innerText = "🟢 Conectado";
|
|
sendButton.disabled = false;
|
|
messageInput.disabled = false;
|
|
messageInput.focus();
|
|
}
|
|
}
|
|
|
|
// Procesar mensaje con API
|
|
async function processMessageWithAPI(text) {
|
|
showLoadingIndicator();
|
|
|
|
try {
|
|
const response = await fetch(API_URL, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
chatInput: text,
|
|
sessionId: sessionId
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Error ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
removeLoadingIndicator();
|
|
|
|
const botReply = data.output || "Lo siento, no pude procesar tu solicitud.";
|
|
addMessage(botReply, "bot");
|
|
|
|
// Actualizar contexto después de recibir respuesta del bot
|
|
currentContext = detectContext(botReply);
|
|
|
|
// Si el bot está pidiendo fecha, mostrar selector automáticamente
|
|
if (currentContext === "fecha") {
|
|
showDatePicker((formattedDate) => {
|
|
addMessage(formattedDate, "user");
|
|
processMessageWithAPI(formattedDate);
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
removeLoadingIndicator();
|
|
addMessage("⚠️ Error de conexión. Por favor, intenta de nuevo.", "bot");
|
|
statusBar.innerText = "🔴 Error de conexión";
|
|
console.error("Error:", error);
|
|
}
|
|
}
|
|
|
|
// Enviar mensaje principal
|
|
async function sendMessage() {
|
|
const userText = messageInput.value.trim();
|
|
if (!userText || isLoading || awaitingDate) return;
|
|
|
|
// Obtener último mensaje del bot para validar según contexto
|
|
const lastBotMessages = Array.from(chatMessages.children)
|
|
.filter(msg => msg.classList.contains('bot'));
|
|
const lastBotMessage = lastBotMessages.length > 0
|
|
? lastBotMessages[lastBotMessages.length - 1].textContent
|
|
: '';
|
|
|
|
// Si no tenemos contexto actual, detectar del último mensaje
|
|
if (!currentContext) {
|
|
currentContext = detectContext(lastBotMessage);
|
|
}
|
|
|
|
let validationError = null;
|
|
|
|
if (currentContext === "nombre") {
|
|
validationError = validators.nombre(userText);
|
|
} else if (currentContext === "email") {
|
|
validationError = validators.email(userText);
|
|
} else if (currentContext === "telefono") {
|
|
validationError = validators.telefono(userText);
|
|
} else if (currentContext === "fecha") {
|
|
// Para fecha, mostrar el selector en lugar de validar texto
|
|
showDatePicker((formattedDate) => {
|
|
addMessage(formattedDate, "user");
|
|
processMessageWithAPI(formattedDate);
|
|
});
|
|
messageInput.value = "";
|
|
return;
|
|
}
|
|
|
|
if (validationError) {
|
|
addSystemMessage(validationError, "error");
|
|
messageInput.classList.add('error');
|
|
setTimeout(() => messageInput.classList.remove('error'), 300);
|
|
return;
|
|
}
|
|
|
|
// Mostrar mensaje del usuario
|
|
addMessage(userText, "user");
|
|
messageInput.value = "";
|
|
|
|
// Limpiar contexto después de enviar (se actualizará con la respuesta)
|
|
currentContext = null;
|
|
|
|
await processMessageWithAPI(userText);
|
|
}
|
|
|
|
// Event Listeners
|
|
messageInput.addEventListener("keypress", (e) => {
|
|
if (e.key === "Enter") sendMessage();
|
|
});
|
|
|
|
sendButton.addEventListener("click", sendMessage);
|
|
|
|
closeDatePicker.addEventListener("click", hideDatePicker);
|
|
|
|
confirmDateBtn.addEventListener("click", () => {
|
|
if (validateSelectedDate() && dateValidationCallback) {
|
|
const formattedDate = `${daySelect.value.padStart(2, '0')}/${monthSelect.value.padStart(2, '0')}/${yearSelect.value}`;
|
|
dateValidationCallback(formattedDate);
|
|
hideDatePicker();
|
|
}
|
|
});
|
|
|
|
// Remover error cuando se selecciona un valor
|
|
[daySelect, monthSelect, yearSelect].forEach(select => {
|
|
select.addEventListener('change', () => {
|
|
select.classList.remove('error');
|
|
});
|
|
});
|
|
|
|
// Inicializar
|
|
initializeDatePicker();
|
|
addMessage("👋 ¡Hola! Soy el asistente de SkyBalloons. Para comenzar con su reserva, ¿podría indicarme su **nombre completo** (nombre y apellidos)?", "bot");
|
|
currentContext = "nombre";
|
|
messageInput.focus();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html> |