repos
/ finance-rust master

finance-rust

mirror archived upstream

Single-binary self-hosted market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, SEC filings, and SSE streaming.

axumdockerfinancerustself-hostedsqlitestocksvite

1.9 KB · 62 lines · JavaScript Raw History
 1// Dashboard watchlist editing (Phase C).
 2//
 3// Add and remove post to /api/watchlist; on success the page reloads so the
 4// server re-renders the cards, re-registers the live stream tickers, and the
 5// hero graph re-fetches with the new set. A brand-new symbol is validated and
 6// backfilled server-side before it returns, so the reloaded page is complete.
 7
 8async function post(url, ticker) {
 9  try {
10    const res = await fetch(url, {
11      method: "POST",
12      headers: { "Content-Type": "application/json" },
13      body: JSON.stringify({ ticker }),
14    });
15    return await res.json();
16  } catch {
17    return { ok: false, error: "Network error — try again." };
18  }
19}
20
21export function initWatchlist() {
22  const form = document.querySelector('[data-role="watch-add"]');
23  const msg = document.querySelector('[data-role="watch-msg"]');
24
25  function showMsg(text, isError) {
26    if (!msg) return;
27    msg.textContent = text;
28    msg.hidden = false;
29    msg.classList.toggle("is-error", !!isError);
30  }
31
32  if (form) {
33    form.addEventListener("submit", async (e) => {
34      e.preventDefault();
35      const input = form.querySelector('[name="ticker"]');
36      const ticker = (input.value || "").trim();
37      if (!ticker) return;
38      const btn = form.querySelector("button");
39      if (btn) btn.disabled = true;
40      showMsg("Adding " + ticker.toUpperCase() + "…", false);
41      const res = await post("/api/watchlist", ticker);
42      if (res.ok) {
43        location.reload();
44      } else {
45        if (btn) btn.disabled = false;
46        showMsg(res.error || "Could not add that symbol.", true);
47      }
48    });
49  }
50
51  document.querySelectorAll("[data-remove]").forEach((btn) => {
52    btn.addEventListener("click", async () => {
53      const ticker = btn.dataset.ticker;
54      if (!ticker) return;
55      btn.disabled = true;
56      const res = await post("/api/watchlist/remove", ticker);
57      if (res.ok) location.reload();
58      else btn.disabled = false;
59    });
60  });
61}