Skip to content

Conversation

@Ojasp21
Copy link

@Ojasp21 Ojasp21 commented Jan 3, 2026

Closes #265

📝 Description

This pull request introduces a global footer component that is rendered consistently across the entire application. Previously, footer implementations were duplicated within individual pages, leading to redundancy and maintenance overhead. This PR centralizes the footer logic into a single reusable component and applies it at the app layout level.

The footer also includes a smooth scroll-based animation that triggers every time it enters the viewport, improving the overall user experience.

🔧 Changes Made

  1. Added a reusable global Footer component under components/.
  2. Integrated the footer globally via App.tsx.
  3. Removed duplicate footer implementations from individual pages (e.g., HomePage).
  4. Implemented scroll-based animation using IntersectionObserver.
  5. Ensured the animation triggers on every viewport entry.
  6. Maintained existing UI design and routing behavior.

📷 Screenshots or Visual Changes (if applicable)

Screenshot 2026-01-03 at 8 44 54 PM Screenshot 2026-01-03 at 8 45 31 PM

✅ Checklist

  • [ ✅ ] I have read the contributing guidelines.
  • [ ✅ ] I have added tests that prove my fix is effective or that my feature works.
  • [ ✅ ] I have added necessary documentation (if applicable).
  • [ ✅ ] Any dependent changes have been merged and published in downstream modules.

Summary by CodeRabbit

  • New Features

    • Added a footer to the application layout featuring navigation links, branding information, and copyright details.
  • Chores

    • Updated UI component libraries to support enhanced styling and icon capabilities.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 3, 2026

📝 Walkthrough

Walkthrough

The changes consolidate footer functionality from HomePage into a new reusable global Footer component rendered in App.tsx. Material-UI and Emotion dependencies were added to support the footer's styling and icons. HomePage's footer code was removed to eliminate duplication.

Changes

Cohort / File(s) Summary
UI Framework Dependencies
Frontend/package.json
Added four dependencies: @emotion/react, @emotion/styled, @mui/icons-material, and @mui/material to support Material-UI components and styling.
Global Footer Integration
Frontend/src/App.tsx
Imported and rendered new Footer component. Wrapped routing structure with container div to place Footer beneath all routed content without affecting routing logic.
New Footer Component
Frontend/src/components/footer.tsx
Created new React component with styled gradient background, IntersectionObserver for fade/slide-in animation (threshold 0.15), MUI Rocket icon, navigation links (Dashboard, Opportunities, Analytics, Messages), and dynamic copyright year.
Footer Cleanup
Frontend/src/pages/HomePage.tsx
Removed footer-related logic: footerRef ref, isFooterVisible state, observer useEffect, and two Footer JSX sections. Component signature unchanged.

Sequence Diagram

sequenceDiagram
    participant App as App.tsx
    participant Footer as Footer Component
    participant Observer as IntersectionObserver
    participant DOM as DOM

    App->>Footer: Render Footer component
    activate Footer
    Footer->>DOM: Mount footer element
    Footer->>Observer: Create IntersectionObserver (threshold: 0.15)
    activate Observer
    
    Note over Observer: Observing visibility<br/>in viewport
    
    alt Footer enters viewport
        Observer->>Footer: Intersection detected
        Footer->>DOM: Apply fade/slide-in animation
        Footer->>DOM: Render content (icon, links, copyright)
    else Footer leaves viewport
        Observer->>Footer: No intersection
        Footer->>DOM: Maintain resting state
    end
    
    deactivate Observer
    deactivate Footer
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A footer hops from every page,
Now global, wise, and centered-stage!
No more duplication's dance,
One Footer leads the grand entrance—
Consistent grace in every glance!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding a global footer component and removing duplicate footers from individual pages.
Linked Issues check ✅ Passed All objectives from issue #265 are met: global Footer component created, integrated at app layout level (App.tsx), and duplicate footers removed from HomePage.
Out of Scope Changes check ✅ Passed All changes align with the scope: dependency additions support the new component implementation, footer component creation and integration, and removal of duplicate footers from HomePage.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
Frontend/src/pages/HomePage.tsx (1)

429-430: Remove or update outdated comment about footer observer.

The comment references keeping "other observers for footer" but the footer observer and all footer-related code have been removed from this component. This comment is now misleading.

🔎 Proposed fix
-  // ... keep other observers for footer, etc. if needed ...

Or update it to reflect current observers:

-  // ... keep other observers for footer, etc. if needed ...
+  // Intersection observers for section animations
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3be437 and 32b255b.

⛔ Files ignored due to path filters (1)
  • Frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • Frontend/package.json
  • Frontend/src/App.tsx
  • Frontend/src/components/footer.tsx
  • Frontend/src/pages/HomePage.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/App.tsx (1)
Frontend/src/context/AuthContext.tsx (1)
  • AuthProvider (64-215)
🔇 Additional comments (4)
Frontend/src/App.tsx (2)

48-50: Layout structure looks good.

The flex-col container ensures the footer stays at the bottom while allowing the main content to grow. This is a clean implementation of the sticky footer pattern.

Also applies to: 140-145


23-23: [Your rewritten review comment text here]
[Exactly ONE classification tag]

Frontend/src/components/footer.tsx (1)

1-3: Imports are clean and minimal.

Good use of only the necessary dependencies. The component doesn't rely on the newly added Material UI libraries.

Frontend/src/pages/HomePage.tsx (1)

386-393: Footer removal implemented cleanly.

The footer-related code (refs, state, useEffect, and JSX) has been properly removed from HomePage, successfully eliminating duplication. The component now relies on the global Footer rendered in App.tsx.

Comment on lines +13 to +16
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.3.6",
"@mui/material": "^7.3.6",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for Material UI imports across the codebase

echo "=== Checking for @mui/material imports ==="
rg -n "from ['\"]@mui/material" --type=tsx --type=ts --type=jsx --type=js -C2

echo -e "\n=== Checking for @mui/icons-material imports ==="
rg -n "from ['\"]@mui/icons-material" --type=tsx --type=ts --type=jsx --type=js -C2

echo -e "\n=== Checking for @emotion imports ==="
rg -n "from ['\"]@emotion/(react|styled)" --type=tsx --type=ts --type=jsx --type=js -C2

echo -e "\n=== Checking MUI imports (alternative patterns) ==="
rg -n "@mui|@emotion" --type=tsx --type=ts --type=jsx --type=js | head -30

Repository: AOSSIE-Org/InPactAI

Length of output: 376


🏁 Script executed:

#!/bin/bash
# Search for Material UI and Emotion imports without type restrictions

echo "=== Checking for @mui/material imports ==="
rg "@mui/material" Frontend/ -A2

echo -e "\n=== Checking for @mui/icons-material imports ==="
rg "@mui/icons-material" Frontend/ -A2

echo -e "\n=== Checking for @emotion imports ==="
rg "@emotion/(react|styled)" Frontend/ -A2

echo -e "\n=== Checking footer.tsx content ==="
if [ -f "Frontend/src/components/footer.tsx" ]; then
  cat -n Frontend/src/components/footer.tsx
else
  echo "footer.tsx not found at expected location"
  find Frontend -name "footer.tsx" -o -name "footer.ts"
fi

echo -e "\n=== All files in Frontend/src/components ==="
find Frontend/src/components -type f -name "*.tsx" -o -name "*.ts" 2>/dev/null | head -20

Repository: AOSSIE-Org/InPactAI

Length of output: 10334


🏁 Script executed:

#!/bin/bash
# More comprehensive search for MUI/Emotion usage in all source files

echo "=== All TypeScript/JavaScript source files searching for MUI usage ==="
find Frontend/src -type f \( -name "*.tsx" -o -name "*.ts" -o -name "*.jsx" -o -name "*.js" \) | while read file; do
  if grep -l "@mui\|@emotion" "$file" 2>/dev/null; then
    echo "Found in: $file"
    grep -n "@mui\|@emotion" "$file"
  fi
done

echo -e "\n=== Checking all files for import statements from @mui or @emotion ==="
rg "import.*from.*[@'\"]@(mui|emotion)" Frontend/src/ 2>/dev/null || echo "No matches found"

echo -e "\n=== Checking all files for require statements from @mui or @emotion ==="
rg "require.*[@'\"]@(mui|emotion)" Frontend/src/ 2>/dev/null || echo "No matches found"

Repository: AOSSIE-Org/InPactAI

Length of output: 312


Remove unused Material UI and Emotion dependencies.

MUI and Emotion packages (@mui/material, @mui/icons-material, @emotion/react, @emotion/styled) are declared in package.json but have zero imports throughout the entire codebase. The Footer component uses lucide-react for icons and Tailwind CSS for styling—no MUI components are utilized.

These libraries add ~500KB+ combined minified size with no benefit. Remove them from package.json and run npm install to clean up the dependency tree.

🤖 Prompt for AI Agents
In Frontend/package.json around lines 13 to 16, remove the unused dependencies
"@mui/material", "@mui/icons-material", "@emotion/react", and "@emotion/styled"
from the dependencies list, then run npm install (or npm ci) to update
node_modules and package-lock.json; before removing, ensure a repo-wide search
confirms there are no imports/usages of these packages (the review indicates
zero imports), and after install run the build and a quick smoke test to verify
nothing breaks.

Comment on lines +9 to +22
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
setIsFooterVisible(entry.isIntersecting);
},
{ threshold: 0.15 }
);

if (footerRef.current) observer.observe(footerRef.current);

return () => {
if (footerRef.current) observer.unobserve(footerRef.current);
};
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix potential memory leak in IntersectionObserver cleanup.

The cleanup function accesses footerRef.current which may be null or may have changed by the time cleanup runs. In React 19, refs can be cleaned up before effects, leading to potential issues.

🔎 Proposed fix
 useEffect(() => {
   const observer = new IntersectionObserver(
     ([entry]) => {
       setIsFooterVisible(entry.isIntersecting);
     },
     { threshold: 0.15 }
   );

-  if (footerRef.current) observer.observe(footerRef.current);
+  const element = footerRef.current;
+  if (element) observer.observe(element);

   return () => {
-    if (footerRef.current) observer.unobserve(footerRef.current);
+    if (element) observer.unobserve(element);
+    observer.disconnect();
   };
 }, []);
🤖 Prompt for AI Agents
In Frontend/src/components/footer.tsx around lines 9 to 22, the cleanup
currently reads footerRef.current which can be null or changed before cleanup;
capture the observed element in a local variable (e.g., const observed =
footerRef.current) before calling observer.observe, then in the cleanup check
and call observer.unobserve(observed) only if observed is non-null and finally
call observer.disconnect() to fully clean up the observer; ensure you reference
the captured element rather than footerRef.current in the cleanup to avoid the
potential memory leak.

Comment on lines +51 to +73
<nav className="mt-8 flex flex-wrap justify-center gap-x-8 gap-y-3 text-sm text-gray-400">
<Link to="/dashboard" className="hover:text-white transition-colors">
Dashboard
</Link>
<Link
to="/dashboard/sponsorships"
className="hover:text-white transition-colors"
>
Opportunities
</Link>
<Link
to="/dashboard/analytics"
className="hover:text-white transition-colors"
>
Analytics
</Link>
<Link
to="/dashboard/messages"
className="hover:text-white transition-colors"
>
Messages
</Link>
</nav>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Navigation links reference protected routes that unauthenticated users cannot access.

The footer includes links to /dashboard, /dashboard/sponsorships, /dashboard/analytics, and /dashboard/messages. Since this footer is rendered globally (including on public pages per App.tsx), unauthenticated users will see these links but encounter ProtectedRoute guards when clicking them.

Consider one of these approaches:

  1. Conditional rendering - Show different links based on authentication state
  2. Public links only - Use public navigation items (About, Pricing, Contact)
  3. Route-based footer - Render different footers for authenticated vs public routes
