06/01 App enhanced
This commit is contained in:
@@ -304,6 +304,61 @@ function ocrExistingReceipt(filename) {
|
||||
});
|
||||
}
|
||||
|
||||
// ── Client-side form validation ───────────────────────────────────────────────
|
||||
document.getElementById('txnForm').addEventListener('submit', function(e) {
|
||||
let valid = true;
|
||||
|
||||
const desc = document.getElementById('field_description');
|
||||
if (!desc.value.trim()) {
|
||||
desc.classList.add('is-invalid');
|
||||
if (!desc.nextElementSibling || !desc.nextElementSibling.classList.contains('invalid-feedback')) {
|
||||
const err = document.createElement('div');
|
||||
err.className = 'invalid-feedback';
|
||||
err.textContent = 'Description is required.';
|
||||
desc.after(err);
|
||||
}
|
||||
valid = false;
|
||||
} else {
|
||||
desc.classList.remove('is-invalid');
|
||||
}
|
||||
|
||||
const amt = document.getElementById('field_amount');
|
||||
const amtVal = parseFloat(amt.value);
|
||||
const amtParent = amt.closest('.input-group') || amt;
|
||||
if (!amt.value || isNaN(amtVal) || amtVal <= 0) {
|
||||
amt.classList.add('is-invalid');
|
||||
let errEl = amtParent.parentElement.querySelector('.amt-error');
|
||||
if (!errEl) {
|
||||
errEl = document.createElement('div');
|
||||
errEl.className = 'text-danger mt-1 amt-error';
|
||||
errEl.style.fontSize = '12px';
|
||||
amtParent.after(errEl);
|
||||
}
|
||||
errEl.textContent = amtVal < 0 ? 'Amount must be positive.' : 'Amount is required.';
|
||||
valid = false;
|
||||
} else {
|
||||
amt.classList.remove('is-invalid');
|
||||
const errEl = amtParent.parentElement.querySelector('.amt-error');
|
||||
if (errEl) errEl.remove();
|
||||
}
|
||||
|
||||
const dt = document.getElementById('field_date');
|
||||
if (!dt.value) {
|
||||
dt.classList.add('is-invalid');
|
||||
valid = false;
|
||||
} else {
|
||||
dt.classList.remove('is-invalid');
|
||||
}
|
||||
|
||||
if (!valid) e.preventDefault();
|
||||
});
|
||||
|
||||
// Clear validation state on input
|
||||
['field_description', 'field_amount', 'field_date'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.addEventListener('input', () => el.classList.remove('is-invalid'));
|
||||
});
|
||||
|
||||
// ── Auto-OCR when receipt is selected in edit form ────────────────────────────
|
||||
function autoOcrOnUpload(input) {
|
||||
const file = input.files[0];
|
||||
|
||||
Reference in New Issue
Block a user