Skip to content

Commit 523ace8

Browse files
authored
LeetCodeStats
Program to check stats on leetcode using username only.
1 parent baa5347 commit 523ace8

File tree

3 files changed

+380
-0
lines changed

3 files changed

+380
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>LeetMetric</title>
7+
<link rel="stylesheet" href="style.css" />
8+
</head>
9+
<body>
10+
<div class="container">
11+
<!-- heading
12+
user
13+
stats -->
14+
<h1>LeetMetric</h1>
15+
16+
<div class="user-container">
17+
<p>Enter your username below:</p>
18+
<div class="user-input-container">
19+
<input
20+
type="text"
21+
placeholder="enter your username here"
22+
id="user-input"
23+
/>
24+
<button id="search-btn">Search</button>
25+
</div>
26+
</div>
27+
28+
<div class="stats-container">
29+
<div class="progress">
30+
<div class="progress-item">
31+
<div class="easy-progress circle">
32+
<span id="easy-label"></span>
33+
<p>Easy</p>
34+
</div>
35+
</div>
36+
37+
<div class="progress-item">
38+
<div class="medium-progress circle">
39+
<span id="medium-label"></span>
40+
<p>Medium</p>
41+
</div>
42+
</div>
43+
44+
<div class="progress-item">
45+
<div class="hard-progress circle">
46+
<span id="hard-label"></span>
47+
<p>Hard</p>
48+
</div>
49+
</div>
50+
</div>
51+
52+
<div class="stats-cards">
53+
<!-- directly populate card here from the JS code -->
54+
</div>
55+
</div>
56+
</div>
57+
58+
<script src="script.js"></script>
59+
</body>
60+
</html>

Javascript/LeetCodeStats/script.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// https://cors-anywhere.herokuapp.com/corsdemo request temperory access here for the code to work
2+
3+
document.addEventListener("DOMContentLoaded", function () {
4+
const searchButton = document.getElementById("search-btn");
5+
const usernameInput = document.getElementById("user-input");
6+
const statsContainer = document.querySelector(".stats-container");
7+
const easyProgressCircle = document.querySelector(".easy-progress");
8+
const mediumProgressCircle = document.querySelector(".medium-progress");
9+
const hardProgressCircle = document.querySelector(".hard-progress");
10+
const easyLabel = document.getElementById("easy-label");
11+
const mediumLabel = document.getElementById("medium-label");
12+
const hardLabel = document.getElementById("hard-label");
13+
const cardStatsContainer = document.querySelector(".stats-cards");
14+
15+
//return true or false based on a regex
16+
function validateUsername(username) {
17+
if (username.trim() === "") {
18+
alert("Username should not be empty");
19+
return false;
20+
}
21+
const regex = /^[a-zA-Z0-9_-]{1,15}$/;
22+
const isMatching = regex.test(username);
23+
if (!isMatching) {
24+
alert("Invalid Username");
25+
}
26+
return isMatching;
27+
}
28+
29+
async function fetchUserDetails(username) {
30+
try {
31+
searchButton.textContent = "Searching...";
32+
searchButton.disabled = true;
33+
//statsContainer.classList.add("hidden");
34+
35+
// const response = await fetch(url);
36+
const proxyUrl = "https://cors-anywhere.herokuapp.com/";
37+
const targetUrl = "https://leetcode.com/graphql/";
38+
39+
const myHeaders = new Headers();
40+
myHeaders.append("content-type", "application/json");
41+
42+
const graphql = JSON.stringify({
43+
query:
44+
"\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 ",
45+
variables: { username: `${username}` },
46+
});
47+
const requestOptions = {
48+
method: "POST",
49+
headers: myHeaders,
50+
body: graphql,
51+
};
52+
53+
const response = await fetch(proxyUrl + targetUrl, requestOptions);
54+
if (!response.ok) {
55+
throw new Error("Unable to fetch the User details");
56+
}
57+
const parsedData = await response.json();
58+
console.log("Logging data: ", parsedData);
59+
60+
displayUserData(parsedData);
61+
} catch (error) {
62+
statsContainer.innerHTML = `<p>${error.message}</p>`;
63+
} finally {
64+
searchButton.textContent = "Search";
65+
searchButton.disabled = false;
66+
}
67+
}
68+
69+
function updateProgress(solved, total, label, circle) {
70+
const progressDegree = (solved / total) * 100;
71+
circle.style.setProperty("--progress-degree", `${progressDegree}%`);
72+
label.textContent = `${solved}/${total}`;
73+
}
74+
75+
function displayUserData(parsedData) {
76+
const totalQues = parsedData.data.allQuestionsCount[0].count;
77+
const totalEasyQues = parsedData.data.allQuestionsCount[1].count;
78+
const totalMediumQues = parsedData.data.allQuestionsCount[2].count;
79+
const totalHardQues = parsedData.data.allQuestionsCount[3].count;
80+
81+
const solvedTotalQues =
82+
parsedData.data.matchedUser.submitStats.acSubmissionNum[0].count;
83+
const solvedTotalEasyQues =
84+
parsedData.data.matchedUser.submitStats.acSubmissionNum[1].count;
85+
const solvedTotalMediumQues =
86+
parsedData.data.matchedUser.submitStats.acSubmissionNum[2].count;
87+
const solvedTotalHardQues =
88+
parsedData.data.matchedUser.submitStats.acSubmissionNum[3].count;
89+
90+
updateProgress(
91+
solvedTotalEasyQues,
92+
totalEasyQues,
93+
easyLabel,
94+
easyProgressCircle
95+
);
96+
updateProgress(
97+
solvedTotalMediumQues,
98+
totalMediumQues,
99+
mediumLabel,
100+
mediumProgressCircle
101+
);
102+
updateProgress(
103+
solvedTotalHardQues,
104+
totalHardQues,
105+
hardLabel,
106+
hardProgressCircle
107+
);
108+
109+
const cardsData = [
110+
{
111+
label: "Overall Submissions",
112+
value:
113+
parsedData.data.matchedUser.submitStats.totalSubmissionNum[0]
114+
.submissions,
115+
},
116+
{
117+
label: "Overall Easy Submissions",
118+
value:
119+
parsedData.data.matchedUser.submitStats.totalSubmissionNum[1]
120+
.submissions,
121+
},
122+
{
123+
label: "Overall Medium Submissions",
124+
value:
125+
parsedData.data.matchedUser.submitStats.totalSubmissionNum[2]
126+
.submissions,
127+
},
128+
{
129+
label: "Overall Hard Submissions",
130+
value:
131+
parsedData.data.matchedUser.submitStats.totalSubmissionNum[3]
132+
.submissions,
133+
},
134+
];
135+
136+
console.log("card ka data: ", cardsData);
137+
138+
cardStatsContainer.innerHTML = cardsData
139+
.map(
140+
(data) =>
141+
`<div class="card">
142+
<h4>${data.label}</h4>
143+
<p>${data.value}</p>
144+
</div>`
145+
)
146+
.join("");
147+
}
148+
149+
searchButton.addEventListener("click", function () {
150+
const username = usernameInput.value;
151+
console.log("logggin username: ", username);
152+
if (validateUsername(username)) {
153+
fetchUserDetails(username);
154+
}
155+
});
156+
});

