Skip to content

Fix: use animated number#13

Merged
SimonBurmer merged 5 commits intomainfrom
fix-useAnimatedNumber
Mar 24, 2026
Merged

Fix: use animated number#13
SimonBurmer merged 5 commits intomainfrom
fix-useAnimatedNumber

Conversation

@SimonBurmer
Copy link
Copy Markdown
Collaborator

@SimonBurmer SimonBurmer commented Mar 24, 2026

Summary by CodeRabbit

  • New Features

    • Added footer with donation link, legal navigation, and social media links.
    • Added Legal Notice and Privacy Policy pages.
  • UI/UX Improvements

    • Updated member testimonials with company logos.
    • Refined event card layouts and spacing.
    • Updated Members page hero background image.
    • Improved overall page layout structure for better footer positioning.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
website-special-pages-y5ch Ready Ready Preview, Comment Mar 24, 2026 9:33am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 24, 2026

Warning

Rate limit exceeded

@SimonBurmer has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 9 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 55aab39e-64a5-4565-8ce7-7cc66df3c6f6

📥 Commits

Reviewing files that changed from the base of the PR and between db6afee and 43e1eff.

📒 Files selected for processing (2)
  • app/member-journey/page.tsx
  • lib/useAnimatedNumber.ts
📝 Walkthrough

Walkthrough

The pull request introduces structural layout improvements with a sticky footer, extracts shared animation hooks to a library, adds placeholder legal and privacy policy pages, refines testimonial and member journey data structures with multi-logo support, and simplifies event card UI by removing date badge displays.

Changes

Cohort / File(s) Summary
Layout & Footer Integration
app/layout.tsx, components/Footer.tsx
Root layout adopts flex-column structure with full viewport height. Footer component added with donate link, internal legal navigation, and external social links (Instagram, LinkedIn).
New Legal Pages
app/legal-notice/page.tsx, app/privacy-policy/page.tsx
Two new placeholder pages added with branded backgrounds, centered containers, and "Content coming soon..." messaging.
Animation Hooks Consolidation
lib/hooks.ts, app/home/page.tsx
New shared hooks module exports useInView and re-exports useAnimatedNumber. Home page removes local useCountUp and useInView implementations, replacing five fact animations with consolidated useAnimatedNumber calls.
Event Cards UI Simplification
components/PastEventsGrid.tsx, components/UpcomingEventsGrid.tsx
Date badge UI blocks removed from both event card grids. Upcoming events grid padding adjusted to single p-4 class.
Testimonials & Member Journey
components/TestimonialsSection.tsx, app/member-journey/page.tsx
TestimonialItem interface updated from single logo/logoAlt to optional logos array with URL support. Member journey data refreshed with story details and logo arrays. Logos rendered as right-aligned stack within testimonial content. Event frequency pills conditionally hidden.
Minor Updates
app/events/page.tsx, app/members/page.tsx
Events page changes bottom margin to padding (mb-20pb-20). Members page hero background updated from "/member-background.png" to "/ourMembers/hero.png".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A footer hops into place with grace,
Hooks consolidate in their cozy space,
Logos dance in testimonials new,
Events simplified, styling fresh and true,
The layout flexes, the pages spread wide—
Another sprint complete with rabbit pride! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title 'Fix: use animated number' is partially related to the changeset but does not capture the main scope of changes. Consider expanding the title to better reflect the broader scope, such as 'Refactor: consolidate animated counters and add footer layout' to capture both the hook consolidation and layout restructuring changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix-useAnimatedNumber

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

@SimonBurmer SimonBurmer changed the title Fix use animated number Fix: use animated number Mar 24, 2026
Copy link
Copy Markdown

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/UpcomingEventsGrid.tsx (1)

98-116: 🛠️ Refactor suggestion | 🟠 Major

Remove unused formattedDate computation.

The formattedDate variable is computed but never rendered after the date badge removal. This is now dead code that adds unnecessary complexity and computation.

