06/05 Optimize app
This commit is contained in:
@@ -120,6 +120,13 @@
|
||||
{{ form.notes(class="form-control", rows=2, placeholder="Optional notes", id="field_notes") }}
|
||||
</div>
|
||||
|
||||
<!-- Duplicate warning -->
|
||||
<div id="dupe-banner" style="display:none;background:#fef9c3;border:1px solid #fcd34d;border-radius:8px;padding:8px 12px;margin-bottom:12px;font-size:12px;color:#854d0e;align-items:center;gap-8px;">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2" style="color:#d97706;"></i>
|
||||
<span id="dupe-text"></span>
|
||||
<button type="button" onclick="document.getElementById('dupe-banner').style.display='none';" style="background:none;border:none;font-size:14px;color:#854d0e;cursor:pointer;padding:0;margin-left:auto;">×</button>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" id="submitBtn"
|
||||
class="btn {% if txn_type=='income' %}btn-success{% else %}btn-danger{% endif %}">
|
||||
@@ -426,5 +433,39 @@ function setTxnType(type) {
|
||||
sel.value = prevVal;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Duplicate detection ───────────────────────────────────────────────────────
|
||||
{% if not txn %}
|
||||
const DUPE_EXCLUDE_ID = '';
|
||||
{% else %}
|
||||
const DUPE_EXCLUDE_ID = '{{ txn.id }}';
|
||||
{% endif %}
|
||||
|
||||
let _dupeTimer = null;
|
||||
function checkDuplicate() {
|
||||
const amt = document.getElementById('field_amount').value;
|
||||
const dt = document.getElementById('field_date').value;
|
||||
const typ = document.querySelector('[name=transaction_type]').value;
|
||||
const banner = document.getElementById('dupe-banner');
|
||||
if (!amt || !dt || parseFloat(amt) <= 0) { banner.style.display = 'none'; return; }
|
||||
clearTimeout(_dupeTimer);
|
||||
_dupeTimer = setTimeout(() => {
|
||||
const url = `/transactions/api/check-duplicate?date=${dt}&amount=${amt}&type=${typ}${DUPE_EXCLUDE_ID ? '&exclude_id=' + DUPE_EXCLUDE_ID : ''}`;
|
||||
fetch(url).then(r => r.json()).then(data => {
|
||||
if (data.duplicates && data.duplicates.length > 0) {
|
||||
const list = data.duplicates.map(d => `"${d.description}" on ${d.date}${d.account ? ' (' + d.account + ')' : ''}`).join('; ');
|
||||
document.getElementById('dupe-text').textContent = `Possible duplicate: ${list}`;
|
||||
banner.style.display = 'flex';
|
||||
} else {
|
||||
banner.style.display = 'none';
|
||||
}
|
||||
}).catch(() => {});
|
||||
}, 600);
|
||||
}
|
||||
|
||||
['field_amount', 'field_date'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.addEventListener('change', checkDuplicate);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user