From b59cb2f12289424233357c7d037bad89b929db10 Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Wed, 13 Aug 2025 09:09:34 -0600 Subject: [PATCH] feat(ui): redesign client form and enhance UI - Reverted to a dark/grey theme for UI elements. - Replaced text-based logout button with a red icon. - Redesigned the client form to a cleaner, single-column layout. - Added 'Gender' field to the client form. - Added a comprehensive section for 'Oncological Patient' status with conditional fields. - Updated client database schema and API to support new fields. - Standardized form input styles, including the telephone field. - Updated version in the footer to 0.3.0. --- ap-pos/app.js | 38 ++++++++- ap-pos/index.html | 91 ++++++++++++++++---- ap-pos/server.js | 30 ++++++- ap-pos/styles.css | 206 ++++++++++++++++++++++++++++------------------ 4 files changed, 265 insertions(+), 100 deletions(-) diff --git a/ap-pos/app.js b/ap-pos/app.js index 5b6eba2..66af944 100644 --- a/ap-pos/app.js +++ b/ap-pos/app.js @@ -115,12 +115,20 @@ async function saveClient(clientData) { } else { isUpdate = !!document.getElementById('c-id').value; const id = isUpdate ? document.getElementById('c-id').value : crypto.randomUUID(); + clientToSave = { id: id, nombre: document.getElementById('c-nombre').value, telefono: document.getElementById('c-telefono').value, + genero: document.getElementById('c-genero').value, cumpleaños: document.getElementById('c-cumple').value, consentimiento: document.getElementById('c-consent').checked, + esOncologico: document.getElementById('c-esOncologico').checked, + oncologoAprueba: document.getElementById('c-oncologoAprueba').checked, + nombreMedico: document.getElementById('c-nombreMedico').value, + telefonoMedico: document.getElementById('c-telefonoMedico').value, + cedulaMedico: document.getElementById('c-cedulaMedico').value, + pruebaAprobacion: document.getElementById('c-pruebaAprobacion').checked, }; } @@ -143,6 +151,7 @@ async function saveClient(clientData) { if (!clientData) { document.getElementById('formClient').reset(); document.getElementById('c-id').value = ''; + document.getElementById('oncologico-fields').classList.add('hidden'); } } @@ -445,9 +454,26 @@ function handleTableClick(e) { if (action === 'edit-client') { document.getElementById('c-id').value = client.id; document.getElementById('c-nombre').value = client.nombre; - document.getElementById('c-telefono').value = client.telefono; + document.getElementById('c-telefono').value = client.telefono || ''; + document.getElementById('c-genero').value = client.genero || ''; document.getElementById('c-cumple').value = client.cumpleaños; document.getElementById('c-consent').checked = client.consentimiento; + + // Campos oncológicos + const esOncologicoCheckbox = document.getElementById('c-esOncologico'); + const oncologicoFields = document.getElementById('oncologico-fields'); + esOncologicoCheckbox.checked = client.esOncologico; + if (client.esOncologico) { + oncologicoFields.classList.remove('hidden'); + } else { + oncologicoFields.classList.add('hidden'); + } + document.getElementById('c-oncologoAprueba').checked = client.oncologoAprueba; + document.getElementById('c-nombreMedico').value = client.nombreMedico || ''; + document.getElementById('c-telefonoMedico').value = client.telefonoMedico || ''; + document.getElementById('c-cedulaMedico').value = client.cedulaMedico || ''; + document.getElementById('c-pruebaAprobacion').checked = client.pruebaAprobacion; + } else if (action === 'delete-client') { deleteClient(id); } @@ -632,6 +658,16 @@ async function initializeApp() { document.getElementById('btnCancelEditClient')?.addEventListener('click', () => { formClient.reset(); document.getElementById('c-id').value = ''; + document.getElementById('oncologico-fields').classList.add('hidden'); + }); + + document.getElementById('c-esOncologico')?.addEventListener('change', (e) => { + const oncologicoFields = document.getElementById('oncologico-fields'); + if (e.target.checked) { + oncologicoFields.classList.remove('hidden'); + } else { + oncologicoFields.classList.add('hidden'); + } }); btnCancelEditUser?.addEventListener('click', (e) => { diff --git a/ap-pos/index.html b/ap-pos/index.html index 7bdab94..5796ba3 100644 --- a/ap-pos/index.html +++ b/ap-pos/index.html @@ -4,8 +4,15 @@ Ale Ponce | AlMa - - + + + + + + + + + @@ -14,12 +21,22 @@ - + @@ -114,20 +131,64 @@

Administrar Clientes

-
- +
+ - + + - + + + + + - +
- + +
+ +
+ +
-
+ + + + +
@@ -244,7 +305,7 @@ diff --git a/ap-pos/server.js b/ap-pos/server.js index c7ecf54..5dd95cf 100644 --- a/ap-pos/server.js +++ b/ap-pos/server.js @@ -82,7 +82,20 @@ db.serialize(() => { // Tablas existentes db.run(`CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT)`); - db.run(`CREATE TABLE IF NOT EXISTS clients (id TEXT PRIMARY KEY, nombre TEXT, telefono TEXT, cumpleaños TEXT, consentimiento INTEGER)`); + db.run(`CREATE TABLE IF NOT EXISTS clients ( + id TEXT PRIMARY KEY, + nombre TEXT, + telefono TEXT, + genero TEXT, + cumpleaños TEXT, + consentimiento INTEGER, + esOncologico INTEGER, + oncologoAprueba INTEGER, + nombreMedico TEXT, + telefonoMedico TEXT, + cedulaMedico TEXT, + pruebaAprobacion INTEGER + )`); db.run(`CREATE TABLE IF NOT EXISTS movements (id TEXT PRIMARY KEY, folio TEXT, fechaISO TEXT, clienteId TEXT, tipo TEXT, monto REAL, metodo TEXT, concepto TEXT, staff TEXT, notas TEXT, fechaCita TEXT, horaCita TEXT, FOREIGN KEY (clienteId) REFERENCES clients (id))`); }); @@ -211,9 +224,18 @@ apiRouter.get('/clients', (req, res) => { apiRouter.post('/clients', (req, res) => { const { client } = req.body; - const { id, nombre, telefono, cumpleaños, consentimiento } = client; - db.run(`INSERT OR REPLACE INTO clients (id, nombre, telefono, cumpleaños, consentimiento) VALUES (?, ?, ?, ?, ?)`, - [id, nombre, telefono, cumpleaños, consentimiento], function(err) { + const { + id, nombre, telefono, genero, cumpleaños, consentimiento, + esOncologico, oncologoAprueba, nombreMedico, telefonoMedico, cedulaMedico, pruebaAprobacion + } = client; + db.run(`INSERT OR REPLACE INTO clients ( + id, nombre, telefono, genero, cumpleaños, consentimiento, + esOncologico, oncologoAprueba, nombreMedico, telefonoMedico, cedulaMedico, pruebaAprobacion + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [ + id, nombre, telefono, genero, cumpleaños, consentimiento, + esOncologico, oncologoAprueba, nombreMedico, telefonoMedico, cedulaMedico, pruebaAprobacion + ], function(err) { if (err) { res.status(500).json({ error: err.message }); return; diff --git a/ap-pos/styles.css b/ap-pos/styles.css index 08532b3..4870f72 100644 --- a/ap-pos/styles.css +++ b/ap-pos/styles.css @@ -4,13 +4,13 @@ - Fondo: #f8f9fa (gris muy claro) - Texto principal: #212529 (casi negro) - Bordes/Divisores: #dee2e6 (gris claro) - - Botón primario: #343a40 (gris oscuro) - - Botón secundario: #6c757d (gris medio) + - Primario: #007bff (azul) + - Secundario: #6c757d (gris medio) */ -/* Estilos generales */ +/* Estilos generales y tipografías */ body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: 0; background-color: #f8f9fa; color: #212529; @@ -27,20 +27,22 @@ body { box-shadow: 0 4px 20px rgba(0,0,0,0.05); } -h1, h2 { +h1, h2, h3 { + font-family: 'Montserrat', sans-serif; + font-weight: 600; color: #212529; +} + +h2 { + font-size: 22px; border-bottom: 1px solid #dee2e6; padding-bottom: 12px; margin-top: 0; margin-bottom: 25px; } -h1 { - font-size: 28px; -} - -h2 { - font-size: 22px; +h3 { + font-size: 18px; } .section { @@ -56,29 +58,38 @@ h2 { } label { - font-weight: 500; + font-weight: 600; text-align: right; color: #495057; + font-size: 14px; } input[type="text"], +input[type="password"], input[type="number"], input[type="date"], input[type="time"], +input[type="tel"], select, textarea { width: 100%; - padding: 10px; + padding: 10px 12px; border: 1px solid #ced4da; border-radius: 5px; box-sizing: border-box; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + font-family: 'Open Sans', sans-serif; + font-size: 15px; } input:focus, select:focus, textarea:focus { border-color: #80bdff; outline: 0; box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); } +input:disabled { + background-color: #e9ecef; + cursor: not-allowed; +} button { background-color: #343a40; @@ -88,7 +99,8 @@ button { border-radius: 5px; cursor: pointer; font-size: 14px; - font-weight: 500; + font-family: 'Open Sans', sans-serif; + font-weight: 600; margin-right: 10px; transition: background-color 0.2s; } @@ -97,10 +109,10 @@ button:hover { background-color: #212529; } -button[type="reset"], button#btnTestTicket, #btnExport { +.btn-secondary, button[type="reset"], button#btnTestTicket, #btnExport { background-color: #6c757d; } -button[type="reset"]:hover, button#btnTestTicket:hover, #btnExport:hover, .btn-secondary:hover { +.btn-secondary:hover, button[type="reset"]:hover, button#btnTestTicket:hover, #btnExport:hover { background-color: #5a6268; } @@ -111,17 +123,26 @@ button[type="reset"]:hover, button#btnTestTicket:hover, #btnExport:hover, .btn-s background-color: #c82333; } -.form-actions button { - margin-right: 0; /* Remove right margin */ - margin-left: 10px; /* Add left margin for spacing */ +.btn-icon { + padding: 8px; + line-height: 1; + display: flex; + align-items: center; + justify-content: center; +} +.btn-icon .material-icons-outlined { + font-size: 20px; } .form-actions { - /* Empuja los botones a la derecha en el grid */ grid-column-start: 2; - margin-top: 20px; /* Aumentar espacio superior */ + margin-top: 20px; display: flex; - justify-content: flex-end; /* Alinea botones a la derecha */ + justify-content: flex-end; +} +.form-actions button { + margin-right: 0; + margin-left: 10px; } /* Tabla */ @@ -131,32 +152,36 @@ button[type="reset"]:hover, button#btnTestTicket:hover, #btnExport:hover, .btn-s border-radius: 5px; } -#tblMoves, #tblClients { +#tblMoves, #tblClients, #tblUsers { width: 100%; border-collapse: collapse; margin: 0; } #tblMoves th, #tblMoves td, -#tblClients th, #tblClients td { +#tblClients th, #tblClients td, +#tblUsers th, #tblUsers td { border-bottom: 1px solid #dee2e6; padding: 12px 15px; text-align: left; white-space: nowrap; } #tblMoves td:last-child, #tblMoves th:last-child, -#tblClients td:last-child, #tblClients th:last-child { +#tblClients td:last-child, #tblClients th:last-child, +#tblUsers td:last-child, #tblUsers th:last-child { text-align: center; } -#tblMoves th, #tblClients th { +#tblMoves th, #tblClients th, #tblUsers th { background-color: #f8f9fa; - font-weight: 600; + font-family: 'Montserrat', sans-serif; + font-weight: 500; border-bottom-width: 2px; } #tblMoves tbody tr:last-child td, -#tblClients tbody tr:last-child td { +#tblClients tbody tr:last-child td, +#tblUsers tbody tr:last-child td { border-bottom: none; } @@ -240,26 +265,48 @@ button.action-btn { border-bottom: 1px solid #dee2e6; } -.main-header h1 { - border-bottom: none; - margin-bottom: 0; - padding-bottom: 0; -} - -/* Logo en header */ -.main-header .header-logo { +.header-logo { height: 50px; width: auto; margin-right: 2rem; } -.main-header { +.tabs { + display: flex; + flex-grow: 1; +} + +.tab-link { display: flex; - justify-content: space-between; align-items: center; - margin-bottom: 1.5rem; - padding-bottom: 1rem; - border-bottom: 1px solid var(--color-border); + gap: 8px; + padding: 10px 20px; + cursor: pointer; + background: none; + border: none; + font-family: 'Montserrat', sans-serif; + font-weight: 500; + font-size: 16px; + color: #6c757d; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + transition: color 0.2s, border-color 0.2s; +} +.tab-link:hover { + color: #343a40; +} + +.tab-link.active { + color: #343a40; + border-bottom-color: #343a40; +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; } /* Dashboard Styles */ @@ -282,13 +329,14 @@ button.action-btn { margin: 0 0 0.5rem 0; font-size: 1rem; color: #555; + font-weight: 500; } .stat-card p { margin: 0; font-size: 2rem; - font-weight: bold; - color: var(--color-primary); + font-weight: 600; + color: #343a40; } .dashboard-chart { @@ -296,59 +344,48 @@ button.action-btn { padding: 1.5rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); - /* Fijar altura para evitar bucle infinito de redibujo de Chart.js */ position: relative; height: 300px; } - -.tabs { - display: flex; -} - -.tab-link { - padding: 10px 20px; - cursor: pointer; - background: none; - border: none; - font-size: 16px; - color: #6c757d; - border-bottom: 2px solid transparent; - margin-bottom: -1px; -} - -.tab-link.active { - color: #343a40; - border-bottom-color: #343a40; -} - -.tab-content { - display: none; -} - -.tab-content.active { - display: block; -} - /* --- Estilos específicos de Clientes --- */ -.client-grid { +.form-grid-single { display: grid; - grid-template-columns: 120px 1fr 120px 1fr; /* Dos columnas de etiquetas y campos */ - gap: 18px 12px; /* Espacio vertical y horizontal */ - align-items: center; + grid-template-columns: 1fr; + gap: 12px; +} +.form-grid-single label { + text-align: left; + margin-bottom: -5px; /* Acercar la etiqueta al campo */ +} +.form-grid-single input[type="tel"] { + max-width: 250px; +} +.form-grid-single .checkbox-container { + margin-top: 10px; +} +.form-grid-single .checkbox-container label { + font-weight: 400; /* Peso normal para checkboxes */ +} +.form-actions-single { + margin-top: 20px; + display: flex; + justify-content: flex-end; } -.client-grid .checkbox-container { - grid-column: 2 / span 3; /* El checkbox ocupa las columnas de la derecha */ +.checkbox-container { display: flex; align-items: center; } - .checkbox-container input[type="checkbox"] { width: auto; margin-right: 8px; } +.hidden { + display: none !important; +} + /* --- Estilos de Configuración --- */ .data-location-info { background-color: #e9ecef; @@ -361,6 +398,15 @@ button.action-btn { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; } +.sub-section { + margin-top: 30px; + padding-top: 20px; + border-top: 1px solid #e9ecef; +} +.sub-section h3 { + margin-top: 0; +} + /* --- Estilos del Pie de Página --- */ .main-footer-credits { text-align: center;