import { api } from "../lib/api.js"; const DAYS = [ { id: "lun", label: "Lunes", short: "L" }, { id: "mar", label: "Martes", short: "M" }, { id: "mie", label: "Miércoles", short: "X" }, { id: "jue", label: "Jueves", short: "J" }, { id: "vie", label: "Viernes", short: "V" }, { id: "sab", label: "Sábado", short: "S" }, { id: "dom", label: "Domingo", short: "D" }, ]; // Lista oficial de 48 barrios de CABA const CABA_BARRIOS = [ "Agronomía", "Almagro", "Balvanera", "Barracas", "Belgrano", "Boedo", "Caballito", "Chacarita", "Coghlan", "Colegiales", "Constitución", "Flores", "Floresta", "La Boca", "La Paternal", "Liniers", "Mataderos", "Monte Castro", "Montserrat", "Nueva Pompeya", "Núñez", "Palermo", "Parque Avellaneda", "Parque Chacabuco", "Parque Chas", "Parque Patricios", "Puerto Madero", "Recoleta", "Retiro", "Saavedra", "San Cristóbal", "San Nicolás", "San Telmo", "Vélez Sársfield", "Versalles", "Villa Crespo", "Villa del Parque", "Villa Devoto", "Villa General Mitre", "Villa Lugano", "Villa Luro", "Villa Ortúzar", "Villa Pueyrredón", "Villa Real", "Villa Riachuelo", "Villa Santa Rita", "Villa Soldati", "Villa Urquiza" ]; class SettingsCrud extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.settings = null; this.loading = false; this.saving = false; this.shadowRoot.innerHTML = `
Cargando configuración...
`; } connectedCallback() { this.load(); } async load() { this.loading = true; this.render(); try { this.settings = await api.getSettings(); // Asegurar que schedule existe if (!this.settings.schedule) { this.settings.schedule = { delivery: {}, pickup: {} }; } // Asegurar que delivery_zones existe if (!this.settings.delivery_zones) { this.settings.delivery_zones = {}; } this.loading = false; this.render(); } catch (e) { console.error("Error loading settings:", e); this.loading = false; this.showError("Error cargando configuración: " + e.message); } } getScheduleSlot(type, dayId) { return this.settings?.schedule?.[type]?.[dayId] || null; } setScheduleSlot(type, dayId, slot) { if (!this.settings.schedule) { this.settings.schedule = { delivery: {}, pickup: {} }; } if (!this.settings.schedule[type]) { this.settings.schedule[type] = {}; } this.settings.schedule[type][dayId] = slot; } renderScheduleGrid(type, enabled) { const defaultStart = type === "delivery" ? "09:00" : "08:00"; const defaultEnd = type === "delivery" ? "18:00" : "20:00"; return DAYS.map(day => { const slot = this.getScheduleSlot(type, day.id); const isActive = slot !== null && slot !== undefined; const start = slot?.start || defaultStart; const end = slot?.end || defaultEnd; return `
${day.label}
a
`; }).join(""); } // Convierte nombre de barrio a key (ej: "Villa Crespo" -> "villa_crespo") barrioToKey(name) { return name.toLowerCase() .normalize("NFD").replace(/[\u0300-\u036f]/g, "") // quitar acentos .replace(/\s+/g, "_"); } getZoneConfig(barrioKey) { return this.settings?.delivery_zones?.[barrioKey] || null; } setZoneConfig(barrioKey, config) { if (!this.settings.delivery_zones) { this.settings.delivery_zones = {}; } if (config === null) { delete this.settings.delivery_zones[barrioKey]; } else { this.settings.delivery_zones[barrioKey] = config; } } renderZonesList() { return CABA_BARRIOS.map(barrio => { const key = this.barrioToKey(barrio); const config = this.getZoneConfig(key); const isActive = config?.enabled === true; const days = config?.days || []; const cost = config?.delivery_cost || 0; return `
${barrio}
${DAYS.map(d => `
${d.short}
`).join("")}
`; }).join(""); } renderZonesSummary() { const zones = this.settings?.delivery_zones || {}; const activeZones = Object.entries(zones).filter(([k, v]) => v?.enabled); if (activeZones.length === 0) { return `
No hay zonas de entrega configuradas. Activá los barrios donde hacés delivery.
`; } return `
${activeZones.length} zona${activeZones.length > 1 ? 's' : ''} de entrega activa${activeZones.length > 1 ? 's' : ''}
`; } render() { const content = this.shadowRoot.getElementById("content"); if (this.loading) { content.innerHTML = `
Cargando configuración...
`; return; } if (!this.settings) { content.innerHTML = `
No se pudo cargar la configuración
`; return; } const s = this.settings; content.innerHTML = `
Información del Negocio
Se usa en los mensajes del bot
El asistente virtual
Delivery (Envío a domicilio)
Delivery habilitado
${this.renderScheduleGrid("delivery", s.delivery_enabled)}
Retiro en Tienda
Retiro en tienda habilitado
${this.renderScheduleGrid("pickup", s.pickup_enabled)}
Zonas de Entrega (Barrios CABA)
${this.renderZonesList()}
${this.renderZonesSummary()}
`; this.setupEventListeners(); } setupEventListeners() { // Toggle delivery const deliveryToggle = this.shadowRoot.getElementById("deliveryToggle"); deliveryToggle?.addEventListener("click", () => { this.settings.delivery_enabled = !this.settings.delivery_enabled; this.render(); }); // Toggle pickup const pickupToggle = this.shadowRoot.getElementById("pickupToggle"); pickupToggle?.addEventListener("click", () => { this.settings.pickup_enabled = !this.settings.pickup_enabled; this.render(); }); // Day toggles this.shadowRoot.querySelectorAll(".day-toggle").forEach(toggle => { toggle.addEventListener("click", () => { const type = toggle.dataset.type; const day = toggle.dataset.day; const currentSlot = this.getScheduleSlot(type, day); if (currentSlot) { // Desactivar día this.setScheduleSlot(type, day, null); } else { // Activar día con horarios default const defaultStart = type === "delivery" ? "09:00" : "08:00"; const defaultEnd = type === "delivery" ? "18:00" : "20:00"; this.setScheduleSlot(type, day, { start: defaultStart, end: defaultEnd }); } this.render(); }); }); // Hour inputs - update on blur this.shadowRoot.querySelectorAll(".hour-start, .hour-end").forEach(input => { input.addEventListener("blur", () => { const type = input.dataset.type; const day = input.dataset.day; const isStart = input.classList.contains("hour-start"); const slot = this.getScheduleSlot(type, day); if (!slot) return; const value = input.value.trim(); if (isStart) { slot.start = value || (type === "delivery" ? "09:00" : "08:00"); } else { slot.end = value || (type === "delivery" ? "18:00" : "20:00"); } this.setScheduleSlot(type, day, slot); }); }); // Save button this.shadowRoot.getElementById("saveBtn")?.addEventListener("click", () => this.save()); // Reset button this.shadowRoot.getElementById("resetBtn")?.addEventListener("click", () => this.load()); // Zone search this.shadowRoot.getElementById("zoneSearch")?.addEventListener("input", (e) => { const query = e.target.value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); this.shadowRoot.querySelectorAll(".zone-row").forEach(row => { const barrio = row.dataset.barrio; const barrioName = CABA_BARRIOS.find(b => this.barrioToKey(b) === barrio) || ""; const normalized = barrioName.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); row.classList.toggle("hidden", query && !normalized.includes(query)); }); }); // Zone toggles this.shadowRoot.querySelectorAll(".zone-toggle").forEach(toggle => { toggle.addEventListener("click", () => { const barrio = toggle.dataset.barrio; const config = this.getZoneConfig(barrio); if (config?.enabled) { // Desactivar zona this.setZoneConfig(barrio, null); } else { // Activar zona con días default (lun-sab) this.setZoneConfig(barrio, { enabled: true, days: ["lun", "mar", "mie", "jue", "vie", "sab"], delivery_cost: 0 }); } this.render(); }); }); // Zone day toggles this.shadowRoot.querySelectorAll(".zone-day").forEach(dayBtn => { dayBtn.addEventListener("click", () => { const barrio = dayBtn.dataset.barrio; const day = dayBtn.dataset.day; const config = this.getZoneConfig(barrio); if (!config) return; const days = config.days || []; const idx = days.indexOf(day); if (idx >= 0) { days.splice(idx, 1); } else { days.push(day); } config.days = days; this.setZoneConfig(barrio, config); // Update UI without full re-render dayBtn.classList.toggle("active", days.includes(day)); }); }); // Zone cost inputs this.shadowRoot.querySelectorAll(".zone-cost-input").forEach(input => { input.addEventListener("change", () => { const barrio = input.dataset.barrio; const config = this.getZoneConfig(barrio); if (!config) return; config.delivery_cost = parseFloat(input.value) || 0; this.setZoneConfig(barrio, config); }); }); } collectScheduleFromInputs() { const schedule = { delivery: {}, pickup: {} }; for (const type of ["delivery", "pickup"]) { this.shadowRoot.querySelectorAll(`.hour-start[data-type="${type}"]`).forEach(input => { const day = input.dataset.day; const endInput = this.shadowRoot.querySelector(`.hour-end[data-type="${type}"][data-day="${day}"]`); const toggle = this.shadowRoot.querySelector(`.day-toggle[data-type="${type}"][data-day="${day}"]`); if (toggle?.classList.contains("active")) { schedule[type][day] = { start: input.value.trim() || (type === "delivery" ? "09:00" : "08:00"), end: endInput?.value.trim() || (type === "delivery" ? "18:00" : "20:00"), }; } }); } return schedule; } async save() { // Collect schedule from inputs const schedule = this.collectScheduleFromInputs(); // Collect delivery zones (already in settings from event handlers) const delivery_zones = this.settings.delivery_zones || {}; const data = { store_name: this.shadowRoot.getElementById("storeName")?.value || "", bot_name: this.shadowRoot.getElementById("botName")?.value || "", store_address: this.shadowRoot.getElementById("storeAddress")?.value || "", store_phone: this.shadowRoot.getElementById("storePhone")?.value || "", delivery_enabled: this.settings.delivery_enabled, pickup_enabled: this.settings.pickup_enabled, delivery_min_order: parseFloat(this.shadowRoot.getElementById("deliveryMinOrder")?.value) || 0, schedule, delivery_zones, }; // Update settings with form values this.settings = { ...this.settings, ...data }; this.saving = true; this.render(); try { console.log("[settings-crud] Saving:", data); const result = await api.saveSettings(data); console.log("[settings-crud] Save result:", result); if (result.ok === false) { throw new Error(result.message || result.error || "Error desconocido"); } this.settings = result.settings || data; this.saving = false; this.showSuccess(result.message || "Configuración guardada correctamente"); this.render(); } catch (e) { console.error("[settings-crud] Error saving settings:", e); this.saving = false; this.showError("Error guardando: " + (e.message || e)); this.render(); } } escapeHtml(str) { return (str || "").replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } showSuccess(msg) { const messages = this.shadowRoot.getElementById("messages"); messages.innerHTML = `
${msg}
`; setTimeout(() => { messages.innerHTML = ""; }, 4000); } showError(msg) { const messages = this.shadowRoot.getElementById("messages"); messages.innerHTML = `
${msg}
`; setTimeout(() => { messages.innerHTML = ""; }, 5000); } } customElements.define("settings-crud", SettingsCrud);