Skip to content
Merged
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,22 @@ To run this project locally, you'll need your own Firebase project:
5. **Open your browser:**
Navigate to [http://localhost:3000](http://localhost:3000) to see the application running.

### 🚀 Firebase Hosting Deployment

To deploy the production-ready site directly to Firebase Hosting:

1. **Build the production static export**:
This compiles the Next.js App Router files into highly optimized static assets inside the `out/` directory:
```bash
npm run build
```

2. **Deploy to Firebase**:
Deploy the build files along with custom Firestore indexes and rules to the live platform:
```bash
npx firebase deploy
```

## 📜 Scripts

- `npm run dev`: Starts the development server.
Expand Down
7 changes: 7 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ export default function RootLayout({
}>) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<script
async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5192400464044260"
crossOrigin="anonymous"
/>
</head>
<body className={`${inter.variable} ${spaceGrotesk.variable} ${barlowCondensed.variable}`}>
<ThemeProvider
attribute="class"
Expand Down
12 changes: 10 additions & 2 deletions src/app/opensource/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,15 @@ export default function OpenSourcePage() {
localStorage.setItem('github_access_token', token); // Persist token

// Fetch Extended Data
const { fetchUserProfile, fetchUserRepos, fetchUserActivity } = await import('@/lib/github');
const { fetchUserProfile, fetchUserRepos, fetchUserActivity, fetchRepoContributorStats, calculateUserLinesContributed } = await import('@/lib/github');
const profile = await fetchUserProfile(token);
const repos = await fetchUserRepos(token);
const activity = await fetchUserActivity(profile.login, token);

// Fetch contributor stats (lines and commits)
const repoStats = await fetchRepoContributorStats(token);
const userLineStats = calculateUserLinesContributed(repoStats, profile.login);

// Calculate Total Stars
const totalStars = repos.reduce((acc: number, repo: any) => acc + (repo.stargazers_count || 0), 0);

Expand Down Expand Up @@ -106,7 +110,11 @@ export default function OpenSourcePage() {
bio: profile.bio,
company: profile.company,
location: profile.location,
createdAt: profile.created_at
createdAt: profile.created_at,
linesAdded: userLineStats.additions,
linesRemoved: userLineStats.deletions,
linesContributed: userLineStats.additions,
contributions: userLineStats.commits
},
github: profile.login, // Store username
// Store detailed data in subcollection or just basic stats here?
Expand Down
27 changes: 21 additions & 6 deletions src/app/u/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { doc, getDoc, collection, query, where, getDocs, orderBy, updateDoc, arr
import { db } from '@/lib/firebase';
import { getEmbedUrl } from '@/lib/utils';
import { teamMembers } from '@/data/team';
import { Trophy, Flame, Star, Target, MapPin, Link as LinkIcon, Calendar, Phone, Github, Instagram, Linkedin, CheckCircle, User as UserIcon, Heart, Share2, Video, Image as ImageIcon, Globe, Check, Users, Shield, X, GitMerge, BookOpen, Plus } from 'lucide-react';
import { Trophy, Flame, Star, Target, MapPin, Link as LinkIcon, Calendar, Phone, Github, Instagram, Linkedin, CheckCircle, User as UserIcon, Heart, Share2, Video, Image as ImageIcon, Globe, Check, Users, Shield, X, GitMerge, BookOpen, Plus, Code2 } from 'lucide-react';
import styles from '@/components/profile/Profile.module.css';
import Rewards from '@/components/profile/Rewards';
import FollowButton from '@/components/profile/FollowButton';
import LoginHeatmap from '@/components/profile/LoginHeatmap';
import { useSearchParams } from 'next/navigation';
import { useAuth } from '@/context/AuthContext';
import { GIT_FALLBACK_STATS } from '@/lib/github';

interface PublicUser {
id?: string;
Expand Down Expand Up @@ -58,6 +59,10 @@ interface PublicUser {
location?: string;
createdAt?: string;
recentActivity?: any[];
linesAdded?: number;
linesRemoved?: number;
linesContributed?: number;
contributions?: number;
};
}

Expand Down Expand Up @@ -481,26 +486,36 @@ function ProfileContent() {
<h3 className="text-xl font-bold flex items-center gap-2 mb-4">
<Github className="text-primary" size={20} /> GitHub Activity
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-4">
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Globe className="mb-2 text-primary h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.repos || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Repositories</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Repositories</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Star className="mb-2 text-yellow-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.totalStars || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Total Stars</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Total Stars</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Users className="mb-2 text-blue-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.followers || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Followers</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Followers</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<UserIcon className="mb-2 text-purple-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.following || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Following</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Following</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Code2 className="mb-2 text-emerald-500 h-6 w-6" />
<span className="text-2xl font-bold">{(user.githubStats.linesContributed ?? GIT_FALLBACK_STATS[(user.githubStats.username || '').toLowerCase()]?.additions ?? 0).toLocaleString()}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Lines Contributed</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<GitMerge className="mb-2 text-orange-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.contributions ?? GIT_FALLBACK_STATS[(user.githubStats.username || '').toLowerCase()]?.commits ?? 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Commits Contributed</span>
</div>
</div>

Expand Down
37 changes: 30 additions & 7 deletions src/components/profile/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
import { useAuth } from '@/context/AuthContext';
import { useRouter } from 'next/navigation';
import { teamMembers } from '@/data/team';
import { Trophy, Flame, Star, Target, MapPin, Link as LinkIcon, Calendar, Phone, LogOut, Camera, Save, X, Github, Instagram, Linkedin, CheckCircle, Share2, Shield, Copy, Check, Plus, Edit3, Users, Globe, BookOpen, GitMerge } from 'lucide-react';
import { Trophy, Flame, Star, Target, MapPin, Link as LinkIcon, Calendar, Phone, LogOut, Camera, Save, X, Github, Instagram, Linkedin, CheckCircle, Share2, Shield, Copy, Check, Plus, Edit3, Users, Globe, BookOpen, GitMerge, Code2 } from 'lucide-react';
import styles from './Profile.module.css';
import 'github-markdown-css/github-markdown.css';
import ProjectUploadModal from '@/components/projects/ProjectUploadModal';
Expand All @@ -20,7 +20,16 @@ import { collection, query, where, orderBy, getDocs, doc, updateDoc, arrayUnion,
import { db } from '@/lib/firebase';
import { calculateLevel } from '@/lib/points';
import { getEmbedUrl } from '@/lib/utils';

import { GIT_FALLBACK_STATS } from '@/lib/github';

/**
* UserProfile component renders the main dashboard profile page for authenticated developers.
* It manages:
* - Local layout state for editing avatars and bios.
* - Loading and sorting uploaded developer projects from Firestore.
* - Real-time calculations of gamification Dev Points, progress levels, and achievements.
* - Rendering animated progress rings and privacy toggle modals.
*/
export default function UserProfile() {
const { user, logout, updateUserProfile } = useAuth();
const router = useRouter();
Expand All @@ -37,6 +46,10 @@ export default function UserProfile() {
const levelInfo = calculateLevel(user?.points || 0);
const targetProgress = levelInfo.progress;

/**
* Triggers animated loading effect for the custom circular progress ring
* once the component is mounted.
*/
useEffect(() => {
if (user) {
const timer = setTimeout(() => {
Expand Down Expand Up @@ -511,26 +524,36 @@ export default function UserProfile() {
<h3 className="text-xl font-bold flex items-center gap-2 mb-4">
<Github className="text-primary" size={20} /> GitHub Activity
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-4">
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<BookOpen className="mb-2 text-primary h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.repos || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Repositories</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Repositories</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Star className="mb-2 text-yellow-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.totalStars || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Total Stars</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Total Stars</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Users className="mb-2 text-blue-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.followers || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Followers</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Followers</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<GitMerge className="mb-2 text-purple-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.following || 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider">Following</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Following</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<Code2 className="mb-2 text-emerald-500 h-6 w-6" />
<span className="text-2xl font-bold">{(user.githubStats.linesContributed ?? GIT_FALLBACK_STATS[(user.githubStats.username || '').toLowerCase()]?.additions ?? 0).toLocaleString()}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Lines Contributed</span>
</div>
<div className="flex flex-col items-center p-4 bg-muted/30 rounded-xl border border-border/50 hover:border-primary/50 transition-colors">
<GitMerge className="mb-2 text-orange-500 h-6 w-6" />
<span className="text-2xl font-bold">{user.githubStats.contributions ?? GIT_FALLBACK_STATS[(user.githubStats.username || '').toLowerCase()]?.commits ?? 0}</span>
<span className="text-xs text-muted-foreground font-medium uppercase tracking-wider text-center">Commits Contributed</span>
</div>
</div>

Expand Down
9 changes: 9 additions & 0 deletions src/components/resources/QuizComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { useState } from "react";
import styles from "./QuizComponent.module.css";
import { useGamification } from "../../context/GamificationContext";

/**
* Static list of quiz questions used for developer resource testing.
* Each question contains a prompt, list of choice options, and the correct answer.
*/
const questions = [
{
question: "What is React?",
Expand All @@ -15,6 +19,11 @@ const questions = [
},
];

/**
* QuizComponent renders an interactive quiz interface.
* On completion, it calculates the user's score and awards gamification XP
* through the global GamificationContext depending on performance.
*/
export default function QuizComponent() {
const { addXp } = useGamification();

Expand Down
3 changes: 3 additions & 0 deletions src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ interface User {
company?: string;
location?: string;
createdAt?: string;
linesAdded?: number;
linesRemoved?: number;
linesContributed?: number;
};
followers?: string[]; // Array of user UIDs
following?: string[]; // Array of user UIDs
Expand Down
Loading