193 lines
7.9 KiB
JavaScript
Executable File
193 lines
7.9 KiB
JavaScript
Executable File
import { renderDashboard } from './DashboardPage.js';
|
|
import { renderFacturasPage } from './Facturas.js';
|
|
import { renderCreateInvoicePage } from './CreateInvoicePage.js';
|
|
import { renderClientesPage } from './ClientesPage.js';
|
|
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,
|
|
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');
|
|
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);
|
|
}
|