diff --git a/src/components/InvoiceModal.js b/src/components/InvoiceModal.js index 6309be2..a28f140 100644 --- a/src/components/InvoiceModal.js +++ b/src/components/InvoiceModal.js @@ -109,7 +109,7 @@ export function InvoiceModal(invoiceId, onClose, onUpdate) {
- +
- +
- - + +
- - + +
diff --git a/src/pages/CreateInvoicePage.js b/src/pages/CreateInvoicePage.js index 4e9fe46..a91bef8 100644 --- a/src/pages/CreateInvoicePage.js +++ b/src/pages/CreateInvoicePage.js @@ -25,24 +25,34 @@ export function renderCreateInvoicePage() {
- - + +
+ + +
- - + +
+ + +
- +
- +
@@ -100,6 +110,14 @@ export function renderCreateInvoicePage() { expireDate.setDate(expireDate.getDate() + 30); container.querySelector('#expireDate').value = expireDate.toISOString().split('T')[0]; + // Event listeners para botones de calendario + container.querySelectorAll('.date-picker-btn').forEach(btn => { + btn.addEventListener('click', () => { + const targetInput = container.querySelector(`#${btn.dataset.target}`); + if (targetInput) targetInput.showPicker(); + }); + }); + let lineCounter = 0; function createInvoiceLine() { @@ -204,6 +222,41 @@ export function renderCreateInvoicePage() { return; } + // Validar fechas coherentes + const dateValue = container.querySelector('#date').value; + const expireDateValue = container.querySelector('#expireDate').value; + + function isValidDate(dateStr) { + if (!dateStr) return false; + const parts = dateStr.split('-'); + if (parts.length !== 3) return false; + const year = parseInt(parts[0]); + const month = parseInt(parts[1]); + const day = parseInt(parts[2]); + if (year < 2000 || year > 2100) return false; + if (month < 1 || month > 12) return false; + if (day < 1 || day > 31) return false; + const d = new Date(year, month - 1, day); + return d.getFullYear() === year && d.getMonth() === month - 1 && d.getDate() === day; + } + + if (!isValidDate(dateValue)) { + alert('La fecha de factura no es válida. Introduce una fecha entre los años 2000 y 2100.'); + return; + } + + if (!isValidDate(expireDateValue)) { + alert('La fecha de vencimiento no es válida. Introduce una fecha entre los años 2000 y 2100.'); + return; + } + + const dateObj = new Date(dateValue); + const expireDateObj = new Date(expireDateValue); + if (expireDateObj < dateObj) { + alert('La fecha de vencimiento no puede ser anterior a la fecha de factura.'); + return; + } + const formData = { clientId: clientIdValue, date: container.querySelector('#date').value + 'T00:00:00', diff --git a/src/pages/Facturas.js b/src/pages/Facturas.js index ddacb2c..55ff110 100755 --- a/src/pages/Facturas.js +++ b/src/pages/Facturas.js @@ -144,7 +144,7 @@ export function renderFacturasPage() { // Manejo de respuesta - obtener todas las facturas allInvoices = Array.isArray(data) ? data : data.data || data.invoices || []; - filteredInvoices = [...allInvoices]; + filteredInvoices = [...allInvoices].reverse(); console.log(`Total de facturas cargadas: ${allInvoices.length}`); diff --git a/src/style.css b/src/style.css index eeb527c..ec6d546 100755 --- a/src/style.css +++ b/src/style.css @@ -721,6 +721,57 @@ button:disabled { color: var(--text-primary); } +/* Notes column */ +.invoice-notes { + max-width: 200px; +} + +.notes-preview { + display: flex; + flex-direction: column; + gap: 4px; +} + +.note-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.75rem; + padding: 2px 8px; + border-radius: 12px; + line-height: 1.4; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: default; +} + +.note-public { + background: rgba(37, 99, 235, 0.08); + color: var(--primary); + border: 1px solid rgba(37, 99, 235, 0.15); +} + +.note-public svg { + flex-shrink: 0; +} + +.note-private { + background: rgba(245, 158, 11, 0.08); + color: #b45309; + border: 1px solid rgba(245, 158, 11, 0.15); +} + +.note-private svg { + flex-shrink: 0; +} + +.no-notes { + color: var(--text-secondary); + font-size: 0.875rem; +} + .invoice-actions { display: flex; gap: var(--space-1); @@ -939,6 +990,46 @@ button:disabled { box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); } +/* Date input wrapper */ +.date-input-wrapper { + position: relative; + display: flex; + align-items: stretch; +} + +.date-input-wrapper input[type="date"] { + flex: 1; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; +} + +.date-input-wrapper input[type="date"]:focus { + z-index: 1; +} + +.date-picker-btn { + display: flex; + align-items: center; + justify-content: center; + padding: 0 0.75rem; + background: var(--primary); + color: white; + border: 1px solid var(--primary); + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + cursor: pointer; + transition: background 0.2s; +} + +.date-picker-btn:hover { + background: var(--primary-hover, #1d4ed8); +} + +.date-picker-btn:active { + transform: scale(0.96); +} + .lines-section-compact { flex: 1; display: flex;