portfolio-edit: ticker validate on blur + duplicate warning
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f1b242720d
commit
ee6966399c
1 changed files with 84 additions and 0 deletions
|
|
@ -40,4 +40,88 @@
|
||||||
|
|
||||||
editBtn.addEventListener('click', enterEditMode);
|
editBtn.addEventListener('click', enterEditMode);
|
||||||
doneBtn.addEventListener('click', exitEditMode);
|
doneBtn.addEventListener('click', exitEditMode);
|
||||||
|
|
||||||
|
// ---- Ticker validation on blur -------------------------------------
|
||||||
|
|
||||||
|
const tickerInput = document.getElementById('pf-add-ticker');
|
||||||
|
const tickerStatus = document.getElementById('pf-add-ticker-status');
|
||||||
|
const costCurrencyEl = document.getElementById('pf-add-cost-currency');
|
||||||
|
const submitBtn = document.getElementById('pf-add-submit');
|
||||||
|
const warningEl = document.getElementById('pf-add-warning');
|
||||||
|
|
||||||
|
let validated = null; // {symbol, price, currency, as_of} or null
|
||||||
|
|
||||||
|
function setStatus(el, text, kind) {
|
||||||
|
el.textContent = text;
|
||||||
|
el.className = 'pf-add-status' + (kind ? ' pf-add-status--' + kind : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSubmitState() {
|
||||||
|
const qty = parseFloat(document.getElementById('pf-add-qty').value);
|
||||||
|
const cost = parseFloat(document.getElementById('pf-add-cost').value);
|
||||||
|
submitBtn.disabled = !(
|
||||||
|
validated && qty > 0 && cost > 0 && isFinite(qty) && isFinite(cost)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDuplicateWarning() {
|
||||||
|
warningEl.hidden = true;
|
||||||
|
warningEl.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDuplicateWarning(existing) {
|
||||||
|
warningEl.hidden = false;
|
||||||
|
warningEl.textContent =
|
||||||
|
`Already in your portfolio (${existing.qty} shares @ ` +
|
||||||
|
`${existing.avg_cost.toFixed(2)}). Adding will create a duplicate row.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateTicker() {
|
||||||
|
const raw = tickerInput.value.trim().toUpperCase();
|
||||||
|
if (!raw) {
|
||||||
|
validated = null;
|
||||||
|
setStatus(tickerStatus, '', '');
|
||||||
|
costCurrencyEl.textContent = '';
|
||||||
|
clearDuplicateWarning();
|
||||||
|
updateSubmitState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setStatus(tickerStatus, 'checking…', 'pending');
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/ticker/validate?symbol=' + encodeURIComponent(raw));
|
||||||
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||||
|
const j = await r.json();
|
||||||
|
if (j.ok) {
|
||||||
|
validated = j;
|
||||||
|
setStatus(
|
||||||
|
tickerStatus,
|
||||||
|
'✓ ' + j.price.toFixed(2) + ' ' + (j.currency || ''),
|
||||||
|
'ok',
|
||||||
|
);
|
||||||
|
costCurrencyEl.textContent = j.currency || '';
|
||||||
|
// Duplicate detection.
|
||||||
|
const pie = window.CassandraPortfolio.loadPie();
|
||||||
|
const existing = pie && (pie.positions || []).find(
|
||||||
|
p => (p.yahoo_ticker || '').toUpperCase() === j.symbol
|
||||||
|
);
|
||||||
|
if (existing) showDuplicateWarning(existing);
|
||||||
|
else clearDuplicateWarning();
|
||||||
|
} else {
|
||||||
|
validated = null;
|
||||||
|
setStatus(tickerStatus, '✗ ' + (j.error || 'not recognised'), 'err');
|
||||||
|
costCurrencyEl.textContent = '';
|
||||||
|
clearDuplicateWarning();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
validated = null;
|
||||||
|
setStatus(tickerStatus, '✗ couldn't validate — try again', 'err');
|
||||||
|
costCurrencyEl.textContent = '';
|
||||||
|
clearDuplicateWarning();
|
||||||
|
}
|
||||||
|
updateSubmitState();
|
||||||
|
}
|
||||||
|
|
||||||
|
tickerInput.addEventListener('blur', validateTicker);
|
||||||
|
document.getElementById('pf-add-qty').addEventListener('input', updateSubmitState);
|
||||||
|
document.getElementById('pf-add-cost').addEventListener('input', updateSubmitState);
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue