From c84ecaee11aae074c1aae49e3d5e09e16937b648 Mon Sep 17 00:00:00 2001 From: Bhavya Reddy Date: Sun, 24 May 2026 14:29:54 +0530 Subject: [PATCH 1/3] feat: improve homepage feature showcase UI --- src/components/layout/PublicNavbar.jsx | 6 +- src/lib/firebase.js | 47 +++--- src/pages/Home.jsx | 207 ++++++++++++++++++------- 3 files changed, 186 insertions(+), 74 deletions(-) diff --git a/src/components/layout/PublicNavbar.jsx b/src/components/layout/PublicNavbar.jsx index 19e4208..f2a00b9 100644 --- a/src/components/layout/PublicNavbar.jsx +++ b/src/components/layout/PublicNavbar.jsx @@ -67,12 +67,12 @@ export const PublicNavbar = () => { {/* Right side actions */} -
+
@@ -82,7 +82,7 @@ export const PublicNavbar = () => { Sign In diff --git a/src/lib/firebase.js b/src/lib/firebase.js index 08145d1..7f00a55 100644 --- a/src/lib/firebase.js +++ b/src/lib/firebase.js @@ -24,24 +24,17 @@ const requiredConfigKeys = [ 'appId' ]; -requiredConfigKeys.forEach(key => { - if (!firebaseConfig[key]) { - console.error(`Firebase config error: ${key} is missing. Check your .env file`); - } -}); +const hasRequiredConfig = requiredConfigKeys.every((key) => Boolean(firebaseConfig[key])); -// Initialize Firebase -let app; -try { - app = initializeApp(firebaseConfig); - console.log('Firebase initialized successfully'); -} catch (error) { - console.error('Firebase initialization error:', error); - throw error; +if (!hasRequiredConfig) { + console.warn("Firebase is not configured. Auth, database, analytics, and storage services are disabled for this environment."); } +// Initialize Firebase +const app = hasRequiredConfig ? initializeApp(firebaseConfig) : null; + // Initialize Firebase services -export const auth = getAuth(app); +export const auth = app ? getAuth(app) : null; export const githubProvider = new GithubAuthProvider(); // Configure GitHub Provider with additional scopes if needed @@ -58,27 +51,31 @@ githubProvider.setCustomParameters({ // 'allow_signup': 'true' }); -export const db = getFirestore(app); +export const db = app ? getFirestore(app) : null; // Initialize analytics only in the browser, and don't let analytics // availability crash auth or the rest of Firebase setup. let analyticsInstance = null; -if (typeof window !== "undefined") { +if (app && typeof window !== "undefined") { try { analyticsInstance = getAnalytics(app); } catch (error) { - console.error("Analytics initialization error:", error); + console.warn("Analytics initialization skipped:", error); } } export const analytics = analyticsInstance; // Initialize storage (useful for profile pictures, etc.) -export const storage = getStorage(app); +export const storage = app ? getStorage(app) : null; // Helper function to sign in with GitHub export const signInWithGitHub = async () => { + if (!auth) { + throw new Error("Firebase is not configured. Add the required VITE_FIREBASE_* values before signing in."); + } + try { const result = await signInWithPopup(auth, githubProvider); // The signed-in user info @@ -119,6 +116,10 @@ export const signInWithGitHub = async () => { // Helper function to sign out export const signOutUser = async () => { + if (!auth) { + return true; + } + try { await signOut(auth); return true; @@ -130,6 +131,10 @@ export const signOutUser = async () => { // Helper function to get current user's token export const getCurrentUserToken = async () => { + if (!auth) { + return null; + } + const user = auth.currentUser; if (user) { try { @@ -145,6 +150,10 @@ export const getCurrentUserToken = async () => { // Helper function to refresh user token export const refreshUserToken = async () => { + if (!auth) { + return null; + } + const user = auth.currentUser; if (user) { try { @@ -159,4 +168,4 @@ export const refreshUserToken = async () => { }; // Export initialized app as default -export default app; \ No newline at end of file +export default app; diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 2326dfd..7c0ebbc 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useRef } from "react"; import { Link } from "react-router-dom"; import { motion } from "framer-motion"; import { @@ -6,10 +6,15 @@ import { Code2, BookOpen, ArrowRight, + ChevronLeft, + ChevronRight, Award, Users, Zap, - Target + Target, + Trophy, + UserPlus, + Gift } from "lucide-react"; import { Github } from "../components/ui/Icons"; import { fadeUp, staggerContainer } from "../utils/motion"; @@ -18,34 +23,81 @@ import Card from "../components/ui/Card"; import logo from "../assets/logo.png"; export const Home = () => { + const featureRailRef = useRef(null); + + const scrollFeatures = (direction) => { + const rail = featureRailRef.current; + if (!rail) return; + + rail.scrollBy({ + left: direction * Math.min(rail.clientWidth * 0.85, 420), + behavior: "smooth" + }); + }; + const features = [ { title: "GitRank", description: "Analyze commits, pull requests, and reviews to rank developers globally and by language.", icon: Github, color: "text-blue-500 bg-blue-500/10 border-blue-500/20", - path: "/gitrank" + accent: "from-blue-500/20 via-cyan-500/10 to-transparent", + stats: "PRs, reviews, language ranks", + status: "Contribution intelligence" }, { title: "RankHer", description: "A specialized spotlight ranking and community to support and showcase female software engineers.", icon: Sparkles, color: "text-pink-500 bg-pink-500/10 border-pink-500/20", - path: "/rankher" + accent: "from-pink-500/20 via-rose-500/10 to-transparent", + stats: "Spotlights, cohorts, recognition", + status: "Inclusive rankings" }, { title: "CodingVerse", description: "Solve daily algorithmic challenges, earn points, and climb the problem-solving ladder.", icon: Code2, color: "text-purple-500 bg-purple-500/10 border-purple-500/20", - path: "/codingverse" + accent: "from-violet-500/20 via-indigo-500/10 to-transparent", + stats: "Daily practice, XP, ladders", + status: "Challenge arena" }, { title: "CodingOwl", - description: "Build ironclad habits. Follow streaks and focus sessions backed by a cute habit owl.", + description: "Build ironclad habits. Follow streaks and focus sessions backed by a focused habit assistant.", icon: BookOpen, color: "text-orange-500 bg-orange-500/10 border-orange-500/20", - path: "/codingowl" + accent: "from-amber-500/20 via-orange-500/10 to-transparent", + stats: "Streaks, focus sessions, rituals", + status: "Habit companion" + }, + { + title: "Achievements System", + description: "Turn consistent progress into badges, milestone trophies, and profile-ready proof of work.", + icon: Trophy, + color: "text-emerald-500 bg-emerald-500/10 border-emerald-500/20", + accent: "from-emerald-500/20 via-teal-500/10 to-transparent", + stats: "Badges, trophies, milestones", + status: "Progress rewards" + }, + { + title: "Friends System", + description: "Follow peers, compare momentum, and keep developer growth social without adding noise.", + icon: UserPlus, + color: "text-sky-500 bg-sky-500/10 border-sky-500/20", + accent: "from-sky-500/20 via-blue-500/10 to-transparent", + stats: "Followers, activity, peer ranks", + status: "Social coding graph" + }, + { + title: "Referral System", + description: "Invite developers into the platform and reward community growth with meaningful perks.", + icon: Gift, + color: "text-fuchsia-500 bg-fuchsia-500/10 border-fuchsia-500/20", + accent: "from-fuchsia-500/20 via-purple-500/10 to-transparent", + stats: "Invites, rewards, growth loops", + status: "Community expansion" } ]; @@ -58,7 +110,6 @@ export const Home = () => { return (
- {/* Background Orbs (optimized with radial gradients instead of expensive blur filters) */}
@@ -69,25 +120,27 @@ export const Home = () => { initial="hidden" animate="visible" variants={staggerContainer(0.1, 0.05)} - className="flex flex-col md:flex-row items-center justify-between gap-8 md:gap-12 text-left" + className="flex flex-col xl:flex-row items-start xl:items-center justify-between gap-8 md:gap-12 text-left" > -
+
{/* Tagline Badge */} - 🚀 The Developer Gamification Platform + The Developer Gamification Platform {/* Heading */} Level Up Your Code.
- - Claim Your Leaderboard Rank. + + Claim Your + Leaderboard + Rank.
@@ -96,31 +149,26 @@ export const Home = () => { variants={fadeUp()} className="text-base sm:text-lg md:text-xl text-slate-500 dark:text-slate-400 font-medium" > - RankerHub tracks commits, streaks, and problem-solving to gamify your software development journey. Build habits, spot-light contributions, and earn badges. + RankerHub tracks commits, streaks, and problem-solving to gamify your software development journey. Build habits, spotlight contributions, and earn badges. - {/* CTA Buttons */} + {/* CTA Button */} - + Get Started - - - Explore GitRank - -
{/* Big Circular Logo on the Right */}
@@ -133,11 +181,11 @@ export const Home = () => { {/* Metrics Section */}
-
- {valueProps.map((prop, idx) => { +
+ {valueProps.map((prop) => { const Icon = prop.icon; return ( -
+
@@ -153,44 +201,99 @@ export const Home = () => {
- {/* Features Grid Section */} -
-
-

- Core Ranking Modules -

-

- Discover the distinct features that drive developers' motivation. -

+ {/* Feature Showcase Section */} +
+
+
+ + Feature suite + +

+ Everything developers need to turn progress into rank. +

+

+ A connected set of ranking, learning, habit, achievement, social, and referral systems designed for a modern developer platform. +

+
+ +
+ + +
-
+
{features.map((feature, idx) => { const Icon = feature.icon; return ( - - -
-
- + +
+

+ Swipe to view all features +

+
); }; From e4453c7d2f793e0e5b457d2c9f9da007fe3d7246 Mon Sep 17 00:00:00 2001 From: Bhavya Reddy Date: Mon, 25 May 2026 21:29:51 +0530 Subject: [PATCH 2/3] fix homepage feature showcase build --- src/pages/Home.jsx | 80 ++-------------------------------------- src/pages/Onboarding.jsx | 55 ++++++++++++--------------- 2 files changed, 28 insertions(+), 107 deletions(-) diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 6e0904c..35fbece 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -110,54 +110,10 @@ export const Home = () => { return (
- {/* Background Orbs (optimized with radial gradients instead of expensive blur filters) */}
- {/* Hero Section */} -
- -
- {/* Tagline Badge */} - - The Developer Gamification Platform - - - {/* Heading */} - - Level Up Your Code.
- - Claim Your - Leaderboard - Rank. - -
- - {/* Subtitle */} - - RankerHub tracks commits, streaks, and problem-solving to gamify your software development journey. Build habits, spotlight contributions, and earn badges. - - - {/* CTA Button */} - {/* Hero Section with Background Video - Slightly Increased Height */}
- - {/* 🎥 Background Video - Height set to 55% (slightly increased from 50%) */} - {/* Change this value to adjust video height: h-1/2 (50%), h-[55%] (55%), h-[60%] (60%), h-2/3 (66%) */}
- {/* Metrics Section */}
{valueProps.map((prop) => { @@ -278,7 +207,6 @@ export const Home = () => {
- {/* Feature Showcase Section */}
@@ -375,4 +303,4 @@ export const Home = () => { ); }; -export default Home; \ No newline at end of file +export default Home; diff --git a/src/pages/Onboarding.jsx b/src/pages/Onboarding.jsx index 9f37c80..c243b5e 100644 --- a/src/pages/Onboarding.jsx +++ b/src/pages/Onboarding.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useMemo, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { motion, AnimatePresence } from "framer-motion"; import { @@ -37,7 +37,10 @@ export const Onboarding = () => { const navigate = useNavigate(); // Fields state + const suggestedName = userData?.name || user?.displayName || ""; const [name, setName] = useState(""); + const [hasEditedName, setHasEditedName] = useState(false); + const displayName = hasEditedName ? name : suggestedName; const [gender, setGender] = useState(""); const [dob, setDob] = useState(""); const [city] = useState("Mumbai"); // Strictly Locked @@ -46,9 +49,18 @@ export const Onboarding = () => { const [collegeSearch, setCollegeSearch] = useState(""); const [selectedCollege, setSelectedCollege] = useState(""); const [showCollegeDropdown, setShowCollegeDropdown] = useState(false); - const [filteredColleges, setFilteredColleges] = useState(collegesList); + const filteredColleges = useMemo(() => { + if (collegeSearch.trim() === "") { + return collegesList; + } + + const searchLower = collegeSearch.toLowerCase(); + return collegesList.filter((col) => col.toLowerCase().includes(searchLower)); + }, [collegeSearch]); - const [referralCode, setReferralCode] = useState(""); + const [referralCode, setReferralCode] = useState(() => + typeof sessionStorage === "undefined" ? "" : sessionStorage.getItem("referred_by_code") || "" + ); const [linkedinUrl, setLinkedinUrl] = useState(""); const [instagramHandle, setInstagramHandle] = useState(""); @@ -59,38 +71,14 @@ export const Onboarding = () => { const dropdownRef = useRef(null); - // Prefill name from GitHub when session is loaded - useEffect(() => { - if (userData && userData.name) { - setName(userData.name); - } else if (user && user.displayName) { - setName(user.displayName); - } - }, [user, userData]); - // Prefill referral code from session storage (URL parse cache) useEffect(() => { const savedRef = sessionStorage.getItem("referred_by_code"); if (savedRef) { - setReferralCode(savedRef); - // Clean up after prefilling once sessionStorage.removeItem("referred_by_code"); } }, []); - // Handle college typing search filter - useEffect(() => { - if (collegeSearch.trim() === "") { - setFilteredColleges(collegesList); - } else { - const searchLower = collegeSearch.toLowerCase(); - const filtered = collegesList.filter((col) => - col.toLowerCase().includes(searchLower) - ); - setFilteredColleges(filtered); - } - }, [collegeSearch]); - // Click outside to close dropdown useEffect(() => { const handleClickOutside = (event) => { @@ -126,7 +114,9 @@ export const Onboarding = () => { setSuccessMsg(""); // 1. Validations - if (!name.trim()) { + const finalName = displayName.trim(); + + if (!finalName) { setError("Please enter your full name."); setIsLoading(false); return; @@ -221,7 +211,7 @@ export const Onboarding = () => { uid: activeUid, githubUsername, githubId: userData?.githubId || user.providerData[0]?.uid || null, - name, + name: finalName, email: user.email || "", avatar: userData?.avatar || user.photoURL || "", gender, @@ -384,8 +374,11 @@ export const Onboarding = () => { setName(e.target.value)} + value={displayName} + onChange={(e) => { + setHasEditedName(true); + setName(e.target.value); + }} className="w-full px-4 py-3 text-sm rounded-xl border border-slate-200 dark:border-slate-800 bg-white/40 dark:bg-slate-950/20 focus:outline-none focus:ring-2 focus:ring-violet-500/20 focus:border-violet-500 dark:text-white transition-all placeholder:text-slate-400" />
From 4ee1bc03b0c2d7829c2be53167dfa7145e499929 Mon Sep 17 00:00:00 2001 From: Bhavya Reddy Date: Mon, 25 May 2026 21:34:01 +0530 Subject: [PATCH 3/3] fix onboarding merge conflict markers --- src/pages/Onboarding.jsx | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/pages/Onboarding.jsx b/src/pages/Onboarding.jsx index 595abe8..c4d9f12 100644 --- a/src/pages/Onboarding.jsx +++ b/src/pages/Onboarding.jsx @@ -69,50 +69,14 @@ export const Onboarding = () => { const dropdownRef = useRef(null); -<<<<<<< feature/homepage-ui-improvements -======= - // Prefill name from GitHub when session is loaded - useEffect(() => { - if (userData && userData.name) { - // eslint-disable-next-line react-hooks/set-state-in-effect - setName(userData.name); - } else if (user && user.displayName) { - setName(user.displayName); - } - }, [user, userData]); - ->>>>>>> main // Prefill referral code from session storage (URL parse cache) useEffect(() => { const savedRef = sessionStorage.getItem("referred_by_code"); if (savedRef) { -<<<<<<< feature/homepage-ui-improvements -======= - // eslint-disable-next-line react-hooks/set-state-in-effect - setReferralCode(savedRef); - // Clean up after prefilling once ->>>>>>> main sessionStorage.removeItem("referred_by_code"); } }, []); -<<<<<<< feature/homepage-ui-improvements -======= - // Handle college typing search filter - useEffect(() => { - if (collegeSearch.trim() === "") { - // eslint-disable-next-line react-hooks/set-state-in-effect - setFilteredColleges(collegesList); - } else { - const searchLower = collegeSearch.toLowerCase(); - const filtered = collegesList.filter((col) => - col.toLowerCase().includes(searchLower) - ); - setFilteredColleges(filtered); - } - }, [collegeSearch]); - ->>>>>>> main // Click outside to close dropdown useEffect(() => { const handleClickOutside = (event) => {