Skip to content

Commit 8e59bf3

Browse files
committed
feat: Add PromotionCard component to Home page + api working
1 parent 11f1873 commit 8e59bf3

File tree

5 files changed

+278
-17
lines changed

5 files changed

+278
-17
lines changed

client/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"axios": "^1.7.3",
13+
"next": "14.2.5",
1214
"react": "^18",
13-
"react-dom": "^18",
14-
"next": "14.2.5"
15+
"react-dom": "^18"
1516
},
1617
"devDependencies": {
17-
"typescript": "^5",
1818
"@types/node": "^20",
1919
"@types/react": "^18",
2020
"@types/react-dom": "^18",
21+
"eslint": "^8",
22+
"eslint-config-next": "14.2.5",
2123
"postcss": "^8",
2224
"tailwindcss": "^3.4.1",
23-
"eslint": "^8",
24-
"eslint-config-next": "14.2.5"
25+
"typescript": "^5"
2526
}
2627
}

client/src/app/components/Card.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ import Profile from "./Profile";
33
import Questions from "./Questions";
44
import SocialLinks from "./SocialLinks";
55

6-
const userData = {
6+
export const data = {
77
profileData: {
88
image: "https://assets.leetcode.com/users/avatars/avatar_1672478903.png",
99
fullName: "John Doe",
1010
username: "johndoe",
11-
badgeImg: "/assets/images/badges/1.png",
1211
rank: "203432",
1312
},
1413
aboutData: {
@@ -25,19 +24,15 @@ const userData = {
2524
},
2625

2726
totalSolved: 100,
28-
2927
easySolved: 50,
3028
easyTotal: 100,
31-
easyBeats: 50,
3229
mediumSolved: 30,
3330
mediumTotal: 50,
34-
mediumBeats: 20,
3531
hardSolved: 20,
3632
hardTotal: 50,
37-
hardBeats: 30,
3833
};
3934

40-
export default function Card({ data, index }: any) {
35+
export default function Card({ userData = data, index }: any) {
4136
return (
4237
<div className="max-w-[400px] w-full px-8 pb-3 bg-[#0e0e0e] flex justify-center flex-col items-center rounded h-[280px] border-2 border-[#cecece]">
4338
<div>

client/src/app/components/GenerateStats.tsx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1-
import React from "react";
1+
"use client";
2+
import React, { useState } from "react";
23
import Card from "./Card";
34
import Image from "next/image";
5+
import { data as defaultData } from "./Card";
46

57
const GenerateStats = ({ showStats, setShowStats }: any) => {
8+
const [username, setUsername] = useState("");
9+
const [data, setData] = useState<any>(defaultData);
10+
const generateStats = (e: React.FormEvent) => {
11+
e.preventDefault();
12+
13+
if (!username) {
14+
return;
15+
}
16+
17+
try {
18+
fetch("/api/" + username)
19+
.then((res) => res.json())
20+
.then((data) => {
21+
setData(data);
22+
console.log(data);
23+
});
24+
} catch (error) {
25+
console.error("An error occurred. Please try again later");
26+
}
27+
};
28+
629
return (
730
<div
831
onClick={() => setShowStats(false)}
@@ -12,13 +35,18 @@ const GenerateStats = ({ showStats, setShowStats }: any) => {
1235
>
1336
<div
1437
onClick={(e) => e.stopPropagation()}
15-
className="px-4 flex items-center justify-center flex-col gap-4 w-full"
38+
className="px-4 flex items-center justify-center flex-col gap-4"
1639
>
17-
<Card />
40+
<Card userData={data} />
1841

19-
<form className="flex items-center justify-center flex-col">
42+
<form
43+
onSubmit={generateStats}
44+
className="flex items-center justify-center flex-col"
45+
>
2046
<div className="relative ">
2147
<input
48+
value={username}
49+
onChange={(e) => setUsername(e.target.value)}
2250
type="text"
2351
placeholder="Enter your username"
2452
className="bg-[#1f1f1f] pl-10 w-[300px] h-[40px] text-white rounded px-4 py-6 md:text-lg text-base focus:outline-none"
@@ -33,7 +61,12 @@ const GenerateStats = ({ showStats, setShowStats }: any) => {
3361
</div>
3462

3563
<div className="flex gap-2 ">
36-
<button className="border bg-[#010101] px-4 h-[40px] rounded-md text-white font-semibold text-lg mt-4">
64+
<button
65+
type="submit"
66+
disabled={!username}
67+
onClick={generateStats}
68+
className={`border bg-[#010101] px-4 h-[40px] rounded-md text-white font-semibold text-lg mt-4 `}
69+
>
3770
Generate <span className="hidden sm:inline-block">Stats</span>
3871
</button>
3972
<button className=" border bg-[#010101] px-4 h-[40px] rounded-md text-white font-semibold text-lg mt-4">

client/src/pages/api/[username].ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import axios from "axios";
2+
3+
export default async function handler(req: any, res: any) {
4+
if (req.method !== "GET") {
5+
return res.status(405).json({ error: "Method Not Allowed" });
6+
}
7+
const { username } = req.query;
8+
9+
const url = "https://leetcode.com/graphql/";
10+
const headers = {
11+
Accept: "*/*",
12+
"Accept-Encoding": "gzip, deflate, br, zstd",
13+
"Accept-Language": "en-US,en;q=0.7",
14+
Authorization: "YourAuthorizationTokenHere", // Replace with your actual Authorization token
15+
"Content-Type": "application/json",
16+
Cookie: "568e64618f15ed106010276ef0ec7b16", // Replace with your actual Cookie value
17+
Origin: "https://leetcode.com",
18+
Referer: `https://leetcode.com/u/${username}/`, // Dynamically set referer based on username
19+
"User-Agent":
20+
"Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36",
21+
"X-Csrftoken":
22+
"irClyjQ7Qqcp8n65ZppYePQv6wo4mvzcuValmSaXlMeum9ZvYi0QYKmoVDieQKb7",
23+
};
24+
const payload1 = {
25+
operationName: "userSessionProgress",
26+
query: `
27+
query userSessionProgress($username: String!) {
28+
allQuestionsCount {
29+
difficulty
30+
count
31+
}
32+
matchedUser(username: $username) {
33+
submitStats {
34+
acSubmissionNum {
35+
difficulty
36+
count
37+
submissions
38+
}
39+
totalSubmissionNum {
40+
difficulty
41+
count
42+
submissions
43+
}
44+
}
45+
}
46+
}
47+
`,
48+
variables: {
49+
username: username,
50+
},
51+
};
52+
const payload2 = {
53+
operationName: "userPublicProfile",
54+
query: `
55+
query userPublicProfile($username: String!) {
56+
matchedUser(username: $username) {
57+
contestBadge {
58+
name
59+
expired
60+
hoverText
61+
icon
62+
}
63+
username
64+
githubUrl
65+
twitterUrl
66+
linkedinUrl
67+
profile {
68+
ranking
69+
userAvatar
70+
realName
71+
aboutMe
72+
school
73+
websites
74+
countryName
75+
company
76+
jobTitle
77+
skillTags
78+
postViewCount
79+
postViewCountDiff
80+
reputation
81+
reputationDiff
82+
solutionCount
83+
solutionCountDiff
84+
categoryDiscussCount
85+
categoryDiscussCountDiff
86+
}
87+
}
88+
}
89+
`,
90+
variables: {
91+
username: username,
92+
},
93+
};
94+
95+
try {
96+
const response1 = await axios.post(url, payload1, { headers });
97+
const response2 = await axios.post(url, payload2, { headers });
98+
99+
const data1 = response1.data;
100+
const data2 = response2.data;
101+
102+
// Merge the data from both responses
103+
const combinedData = {
104+
userSessionProgress: data1.data,
105+
userPublicProfile: data2.data,
106+
};
107+
108+
const total = combinedData.userSessionProgress.allQuestionsCount[0].count;
109+
const easyTotal =
110+
combinedData.userSessionProgress.allQuestionsCount[1].count;
111+
const mediumTotal =
112+
combinedData.userSessionProgress.allQuestionsCount[2].count;
113+
const hardTotal =
114+
combinedData.userSessionProgress.allQuestionsCount[3].count;
115+
116+
const totalSolved =
117+
combinedData.userSessionProgress.matchedUser.submitStats
118+
.acSubmissionNum[0].count;
119+
const easySolved =
120+
combinedData.userSessionProgress.matchedUser.submitStats
121+
.acSubmissionNum[1].count;
122+
const mediumSolved =
123+
combinedData.userSessionProgress.matchedUser.submitStats
124+
.acSubmissionNum[2].count;
125+
const hardSolved =
126+
combinedData.userSessionProgress.matchedUser.submitStats
127+
.acSubmissionNum[3].count;
128+
129+
const profileData = {
130+
username: combinedData.userPublicProfile.matchedUser.username,
131+
rank: combinedData.userPublicProfile.matchedUser.profile.ranking,
132+
image: combinedData.userPublicProfile.matchedUser.profile.userAvatar,
133+
fullName: combinedData.userPublicProfile.matchedUser.profile.realName,
134+
};
135+
const aboutData = {
136+
github: {
137+
link: combinedData.userPublicProfile.matchedUser.githubUrl,
138+
text: "Github",
139+
},
140+
website: {
141+
link: combinedData.userPublicProfile.matchedUser.profile.websites[0],
142+
text: "Website",
143+
},
144+
linkedin: {
145+
link: combinedData.userPublicProfile.matchedUser.linkedinUrl,
146+
text: "LinkedIn",
147+
},
148+
twitter: {
149+
link: combinedData.userPublicProfile.matchedUser.twitterUrl,
150+
text: "Twitter",
151+
},
152+
};
153+
154+
res.status(200).json({
155+
profileData,
156+
aboutData,
157+
total,
158+
easyTotal,
159+
mediumTotal,
160+
hardTotal,
161+
totalSolved,
162+
easySolved,
163+
mediumSolved,
164+
hardSolved,
165+
});
166+
} catch (error) {
167+
console.error(error);
168+
res.status(500).json({ error: "Internal Server Error" });
169+
}
170+
}

0 commit comments

Comments
 (0)