Skip to content

Commit d0a94fa

Browse files
committed
feat: adding project section
1 parent a0750ba commit d0a94fa

File tree

10 files changed

+150
-121
lines changed

10 files changed

+150
-121
lines changed

client/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Profile from './pages/Profile';
88
import { Toaster } from "@/components/ui/sonner";
99
import EditProfileForm from './pages/EditProfileForm';
1010
import { MessagePage } from './pages/MessagePage';
11+
import Projects from './components/Projects/Projects';
1112

1213
const App = () => {
1314

@@ -21,6 +22,7 @@ const App = () => {
2122
<Route path="/home" element={<Home />} />
2223
<Route path="/settings" element={<EditProfileForm />} />
2324
<Route path="/message" element={<MessagePage/>} />
25+
<Route path="/projects" element={<Projects />} />
2426
<Route path="/u/:username" element={<Profile />} />
2527
<Route path="*" element={<div>404</div>} />
2628
</Routes>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
SidebarInset,
3+
SidebarProvider,
4+
SidebarTrigger,
5+
} from "@/components/ui/sidebar"
6+
import { SidebarLeft } from '@/components/Sidebar/Sidebar'
7+
8+
const Projects = () => {
9+
return (
10+
<SidebarProvider>
11+
<SidebarLeft />
12+
<SidebarInset>
13+
<header className="sticky top-0 flex h-14 shrink-0 items-center gap-2 bg-background">
14+
<div className="flex flex-1 items-center gap-2 px-3">
15+
<SidebarTrigger />
16+
</div>
17+
</header>
18+
<main className="flex flex-col flex-grow p-4 overflow-hidden">
19+
<Dashboard />
20+
</main>
21+
</SidebarInset>
22+
</SidebarProvider>
23+
)
24+
}
25+
26+
const Dashboard = () => {
27+
return(
28+
<>
29+
project
30+
</>
31+
)
32+
}
33+
34+
export default Projects

client/src/components/Sidebar/Sidebar.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
CircleUser,
77
Trash2,
88
LogOut,
9+
MessagesSquare,
910
type LucideIcon,
1011
} from "lucide-react"
1112

