Update vcard_api.html

This commit is contained in:
Lizandro Guarnizo
2026-05-25 15:47:18 -05:00
parent c82831702e
commit c30abb58a6
+24 -23
View File
@@ -140,8 +140,8 @@
<button x-show="u.estado === true || u.estado === 'true'" @click="toggleUsuario(u, 'desactivar')" <button x-show="u.estado === true || u.estado === 'true'" @click="toggleUsuario(u, 'desactivar')"
class="text-red-400 hover:text-red-600 text-xs px-2 py-1 border border-red-200 rounded">Desactivar</button> class="text-red-400 hover:text-red-600 text-xs px-2 py-1 border border-red-200 rounded">Desactivar</button>
<button x-show="u.estado === true || u.estado === 'true'" @click="openDesactivarConVcardsModal(u)" <button x-show="u.estado === true || u.estado === 'true'" @click="openDesactivarConVcardsModal(u)"
class="text-orange-500 hover:text-orange-700 text-xs px-2 py-1 border border-orange-300 rounded" title="Desactiva usuario e inactiva todas sus VCards"> class="text-orange-500 hover:text-orange-700 text-xs px-2 py-1 border border-orange-300 rounded" title="Inactiva todas las VCards (sin desactivar usuario)">
🚫 + VCards 🚫 VCards
</button> </button>
<button @click="openMembresiaModal(u)" <button @click="openMembresiaModal(u)"
class="text-blue-500 hover:text-blue-700 text-xs px-2 py-1 border border-blue-200 rounded">Membresía</button> class="text-blue-500 hover:text-blue-700 text-xs px-2 py-1 border border-blue-200 rounded">Membresía</button>
@@ -1222,7 +1222,7 @@
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4"> <div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
<div class="flex justify-between items-center p-5 border-b"> <div class="flex justify-between items-center p-5 border-b">
<div> <div>
<h3 class="text-base font-semibold text-red-700">Desactivar usuario + VCards</h3> <h3 class="text-base font-semibold text-orange-700">Inactivar VCards del usuario</h3>
<p class="text-xs text-gray-500 mt-0.5" x-text="desactivarVcardsUser ? (desactivarVcardsUser.name || desactivarVcardsUser.email) : ''"></p> <p class="text-xs text-gray-500 mt-0.5" x-text="desactivarVcardsUser ? (desactivarVcardsUser.name || desactivarVcardsUser.email) : ''"></p>
</div> </div>
<button @click="desactivarVcardsModal = false" class="text-gray-400 hover:text-gray-600 text-xl"></button> <button @click="desactivarVcardsModal = false" class="text-gray-400 hover:text-gray-600 text-xl"></button>
@@ -1255,9 +1255,9 @@
</div> </div>
<!-- Sin vcards --> <!-- Sin vcards -->
<div x-show="!desactivarVcardsLoading && desactivarVcardsItems.length === 0" class="p-3 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-500"> <div x-show="!desactivarVcardsLoading && desactivarVcardsItems.length === 0" class="p-3 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-500">
Este usuario no tiene VCards. Solo se desactivará la cuenta. Este usuario no tiene VCards activas para inactivar.
</div> </div>
<p class="text-sm text-gray-700">¿Confirmas desactivar la cuenta del usuario y todas sus VCards?</p> <p class="text-sm text-gray-700">¿Confirmas inactivar todas las VCards de este usuario? <span class="text-orange-600 font-medium">El usuario permanecerá activo.</span></p>
<!-- Error --> <!-- Error -->
<div x-show="desactivarVcardsError" class="p-3 bg-red-50 border border-red-200 rounded text-sm text-red-600" x-text="desactivarVcardsError"></div> <div x-show="desactivarVcardsError" class="p-3 bg-red-50 border border-red-200 rounded text-sm text-red-600" x-text="desactivarVcardsError"></div>
<!-- Resultado --> <!-- Resultado -->
@@ -1266,11 +1266,11 @@
<div class="flex justify-end gap-3 px-5 pb-5"> <div class="flex justify-end gap-3 px-5 pb-5">
<button @click="desactivarVcardsModal = false" class="text-sm px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50">Cancelar</button> <button @click="desactivarVcardsModal = false" class="text-sm px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50">Cancelar</button>
<button @click="confirmarDesactivarConVcards()" :disabled="saving || desactivarVcardsLoading" <button @click="confirmarDesactivarConVcards()" :disabled="saving || desactivarVcardsLoading"
class="text-sm px-4 py-2 rounded-lg text-white bg-red-600 hover:bg-red-700 disabled:opacity-50 flex items-center gap-2"> class="text-sm px-4 py-2 rounded-lg text-white bg-orange-500 hover:bg-orange-600 disabled:opacity-50 flex items-center gap-2">
<svg x-show="saving" class="w-3.5 h-3.5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg x-show="saving" class="w-3.5 h-3.5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg> </svg>
<span x-text="saving ? 'Desactivando...' : 'Confirmar desactivación'"></span> <span x-text="saving ? 'Inactivando...' : 'Inactivar VCards'"></span>
</button> </button>
</div> </div>
</div> </div>
@@ -1584,7 +1584,7 @@ function vcardApiApp() {
knownPlans: [], // planes acumulados de todas las páginas cargadas knownPlans: [], // planes acumulados de todas las páginas cargadas
membresiaMap: {}, // { userId: { fecha_fin, activo, plan } } membresiaMap: {}, // { userId: { fecha_fin, activo, plan } }
// Desactivar usuario + VCards // Inactivar VCards del usuario (sin desactivar usuario)
desactivarVcardsModal: false, desactivarVcardsModal: false,
desactivarVcardsUser: null, desactivarVcardsUser: null,
desactivarVcardsItems: [], desactivarVcardsItems: [],
@@ -1592,6 +1592,9 @@ function vcardApiApp() {
desactivarVcardsError: '', desactivarVcardsError: '',
desactivarVcardsResult: '', desactivarVcardsResult: '',
// Cache acumulado de usuarios de todas las páginas (para filtro de planes)
allUsersCache: {},
// Filtros por tab // Filtros por tab
filters: { filters: {
pagos: { estado: '', moneda: '', desde: '', hasta: '' }, pagos: { estado: '', moneda: '', desde: '', hasta: '' },
@@ -1751,6 +1754,7 @@ function vcardApiApp() {
this.errorMsg = ''; this.errorMsg = '';
this.filterPlan = ''; this.filterPlan = '';
this.knownPlans = []; this.knownPlans = [];
this.allUsersCache = {};
if (this.hasConfig) this.loadTab(); if (this.hasConfig) this.loadTab();
}, },
@@ -1821,6 +1825,9 @@ function vcardApiApp() {
_collectPlanes(users) { _collectPlanes(users) {
users.forEach(u => { users.forEach(u => {
// Acumular en cache para filtrado cross-página
const uid = u.id || u._id;
if (uid) this.allUsersCache[uid] = u;
const nombre = (u.plan && u.plan.nombre) ? u.plan.nombre : ''; const nombre = (u.plan && u.plan.nombre) ? u.plan.nombre : '';
if (nombre && !this.knownPlans.includes(nombre)) { if (nombre && !this.knownPlans.includes(nombre)) {
this.knownPlans.push(nombre); this.knownPlans.push(nombre);
@@ -1924,7 +1931,9 @@ function vcardApiApp() {
usuariosFiltrados() { usuariosFiltrados() {
if (!this.filterPlan) return this.items; if (!this.filterPlan) return this.items;
return this.items.filter(u => ((u.plan && u.plan.nombre) || '') === this.filterPlan); // Filtrar desde el cache acumulado de TODAS las páginas cargadas
return Object.values(this.allUsersCache)
.filter(u => ((u.plan && u.plan.nombre) || '') === this.filterPlan);
}, },
// ─── Planes ────────────────────────────────────────────────────────── // ─── Planes ──────────────────────────────────────────────────────────
@@ -2033,9 +2042,8 @@ function vcardApiApp() {
this.desactivarVcardsError = ''; this.desactivarVcardsError = '';
this.desactivarVcardsResult = ''; this.desactivarVcardsResult = '';
this.saving = true; this.saving = true;
const id = this.desactivarVcardsUser.id || this.desactivarVcardsUser._id;
try { try {
// 1. Inactivar cada VCard activa // Solo inactivar cada VCard activa — no se toca al usuario
let inactivadas = 0; let inactivadas = 0;
const vcards = this.desactivarVcardsItems.filter(v => v.estado === true || v.estado === 1); const vcards = this.desactivarVcardsItems.filter(v => v.estado === true || v.estado === 1);
for (const v of vcards) { for (const v of vcards) {
@@ -2047,18 +2055,11 @@ function vcardApiApp() {
}); });
if (r.ok) inactivadas++; if (r.ok) inactivadas++;
} }
// 2. Desactivar usuario this.desactivarVcardsResult = `VCards inactivadas: ${inactivadas} de ${vcards.length}. El usuario sigue activo.`;
const rU = await fetch(`/app/vcard-api/usuarios/${id}/desactivar`, { method: 'POST' }); setTimeout(async () => {
const dU = await rU.json(); this.desactivarVcardsModal = false;
if (!rU.ok) { await this.loadTab();
this.desactivarVcardsError = dU.error || 'Error al desactivar el usuario.'; }, 1800);
} else {
this.desactivarVcardsResult = `Usuario desactivado. VCards inactivadas: ${inactivadas} de ${vcards.length}.`;
setTimeout(async () => {
this.desactivarVcardsModal = false;
await this.loadTab();
}, 1800);
}
} catch(e) { this.desactivarVcardsError = e.message; } } catch(e) { this.desactivarVcardsError = e.message; }
this.saving = false; this.saving = false;
}, },