Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const router = express.Router();
router.post("/signup", validateRequest(signupSchema), async (req, res) => {

const { username, email, password } = req.body;

try {
const existingUser = await User.findOne({
$or: [{ email }, { username }],
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"postcss": "^8.4.47",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-github-calendar": "^5.0.6",
"react-hot-toast": "^2.4.1",
"react-icons": "^5.3.0",
"react-router-dom": "^6.28.0",
Expand Down
11 changes: 11 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
will-change: filter;
transition: filter 300ms;
}

.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}

.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
Expand All @@ -22,6 +24,7 @@
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
Expand All @@ -40,3 +43,11 @@
.read-the-docs {
color: #888;
}

.calendar-container svg text {
fill: #1f2937 !important;
}

.dark .calendar-container svg text {
fill: #d1d5db !important;
}
6 changes: 5 additions & 1 deletion src/Routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import Signup from "../pages/Signup/Signup.tsx";
import Login from "../pages/Login/Login.tsx";
import ContributorProfile from "../pages/ContributorProfile/ContributorProfile.tsx";
import Home from "../pages/Home/Home.tsx";
import Activity from "../pages/Activity.tsx";
import ProfilePage from "../pages/Profile/ProfilePage.tsx";
import EditProfilePage from "../pages/Profile/EditProfilePage.tsx";
import Activity from "../pages/Activity.tsx";
import PrivacyPolicy from "../pages/Privacy/PrivacyPolicy.tsx"; // ✅ Updated import path to match your new folder structure

const Router = () => {
Expand All @@ -21,6 +23,8 @@ const Router = () => {
<Route path="/contact" element={<Contact />} />
<Route path="/contributors" element={<Contributors />} />
<Route path="/contributor/:username" element={<ContributorProfile />} />
<Route path="/me" element={<ProfilePage />}></Route>
<Route path="/profile/edit" element={<EditProfilePage />}></Route>
<Route path="/activity" element={<Activity />} />

{/* Privacy Policy page route */}
Expand Down
79 changes: 66 additions & 13 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { NavLink, Link } from "react-router-dom";
import { useState, useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
import ProfileDropDown from "./Profile/ProfileDropDown";
import { logoutUser } from "../services/auth";

import { Moon, Sun, Menu, X, Github } from "lucide-react";

const Navbar: React.FC = () => {
Expand All @@ -11,12 +14,21 @@ const Navbar: React.FC = () => {
if (!themeContext) return null;

const { toggleTheme, mode } = themeContext;
const storedUser = localStorage.getItem("user");
let user = null;

try {
user = storedUser ? JSON.parse(storedUser) : null;
} catch (error) {
console.error("Invalid user data in local Storage");
localStorage.removeItem("user");
user = null;
}

const navLinkStyles = ({ isActive }: { isActive: boolean }) =>
`px-4 py-2 rounded-xl text-sm lg:text-base font-semibold transition-all duration-300 ${
isActive
? "text-blue-600 bg-blue-100 dark:bg-blue-900/40 shadow-sm"
: "text-slate-700 dark:text-gray-300 hover:text-blue-500"
`px-4 py-2 rounded-xl text-sm lg:text-base font-semibold transition-all duration-300 ${isActive
? "text-blue-600 bg-blue-100 dark:bg-blue-900/40 shadow-sm"
: "text-slate-700 dark:text-gray-300 hover:text-blue-500"
}`;

const closeMenu = () => setIsOpen(false);
Expand Down Expand Up @@ -52,11 +64,14 @@ const Navbar: React.FC = () => {
<NavLink to="/contributors" className={navLinkStyles}>
Contributors
</NavLink>

<NavLink to="/login" className={navLinkStyles}>
{!user && (<NavLink
to="/login"
className="text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
>
Login
</NavLink>
</NavLink>)}

{user && <ProfileDropDown user={user} />}
{/* Theme Toggle */}
<button
onClick={toggleTheme}
Expand Down Expand Up @@ -130,14 +145,52 @@ const Navbar: React.FC = () => {
>
Contributors
</NavLink>
{!user && (
<NavLink
to="/login"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
onClick={closeMenu}
>
Login
</NavLink>
)}
Comment thread
pranav-gawande1 marked this conversation as resolved.
{user && (
<>
<NavLink
to="/me"
className={navLinkStyles}
onClick={() => setIsOpen(false)}
>
My Profile
</NavLink>

<NavLink
to="/profile/edit"
className={navLinkStyles}
onClick={() => setIsOpen(false)}
>
Edit Profile
</NavLink>
<button
className="px-4 py-2 rounded-xl text-sm lg:text-base font-semibold transition-all duration-300 shadow-sm text-start"
onClick={
logoutUser
}
>
Logout
</button>
</>
)}
Comment thread
pranav-gawande1 marked this conversation as resolved.

<NavLink
to="/login"
className={navLinkStyles}
onClick={closeMenu}
<button
onClick={() => {
toggleTheme();
setIsOpen(false);
}}
className="text-sm font-semibold px-3 py-1 rounded border border-gray-500 hover:text-gray-300 hover:border-gray-300 transition duration-200 w-full text-left"
>
Login
</NavLink>
{mode === "dark" ? "🌞 Light" : "🌙 Dark"}
</button>
</div>
</div>
)}
Expand Down
24 changes: 24 additions & 0 deletions src/components/Profile/AchievementCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
interface AchievementProps {
title: string
description: string
}

const AchievementCard = ({
title,
description
}: AchievementProps) => {
return (
<div className="rounded-xl border border-zinc-800 bg-zinc-900 p-5">

<h3 className="text-lg font-semibold">
{title}
</h3>

<p className="mt-2 text-sm text-zinc-400">
{description}
</p>
</div>
)
}

export default AchievementCard
69 changes: 69 additions & 0 deletions src/components/Profile/ContributionHeatmap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { GitHubCalendar } from "react-github-calendar";

interface UsernameProps {
username: string;
}

const calendarTheme = {
light: [
"#ebedf0",
"#9be9a8",
"#40c463",
"#30a14e",
"#216e39",
],
dark: [
"#161b22",
"#0e4429",
"#006d32",
"#26a641",
"#39d353",
],
};

const ContributionHeatmap = ({
username
}: UsernameProps) => {

if (!username) return null;

const themeMode =
typeof window !== "undefined"
? localStorage.getItem("theme")
: "light";

return (

<div className="rounded-2xl border border-zinc-200 bg-white p-6
dark:border-zinc-800 dark:bg-zinc-900">

<h2 className="mb-4 text-xl font-semibold
text-zinc-700 dark:text-zinc-300">

Contributions

</h2>

<div className="calendar-container overflow-x-auto pb-2 flex justify-center">

<GitHubCalendar
username={username}
blockSize={12}
blockMargin={4}
fontSize={14}
theme={calendarTheme}
colorScheme={
themeMode === "dark"
? "dark"
: "light"
}
/>

</div>

</div>

);
};

export default ContributionHeatmap;
62 changes: 62 additions & 0 deletions src/components/Profile/LanguageChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
interface LanguageChartProps {
languages: Record<string, number>;
}

const LanguageChart = ({ languages }: LanguageChartProps) => {
const total = Object.values(languages).reduce((sum, count) => sum + count, 0);
return (
<div className="rounded-2xl border border-zinc-200 bg-white p-6
dark:border-zinc-800 dark:bg-zinc-900">

<h2 className="mb-4 text-xl font-semibold text-zinc-700 dark:text-zinc-300">
Languages Used
</h2>
<div className="space-y-4">

{Object.entries(languages)
.map(([language, count]) => {

const percentage =
total > 0
? Math.round((count / total) * 100)
: 0;

return (

<div key={language} className="rounded-xl shadow-xl border-zinc-200 dark:border-zinc-800 p-2">

<div className="mb-1 flex justify-between">

<span className="text-zinc-700 dark:text-zinc-300">
{language}
</span>

<span className="text-zinc-700 dark:text-zinc-300">
{percentage}%
</span>

</div>

<div className="h-3 rounded-full bg-white dark:bg-zinc-900">

<div
className="h-3 rounded-full bg-blue-500"
style={{
width: `${percentage}%`
}}
/>

</div>

</div>

);

})}

</div>
</div>
)
}

export default LanguageChart
Loading