Actualizar publi.html
This commit is contained in:
151
publi.html
151
publi.html
@@ -1,32 +1,133 @@
|
||||
// ==========================================
|
||||
// 🎯 RUTA PARA CUANDO EL CLIENTE PULSA "ME INTERESA" EN PUBLICIDAD
|
||||
// ==========================================
|
||||
app.post("/public/portal/:token/interest", async (req, res) => {
|
||||
try {
|
||||
const { token } = req.params;
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Promoción Especial</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<style>
|
||||
:root { --app-bg: #f8fafc; }
|
||||
body { background-color: var(--app-bg); -webkit-tap-highlight-color: transparent; }
|
||||
.fade-in { animation: fadeIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards; opacity: 0; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-slate-800 font-sans antialiased min-h-screen flex flex-col relative pb-24">
|
||||
|
||||
// 1. Buscamos quién es el cliente usando su token
|
||||
const clientQ = await pool.query("SELECT owner_id, full_name, phone FROM clients WHERE portal_token = $1 LIMIT 1", [token]);
|
||||
if (clientQ.rowCount === 0) return res.status(404).json({ ok: false, error: "Token inválido" });
|
||||
<div id="loader" class="fixed inset-0 bg-white z-[100] flex flex-col items-center justify-center transition-opacity duration-500">
|
||||
<div class="relative w-16 h-16 flex items-center justify-center mb-4">
|
||||
<div class="absolute inset-0 border-4 border-slate-100 border-t-blue-600 rounded-full animate-spin"></div>
|
||||
<i data-lucide="star" class="w-6 h-6 text-blue-600 animate-pulse"></i>
|
||||
</div>
|
||||
<p class="text-xs font-black tracking-widest uppercase text-slate-400">Cargando promoción...</p>
|
||||
</div>
|
||||
|
||||
const client = clientQ.rows[0];
|
||||
const ownerId = client.owner_id;
|
||||
<main id="mainContent" class="hidden w-full max-w-lg mx-auto flex flex-col relative z-10 p-5 fade-in">
|
||||
|
||||
// 2. Buscamos el teléfono del administrador (tú) para avisarte
|
||||
const ownerQ = await pool.query("SELECT phone FROM users WHERE id = $1", [ownerId]);
|
||||
if (ownerQ.rowCount === 0) return res.status(404).json({ ok: false, error: "Empresa no encontrada" });
|
||||
<button onclick="goBack()" class="w-10 h-10 bg-white rounded-full flex items-center justify-center text-slate-600 shadow-sm border border-slate-200 active:scale-95 transition-transform mb-6">
|
||||
<i data-lucide="arrow-left" class="w-5 h-5"></i>
|
||||
</button>
|
||||
|
||||
const adminPhone = ownerQ.rows[0].phone;
|
||||
<div class="bg-white p-2 rounded-[2.5rem] shadow-sm border border-slate-100 mb-8">
|
||||
<div class="rounded-[2rem] overflow-hidden bg-slate-50 relative min-h-[200px] flex items-center justify-center">
|
||||
<img id="adImage" src="" alt="Promoción Especial" class="w-full h-auto hidden object-cover">
|
||||
<i id="adFallback" data-lucide="image" class="w-10 h-10 text-slate-300 hidden"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// 3. Montamos el mensaje de WhatsApp para el jefe
|
||||
const msgWa = `🎉 *¡NUEVO LEAD DE PUBLICIDAD!* 🎉\n\nEl cliente *${client.full_name}* ha pulsado el botón "Me interesa" en el banner de publicidad de su portal web.\n\n📞 *Teléfono:* ${client.phone}\n\n¡Llámale cuanto antes para informarle!`;
|
||||
<div class="text-center px-4 mb-10">
|
||||
<h1 class="text-2xl font-black tracking-tight text-slate-900 mb-3">¿Te interesa esta promoción?</h1>
|
||||
<p class="text-sm text-slate-500 font-medium">Pulsa el botón y nos pondremos en contacto contigo para darte todos los detalles sin ningún compromiso.</p>
|
||||
</div>
|
||||
|
||||
// 4. Enviamos el mensaje
|
||||
await sendWhatsAppAuto(adminPhone, msgWa, `cliente_${ownerId}`, false);
|
||||
<button id="btnInterest" onclick="sendInterest()" class="w-full bg-blue-600 text-white font-black py-4 rounded-2xl shadow-xl shadow-blue-500/30 flex items-center justify-center gap-2 uppercase tracking-widest text-xs active:scale-95 transition-all">
|
||||
<i data-lucide="thumbs-up" class="w-5 h-5"></i> ¡Me Interesa!
|
||||
</button>
|
||||
|
||||
res.json({ ok: true });
|
||||
} catch (e) {
|
||||
console.error("Error al registrar interés en publicidad:", e);
|
||||
res.status(500).json({ ok: false });
|
||||
}
|
||||
});
|
||||
<div id="successMsg" class="hidden mt-6 bg-emerald-50 border border-emerald-100 p-5 rounded-2xl text-center">
|
||||
<div class="w-12 h-12 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<i data-lucide="check" class="w-6 h-6"></i>
|
||||
</div>
|
||||
<h3 class="font-black text-emerald-800 text-sm uppercase tracking-widest mb-1">Aviso Enviado</h3>
|
||||
<p class="text-xs text-emerald-600 font-medium">Hemos recibido tu solicitud. Te contactaremos muy pronto.</p>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const API_URL = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
||||
? 'http://localhost:3000'
|
||||
: 'https://integrarepara-api.integrarepara.es';
|
||||
|
||||
let urlToken = "";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
lucide.createIcons();
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
urlToken = urlParams.get('token');
|
||||
|
||||
if (!urlToken) {
|
||||
alert("Enlace no válido.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Pedimos los datos del portal para sacar la foto
|
||||
const res = await fetch(`${API_URL}/public/portal/${urlToken}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.ok && data.company && data.company.ad) {
|
||||
const img = document.getElementById('adImage');
|
||||
img.src = data.company.ad;
|
||||
img.classList.remove('hidden');
|
||||
} else {
|
||||
document.getElementById('adFallback').classList.remove('hidden');
|
||||
}
|
||||
|
||||
document.getElementById('loader').classList.add('opacity-0', 'pointer-events-none');
|
||||
setTimeout(() => {
|
||||
document.getElementById('loader').classList.add('hidden');
|
||||
document.getElementById('mainContent').classList.remove('hidden');
|
||||
}, 300);
|
||||
|
||||
} catch (e) {
|
||||
alert("Error de conexión.");
|
||||
}
|
||||
});
|
||||
|
||||
function goBack() {
|
||||
window.location.href = `index.html?token=${urlToken}`;
|
||||
}
|
||||
|
||||
async function sendInterest() {
|
||||
const btn = document.getElementById('btnInterest');
|
||||
btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Enviando...';
|
||||
btn.disabled = true;
|
||||
lucide.createIcons();
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/public/portal/${urlToken}/interest`, {
|
||||
method: 'POST'
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.ok) {
|
||||
btn.classList.add('hidden');
|
||||
document.getElementById('successMsg').classList.remove('hidden');
|
||||
document.getElementById('successMsg').classList.add('fade-in');
|
||||
} else {
|
||||
alert("No hemos podido enviar el aviso. Inténtalo de nuevo.");
|
||||
btn.innerHTML = '<i data-lucide="thumbs-up" class="w-5 h-5"></i> ¡Me Interesa!';
|
||||
btn.disabled = false;
|
||||
}
|
||||
} catch (e) {
|
||||
alert("Error de conexión.");
|
||||
btn.innerHTML = '<i data-lucide="thumbs-up" class="w-5 h-5"></i> ¡Me Interesa!';
|
||||
btn.disabled = false;
|
||||
}
|
||||
lucide.createIcons();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user