Skip to content

Commit ee0872a

Browse files
Signed-off-by: JAYANTJOSHI001 <[email protected]>
2 parents fe42d44 + ae998e0 commit ee0872a

18 files changed

+1294
-59
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ yarn-error.log*
3131
.pnpm-debug.log*
3232

3333
# env files (can opt-in for committing if needed)
34-
.env*
34+
.env
3535

3636
# vercel
3737
.vercel

README.md

+17-45
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
11
# Leetcode Journal 🚀
22

3-
Your ultimate companion for mastering LeetCode!
4-
53
Leetcode Journal is a robust platform designed to help developers track, organize, and analyze their problem-solving journey on LeetCode. Whether you're preparing for coding interviews or sharpening your skills, Leetcode Journal ensures an intuitive and efficient experience.
64

7-
## Table of Contents
8-
9-
- [Project Overview](#project-overview)
10-
- [Key Features](#key-features)
11-
- [Tech Stack](#tech-stack)
12-
- [Installation](#installation)
13-
- [Usage](#usage)
14-
- [Contributing](#contributing)
15-
165
## Project Overview
176

187
Leetcode Journal is built to address the need for systematic tracking and review of LeetCode solutions. This platform is perfect for developers who want to:
@@ -41,19 +30,6 @@ Leetcode Journal leverages cutting-edge technologies to deliver a seamless user
4130
- **Visualization:** Chart.js for interactive data insights and progress monitoring.
4231
- **Hosting:** Vercel for a fast, optimized live application experience.
4332

44-
## Installation
45-
46-
### Prerequisites
47-
48-
Ensure you have the following tools installed:
49-
50-
- [Node.js](https://nodejs.org/) (v16.x or higher)
51-
- [npm](https://www.npmjs.com/) (v6.x or higher) or yarn (v1.x or higher)
52-
- [Python](https://www.python.org/) (v3.x or higher)
53-
- [PostgreSQL](https://www.postgresql.org/) (v14.x or higher)
54-
Python 3.x
55-
PostgreSQL
56-
5733
### Setup
5834

5935
#### 1. Clone the Repository
@@ -66,36 +42,32 @@ cd leetcode-journal
6642

6743
#### 2. Install Dependencies
6844
```bash
69-
# Install backend dependencies
70-
pip install -r requirements.txt
71-
72-
# Install frontend dependencies
73-
cd client
7445
npm install
7546
```
76-
#### 3. Set Up Database
47+
#### 3. Set Up Supabase
7748

78-
- Configure your PostgreSQL database in the backend settings.
49+
- Go to the [Supabase](https://supabase.io/) website and create an account.
50+
- Create a new project in Supabase.
51+
- Navigate to the API section and create a new API key.
52+
- Copy the API key and the URL of your Supabase project.
7953

80-
#### 4. Start the Application
54+
#### 4. Set Up Environment Variables
55+
- Create a new file named `.env` in the `client` directory.
56+
- Add the following environment variables to the file:
8157
```bash
82-
# Start the backend
83-
python manage.py runserver
58+
NEXT_PUBLIC_SUPABASE_URL = your-supabase-url
59+
NEXT_PUBLIC_SUPABASE_ANON_KEY = your-anon-key
60+
```
8461

85-
# Start the frontend
86-
cd client
87-
npm start
62+
#### 4. Start the Application
63+
```bash
64+
# Start the application
65+
npm run dev
8866
```
67+
8968
#### 5. Open the app in your browser
9069
You should now be able to access the application at [http://localhost:3000](http://localhost:3000)
9170

92-
## Usage
93-
94-
- **Login/Sign Up:** Access your personalized dashboard.
95-
- **Save Solutions:** Add your solutions and tag them by category.
96-
- **Analyze Performance:** Explore your progress using charts and statistics.
97-
- **Categorize Problems:** Organize and retrieve problems effortlessly.
98-
9971
## Contributing
10072

10173
We welcome contributions! Follow these steps to get started:
@@ -104,7 +76,7 @@ We welcome contributions! Follow these steps to get started:
10476
```
10577
```bash
10678
# Clone the forked repository to your local machine
107-
git clone https://github.com/your-username/leetcode-journal.git
79+
git clone https://github.com/yashksaini-coder/leetcode-journal.git
10880
```
10981
```bash
11082
# Navigate into the project directory

app/api/leetcode/route.ts

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { supabase } from '@/lib/supabaseClient';
2+
import axios from 'axios';
3+
import { NextRequest, NextResponse } from 'next/server';
4+
5+
// Fetch LeetCode stats
6+
const fetchLeetCodeStats = async (username: string) => {
7+
const query = `
8+
query getUserProfile($username: String!) {
9+
matchedUser(username: $username) {
10+
username
11+
profile {
12+
realName
13+
ranking
14+
}
15+
submitStats {
16+
acSubmissionNum {
17+
difficulty
18+
count
19+
}
20+
}
21+
}
22+
}
23+
`;
24+
try {
25+
const variables = { username };
26+
const { data } = await axios.post('https://leetcode.com/graphql', {
27+
query,
28+
variables,
29+
});
30+
return data.data.matchedUser;
31+
} catch (error) {
32+
console.error('Error fetching LeetCode data:', error);
33+
return null;
34+
}
35+
};
36+
37+
// Store transformed user stats in Supabase
38+
const storeUserStats = async (id: string, stats: any) => {
39+
const entry = {
40+
id: String(id),
41+
ranking: stats.profile.ranking,
42+
solved_easy: stats.submitStats.acSubmissionNum.find((item: any) => item.difficulty === 'Easy')?.count || "0",
43+
solved_medium: stats.submitStats.acSubmissionNum.find((item: any) => item.difficulty === 'Medium')?.count || "0",
44+
solved_hard: stats.submitStats.acSubmissionNum.find((item: any) => item.difficulty === 'Hard')?.count || "0",
45+
};
46+
const { data, error } = await supabase.from('user_info').upsert([entry]);
47+
48+
if (error) {
49+
console.error('Error storing data in Supabase:', error);
50+
}
51+
52+
return data;
53+
};
54+
55+
// Transform LeetCode data into a UI-friendly structure
56+
const transformLeetCodeData = (stats: any) => {
57+
return {
58+
username: stats.username,
59+
profile: {
60+
realName: stats.profile.realName || "Unknown",
61+
ranking: stats.profile.ranking?.toString() || "0",
62+
},
63+
submitStats: {
64+
acSubmissionNum: stats.submitStats.acSubmissionNum.map((item: any) => ({
65+
difficulty: item.difficulty,
66+
count: item.count?.toString() || "0",
67+
})),
68+
},
69+
};
70+
};
71+
72+
// API POST Handler
73+
export async function POST(req: NextRequest) {
74+
const searchParams = req.nextUrl.searchParams;
75+
const username = searchParams.get('username');
76+
const id = searchParams.get('id');
77+
78+
if (!username || !id) {
79+
return NextResponse.json({ error: "Username and id are required" }, { status: 400 });
80+
}
81+
82+
const stats = await fetchLeetCodeStats(username);
83+
84+
if (!stats) {
85+
return NextResponse.json({ error: "User not found" }, { status: 404 });
86+
}
87+
88+
const transformedStats = transformLeetCodeData(stats);
89+
90+
await storeUserStats(id, transformedStats);
91+
92+
return NextResponse.json({ message: "Success", stats: transformedStats });
93+
}

app/dashboard/page.tsx

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"use client"
2+
import { useEffect, useState } from 'react';
3+
import { supabase } from '@/lib/supabaseClient';
4+
import { useRouter } from 'next/navigation';
5+
import Navbar from '@/components/header';
6+
import StatsCard from '@/components/Stats';
7+
import { fetchLeetCodeStats } from '@/lib/utils';
8+
9+
export default function Dashboard() {
10+
const [userData, setUserData] = useState<any>(null);
11+
const [loading, setLoading] = useState(true);
12+
const [error, setError] = useState<string | null>(null);
13+
const router = useRouter();
14+
15+
useEffect(() => {
16+
const fetchData = async () => {
17+
try {
18+
const { data, error } = await supabase.auth.getSession();
19+
20+
if (error) throw new Error("Error fetching session.");
21+
22+
const session = data.session;
23+
if (!session) {
24+
router.push('/login');
25+
return;
26+
}
27+
// Fetch user-specific data in a single call
28+
const { data: userInfo, error: userInfoError } = await supabase
29+
.from('user_info')
30+
.select('*')
31+
.eq('user_id', session.user.id)
32+
.single();
33+
34+
if (userInfoError) throw userInfoError;
35+
36+
setUserData(userInfo);
37+
38+
} catch (err: any) {
39+
console.error(err);
40+
setError(err.message || 'An error occurred.');
41+
router.push('/login');
42+
} finally {
43+
setLoading(false);
44+
}
45+
};
46+
47+
fetchData();
48+
}, [router]);
49+
50+
if (loading) return <p>Loading...</p>;
51+
52+
if (error) {
53+
return (
54+
<div>
55+
<Navbar userId={userData.user_id} />
56+
<p className="text-red-500">{error}</p>
57+
</div>
58+
);
59+
}
60+
61+
return (
62+
<div>
63+
<Navbar userId={userData?.user_id} />
64+
<div className="container mx-auto p-4">
65+
<h1 className="text-xl font-bold mb-4">Welcome, {userData.name}</h1>
66+
<div className="mb-4">
67+
<p>LeetCode Username: {userData.leetcode_username}</p>
68+
<p>Gender: {userData.gender}</p>
69+
</div>
70+
71+
<div className="mt-6">
72+
<h2 className="text-lg font-bold mb-2">LeetCode Stats</h2>
73+
<StatsCard leetcodeUsername={userData.leetcode_username} id={userData.id} />
74+
</div>
75+
</div>
76+
</div>
77+
);
78+
}

app/login/page.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import LoginForm from "@/components/LoginForm";
2+
3+
export default function SignupPage() {
4+
return (
5+
<div className="">
6+
<LoginForm />
7+
</div>
8+
);
9+
}

app/signup/page.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import SignupForm from "@/components/SignupForm";
2+
3+
export default function SignupPage() {
4+
return (
5+
<div className="">
6+
<SignupForm />
7+
</div>
8+
);
9+
}

0 commit comments

Comments
 (0)