diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 7d51aa6..a194a66 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,29 +1,37 @@
# Pull Request Template 🚀
## Description
+
Please include a summary of the changes and the related issue. Please also include relevant motivation and context.
## Related Issue
+
Fixes # (issue number) or Closes # (issue number)
## Type of Change
+
Please delete options that are not relevant:
+
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Screenshots / Videos (if applicable)
+
Please add screenshots or screen recordings to demonstrate the visual changes.
## Testing Done
+
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
+
- [ ] Command run: `npm run test`
- [ ] Command run: `npm run lint`
- [ ] Command run: `npm run build`
- [ ] Visual verification on local dev server (`http://localhost:5173`)
## Checklist
+
- [ ] My code follows the style guidelines of this project.
- [ ] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
@@ -34,6 +42,7 @@ Please describe the tests that you ran to verify your changes. Provide instructi
- [ ] Any dependent changes have been merged and published in downstream modules.
## Contributor Declaration
+
- [ ] I confirm that this contribution is made under the rules of **GSSoC 2026** and **NSoC 2026**.
- [ ] I confirm that I have been assigned the related issue by a maintainer before opening this PR.
- [ ] I have read the [Contributing Guidelines](https://github.com/indresh404/RankerHub/blob/main/docs/CONTRIBUTING.md) and [Code of Conduct](https://github.com/indresh404/RankerHub/blob/main/docs/CODE_OF_CONDUCT.md).
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ef1bf50..fadb031 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,7 +3,7 @@ name: CI Checks
on:
pull_request:
push:
- branches: [ main ]
+ branches: [main]
jobs:
lint:
@@ -18,7 +18,7 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 20
- cache: 'npm'
+ cache: "npm"
- name: Install dependencies
run: npm ci
@@ -38,7 +38,7 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 20
- cache: 'npm'
+ cache: "npm"
- name: Install dependencies
run: npm ci
@@ -58,7 +58,7 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 20
- cache: 'npm'
+ cache: "npm"
- name: Install dependencies
run: npm ci
diff --git a/.github/workflows/lock-closed.yml b/.github/workflows/lock-closed.yml
index bdbb4fb..eeefe14 100644
--- a/.github/workflows/lock-closed.yml
+++ b/.github/workflows/lock-closed.yml
@@ -5,7 +5,7 @@ name: Lock Closed Threads
on:
schedule:
- - cron: '0 2 * * *' # Run daily at 2:00 AM
+ - cron: "0 2 * * *" # Run daily at 2:00 AM
workflow_dispatch:
permissions:
@@ -20,7 +20,7 @@ jobs:
uses: dessant/lock-threads@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- issue-inactive-days: '14'
- pr-inactive-days: '14'
- issue-comment: 'This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.'
- pr-comment: 'This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related discussions.'
+ issue-inactive-days: "14"
+ pr-inactive-days: "14"
+ issue-comment: "This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs."
+ pr-comment: "This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related discussions."
diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml
index 87d19ec..d653b93 100644
--- a/.github/workflows/quality-checks.yml
+++ b/.github/workflows/quality-checks.yml
@@ -2,7 +2,7 @@ name: Quality & Formatting Checks
on:
push:
- branches: [ main ]
+ branches: [main]
pull_request:
issues:
types: [opened]
@@ -24,7 +24,7 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 20
- cache: 'npm'
+ cache: "npm"
- name: Install dependencies
run: npm ci
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index e4eb080..fa967ae 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -5,7 +5,7 @@ name: Mark stale issues and pull requests
on:
schedule:
- - cron: '30 1 * * *' # Run daily
+ - cron: "30 1 * * *" # Run daily
workflow_dispatch:
permissions:
@@ -19,11 +19,11 @@ jobs:
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!'
- stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!'
+ stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!"
+ stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!"
days-before-stale: 20
days-before-close: 7
- stale-issue-label: 'stale'
- stale-pr-label: 'stale'
- exempt-pr-labels: 'keep-open,pinned,security'
- exempt-issue-labels: 'keep-open,pinned,security'
+ stale-issue-label: "stale"
+ stale-pr-label: "stale"
+ exempt-pr-labels: "keep-open,pinned,security"
+ exempt-issue-labels: "keep-open,pinned,security"
diff --git a/BRANCH_PROTECTION.md b/BRANCH_PROTECTION.md
index 470cd2d..b2e5794 100644
--- a/BRANCH_PROTECTION.md
+++ b/BRANCH_PROTECTION.md
@@ -6,7 +6,7 @@ To ensure repository integrity and maintain high code quality standards, please
1. Navigate to the repository page on GitHub.
2. Click on the **Settings** tab at the top.
-3. In the left sidebar, click on **Branches** (under *Code and automation*).
+3. In the left sidebar, click on **Branches** (under _Code and automation_).
4. Under **Branch protection rules**, click **Add rule** (or edit the existing rule for `main`).
5. Set the **Branch name pattern** to `main` (or the default branch name).
6. Enable the following recommended settings:
@@ -14,13 +14,15 @@ To ensure repository integrity and maintain high code quality standards, please
---
### 1. Require a Pull Request Before Merging
+
- [x] Check **Require a pull request before merging**.
- [x] Check **Require approvals**.
- - Set *Required number of approvals before merging* to **1**.
+ - Set _Required number of approvals before merging_ to **1**.
- [x] Check **Dismiss stale pull request approvals when new commits are pushed**.
- [x] Check **Require review from Code Owners**. (Forces PRs to be approved by owner of code owners path).
### 2. Require Status Checks to Pass Before Merging
+
- [x] Check **Require status checks to pass before merging**.
- [x] Check **Require branches to be up to date before merging**.
- In the search box, find and select the following status checks (they will appear after running the workflows at least once):
@@ -29,6 +31,7 @@ To ensure repository integrity and maintain high code quality standards, please
- `Build Application`
### 3. Block Force Pushes & Deletions
+
- [x] Check **Restrict who can push to matching branches**. (Ensures write-access users can only merge via PRs).
- [x] (Enabled by default) **Block force pushes** and **Block deletions**.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 6c4086d..bb7f02a 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
Examples of behavior that contributes to creating a positive environment include:
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
+- The use of sexualized language or imagery and unwelcome sexual attention or advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1afeed9..02c6397 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,11 +15,14 @@ Please maintain a respectful, welcoming, and inclusive environment. Be helpful t
## Getting Started
### 1. Prerequisites
+
Ensure you have the following installed on your local machine:
+
- [Node.js](https://nodejs.org/) (v20.0.0 or higher recommended)
- [Git](https://git-scm.com/)
### 2. Fork & Clone
+
1. Fork the [RankerHub Repository](https://github.com/indresh404/RankerHub) to your own GitHub account.
2. Clone your fork locally:
```bash
@@ -28,12 +31,15 @@ Ensure you have the following installed on your local machine:
```
### 3. Install Dependencies
+
Run the following command to install the project dependencies:
+
```bash
npm install
```
### 4. Setup Environment Variables
+
1. Copy the `.env.example` file to create a `.env` file in the root directory:
```bash
cp .env.example .env
@@ -41,10 +47,13 @@ npm install
2. Open the `.env` file and fill in your Firebase configuration keys (see the [Firebase Setup](#firebase-setup) below).
### 5. Run the Project
+
Start the local development server:
+
```bash
npm run dev
```
+
The application will be running locally at `http://localhost:5173`.
---
@@ -52,6 +61,7 @@ The application will be running locally at `http://localhost:5173`.
## Firebase Setup
To get your own Firebase credentials for local development:
+
1. Go to the [Firebase Console](https://console.firebase.google.com/).
2. Create a new Firebase project (e.g., `rankerhub-dev`).
3. Add a **Web App** to your project.
@@ -116,7 +126,9 @@ For the private repo sync feature to work, the OAuth App needs the `repo` scope:
To keep the repository history clean, please follow these branching and commit message conventions:
### Branch Naming
+
Create a new branch from `main` before starting your work:
+
- `feat/feature-name` – for new features
- `fix/bug-name` – for bug fixes
- `docs/doc-updates` – for documentation changes
@@ -124,12 +136,15 @@ Create a new branch from `main` before starting your work:
- `chore/task-name` – for maintenance tasks or package upgrades
Example:
+
```bash
git checkout -b feat/user-leaderboard
```
### Commit Messages (Semantic Commits)
+
Write clear and descriptive commit messages following the semantic commit pattern:
+
- `feat: add female developer ranking page`
- `fix: resolve auth validation issue`
- `docs: update setup steps in README`
diff --git a/README.md b/README.md
index 1079c2a..8ca0f73 100644
--- a/README.md
+++ b/README.md
@@ -14,24 +14,24 @@ RankerHub is a developer ranking and coding platform that helps students and dev
## ✨ Features
-* 🔐 GitHub Authentication
-* 🏆 GitHub Contribution Rankings
-* 👩 RankHer – Female Developer Leaderboard
-* 💻 Coding Theory + Practical Questions
-* 🎖️ Badge & Achievement System
-* 🔥 Daily Activity Streaks
-* 🏫 College-based Rankings
-* 👤 Developer Profiles
-* 📊 Community Leaderboards
+- 🔐 GitHub Authentication
+- 🏆 GitHub Contribution Rankings
+- 👩 RankHer – Female Developer Leaderboard
+- 💻 Coding Theory + Practical Questions
+- 🎖️ Badge & Achievement System
+- 🔥 Daily Activity Streaks
+- 🏫 College-based Rankings
+- 👤 Developer Profiles
+- 📊 Community Leaderboards
---
## 🛠️ Tech Stack
-* **Frontend**: React + Vite
-* **Styling**: Tailwind CSS
-* **Database & Auth**: Firebase Auth & Firestore Database
-* **Integration**: GitHub API
+- **Frontend**: React + Vite
+- **Styling**: Tailwind CSS
+- **Database & Auth**: Firebase Auth & Firestore Database
+- **Integration**: GitHub API
---
@@ -40,18 +40,21 @@ RankerHub is a developer ranking and coding platform that helps students and dev
To set up RankerHub locally on your machine, follow these steps:
1. **Clone the Repository**:
+
```bash
git clone https://github.com/indresh404/RankerHub.git
cd RankerHub
```
2. **Install Dependencies**:
+
```bash
npm install
```
3. **Configure Environment Variables**:
Create a `.env` file in the root directory and add your Firebase credentials:
+
```env
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_auth_domain
@@ -84,22 +87,24 @@ To set up RankerHub locally on your machine, follow these steps:
If you see errors like `Firebase config error: apiKey is missing` or `FirebaseError: Firebase: Error (auth/invalid-api-key)` in production, this is due to how Vite compiles environment variables.
### The Problem
-* The `.env` file containing your keys is excluded from git (`.gitignore`).
-* When the project builds on a production deployment server (such as **GitHub Actions** for Firebase Hosting), Vite cannot read the `.env` file, and compiles the bundle with `undefined` values.
+
+- The `.env` file containing your keys is excluded from git (`.gitignore`).
+- When the project builds on a production deployment server (such as **GitHub Actions** for Firebase Hosting), Vite cannot read the `.env` file, and compiles the bundle with `undefined` values.
### The Solution (For Firebase Hosting via GitHub Actions)
+
To fix this, you must feed the environment variables to the GitHub Actions build pipeline:
1. **Add Repository Secrets to GitHub**:
- Go to your GitHub repository -> **Settings** -> **Secrets and variables** -> **Actions**.
- Under **Repository secrets**, click **New repository secret** and add each variable:
- * `VITE_FIREBASE_API_KEY`
- * `VITE_FIREBASE_AUTH_DOMAIN`
- * `VITE_FIREBASE_PROJECT_ID`
- * `VITE_FIREBASE_STORAGE_BUCKET`
- * `VITE_FIREBASE_MESSAGING_SENDER_ID`
- * `VITE_FIREBASE_APP_ID`
- * `VITE_FIREBASE_MEASUREMENT_ID`
+ - `VITE_FIREBASE_API_KEY`
+ - `VITE_FIREBASE_AUTH_DOMAIN`
+ - `VITE_FIREBASE_PROJECT_ID`
+ - `VITE_FIREBASE_STORAGE_BUCKET`
+ - `VITE_FIREBASE_MESSAGING_SENDER_ID`
+ - `VITE_FIREBASE_APP_ID`
+ - `VITE_FIREBASE_MEASUREMENT_ID`
2. **Workflows Update**:
Our deployment workflows in [.github/workflows/firebase-hosting-merge.yml](.github/workflows/firebase-hosting-merge.yml) and [.github/workflows/firebase-hosting-pull-request.yml](.github/workflows/firebase-hosting-pull-request.yml) are set up to pass these secrets into Vite during the build phase:
@@ -115,11 +120,11 @@ To fix this, you must feed the environment variables to the GitHub Actions build
## 🚀 Future Plans
-* Real-time coding contests
-* AI-powered coding insights
-* Multi-language compiler support
-* Advanced leaderboard algorithms
-* Open-source contribution scoring
+- Real-time coding contests
+- AI-powered coding insights
+- Multi-language compiler support
+- Advanced leaderboard algorithms
+- Open-source contribution scoring
---
diff --git a/SUPPORT.md b/SUPPORT.md
index 9228d4c..9a29c02 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -5,6 +5,7 @@ Thank you for using RankerHub! If you need help, have questions, or would like t
## 💬 GitHub Discussions (Recommended)
For general questions, idea proposals, show & tell, and discussions, please use the [Discussions Tab](https://github.com/indresh404/RankerHub/discussions) on our GitHub repository. This is the best place to:
+
- Ask "How do I do X?"
- Discuss design patterns.
- Propose new features before creating issues.
@@ -13,6 +14,7 @@ For general questions, idea proposals, show & tell, and discussions, please use
## 🐛 Bug Reports & Feature Requests
If you have confirmed a bug or have a specific, structured feature request:
+
1. Search the [Issues Tab](https://github.com/indresh404/RankerHub/issues) to ensure it hasn't been reported yet.
2. Open a new issue using the appropriate template (e.g., Bug Report or Feature Request).
3. Provide as much detail as possible to help us triage it quickly.
@@ -20,10 +22,12 @@ If you have confirmed a bug or have a specific, structured feature request:
## 📚 Documentation
For guides on getting started, setting up Firebase, and local installation, please refer to:
+
- Our main [README.md](README.md)
- Our [Contributing Guide](CONTRIBUTING.md)
## ✉️ Direct Contact
If you have a query that cannot be discussed publicly (e.g., security vulnerabilities or code of conduct violations), you can contact the maintainer directly at:
+
- **Email**: [indresh.sharma404@gmail.com]
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 8e33e01..d8eb386 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -47,21 +47,25 @@ RankerHub is a gamified GitHub developer ranking platform built with modern web
## Technology Stack
### Frontend Framework & Build Tools
+
- **React 19**: Core UI framework with modern hooks
- **Vite 8**: Next-generation build tool for fast development
- **React Router 7**: Client-side routing and navigation
- **TypeScript Ready**: ESLint support for code quality
### State Management
+
- **Context API**: Global state (Authentication, Theme, Rate Limiting)
- **React Hooks**: Component-level state management
### Styling & Animation
+
- **Tailwind CSS 3.4**: Utility-first CSS framework
- **Framer Motion 12**: Animation library for smooth transitions
- **PostCSS**: CSS preprocessing and optimization
### Backend & Data
+
- **Firebase 12**: Complete backend-as-a-service solution
- Authentication: GitHub OAuth
- Realtime Database: Firestore
@@ -70,11 +74,13 @@ RankerHub is a gamified GitHub developer ranking platform built with modern web
- **Axios**: HTTP client for API calls
### UI Components & Icons
+
- **Lucide React**: Modern icon library (1.17k+ icons)
- **React Icons**: Additional icon variants
- **Lottie React**: Complex animations support
### Testing & Development
+
- **Vitest 4**: Fast unit testing framework
- **ESLint 10**: Code linting and style enforcement
- **Autoprefixer**: CSS vendor prefix automation
@@ -84,133 +90,134 @@ RankerHub is a gamified GitHub developer ranking platform built with modern web
## Directory Structure
### Root Level
+
\\\
rankerhub/
-├── docs/ # Documentation
-│ ├── ARCHITECTURE.md # This file
-│ └── CONTRIBUTING.md # Contribution guidelines
-├── public/ # Static assets (favicons, robots.txt)
-├── src/ # Source code
-├── .env.example # Environment variables template
-├── .firebase.rc # Firebase configuration
-├── .gitignore # Git ignore rules
-├── .markdownlint.json # Markdown linting rules
-├── eslint.config.js # ESLint configuration
-├── firebase.json # Firebase deployment config
-├── firestore.rules # Firestore security rules
-├── index.html # HTML entry point
-├── package.json # NPM dependencies
-├── postcss.config.js # PostCSS configuration
-├── tailwind.config.js # Tailwind CSS configuration
-├── vite.config.js # Vite configuration
-├── vercel.json # Vercel deployment config
-└── README.md # Project overview
+├── docs/ # Documentation
+│ ├── ARCHITECTURE.md # This file
+│ └── CONTRIBUTING.md # Contribution guidelines
+├── public/ # Static assets (favicons, robots.txt)
+├── src/ # Source code
+├── .env.example # Environment variables template
+├── .firebase.rc # Firebase configuration
+├── .gitignore # Git ignore rules
+├── .markdownlint.json # Markdown linting rules
+├── eslint.config.js # ESLint configuration
+├── firebase.json # Firebase deployment config
+├── firestore.rules # Firestore security rules
+├── index.html # HTML entry point
+├── package.json # NPM dependencies
+├── postcss.config.js # PostCSS configuration
+├── tailwind.config.js # Tailwind CSS configuration
+├── vite.config.js # Vite configuration
+├── vercel.json # Vercel deployment config
+└── README.md # Project overview
\\\
### src/ Directory Structure
\\\
src/
-├── assets/ # Static and animated assets
-│ └── animations/ # Lottie animation files
+├── assets/ # Static and animated assets
+│ └── animations/ # Lottie animation files
│
-├── components/ # React components
-│ ├── about/ # About page components
-│ │ ├── ContributorCard.jsx # Individual contributor card
-│ │ ├── ContributorsGrid.jsx # Grid layout for contributors
-│ │ ├── ContributionCTA.jsx # Call-to-action component
-│ │ └── TeamCard.jsx # Team member showcase
-│ │
-│ ├── dashboard/ # Dashboard-specific components
-│ │ ├── ActivityFeed.jsx # User activity timeline
-│ │ ├── RankPreview.jsx # Rank score display
-│ │ ├── StatsCards.jsx # Statistics cards
-│ │ └── StreakCard.jsx # Streak tracking component
-│ │
-│ ├── friends/ # Friend-related components
-│ │ └── DeveloperCard.jsx # Developer profile card
-│ │
-│ ├── layout/ # Layout components
-│ │ ├── Navbar.jsx # Authenticated user navbar
-│ │ ├── PublicNavbar.jsx # Public site navbar
-│ │ ├── PublicFooter.jsx # Public site footer
-│ │ ├── Sidebar.jsx # Desktop sidebar navigation
-│ │ └── MobileSidebar.jsx # Mobile drawer navigation
-│ │
-│ └── ui/ # Reusable UI components
-│ ├── Card.jsx # Generic card wrapper
-│ ├── ErrorBoundary.jsx # Error fallback component
-│ ├── Toast.jsx # Toast notification system
-│ ├── Loader.jsx # Loading spinner
-│ ├── GradientButton.jsx # Styled button component
-│ ├── ThemeToggle.jsx # Dark/light theme switcher
-│ ├── Icons.jsx # Custom icon set
-│ ├── LottiePlayer.jsx # Animation player wrapper
-│ ├── SectionHeader.jsx # Section title component
-│ ├── RateLimitBanner.jsx # API rate limit indicator
-│ ├── HowItWorksModal.jsx # Feature explanation modal
-│ ├── AboutModal.jsx # About information modal
-│ ├── LogoutConfirmModal.jsx # Confirmation dialog
-│ ├── ComingSoonCard.jsx # Coming soon feature card
-│ └── GlobalModals.jsx # Global modal provider
+├── components/ # React components
+│ ├── about/ # About page components
+│ │ ├── ContributorCard.jsx # Individual contributor card
+│ │ ├── ContributorsGrid.jsx # Grid layout for contributors
+│ │ ├── ContributionCTA.jsx # Call-to-action component
+│ │ └── TeamCard.jsx # Team member showcase
+│ │
+│ ├── dashboard/ # Dashboard-specific components
+│ │ ├── ActivityFeed.jsx # User activity timeline
+│ │ ├── RankPreview.jsx # Rank score display
+│ │ ├── StatsCards.jsx # Statistics cards
+│ │ └── StreakCard.jsx # Streak tracking component
+│ │
+│ ├── friends/ # Friend-related components
+│ │ └── DeveloperCard.jsx # Developer profile card
+│ │
+│ ├── layout/ # Layout components
+│ │ ├── Navbar.jsx # Authenticated user navbar
+│ │ ├── PublicNavbar.jsx # Public site navbar
+│ │ ├── PublicFooter.jsx # Public site footer
+│ │ ├── Sidebar.jsx # Desktop sidebar navigation
+│ │ └── MobileSidebar.jsx # Mobile drawer navigation
+│ │
+│ └── ui/ # Reusable UI components
+│ ├── Card.jsx # Generic card wrapper
+│ ├── ErrorBoundary.jsx # Error fallback component
+│ ├── Toast.jsx # Toast notification system
+│ ├── Loader.jsx # Loading spinner
+│ ├── GradientButton.jsx # Styled button component
+│ ├── ThemeToggle.jsx # Dark/light theme switcher
+│ ├── Icons.jsx # Custom icon set
+│ ├── LottiePlayer.jsx # Animation player wrapper
+│ ├── SectionHeader.jsx # Section title component
+│ ├── RateLimitBanner.jsx # API rate limit indicator
+│ ├── HowItWorksModal.jsx # Feature explanation modal
+│ ├── AboutModal.jsx # About information modal
+│ ├── LogoutConfirmModal.jsx # Confirmation dialog
+│ ├── ComingSoonCard.jsx # Coming soon feature card
+│ └── GlobalModals.jsx # Global modal provider
│
-├── context/ # React Context providers
-│ ├── AuthContext.jsx # Authentication state & methods
-│ ├── ThemeContext.jsx # Theme toggle state
-│ ├── RateLimitContext.jsx # API rate limit tracking
-│ └── rateLimitContextValue.js # Rate limit utilities
+├── context/ # React Context providers
+│ ├── AuthContext.jsx # Authentication state & methods
+│ ├── ThemeContext.jsx # Theme toggle state
+│ ├── RateLimitContext.jsx # API rate limit tracking
+│ └── rateLimitContextValue.js # Rate limit utilities
│
-├── data/ # Static data files
-│ ├── activities.js # Sample activity data
-│ ├── leaderboard.js # Leaderboard data
-│ └── streaks.js # Streak data
+├── data/ # Static data files
+│ ├── activities.js # Sample activity data
+│ ├── leaderboard.js # Leaderboard data
+│ └── streaks.js # Streak data
│
-├── hooks/ # Custom React hooks
-│ ├── useTheme.js # Theme context hook
-│ └── useSidebar.js # Sidebar state hook
+├── hooks/ # Custom React hooks
+│ ├── useTheme.js # Theme context hook
+│ └── useSidebar.js # Sidebar state hook
│
-├── layouts/ # Page layout templates
-│ ├── DashboardLayout.jsx # Authenticated user layout
-│ └── PublicLayout.jsx # Public website layout
+├── layouts/ # Page layout templates
+│ ├── DashboardLayout.jsx # Authenticated user layout
+│ └── PublicLayout.jsx # Public website layout
│
-├── lib/ # Library integrations
-│ └── firebase.js # Firebase configuration & helpers
+├── lib/ # Library integrations
+│ └── firebase.js # Firebase configuration & helpers
│
-├── pages/ # Page components (routes)
-│ ├── Home.jsx # Landing page
-│ ├── Login.jsx # GitHub OAuth login
-│ ├── Onboarding.jsx # User setup wizard
-│ ├── Dashboard.jsx # Main dashboard view
-│ ├── Profile.jsx # User profile (self & others)
-│ ├── Friends.jsx # Friends list and followers
-│ ├── Achievements.jsx # Badges and milestones
-│ ├── GitRank.jsx # GitHub ranking details
-│ ├── RankHer.jsx # Women developers ranking
-│ ├── CodingVerse.jsx # Alternative ranking category
-│ ├── CodingOwl.jsx # Night owl ranking
-│ ├── About.jsx # About the project
-│ ├── Terms.jsx # Terms of service
-│ ├── Privacy.jsx # Privacy policy
-│ └── NotFound.jsx # 404 error page
+├── pages/ # Page components (routes)
+│ ├── Home.jsx # Landing page
+│ ├── Login.jsx # GitHub OAuth login
+│ ├── Onboarding.jsx # User setup wizard
+│ ├── Dashboard.jsx # Main dashboard view
+│ ├── Profile.jsx # User profile (self & others)
+│ ├── Friends.jsx # Friends list and followers
+│ ├── Achievements.jsx # Badges and milestones
+│ ├── GitRank.jsx # GitHub ranking details
+│ ├── RankHer.jsx # Women developers ranking
+│ ├── CodingVerse.jsx # Alternative ranking category
+│ ├── CodingOwl.jsx # Night owl ranking
+│ ├── About.jsx # About the project
+│ ├── Terms.jsx # Terms of service
+│ ├── Privacy.jsx # Privacy policy
+│ └── NotFound.jsx # 404 error page
│
-├── routes/ # Routing configuration
-│ └── AppRoutes.jsx # Centralized route definitions
+├── routes/ # Routing configuration
+│ └── AppRoutes.jsx # Centralized route definitions
│
-├── services/ # Business logic services
-│ └── friendsService.js # Friend operations (add, remove, list)
+├── services/ # Business logic services
+│ └── friendsService.js # Friend operations (add, remove, list)
│
-├── utils/ # Utility functions
-│ ├── motion.js # Framer Motion animations
-│ ├── motion.test.js # Animation tests
-│ └── searchUtils.js # Search functionality helpers
+├── utils/ # Utility functions
+│ ├── motion.js # Framer Motion animations
+│ ├── motion.test.js # Animation tests
+│ └── searchUtils.js # Search functionality helpers
│
-├── constants/ # Application constants
-│ └── index.js # Centralized constants
+├── constants/ # Application constants
+│ └── index.js # Centralized constants
│
-├── App.jsx # Root app component
-├── App.css # Global app styles
-├── main.jsx # React DOM entry point
-└── index.css # Global stylesheet
+├── App.jsx # Root app component
+├── App.css # Global app styles
+├── main.jsx # React DOM entry point
+└── index.css # Global stylesheet
\\\
@@ -222,16 +229,16 @@ src/
\\\mermaid
graph TD
- A[main.jsx] -->|imports| B[App.jsx]
- B -->|wraps with| C[ErrorBoundary]
- C -->|wraps with| D[ThemeProvider]
- D -->|wraps with| E[AuthProvider]
- E -->|wraps with| F[RateLimitProvider]
- F -->|wraps with| G[HashRouter]
- G -->|renders| H[AppRoutes]
- H -->|contains| I[Route Guards
ProtectedRoute
OnboardingRoute
GuestRoute]
- I -->|routes to| J[Page Components]
- I -->|routes to| K[Layout Components]
+A[main.jsx] -->|imports| B[App.jsx]
+B -->|wraps with| C[ErrorBoundary]
+C -->|wraps with| D[ThemeProvider]
+D -->|wraps with| E[AuthProvider]
+E -->|wraps with| F[RateLimitProvider]
+F -->|wraps with| G[HashRouter]
+G -->|renders| H[AppRoutes]
+H -->|contains| I[Route Guards
ProtectedRoute
OnboardingRoute
GuestRoute]
+I -->|routes to| J[Page Components]
+I -->|routes to| K[Layout Components]
\\\
### Provider Hierarchy
@@ -254,17 +261,17 @@ This hierarchy ensures proper state initialization and dependency ordering.
\\\mermaid
graph TD
- App["App
(Root Component)"]
- App -->|children| EB["ErrorBoundary"]
- EB -->|children| Theme["ThemeProvider"]
- Theme -->|children| Auth["AuthProvider"]
- Auth -->|children| Rate["RateLimitProvider"]
- Rate -->|children| Router["HashRouter"]
- Router -->|contains| Routes["Routes Component"]
- Routes -->|public routes| PL["PublicLayout"]
- Routes -->|protected routes| PR["ProtectedRoute"]
- Routes -->|guest only| GR["GuestRoute"]
- Routes -->|onboarding| OR["OnboardingRoute"]
+App["App
(Root Component)"]
+App -->|children| EB["ErrorBoundary"]
+EB -->|children| Theme["ThemeProvider"]
+Theme -->|children| Auth["AuthProvider"]
+Auth -->|children| Rate["RateLimitProvider"]
+Rate -->|children| Router["HashRouter"]
+Router -->|contains| Routes["Routes Component"]
+Routes -->|public routes| PL["PublicLayout"]
+Routes -->|protected routes| PR["ProtectedRoute"]
+Routes -->|guest only| GR["GuestRoute"]
+Routes -->|onboarding| OR["OnboardingRoute"]
PL -->|outlets| PB["Page Body"]
PL -->|has| PNav["PublicNavbar"]
@@ -285,6 +292,7 @@ graph TD
style Router fill:#06b6d4
style PL fill:#f59e0b
style DL fill:#8b5cf6
+
\\\
### Dashboard Component Tree (Example)
@@ -292,26 +300,26 @@ graph TD
\\\
DashboardLayout
├── Navbar
-│ ├── Theme Toggle
-│ ├── User Menu
-│ └── Notifications
+│ ├── Theme Toggle
+│ ├── User Menu
+│ └── Notifications
├── Sidebar
-│ ├── Logo
-│ ├── Navigation Links
-│ └── Collapse Toggle
+│ ├── Logo
+│ ├── Navigation Links
+│ └── Collapse Toggle
├── Main Content (Outlet)
-│ └── Dashboard Page
-│ ├── StatsCards
-│ │ ├── Card (GitRank Points)
-│ │ ├── Card (Achievements)
-│ │ └── Card (Followers)
-│ ├── StreakCard
-│ └── ActivityFeed
-│ ├── Activity Item
-│ ├── Activity Item
-│ └── Activity Item
+│ └── Dashboard Page
+│ ├── StatsCards
+│ │ ├── Card (GitRank Points)
+│ │ ├── Card (Achievements)
+│ │ └── Card (Followers)
+│ ├── StreakCard
+│ └── ActivityFeed
+│ ├── Activity Item
+│ ├── Activity Item
+│ └── Activity Item
└── MobileSidebar (Drawer)
- └── Navigation Links
+└── Navigation Links
\\\
---
@@ -322,12 +330,12 @@ DashboardLayout
\\\mermaid
sequenceDiagram
- participant Browser
- participant Vite as Vite Dev Server
- participant main.jsx
- participant App.jsx
- participant AuthContext
- participant Firebase
+participant Browser
+participant Vite as Vite Dev Server
+participant main.jsx
+participant App.jsx
+participant AuthContext
+participant Firebase
Browser->>Vite: Request application
Vite->>main.jsx: Load entry point
@@ -339,11 +347,13 @@ sequenceDiagram
AuthContext-->>App.jsx: Provide auth state
App.jsx->>App.jsx: Render UI with context
App.jsx-->>Browser: Display application
+
\\\
### Page Load Sequence for Authenticated User
\\\
+
1. User visits application
↓
2. React mounts App component
@@ -356,7 +366,7 @@ sequenceDiagram
- Calls onAuthStateChanged() to check Firebase session
- If user exists, fetches Firestore user profile in real-time
- Sets loading=false when complete
- ↓
+ ↓
6. RateLimitProvider initializes
↓
7. HashRouter mounted with routes
@@ -366,11 +376,11 @@ sequenceDiagram
9. If ProtectedRoute and user authenticated:
- Load DashboardLayout
- Render corresponding page
- ↓
+ ↓
10. Page renders with all context available
↓
11. Components can now use useAuth(), useTheme(), etc.
-\\\
+ \\\
---
@@ -387,20 +397,22 @@ RankerHub uses React Context API for global state with three main contexts:
**State:**
\\\
{
- user: FirebaseUser | null, // Current Firebase auth user
- userData: Object | null, // Firestore user profile document
- loading: boolean, // Auth state loading indicator
- isOnboarding: boolean, // Profile setup incomplete flag
- ghAccessToken: string | null, // GitHub OAuth token (memory only)
+user: FirebaseUser | null, // Current Firebase auth user
+userData: Object | null, // Firestore user profile document
+loading: boolean, // Auth state loading indicator
+isOnboarding: boolean, // Profile setup incomplete flag
+ghAccessToken: string | null, // GitHub OAuth token (memory only)
}
\\\
**Methods:**
+
- \login(requestRepoScope: boolean)\ - GitHub OAuth sign-in
- \logout()\ - Sign out and clear state
- \etchGitHubStats(uid, username)\ - Call GitHub API for user stats
**Key Security Features:**
+
- GitHub access token stored ONLY in React memory (not localStorage)
- Prevents XSS attacks that could steal tokens from Web Storage
- Token lost on page refresh, but only needed once after login
@@ -413,12 +425,13 @@ RankerHub uses React Context API for global state with three main contexts:
**State:**
\\\
{
- theme: 'light' | 'dark', // Current theme
- isDark: boolean, // Convenience boolean
+theme: 'light' | 'dark', // Current theme
+isDark: boolean, // Convenience boolean
}
\\\
**Features:**
+
- Persists to localStorage
- Respects system color scheme on first load
- Updates root HTML element class
@@ -430,14 +443,15 @@ RankerHub uses React Context API for global state with three main contexts:
**State:**
\\\
{
- remaining: number, // Remaining API calls
- limit: number, // Total API limit
- resetTime: Date, // Rate limit reset timestamp
- isLimited: boolean, // Exceeded rate limit flag
+remaining: number, // Remaining API calls
+limit: number, // Total API limit
+resetTime: Date, // Rate limit reset timestamp
+isLimited: boolean, // Exceeded rate limit flag
}
\\\
**Usage:**
+
- Monitors GitHub API response headers
- Displays banner warning when rate limited
- Prevents unnecessary API calls
@@ -446,13 +460,13 @@ RankerHub uses React Context API for global state with three main contexts:
\\\mermaid
graph LR
- A["User Action
(Login, Theme Toggle)"]
- A -->|dispatch| B["Context Update"]
- B -->|persist| C["localStorage/
Firestore"]
- B -->|set state| D["Context Provider"]
- D -->|provide via| E["useContext Hook"]
- E -->|trigger| F["Component Re-render"]
- F -->|display| G["Updated UI"]
+A["User Action
(Login, Theme Toggle)"]
+A -->|dispatch| B["Context Update"]
+B -->|persist| C["localStorage/
Firestore"]
+B -->|set state| D["Context Provider"]
+D -->|provide via| E["useContext Hook"]
+E -->|trigger| F["Component Re-render"]
+F -->|display| G["Updated UI"]
\\\
---
@@ -463,13 +477,13 @@ graph LR
\\\mermaid
graph TD
- AppRoutes["AppRoutes Component"]
- AppRoutes -->|PublicLayout| PL["Public Pages"]
- PL -->|/| Home["Home"]
- PL -->|/gitrank| GitRankPub["GitRank Info"]
- PL -->|/rankher| RankHer["RankHer Info"]
- PL -->|/codingverse| CodingVerse["CodingVerse Info"]
- PL -->|/codingowl| CodingOwl["CodingOwl Info"]
+AppRoutes["AppRoutes Component"]
+AppRoutes -->|PublicLayout| PL["Public Pages"]
+PL -->|/| Home["Home"]
+PL -->|/gitrank| GitRankPub["GitRank Info"]
+PL -->|/rankher| RankHer["RankHer Info"]
+PL -->|/codingverse| CodingVerse["CodingVerse Info"]
+PL -->|/codingowl| CodingOwl["CodingOwl Info"]
AppRoutes -->|GuestRoute| Guest["Guest Only"]
Guest -->|/login| Login["Login Page"]
@@ -494,6 +508,7 @@ graph TD
Legal -->|/privacy| Privacy["Privacy"]
AppRoutes -->|Catch-all| NotFound["404 Page"]
+
\\\
### Route Guards
@@ -501,6 +516,7 @@ graph TD
Three route guard components protect access:
#### ProtectedRoute
+
\\\javascript
// Only accessible if:
// 1. User is authenticated
@@ -509,6 +525,7 @@ Three route guard components protect access:
\\\
#### OnboardingRoute
+
\\\javascript
// Only accessible if:
// 1. User is authenticated
@@ -517,6 +534,7 @@ Three route guard components protect access:
\\\
#### GuestRoute
+
\\\javascript
// Only accessible if NOT authenticated
// Used for: /login page
@@ -527,11 +545,11 @@ Three route guard components protect access:
\\\mermaid
sequenceDiagram
- participant User
- participant Browser
- participant React as React Router
- participant Guard as Route Guard
- participant Page as Page Component
+participant User
+participant Browser
+participant React as React Router
+participant Guard as Route Guard
+participant Page as Page Component
User->>Browser: Click navigation link
Browser->>React: Update URL hash
@@ -547,6 +565,7 @@ sequenceDiagram
Guard->>React: Redirect to /login
React->>Page: Render login page
end
+
\\\
---
@@ -557,11 +576,11 @@ sequenceDiagram
\\\mermaid
sequenceDiagram
- participant User
- participant Browser as Browser/App
- participant Firebase as Firebase Auth
- participant GitHub as GitHub OAuth
- participant Firestore as Firestore
+participant User
+participant Browser as Browser/App
+participant Firebase as Firebase Auth
+participant GitHub as GitHub OAuth
+participant Firestore as Firestore
User->>Browser: Click "Login with GitHub"
Browser->>Firebase: signInWithGitHub()
@@ -584,6 +603,7 @@ sequenceDiagram
Browser->>Browser: Set isOnboarding = false
Browser->>Browser: Redirect to /dashboard
end
+
\\\
### User Data Structure
@@ -591,46 +611,46 @@ sequenceDiagram
**Firestore User Document** (users/{uid}):
\\\javascript
{
- // Core Identity
- uid: "firebase-uid",
- githubUsername: "developer-handle",
- githubId: 12345678,
- email: "",
- name: "Developer Name",
- avatar: "",
-
- // Status
- onboardingStatus: "complete" | "incomplete",
- lastLogin: "2026-05-31T23:41:48Z",
- createdAt: "2026-05-31T23:41:48Z",
-
- // GitHub Stats
- commits: 1250,
- prs: 150,
- reviews: 300,
- publicRepos: 25,
- stars: 5000,
- followers: 500,
- primaryLanguage: "JavaScript",
-
- // Points System
- points: {
- gitRankPoints: 4250, // (commits*2) + (prs*5) + (reviews*10)
- codingVersePoints: 0,
- streakPoints: 0,
- referralPoints: 0,
- totalPoints: 4250
- },
-
- // Profile Data
- city: "San Francisco, CA",
- bio: "Open source enthusiast",
- website: "",
- streak: 42,
-
- // Privacy & Settings
- profileVisibility: "public" | "private",
- privateRepoSyncEnabled: false,
+// Core Identity
+uid: "firebase-uid",
+githubUsername: "developer-handle",
+githubId: 12345678,
+email: "",
+name: "Developer Name",
+avatar: "",
+
+// Status
+onboardingStatus: "complete" | "incomplete",
+lastLogin: "2026-05-31T23:41:48Z",
+createdAt: "2026-05-31T23:41:48Z",
+
+// GitHub Stats
+commits: 1250,
+prs: 150,
+reviews: 300,
+publicRepos: 25,
+stars: 5000,
+followers: 500,
+primaryLanguage: "JavaScript",
+
+// Points System
+points: {
+gitRankPoints: 4250, // (commits*2) + (prs*5) + (reviews\*10)
+codingVersePoints: 0,
+streakPoints: 0,
+referralPoints: 0,
+totalPoints: 4250
+},
+
+// Profile Data
+city: "San Francisco, CA",
+bio: "Open source enthusiast",
+website: "",
+streak: 42,
+
+// Privacy & Settings
+profileVisibility: "public" | "private",
+privateRepoSyncEnabled: false,
}
\\\
@@ -663,13 +683,15 @@ VITE_FIREBASE_MEASUREMENT_ID (optional)
### Firebase Services
#### 1. **Authentication (Firebase Auth)**
+
- GitHub OAuth provider
- Scopes: \
-ead:user\, \user:email\, optional \
-epo\
+ ead:user\, \user:email\, optional \
+ epo\
- Conditional repo scope for private repository sync
#### 2. **Firestore Database**
+
- **Collection: users** - User profiles and settings
- **Collection: leaderboards** - Ranking data by category
- **Collection: friends** - Friend relationship data
@@ -677,11 +699,13 @@ epo\
- Real-time listeners for live updates
#### 3. **Cloud Storage**
+
- Profile pictures
- Custom avatars
- Badge images
#### 4. **Analytics**
+
- Page view tracking
- User interaction tracking
- Custom event logging
@@ -691,11 +715,11 @@ epo\
\\\javascript
// In AuthContext.jsx:
const unsubscribeSnapshot = onSnapshot(userDocRef, (docSnap) => {
- // Called whenever Firestore document changes
- // Updates React state with latest data
- setUserData(docSnap.data());
+// Called whenever Firestore document changes
+// Updates React state with latest data
+setUserData(docSnap.data());
}, (error) => {
- console.error("Listener error:", error);
+console.error("Listener error:", error);
});
// Cleanup on unmount:
@@ -705,6 +729,7 @@ return () => unsubscribeSnapshot();
### Firestore Security Rules
Enforced in \irestore.rules\:
+
- Users can only read/write their own document
- Public profiles readable by all authenticated users
- Friends list visible only to involved parties
@@ -718,9 +743,9 @@ Enforced in \irestore.rules\:
\\\mermaid
sequenceDiagram
- participant App as React App
- participant Context as AuthContext
- participant GitHub as GitHub API
+participant App as React App
+participant Context as AuthContext
+participant GitHub as GitHub API
App->>Context: User logs in
Context->>Context: Store access token in React state
@@ -737,28 +762,29 @@ sequenceDiagram
GitHub-->>Context: Review count
Context->>Context: Calculate GitRank = (commits*2) + (prs*5) + (reviews*10)
Context-->>App: Return stats object
+
\\\
### GitHub API Endpoints Used
\\\
-GET /users/{username}
- Purpose: Public profile info
- Rate Limit: 60 reqs/hr (unauthenticated), 5000/hr (authenticated)
+GET /users/{username}
+Purpose: Public profile info
+Rate Limit: 60 reqs/hr (unauthenticated), 5000/hr (authenticated)
-GET /users/{username}/repos
- Purpose: User's repositories (max 100 per request)
- Data: Stars, language, description
+GET /users/{username}/repos
+Purpose: User's repositories (max 100 per request)
+Data: Stars, language, description
-GET /search/commits?q=author:{username}
- Purpose: Total commits count
- Rate Limit: 30 reqs/min (authenticated only)
+GET /search/commits?q=author:{username}
+Purpose: Total commits count
+Rate Limit: 30 reqs/min (authenticated only)
-GET /search/issues?q=author:{username}+type:pr
- Purpose: Pull requests authored
+GET /search/issues?q=author:{username}+type:pr
+Purpose: Pull requests authored
-GET /search/issues?q=reviewed-by:{username}
- Purpose: Code reviews performed
+GET /search/issues?q=reviewed-by:{username}
+Purpose: Code reviews performed
\\\
### Rate Limit Handling
@@ -777,14 +803,14 @@ GET /search/issues?q=reviewed-by:{username}
\\\mermaid
graph TD
- A["User Authentication
(GitHub OAuth)"]
- A -->|stores in| B["AuthContext"]
- B -->|fetches from| C["Firestore User Doc"]
- C -->|triggers| D["Real-time Listener"]
- D -->|updates| E["userData state"]
- E -->|used by| F["Dashboard Page"]
- F -->|renders| G["StatsCards"]
- G -->|displays| H["Points, Rank, Followers"]
+A["User Authentication
(GitHub OAuth)"]
+A -->|stores in| B["AuthContext"]
+B -->|fetches from| C["Firestore User Doc"]
+C -->|triggers| D["Real-time Listener"]
+D -->|updates| E["userData state"]
+E -->|used by| F["Dashboard Page"]
+F -->|renders| G["StatsCards"]
+G -->|displays| H["Points, Rank, Followers"]
F -->|renders| I["StreakCard"]
I -->|displays| J["Current Streak"]
@@ -797,6 +823,7 @@ graph TD
E -->|also used by| O["Friends Page"]
O -->|displays| P["Friend List"]
+
\\\
### Dashboard Component Data Binding
@@ -807,11 +834,12 @@ graph TD
const { userData } = useAuth();
// Display:
+
- GitRank Points: userData.points.gitRankPoints
- Achievements: userData.achievements?.length || 0
- Followers: userData.followers
- Repositories: userData.publicRepos
-\\\
+ \\\
**ActivityFeed Component**:
\\\javascript
@@ -832,7 +860,7 @@ const { userData } = useAuth();
- Use functional components
- Use React hooks for state
- Follow naming conventions (PascalCase)
- \\\
+ \\\
2. **Add Route** (if page-level)
\\\javascript
@@ -885,15 +913,15 @@ src/services/myService.js
import { myApiFunction } from '../services/myService';
const MyComponent = () => {
- const [data, setData] = useState(null);
- const [loading, setLoading] = useState(false);
-
- useEffect(() => {
- setLoading(true);
- myApiFunction()
- .then(setData)
- .finally(() => setLoading(false));
- }, []);
+const [data, setData] = useState(null);
+const [loading, setLoading] = useState(false);
+
+useEffect(() => {
+setLoading(true);
+myApiFunction()
+.then(setData)
+.finally(() => setLoading(false));
+}, []);
};
\\\
@@ -916,6 +944,7 @@ npm run build
\\\
This executes Vite's build pipeline:
+
1. Transpiles JSX/ES6+ to browser-compatible JavaScript
2. Bundles code using efficient module resolution
3. Minifies output
@@ -935,6 +964,7 @@ firebase deploy
\\\
Deploys:
+
- Firestore security rules
- Cloud functions (if any)
- Analytics configuration
@@ -960,9 +990,9 @@ cp .env.example .env.local
### Production Checklist
- [ ] All tests pass: \
-pm run test\
+ pm run test\
- [ ] No linting errors: \
-pm run lint\
+ pm run lint\
- [ ] Bundle size reviewed
- [ ] Environment variables set
- [ ] Firebase rules deployed
@@ -978,22 +1008,26 @@ pm run lint\
### Common Issues
**Auth state not persisting:**
+
- Check Firebase initialization
- Verify env variables loaded
- Check browser localStorage enabled
**Rate limit errors:**
+
- GitHub API limits hit
- Check RateLimitContext
- Display banner to user
- Implement backoff retry
**Firestore permission denied:**
+
- Check firestore.rules
- Verify user is authenticated
- Check collection path matches
**Animations stuttering:**
+
- Use GPU-accelerated props (transform, opacity)
- Avoid animating layout properties
- Check Framer Motion configuration
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 5d8ca0f..87fe4ec 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -15,11 +15,14 @@ Please maintain a respectful, welcoming, and inclusive environment. Be helpful t
## Getting Started
### 1. Prerequisites
+
Ensure you have the following installed on your local machine:
+
- [Node.js](https://nodejs.org/) (v20.0.0 or higher recommended)
- [Git](https://git-scm.com/)
### 2. Fork & Clone
+
1. Fork the [RankerHub Repository](https://github.com/indresh404/RankerHub) to your own GitHub account.
2. Clone your fork locally:
```bash
@@ -28,12 +31,15 @@ Ensure you have the following installed on your local machine:
```
### 3. Install Dependencies
+
Run the following command to install the project dependencies:
+
```bash
npm install
```
### 4. Setup Environment Variables
+
1. Copy the `.env.example` file to create a `.env` file in the root directory:
```bash
cp .env.example .env
@@ -41,10 +47,13 @@ npm install
2. Open the `.env` file and fill in your Firebase configuration keys (see the [Firebase Setup](#firebase-setup) below).
### 5. Run the Project
+
Start the local development server:
+
```bash
npm run dev
```
+
The application will be running locally at `http://localhost:5173`.
---
@@ -52,6 +61,7 @@ The application will be running locally at `http://localhost:5173`.
## Firebase Setup
To get your own Firebase credentials for local development:
+
1. Go to the [Firebase Console](https://console.firebase.google.com/).
2. Create a new Firebase project (e.g., `rankerhub-dev`).
3. Add a **Web App** to your project.
@@ -144,7 +154,9 @@ Open `http://localhost:5173`. New test users and Firestore documents created whi
To keep the repository history clean, please follow these branching and commit message conventions:
### Branch Naming
+
Create a new branch from `main` before starting your work:
+
- `feat/feature-name` – for new features
- `fix/bug-name` – for bug fixes
- `docs/doc-updates` – for documentation changes
@@ -152,12 +164,15 @@ Create a new branch from `main` before starting your work:
- `chore/task-name` – for maintenance tasks or package upgrades
Example:
+
```bash
git checkout -b feat/user-leaderboard
```
### Commit Messages (Semantic Commits)
+
Write clear and descriptive commit messages following the semantic commit pattern:
+
- `feat: add female developer ranking page`
- `fix: resolve auth validation issue`
- `docs: update setup steps in README`
diff --git a/docs/FIRESTORE_SCHEMA.md b/docs/FIRESTORE_SCHEMA.md
index 0eb46de..2e34642 100644
--- a/docs/FIRESTORE_SCHEMA.md
+++ b/docs/FIRESTORE_SCHEMA.md
@@ -10,15 +10,15 @@ RankerHub primarily uses two root-level collections to manage user profiles, poi
### A. `users` Collection
-* **Path:** `/users/{uid}`
-* **Purpose:** Stores user profiles, authentication metadata, onboarding status, social links, and the points ledger (streak, gitRank, codingVerse, and referral points).
-* **Document ID:** The Firebase Authentication User ID (`uid`).
+- **Path:** `/users/{uid}`
+- **Purpose:** Stores user profiles, authentication metadata, onboarding status, social links, and the points ledger (streak, gitRank, codingVerse, and referral points).
+- **Document ID:** The Firebase Authentication User ID (`uid`).
### B. `referrals` Collection
-* **Path:** `/referrals/{uid}`
-* **Purpose:** Acts as an index and ledger for users who have generated a referral code. It tracks who has used their code to prevent abuse and duplicate rewards.
-* **Document ID:** The Firebase Authentication User ID (`uid`) of the referrer.
+- **Path:** `/referrals/{uid}`
+- **Purpose:** Acts as an index and ledger for users who have generated a referral code. It tracks who has used their code to prevent abuse and duplicate rewards.
+- **Document ID:** The Firebase Authentication User ID (`uid`) of the referrer.
---
@@ -28,47 +28,47 @@ Our security rules enforce strict checks to ensure data consistency, prevent arb
### Global Helpers
-* `isAuthenticated()`: Ensures the incoming request has a valid authentication token.
-* `isOwner(uid)`: Ensures the authenticated user's ID matches the requested document ID.
-* `isOnlySocialUpdate()`: A specialized check allowing users to update non-critical profile fields (e.g., LinkedIn, Instagram, Discord) without triggering strict onboarding checks.
+- `isAuthenticated()`: Ensures the incoming request has a valid authentication token.
+- `isOwner(uid)`: Ensures the authenticated user's ID matches the requested document ID.
+- `isOnlySocialUpdate()`: A specialized check allowing users to update non-critical profile fields (e.g., LinkedIn, Instagram, Discord) without triggering strict onboarding checks.
### A. Users Rules (`/users/{uid}`)
-* **Read Access:** Any authenticated user can read profile data. This is necessary to populate the global leaderboard.
-* **Create Access:** A user can create their own profile document, provided the `onboardingStatus` is explicitly set to `"incomplete"` or `"complete"`.
+- **Read Access:** Any authenticated user can read profile data. This is necessary to populate the global leaderboard.
+- **Create Access:** A user can create their own profile document, provided the `onboardingStatus` is explicitly set to `"incomplete"` or `"complete"`.
**Update Rules (The Core Logic):**
-* **Social Links Bypass (RULE 1):** Users can freely update their social URLs (LinkedIn, Instagram, Discord) and the `updatedAt` timestamp at any time, bypassing strict checks.
-* **Immutable Onboarding Fields (RULE 2.1):** Once a user is onboarded (`onboardingStatus == "complete"`), they cannot modify critical profile metadata like gender, DOB, city, college, or createdAt.
-* **Points Integrity (RULE 2.2 & 2.3):**
- * *Total Points Equation:* `totalPoints` must always equal the sum of `gitRankPoints + codingVersePoints + streakPoints + referralPoints`.
- * *Controlled Spikes:* Users cannot arbitrarily inflate points. Valid scenarios for points updates include:
- * Transitioning from incomplete to complete onboarding.
- * Minor incremental updates (e.g., streak login +2, codingVerse +5, capped at +100 total change per request).
- * GitRank Updates: The `gitRankPoints` must strictly align with the formula. Other points categories must remain unchanged during this specific update.
-* **Referral Rewards (RULE 3 - Exploit Prevention):**
- * This rule governs how a *referred user* updates the *referrer's* document.
- * The referred user can add exactly **100 points** to the referrer's `referralPoints` and `totalPoints`.
- * **Guards:**
- * The referrer's document in the `referrals` collection must exist.
- * The referred user's `uid` *must already be present* in the referrer's `usedBy` array (verified via a `get()` call). This confirms the code was legitimately redeemed before points are granted, closing the vulnerability outlined in Issue #81.
+- **Social Links Bypass (RULE 1):** Users can freely update their social URLs (LinkedIn, Instagram, Discord) and the `updatedAt` timestamp at any time, bypassing strict checks.
+- **Immutable Onboarding Fields (RULE 2.1):** Once a user is onboarded (`onboardingStatus == "complete"`), they cannot modify critical profile metadata like gender, DOB, city, college, or createdAt.
+- **Points Integrity (RULE 2.2 & 2.3):**
+ - _Total Points Equation:_ `totalPoints` must always equal the sum of `gitRankPoints + codingVersePoints + streakPoints + referralPoints`.
+ - _Controlled Spikes:_ Users cannot arbitrarily inflate points. Valid scenarios for points updates include:
+ - Transitioning from incomplete to complete onboarding.
+ - Minor incremental updates (e.g., streak login +2, codingVerse +5, capped at +100 total change per request).
+ - GitRank Updates: The `gitRankPoints` must strictly align with the formula. Other points categories must remain unchanged during this specific update.
+- **Referral Rewards (RULE 3 - Exploit Prevention):**
+ - This rule governs how a _referred user_ updates the _referrer's_ document.
+ - The referred user can add exactly **100 points** to the referrer's `referralPoints` and `totalPoints`.
+ - **Guards:**
+ - The referrer's document in the `referrals` collection must exist.
+ - The referred user's `uid` _must already be present_ in the referrer's `usedBy` array (verified via a `get()` call). This confirms the code was legitimately redeemed before points are granted, closing the vulnerability outlined in Issue #81.
### B. Referrals Rules (`/referrals/{uid}`)
-* **Read Access:** Any authenticated user can read referral data.
-* **Create Access:** Only the owner can create their referral index document.
-* **Update Access (The Uniqueness Guard):**
- * The owner can update their document.
- * A *referred user* can update the referrer's document to claim a referral, but with strict conditions:
- * They must append their `uid` to the `usedBy` array.
- * The `totalEarned` must increment by exactly 100.
- * **Crucial Uniqueness Check:** `!(request.auth.uid in resource.data.usedBy)` ensures a user cannot use the same referral code twice. Additionally, size growth checks guarantee only one ID is appended at a time, preventing array-stuffing exploits.
+- **Read Access:** Any authenticated user can read referral data.
+- **Create Access:** Only the owner can create their referral index document.
+- **Update Access (The Uniqueness Guard):**
+ - The owner can update their document.
+ - A _referred user_ can update the referrer's document to claim a referral, but with strict conditions:
+ - They must append their `uid` to the `usedBy` array.
+ - The `totalEarned` must increment by exactly 100.
+ - **Crucial Uniqueness Check:** `!(request.auth.uid in resource.data.usedBy)` ensures a user cannot use the same referral code twice. Additionally, size growth checks guarantee only one ID is appended at a time, preventing array-stuffing exploits.
---
## 3. Global Lockdown
-* **Path:** `/{document=**}`
-* **Rule:** `allow read, write: if false;`
-* **Purpose:** By default, all other collections in the database are completely locked down. Access must be explicitly granted.
+- **Path:** `/{document=**}`
+- **Rule:** `allow read, write: if false;`
+- **Purpose:** By default, all other collections in the database are completely locked down. Access must be explicitly granted.
diff --git a/docs/FIRESTORE_SECURITY.md b/docs/FIRESTORE_SECURITY.md
new file mode 100644
index 0000000..b70bcb4
--- /dev/null
+++ b/docs/FIRESTORE_SECURITY.md
@@ -0,0 +1,78 @@
+# Firestore Security Rules & Indexes Documentation
+
+This document outlines the security rules implemented in `firestore.rules` and the composite index setup in `firestore.indexes.json` for RankerHub.
+
+## Whitelisted Profile Fields
+
+To allow users to update their basic profile information without running into strict point-change or onboarding-lock constraints, the `isOnlyProfileUpdate()` helper function whitelists specific fields.
+
+An update is allowed **anytime** as long as it **only** touches these fields:
+
+- `name`
+- `avatar`
+- `gender`
+- `dob`
+- `city`
+- `college`
+- `linkedinUrl`
+- `instagramHandle`
+- `discordUsername`
+- `updatedAt`
+
+## Points Change Limitations & Streak Protections
+
+### Streak Updates
+
+The `isStreakUpdate()` helper ensures that daily check-ins cannot be exploited.
+
+- **Allowed Fields:** `streak`, `longestStreak`, `lastLogin`, `points`
+- **Validation:**
+ - `longestStreak` must be monotonically non-decreasing (cannot go down).
+ - `streak` must be `>= 0`.
+ - `points.streakPoints` must not decrease.
+
+### General Point Spikes (Rule 3)
+
+To prevent users from maliciously granting themselves unlimited points, the rules enforce strict boundaries on point adjustments during profile writes:
+
+- **Total Points Cap:** `totalPoints` can increase by a maximum of `100` points in a single standard client write (accommodating normal actions like streak logins or minor challenge completions).
+- **GitRank Formula:** If GitHub stats are updated, `gitRankPoints` must equal:
+ `(commits * 2) + (prs * 5) + (reviews * 10)`
+ During this sync, all other point categories (`codingVersePoints`, `streakPoints`, `referralPoints`) must remain unchanged.
+
+### Referral System Protections
+
+Referral points updates are strictly guarded to prevent farming exploits (e.g., Issue #81):
+
+- A referred user can atomically add exactly `100` points to a referrer's `referralPoints` and `totalPoints`.
+- The caller must prove they actually redeemed the code by being listed in the referrer's `usedBy` array (`request.auth.uid in get(...).data.usedBy`).
+- To prevent duplicate entries in the `referrals` collection, a user cannot add their UID to the `usedBy` array if they are already in it (`!(request.auth.uid in resource.data.usedBy)`). The array size must grow by exactly 1, and the caller's ID must be at the very end of the array.
+
+## Onboarding Immutability
+
+Once a user's `onboardingStatus` is set to `"complete"`, certain core fields cannot be altered through standard restricted updates (though they can still be altered via the whitelisted profile update rule mentioned above):
+
+- `gender`
+- `dob`
+- `city`
+- `college`
+- `createdAt`
+
+## Composite Index Setup
+
+To support efficient leaderboard queries and sorting, the following composite indexes are configured for the `users` collection in `firestore.indexes.json`. All queries first filter by `onboardingStatus` (ASCENDING) to only show fully onboarded users.
+
+1. **Global GitRank Leaderboard:**
+ - `onboardingStatus` (ASC)
+ - `points.gitRankPoints` (DESC)
+2. **Language-Specific GitRank Leaderboard:**
+ - `onboardingStatus` (ASC)
+ - `githubStats.primaryLanguage` (ASC)
+ - `points.gitRankPoints` (DESC)
+3. **Gender-Specific Total Points Leaderboard:**
+ - `onboardingStatus` (ASC)
+ - `gender` (ASC)
+ - `points.totalPoints` (DESC)
+4. **CodingVerse Leaderboard:**
+ - `onboardingStatus` (ASC)
+ - `points.codingVersePoints` (DESC)
diff --git a/docs/POINTS_SPEC.md b/docs/POINTS_SPEC.md
index fc3a997..a239def 100644
--- a/docs/POINTS_SPEC.md
+++ b/docs/POINTS_SPEC.md
@@ -12,3 +12,4 @@ The GitRank engine audits a connected GitHub account to evaluate real-world deve
```text
GitRank Points = (Commits × 2) + (Pull Requests × 5) + (Code Reviews × 10)
+```
diff --git a/eslint.config.js b/eslint.config.js
index c21974a..056d8f6 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,13 +1,13 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import { defineConfig, globalIgnores } from 'eslint/config'
+import js from "@eslint/js";
+import globals from "globals";
+import reactHooks from "eslint-plugin-react-hooks";
+import reactRefresh from "eslint-plugin-react-refresh";
+import { defineConfig, globalIgnores } from "eslint/config";
export default defineConfig([
- globalIgnores(['dist']),
+ globalIgnores(["dist"]),
{
- files: ['**/*.{js,jsx}'],
+ files: ["**/*.{js,jsx}"],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
@@ -18,17 +18,17 @@ export default defineConfig([
parserOptions: { ecmaFeatures: { jsx: true } },
},
rules: {
- 'no-unused-vars': [
- 'warn',
+ "no-unused-vars": [
+ "warn",
{
- varsIgnorePattern: '^React$',
- argsIgnorePattern: '^_'
- }
+ varsIgnorePattern: "^React$",
+ argsIgnorePattern: "^_",
+ },
],
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true }
+ "react-refresh/only-export-components": [
+ "warn",
+ { allowConstantExport: true },
],
},
},
-])
+]);
diff --git a/firebase.json b/firebase.json
index e86731b..f74b34b 100644
--- a/firebase.json
+++ b/firebase.json
@@ -5,11 +5,7 @@
},
"hosting": {
"public": "dist",
- "ignore": [
- "firebase.json",
- "**/.*",
- "**/node_modules/**"
- ],
+ "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
diff --git a/fix_lint.mjs b/fix_lint.mjs
index 04f0527..4e3f504 100644
--- a/fix_lint.mjs
+++ b/fix_lint.mjs
@@ -1,48 +1,188 @@
-import fs from 'fs';
+import fs from "fs";
const replacements = [
- { file: 'src/components/about/TeamCard.jsx', search: /profileLink(,\s*)?|,\s*profileLink/, replace: '' },
- { file: 'src/components/dashboard/RankPreview.jsx', search: /Award(,\s*)?|,\s*Award/, replace: '' },
- { file: 'src/components/dashboard/StreakCard.jsx', search: /HelpCircle(,\s*)?|,\s*HelpCircle/, replace: '' },
- { file: 'src/components/layout/MobileSidebar.jsx', search: /systemBadges(,\s*)?|,\s*systemBadges/, replace: '' },
- { file: 'src/components/layout/Navbar.jsx', search: /ArrowUpRight(,\s*)?|,\s*ArrowUpRight/, replace: '' },
- { file: 'src/components/layout/Sidebar.jsx', search: /systemBadges(,\s*)?|,\s*systemBadges/, replace: '' },
- { file: 'src/components/ui/ComingSoonCard.jsx', search: /motion(,\s*)?|,\s*motion/, replace: '' },
- { file: 'src/components/ui/HowItWorksModal.jsx', search: /ArrowRight(,\s*)?|,\s*ArrowRight/, replace: '' },
- { file: 'src/components/ui/LogoutConfirmModal.jsx', search: /X(,\s*)?|,\s*X/, replace: '' },
- { file: 'src/components/ui/LogoutConfirmModal.jsx', search: /Card(,\s*)?|,\s*Card/, replace: '' },
- { file: 'src/components/ui/LottiePlayer.jsx', search: /error/, replace: '_error' },
- { file: 'src/components/ui/ThemeToggle.jsx', search: /const \[theme, setTheme\] = useTheme\(\)/, replace: 'const { setTheme } = useTheme()' },
- { file: 'src/context/AuthContext.jsx', search: /publicRepos(,\s*)?|,\s*publicRepos/, replace: '' },
- { file: 'src/context/AuthContext.jsx', search: /followers(,\s*)?|,\s*followers/, replace: '' },
- { file: 'src/context/AuthContext.jsx', search: /err/, replace: '_err' },
- { file: 'src/pages/Achievements.jsx', search: /TrendingUp(,\s*)?|,\s*TrendingUp/, replace: '' },
- { file: 'src/pages/CodingOwl.jsx', search: /Flame(,\s*)?|,\s*Flame/, replace: '' },
- { file: 'src/pages/CodingOwl.jsx', search: /Play(,\s*)?|,\s*Play/, replace: '' },
- { file: 'src/pages/CodingOwl.jsx', search: /Sparkles(,\s*)?|,\s*Sparkles/, replace: '' },
- { file: 'src/pages/CodingOwl.jsx', search: /focusStats(,\s*)?|,\s*focusStats/, replace: '' },
- { file: 'src/pages/Dashboard.jsx', search: /Zap(,\s*)?|,\s*Zap/, replace: '' },
- { file: 'src/pages/Dashboard.jsx', search: /Code(,\s*)?|,\s*Code/, replace: '' },
- { file: 'src/pages/Dashboard.jsx', search: /Flame(,\s*)?|,\s*Flame/, replace: '' },
- { file: 'src/pages/Dashboard.jsx', search: /ArrowUpRight(,\s*)?|,\s*ArrowUpRight/, replace: '' },
- { file: 'src/pages/Dashboard.jsx', search: /GradientButton(,\s*)?|,\s*GradientButton/, replace: '' },
- { file: 'src/pages/GitRank.jsx', search: /ShieldAlert(,\s*)?|,\s*ShieldAlert/, replace: '' },
- { file: 'src/pages/GitRank.jsx', search: /Award(,\s*)?|,\s*Award/, replace: '' },
- { file: 'src/pages/GitRank.jsx', search: /trophyAnimation(,\s*)?|,\s*trophyAnimation/, replace: '' },
- { file: 'src/pages/Login.jsx', search: /const navigate = useNavigate\(\);\n/, replace: '' },
- { file: 'src/pages/Profile.jsx', search: /Sparkles(,\s*)?|,\s*Sparkles/, replace: '' },
- { file: 'src/pages/Profile.jsx', search: /TrendingUp(,\s*)?|,\s*TrendingUp/, replace: '' },
- { file: 'src/pages/Profile.jsx', search: /Bookmark(,\s*)?|,\s*Bookmark/, replace: '' },
- { file: 'src/pages/Profile.jsx', search: /CheckCircle2(,\s*)?|,\s*CheckCircle2/, replace: '' },
- { file: 'src/pages/Profile.jsx', search: /Twitter(,\s*)?|,\s*Twitter/, replace: '' },
- { file: 'src/pages/RankHer.jsx', search: /Trophy(,\s*)?|,\s*Trophy/, replace: '' },
- { file: 'src/pages/RankHer.jsx', search: /ArrowRight(,\s*)?|,\s*ArrowRight/, replace: '' },
- { file: 'src/pages/RankHer.jsx', search: /\bidx\b/, replace: '_idx' }
+ {
+ file: "src/components/about/TeamCard.jsx",
+ search: /profileLink(,\s*)?|,\s*profileLink/,
+ replace: "",
+ },
+ {
+ file: "src/components/dashboard/RankPreview.jsx",
+ search: /Award(,\s*)?|,\s*Award/,
+ replace: "",
+ },
+ {
+ file: "src/components/dashboard/StreakCard.jsx",
+ search: /HelpCircle(,\s*)?|,\s*HelpCircle/,
+ replace: "",
+ },
+ {
+ file: "src/components/layout/MobileSidebar.jsx",
+ search: /systemBadges(,\s*)?|,\s*systemBadges/,
+ replace: "",
+ },
+ {
+ file: "src/components/layout/Navbar.jsx",
+ search: /ArrowUpRight(,\s*)?|,\s*ArrowUpRight/,
+ replace: "",
+ },
+ {
+ file: "src/components/layout/Sidebar.jsx",
+ search: /systemBadges(,\s*)?|,\s*systemBadges/,
+ replace: "",
+ },
+ {
+ file: "src/components/ui/ComingSoonCard.jsx",
+ search: /motion(,\s*)?|,\s*motion/,
+ replace: "",
+ },
+ {
+ file: "src/components/ui/HowItWorksModal.jsx",
+ search: /ArrowRight(,\s*)?|,\s*ArrowRight/,
+ replace: "",
+ },
+ {
+ file: "src/components/ui/LogoutConfirmModal.jsx",
+ search: /X(,\s*)?|,\s*X/,
+ replace: "",
+ },
+ {
+ file: "src/components/ui/LogoutConfirmModal.jsx",
+ search: /Card(,\s*)?|,\s*Card/,
+ replace: "",
+ },
+ {
+ file: "src/components/ui/LottiePlayer.jsx",
+ search: /error/,
+ replace: "_error",
+ },
+ {
+ file: "src/components/ui/ThemeToggle.jsx",
+ search: /const \[theme, setTheme\] = useTheme\(\)/,
+ replace: "const { setTheme } = useTheme()",
+ },
+ {
+ file: "src/context/AuthContext.jsx",
+ search: /publicRepos(,\s*)?|,\s*publicRepos/,
+ replace: "",
+ },
+ {
+ file: "src/context/AuthContext.jsx",
+ search: /followers(,\s*)?|,\s*followers/,
+ replace: "",
+ },
+ { file: "src/context/AuthContext.jsx", search: /err/, replace: "_err" },
+ {
+ file: "src/pages/Achievements.jsx",
+ search: /TrendingUp(,\s*)?|,\s*TrendingUp/,
+ replace: "",
+ },
+ {
+ file: "src/pages/CodingOwl.jsx",
+ search: /Flame(,\s*)?|,\s*Flame/,
+ replace: "",
+ },
+ {
+ file: "src/pages/CodingOwl.jsx",
+ search: /Play(,\s*)?|,\s*Play/,
+ replace: "",
+ },
+ {
+ file: "src/pages/CodingOwl.jsx",
+ search: /Sparkles(,\s*)?|,\s*Sparkles/,
+ replace: "",
+ },
+ {
+ file: "src/pages/CodingOwl.jsx",
+ search: /focusStats(,\s*)?|,\s*focusStats/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Dashboard.jsx",
+ search: /Zap(,\s*)?|,\s*Zap/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Dashboard.jsx",
+ search: /Code(,\s*)?|,\s*Code/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Dashboard.jsx",
+ search: /Flame(,\s*)?|,\s*Flame/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Dashboard.jsx",
+ search: /ArrowUpRight(,\s*)?|,\s*ArrowUpRight/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Dashboard.jsx",
+ search: /GradientButton(,\s*)?|,\s*GradientButton/,
+ replace: "",
+ },
+ {
+ file: "src/pages/GitRank.jsx",
+ search: /ShieldAlert(,\s*)?|,\s*ShieldAlert/,
+ replace: "",
+ },
+ {
+ file: "src/pages/GitRank.jsx",
+ search: /Award(,\s*)?|,\s*Award/,
+ replace: "",
+ },
+ {
+ file: "src/pages/GitRank.jsx",
+ search: /trophyAnimation(,\s*)?|,\s*trophyAnimation/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Login.jsx",
+ search: /const navigate = useNavigate\(\);\n/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Profile.jsx",
+ search: /Sparkles(,\s*)?|,\s*Sparkles/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Profile.jsx",
+ search: /TrendingUp(,\s*)?|,\s*TrendingUp/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Profile.jsx",
+ search: /Bookmark(,\s*)?|,\s*Bookmark/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Profile.jsx",
+ search: /CheckCircle2(,\s*)?|,\s*CheckCircle2/,
+ replace: "",
+ },
+ {
+ file: "src/pages/Profile.jsx",
+ search: /Twitter(,\s*)?|,\s*Twitter/,
+ replace: "",
+ },
+ {
+ file: "src/pages/RankHer.jsx",
+ search: /Trophy(,\s*)?|,\s*Trophy/,
+ replace: "",
+ },
+ {
+ file: "src/pages/RankHer.jsx",
+ search: /ArrowRight(,\s*)?|,\s*ArrowRight/,
+ replace: "",
+ },
+ { file: "src/pages/RankHer.jsx", search: /\bidx\b/, replace: "_idx" },
];
for (const { file, search, replace } of replacements) {
try {
- let content = fs.readFileSync(file, 'utf8');
+ let content = fs.readFileSync(file, "utf8");
content = content.replace(search, replace);
fs.writeFileSync(file, content);
} catch (e) {
diff --git a/index.html b/index.html
index 84baee7..260d0a8 100644
--- a/index.html
+++ b/index.html
@@ -6,12 +6,18 @@
-
-
+
+
-
+
-
+
RankerHub — Gamified Developer Leaderboard
@@ -20,4 +26,4 @@