Skip to content

Commit 1a02045

Browse files
committed
Any
1 parent 313a09f commit 1a02045

File tree

1 file changed

+178
-90
lines changed

1 file changed

+178
-90
lines changed

app/dashboard/page.tsx

Lines changed: 178 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,201 @@
1-
"use client"
1+
"use client";
22

3-
import { Badge } from "@/components/ui/badge"
4-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
5-
import { Github, Linkedin, Twitter } from "lucide-react"
6-
import Image from "next/image"
7-
import { useLeetcodeStore } from "@/store/LeetcodeStore/useLeetcodeStore"
8-
import React from "react"
3+
import React from "react";
4+
import Image from "next/image";
5+
import { useLeetcodeStore } from "@/store/LeetcodeStore/useLeetcodeStore";
6+
import { Badge } from "@/components/ui/badge";
7+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
8+
import { Skeleton } from "@/components/ui/skeleton";
9+
import { Github, Linkedin, Twitter, Award, Book, Star } from "lucide-react";
910

1011
export default function Dashboard() {
11-
const { fetchLeetcodeUserProfile, leetcodeUserProfile } = useLeetcodeStore()
12+
const { fetchLeetcodeUserProfile, leetcodeUserProfile } = useLeetcodeStore();
1213

1314
React.useEffect(() => {
14-
fetchLeetcodeUserProfile()
15-
}, [fetchLeetcodeUserProfile])
15+
fetchLeetcodeUserProfile();
16+
}, [fetchLeetcodeUserProfile]);
1617

1718
if (!leetcodeUserProfile) {
18-
return <div>Loading...</div>
19+
return <DashboardSkeleton />;
1920
}
2021