🔎 Example: Conditional navigation based on auth state
+import { useAuth } from "../context/AuthContext";
+
 const Footer = () => {
   const footerRef = useRef<HTMLElement | null>(null);
   const [isFooterVisible, setIsFooterVisible] = useState(false);
+  const { isAuthenticated } = useAuth();

   // ... useEffect ...

   return (
     <footer /* ... */>
       {/* ... */}
       <nav className="mt-8 flex flex-wrap justify-center gap-x-8 gap-y-3 text-sm text-gray-400">
-        <Link to="/dashboard" className="hover:text-white transition-colors">
-          Dashboard
-        </Link>
-        <Link to="/dashboard/sponsorships" className="hover:text-white transition-colors">
-          Opportunities
-        </Link>
-        <Link to="/dashboard/analytics" className="hover:text-white transition-colors">
-          Analytics
-        </Link>
-        <Link to="/dashboard/messages" className="hover:text-white transition-colors">
-          Messages
-        </Link>
+        {isAuthenticated ? (
+          <>
+            <Link to="/dashboard" className="hover:text-white transition-colors">
+              Dashboard
+            </Link>
+            <Link to="/dashboard/sponsorships" className="hover:text-white transition-colors">
+              Opportunities
+            </Link>
+            <Link to="/dashboard/analytics" className="hover:text-white transition-colors">
+              Analytics
+            </Link>
+            <Link to="/dashboard/messages" className="hover:text-white transition-colors">
+              Messages
+            </Link>
+          </>
+        ) : (
+          <>
+            <Link to="/" className="hover:text-white transition-colors">
+              Home
+            </Link>
+            <a href="#features" className="hover:text-white transition-colors">
+              Features
+            </a>
+            <a href="#pricing" className="hover:text-white transition-colors">
+              Pricing
+            </a>
+            <Link to="/login" className="hover:text-white transition-colors">
+              Login
+            </Link>
+          </>
+        )}
       </nav>
       {/* ... */}
     </footer>
   );
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<nav className="mt-8 flex flex-wrap justify-center gap-x-8 gap-y-3 text-sm text-gray-400">
<Link to="/dashboard" className="hover:text-white transition-colors">
Dashboard
</Link>
<Link
to="/dashboard/sponsorships"
className="hover:text-white transition-colors"
>
Opportunities
</Link>
<Link
to="/dashboard/analytics"
className="hover:text-white transition-colors"
>
Analytics
</Link>
<Link
to="/dashboard/messages"
className="hover:text-white transition-colors"
>
Messages
</Link>
</nav>
import { useAuth } from "../context/AuthContext";
const Footer = () => {
const footerRef = useRef<HTMLElement | null>(null);
const [isFooterVisible, setIsFooterVisible] = useState(false);
const { isAuthenticated } = useAuth();
// ... useEffect ...
return (
<footer /* ... */>
{/* ... */}
<nav className="mt-8 flex flex-wrap justify-center gap-x-8 gap-y-3 text-sm text-gray-400">
{isAuthenticated ? (
<>
<Link to="/dashboard" className="hover:text-white transition-colors">
Dashboard
</Link>
<Link to="/dashboard/sponsorships" className="hover:text-white transition-colors">
Opportunities
</Link>
<Link to="/dashboard/analytics" className="hover:text-white transition-colors">
Analytics
</Link>
<Link to="/dashboard/messages" className="hover:text-white transition-colors">
Messages
</Link>
</>
) : (
<>
<Link to="/" className="hover:text-white transition-colors">
Home
</Link>
<a href="#features" className="hover:text-white transition-colors">
Features
</a>
<a href="#pricing" className="hover:text-white transition-colors">
Pricing
</a>
<Link to="/login" className="hover:text-white transition-colors">
Login
</Link>
</>
)}
</nav>
{/* ... */}
</footer>
);
};
🤖 Prompt for AI Agents
In Frontend/src/components/footer.tsx around lines 51 to 73, the footer
currently renders links to protected routes (/dashboard,
/dashboard/sponsorships, /dashboard/analytics, /dashboard/messages) which are
visible on public pages; update the component to conditionally render navigation
based on authentication state: import/use the existing auth context or
isAuthenticated hook, wrap the current dashboard links in a check that only
renders them when authenticated, and render an alternative set of public links
(e.g., About, Pricing, Contact, Login) when not authenticated; ensure you don't
remove the footer entirely and that no protected route links are rendered for
unauthenticated users.

<div className="mt-10 h-px w-full bg-gradient-to-r from-transparent via-gray-700 to-transparent" />

<p className="mt-6 text-xs text-gray-500">
© {new Date().getFullYear()} InpactAI. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Brand name inconsistency: "InpactAI" vs "Inpact".

The copyright shows "InpactAI" but the application consistently uses "Inpact" elsewhere (header, title, etc.). Maintain consistency with the established branding.

🔎 Proposed fix
-        © {new Date().getFullYear()} InpactAI. All rights reserved.
+        © {new Date().getFullYear()} Inpact. All rights reserved.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
© {new Date().getFullYear()} InpactAI. All rights reserved.
© {new Date().getFullYear()} Inpact. All rights reserved.
🤖 Prompt for AI Agents
In Frontend/src/components/footer.tsx around line 78, the footer uses the brand
name "InpactAI" which is inconsistent with the rest of the app using "Inpact";
update the string to "Inpact" so branding matches everywhere (e.g., change ©
{new Date().getFullYear()} InpactAI. All rights reserved. to use "Inpact"
instead), run a quick grep across the repo to confirm no other footer instances
remain with "InpactAI".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Single Global Footer to Avoid Duplicate Page-Level Footers

1 participant