Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions Javascript/LeetCodeStats/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LeetMetric</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<!-- heading
user
stats -->
<h1>LeetMetric</h1>

<div class="user-container">
<p>Enter your username below:</p>
<div class="user-input-container">
<input
type="text"
placeholder="enter your username here"
id="user-input"
/>
<button id="search-btn">Search</button>
</div>
</div>

<div class="stats-container">
<div class="progress">
<div class="progress-item">
<div class="easy-progress circle">
<span id="easy-label"></span>
<p>Easy</p>
</div>
</div>

<div class="progress-item">
<div class="medium-progress circle">
<span id="medium-label"></span>
<p>Medium</p>
</div>
</div>

<div class="progress-item">
<div class="hard-progress circle">
<span id="hard-label"></span>
<p>Hard</p>
</div>
</div>
</div>

<div class="stats-cards">
<!-- directly populate card here from the JS code -->
</div>
</div>
</div>

<script src="script.js"></script>
</body>
</html>
39 changes: 39 additions & 0 deletions Javascript/LeetCodeStats/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 🧩 LeetCode User Stats Tracker

A simple web app that lets you fetch and visualize **LeetCode user statistics** such as total problems solved, difficulty-wise progress, and overall submissions — all displayed in a clean, LeetCode-themed UI.

---

## 🚀 Features

- 🔍 Search any LeetCode username
- 📊 Shows total, easy, medium, and hard problems solved
- 🧠 Displays total submission counts
- 🎨 Beautiful LeetCode-inspired UI
- 🔁 Uses LeetCode’s GraphQL API
- 🧰 Built with **HTML, CSS, and Vanilla JavaScript**

---

## ⚙️ How It Works

1. Enter a valid **LeetCode username** in the input box.
2. Click **Search**.
3. The app fetches live data from the [LeetCode GraphQL API](https://leetcode.com/graphql/) through a free **CORS proxy**.
4. The data is visualized using animated circular progress bars and submission cards.

---

## 🛠️ Setup & Usage
'''NOTE:
If the code fils to fetch data the go to "https://cors-anywhere.herokuapp.com/corsdemo" and request temperory access here for the code to work.


### 1. Clone or Download
```bash
git clone https://github.com/your-username/leetcode-stats-tracker.git
cd leetcode-stats-tracker




156 changes: 156 additions & 0 deletions Javascript/LeetCodeStats/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// https://cors-anywhere.herokuapp.com/corsdemo request temperory access here for the code to work

document.addEventListener("DOMContentLoaded", function () {
const searchButton = document.getElementById("search-btn");
const usernameInput = document.getElementById("user-input");
const statsContainer = document.querySelector(".stats-container");
const easyProgressCircle = document.querySelector(".easy-progress");
const mediumProgressCircle = document.querySelector(".medium-progress");
const hardProgressCircle = document.querySelector(".hard-progress");
const easyLabel = document.getElementById("easy-label");
const mediumLabel = document.getElementById("medium-label");
const hardLabel = document.getElementById("hard-label");
const cardStatsContainer = document.querySelector(".stats-cards");

//return true or false based on a regex
function validateUsername(username) {
if (username.trim() === "") {
alert("Username should not be empty");
return false;
}
const regex = /^[a-zA-Z0-9_-]{1,15}$/;
const isMatching = regex.test(username);
if (!isMatching) {
alert("Invalid Username");
}
return isMatching;
}

async function fetchUserDetails(username) {
try {
searchButton.textContent = "Searching...";
searchButton.disabled = true;
//statsContainer.classList.add("hidden");

// const response = await fetch(url);
const proxyUrl = "https://cors-anywhere.herokuapp.com/";
const targetUrl = "https://leetcode.com/graphql/";

const myHeaders = new Headers();
myHeaders.append("content-type", "application/json");

const graphql = JSON.stringify({
query:
"\n query userSessionProgress($username: String!) {\n allQuestionsCount {\n difficulty\n count\n }\n matchedUser(username: $username) {\n submitStats {\n acSubmissionNum {\n difficulty\n count\n submissions\n }\n totalSubmissionNum {\n difficulty\n count\n submissions\n }\n }\n }\n}\n ",
variables: { username: `${username}` },
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: graphql,
};

const response = await fetch(proxyUrl + targetUrl, requestOptions);
if (!response.ok) {
throw new Error("Unable to fetch the User details");
}
const parsedData = await response.json();
console.log("Logging data: ", parsedData);

displayUserData(parsedData);
} catch (error) {
statsContainer.innerHTML = `<p>${error.message}</p>`;
} finally {
searchButton.textContent = "Search";
searchButton.disabled = false;
}
}

function updateProgress(solved, total, label, circle) {
const progressDegree = (solved / total) * 100;
circle.style.setProperty("--progress-degree", `${progressDegree}%`);
label.textContent = `${solved}/${total}`;
}

function displayUserData(parsedData) {
const totalQues = parsedData.data.allQuestionsCount[0].count;
const totalEasyQues = parsedData.data.allQuestionsCount[1].count;
const totalMediumQues = parsedData.data.allQuestionsCount[2].count;
const totalHardQues = parsedData.data.allQuestionsCount[3].count;

const solvedTotalQues =
parsedData.data.matchedUser.submitStats.acSubmissionNum[0].count;
const solvedTotalEasyQues =
parsedData.data.matchedUser.submitStats.acSubmissionNum[1].count;
const solvedTotalMediumQues =
parsedData.data.matchedUser.submitStats.acSubmissionNum[2].count;
const solvedTotalHardQues =
parsedData.data.matchedUser.submitStats.acSubmissionNum[3].count;

updateProgress(
solvedTotalEasyQues,
totalEasyQues,
easyLabel,
easyProgressCircle
);
updateProgress(
solvedTotalMediumQues,
totalMediumQues,
mediumLabel,
mediumProgressCircle
);
updateProgress(
solvedTotalHardQues,
totalHardQues,
hardLabel,
hardProgressCircle
);

const cardsData = [
{
label: "Overall Submissions",
value:
parsedData.data.matchedUser.submitStats.totalSubmissionNum[0]
.submissions,
},
{
label: "Overall Easy Submissions",
value:
parsedData.data.matchedUser.submitStats.totalSubmissionNum[1]
.submissions,
},
{
label: "Overall Medium Submissions",
value:
parsedData.data.matchedUser.submitStats.totalSubmissionNum[2]
.submissions,
},
{
label: "Overall Hard Submissions",
value:
parsedData.data.matchedUser.submitStats.totalSubmissionNum[3]
.submissions,
},
];

console.log("card ka data: ", cardsData);

cardStatsContainer.innerHTML = cardsData
.map(
(data) =>
`<div class="card">
<h4>${data.label}</h4>
<p>${data.value}</p>
</div>`
)
.join("");
}

searchButton.addEventListener("click", function () {
const username = usernameInput.value;
console.log("logggin username: ", username);
if (validateUsername(username)) {
fetchUserDetails(username);
}
});
});
Loading
Loading