🧹 Proposed fix to remove dead code
          return (
            <a
              key={eventWrapper.api_id}
              href={event.url}
              target="_blank"
              rel="noopener noreferrer"
-             
-          // Parse the date and handle different formats
-          let formattedDate = 'Date unavailable'
-
-          try {
-            const dateStr = event.start_at
-
-            if (dateStr) {
-              const eventDate = new Date(dateStr)
-
-              if (!isNaN(eventDate.getTime())) {
-                formattedDate = eventDate.toLocaleDateString('en-US', {
-                  month: 'short',
-                  day: 'numeric',
-                  year: 'numeric'
-                })
-              }
-            }
-          } catch (err) {
-            console.error('Error parsing date:', err, event)
-          }
-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/UpcomingEventsGrid.tsx` around lines 98 - 116, The formattedDate
computation in UpcomingEventsGrid (the let formattedDate = 'Date unavailable'
and its surrounding try/catch that reads event.start_at, constructs eventDate,
and calls console.error on error) is dead now that the date badge was
removed—delete the entire block (the formattedDate declaration, the try { ... }
catch { ... } and any console.error) and ensure no other code references
formattedDate or relies on that parsing; if any leftover tests or variables
reference formattedDate, remove or update them accordingly.
🧹 Nitpick comments (7)
components/UpcomingEventsGrid.tsx (2)

152-157: Remove commented-out code.

Commented-out JSX for the "View Details" link indicator should either be implemented or removed. Version control preserves history if it's needed later.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/UpcomingEventsGrid.tsx` around lines 152 - 157, In
UpcomingEventsGrid component remove the commented-out JSX block for the "View
Details" link indicator (the commented div containing the span "View Details"
and the svg arrow) to clean up dead code; if the functionality is required,
instead implement it as a live element within the component (e.g., re-add the
div with appropriate classes and accessible text/aria attributes) otherwise
delete the entire commented block so version control keeps history.

38-40: Remove debug console.log statements.

These debug logs are useful during development but should be removed before merging to production. They expose API response details in the browser console.

🧹 Proposed fix
        const data = await response.json()

-        // Log the full API response for debugging
-        console.log('Upcoming Events API Response:', data)
-        console.log('Number of upcoming events:', data.entries?.length || 0)
-
        // Sort events by date (soonest first)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/UpcomingEventsGrid.tsx` around lines 38 - 40, In the
UpcomingEventsGrid component remove the two debug console.log statements that
print 'Upcoming Events API Response:' and 'Number of upcoming events:' (they
reference the data variable and data.entries?.length); delete those
console.log(...) lines (or wrap them behind a dev-only check such as
process.env.NODE_ENV !== 'production' if you prefer preserving dev-time logging)
so API response details are not exposed in production.
app/legal-notice/page.tsx (1)

1-17: Consider removing min-h-screen from page content.

Since the root layout now wraps children in <main className="flex-grow">, individual pages don't need their own min-h-screen. The parent flex container already ensures proper height distribution. This could cause the page to be taller than necessary.