@@ -68,6 +69,11 @@ export function SidebarLeft({ ...props }: React.ComponentProps<typeof Sidebar>)
6869
{
6970
title: "Message",
7071
url: "/message",
72+
icon: MessagesSquare,
73+
},
74+
{
75+
title: "Projects",
76+
url: "/projects",
7177
icon: Inbox,
7278
},
7379
],
@@ -155,7 +161,7 @@ function NavSecondary({
155161
url: string
156162
icon: LucideIcon
157163
badge?: React.ReactNode
158-
onClick?: React.MouseEventHandler<HTMLAnchorElement> // Add onClick type
164+
onClick?: React.MouseEventHandler<HTMLAnchorElement>
159165
}[]
160166
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
161167
return (
@@ -165,7 +171,6 @@ function NavSecondary({
165171
{items.map((item) => (
166172
<SidebarMenuItem key={item.title}>
167173
<SidebarMenuButton asChild>
168-
{/* Handle click if provided */}
169174
<a href={item.url} onClick={item.onClick}>
170175
<item.icon />
171176
<span>{item.title}</span>

client/src/pages/Profile.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,8 @@ const Dashboard = () => {
125125
setProfileData(profileResponse.data);
126126

127127
const friendsResponse = await axios.get(`${backendUrl}/profile/${username}/friends`);
128-
setFriendsList(friendsResponse.data.friends); // Set the visited user's friends list
128+
setFriendsList(friendsResponse.data.friends);
129129

130-
// Check if logged-in user is a friend of the profile user
131130
const loggedInFriendsResponse = await axios.get(`${backendUrl}/profile/${loggedInUsername}/friends`);
132131
const isFriendOfProfileUser = loggedInFriendsResponse.data.friends.includes(username);
133132
setIsFriend(isFriendOfProfileUser);
@@ -171,22 +170,19 @@ const Dashboard = () => {
171170
const handleFriendRequest = async () => {
172171
try {
173172
if (isFriend) {
174-
// Disconnect if already a friend
175173
await axios.delete(`${backendUrl}/profile/${profileData?.username}/friends`, { data: { friend_username: loggedInUsername } });
176174
setIsFriend(false);
177-
if (username) { // Ensure username is defined
175+
if (username) {
178176
dispatch(setFriendStatus({ username, isFriend: false }));
179177
}
180178
} else {
181-
// Connect if not a friend
182179
await axios.post(`${backendUrl}/profile/${profileData?.username}/friends`, { friend_username: loggedInUsername });
183180
setIsFriend(true);
184-
if (username) { // Ensure username is defined
181+
if (username) {
185182
dispatch(setFriendStatus({ username, isFriend: true }));
186183
}
187184
}
188185

189-
// Fetch the updated friends list for the visited user
190186
const friendsResponse = await axios.get(`${backendUrl}/profile/${username}/friends`);
191187
setFriendsList(friendsResponse.data.friends);
192188
} catch (error) {
@@ -203,7 +199,6 @@ const Dashboard = () => {
203199
return (
204200
<div className='flex flex-col w-full h-screen bg-neutral-50 p-4 overflow-y-auto bg-white dark:bg-zinc-950'>
205201
<div className='grid gap-6 min-h-screen grid-cols-1 lg:grid-cols-[350px_1fr_300px] lg:px-6 xl:gap-10 w-full'>
206-
{/* Sidebar */}
207202
<div className='space-y-6 py-6 rounded-2xl border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-zinc-900 px-2 '>
208203
<div className='flex flex-col items-center space-y-3'>
209204
{githubData ? (
@@ -234,7 +229,6 @@ const Dashboard = () => {
234229
</p>
235230
</div>
236231
</div>
237-
{/* Profile Info Section */}
238232
<div className='space-y-4'>
239233
<div className='space-y-2'>
240234
<p className='font-semibold'>Bio</p>
@@ -258,7 +252,6 @@ const Dashboard = () => {
258252
)}
259253
</div>
260254
</div>
261-
{/* GitHub and LeetCode Links */}
262255
<div className='flex space-x-4'>
263256
{profileData ? (
264257
<>
@@ -310,14 +303,13 @@ const Dashboard = () => {
310303
</div>
311304
)}
312305
</div>
313-
{/* Friend Button */}
306+
314307
{!isOwnProfile && (
315308
<button onClick={handleFriendRequest} className="bg-blue-500 text-white rounded py-2 px-4">
316309
{isFriend ? 'Disconnect' : 'Connect'}
317310
</button>
318311
)}
319312

320-
{/* Friends List */}
321313
<div>
322314
<h2 className='text-xl font-bold'>Friends</h2>
323315
{friends.length > 0 ? (
@@ -330,10 +322,7 @@ const Dashboard = () => {
330322
</div>
331323
</div>
332324

333-
{/* Main Content Section */}
334325
<div className='space-y-6 col-span-2 rounded-2xl border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-zinc-900 p-4'>
335-
{/* Friends Section */}
336-
337326
<h2 className='text-xl font-bold'>Projects</h2>
338327
<div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
339328
{profileData ? (
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from flask import request, jsonify, current_app
2+
from models import Project
3+
from extensions import neo4j_db
4+
5+
def add_project(username):
6+
data = request.get_json()
7+
8+
# Get project details from request
9+
title = data.get('title')
10+
description = data.get('description', '')
11+
repo_link = data.get('repo_link', '')
12+
tags = data.get('tags', '')
13+
14+
# Define a query to create a project without tags initially
15+
create_project_query = """
16+
MATCH (u:User {username: $username})
17+
CREATE (p:Project {title: $title, description: $description, repo_link: $repo_link, tags: $tags})
18+
CREATE (u)-[:OWNS]->(p)
19+
RETURN p
20+
"""
21+
22+
try:
23+
with neo4j_db.driver.session() as session:
24+
# Create the project
25+
result = session.run(create_project_query, username=username, title=title, description=description, repo_link=repo_link, tags=tags)
26+
project_record = result.single()
27+
28+
if project_record:
29+
project = project_record["p"]
30+
31+
domain_tags = [tag for tag in tags.split(',') if tag.strip() in tags]
32+
33+
# Update project with tags
34+
update_project_query = """
35+
MATCH (p:Project {title: $title, description: $description, repo_link: $repo_link})
36+
WITH p, $tags AS tags
37+
UNWIND tags AS tagName
38+
MERGE (t:Tag {name: tagName})
39+
CREATE (p)-[:TAGGED_WITH]->(t)
40+
RETURN p
41+
"""
42+
43+
# Update the project with tags
44+
session.run(update_project_query, title=title, description=description, repo_link=repo_link, tags=domain_tags)
45+
46+
return jsonify({'message': 'Project added and categorized successfully', 'project': {
47+
'title': project["title"],
48+
'description': project.get("description", ""),
49+
'repoLink': project.get("repo_link", ""),
50+
'tags': domain_tags
51+
}}), 201
52+
else:
53+
return jsonify({'message': 'User not found'}), 404
54+
except Exception as e:
55+
current_app.logger.error(f"Error adding project: {e}")
56+
return jsonify({'message': 'An error occurred while adding the project'}), 500
57+
58+
59+
60+
def update_project(username, project_id):
61+
data = request.get_json()
62+
title = data.get('title')
63+
description = data.get('description')
64+
repo_link = data.get('repo_link')
65+
tags = data.get('tags', '')
66+
67+
query = """
68+
MATCH (u:User {username: $username})-[:OWNS]->(p:Project {id: $project_id})
69+
SET p.title = $title, p.description = $description, p.repo_link = $repo_link
70+
WITH p
71+
OPTIONAL MATCH (p)-[r:TAGGED_WITH]->(t:Tag)
72+
DELETE r
73+
WITH p
74+
UNWIND $tags AS tagName
75+
MERGE (t:Tag {name: tagName})
76+
CREATE (p)-[:TAGGED_WITH]->(t)
77+
RETURN p
78+
"""
79+
with neo4j_db.driver.session() as session:
80+
result = session.run(query, username=username, project_id=project_id, title=title, description=description, repo_link=repo_link, tags=tags.split(', ') if tags else [])
81+
if result.single():
82+
return jsonify({'message': 'Project updated successfully'}), 200
83+
return jsonify({'message': 'Project or user not found'}), 404
84+
85+
def delete_project(username, project_title):
86+
query = """
87+
MATCH (u:User {username: $username})-[:OWNS]->(p:Project {title: $project_title})
88+
OPTIONAL MATCH (p)-[r]-()
89+
DELETE r, p
90+
RETURN u
91+
"""
92+
with neo4j_db.driver.session() as session:
93+
result = session.run(query, username=username, project_title=project_title)
94+
if result.single():
95+
return jsonify({'message': 'Project deleted successfully'}), 200
96+
return jsonify({'message': 'Project or user not found'}), 404
Lines changed: 1 addition & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
from flask import request, jsonify, current_app
1+
from flask import request, jsonify
22
from extensions import neo4j_db
3-
from models import User, Project, Tag
4-
from sqlalchemy.orm import sessionmaker
5-
import os
63

74
def get_profile(username):
85
logged_in_user = request.args.get('logged_in_user')
@@ -41,7 +38,6 @@ def get_profile(username):
4138
profile_data['projects'] = projects
4239

4340
if logged_in_user:
44-
# Check if the logged-in user is friends with the profile user
4541
friendship_query = """
4642
MATCH (u1:User {username: $logged_in_user})-[:FRIEND]->(u2:User {username: $username})
4743
RETURN COUNT(u1) > 0 AS isFriend
@@ -71,95 +67,3 @@ def update_profile(username):
7167
return jsonify({'message': 'Profile updated successfully'}), 200
7268
return jsonify({'message': 'User not found'}), 404
7369

74-
def add_project(username):
75-
data = request.get_json()
76-
77-
# Get project details from request
78-
title = data.get('title')
79-
description = data.get('description', '')
80-
repo_link = data.get('repo_link', '')
81-
tags = data.get('tags', '')
82-
83-
# Define a query to create a project without tags initially
84-
create_project_query = """
85-
MATCH (u:User {username: $username})
86-
CREATE (p:Project {title: $title, description: $description, repo_link: $repo_link, tags: $tags})
87-
CREATE (u)-[:OWNS]->(p)
88-
RETURN p
89-
"""
90-
91-
try:
92-
with neo4j_db.driver.session() as session:
93-
# Create the project
94-
result = session.run(create_project_query, username=username, title=title, description=description, repo_link=repo_link, tags=tags)
95-
project_record = result.single()
96-
97-
if project_record:
98-
project = project_record["p"]
99-
100-
domain_tags = [tag for tag in tags.split(',') if tag.strip() in tags]
101-
102-
# Update project with tags
103-
update_project_query = """
104-
MATCH (p:Project {title: $title, description: $description, repo_link: $repo_link})
105-
WITH p, $tags AS tags
106-
UNWIND tags AS tagName
107-
MERGE (t:Tag {name: tagName})
108-
CREATE (p)-[:TAGGED_WITH]->(t)
109-
RETURN p
110-
"""
111-
112-
# Update the project with tags
113-
session.run(update_project_query, title=title, description=description, repo_link=repo_link, tags=domain_tags)
114-
115-
return jsonify({'message': 'Project added and categorized successfully', 'project': {
116-
'title': project["title"],
117-
'description': project.get("description", ""),
118-
'repoLink': project.get("repo_link", ""),
119-
'tags': domain_tags
120-
}}), 201
121-
else:
122-
return jsonify({'message': 'User not found'}), 404
123-
except Exception as e:
124-
current_app.logger.error(f"Error adding project: {e}")
125-
return jsonify({'message': 'An error occurred while adding the project'}), 500
126-
127-
128-
129-
def update_project(username, project_id):
130-
data = request.get_json()
131-
title = data.get('title')
132-
description = data.get('description')
133-
repo_link = data.get('repo_link')
134-
tags = data.get('tags', '')
135-
136-
query = """
137-
MATCH (u:User {username: $username})-[:OWNS]->(p:Project {id: $project_id})
138-
SET p.title = $title, p.description = $description, p.repo_link = $repo_link
139-
WITH p
140-
OPTIONAL MATCH (p)-[r:TAGGED_WITH]->(t:Tag)
141-
DELETE r
142-
WITH p
143-
UNWIND $tags AS tagName
144-
MERGE (t:Tag {name: tagName})
145-
CREATE (p)-[:TAGGED_WITH]->(t)
146-
RETURN p
147-
"""
148-
with neo4j_db.driver.session() as session:
149-
result = session.run(query, username=username, project_id=project_id, title=title, description=description, repo_link=repo_link, tags=tags.split(', ') if tags else [])
150-
if result.single():
151-
return jsonify({'message': 'Project updated successfully'}), 200
152-
return jsonify({'message': 'Project or user not found'}), 404
153-
154-
def delete_project(username, project_title):
155-
query = """
156-
MATCH (u:User {username: $username})-[:OWNS]->(p:Project {title: $project_title})
157-
OPTIONAL MATCH (p)-[r]-()
158-
DELETE r, p
159-
RETURN u
160-
"""
161-
with neo4j_db.driver.session() as session:
162-
result = session.run(query, username=username, project_title=project_title)
163-
if result.single():
164-
return jsonify({'message': 'Project deleted successfully'}), 200
165-
return jsonify({'message': 'Project or user not found'}), 404

server/api/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from api.handlers.auth.userauth import signup, login, check_auth, home, logout, index, check_username
2-
from api.handlers.user.profile import get_profile, update_profile, add_project, update_project, delete_project
2+
from api.handlers.user.profile import get_profile, update_profile
3+
from api.handlers.projects.projects import add_project, update_project, delete_project
34
from api.handlers.analyze.githubdata import github_data, top_languages, streak_stats, pinned_repos, streak_chart
45
from api.handlers.analyze.leetcodedata import leetcode_data, leetcode_card
56
from api.handlers.query.querymodel import chat,chat_history

0 commit comments

Comments
 (0)