Skip to content

Commit 1237b92

Browse files
refactor: 🛠️ Update Dashboard to use ActivityCalendar and improve data processing logic
1 parent af83b54 commit 1237b92

File tree

3 files changed

+747
-79
lines changed

3 files changed

+747
-79
lines changed

Diff for: ‎app/dashboard/page.tsx

+51-40
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import { useLeetcodeStore } from "@/store/LeetcodeStore/useLeetcodeStore";
77
import { Card, CardContent, CardHeader } from "@/components/ui/card";
88
import { Skeleton } from "@/components/ui/skeleton";
99
import { Doughnut } from "react-chartjs-2";
10-
11-
import CalendarHeatmap from "react-calendar-heatmap";
12-
import "../styles/style.css";
13-
import 'react-calendar-heatmap/dist/styles.css';
10+
import { Tooltip as MuiTooltip } from '@mui/material'
11+
import { ActivityCalendar } from 'react-activity-calendar'
1412

1513
import {
1614
Chart as ChartJS,
@@ -89,13 +87,23 @@ export default function Dashboard() {
8987

9088
const processLeetCodeData = (submissionCalendar: string) => {
9189
const parsedData = JSON.parse(submissionCalendar);
92-
93-
return Object.entries(parsedData).map(([timestamp, count]) => ({
94-
date: new Date(Number(timestamp) * 1000).toISOString().split("T")[0],
95-
count: count as number
96-
}));
90+
91+
return Object.entries(parsedData).map(([timestamp, count]) => {
92+
const contributionCount = count as number;
93+
let level = 0;
94+
if (contributionCount > 0) {
95+
level = Math.min(Math.ceil(contributionCount / 5), 4);
96+
}
97+
98+
return {
99+
date: new Date(Number(timestamp) * 1000).toISOString().split("T")[0],
100+
count: contributionCount,
101+
level: level
102+
};
103+
});
97104
};
98105

106+
console.log(processLeetCodeData(userDetails.submissionCalendar));
99107
return (
100108
<div className="w-full max-w-7xl mx-auto px-3 sm:px-4 md:px-6 lg:px-8 py-4 sm:py-6 md:py-8 space-y-4 sm:space-y-6 md:space-y-8">
101109
{/* Profile Header Card */}
@@ -124,19 +132,19 @@ export default function Dashboard() {
124132
</div>
125133
</div>
126134
<div className="grid grid-cols-3 gap-2 sm:gap-4 w-full sm:w-auto mt-4 sm:mt-0">
127-
<QuickStat
135+
<QuickStat
128136
icon={<Target />}
129137
label="Rating"
130138
value={userContestRanking?.rating || 0}
131139
color="blue"
132140
/>
133-
<QuickStat
141+
<QuickStat
134142
icon={<Trophy />}
135143
label="Top"
136144
value={`${userContestRanking?.topPercentage}%`}
137145
color="yellow"
138146
/>
139-
<QuickStat
147+
<QuickStat
140148
icon={<Award />}
141149
label="Rank"
142150
value={userContestRanking?.globalRanking || 0}
@@ -162,17 +170,20 @@ export default function Dashboard() {
162170
</div>
163171
</CardHeader>
164172
<CardContent className="p-2 sm:p-4 md:p-6 overflow-x-auto">
165-
<div className="min-w-[600px]">
166-
<CalendarHeatmap
167-
values={processLeetCodeData(userDetails.submissionCalendar)}
168-
startDate={new Date(new Date().setFullYear(new Date().getFullYear() - 1))}
169-
endDate={new Date()}
170-
classForValue={(value) => {
171-
if (!value) {
172-
return 'color-empty';
173-
}
174-
return `color-scale-${(value.count)}`;
175-
}}
173+
<div className="h-[160px] transform scale-30 origin-center">
174+
<ActivityCalendar
175+
theme={{ dark: ['#020202', '#058c42', '#16DB65', '#0D2818', '#04471C'] }}
176+
data={processLeetCodeData(userDetails.submissionCalendar)}
177+
renderBlock={(block, activity) => (
178+
<MuiTooltip title={`${activity.count} activities on ${activity.date}`}>
179+
{block}
180+
</MuiTooltip>
181+
)}
182+
renderColorLegend={(block, level) => (
183+
<MuiTooltip title={`Level: ${level}`}>{block}</MuiTooltip>
184+
)}
185+
weekStart={1}
186+
ref={(ref) => console.log(ref)}
176187
/>
177188
</div>
178189
</CardContent>
@@ -211,9 +222,9 @@ export default function Dashboard() {
211222
<CardContent className="p-0 overflow-y-auto h-[calc(350px-3rem)] sm:h-[calc(400px-4rem)]">
212223
<div className="divide-y">
213224
{recentSubmissions.map((submission, idx) => (
214-
<Link
225+
<Link
215226
href={`https://leetcode.com/problems/${submission.titleSlug}`}
216-
key={idx}
227+
key={idx}
217228
target="_blank"
218229
className="flex items-center p-3 sm:p-4 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors group"
219230
>
@@ -235,53 +246,53 @@ export default function Dashboard() {
235246
{/* Statistics Cards */}
236247
<div className="md:col-span-2 max-h-[400px] sm:max-h-[450px] lg:max-h-[500px] overflow-hidden">
237248
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6">
238-
<DetailCard
249+
<DetailCard
239250
title="Problem Solving Stats"
240251
icon={<Star className="w-4 h-4 sm:w-5 sm:h-5 text-yellow-600" />}
241252
stats={[
242-
{
253+
{
243254
label: 'Total Solved',
244255
value: userDetails.submitStats.acSubmissionNum[0].count,
245256
icon: <CheckCircle className="w-3 h-3 sm:w-4 sm:h-4 text-green-500" />
246257
},
247-
{
258+
{
248259
label: 'Easy Problems',
249260
value: userDetails.submitStats.acSubmissionNum[1].count,
250261
icon: <Zap className="w-3 h-3 sm:w-4 sm:h-4 text-green-500" />
251262
},
252-
{
263+
{
253264
label: 'Medium Problems',
254265
value: userDetails.submitStats.acSubmissionNum[2].count,
255266
icon: <Zap className="w-3 h-3 sm:w-4 sm:h-4 text-yellow-500" />
256267
},
257-
{
268+
{
258269
label: 'Hard Problems',
259270
value: userDetails.submitStats.acSubmissionNum[3].count,
260271
icon: <Zap className="w-3 h-3 sm:w-4 sm:h-4 text-red-500" />
261272
},
262273
]}
263274
/>
264-
<DetailCard
275+
<DetailCard
265276
title="Performance Metrics"
266277
icon={<Timer className="w-4 h-4 sm:w-5 sm:h-5 text-purple-600" />}
267278
stats={[
268-
{
279+
{
269280
label: 'Acceptance Rate',
270-
value: `${(userDetails.submitStats.acSubmissionNum[0].count /
281+
value: `${(userDetails.submitStats.acSubmissionNum[0].count /
271282
userDetails.submitStats.totalSubmissionNum[0].count * 100).toFixed(1)}%`,
272283
icon: <TrendingUp className="w-3 h-3 sm:w-4 sm:h-4 text-blue-500" />
273284
},
274-
{
285+
{
275286
label: 'Total Submissions',
276287
value: userDetails.submitStats.totalSubmissionNum[0].count,
277288
icon: <Code className="w-3 h-3 sm:w-4 sm:h-4 text-green-500" />
278289
},
279-
{
290+
{
280291
label: 'Contribution Points',
281292
value: userDetails.contributions.points,
282293
icon: <Star className="w-3 h-3 sm:w-4 sm:h-4 text-yellow-500" />
283294
},
284-
{
295+
{
285296
label: 'Contest Count',
286297
value: userContestRanking?.attendedContestsCount || 0,
287298
icon: <Trophy className="w-3 h-3 sm:w-4 sm:h-4 text-orange-500" />
@@ -304,8 +315,8 @@ export default function Dashboard() {
304315
<CardContent className="p-2 sm:p-4 flex justify-center items-center flex-1 overflow-hidden">
305316
<div className="h-full w-full flex items-center justify-center">
306317
<div className="h-48 w-48 sm:h-56 sm:w-56 md:h-64 md:w-64">
307-
<Doughnut
308-
data={difficultyData}
318+
<Doughnut
319+
data={difficultyData}
309320
options={{
310321
cutout: '65%',
311322
responsive: true,
@@ -341,7 +352,7 @@ export default function Dashboard() {
341352
}
342353
}
343354
}
344-
}}
355+
}}
345356
/>
346357
</div>
347358
</div>
@@ -392,7 +403,7 @@ function DetailCard({ title, icon, stats }: { title: string; icon: React.ReactNo
392403
<CardContent className="p-2 sm:p-4">
393404
<div className="grid grid-cols-2 gap-2 sm:gap-4">
394405
{stats.map((stat, idx) => (
395-
<div key={idx}
406+
<div key={idx}
396407
className="bg-gray-100/80 dark:bg-gray-700/50 p-2 sm:p-4 rounded-lg hover:bg-gray-200/80 dark:hover:bg-gray-700/80 transition-colors flex flex-col justify-between h-full"
397408
>
398409
<div className="flex items-center gap-1 sm:gap-2 mb-1 sm:mb-2">

0 commit comments

Comments
 (0)