diff --git a/src/components/InvoiceModal.js b/src/components/InvoiceModal.js
index 1f5565d..d178182 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 dd75110..bb557a1 100755
--- a/src/pages/Facturas.js
+++ b/src/pages/Facturas.js
@@ -145,7 +145,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 5ad7f13..c967b4a 100755
--- a/src/style.css
+++ b/src/style.css
@@ -605,6 +605,57 @@ button:focus-visible {
font-weight: 600;
}
+/* 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: 0.5rem;
@@ -893,6 +944,46 @@ button:focus-visible {
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
+/* 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;