feat(front) now can block
This commit is contained in:
+154
-13
@@ -130,7 +130,11 @@
|
||||
</div>
|
||||
|
||||
<div class="bg-zinc-900 border border-zinc-800 rounded-2xl p-4">
|
||||
<h3 class="font-bold text-lg mb-3">Lista de Sesiones</h3>
|
||||
<div class="flex justify-between items-center mb-3">
|
||||
<h3 class="font-bold text-lg">Lista de Sesiones</h3>
|
||||
</div>
|
||||
<input id="sessionSearch" placeholder="Buscar por teléfono, nombre o resumen..."
|
||||
class="w-full bg-zinc-950 border border-zinc-800 rounded-xl p-3 outline-none focus:ring-2 focus:ring-indigo-500 mb-3"/>
|
||||
<div id="sessionList" class="space-y-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -250,6 +254,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- BLOCK SESSION MODAL -->
|
||||
<!-- ========================= -->
|
||||
<div id="blockSessionModal" class="hidden fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div class="bg-zinc-900 border border-zinc-800 rounded-2xl max-w-sm w-full p-6 shadow-2xl text-center">
|
||||
<h2 class="text-xl font-bold mb-3">¿Bloquear Sesión?</h2>
|
||||
<p class="text-sm text-zinc-400 mb-6">¿Estás seguro de que quieres bloquear esta sesión? El número de teléfono será bloqueado.</p>
|
||||
|
||||
<input type="hidden" id="blockSessionId" />
|
||||
<input type="hidden" id="blockSessionPhone" />
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button id="confirmBlockSessionBtn" class="flex-1 bg-red-600 hover:bg-red-500 transition rounded-xl p-3 font-semibold text-white">Bloquear</button>
|
||||
<button id="cancelBlockSessionBtn" class="flex-1 bg-zinc-800 hover:bg-zinc-700 transition rounded-xl p-3 font-semibold text-white">Cancelar</button>
|
||||
</div>
|
||||
<div id="blockSessionMsg" class="text-sm mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// =============================
|
||||
// CONFIG
|
||||
@@ -564,6 +587,8 @@
|
||||
// sessions table must exist
|
||||
// columns: id, campaign_id, created_at, ip, user_agent, etc
|
||||
// =============================
|
||||
let allSessions = [];
|
||||
|
||||
async function loadSessions() {
|
||||
const campaignFilter = document.getElementById("sessionsCampaignFilter").value;
|
||||
|
||||
@@ -579,26 +604,43 @@
|
||||
|
||||
const { data, error } = await query;
|
||||
|
||||
if (error) {
|
||||
document.getElementById("sessionList").innerHTML = `<div class="text-red-400 text-sm">Error loading sessions: ${error.message}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
allSessions = data || [];
|
||||
renderSessions();
|
||||
}
|
||||
|
||||
function renderSessions() {
|
||||
const searchTerm = document.getElementById("sessionSearch").value.toLowerCase();
|
||||
const list = document.getElementById("sessionList");
|
||||
list.innerHTML = "";
|
||||
|
||||
if (error) {
|
||||
list.innerHTML = `<div class="text-red-400 text-sm">Error loading sessions: ${error.message}</div>`;
|
||||
let filtered = allSessions;
|
||||
if (searchTerm) {
|
||||
filtered = allSessions.filter(s =>
|
||||
(s.phone && s.phone.toLowerCase().includes(searchTerm)) ||
|
||||
(s.name && s.name.toLowerCase().includes(searchTerm)) ||
|
||||
(s.summary && s.summary.toLowerCase().includes(searchTerm))
|
||||
);
|
||||
}
|
||||
|
||||
if (filtered.length === 0) {
|
||||
list.innerHTML = `<div class="text-zinc-400 text-sm">${allSessions.length === 0 ? "No sessions found." : "No sessions match the search."}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
list.innerHTML = `<div class="text-zinc-400 text-sm">No sessions found.</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
data.forEach(s => {
|
||||
filtered.forEach(s => {
|
||||
const card = document.createElement("div");
|
||||
card.className = "bg-zinc-950 border border-zinc-800 rounded-2xl p-4";
|
||||
|
||||
const statusClass = s.finished ? "bg-green-500/20 text-green-500" : "bg-amber-500/20 text-amber-500";
|
||||
const statusText = s.finished ? "Finished" : "Active";
|
||||
|
||||
const blockedBadge = s.block ? `<span class="text-[10px] px-2 py-0.5 rounded-full font-bold uppercase bg-red-500/20 text-red-500">Blocked</span>` : '';
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="w-full">
|
||||
@@ -610,9 +652,22 @@
|
||||
<div class="text-[10px] px-2 py-0.5 rounded-full font-bold uppercase ${statusClass}">
|
||||
${statusText}
|
||||
</div>
|
||||
<button class="deleteSessionBtn bg-red-500/20 hover:bg-red-500/40 text-red-400 p-1.5 rounded-lg transition" data-id="${s.id}" data-phone="${s.phone}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-3.5 h-3.5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.134-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.067-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg>
|
||||
${blockedBadge}
|
||||
<div class="relative">
|
||||
<button class="sessionMenuBtn bg-zinc-800 hover:bg-zinc-700 p-1.5 rounded-lg transition" data-id="${s.id}" data-phone="${s.phone}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="sessionMenu hidden absolute right-0 top-full mt-1 bg-zinc-900 border border-zinc-800 rounded-xl shadow-xl z-10 min-w-[140px] overflow-hidden">
|
||||
<button class="blockSessionItem w-full text-left px-4 py-2.5 text-sm hover:bg-zinc-800 transition text-red-400" data-id="${s.id}" data-phone="${s.phone}">
|
||||
${s.block ? 'Desbloquear' : 'Bloquear'}
|
||||
</button>
|
||||
<button class="deleteSessionItem w-full text-left px-4 py-2.5 text-sm hover:bg-zinc-800 transition text-red-400 border-t border-zinc-800" data-id="${s.id}" data-phone="${s.phone}">
|
||||
Eliminar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-xs text-zinc-400 mt-2"><span class="font-semibold text-zinc-300">Summary:</span> ${s.summary || "No summary yet."}</div>
|
||||
@@ -629,17 +684,51 @@
|
||||
list.appendChild(card);
|
||||
});
|
||||
|
||||
list.querySelectorAll(".deleteSessionBtn").forEach(btn => {
|
||||
btn.addEventListener("click", () => {
|
||||
list.querySelectorAll(".sessionMenuBtn").forEach(btn => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const menu = btn.nextElementSibling;
|
||||
const wasHidden = menu.classList.contains("hidden");
|
||||
document.querySelectorAll(".sessionMenu").forEach(m => m.classList.add("hidden"));
|
||||
if (wasHidden) menu.classList.remove("hidden");
|
||||
});
|
||||
});
|
||||
|
||||
list.querySelectorAll(".deleteSessionItem").forEach(btn => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const phone = btn.dataset.phone;
|
||||
const id = btn.dataset.id;
|
||||
if (id && phone && phone !== 'unknown') {
|
||||
deleteSession(id, phone);
|
||||
}
|
||||
document.querySelectorAll(".sessionMenu").forEach(m => m.classList.add("hidden"));
|
||||
});
|
||||
});
|
||||
|
||||
list.querySelectorAll(".blockSessionItem").forEach(btn => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const phone = btn.dataset.phone;
|
||||
const id = btn.dataset.id;
|
||||
if (id && phone && phone !== 'unknown') {
|
||||
if (btn.textContent.trim() === 'Desbloquear') {
|
||||
unblockSession(id, phone);
|
||||
} else {
|
||||
openBlockModal(id, phone);
|
||||
}
|
||||
}
|
||||
document.querySelectorAll(".sessionMenu").forEach(m => m.classList.add("hidden"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", () => {
|
||||
document.querySelectorAll(".sessionMenu").forEach(m => m.classList.add("hidden"));
|
||||
});
|
||||
|
||||
document.getElementById("sessionSearch").addEventListener("input", renderSessions);
|
||||
|
||||
async function deleteSession(id, phone) {
|
||||
if (!confirm(`Delete session for ${phone} and all its chat history?`)) return;
|
||||
|
||||
@@ -666,6 +755,55 @@
|
||||
await loadSessions();
|
||||
}
|
||||
|
||||
function openBlockModal(id, phone) {
|
||||
document.getElementById("blockSessionId").value = id;
|
||||
document.getElementById("blockSessionPhone").value = phone;
|
||||
setMessage(document.getElementById("blockSessionMsg"), "");
|
||||
show(document.getElementById("blockSessionModal"));
|
||||
}
|
||||
|
||||
function closeBlockModal() {
|
||||
hide(document.getElementById("blockSessionModal"));
|
||||
}
|
||||
|
||||
async function confirmBlockSession() {
|
||||
const id = document.getElementById("blockSessionId").value;
|
||||
const phone = document.getElementById("blockSessionPhone").value;
|
||||
const msg = document.getElementById("blockSessionMsg");
|
||||
|
||||
setMessage(msg, "Bloqueando...");
|
||||
|
||||
const { error } = await supabaseClient
|
||||
.from("sessions")
|
||||
.update({ block: true })
|
||||
.eq("phone", phone);
|
||||
|
||||
if (error) {
|
||||
setMessage(msg, "Error: " + error.message, true);
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage(msg, "Sesión bloqueada!", false);
|
||||
closeBlockModal();
|
||||
await loadSessions();
|
||||
}
|
||||
|
||||
async function unblockSession(id, phone) {
|
||||
if (!confirm(`Desbloquear sesión para ${phone}?`)) return;
|
||||
|
||||
const { error } = await supabaseClient
|
||||
.from("sessions")
|
||||
.update({ block: false })
|
||||
.eq("phone", phone);
|
||||
|
||||
if (error) {
|
||||
alert("Error: " + error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
await loadSessions();
|
||||
}
|
||||
|
||||
// =============================
|
||||
// MEDIA UPLOAD
|
||||
// media table must exist
|
||||
@@ -894,6 +1032,9 @@
|
||||
document.getElementById("cancelDeleteMediaBtn").addEventListener("click", closeDeleteMediaModal);
|
||||
document.getElementById("confirmDeleteMediaBtn").addEventListener("click", confirmDeleteMedia);
|
||||
|
||||
document.getElementById("cancelBlockSessionBtn").addEventListener("click", closeBlockModal);
|
||||
document.getElementById("confirmBlockSessionBtn").addEventListener("click", confirmBlockSession);
|
||||
|
||||
setupTabs();
|
||||
|
||||
// Keep session state updated
|
||||
|
||||
Reference in New Issue
Block a user