Suggested adjustment
 export default function LegalNoticePage() {
   return (
-    <div className="min-h-screen bg-brand-dark-blue">
+    <div className="bg-brand-dark-blue py-20">
       <div className="mx-auto px-10 lg:px-20 py-20">

Or keep the outer div minimal and let the layout handle the height:

-    <div className="min-h-screen bg-brand-dark-blue">
+    <div className="flex-grow bg-brand-dark-blue">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/legal-notice/page.tsx` around lines 1 - 17, The outer container in the
LegalNoticePage component includes the unnecessary "min-h-screen" utility
(className="min-h-screen bg-brand-dark-blue"); remove "min-h-screen" from that
div's className so the page relies on the root layout's <main
className="flex-grow"> for height handling, keeping the rest of the JSX and
styling intact.
app/members/page.tsx (1)

8-8: Consider consistent import pattern.

This file imports useAnimatedNumber directly from @/lib/useAnimatedNumber, while app/home/page.tsx imports from @/lib/hooks. For consistency across the codebase, consider using the centralized export:

-import { useAnimatedNumber } from "@/lib/useAnimatedNumber"
+import { useAnimatedNumber } from "@/lib/hooks"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/members/page.tsx` at line 8, The import for useAnimatedNumber in page.tsx
is inconsistent with the project's centralized exports; update the import to
pull useAnimatedNumber from the central hooks barrel (the same module other
files use) so the component references useAnimatedNumber from the shared export
(e.g., replace the direct "@/lib/useAnimatedNumber" import with the centralized
"@/lib/hooks" export and ensure the symbol useAnimatedNumber is exported from
that barrel).
app/privacy-policy/page.tsx (1)

1-17: Same min-h-screen consideration as Legal Notice page.

This page has the same structure and the same potential layout concern. Consider the same adjustment.

Additionally, since both placeholder pages are nearly identical, you could extract a shared component:

Optional: Extract shared placeholder component
// components/PlaceholderPage.tsx
export default function PlaceholderPage({ title }: { title: string }) {
  return (
    <div className="bg-brand-dark-blue">
      <div className="mx-auto px-10 lg:px-20 py-20">
        <h1 className="text-4xl md:text-5xl font-black text-white mb-12">
          {title}
        </h1>
        <div className="prose prose-invert max-w-none">
          <p className="text-gray-300 text-lg">Content coming soon...</p>
        </div>
      </div>
    </div>
  )
}

Then use it in both pages:

import PlaceholderPage from '@/components/PlaceholderPage'
export default function PrivacyPolicyPage() {
  return <PlaceholderPage title="PRIVACY POLICY" />
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/privacy-policy/page.tsx` around lines 1 - 17, The page uses a top-level
"min-h-screen" which can cause unwanted spacing similar to the Legal Notice
page; remove or replace "min-h-screen" from PrivacyPolicyPage's root div (or
move the background class "bg-brand-dark-blue" to a non-height-constraining
wrapper) so the page doesn't force full viewport height. Also extract the
duplicated placeholder into a shared component (e.g., PlaceholderPage with a
title prop) and replace PrivacyPolicyPage (and the Legal Notice page) to return
<PlaceholderPage title="PRIVACY POLICY" /> to avoid duplication and keep styling
consistent.
lib/hooks.ts (1)

13-30: LGTM! Well-structured viewport detection hook.

The implementation correctly handles the one-time visibility detection pattern with proper cleanup. Consider making the ref type generic for broader element support in the future:

export function useInView<T extends HTMLElement = HTMLDivElement>(threshold = 0.2) {
  const ref = useRef<T>(null)
  // ...
}

This is optional since HTMLDivElement works for most use cases.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/hooks.ts` around lines 13 - 30, Change the useInView hook to accept a
generic element type so it can be reused for non-div elements: update the
function signature of useInView to be generic (e.g., useInView<T extends
HTMLElement = HTMLDivElement>(threshold = 0.2)) and change the ref creation
inside the function from useRef<HTMLDivElement>(null) to useRef<T>(null); ensure
any references to the returned ref/visible from useInView still work with the
new generic type (no other logic changes required).
components/TestimonialsSection.tsx (1)

70-70: Remove duplicate Tailwind utility class.

w-auto is repeated in the same className.

♻️ Proposed cleanup
-                                                    className="h-5 w-auto w-auto object-contain"
+                                                    className="h-5 w-auto object-contain"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/TestimonialsSection.tsx` at line 70, In the TestimonialsSection
component remove the duplicate Tailwind utility by editing the className value
that currently contains "h-5 w-auto w-auto object-contain" so it only includes a
single "w-auto" (e.g., "h-5 w-auto object-contain"); locate the className on the
element in TestimonialsSection.tsx and delete the extra "w-auto".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/member-journey/page.tsx`:
- Around line 257-258: The semester stat is showing fractional values because
useAnimatedNumber(2, loading, 1200) emits intermediate decimals; when rendering
the value (e.g., semesterCount) convert it to an integer to avoid flicker — for
example apply Math.round (or Math.floor/Math.ceil as desired) to semesterCount
at render time in the hero and in the other occurrences noted (lines around
402-404) so the displayed value is always an integer while the animation still
runs.

In `@components/Footer.tsx`:
- Line 6: In components/Footer.tsx there is an extra space between the attribute
name and its opening quote in the JSX div (the line with className= "mx-auto
px-20 py-10"); remove the stray space so the attribute reads className="mx-auto
px-20 py-10" to match project style and consistency when rendering the Footer
component.

In `@components/TestimonialsSection.tsx`:
- Around line 12-13: The logos array type and render logic use a single
company-level alt (alt={item.company}) which is not descriptive for multiple
logos; update the logos type to logos?: { src: string; url?: string; alt?:
string }[] and change the rendering in the map (the code that renders each logo
image—referenced near the current logos prop and the JSX around lines noted
67-70) to use the per-logo alt field (alt={logo.alt ?? item.company ?? ''}) so
each image has a specific alt text with a sensible fallback to the company name
or empty string.

---

Outside diff comments:
In `@components/UpcomingEventsGrid.tsx`:
- Around line 98-116: The formattedDate computation in UpcomingEventsGrid (the
let formattedDate = 'Date unavailable' and its surrounding try/catch that reads
event.start_at, constructs eventDate, and calls console.error on error) is dead
now that the date badge was removed—delete the entire block (the formattedDate
declaration, the try { ... } catch { ... } and any console.error) and ensure no
other code references formattedDate or relies on that parsing; if any leftover
tests or variables reference formattedDate, remove or update them accordingly.

---

Nitpick comments:
In `@app/legal-notice/page.tsx`:
- Around line 1-17: The outer container in the LegalNoticePage component
includes the unnecessary "min-h-screen" utility (className="min-h-screen
bg-brand-dark-blue"); remove "min-h-screen" from that div's className so the
page relies on the root layout's <main className="flex-grow"> for height
handling, keeping the rest of the JSX and styling intact.

In `@app/members/page.tsx`:
- Line 8: The import for useAnimatedNumber in page.tsx is inconsistent with the
project's centralized exports; update the import to pull useAnimatedNumber from
the central hooks barrel (the same module other files use) so the component
references useAnimatedNumber from the shared export (e.g., replace the direct
"@/lib/useAnimatedNumber" import with the centralized "@/lib/hooks" export and
ensure the symbol useAnimatedNumber is exported from that barrel).

In `@app/privacy-policy/page.tsx`:
- Around line 1-17: The page uses a top-level "min-h-screen" which can cause
unwanted spacing similar to the Legal Notice page; remove or replace
"min-h-screen" from PrivacyPolicyPage's root div (or move the background class
"bg-brand-dark-blue" to a non-height-constraining wrapper) so the page doesn't
force full viewport height. Also extract the duplicated placeholder into a
shared component (e.g., PlaceholderPage with a title prop) and replace
PrivacyPolicyPage (and the Legal Notice page) to return <PlaceholderPage
title="PRIVACY POLICY" /> to avoid duplication and keep styling consistent.

In `@components/TestimonialsSection.tsx`:
- Line 70: In the TestimonialsSection component remove the duplicate Tailwind
utility by editing the className value that currently contains "h-5 w-auto
w-auto object-contain" so it only includes a single "w-auto" (e.g., "h-5 w-auto
object-contain"); locate the className on the element in TestimonialsSection.tsx
and delete the extra "w-auto".

In `@components/UpcomingEventsGrid.tsx`:
- Around line 152-157: In UpcomingEventsGrid component remove the commented-out
JSX block for the "View Details" link indicator (the commented div containing
the span "View Details" and the svg arrow) to clean up dead code; if the
functionality is required, instead implement it as a live element within the
component (e.g., re-add the div with appropriate classes and accessible
text/aria attributes) otherwise delete the entire commented block so version
control keeps history.
- Around line 38-40: In the UpcomingEventsGrid component remove the two debug
console.log statements that print 'Upcoming Events API Response:' and 'Number of
upcoming events:' (they reference the data variable and data.entries?.length);
delete those console.log(...) lines (or wrap them behind a dev-only check such
as process.env.NODE_ENV !== 'production' if you prefer preserving dev-time
logging) so API response details are not exposed in production.

In `@lib/hooks.ts`:
- Around line 13-30: Change the useInView hook to accept a generic element type
so it can be reused for non-div elements: update the function signature of
useInView to be generic (e.g., useInView<T extends HTMLElement =
HTMLDivElement>(threshold = 0.2)) and change the ref creation inside the
function from useRef<HTMLDivElement>(null) to useRef<T>(null); ensure any
references to the returned ref/visible from useInView still work with the new
generic type (no other logic changes required).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cd609d62-d68d-4b84-851e-6e11184485d5

📥 Commits

Reviewing files that changed from the base of the PR and between 5aa8a0c and db6afee.

⛔ Files ignored due to path filters (3)
  • public/memberJourney/alumni/FelixHaas.png is excluded by !**/*.png
  • public/memberJourney/alumni/JoshuaCornelius.png is excluded by !**/*.png
  • public/ourMembers/hero.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • app/events/page.tsx
  • app/home/page.tsx
  • app/layout.tsx
  • app/legal-notice/page.tsx
  • app/member-journey/page.tsx
  • app/members/page.tsx
  • app/privacy-policy/page.tsx
  • components/Footer.tsx
  • components/PastEventsGrid.tsx
  • components/TestimonialsSection.tsx
  • components/UpcomingEventsGrid.tsx
  • lib/hooks.ts
💤 Files with no reviewable changes (1)
  • components/PastEventsGrid.tsx

Comment thread app/member-journey/page.tsx Outdated
Comment on lines +257 to +258
const semesterCount = useAnimatedNumber(2, loading, 1200)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Render an integer for the semester stat to avoid decimal flicker.

useAnimatedNumber(2, ...) produces fractional intermediate values, so the hero currently shows decimals (e.g. 1.366...) during animation.

💡 Proposed fix
-  const semesterCount = useAnimatedNumber(2, loading, 1200)
+  const semesterCount = useAnimatedNumber(2, loading, 1200)
+  const displaySemesterCount = Math.round(semesterCount)
...
-                  {semesterCount}
+                  {displaySemesterCount}

Also applies to: 402-404

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/member-journey/page.tsx` around lines 257 - 258, The semester stat is
showing fractional values because useAnimatedNumber(2, loading, 1200) emits
intermediate decimals; when rendering the value (e.g., semesterCount) convert it
to an integer to avoid flicker — for example apply Math.round (or
Math.floor/Math.ceil as desired) to semesterCount at render time in the hero and
in the other occurrences noted (lines around 402-404) so the displayed value is
always an integer while the animation still runs.

Comment thread components/Footer.tsx
export default function Footer() {
return (
<footer className="bg-brand-dark-blue">
<div className= "mx-auto px-20 py-10">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor: Extra space in className attribute.

There's an extra space between className= and the opening quote. While this works, it's inconsistent with the codebase style.

Fix
-      <div className= "mx-auto px-20 py-10">
+      <div className="mx-auto px-20 py-10">
📝 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
<div className= "mx-auto px-20 py-10">
<div className="mx-auto px-20 py-10">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/Footer.tsx` at line 6, In components/Footer.tsx there is an extra
space between the attribute name and its opening quote in the JSX div (the line
with className= "mx-auto px-20 py-10"); remove the stray space so the attribute
reads className="mx-auto px-20 py-10" to match project style and consistency
when rendering the Footer component.

Comment on lines +12 to 13
logos?: { src: string; url?: string }[] // Optional logos with optional links
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use per-logo alt text instead of one company alt for all logos.

For multi-logo cards, repeated alt={item.company} is not descriptive and can be incorrect.

💡 Proposed fix
 export interface TestimonialItem {
@@
-    logos?: { src: string; url?: string }[] // Optional logos with optional links
+    logos?: { src: string; url?: string; alt?: string }[] // Optional logos with optional links
 }
@@
-                                                    alt={item.company}
+                                                    alt={logo.alt ?? `${item.company} logo ${index + 1}`}

Also applies to: 67-70

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/TestimonialsSection.tsx` around lines 12 - 13, The logos array
type and render logic use a single company-level alt (alt={item.company}) which
is not descriptive for multiple logos; update the logos type to logos?: { src:
string; url?: string; alt?: string }[] and change the rendering in the map (the
code that renders each logo image—referenced near the current logos prop and the
JSX around lines noted 67-70) to use the per-logo alt field (alt={logo.alt ??
item.company ?? ''}) so each image has a specific alt text with a sensible
fallback to the company name or empty string.

@SimonBurmer SimonBurmer merged commit 8619f4a into main Mar 24, 2026
3 checks passed
@SimonBurmer SimonBurmer deleted the fix-useAnimatedNumber branch March 25, 2026 17:52
This was referenced Apr 6, 2026
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.

1 participant