diff --git a/.gitignore b/.gitignore index 1b7917a..cd2e879 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ keepcode.zip -bugs.md \ No newline at end of file +bugs.md +TODO.md diff --git a/content.js b/content.js index 4bb1b3e..3a47e21 100644 --- a/content.js +++ b/content.js @@ -45,17 +45,24 @@ async function getProblemData() { function waitForContentAndStore() { const observer = new MutationObserver(async () => { const titleEl = document.querySelector("div"); - if (titleEl && titleEl.textContent.trim()) { + if (titleEl?.textContent.trim()) { observer.disconnect(); const data = await getProblemData(); if (!data) return; // Don't store invalid/undefined problems - browser.storage.local.set({ [data.slug]: data }).then(() => { - console.log("Saved to storage:", data); - }).catch((err) => { - console.error("Storage error:", err); + // Only update non-status fields, always preserve status/solvedAt + browser.storage.local.get(data.slug).then((existing) => { + const prev = existing[data.slug] || {}; + // Always preserve status and solvedAt if they exist + if (prev.status) data.status = prev.status; + if (prev.solvedAt) data.solvedAt = prev.solvedAt; + browser.storage.local.set({ [data.slug]: data }).then(() => { + console.log("Saved to storage (non-status fields updated):", data); + }).catch((err) => { + console.error("Storage error:", err); + }); + // Start watching for submission result after we have the slug + waitForSubmissionResult(data.slug); }); - // Start watching for submission result after we have the slug - waitForSubmissionResult(data.slug); } }); @@ -65,7 +72,7 @@ function waitForContentAndStore() { function waitForSubmissionResult(slug) { const observer = new MutationObserver(() => { const resultEl = document.querySelector('span[data-e2e-locator="submission-result"]'); - if (resultEl && resultEl.textContent.includes("Accepted")) { + if (resultEl?.textContent.includes("Accepted")) { console.log("✅ Accepted detected via submission result!"); browser.storage.local.get(slug).then((existing) => { diff --git a/manifest.json b/manifest.json index 4d11143..17fbb53 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 2, "name": "KeepCode", - "version": "0.2.0", - "description": "Focus on answering problems, let KeepCode handle the rest", + "version": "0.2.1", + "description": "Prep smarter for coding interviews: KeepCode tracks your LeetCode progress so you can focus on solving.", "permissions": ["storage", "tabs", "activeTab", "https://leetcode.com/*"], "background": { "scripts": ["background.js"], diff --git a/popup/popup.js b/popup/popup.js index 1cede5a..eff3df2 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -10,41 +10,53 @@ document.addEventListener("DOMContentLoaded", () => { return; } - browser.runtime - .sendMessage({ type: "GET_PROBLEM_DATA", slug }) - .then((data) => { - const container = document.getElementById("popupContent"); - if (!data) { - container.innerHTML = "

To track a problem please visit a leetcode problem page

"; - return; - } + const container = document.getElementById("popupContent"); - container.innerHTML = ""; - const titleEl = document.createElement("h3"); - titleEl.textContent = `Problem: ${data.title}`; - const diffEl = document.createElement("p"); - diffEl.textContent = `Difficulty: ${data.difficulty} `; - const statusEl = document.createElement("p"); - statusEl.id = "status"; - const strongEl = document.createElement("strong"); - strongEl.textContent = data.status || "Unsolved"; - statusEl.appendChild(strongEl); - container.appendChild(titleEl); - container.appendChild(diffEl); - container.appendChild(statusEl); - - // Listen for problem solved message - browser.runtime.onMessage.addListener((msg) => { - if (msg.type === "PROBLEM_SOLVED" && msg.slug === data.slug) { - const statusEl = document.getElementById("status"); - if (statusEl) statusEl.textContent = "Solved ✅"; - } - }); - }) - .catch((err) => { - document.getElementById("popupContent").innerHTML = "

Unable to read this page

"; - console.error(err); + browser.storage.local.get(slug).then((result) => { + let data = result[slug]; + if (data) { + renderCurrentProblem(data); + } else { + + browser.runtime + .sendMessage({ type: "GET_PROBLEM_DATA", slug }) + .then((data) => { + if (data) { + renderCurrentProblem(data); + } else { + container.innerHTML = "

To track a problem please visit a leetcode problem page

"; + } + }) + .catch((err) => { + container.innerHTML = "

Unable to read this page.

"; + console.error(err); + }); + } + }); + + function renderCurrentProblem(data) { + container.innerHTML = ""; + const titleEl = document.createElement("h3"); + titleEl.textContent = `Problem: ${data.title}`; + const diffEl = document.createElement("p"); + diffEl.textContent = `Difficulty: ${data.difficulty} `; + const statusEl = document.createElement("p"); + statusEl.id = "status"; + const strongEl = document.createElement("strong"); + strongEl.textContent = data.status || "Unsolved"; + statusEl.appendChild(strongEl); + container.appendChild(titleEl); + container.appendChild(diffEl); + container.appendChild(statusEl); + + // Listen for problem solved message + browser.runtime.onMessage.addListener((msg) => { + if (msg.type === "PROBLEM_SOLVED" && msg.slug === data.slug) { + const statusEl = document.getElementById("status"); + if (statusEl) statusEl.textContent = "Solved ✅"; + } }); + } }); }); @@ -62,10 +74,9 @@ document.addEventListener("DOMContentLoaded", () => { p.difficulty !== "Unknown Difficulty" && p.status === "Solved" ); - // Sort by solvedAt descending (most recent first) + problems.sort((a, b) => (b.solvedAt || 0) - (a.solvedAt || 0)); - // Collect all unique tags (flattened) const tagSet = new Set(); problems.forEach((p) => { if (Array.isArray(p.tags)) { @@ -94,7 +105,6 @@ document.addEventListener("DOMContentLoaded", () => { } } - // Render problems (filtered and limited) function renderProblems() { const list = document.getElementById("solvedList"); list.innerHTML = ""; @@ -115,7 +125,7 @@ document.addEventListener("DOMContentLoaded", () => { const difficultyClass = problem.difficulty ? problem.difficulty.toLowerCase() : ""; - // Use DOM methods instead of innerHTML for safety + const link = document.createElement("a"); link.href = problem.url; link.target = "_blank"; @@ -148,12 +158,11 @@ document.addEventListener("DOMContentLoaded", () => { renderProblems(); }); - // View All link opens options page const viewAllLink = document.getElementById("viewAllLink"); if (viewAllLink) { viewAllLink.addEventListener("click", (e) => { e.preventDefault(); - if (browser.runtime && browser.runtime.openOptionsPage) { + if (browser.runtime?.openOptionsPage) { browser.runtime.openOptionsPage(); } else { window.open("../options/options.html", "_blank"); @@ -166,10 +175,9 @@ document.addEventListener("DOMContentLoaded", () => { const optionsBtn = document.getElementById("optionsBtn"); if (optionsBtn) { optionsBtn.addEventListener("click", () => { - if (browser.runtime && browser.runtime.openOptionsPage) { + if (browser.runtime?.openOptionsPage) { browser.runtime.openOptionsPage(); } else { - // fallback for browsers that don't support openOptionsPage window.open("../options/options.html", "_blank"); } });