ClauseGuard / extension /popup.js
gaurv007's picture
fix(popup.js): async sidePanel.open, add CRITICAL severity count, show session_id source
0a33acd verified
/**
* ClauseGuard — Popup Script v4.3
* Shows user status (logged in / guest), scan results, usage.
*
* FIXED v4.3: sidePanel.open() is properly awaited.
* FIXED v4.3: CRITICAL severity is now counted and displayed.
* FIXED v4.3: Shows scan source ("Legal-BERT" / "Local") accurately.
*/
document.addEventListener("DOMContentLoaded", async () => {
const resultsView = document.getElementById("results-view");
const emptyView = document.getElementById("empty-view");
const limitBanner = document.getElementById("limit-banner");
const userBar = document.getElementById("user-bar");
const userEmail = document.getElementById("user-email");
const userPlan = document.getElementById("user-plan");
const guestBar = document.getElementById("guest-bar");
let tab;
try { const [t] = await chrome.tabs.query({ active: true, currentWindow: true }); tab = t; } catch { return; }
if (!tab?.id) return;
// Load user info
let auth = null;
try { auth = await chrome.runtime.sendMessage({ type: "GET_USER" }); } catch {}
if (auth?.isLoggedIn) {
if (userBar) userBar.style.display = "flex";
if (guestBar) guestBar.style.display = "none";
if (userEmail) userEmail.textContent = auth.email || "User";
if (userPlan) {
userPlan.textContent = auth.plan?.toUpperCase() || "FREE";
userPlan.className = "plan-badge plan-" + (auth.plan || "free");
}
} else {
if (userBar) userBar.style.display = "none";
if (guestBar) guestBar.style.display = "flex";
}
// Check usage
let usage = null;
try { usage = await chrome.runtime.sendMessage({ type: "CHECK_USAGE" }); } catch {}
updateUsage(usage);
if (usage && !usage.allowed && limitBanner) limitBanner.style.display = "block";
// Load results
let results = null;
try { results = await chrome.runtime.sendMessage({ type: "GET_RESULTS", tabId: tab.id }); } catch {}
if (results && results.risk_score !== undefined) {
showResults(results);
} else {
if (emptyView) emptyView.style.display = "block";
if (resultsView) resultsView.style.display = "none";
}
// Scan button
const btnScan = document.getElementById("btn-scan");
if (btnScan) {
btnScan.addEventListener("click", async () => {
if (usage && !usage.allowed) { if (limitBanner) limitBanner.style.display = "block"; return; }
btnScan.textContent = "Scanning..."; btnScan.disabled = true;
try {
await chrome.tabs.sendMessage(tab.id, { type: "TRIGGER_SCAN" });
setTimeout(async () => {
try {
const r = await chrome.runtime.sendMessage({ type: "GET_RESULTS", tabId: tab.id });
if (r?.risk_score !== undefined) showResults(r);
} catch {}
try { usage = await chrome.runtime.sendMessage({ type: "CHECK_USAGE" }); updateUsage(usage); } catch {}
btnScan.textContent = "Scan this page"; btnScan.disabled = false;
}, 3000);
} catch { btnScan.textContent = "Error — refresh page"; btnScan.disabled = false; }
});
}
// Re-scan
const btnRescan = document.getElementById("btn-rescan");
if (btnRescan) btnRescan.addEventListener("click", async () => {
if (usage && !usage.allowed) { if (limitBanner) limitBanner.style.display = "block"; return; }
try { await chrome.tabs.sendMessage(tab.id, { type: "TRIGGER_SCAN" }); } catch {} window.close();
});
// FIX v4.3: Properly await async sidePanel.open() so errors are caught
const btnDetails = document.getElementById("btn-details");
if (btnDetails) btnDetails.addEventListener("click", async () => {
try { await chrome.sidePanel.open({ tabId: tab.id }); } catch(e) { console.warn("sidePanel.open failed:", e); }
window.close();
});
// Login button
const btnLogin = document.getElementById("btn-login");
if (btnLogin) btnLogin.addEventListener("click", () => {
chrome.tabs.create({ url: "https://clauseguardweb.netlify.app/auth/login" });
});
});
function showResults(results) {
const rv = document.getElementById("results-view");
const ev = document.getElementById("empty-view");
if (rv) rv.style.display = "block";
if (ev) ev.style.display = "none";
const el = (id) => document.getElementById(id);
if (el("risk-score")) el("risk-score").textContent = results.risk_score;
const grade = results.grade || "C";
const badge = el("grade-badge");
if (badge) { badge.className = "grade grade-" + grade.toLowerCase(); badge.textContent = "Grade " + grade; }
const bar = el("bar-fill");
if (bar) {
bar.style.width = results.risk_score + "%";
bar.className = "bar-fill " + (results.risk_score >= 60 ? "bar-red" : results.risk_score >= 30 ? "bar-amber" : "bar-green");
}
// FIX v4.3: Count CRITICAL severity too (backend can return it)
const counts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
(results.results || []).forEach(r => (r.categories || []).forEach(c => {
if (counts[c.severity] !== undefined) counts[c.severity]++;
else counts.MEDIUM++; // Unknown severities default to MEDIUM
}));
// Merge CRITICAL into HIGH for display (popup only has 3 columns)
if (el("c-high")) el("c-high").textContent = counts.CRITICAL + counts.HIGH;
if (el("c-med")) el("c-med").textContent = counts.MEDIUM;
if (el("c-low")) el("c-low").textContent = counts.LOW;
// Show source indicator
const src = el("scan-source");
if (src) src.textContent = results.source === "api" ? "Legal-BERT" : results.source === "local" ? "Local (offline)" : "";
}
function updateUsage(usage) {
if (!usage) return;
const text = document.getElementById("usage-text");
const fill = document.getElementById("usage-fill");
if (!text || !fill) return;
if (usage.plan === "free") {
text.textContent = usage.used + "/" + usage.limit + " scans";
const pct = Math.min(100, (usage.used / usage.limit) * 100);
fill.style.width = pct + "%";
if (pct >= 100) fill.style.background = "#ef4444";
else if (pct >= 70) fill.style.background = "#f59e0b";
} else {
text.textContent = "Unlimited";
fill.style.width = "100%"; fill.style.background = "#22c55e";
}
}