Javascript/LeetCodeStats/style.css

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
box-sizing: border-box;
5+
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
6+
}
7+
8+
body {
9+
background-color: #0f172a;
10+
color: #f1f5f9;
11+
height: 100vh;
12+
display: flex;
13+
justify-content: center;
14+
align-items: center;
15+
}
16+
17+
/* --- Container --- */
18+
.container {
19+
display: flex;
20+
flex-direction: column;
21+
gap: 1rem;
22+
background-color: #1e293b;
23+
padding: 25px;
24+
border-radius: 12px;
25+
width: 50%;
26+
max-width: 600px;
27+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
28+
}
29+
30+
/* --- Header --- */
31+
h1 {
32+
font-size: 2rem;
33+
color: #3a3a02;
34+
text-align: center;
35+
margin-bottom: 15px;
36+
}
37+
38+
/* --- User Input --- */
39+
.user-container {
40+
display: flex;
41+
flex-direction: column;
42+
gap: 10px;
43+
}
44+
45+
.user-input-container {
46+
display: flex;
47+
justify-content: space-between;
48+
gap: 10px;
49+
}
50+
51+
#user-input {
52+
width: 80%;
53+
padding: 0.5rem;
54+
border-radius: 8px;
55+
border: 1px solid #475569;
56+
background-color: #0f172a;
57+
color: #f1f5f9;
58+
outline: none;
59+
}
60+
61+
#user-input::placeholder {
62+
color: #94a3b8;
63+
}
64+
65+
#search-btn {
66+
padding: 0.5rem 1rem;
67+
border-radius: 8px;
68+
border: none;
69+
background-color: #ffff00;
70+
color: #0f172a;
71+
font-weight: bold;
72+
cursor: pointer;
73+
transition: 0.3s;
74+
}
75+
76+
#search-btn:hover {
77+
background-color: #ffff00;
78+
}
79+
80+
.circle {
81+
width: 120px;
82+
height: 120px;
83+
border-radius: 50%;
84+
border: 4px solid #334155;
85+
position: relative;
86+
display: flex;
87+
align-items: center;
88+
justify-content: center;
89+
font-weight: 700;
90+
flex-direction: column;
91+
background: conic-gradient(
92+
var(--progress-color, #22c55e) var(--progress-degree, 0%),
93+
#334155 0%
94+
);
95+
color: #f1f5f9;
96+
}
97+
98+
.circle span {
99+
position: relative;
100+
z-index: 2;
101+
font-size: 1.2rem;
102+
}
103+
104+
.circle p {
105+
font-size: 0.9rem;
106+
margin-top: 5px;
107+
color: #cbd5e1;
108+
}
109+
110+
.progress {
111+
display: flex;
112+
justify-content: space-around;
113+
flex-wrap: wrap;
114+
gap: 20px;
115+
margin: 1rem 0;
116+
}
117+
118+
.easy-progress {
119+
--progress-color: #22c55e;
120+
}
121+
.medium-progress {
122+
--progress-color: #ffff00;
123+
}
124+
.hard-progress {
125+
--progress-color: #ef4444;
126+
}
127+
128+
.stats-cards {
129+
display: flex;
130+
flex-wrap: wrap;
131+
gap: 15px;
132+
justify-content: space-evenly;
133+
margin-top: 1rem;
134+
}
135+
136+
.card {
137+
background-color: #334155;
138+
color: #f1f5f9;
139+
width: 45%;
140+
max-width: 250px;
141+
padding: 15px;
142+
border-radius: 10px;
143+
display: flex;
144+
flex-direction: column;
145+
align-items: center;
146+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
147+
transition: transform 0.3s, background 0.3s;
148+
}
149+
150+
.card:hover {
151+
transform: translateY(-5px);
152+
background-color: #475569;
153+
}
154+
155+
.card h4 {
156+
font-size: 1rem;
157+
color: #ffff00;
158+
margin-bottom: 5px;
159+
}
160+
161+
.card p {
162+
font-size: 1.2rem;
163+
font-weight: bold;
164+
}

0 commit comments

Comments
 (0)