Newer
Older
veriq / frontend / assets / result.js
/* VerIQ result page logic */
(function () {
  "use strict";
  var $ = function (id) { return document.getElementById(id); };

  function showError(msg) {
    $("errorArea").textContent = msg;
    $("errorArea").style.display = "";
    $("loading").style.display = "none";
  }

  var m = window.location.pathname.match(/^\/result\/([A-Za-z0-9]{8})$/);
  if (!m) { showError("Invalid result link."); return; }
  var rid = m[1];

  fetch("/api/result/" + rid).then(function (r) {
    if (!r.ok) return r.json().then(function (e) { throw new Error(e.detail || r.status); });
    return r.json();
  }).then(function (d) {
    $("loading").style.display = "none";
    $("resultArea").style.display = "";

    $("iqScore").textContent = d.iq;
    var pct = d.percentile;
    $("percentileLine").textContent =
      "higher than " + pct + "% of test takers" +
      (d.calibrated === false ? " · preliminary calibration" : "");

    var badges = $("badges");
    badges.innerHTML = "";
    var b1 = document.createElement("span");
    b1.className = "badge " + (d.signature_valid ? "ok" : "bad");
    b1.textContent = d.signature_valid ? "signature valid" : "SIGNATURE INVALID";
    badges.appendChild(b1);
    if (d.flagged) {
      var bf = document.createElement("span");
      bf.className = "badge warn";
      bf.textContent = "flagged: implausible timing";
      badges.appendChild(bf);
    }
    var b2 = document.createElement("span");
    b2.className = "badge";
    b2.textContent = "bank v" + d.bank_version;
    badges.appendChild(b2);
    var b3 = document.createElement("span");
    b3.className = "badge";
    b3.textContent = d.completed_at;
    badges.appendChild(b3);

    var cats = $("cats");
    cats.innerHTML = "";
    var order = ["numeric", "matrix", "verbal", "spatial"];
    order.forEach(function (k) {
      var c = (d.categories || {})[k];
      if (!c) return;
      var row = document.createElement("div");
      row.className = "catrow";
      var name = document.createElement("span");
      name.className = "name";
      name.textContent = k;
      var bar = document.createElement("span");
      bar.className = "bar";
      var fill = document.createElement("span");
      fill.style.display = "block";
      fill.style.height = "100%";
      fill.style.width = Math.round(100 * c.correct / c.total) + "%";
      fill.style.background = "var(--accent2)";
      bar.appendChild(fill);
      var val = document.createElement("span");
      val.className = "val";
      val.textContent = c.correct + "/" + c.total;
      row.appendChild(name); row.appendChild(bar); row.appendChild(val);
      cats.appendChild(row);
    });

    var link = window.location.origin + "/v/" + rid;
    $("verifyLink").value = link;
    $("copyBtn").addEventListener("click", function () {
      var inp = $("verifyLink");
      inp.select();
      try { document.execCommand("copy"); } catch (e) {}
      if (navigator.clipboard) navigator.clipboard.writeText(link);
      $("copyBtn").textContent = "Copied ✓";
      setTimeout(function () { $("copyBtn").textContent = "Copy"; }, 1500);
    });

    // claim buttons: ask backend for authorize_url, redirect; 503 -> hint
    function wireClaim(btnId, provider) {
      var btn = $(btnId);
      if (!btn) return;
      btn.addEventListener("click", function () {
        btn.disabled = true;
        fetch("/auth/" + provider + "/start?result_id=" + rid)
          .then(function (r) {
            if (r.status === 503) {
              throw new Error("not_configured");
            }
            if (!r.ok) throw new Error("http " + r.status);
            return r.json();
          })
          .then(function (data) {
            window.location.href = data.authorize_url;
          })
          .catch(function (e) {
            btn.disabled = false;
            var err = $("claimErr");
            err.style.display = "";
            if (e.message === "not_configured") {
              err.textContent = "Identity binding is being set up — " +
                "the service owner must register the X/Instagram apps first. " +
                "Your result is already signed and verifiable without it.";
            } else {
              err.textContent = "Claim failed: " + e.message;
            }
          });
      });
    }
    wireClaim("claimX", "x");
    wireClaim("claimIg", "ig");

    var msg = "My VerIQ score: " + d.iq +
      " (higher than " + pct + "%). Verify it: " + link;
    $("shareX").href = "https://twitter.com/intent/tweet?text=" +
      encodeURIComponent(msg);
    $("shareTg").href = "https://t.me/share/url?url=" +
      encodeURIComponent(link) + "&text=" +
      encodeURIComponent("My VerIQ score: " + d.iq + " — verify it yourself");
  }).catch(function (e) {
    showError("Could not load result: " + e.message);
  });
})();