crear apartado facturas

This commit is contained in:
Алекс 2026-01-27 18:51:20 +01:00
parent 3241c77646
commit 6408d3325b
3 changed files with 197 additions and 37 deletions

View File

@ -50,7 +50,6 @@ export function InvoiceItem(invoice) {
${getStatusText(invoice.status)} ${getStatusText(invoice.status)}
</span> </span>
</div> </div>
<div class="invoice-id">${invoice.id}</div>
<div class="invoice-client"> <div class="invoice-client">
<span class="client-icon">👤</span> <span class="client-icon">👤</span>
Cliente #${invoice.clientId} Cliente #${invoice.clientId}

View File

@ -4,6 +4,12 @@ export function renderFacturasPage() {
const container = document.createElement('div'); const container = document.createElement('div');
container.className = 'facturas-page'; container.className = 'facturas-page';
// Estado de paginación
let currentPage = 1;
let totalPages = 1;
const pageSize = 20;
let allInvoices = []; // Almacenar todas las facturas
container.innerHTML = /*html*/` container.innerHTML = /*html*/`
<div class="facturas-header"> <div class="facturas-header">
<h1>Facturas</h1> <h1>Facturas</h1>
@ -29,7 +35,6 @@ export function renderFacturasPage() {
</div> </div>
<div class="invoice-number">Número</div> <div class="invoice-number">Número</div>
<div class="invoice-status">Estado</div> <div class="invoice-status">Estado</div>
<div class="invoice-id">ID</div>
<div class="invoice-client">Cliente</div> <div class="invoice-client">Cliente</div>
<div class="invoice-date">Fecha</div> <div class="invoice-date">Fecha</div>
<div class="invoice-total">Total</div> <div class="invoice-total">Total</div>
@ -40,42 +45,81 @@ export function renderFacturasPage() {
<div class="loading">Cargando facturas...</div> <div class="loading">Cargando facturas...</div>
</div> </div>
</div> </div>
<div class="pagination">
<button class="btn-pagination btn-prev">← Anterior</button>
<div class="pagination-info">
<span class="current-page">1</span> / <span class="total-pages">1</span>
</div>
<button class="btn-pagination btn-next">Siguiente →</button>
</div>
`; `;
// Función para cargar las facturas // Función para renderizar la página actual
async function loadInvoices() { function renderPage(page = 1) {
const invoicesList = container.querySelector('.invoices-list');
currentPage = page;
totalPages = Math.ceil(allInvoices.length / pageSize);
// Calcular índices para la página
const startIndex = (page - 1) * pageSize;
const endIndex = Math.min(startIndex + pageSize, allInvoices.length);
const invoices = allInvoices.slice(startIndex, endIndex);
console.log(`Página ${currentPage}/${totalPages}, Facturas en esta página: ${invoices.length}, Total: ${allInvoices.length}`);
// Actualizar UI de paginación
updatePaginationUI();
// Limpiar lista
invoicesList.innerHTML = '';
// Si no hay facturas
if (invoices.length === 0) {
invoicesList.innerHTML = '<div class="no-invoices">No hay facturas disponibles</div>';
return;
}
// Renderizar cada factura
invoices.forEach(invoice => {
const invoiceItem = InvoiceItem(invoice);
invoicesList.appendChild(invoiceItem);
});
}
// Función para cargar todas las facturas
async function loadAllInvoices() {
const invoicesList = container.querySelector('.invoices-list'); const invoicesList = container.querySelector('.invoices-list');
try { try {
invoicesList.innerHTML = '<div class="loading">Cargando facturas...</div>';
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const response = await fetch(`${import.meta.env.VITE_API_BASE_URL}/api/Invoices`, { const response = await fetch(
method: 'GET', `${import.meta.env.VITE_API_BASE_URL}/api/Invoices`,
headers: { {
'Authorization': `Bearer ${token}`, method: 'GET',
'Content-Type': 'application/json' headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
} }
}); );
if (!response.ok) { if (!response.ok) {
throw new Error('Error al cargar facturas'); throw new Error('Error al cargar facturas');
} }
const invoices = await response.json(); const data = await response.json();
// Limpiar lista // Manejo de respuesta - obtener todas las facturas
invoicesList.innerHTML = ''; allInvoices = Array.isArray(data) ? data : data.data || data.invoices || [];
// Si no hay facturas console.log(`Total de facturas cargadas: ${allInvoices.length}`);
if (invoices.length === 0) {
invoicesList.innerHTML = '<div class="no-invoices">No hay facturas disponibles</div>'; // Renderizar la primera página
return; renderPage(1);
}
// Renderizar cada factura
invoices.forEach(invoice => {
const invoiceItem = InvoiceItem(invoice);
invoicesList.appendChild(invoiceItem);
});
} catch (error) { } catch (error) {
console.error('Error al cargar facturas:', error); console.error('Error al cargar facturas:', error);
@ -83,6 +127,21 @@ export function renderFacturasPage() {
} }
} }
// Función para actualizar la UI de paginación
function updatePaginationUI() {
const currentPageSpan = container.querySelector('.current-page');
const totalPagesSpan = container.querySelector('.total-pages');
const btnPrev = container.querySelector('.btn-prev');
const btnNext = container.querySelector('.btn-next');
currentPageSpan.textContent = currentPage;
totalPagesSpan.textContent = totalPages;
// Deshabilitar botones según corresponda
btnPrev.disabled = currentPage === 1;
btnNext.disabled = currentPage === totalPages;
}
// Event listeners // Event listeners
const newInvoiceBtn = container.querySelector('.btn-new-invoice'); const newInvoiceBtn = container.querySelector('.btn-new-invoice');
newInvoiceBtn.addEventListener('click', () => { newInvoiceBtn.addEventListener('click', () => {
@ -121,8 +180,31 @@ export function renderFacturasPage() {
}); });
}); });
// Cargar facturas al montar el componente // Event listeners de paginación
loadInvoices(); const btnPrev = container.querySelector('.btn-prev');
const btnNext = container.querySelector('.btn-next');
btnPrev.addEventListener('click', () => {
if (currentPage > 1) {
renderPage(currentPage - 1);
scrollToTop();
}
});
btnNext.addEventListener('click', () => {
if (currentPage < totalPages) {
renderPage(currentPage + 1);
scrollToTop();
}
});
// Función para scroll al inicio
function scrollToTop() {
container.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
// Cargar todas las facturas al montar el componente
loadAllInvoices();
return container; return container;
} }

View File

@ -229,22 +229,22 @@ button:focus-visible {
.status-pending { .status-pending {
background-color: #fef3c7; background-color: #fef3c7;
color: #d97706; color: #000000;
} }
.status-paid { .status-paid {
background-color: #d1fae5; background-color: #d1fae5;
color: #059669; color: #000000;
} }
.status-overdue { .status-overdue {
background-color: #fee2e2; background-color: #fee2e2;
color: #dc2626; color: #000000;
} }
.status-draft { .status-draft {
background-color: #f1f5f9; background-color: #f1f5f9;
color: #64748b; color: #000000;
} }
.amount-display { .amount-display {
@ -480,6 +480,7 @@ button:focus-visible {
border-radius: 8px; border-radius: 8px;
font-size: 0.95rem; font-size: 0.95rem;
background: var(--card-bg); background: var(--card-bg);
color: #000000;
} }
.search-input { .search-input {
@ -502,7 +503,7 @@ button:focus-visible {
.invoices-header, .invoices-header,
.invoice-item { .invoice-item {
display: grid; display: grid;
grid-template-columns: 40px 150px 120px 60px 150px 120px 120px 120px 80px; grid-template-columns: 40px 150px 120px 120px 120px 120px 120px 120px 80px;
gap: 1rem; gap: 1rem;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
align-items: center; align-items: center;
@ -552,27 +553,27 @@ button:focus-visible {
.status-draft { .status-draft {
background: #f3f4f6; background: #f3f4f6;
color: #6b7280; color: #000000;
} }
.status-validated { .status-validated {
background: #dbeafe; background: #dbeafe;
color: #1d4ed8; color: #000000;
} }
.status-paid { .status-paid {
background: #d1fae5; background: #d1fae5;
color: #059669; color: #000000;
} }
.status-unpaid { .status-unpaid {
background: #fee2e2; background: #fee2e2;
color: #dc2626; color: #000000;
} }
.status-canceled { .status-canceled {
background: #f3f4f6; background: #f3f4f6;
color: #374151; color: #000000;
text-decoration: line-through; text-decoration: line-through;
} }
@ -633,7 +634,85 @@ button:focus-visible {
color: var(--danger); color: var(--danger);
} }
/* Pagination Styles */
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
margin-top: 2rem;
padding: 1.5rem;
background: var(--card-bg);
border-radius: 12px;
border: 1px solid var(--border-color);
}
.pagination-info {
font-weight: 600;
color: var(--text-primary);
font-size: 1rem;
display: flex;
gap: 0.5rem;
align-items: center;
}
.pagination-info .current-page,
.pagination-info .total-pages {
font-weight: 700;
color: var(--primary);
min-width: 30px;
text-align: center;
}
.btn-pagination {
padding: 0.75rem 1.5rem;
background-color: var(--primary);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-pagination:hover:not(:disabled) {
background-color: var(--primary-hover);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
.btn-pagination:disabled {
background-color: #cbd5e1;
cursor: not-allowed;
opacity: 0.6;
}
.btn-pagination:active:not(:disabled) {
transform: translateY(0);
}
/* Responsive */ /* Responsive */
@media (max-width: 768px) {
.pagination {
flex-wrap: wrap;
gap: 1rem;
}
.btn-pagination {
flex: 1;
min-width: 120px;
}
.pagination-info {
order: 3;
width: 100%;
justify-content: center;
}
}
@media (max-width: 1400px) { @media (max-width: 1400px) {
.invoices-header, .invoices-header,
.invoice-item { .invoice-item {