configuracion: sección perfil WhatsApp Business (foto, about, dirección, email, webs, categoría)

- wa_profile.php: GET carga perfil desde Graph API, POST guardar campos, POST foto sube imagen
- configuracion.php tab sesión: UI con foto de perfil editable, campos del negocio y botón guardar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-03 10:08:41 -05:00
co-authored by Claude Sonnet 4.6
parent eddfe4d16c
commit 707ef24572
2 changed files with 307 additions and 0 deletions
+155
View File
@@ -794,6 +794,87 @@ $tab = $_GET['tab'] ?? 'lugares';
</div>
</div>
<!-- Perfil de WhatsApp Business -->
<div class="mt-4">
<p class="section-title"><i class="fab fa-whatsapp me-1" style="color:#25d366"></i>Perfil de WhatsApp Business</p>
<div class="d-flex align-items-center gap-3 mb-3">
<!-- Foto de perfil -->
<div style="position:relative;flex-shrink:0">
<img id="wa-perfil-foto" src="" alt="Foto perfil"
style="width:80px;height:80px;border-radius:50%;object-fit:cover;
border:2px solid #dee2e6;background:#f1f5f9;display:none">
<div id="wa-perfil-foto-placeholder"
style="width:80px;height:80px;border-radius:50%;background:#e2e8f0;
display:flex;align-items:center;justify-content:center;font-size:2rem">
<i class="fab fa-whatsapp" style="color:#25d366"></i>
</div>
<label title="Cambiar foto" style="position:absolute;bottom:0;right:0;
background:#25d366;color:#fff;border-radius:50%;width:26px;height:26px;
display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:.8rem">
<i class="fas fa-camera"></i>
<input type="file" id="wa-foto-input" accept="image/jpeg,image/png"
style="display:none" onchange="subirFotoPerfil(this)">
</label>
</div>
<div class="flex-grow-1">
<div class="fw-semibold" id="wa-perfil-nombre" style="font-size:.95rem">—</div>
<div class="text-muted small" id="wa-perfil-about">—</div>
<button class="btn btn-outline-secondary btn-sm mt-1" onclick="cargarPerfilWA()">
<i class="fas fa-sync-alt me-1"></i>Cargar perfil actual
</button>
</div>
</div>
<div class="row g-2">
<div class="col-12">
<label class="form-label small fw-semibold">Descripción corta (About) <small class="text-muted fw-normal">máx. 139 chars</small></label>
<input type="text" id="wa-about" maxlength="139" class="form-control form-control-sm"
placeholder="Ej: Laboratorio clínico · Lunes a Sábado 7am-5pm">
</div>
<div class="col-12">
<label class="form-label small fw-semibold">Descripción del negocio</label>
<textarea id="wa-description" rows="2" class="form-control form-control-sm"
placeholder="Descripción completa del laboratorio…"></textarea>
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold">Dirección</label>
<input type="text" id="wa-address" class="form-control form-control-sm"
placeholder="Calle 5 #12-34, Cúcuta">
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold">Email</label>
<input type="email" id="wa-email" class="form-control form-control-sm"
placeholder="contacto@laboratorio.com">
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold">Sitio web 1</label>
<input type="url" id="wa-web1" class="form-control form-control-sm"
placeholder="https://www.laboratorio.com">
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold">Sitio web 2 <small class="text-muted fw-normal">(opcional)</small></label>
<input type="url" id="wa-web2" class="form-control form-control-sm"
placeholder="https://instagram.com/laboratorio">
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold">Categoría</label>
<select id="wa-vertical" class="form-select form-select-sm">
<option value="">— sin especificar —</option>
<option value="HEALTH">Salud</option>
<option value="MEDICAL_AND_HEALTH">Médico y Salud</option>
<option value="BEAUTY">Belleza</option>
<option value="EDUCATION">Educación</option>
<option value="OTHER">Otro</option>
</select>
</div>
</div>
<div class="d-flex justify-content-end mt-2">
<button class="btn btn-success btn-sm" onclick="guardarPerfilWA()">
<i class="fas fa-save me-1"></i>Guardar perfil
</button>
</div>
</div>
<!-- ════════════════════════════════════════
TAB 5 — PANTALLA TV
════════════════════════════════════════ -->
@@ -1179,6 +1260,80 @@ async function borrarTvVideo() {
} catch(e) { toast('Error de conexión', 'error'); }
}
async function cargarPerfilWA() {
try {
const res = await fetch(API + 'wa_profile.php');
const json = await res.json();
if (!json.ok) { toast(json.error || 'Error al cargar perfil', 'error'); return; }
const p = json.perfil || {};
if (p.profile_picture_url) {
document.getElementById('wa-perfil-foto').src = p.profile_picture_url;
document.getElementById('wa-perfil-foto').style.display = '';
document.getElementById('wa-perfil-foto-placeholder').style.display = 'none';
}
document.getElementById('wa-perfil-about').textContent = p.about || '—';
document.getElementById('wa-about').value = p.about || '';
document.getElementById('wa-description').value = p.description || '';
document.getElementById('wa-address').value = p.address || '';
document.getElementById('wa-email').value = p.email || '';
const webs = p.websites || [];
document.getElementById('wa-web1').value = webs[0] || '';
document.getElementById('wa-web2').value = webs[1] || '';
if (p.vertical) document.getElementById('wa-vertical').value = p.vertical;
toast('Perfil cargado');
} catch (e) { toast('Error de conexión', 'error'); }
}
async function guardarPerfilWA() {
const body = {
accion: 'guardar',
about: document.getElementById('wa-about').value.trim(),
description: document.getElementById('wa-description').value.trim(),
address: document.getElementById('wa-address').value.trim(),
email: document.getElementById('wa-email').value.trim(),
vertical: document.getElementById('wa-vertical').value,
websites: [document.getElementById('wa-web1').value.trim(),
document.getElementById('wa-web2').value.trim()].filter(Boolean),
};
try {
const res = await fetch(API + 'wa_profile.php', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const json = await res.json();
if (!json.ok) { toast(json.error || 'Error', 'error'); return; }
toast('Perfil de WhatsApp actualizado');
document.getElementById('wa-perfil-about').textContent = body.about || '—';
} catch (e) { toast('Error de conexión', 'error'); }
}
async function subirFotoPerfil(input) {
if (!input.files[0]) return;
const form = new FormData();
form.append('accion', 'foto');
form.append('foto', input.files[0]);
const btn = input.closest('label');
const orig = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
try {
const res = await fetch(API + 'wa_profile.php', { method: 'POST', body: form });
const json = await res.json();
if (!json.ok) { toast(json.error || 'Error al subir foto', 'error'); return; }
// Preview local
const reader = new FileReader();
reader.onload = e => {
document.getElementById('wa-perfil-foto').src = e.target.result;
document.getElementById('wa-perfil-foto').style.display = '';
document.getElementById('wa-perfil-foto-placeholder').style.display = 'none';
};
reader.readAsDataURL(input.files[0]);
toast('Foto de perfil actualizada');
} catch (e) { toast('Error al subir foto', 'error'); } finally {
btn.innerHTML = orig;
input.value = '';
}
}
async function guardarWhatsApp() {
const template = document.getElementById('wa-template')?.value.trim();
const templateMuestra = document.getElementById('wa-template-muestra')?.value.trim();