diff --git a/GQL_Queries/index.ts b/GQL_Queries/index.ts
index ac32ffe..f138464 100644
--- a/GQL_Queries/index.ts
+++ b/GQL_Queries/index.ts
@@ -6,6 +6,6 @@
*/
export { default as AcSubmissionQuery } from './recentAcSubmit';
export { default as contestQuery } from './contest';
-export { default as userProfileQuery } from './userProfile';
+export { userProfileQuery } from './userProfile';
export { default as submissionQuery } from './recentSubmit';
export { default as languageStatsQuery } from './languageStats';
\ No newline at end of file
diff --git a/GQL_Queries/userProfile.ts b/GQL_Queries/userProfile.ts
index e3ac5d3..3326635 100644
--- a/GQL_Queries/userProfile.ts
+++ b/GQL_Queries/userProfile.ts
@@ -20,7 +20,7 @@
*
* @param {string} $username - The username of the user whose profile is to be fetched.
*/
-const query = `#graphql
+export const userProfileQuery = `#graphql
query getUserProfile($username: String!) {
allQuestionsCount {
difficulty
@@ -87,6 +87,4 @@ query getUserProfile($username: String!) {
statusDisplay
lang
}
-}`;
-
-export default query;
+}`;
\ No newline at end of file
diff --git a/app/api/leetcode/userDetails/route.ts b/app/api/leetcode/userDetails/route.ts
new file mode 100644
index 0000000..0303cba
--- /dev/null
+++ b/app/api/leetcode/userDetails/route.ts
@@ -0,0 +1,32 @@
+import prisma from "@/lib/database/prismaClient";
+import { getLeetCodeUserDetails } from "@/utils/leetcode/leetcodeContollers";
+import { createClient } from "@/utils/supabase/server";
+import { NextResponse } from "next/server";
+
+export async function GET() {
+ try {
+ const supabase = await createClient();
+ const supabaseUser = (await supabase.auth.getUser()).data.user;
+
+ if (!supabaseUser) {
+ return NextResponse.json({ error: "User not authenticated" }, { status: 401 });
+ }
+
+ const user = await prisma.user.findFirst({
+ where: {
+ supabaseId: supabaseUser.id,
+ },
+ });
+
+ if (!user) {
+ return NextResponse.json({ error: "User not found" }, { status: 404 });
+ }
+
+ const LeetCodeUsername = user.leetcodeUsername;
+
+ const result = await getLeetCodeUserDetails(LeetCodeUsername)
+ return NextResponse.json(result);
+ } catch (error: any) {
+ return NextResponse.json({ error: error.message }, { status: 500 });
+ }
+}
\ No newline at end of file
diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx
index b8a8062..6df58c7 100644
--- a/app/dashboard/page.tsx
+++ b/app/dashboard/page.tsx
@@ -1,9 +1,201 @@
+"use client";
+
import React from "react";
+import Image from "next/image";
+import { useLeetcodeStore } from "@/store/LeetcodeStore/useLeetcodeStore";
+import { Badge } from "@/components/ui/badge";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Skeleton } from "@/components/ui/skeleton";
+import { Github, Linkedin, Twitter, Award, Book, Star } from "lucide-react";
export default function Dashboard() {
+ const { fetchLeetcodeUserProfile, leetcodeUserProfile } = useLeetcodeStore();
+
+ React.useEffect(() => {
+ fetchLeetcodeUserProfile();
+ }, [fetchLeetcodeUserProfile]);
+
+ if (!leetcodeUserProfile) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {leetcodeUserProfile.profile.realName}
+
+
+ @{leetcodeUserProfile.username}
+
+
+ {leetcodeUserProfile.profile.skillTags.map((skill, index) => (
+
+ {skill}
+
+ ))}
+
+
+
+
+
+
+
Statistics
+
+ }
+ value={
+ leetcodeUserProfile.submitStats.acSubmissionNum[0].count ||
+ 0
+ }
+ label="Problems Solved"
+ />
+ }
+ value={leetcodeUserProfile.contributions.points}
+ label="Contribution Points"
+ />
+ }
+ value={leetcodeUserProfile.profile.starRating}
+ label="Star Rating"
+ />
+ }
+ value={leetcodeUserProfile.profile.ranking}
+ label="Global Ranking"
+ />
+
+
+
+
Recent Badges
+
+ {leetcodeUserProfile.badges.slice(0, 6).map((badge) => (
+
+
+
+
+
+ {badge.displayName}
+
+
+ ))}
+
+
+
+
+ }
+ />
+ }
+ />
+ }
+ />
+
+
+
+
+ );
+}
+
+function StatItem({
+ icon,
+ value,
+ label,
+}: {
+ icon: React.ReactNode;
+ value: number;
+ label: string;
+}) {
+ return (
+
+ );
+}
+
+function SocialLink({ href, icon }: { href: string; icon: React.ReactNode }) {
+ if (!href) return null;
+ return (
+
+ {icon}
+
+ );
+}
+
+function DashboardSkeleton() {
return (
-
-
This is the dashboard
+
+
+
+
+
+
+
+
+ {[1, 2, 3].map((i) => (
+
+ ))}
+
+
+
+
+
+ {[1, 2].map((section) => (
+
+
+
+ {[1, 2, 3, 4].map((item) => (
+
+ ))}
+
+
+ ))}
+
+
+ {[1, 2, 3].map((icon) => (
+
+ ))}
+
+
+
);
}
diff --git a/next.config.ts b/next.config.ts
index 02f7357..23be141 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -5,6 +5,14 @@ const nextConfig: NextConfig = {
eslint: {
ignoreDuringBuilds: true, // Ignores all ESLint warnings and errors during builds
},
+ images: {
+ remotePatterns: [
+ {
+ protocol: 'https',
+ hostname: '**', // Match any hostname
+ },
+ ],
+ },
};
export default nextConfig;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index b617548..1797a61 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -27,9 +27,35 @@ model User {
email String @unique
fullName String
gender String
- leetcodeUsername String
+ leetcodeUsername String
password String
isVerified Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
+
+// model leetcodeUser {
+// id String @id @unique @default(uuid())
+// username String
+// githubURL String
+// twitterUrl String
+// linkedinUrl String
+// userAvatar String
+// countryName String
+// skillTags String[]
+// starRating Int
+// badges Badges[]
+// }
+
+// model Badges {
+// id String @id @unique @default(uuid())
+// displayName String
+// icon String
+// creationDate String
+// leetcodeUserId String?
+// leetcodeUser leetcodeUser? @relation(fields: [leetcodeUserId], references: [id])
+// }
+
+
+
+
diff --git a/store/LeetcodeStore/useLeetcodeStore.ts b/store/LeetcodeStore/useLeetcodeStore.ts
new file mode 100644
index 0000000..d616dce
--- /dev/null
+++ b/store/LeetcodeStore/useLeetcodeStore.ts
@@ -0,0 +1,77 @@
+import axios from "axios";
+import { create } from "zustand";
+
+interface leetcodeProfile {
+ username: string;
+ githubUrl: string;
+ twitterUrl: string | null;
+ linkedinUrl: string;
+ contributions: {
+ points: number;
+ questionCount: number;
+ testcaseCount: number;
+ };
+ profile: {
+ realName: string;
+ userAvatar: string;
+ birthday: string | null;
+ ranking: number;
+ reputation: number;
+ websites: string[];
+ countryName: string;
+ company: string | null;
+ school: string | null;
+ skillTags: string[];
+ aboutMe: string;
+ starRating: number;
+ };
+ badges: {
+ id: string;
+ displayName: string;
+ icon: string;
+ creationDate: string;
+ }[];
+ upcomingBadges: {
+ name: string;
+ icon: string;
+ }[];
+ activeBadge: {
+ id: string;
+ displayName: string;
+ icon: string;
+ creationDate: string;
+ };
+ submitStats: {
+ totalSubmissionNum: {
+ difficulty: "All" | "Easy" | "Medium" | "Hard";
+ count: number;
+ submissions: number;
+ }[];
+ acSubmissionNum: {
+ difficulty: "All" | "Easy" | "Medium" | "Hard";
+ count: number;
+ submissions: number;
+ }[];
+ };
+ submissionCalendar: string; // JSON string representing submission data
+ }
+
+
+interface LeetcodeStore {
+ leetcodeUserProfile : leetcodeProfile | null;
+ fetchLeetcodeUserProfile : VoidFunction
+}
+
+export const useLeetcodeStore = create
((set) => ({
+ leetcodeUserProfile: null,
+ fetchLeetcodeUserProfile: async () => {
+ try {
+ const response = await axios.get("/api/leetcode/userDetails");
+ const data = response.data;
+ console.log("data", data);
+ set({ leetcodeUserProfile: data });
+ } catch (error) {
+ console.error(error);
+ }
+ }
+}))
diff --git a/utils/leetcode/leetcodeContollers.ts b/utils/leetcode/leetcodeContollers.ts
new file mode 100644
index 0000000..19d4b74
--- /dev/null
+++ b/utils/leetcode/leetcodeContollers.ts
@@ -0,0 +1,13 @@
+import { userProfileQuery } from "@/GQL_Queries/userProfile";
+import { queryLeetCodeAPI } from "./queryLeetCodeAPI";
+
+export const getLeetCodeUserDetails = async (username: string) => {
+ const response = await queryLeetCodeAPI(userProfileQuery, {
+ username: username,
+ });
+
+ console.log(response);
+ return response.data.matchedUser;
+}
+
+
diff --git a/utils/leetcode/queryLeetCodeAPI.ts b/utils/leetcode/queryLeetCodeAPI.ts
new file mode 100644
index 0000000..7b87e9e
--- /dev/null
+++ b/utils/leetcode/queryLeetCodeAPI.ts
@@ -0,0 +1,21 @@
+import axios from "axios";
+
+const API_URL = process.env.LEETCODE_API_URL || 'https://leetcode.com/graphql';
+
+export async function queryLeetCodeAPI(query: string, variables: any) {
+ try {
+ const response = await axios.post(API_URL, { query, variables });
+ if (response.data.errors) {
+ throw new Error(response.data.errors[0].message);
+ }
+ return response.data;
+ } catch (error: any) {
+ if (error.response) {
+ throw new Error(`Error from LeetCode API: ${error.response.data}`);
+ } else if (error.request) {
+ throw new Error('No response received from LeetCode API');
+ } else {
+ throw new Error(`Error in setting up the request: ${error.message}`);
+ }
+ }
+}
\ No newline at end of file