2122
return (
22-
<div className="flex flex-col h-full p-4">
23-
<Card className="w-full max-w-3xl mx-auto">
24-
<CardHeader className="flex flex-row items-center gap-4">
25-
{leetcodeUserProfile.profile.userAvatar && (
26-
<div className="">
27-
<Image
28-
src={leetcodeUserProfile.profile.userAvatar || "/placeholder.svg"}
29-
alt="Profile Image"
30-
height={500}
31-
width={500}
32-
className="rounded-full object-cover"
33-
priority
34-
/>
35-
</div>
36-
)}
37-
<div className="flex flex-col">
38-
<CardTitle>{leetcodeUserProfile.profile.realName}</CardTitle>
39-
<CardDescription>@{leetcodeUserProfile.username}</CardDescription>
40-
<div className="flex flex-wrap gap-2 mt-2">
41-
{leetcodeUserProfile.badges.map((badge) => (
42-
<div key={badge.id} className="flex items-center gap-1">
43-
<Badge variant="secondary">{badge.displayName}</Badge>
44-
<div className="relative w-5 h-5">
45-
<Image
46-
src={badge.icon || "/placeholder.svg"}
47-
alt={badge.displayName}
48-
fill
49-
className="object-contain"
50-
/>
51-
</div>
52-
</div>
23+
<div className="flex flex-col min-h-screen p-4 sm:p-6 md:p-8">
24+
<Card className="w-full max-w-4xl mx-auto shadow-xl border-none">
25+
<CardHeader className="flex flex-col sm:flex-row items-center gap-6 pb-6 border-b">
26+
<div className="relative w-32 h-32 sm:w-40 sm:h-40">
27+
<Image
28+
src={leetcodeUserProfile.profile.userAvatar || "/placeholder.svg"}
29+
alt="Profile Image"
30+
fill
31+
className="rounded-full object-cover border-4 border-primary shadow-md"
32+
priority
33+
/>
34+
</div>
35+
<div className="flex flex-col items-center sm:items-start text-center sm:text-left">
36+
<CardTitle className="text-3xl font-bold mb-2">
37+
{leetcodeUserProfile.profile.realName}
38+
</CardTitle>
39+
<p className="text-xl text-muted-foreground mb-4">
40+
@{leetcodeUserProfile.username}
41+
</p>
42+
<div className="flex flex-wrap justify-center sm:justify-start gap-2">
43+
{leetcodeUserProfile.profile.skillTags.map((skill, index) => (
44+
<Badge
45+
key={index}
46+
variant="secondary"
47+
className="text-sm px-3 py-1"
48+
>
49+
{skill}
50+
</Badge>
5351
))}
5452
</div>
5553
</div>
5654
</CardHeader>
57-
<CardContent>
58-
<div className="grid gap-4">
59-
<div className="grid grid-cols-3 gap-4">
60-
<div className="flex flex-col">
61-
<span className="text-2xl font-bold">
62-
{leetcodeUserProfile.submitStats.acSubmissionNum[0].count || 0}
63-
</span>
64-
<span className="text-sm text-muted-foreground">Problems Solved</span>
65-
</div>
66-
<div className="flex flex-col">
67-
<span className="text-2xl font-bold">{leetcodeUserProfile.contributions.points}</span>
68-
<span className="text-sm text-muted-foreground">Contribution Points</span>
69-
</div>
70-
<div className="flex flex-col">
71-
<span className="text-2xl font-bold">{leetcodeUserProfile.profile.starRating}</span>
72-
<span className="text-sm text-muted-foreground">Star Rating</span>
55+
<CardContent className="pt-6">
56+
<div className="grid gap-6 md:grid-cols-2">
57+
<div className="space-y-4">
58+
<h3 className="text-xl font-semibold mb-3">Statistics</h3>
59+
<div className="grid grid-cols-2 gap-4">
60+
<StatItem
61+
icon={<Book className="w-5 h-5" />}
62+
value={
63+
leetcodeUserProfile.submitStats.acSubmissionNum[0].count ||
64+
0
65+
}
66+
label="Problems Solved"
67+
/>
68+
<StatItem
69+
icon={<Award className="w-5 h-5" />}
70+
value={leetcodeUserProfile.contributions.points}
71+
label="Contribution Points"
72+
/>
73+
<StatItem
74+
icon={<Star className="w-5 h-5" />}
75+
value={leetcodeUserProfile.profile.starRating}
76+
label="Star Rating"
77+
/>
78+
<StatItem
79+
icon={<Award className="w-5 h-5" />}
80+
value={leetcodeUserProfile.profile.ranking}
81+
label="Global Ranking"
82+
/>
7383
</div>
7484
</div>
75-
<div className="flex gap-4 pt-4">
76-
{leetcodeUserProfile.githubUrl && (
77-
<a
78-
href={leetcodeUserProfile.githubUrl}
79-
className="text-muted-foreground hover:text-primary"
80-
target="_blank"
81-
rel="noopener noreferrer"
82-
>
83-
<Github className="w-6 h-6" />
84-
</a>
85-
)}
86-
{leetcodeUserProfile.linkedinUrl && (
87-
<a
88-
href={leetcodeUserProfile.linkedinUrl}
89-
className="text-muted-foreground hover:text-primary"
90-
target="_blank"
91-
rel="noopener noreferrer"
92-
>
93-
<Linkedin className="w-6 h-6" />
94-
</a>
95-
)}
96-
{leetcodeUserProfile.twitterUrl && (
97-
<a
98-
href={leetcodeUserProfile.twitterUrl}
99-
className="text-muted-foreground hover:text-primary"
100-
target="_blank"
101-
rel="noopener noreferrer"
102-
>
103-
<Twitter className="w-6 h-6" />
104-
</a>
105-
)}
85+
<div className="space-y-4">
86+
<h3 className="text-xl font-semibold mb-3">Recent Badges</h3>
87+
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
88+
{leetcodeUserProfile.badges.slice(0, 6).map((badge) => (
89+
<div
90+
key={badge.id}
91+
className="flex flex-col items-center p-2 bg-secondary rounded-lg"
92+
>
93+
<div className="relative w-12 h-12 mb-2">
94+
<Image
95+
src={badge.icon || "/placeholder.svg"}
96+
alt={badge.displayName}
97+
fill
98+
className="object-contain"
99+
/>
100+
</div>
101+
<span className="text-xs text-center">
102+
{badge.displayName}
103+
</span>
104+
</div>
105+
))}
106+
</div>
106107
</div>
107108
</div>
109+
<div className="flex justify-center gap-6 mt-8">
110+
<SocialLink
111+
href={leetcodeUserProfile.githubUrl}
112+
icon={<Github className="w-6 h-6" />}
113+
/>
114+
<SocialLink
115+
href={leetcodeUserProfile.linkedinUrl}
116+
icon={<Linkedin className="w-6 h-6" />}
117+
/>
118+
<SocialLink
119+
href={leetcodeUserProfile.twitterUrl!}
120+
icon={<Twitter className="w-6 h-6" />}
121+
/>
122+
</div>
108123
</CardContent>
109124
</Card>
110125
</div>
111-
)
126+
);
127+
}
128+
129+
function StatItem({
130+
icon,
131+
value,
132+
label,
133+
}: {
134+
icon: React.ReactNode;
135+
value: number;
136+
label: string;
137+
}) {
138+
return (
139+
<div className="flex items-center space-x-3 bg-secondary/50 rounded-lg p-3">
140+
{icon}
141+
<div>
142+
<div className="text-2xl font-bold">{value}</div>
143+
<div className="text-sm text-muted-foreground">{label}</div>
144+
</div>
145+
</div>
146+
);
112147
}
113148

149+
function SocialLink({ href, icon }: { href: string; icon: React.ReactNode }) {
150+
if (!href) return null;
151+
return (
152+
<a
153+
href={href}
154+
className="text-muted-foreground hover:text-primary transition-colors"
155+
target="_blank"
156+
rel="noopener noreferrer"
157+
>
158+
{icon}
159+
</a>
160+
);
161+
}
162+
163+
function DashboardSkeleton() {
164+
return (
165+
<div className="flex flex-col min-h-screen bg-gradient-to-b from-gray-100 to-gray-200 dark:from-gray-900 dark:to-gray-800 p-4 sm:p-6 md:p-8">
166+
<Card className="w-full max-w-4xl mx-auto shadow-xl">
167+
<CardHeader className="flex flex-col sm:flex-row items-center gap-6 pb-6 border-b">
168+
<Skeleton className="w-32 h-32 sm:w-40 sm:h-40 rounded-full" />
169+
<div className="flex flex-col items-center sm:items-start space-y-4 w-full">
170+
<Skeleton className="h-8 w-48" />
171+
<Skeleton className="h-6 w-36" />
172+
<div className="flex flex-wrap justify-center sm:justify-start gap-2">
173+
{[1, 2, 3].map((i) => (
174+
<Skeleton key={i} className="h-6 w-20" />
175+
))}
176+
</div>
177+
</div>
178+
</CardHeader>
179+
<CardContent className="pt-6">
180+
<div className="grid gap-6 md:grid-cols-2">
181+
{[1, 2].map((section) => (
182+
<div key={section} className="space-y-4">
183+
<Skeleton className="h-7 w-32" />
184+
<div className="grid grid-cols-2 gap-4">
185+
{[1, 2, 3, 4].map((item) => (
186+
<Skeleton key={item} className="h-20 w-full" />
187+
))}
188+
</div>
189+
</div>
190+
))}
191+
</div>
192+
<div className="flex justify-center gap-6 mt-8">
193+
{[1, 2, 3].map((icon) => (
194+
<Skeleton key={icon} className="w-6 h-6 rounded-full" />
195+
))}
196+
</div>
197+
</CardContent>
198+
</Card>
199+
</div>
200+
);
201+
}

0 commit comments

Comments
 (0)