From f5197b219c7e5b10519560ebb039294359590943 Mon Sep 17 00:00:00 2001 From: Rahul Date: Thu, 11 Jun 2026 00:00:09 +0530 Subject: [PATCH 1/2] feat : login page --- extension/background.js | 59 +- extension/content.js | 7 + extension/dashboard.js | 15 +- extension/popup.html | 1397 +++++++++++++++++++++++---------------- extension/popup.js | 121 +++- 5 files changed, 992 insertions(+), 607 deletions(-) diff --git a/extension/background.js b/extension/background.js index 3ce4bd2..4a6a53a 100644 --- a/extension/background.js +++ b/extension/background.js @@ -1,38 +1,45 @@ const API_BASE_URL = "https://leetcodeai-backend.onrender.com"; //const API_BASE_URL = "http://localhost:10000"; -function getUserEmail() { - return new Promise(resolve => { - chrome.storage.local.get({ userEmail: null }, ({ userEmail }) => resolve(userEmail)); - }); + +async function parseApiResponse(response) { + const data = await response.json().catch(() => ({})); + if (!response.ok) { + throw new Error(data.detail || data.message || `Request failed with status ${response.status}`); + } + return data; } -function getUserEmail() { - return new Promise(resolve => { - chrome.storage.local.get({ userEmail: null }, ({ userEmail }) => resolve(userEmail)); - }); +function authHeaders(userEmail, sessionToken) { + return { + "Content-Type": "application/json", + "X-User-Email": userEmail, + "Authorization": `Bearer ${sessionToken}` + }; } + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === 'GENERATE_BLOG') { - const { title, description, code, author, client_time, custom_prompt, difficulty } = request.payload; + const { title, description, code, author, client_time, custom_prompt, difficulty, language } = request.payload; chrome.storage.local.get({ publishingPlatforms: ['devto'], publishAsDraft: false, userEmail: null, - }, async ({ publishingPlatforms, publishAsDraft, userEmail }) => { - if (!userEmail) { - chrome.runtime.sendMessage({ type: 'STATUS_UPDATE', message: 'Please set your email in the extension settings before publishing.', status: 'error' }); + sessionToken: null, + }, async ({ publishingPlatforms, publishAsDraft, userEmail, sessionToken }) => { + if (!userEmail || !sessionToken) { + chrome.runtime.sendMessage({ type: 'STATUS_UPDATE', message: 'Please log in before publishing.', status: 'error' }); return; } fetch(`${API_BASE_URL}/generate-blog`, { method: "POST", - headers: { "Content-Type": "application/json", "X-User-Email": userEmail }, + headers: authHeaders(userEmail, sessionToken), body: JSON.stringify({ - title, description, code, author, client_time, custom_prompt, difficulty, + title, description, code, author, client_time, custom_prompt, difficulty, language, platforms: publishingPlatforms, publish_as_draft: publishAsDraft }) }) - .then(r => r.json()) + .then(parseApiResponse) .then(data => { if (data.status === 'success' || data.status === 'partial_success'){ const generatedBlog = @@ -54,15 +61,14 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { const platforms = data.data?.platforms || []; const postedPlatforms = platforms .filter(result => result.status === 'success') - .map(result => result.platform) - .join(', '); + .map(result => result.platform); const devtoResult = platforms.find(r => r.platform === 'devto' && r.status === 'success'); chrome.storage.local.get({ publishHistory: [] }, (res) => { const entry = { title: title, url: devtoResult?.url || null, publishedAt: client_time || new Date().toISOString(), - platforms: postedPlatforms ? postedPlatforms.split(', ').filter(p => p) : [] + platforms: postedPlatforms }; const history = res.publishHistory; history.unshift(entry); @@ -89,7 +95,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { fetch(`${API_BASE_URL}/dashboard/record`, { method: "POST", - headers: { "Content-Type": "application/json", "X-User-Email": userEmail }, + headers: authHeaders(userEmail, sessionToken), body: JSON.stringify(entry) }).catch(() => {}); chrome.runtime.sendMessage({ @@ -126,17 +132,18 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { publishingPlatforms: ['devto'], publishAsDraft: false, userEmail: null, + sessionToken: null, generatedProblemTitle: 'leetcode-blog' - }, async ({ publishingPlatforms, publishAsDraft, userEmail, generatedProblemTitle }) => { - if (!userEmail) { - const errMsg = 'Please set your email in the extension settings before publishing.'; + }, async ({ publishingPlatforms, publishAsDraft, userEmail, sessionToken, generatedProblemTitle }) => { + if (!userEmail || !sessionToken) { + const errMsg = 'Please log in before publishing.'; chrome.runtime.sendMessage({ type: 'STATUS_UPDATE', message: errMsg, status: 'error' }); sendResponse({ success: false, error: errMsg }); return; } fetch(`${API_BASE_URL}/publish-blog`, { method: "POST", - headers: { "Content-Type": "application/json", "X-User-Email": userEmail }, + headers: authHeaders(userEmail, sessionToken), body: JSON.stringify({ title: generatedProblemTitle, content: blog, @@ -145,7 +152,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { author: "Anonymous Developer" }) }) - .then(r => r.json()) + .then(parseApiResponse) .then(data => { if (data.status === 'success' || data.status === 'partial_success') { const platforms = data.data?.platforms || []; @@ -172,7 +179,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { fetch(`${API_BASE_URL}/dashboard/record`, { method: "POST", - headers: { "Content-Type": "application/json", "X-User-Email": userEmail }, + headers: authHeaders(userEmail, sessionToken), body: JSON.stringify(entry) }).catch(() => {}); @@ -207,4 +214,4 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }); return true; } -}); \ No newline at end of file +}); diff --git a/extension/content.js b/extension/content.js index 4f42905..a35b1be 100644 --- a/extension/content.js +++ b/extension/content.js @@ -55,6 +55,13 @@ document.querySelector('.ant-select-selection-item'); const language = langElement ? langElement.innerText.trim().toLowerCase() : "unknown"; + const difficultyElement = document.querySelector('[diff]') || + document.querySelector('div[class*="text-difficulty-"]') || + document.querySelector('span[class*="text-difficulty-"]'); + const difficulty = difficultyElement + ? (difficultyElement.getAttribute('diff') || difficultyElement.innerText || "").trim() + : null; + // Extract the user's LeetCode Username let author = "Anonymous LeetCoder"; const allLinks = document.querySelectorAll('a[href^="/u/"]'); diff --git a/extension/dashboard.js b/extension/dashboard.js index 71fc143..27b549e 100644 --- a/extension/dashboard.js +++ b/extension/dashboard.js @@ -26,13 +26,13 @@ function escapeHTML(str) { } document.addEventListener('DOMContentLoaded', () => { - chrome.storage.local.get({ userEmail: null }, ({ userEmail }) => { - if (!userEmail) { + chrome.storage.local.get({ userEmail: null, sessionToken: null }, ({ userEmail, sessionToken }) => { + if (!userEmail || !sessionToken) { showBanner('No email set — open the extension and enter your email first.'); return; } setLoading(true); - fetchStatsFromBackend(userEmail) + fetchStatsFromBackend(userEmail, sessionToken) .catch(() => { showBanner("Couldn't reach backend — showing local data."); return loadFromLocalStorage(userEmail); @@ -41,9 +41,12 @@ document.addEventListener('DOMContentLoaded', () => { }); }); -async function fetchStatsFromBackend(email) { +async function fetchStatsFromBackend(email, sessionToken) { const res = await fetch(`${API_BASE_URL}/dashboard/stats`, { - headers: { 'X-User-Email': email } + headers: { + 'X-User-Email': email, + 'Authorization': `Bearer ${sessionToken}` + } }); if (!res.ok) throw new Error('Bad response'); const { total_posts, platform_counts, week_activity, recent } = await res.json(); @@ -191,4 +194,4 @@ function renderHistory(history) {
${dateStr}
`; }).join(''); -} \ No newline at end of file +} diff --git a/extension/popup.html b/extension/popup.html index 5c9dbed..dd92330 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -1,607 +1,884 @@ - + - - + + LeetLog AI - + - - - + + +
-

👋 Welcome to LeetLog AI

-

Enter your email so your stats are saved separately from other users.

- - - +

Log in to LeetLog AI

+

+ Connect your account so generated blogs publish to the right user + profile. +

+ + +

+ +

+ New here? + +

- +
- Logged in as - + Logged in as +

LeetLog AI

-

Generate & publish stunning LeetCode blogs instantly.

- +

+ Generate & publish stunning LeetCode blogs instantly. +

+
- - + +
- Publish Destinations -
- - - - -
-
- -
- - + -
+ + -