doli-front/src/pages/pagesRegistry.js

193 lines
7.9 KiB
JavaScript
Raw Normal View History

import { renderDashboard } from './DashboardPage.js';
2026-01-23 18:53:02 +00:00
import { renderFacturasPage } from './Facturas.js';
import { renderCreateInvoicePage } from './CreateInvoicePage.js';
import { renderClientesPage } from './ClientesPage.js';
2026-02-06 22:00:04 +00:00
import { authFetch } from '../services/auth.js';
import { showConfirmDialog } from '../components/ConfirmDialog.js';
import { showToast } from '../components/Toast.js';
// Registry of all pages available in the application
export const pagesRegistry = [
{
route: 'dashboard',
name: 'Dashboard',
icon: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>',
requiresAuth: true,
showInSidebar: true,
render: renderDashboard
},
{
route: 'invoices',
name: 'Facturas',
icon: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>',
requiresAuth: true,
showInSidebar: true,
2026-01-23 18:53:02 +00:00
render: renderFacturasPage
},
{
route: 'create-invoice',
name: 'Nueva Factura',
icon: '+',
requiresAuth: true,
showInSidebar: false, // No mostrar en sidebar
render: renderCreateInvoicePage
},
{
route: 'clients',
name: 'Clientes',
icon: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
requiresAuth: true,
showInSidebar: true,
render: renderClientesPage
},
{
route: 'settings',
name: 'Configuración',
icon: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v6m0 6v6M5.64 5.64l4.24 4.24m4.24 4.24l4.24 4.24M1 12h6m6 0h6M5.64 18.36l4.24-4.24m4.24-4.24l4.24-4.24"/></svg>',
requiresAuth: true,
showInSidebar: true,
render: () => {
const div = document.createElement('div');
2026-02-06 22:00:04 +00:00
div.className = 'settings-page';
const apiUrl = import.meta.env.VITE_API_BASE_URL || 'No configurada';
div.innerHTML = /*html*/`
<div class="settings-header">
<h1>Configuración</h1>
<p class="settings-subtitle">Ajustes de la aplicación y sesión</p>
</div>
<div class="settings-grid">
<!-- Sesión -->
<div class="settings-card">
<div class="settings-card-icon session-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
</div>
<h3>Sesión</h3>
<div class="settings-info">
<div class="settings-info-row">
<span>Estado:</span>
<span class="status-badge status-paid">Activa</span>
</div>
<div class="settings-info-row">
<span>Token:</span>
<span class="settings-token">${localStorage.getItem('token') ? '••••••••' + localStorage.getItem('token').slice(-8) : 'No disponible'}</span>
</div>
</div>
<button class="btn-settings btn-danger-settings" id="btn-logout">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
Cerrar Sesión
</button>
</div>
<!-- API -->
<div class="settings-card">
<div class="settings-card-icon api-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
</div>
<h3>Conexión API</h3>
<div class="settings-info">
<div class="settings-info-row">
<span>URL:</span>
<span class="settings-api-url">${apiUrl}</span>
</div>
<div class="settings-info-row">
<span>Estado:</span>
<span class="settings-api-status" id="api-status">Comprobando...</span>
</div>
</div>
<button class="btn-settings btn-outline-settings" id="btn-check-api">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
Comprobar Conexión
</button>
</div>
<!-- Acerca de -->
<div class="settings-card">
<div class="settings-card-icon about-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
</div>
<h3>Acerca de</h3>
<div class="settings-info">
<div class="settings-info-row">
<span>Aplicación:</span>
<strong>Doli App</strong>
</div>
<div class="settings-info-row">
<span>Versión:</span>
<span>1.0.0</span>
</div>
<div class="settings-info-row">
<span>Backend:</span>
<span>Dolibarr BFF</span>
</div>
</div>
</div>
</div>
`;
// Logout
div.querySelector('#btn-logout').addEventListener('click', async () => {
const confirmed = await showConfirmDialog({
title: '¿Cerrar sesión?',
message: 'Se cerrará tu sesión y tendrás que volver a iniciar sesión.',
confirmText: 'Cerrar sesión',
cancelText: 'Cancelar',
variant: 'warning'
});
if (confirmed) {
localStorage.removeItem('token');
window.location.hash = '#login';
window.location.reload();
}
});
// Check API
async function checkApi() {
const statusEl = div.querySelector('#api-status');
statusEl.textContent = 'Comprobando...';
statusEl.className = 'settings-api-status';
try {
const token = localStorage.getItem('token');
const res = await authFetch(`${apiUrl}/api/Invoices?limit=1`, {
headers: { 'Authorization': `Bearer ${token}` }
});
if (res.ok) {
statusEl.textContent = '✓ Conectado';
statusEl.classList.add('api-ok');
} else {
statusEl.textContent = '✗ Error ' + res.status;
statusEl.classList.add('api-error');
}
} catch {
statusEl.textContent = '✗ Sin conexión';
statusEl.classList.add('api-error');
}
}
div.querySelector('#btn-check-api').addEventListener('click', checkApi);
checkApi();
return div;
}
}
];
// Get pages that the user can access
export function getAvailablePages(isAuthenticated) {
if (!isAuthenticated) {
return [];
}
// Filter pages based on authentication requirement and sidebar visibility
return pagesRegistry.filter(page => {
if (page.requiresAuth && !isAuthenticated) return false;
return page.showInSidebar;
});
}
// Get page by route
export function getPageByRoute(route) {
return pagesRegistry.find(page => page.route === route);
}