@@ -475,6 +826,34 @@ function vcardApiApp() {
membresiaError: '',
planes: [],
+ // Filtros por tab
+ filters: {
+ pagos: { estado: '', moneda: '', desde: '', hasta: '' },
+ transacciones: { type: '', status: '' },
+ logs: { type: '', desde: '', hasta: '' },
+ },
+
+ // Modal editar usuario
+ editUsuarioModal: false,
+ editUsuarioData: null,
+ editUsuarioForm: { name: '', email: '', rol_id: '', plan_id: '' },
+ editUsuarioError: '',
+ editUsuarioSuccess: false,
+
+ // Modal editar vcard
+ editVcardModal: false,
+ editVcardData: null,
+ editVcardForm: { nombre: '', cargo: '', descripcion: '', telefono: '', whatsapp: '', email: '', empresa: '', direccion: '', website: '', pais: '', ciudad: '', estado: true, privacidad: 'publica', es_borrador: false },
+ editVcardError: '',
+ editVcardSuccess: false,
+
+ // Drill-down por usuario
+ drillDownUserId: null,
+ drillDownSection: '',
+ drillDownItems: [],
+ drillDownLoading: false,
+ drillDownError: '',
+
get totalPages() {
return Math.max(1, Math.ceil(this.total / this.perPage));
},
@@ -485,6 +864,13 @@ function vcardApiApp() {
this.loadPlanes();
},
+ closeModals() {
+ this.configModal = false;
+ this.membresiaModal = false;
+ this.editUsuarioModal = false;
+ this.editVcardModal = false;
+ },
+
async loadConfig() {
try {
const r = await fetch('/app/vcard-api/config');
@@ -551,27 +937,43 @@ function vcardApiApp() {
this.items = [];
this.total = 0;
this.errorMsg = '';
+ this.closeDrillDown();
if (this.hasConfig) this.loadTab();
},
+ buildEndpoint() {
+ const qs = (p) => Object.entries(p).filter(([,v]) => v !== '').map(([k,v]) => `${k}=${encodeURIComponent(v)}`).join('&');
+ const base = {
+ usuarios: `/app/vcard-api/usuarios?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
+ vcards: `/app/vcard-api/vcards?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
+ planes: `/app/vcard-api/planes`,
+ pagos: `/app/vcard-api/pagos?per_page=${this.perPage}&page=${this.page}`,
+ transacciones: `/app/vcard-api/transacciones?per_page=${this.perPage}&page=${this.page}`,
+ logs: `/app/vcard-api/logs?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
+ miniwebs: `/app/vcard-api/miniwebs?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
+ };
+ let url = base[this.tab] || '';
+ if (this.tab === 'pagos') {
+ const f = qs(this.filters.pagos);
+ if (f) url += '&' + f;
+ } else if (this.tab === 'transacciones') {
+ const f = qs(this.filters.transacciones);
+ if (f) url += '&' + f;
+ } else if (this.tab === 'logs') {
+ const f = qs(this.filters.logs);
+ if (f) url += '&' + f;
+ }
+ return url;
+ },
+
async loadTab() {
if (!this.hasConfig) return;
this.loading = true;
this.errorMsg = '';
- const endpoints = {
- usuarios: `/app/vcard-api/usuarios?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
- vcards: `/app/vcard-api/vcards?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
- planes: `/app/vcard-api/planes`,
- pagos: `/app/vcard-api/pagos?per_page=${this.perPage}&page=${this.page}`,
- transacciones: `/app/vcard-api/transacciones?per_page=${this.perPage}&page=${this.page}`,
- logs: `/app/vcard-api/logs?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
- miniwebs: `/app/vcard-api/miniwebs?search=${encodeURIComponent(this.search)}&per_page=${this.perPage}&page=${this.page}`,
- };
try {
- const r = await fetch(endpoints[this.tab]);
+ const r = await fetch(this.buildEndpoint());
const d = await r.json();
if (!r.ok) { this.errorMsg = d.error || `Error ${r.status}`; this.loading = false; return; }
- // Laravel pagination o array plano
if (d.data && Array.isArray(d.data)) {
this.items = d.data;
this.total = d.total || d.data.length;
@@ -587,6 +989,14 @@ function vcardApiApp() {
this.loading = false;
},
+ clearFilters(tab) {
+ if (tab === 'pagos') this.filters.pagos = { estado: '', moneda: '', desde: '', hasta: '' };
+ if (tab === 'transacciones') this.filters.transacciones = { type: '', status: '' };
+ if (tab === 'logs') this.filters.logs = { type: '', desde: '', hasta: '' };
+ this.page = 1;
+ this.loadTab();
+ },
+
async loadPlanes() {
try {
const r = await fetch('/app/vcard-api/planes');
@@ -615,6 +1025,145 @@ function vcardApiApp() {
this.loading = false;
},
+ // ─── Edit Usuario ────────────────────────────────────────────────────
+
+ openEditUsuarioModal(u) {
+ this.editUsuarioData = u;
+ this.editUsuarioForm = {
+ name: u.name || u.nombre || '',
+ email: u.email || '',
+ rol_id: (u.rol && (u.rol.id || u.rol._id)) ? (u.rol.id || u.rol._id) : '',
+ plan_id: (u.plan && (u.plan.id || u.plan._id)) ? (u.plan.id || u.plan._id) : '',
+ };
+ this.editUsuarioError = '';
+ this.editUsuarioSuccess = false;
+ this.editUsuarioModal = true;
+ },
+
+ async saveEditUsuario() {
+ this.editUsuarioError = '';
+ this.editUsuarioSuccess = false;
+ if (!this.editUsuarioForm.name.trim() || !this.editUsuarioForm.email.trim()) {
+ this.editUsuarioError = 'Nombre y email son requeridos.'; return;
+ }
+ this.saving = true;
+ const id = this.editUsuarioData.id || this.editUsuarioData._id;
+ const body = {};
+ if (this.editUsuarioForm.name) body.name = this.editUsuarioForm.name;
+ if (this.editUsuarioForm.email) body.email = this.editUsuarioForm.email;
+ if (this.editUsuarioForm.rol_id) body.rol_id = this.editUsuarioForm.rol_id;
+ if (this.editUsuarioForm.plan_id) body.plan_id = this.editUsuarioForm.plan_id;
+ try {
+ const r = await fetch(`/app/vcard-api/usuarios/${id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body)
+ });
+ const d = await r.json();
+ if (!r.ok) {
+ this.editUsuarioError = d.error || d.message || `Error ${r.status}`;
+ } else {
+ this.editUsuarioSuccess = true;
+ await this.loadTab();
+ setTimeout(() => { this.editUsuarioModal = false; }, 1200);
+ }
+ } catch(e) { this.editUsuarioError = e.message; }
+ this.saving = false;
+ },
+
+ // ─── Edit VCard ──────────────────────────────────────────────────────
+
+ openEditVcardModal(v) {
+ this.editVcardData = v;
+ this.editVcardForm = {
+ nombre: v.nombre || '',
+ cargo: v.cargo || '',
+ descripcion: v.descripcion || '',
+ telefono: v.telefono || '',
+ whatsapp: v.whatsapp || '',
+ email: v.email || '',
+ empresa: v.empresa || '',
+ direccion: v.direccion || '',
+ website: v.website || '',
+ pais: v.pais || '',
+ ciudad: v.ciudad || '',
+ estado: !!v.estado,
+ privacidad: v.privacidad || 'publica',
+ es_borrador: !!v.es_borrador,
+ };
+ this.editVcardError = '';
+ this.editVcardSuccess = false;
+ this.editVcardModal = true;
+ },
+
+ async saveEditVcard() {
+ this.editVcardError = '';
+ this.editVcardSuccess = false;
+ this.saving = true;
+ const id = this.editVcardData.id || this.editVcardData._id;
+ try {
+ const r = await fetch(`/app/vcard-api/vcards/${id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(this.editVcardForm)
+ });
+ const d = await r.json();
+ if (!r.ok) {
+ this.editVcardError = d.error || d.message || `Error ${r.status}`;
+ } else {
+ this.editVcardSuccess = true;
+ await this.loadTab();
+ setTimeout(() => { this.editVcardModal = false; }, 1200);
+ }
+ } catch(e) { this.editVcardError = e.message; }
+ this.saving = false;
+ },
+
+ // ─── Drill-down por usuario ──────────────────────────────────────────
+
+ openDrillDown(u) {
+ const id = u.id || u._id;
+ if (this.drillDownUserId === id) { this.closeDrillDown(); return; }
+ this.drillDownUserId = id;
+ this.drillDownSection = 'vcards';
+ this.drillDownItems = [];
+ this.drillDownError = '';
+ this.loadDrillDown('vcards');
+ },
+
+ closeDrillDown() {
+ this.drillDownUserId = null;
+ this.drillDownSection = '';
+ this.drillDownItems = [];
+ this.drillDownError = '';
+ },
+
+ async loadDrillDown(section) {
+ this.drillDownSection = section;
+ this.drillDownItems = [];
+ this.drillDownError = '';
+ if (!this.drillDownUserId) return;
+ this.drillDownLoading = true;
+ const map = {
+ vcards: `/app/vcard-api/usuarios/${this.drillDownUserId}/vcards`,
+ pagos: `/app/vcard-api/usuarios/${this.drillDownUserId}/pagos`,
+ transacciones: `/app/vcard-api/usuarios/${this.drillDownUserId}/transacciones`,
+ logs: `/app/vcard-api/usuarios/${this.drillDownUserId}/logs`,
+ miniwebs: `/app/vcard-api/usuarios/${this.drillDownUserId}/miniwebs`,
+ };
+ try {
+ const r = await fetch(map[section]);
+ const d = await r.json();
+ if (!r.ok) { this.drillDownError = d.error || `Error ${r.status}`; }
+ else if (d.data && Array.isArray(d.data)) { this.drillDownItems = d.data; }
+ else if (Array.isArray(d)) { this.drillDownItems = d; }
+ else { this.drillDownError = 'Respuesta inesperada.'; }
+ } catch(e) { this.drillDownError = e.message; }
+ this.drillDownLoading = false;
+ },
+
+ // ─── Membresía ───────────────────────────────────────────────────────
+
async openMembresiaModal(u) {
this.membresiaUser = u;
this.membresiaInfo = null;