feat: Añadir modo de revisión y mejorar la retroalimentación en el panel

This commit is contained in:
Naiel
2026-02-24 12:17:26 +00:00
parent 09a9a95df0
commit 382e31158a
2 changed files with 51 additions and 102 deletions

View File

@@ -5,8 +5,6 @@ PAGES.pagos = {
icon: 'static/appico/credit_cards.png', icon: 'static/appico/credit_cards.png',
AccessControl: true, AccessControl: true,
Title: 'Pagos', Title: 'Pagos',
CajaCafeID: 'caja_cafe',
CajaCafeNombre: 'Caja Café',
__getVisiblePersonas: function () { __getVisiblePersonas: function () {
return Object.fromEntries( return Object.fromEntries(
@@ -14,70 +12,6 @@ PAGES.pagos = {
); );
}, },
__ensureCajaCafePersona: function () {
var cajaId = PAGES.pagos.CajaCafeID;
var cajaNombre = PAGES.pagos.CajaCafeNombre;
var existing = SC_Personas[cajaId];
if (existing && existing.Nombre === cajaNombre && existing.Oculto === true) {
return Promise.resolve(cajaId);
}
var data = {
Nombre: cajaNombre,
Region: 'Sistema',
Roles: '',
SC_Anilla: '',
markdown: 'Monedero interno de cafetería',
Monedero_Balance: parseFloat((existing && existing.Monedero_Balance) || 0) || 0,
Monedero_Notas: (existing && existing.Monedero_Notas) || '',
Oculto: true,
};
return DB.put('personas', cajaId, data)
.then(() => {
SC_Personas[cajaId] = data;
return cajaId;
})
.catch((e) => {
console.warn('DB.put error', e);
return null;
});
},
__creditCajaCafeForGasto: function (personaOrigenId, monto, callback) {
var cajaId = PAGES.pagos.CajaCafeID;
if (personaOrigenId === cajaId) {
if (callback) callback();
return;
}
PAGES.pagos.__ensureCajaCafePersona().then((resolvedCajaId) => {
if (!resolvedCajaId) {
if (callback) callback();
return;
}
var caja = SC_Personas[resolvedCajaId];
if (!caja) {
if (callback) callback();
return;
}
var currentBalance = parseFloat(caja.Monedero_Balance || 0);
caja.Monedero_Balance = fixfloat(currentBalance + monto);
DB.put('personas', resolvedCajaId, caja)
.then(() => {
if (callback) callback();
})
.catch((e) => {
console.warn('DB.put error', e);
if (callback) callback();
});
});
},
// Datafono view for creating/processing transactions // Datafono view for creating/processing transactions
datafono: function (prefilledData = {}) { datafono: function (prefilledData = {}) {
if (!checkRole('pagos:edit')) { if (!checkRole('pagos:edit')) {
@@ -104,8 +38,6 @@ PAGES.pagos = {
sessionStorage.removeItem('pagos_scanned_persona'); sessionStorage.removeItem('pagos_scanned_persona');
} }
PAGES.pagos.__ensureCajaCafePersona();
var field_tipo = safeuuid(); var field_tipo = safeuuid();
var field_monto = safeuuid(); var field_monto = safeuuid();
var field_persona = safeuuid(); var field_persona = safeuuid();
@@ -577,13 +509,7 @@ PAGES.pagos = {
var shouldUpdateBalance = !(tipo === 'Gasto' && metodo === 'Efectivo'); var shouldUpdateBalance = !(tipo === 'Gasto' && metodo === 'Efectivo');
function finalizeTransactionSave() { function finalizeTransactionSave() {
if (tipo === 'Gasto') {
PAGES.pagos.__creditCajaCafeForGasto(personaId, monto, () => {
saveTransaction(ticketId, transactionData); saveTransaction(ticketId, transactionData);
});
} else {
saveTransaction(ticketId, transactionData);
}
} }
if (shouldUpdateBalance) { if (shouldUpdateBalance) {
@@ -1017,14 +943,7 @@ PAGES.pagos = {
}); });
} else if (tipo === 'Gasto') { } else if (tipo === 'Gasto') {
revertWalletBalance(personaId, 'Ingreso', monto, () => { revertWalletBalance(personaId, 'Ingreso', monto, () => {
var cajaId = PAGES.pagos.CajaCafeID;
if (personaId === cajaId) {
deleteTransaction(tid); deleteTransaction(tid);
return;
}
revertWalletBalance(cajaId, 'Gasto', monto, () => {
deleteTransaction(tid);
});
}); });
} else if (tipo === 'Transferencia') { } else if (tipo === 'Transferencia') {
var destinoId = data.PersonaDestino; var destinoId = data.PersonaDestino;
@@ -1089,8 +1008,6 @@ PAGES.pagos = {
return; return;
} }
PAGES.pagos.__ensureCajaCafePersona();
var btn_datafono = safeuuid(); var btn_datafono = safeuuid();
var total_ingresos = safeuuid(); var total_ingresos = safeuuid();
var total_gastos = safeuuid(); var total_gastos = safeuuid();
@@ -1373,8 +1290,6 @@ PAGES.pagos = {
return; return;
} }
PAGES.pagos.__ensureCajaCafePersona();
var field_tipo = safeuuid(); var field_tipo = safeuuid();
var field_monto = safeuuid(); var field_monto = safeuuid();
var field_persona = safeuuid(); var field_persona = safeuuid();

View File

@@ -276,6 +276,8 @@ PAGES.panel = {
answers: {}, answers: {},
score: 0, score: 0,
feedback: '', feedback: '',
feedbackType: '',
reviewMode: false,
}; };
function saveResult() { function saveResult() {
@@ -299,16 +301,36 @@ PAGES.panel = {
.map((option, i) => { .map((option, i) => {
var oid = safeuuid(); var oid = safeuuid();
var checked = selected === option ? 'checked' : ''; var checked = selected === option ? 'checked' : '';
var disabled = state.reviewMode ? 'disabled' : '';
var optionStyle =
'display:block;margin: 8px 0;padding: 8px;border: 1px solid #ccc;border-radius: 6px;cursor:pointer;max-width: 150px;text-align: center;';
if (state.reviewMode) {
if (option === q.correct) {
optionStyle =
'display:block;margin: 8px 0;padding: 8px;border: 2px solid #2ed573;background:#eafff1;border-radius: 6px;cursor:pointer;max-width: 150px;text-align: center;';
} else if (option === selected && option !== q.correct) {
optionStyle =
'display:block;margin: 8px 0;padding: 8px;border: 2px solid #ff4757;background:#ffecec;border-radius: 6px;cursor:pointer;max-width: 150px;text-align: center;';
}
}
var optionContent = PAGES.panel.__renderOptionContent(q, option); var optionContent = PAGES.panel.__renderOptionContent(q, option);
return ` return `
<label class="panel-option" for="${oid}" style="display:block;margin: 8px 0;padding: 8px;border: 1px solid #ccc;border-radius: 6px;cursor:pointer;max-width: 150px;text-align: center;"> <label class="panel-option" for="${oid}" style="${optionStyle}">
<input id="${oid}" type="radio" name="panel-question" value="${option.replace(/"/g, '&quot;')}" ${checked} /> <input id="${oid}" type="radio" name="panel-question" value="${option.replace(/"/g, '&quot;')}" ${checked} ${disabled} />
${optionContent} ${optionContent}
</label> </label>
`; `;
}) })
.join(''); .join('');
var feedbackColor = '#555';
if (state.feedbackType === 'ok') feedbackColor = '#1f8f4a';
if (state.feedbackType === 'bad') feedbackColor = '#c0392b';
var nextButtonText = state.reviewMode ? 'Continuar' : 'Comprobar';
target.innerHTML = html` target.innerHTML = html`
<fieldset style="max-width: 800px;"> <fieldset style="max-width: 800px;">
<legend>Pregunta ${state.idx + 1} de ${questions.length}</legend> <legend>Pregunta ${state.idx + 1} de ${questions.length}</legend>
@@ -318,9 +340,9 @@ PAGES.panel = {
${ctx.comedor.postre || '—'} ${ctx.comedor.postre || '—'}
</small> </small>
<div style="margin-top: 10px; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px;">${optionsHtml}</div> <div style="margin-top: 10px; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px;">${optionsHtml}</div>
<div id="panel-feedback" style="margin-top: 12px;"><i>${state.feedback || ''}</i></div> <div id="panel-feedback" style="margin-top: 12px; color:${feedbackColor};"><i>${state.feedback || ''}</i></div>
<div style="margin-top: 12px; display:flex; gap:8px;"> <div style="margin-top: 12px; display:flex; gap:8px;">
<button class="btn5" id="panel-next">Comprobar y continuar</button> <button class="btn5" id="panel-next">${nextButtonText}</button>
<button id="panel-cancel">Salir</button> <button id="panel-cancel">Salir</button>
</div> </div>
</fieldset> </fieldset>
@@ -328,9 +350,26 @@ PAGES.panel = {
document.getElementById('panel-cancel').onclick = () => setUrlHash('index'); document.getElementById('panel-cancel').onclick = () => setUrlHash('index');
document.getElementById('panel-next').onclick = () => { document.getElementById('panel-next').onclick = () => {
if (state.reviewMode) {
state.reviewMode = false;
state.feedback = '';
state.feedbackType = '';
if (state.idx < questions.length - 1) {
state.idx++;
renderCurrent();
return;
}
saveResult();
renderFinal();
return;
}
var checked = document.querySelector('input[name="panel-question"]:checked'); var checked = document.querySelector('input[name="panel-question"]:checked');
if (!checked) { if (!checked) {
state.feedback = 'Selecciona una opción antes de continuar.'; state.feedback = 'Selecciona una opción antes de continuar.';
state.feedbackType = 'bad';
renderCurrent(); renderCurrent();
return; return;
} }
@@ -342,21 +381,14 @@ PAGES.panel = {
if (wasCorrect) { if (wasCorrect) {
state.score++; state.score++;
state.feedback = '✅ ' + q.ok; state.feedback = '✅ ' + q.ok;
state.feedbackType = 'ok';
} else { } else {
state.feedback = '❌ ' + q.bad + ' Respuesta esperada: ' + q.correct; state.feedback = '❌ ' + q.bad + ' Respuesta esperada: ' + q.correct;
state.feedbackType = 'bad';
} }
if (state.idx < questions.length - 1) { state.reviewMode = true;
state.idx++;
setTimeout(() => {
state.feedback = '';
renderCurrent(); renderCurrent();
}, 350);
return;
}
saveResult();
renderFinal();
}; };
} }
@@ -383,6 +415,8 @@ PAGES.panel = {
state.answers = {}; state.answers = {};
state.score = 0; state.score = 0;
state.feedback = ''; state.feedback = '';
state.feedbackType = '';
state.reviewMode = false;
renderCurrent(); renderCurrent();
}; };
document.getElementById('panel-home').onclick = () => setUrlHash('index'); document.getElementById('panel-home').onclick = () => setUrlHash('index');