Actualizar configuracion.html
This commit is contained in:
@@ -50,40 +50,20 @@
|
|||||||
|
|
||||||
<div id="view-templates" class="tab-content h-full fade-in flex flex-col md:flex-row gap-6">
|
<div id="view-templates" class="tab-content h-full fade-in flex flex-col md:flex-row gap-6">
|
||||||
<div class="w-full md:w-1/3 bg-white rounded-xl shadow border border-gray-100 overflow-hidden flex flex-col">
|
<div class="w-full md:w-1/3 bg-white rounded-xl shadow border border-gray-100 overflow-hidden flex flex-col">
|
||||||
<div class="p-4 bg-gray-50 border-b border-gray-200 font-bold text-gray-700 text-sm uppercase tracking-wide">
|
<div class="p-4 bg-gray-50 border-b border-gray-200 font-bold text-gray-700 text-sm uppercase tracking-wide">Tipos de Mensaje</div>
|
||||||
Tipos de Mensaje
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 overflow-y-auto p-2 space-y-1">
|
<div class="flex-1 overflow-y-auto p-2 space-y-1">
|
||||||
<button onclick="selectTemplate('welcome', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
<button onclick="selectTemplate('welcome', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-blue-100 text-blue-600 p-1.5 rounded-md group-hover:bg-blue-200 transition"><i data-lucide="hand" class="w-4 h-4"></i></span> Bienvenida / Alta</button>
|
||||||
<span class="bg-blue-100 text-blue-600 p-1.5 rounded-md group-hover:bg-blue-200 transition"><i data-lucide="hand" class="w-4 h-4"></i></span> Bienvenida / Alta
|
<button onclick="selectTemplate('no_contact', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-orange-100 text-orange-600 p-1.5 rounded-md group-hover:bg-orange-200 transition"><i data-lucide="phone-off" class="w-4 h-4"></i></span> Cliente No Localizado</button>
|
||||||
</button>
|
<button onclick="selectTemplate('appointment', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-green-100 text-green-600 p-1.5 rounded-md group-hover:bg-green-200 transition"><i data-lucide="calendar-check" class="w-4 h-4"></i></span> Cita Creada</button>
|
||||||
<button onclick="selectTemplate('no_contact', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
<button onclick="selectTemplate('update', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-purple-100 text-purple-600 p-1.5 rounded-md group-hover:bg-purple-200 transition"><i data-lucide="refresh-cw" class="w-4 h-4"></i></span> Modificación de Servicio</button>
|
||||||
<span class="bg-orange-100 text-orange-600 p-1.5 rounded-md group-hover:bg-orange-200 transition"><i data-lucide="phone-off" class="w-4 h-4"></i></span> Cliente No Localizado
|
<button onclick="selectTemplate('on_way', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-teal-100 text-teal-600 p-1.5 rounded-md group-hover:bg-teal-200 transition"><i data-lucide="truck" class="w-4 h-4"></i></span> Técnico de Camino</button>
|
||||||
</button>
|
<button onclick="selectTemplate('survey', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-yellow-100 text-yellow-600 p-1.5 rounded-md group-hover:bg-yellow-200 transition"><i data-lucide="star" class="w-4 h-4"></i></span> Encuesta de Calidad</button>
|
||||||
<button onclick="selectTemplate('appointment', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
|
||||||
<span class="bg-green-100 text-green-600 p-1.5 rounded-md group-hover:bg-green-200 transition"><i data-lucide="calendar-check" class="w-4 h-4"></i></span> Cita Creada
|
|
||||||
</button>
|
|
||||||
<button onclick="selectTemplate('update', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
|
||||||
<span class="bg-purple-100 text-purple-600 p-1.5 rounded-md group-hover:bg-purple-200 transition"><i data-lucide="refresh-cw" class="w-4 h-4"></i></span> Modificación de Servicio
|
|
||||||
</button>
|
|
||||||
<button onclick="selectTemplate('on_way', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
|
||||||
<span class="bg-teal-100 text-teal-600 p-1.5 rounded-md group-hover:bg-teal-200 transition"><i data-lucide="truck" class="w-4 h-4"></i></span> Técnico de Camino
|
|
||||||
</button>
|
|
||||||
<button onclick="selectTemplate('survey', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
|
|
||||||
<span class="bg-yellow-100 text-yellow-600 p-1.5 rounded-md group-hover:bg-yellow-200 transition"><i data-lucide="star" class="w-4 h-4"></i></span> Encuesta de Calidad
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1 bg-white rounded-xl shadow border border-gray-100 flex flex-col overflow-hidden">
|
<div class="flex-1 bg-white rounded-xl shadow border border-gray-100 flex flex-col overflow-hidden">
|
||||||
<div class="p-4 border-b bg-gray-50 flex justify-between items-center shrink-0">
|
<div class="p-4 border-b bg-gray-50 flex justify-between items-center shrink-0">
|
||||||
<div>
|
<div><span class="block font-bold text-gray-800" id="editorTitle">Selecciona una plantilla</span><span class="text-xs text-gray-500">Edita el mensaje que se enviará por WhatsApp/Email</span></div>
|
||||||
<span class="block font-bold text-gray-800" id="editorTitle">Selecciona una plantilla</span>
|
<button onclick="saveTemplate()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-lg transition-all transform active:scale-95 flex items-center gap-2"><i data-lucide="save" class="w-4 h-4"></i> Guardar</button>
|
||||||
<span class="text-xs text-gray-500">Edita el mensaje que se enviará por WhatsApp/Email</span>
|
|
||||||
</div>
|
|
||||||
<button onclick="saveTemplate()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-lg transition-all transform active:scale-95 flex items-center gap-2">
|
|
||||||
<i data-lucide="save" class="w-4 h-4"></i> Guardar
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="p-3 border-b bg-gray-50/50 flex flex-wrap gap-2 items-center">
|
<div class="p-3 border-b bg-gray-50/50 flex flex-wrap gap-2 items-center">
|
||||||
<span class="text-[10px] font-bold text-gray-400 uppercase tracking-wide mr-1">Variables:</span>
|
<span class="text-[10px] font-bold text-gray-400 uppercase tracking-wide mr-1">Variables:</span>
|
||||||
@@ -94,55 +74,33 @@
|
|||||||
<button onclick="insertVar('{{COMPANIA}}')" class="var-btn">{{COMPANIA}}</button>
|
<button onclick="insertVar('{{COMPANIA}}')" class="var-btn">{{COMPANIA}}</button>
|
||||||
<button onclick="insertVar('{{REFERENCIA}}')" class="var-btn">{{REFERENCIA}}</button>
|
<button onclick="insertVar('{{REFERENCIA}}')" class="var-btn">{{REFERENCIA}}</button>
|
||||||
</div>
|
</div>
|
||||||
<textarea id="tplContent" class="flex-1 p-6 outline-none resize-none text-sm leading-relaxed text-gray-700 font-sans" placeholder="Selecciona un tipo de mensaje..."></textarea>
|
<textarea id="tplContent" class="flex-1 p-6 outline-none resize-none text-sm leading-relaxed text-gray-700 font-sans" placeholder="Selecciona un tipo de mensaje a la izquierda..."></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="view-whatsapp" class="tab-content hidden h-full fade-in">
|
<div id="view-whatsapp" class="tab-content hidden h-full fade-in">
|
||||||
<div class="max-w-4xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div class="max-w-2xl mx-auto mt-10">
|
||||||
|
<div class="bg-white rounded-xl shadow-lg border border-gray-100 p-8 flex flex-col items-center text-center">
|
||||||
<div class="bg-white rounded-xl shadow border border-gray-100 p-6">
|
<div class="w-16 h-16 bg-blue-50 rounded-full flex items-center justify-center mb-6">
|
||||||
<h3 class="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
|
<i data-lucide="smartphone" class="w-8 h-8 text-blue-600"></i>
|
||||||
<i data-lucide="activity" class="text-blue-600"></i> Estado de Conexión
|
</div>
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div id="waStatusContainer" class="flex flex-col items-center justify-center p-6 bg-gray-50 rounded-lg border border-gray-200 min-h-[200px]">
|
<h2 class="text-2xl font-bold text-gray-800 mb-2">Conexión con WhatsApp</h2>
|
||||||
|
<p class="text-gray-500 mb-8 max-w-md">Escanea el código QR para vincular tu número de empresa. Esto permitirá enviar notificaciones automáticas.</p>
|
||||||
|
|
||||||
|
<div id="waStatusContainer" class="w-full flex flex-col items-center justify-center min-h-[250px] bg-gray-50 rounded-xl border-2 border-dashed border-gray-200 p-6 mb-6">
|
||||||
<div class="animate-pulse flex flex-col items-center">
|
<div class="animate-pulse flex flex-col items-center">
|
||||||
<div class="w-12 h-12 bg-gray-200 rounded-full mb-3"></div>
|
<div class="w-10 h-10 border-4 border-blue-200 border-t-blue-600 rounded-full animate-spin mb-4"></div>
|
||||||
<span class="text-gray-400 text-sm">Comprobando estado...</span>
|
<span class="text-sm font-bold text-gray-400">Iniciando instancia segura...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onclick="checkWhatsappStatus()" class="mt-4 w-full bg-white border border-gray-300 text-gray-700 font-bold py-2 rounded-lg hover:bg-gray-50 transition shadow-sm flex items-center justify-center gap-2">
|
<button onclick="checkWhatsappStatus()" class="bg-slate-800 hover:bg-slate-700 text-white font-bold py-3 px-8 rounded-xl transition shadow-lg flex items-center gap-2">
|
||||||
<i data-lucide="refresh-cw" class="w-4 h-4"></i> Actualizar Estado
|
<i data-lucide="refresh-cw" class="w-4 h-4"></i> Actualizar Estado
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow border border-gray-100 p-6">
|
|
||||||
<h3 class="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
|
|
||||||
<i data-lucide="settings-2" class="text-gray-600"></i> Configuración API
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-gray-500 mb-4">Introduce los datos de tu instancia de Evolution API.</p>
|
|
||||||
|
|
||||||
<div class="space-y-4">
|
<p class="text-[10px] text-gray-400 mt-6">Instancia segura gestionada automáticamente por el servidor.</p>
|
||||||
<div>
|
|
||||||
<label class="block text-xs font-bold text-gray-600 mb-1">URL Base (Evolution API)</label>
|
|
||||||
<input type="url" id="waUrl" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="https://api.midominio.com">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-xs font-bold text-gray-600 mb-1">API Key (Global)</label>
|
|
||||||
<input type="password" id="waKey" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="sk-...">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-xs font-bold text-gray-600 mb-1">Nombre de Instancia</label>
|
|
||||||
<input type="text" id="waInstance" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="IntegraRepara">
|
|
||||||
</div>
|
|
||||||
<button onclick="saveWhatsappConfig()" class="w-full bg-slate-800 text-white font-bold py-2 rounded-lg hover:bg-slate-700 transition">
|
|
||||||
Guardar Configuración
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -193,7 +151,6 @@
|
|||||||
if (!localStorage.getItem("token")) window.location.href = "index.html";
|
if (!localStorage.getItem("token")) window.location.href = "index.html";
|
||||||
showTab('templates');
|
showTab('templates');
|
||||||
loadTemplates();
|
loadTemplates();
|
||||||
loadWhatsappConfig(); // Cargar config si existe
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function showTab(tabId) {
|
function showTab(tabId) {
|
||||||
@@ -212,105 +169,62 @@
|
|||||||
if(tabId === 'whatsapp') { checkWhatsappStatus(); }
|
if(tabId === 'whatsapp') { checkWhatsappStatus(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- WHATSAPP CONFIG & STATUS ---
|
// --- WHATSAPP STATUS (AUTOMÁTICO) ---
|
||||||
function loadWhatsappConfig() {
|
|
||||||
// Por ahora usamos localStorage, idealmente vendría del backend
|
|
||||||
const conf = JSON.parse(localStorage.getItem('wa_config') || '{}');
|
|
||||||
if(conf.url) document.getElementById('waUrl').value = conf.url;
|
|
||||||
if(conf.key) document.getElementById('waKey').value = conf.key;
|
|
||||||
if(conf.instance) document.getElementById('waInstance').value = conf.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveWhatsappConfig() {
|
|
||||||
const url = document.getElementById('waUrl').value.replace(/\/$/, ""); // Quitar slash final
|
|
||||||
const key = document.getElementById('waKey').value;
|
|
||||||
const instance = document.getElementById('waInstance').value;
|
|
||||||
|
|
||||||
if(!url || !key || !instance) { showToast("Rellena todos los campos", true); return; }
|
|
||||||
|
|
||||||
localStorage.setItem('wa_config', JSON.stringify({ url, key, instance }));
|
|
||||||
showToast("Configuración guardada");
|
|
||||||
checkWhatsappStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkWhatsappStatus() {
|
async function checkWhatsappStatus() {
|
||||||
const conf = JSON.parse(localStorage.getItem('wa_config') || '{}');
|
|
||||||
const container = document.getElementById('waStatusContainer');
|
const container = document.getElementById('waStatusContainer');
|
||||||
|
|
||||||
if(!conf.url || !conf.key || !conf.instance) {
|
|
||||||
container.innerHTML = `
|
|
||||||
<div class="text-center text-gray-400">
|
|
||||||
<i data-lucide="settings" class="w-10 h-10 mx-auto mb-2 text-gray-300"></i>
|
|
||||||
<p class="text-sm">Configura la API primero</p>
|
|
||||||
</div>`;
|
|
||||||
lucide.createIcons();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="flex flex-col items-center animate-pulse">
|
<div class="flex flex-col items-center animate-pulse">
|
||||||
<i data-lucide="loader-2" class="w-8 h-8 text-blue-500 animate-spin mb-2"></i>
|
<i data-lucide="loader-2" class="w-8 h-8 text-blue-500 animate-spin mb-3"></i>
|
||||||
<span class="text-sm text-blue-600 font-medium">Conectando con Evolution API...</span>
|
<span class="text-sm text-blue-600 font-medium">Verificando instancia...</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Verificar estado de la instancia
|
// Llamamos a NUESTRO backend, que gestiona todo con Evolution
|
||||||
const res = await fetch(`${conf.url}/instance/connectionState/${conf.instance}`, {
|
const res = await fetch(`${API_URL}/whatsapp/status`, {
|
||||||
headers: { "apikey": conf.key }
|
headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!res.ok) throw new Error("Error al conectar");
|
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const state = data.instance?.state || "close";
|
|
||||||
|
|
||||||
if (state === "open") {
|
if (!data.ok) throw new Error(data.error || "Error desconocido");
|
||||||
|
|
||||||
|
if (data.state === "open") {
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-3">
|
<div class="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mb-4 shadow-sm border border-green-200">
|
||||||
<i data-lucide="check" class="w-8 h-8 text-green-600"></i>
|
<i data-lucide="check" class="w-10 h-10 text-green-600"></i>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="text-lg font-bold text-green-700">Conectado</h4>
|
<h4 class="text-xl font-bold text-green-700">Conectado</h4>
|
||||||
<p class="text-xs text-green-600 mt-1">Listo para enviar mensajes</p>
|
<p class="text-sm text-green-600 mt-1 font-medium">Instancia: ${data.instanceName}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else if (data.qr) {
|
||||||
// Si no está conectado, intentamos obtener el QR
|
|
||||||
// Nota: En Evolution v2 el endpoint de QR puede variar, aquí asumo el estándar
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="flex flex-col items-center text-center">
|
<div class="flex flex-col items-center w-full">
|
||||||
<div class="w-16 h-16 bg-orange-100 rounded-full flex items-center justify-center mb-3">
|
<div id="qrcode" class="bg-white p-3 border rounded-lg shadow-sm"></div>
|
||||||
<i data-lucide="qr-code" class="w-8 h-8 text-orange-600"></i>
|
<p class="text-xs text-orange-500 mt-4 font-bold animate-pulse">Esperando escaneo...</p>
|
||||||
</div>
|
|
||||||
<h4 class="text-lg font-bold text-orange-700">Desconectado</h4>
|
|
||||||
<p class="text-xs text-orange-600 mt-1 mb-3">Escanea el QR para vincular</p>
|
|
||||||
<div id="qrcode" class="bg-white p-2 border rounded"></div>
|
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
// Fetch QR (esto depende de la versión exacta de Evolution API)
|
if(data.qr.startsWith('data:image')) {
|
||||||
const resQr = await fetch(`${conf.url}/instance/connect/${conf.instance}`, { headers: { "apikey": conf.key } });
|
document.getElementById('qrcode').innerHTML = `<img src="${data.qr}" class="w-48 h-48">`;
|
||||||
const dataQr = await resQr.json();
|
} else {
|
||||||
if(dataQr.code || dataQr.base64) {
|
new QRCode(document.getElementById("qrcode"), { text: data.qr, width: 180, height: 180 });
|
||||||
// Si recibimos base64, lo mostramos como imagen
|
|
||||||
// Si recibimos string, usamos qrcode.js (si está cargado)
|
|
||||||
const qrCode = dataQr.code || dataQr.base64;
|
|
||||||
if(qrCode.startsWith('data:image')) {
|
|
||||||
document.getElementById('qrcode').innerHTML = `<img src="${qrCode}" class="w-40 h-40">`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
container.innerHTML = `<p class="text-orange-500 font-bold">Iniciando... intenta de nuevo en unos segundos.</p>`;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="text-center text-red-500">
|
<div class="text-center text-red-500 p-4">
|
||||||
<i data-lucide="alert-triangle" class="w-10 h-10 mx-auto mb-2"></i>
|
<i data-lucide="alert-triangle" class="w-10 h-10 mx-auto mb-2 opacity-80"></i>
|
||||||
<p class="text-sm font-bold">Error de conexión</p>
|
<p class="font-bold">Error de conexión</p>
|
||||||
<p class="text-xs mt-1 opacity-75">Revisa la URL y la API Key</p>
|
<p class="text-xs mt-1 bg-red-50 p-2 rounded">${e.message}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- GESTIÓN DE PLANTILLAS (IGUAL QUE ANTES) ---
|
// --- GESTIÓN DE PLANTILLAS ---
|
||||||
async function loadTemplates() {
|
async function loadTemplates() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_URL}/templates`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
|
const res = await fetch(`${API_URL}/templates`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
|
||||||
|
|||||||
Reference in New Issue
Block a user