Skip to content

Ft member#21

Merged
SimonBurmer merged 5 commits intomainfrom
ft_member
Mar 27, 2026
Merged

Ft member#21
SimonBurmer merged 5 commits intomainfrom
ft_member

Conversation

@GAL1LAO
Copy link
Copy Markdown
Contributor

@GAL1LAO GAL1LAO commented Mar 27, 2026

Member website - First version merge

Summary by CodeRabbit

  • New Features

    • Added board member information display
    • Enabled dynamic batch member lookups with async loading
    • Enhanced profile image handling with fallback initials
  • Improvements

    • Updated member card rendering with improved image support
    • Added loading indicators for batch member fetching
    • Improved fallback image selection and display logic

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 27, 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 27, 2026 8:44am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

This pull request adds two new API route handlers for fetching board and batch member data from an external API, then integrates them into the members page with state management, data transformation logic, and updated UI rendering for displaying batch and board members.

Changes

Cohort / File(s) Summary
Board API Endpoint
app/api/board/route.ts
New GET endpoint that proxies board data from external Startmunich API with optional termStartYears query parameter, bearer token authentication, and error handling.
Batch Members API Endpoint
app/api/members/batch/[batchId]/route.ts
New GET endpoint that normalizes batch identifiers (semester/year formats), fetches members from external API, transforms them into strongly-typed Member objects with role mapping and image URL normalization, and returns mock fallback data on errors.
Members Page Integration
app/members/page.tsx
Extended Member/BoardMember types with profileImage field; added batch and board loading state; implemented async data fetching for both /api/members/batch/:id and /api/board endpoints; added member transformation, role-based normalization, and batch image mapping; reworked analytics to use fixed values; updated card rendering to use fetched profile images with initials fallbacks.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MembersPage as Members Page
    participant BoardAPI as /api/board
    participant BatchAPI as /api/members/batch
    participant ExternalAPI as External API

    User->>MembersPage: Page loads / Expand Board
    MembersPage->>BoardAPI: GET /api/board?termStartYears=...
    BoardAPI->>ExternalAPI: Fetch board data
    ExternalAPI-->>BoardAPI: Board JSON response
    BoardAPI->>BoardAPI: Parse & transform to Members
    BoardAPI-->>MembersPage: Member list JSON
    MembersPage->>MembersPage: Normalize roles, match by alias, update state
    MembersPage->>User: Render board member cards

    User->>MembersPage: Expand batch
    MembersPage->>BatchAPI: GET /api/members/batch/[batchId]
    BatchAPI->>ExternalAPI: Fetch members for batch
    ExternalAPI-->>BatchAPI: Members JSON response
    BatchAPI->>BatchAPI: Transform to typed Members
    BatchAPI->>BatchAPI: Normalize image URLs
    BatchAPI-->>MembersPage: Member array JSON
    MembersPage->>MembersPage: Set batchMembers state
    MembersPage->>User: Render batch member grid
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 New routes spring forth like carrots in spring,
Board and batch members in data they bring,
From external API we fetch and transform,
With images and roles, the members take form,
Profile pictures nestled and initials so neat,
The members page now is remarkably sweet! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Ft member' is vague and does not clearly summarize the main changes; it lacks specificity about what 'Ft' means and provides minimal information about the substantial work (new API routes, member display logic, board data integration). Revise the title to be more descriptive and specific, e.g., 'Add member website with batch/board API integration and profile display' or 'Implement member listing with batch member fetching and board data integration'.
✅ 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 ft_member

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

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: 6

🧹 Nitpick comments (4)
app/members/page.tsx (2)

905-913: Inconsistent fallback rendering in advisory board vs main board.

The advisory board section renders an empty <div> when profileImage is missing (line 912), while the main board section (lines 798-800) displays initials. Although showAdvisoryBoard is currently false, this inconsistency should be addressed for future use.

Proposed fix for consistency
                                {member.profileImage ? (
                                  <img
                                    src={member.profileImage}
                                    alt={member.name}
                                    className="w-full h-64 object-cover"
                                  />
                                ) : (
-                                  <div className="w-full h-64 bg-[`#00002c`]" />
+                                  <div className="w-full h-64 flex items-center justify-center bg-[`#00002c`] text-white text-4xl font-black">
+                                    {getInitials(member.name)}
+                                  </div>
                                )}

Apply similar fix to lines 940-942.

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

In `@app/members/page.tsx` around lines 905 - 913, The advisory board card
currently uses an empty <div> when member.profileImage is missing; update the
JSX that checks member.profileImage (the block rendering the empty div) to
render the same initials fallback used in the main board instead of the empty
div — compute initials from member.name and render the same styled
element/classNames used for the main board initials so both boards are
consistent (also apply this same change to the similar fallback at the other
advisory-board location referenced around the later check for profileImage).

345-353: Sequential board loading could be parallelized.

The loadAllBoards function awaits each board sequentially. With only 2 boards this is negligible, but for scalability consider using Promise.all.

Parallel loading
   useEffect(() => {
     const loadAllBoards = async () => {
-      for (const board of boards) {
-        await loadBoardMembers(board.id)
-      }
+      await Promise.all(boards.map(board => loadBoardMembers(board.id)))
     }

     void loadAllBoards()
   }, [])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/members/page.tsx` around lines 345 - 353, The current loadAllBoards
function inside the useEffect is awaiting each board sequentially; change it to
run in parallel by replacing the for-loop with a Promise.all over
boards.map(board => loadBoardMembers(board.id)) and await that Promise.all,
ensuring this change is made inside the same useEffect and referencing
loadAllBoards, loadBoardMembers, boards and useEffect; also consider whether
boards should be added to the effect dependency array if boards can change.
app/api/members/batch/[batchId]/route.ts (2)

91-96: Logic gap: code continues to transform empty dataMembers when fallback is also empty.

When dataMembers is empty and fallbackMembers also has zero length, the code falls through to the transformation at line 164, which will return an empty array. This is fine but the conditional structure is confusing. If fallbackMembers is empty, perhaps return early with [] or let it continue explicitly.

Suggested clarification
     if (!Array.isArray(dataMembers) || dataMembers.length === 0) {
       const fallbackMembers = getMembersByBatch(batchId)
-      if (fallbackMembers.length > 0) {
-        return NextResponse.json(fallbackMembers)
-      }
+      // Always return fallback when API returns no data
+      return NextResponse.json(fallbackMembers)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/members/batch/`[batchId]/route.ts around lines 91 - 96, The branch
that handles an empty or non-array dataMembers calls getMembersByBatch(batchId)
and returns fallbackMembers only if non-empty, otherwise it falls through to the
later transformation causing confusing control flow; change the if-block so that
when Array.isArray(dataMembers) is false or dataMembers.length === 0 you call
getMembersByBatch(batchId) and if fallbackMembers.length > 0 return
NextResponse.json(fallbackMembers) else return NextResponse.json([]) immediately
(i.e., return early) instead of letting execution continue to the transformation
logic that maps members.

182-185: Inconsistent error handling: catch returns empty array while non-OK response returns fallback.

When the upstream responds with a non-2xx status (line 82-83), fallback data is returned. However, when an exception occurs (e.g., network error, JSON parse failure), an empty array is returned. Consider returning fallback data here as well for consistency.

Proposed fix
   } catch (error) {
     console.error('Error fetching batch members:', error)
-    // Return empty array on error
-    return NextResponse.json([])
+    // Fallback to mock members on error
+    const fallbackMembers = getMembersByBatch(batchId)
+    return NextResponse.json(fallbackMembers)
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/members/batch/`[batchId]/route.ts around lines 182 - 185, The catch
block in app/api/members/batch/[batchId]/route.ts currently returns
NextResponse.json([]) on exceptions; change it to return the same fallback
response used in the non-OK response branch so both error paths are consistent.
Locate the catch that logs "Error fetching batch members" and replace the
empty-array response with the same fallback variable or construct used in the
earlier response.ok check (i.e., return the identical NextResponse.json(...)
payload that the non-2xx branch returns). Ensure you keep the console.error
logging but unify the returned payload across both the response.ok false branch
and the catch block.
🤖 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/api/board/route.ts`:
- Line 9: The code currently sets const API_KEY =
process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER', which masks
missing configuration; change this to fail fast by checking
process.env.STARTMUNICH_API_KEY and either throw an Error or log a clear error
and return a 5xx response during initialization/use instead of using the
placeholder. Locate the API_KEY constant and replace the fallback behavior with
an explicit check that raises an exception (or logs and halts request handling)
when STARTMUNICH_API_KEY is absent so consumers cannot proceed with the
placeholder value.

In `@app/api/members/batch/`[batchId]/route.ts:
- Line 66: Remove the hardcoded fallback API key by not assigning
'YOUR_API_KEY_PLACEHOLDER' to API_KEY; instead read
process.env.STARTMUNICH_API_KEY into API_KEY and validate it at the start of the
route handler (the GET/POST export in app/api/members/batch/[batchId]/route.ts).
If API_KEY is missing or empty, return an appropriate HTTP error response (e.g.,
401/500 with a clear message) before making any downstream requests, and ensure
any logs reference API_KEY absence for easier debugging.
- Line 172: The object construction for linkedinUrl contains a duplicate access
to member.linkedinUrl; remove the redundant final `member.linkedinUrl` and keep
a clear fallback chain (e.g., assign linkedinUrl using member.linkedinUrl ||
member.linkedin || member.linkedin_profile || null) so the value resolution is
correct and not repeated; update the expression in the code that builds the
member object (the property labeled linkedinUrl) accordingly.

In `@app/members/page.tsx`:
- Around line 120-130: Remove the temporary debug console.log calls in
app/members/page.tsx that inspect the API response and image URLs (the logs
around "API Response data:", "First member imageUrl:", "Checking if
placeholder:", and "Transformed data:"); keep the transformation logic that maps
Member to add profileImage using isPlaceholderImage but delete the console.log
statements so only the const transformedData = data.map((member: Member) => ({
... })) and related production code remain.
- Around line 1036-1039: The anchor currently uses href="#" when
member.linkedinUrl is missing, causing page scroll-to-top; update the JSX around
the element that uses member.linkedinUrl so you conditionally render a real <a>
when member.linkedinUrl is truthy and render a non-anchor element (e.g., <div>
or <span>) with the exact same classes/structure when falsy, preserving
cursor/default styles and accessibility (role/aria-disabled if needed), or
alternatively attach an onClick that calls event.preventDefault() when rendering
the anchor without a real URL; target symbols to change: the JSX element that
sets href={member.linkedinUrl || '#'} and the conditional use of
member.linkedinUrl for target/rel/className.
- Around line 339-353: The first useEffect that calls loadBoardMembers should
include boards in its dependency array to avoid a stale closure—change its
dependencies to [expandedBoard, boards]; the second useEffect that defines
loadAllBoards currently has an empty dependency array but references boards, so
either document the intent to run only once or change its dependency to [boards]
so it re-runs when boards updates (the symbols to modify are loadAllBoards,
loadBoardMembers and the useEffect wrappers); finally remove the temporary debug
console.log statements scattered in this file (the debug logs that were added
around earlier board loading logic) before merging.

---

Nitpick comments:
In `@app/api/members/batch/`[batchId]/route.ts:
- Around line 91-96: The branch that handles an empty or non-array dataMembers
calls getMembersByBatch(batchId) and returns fallbackMembers only if non-empty,
otherwise it falls through to the later transformation causing confusing control
flow; change the if-block so that when Array.isArray(dataMembers) is false or
dataMembers.length === 0 you call getMembersByBatch(batchId) and if
fallbackMembers.length > 0 return NextResponse.json(fallbackMembers) else return
NextResponse.json([]) immediately (i.e., return early) instead of letting
execution continue to the transformation logic that maps members.
- Around line 182-185: The catch block in
app/api/members/batch/[batchId]/route.ts currently returns NextResponse.json([])
on exceptions; change it to return the same fallback response used in the non-OK
response branch so both error paths are consistent. Locate the catch that logs
"Error fetching batch members" and replace the empty-array response with the
same fallback variable or construct used in the earlier response.ok check (i.e.,
return the identical NextResponse.json(...) payload that the non-2xx branch
returns). Ensure you keep the console.error logging but unify the returned
payload across both the response.ok false branch and the catch block.

In `@app/members/page.tsx`:
- Around line 905-913: The advisory board card currently uses an empty <div>
when member.profileImage is missing; update the JSX that checks
member.profileImage (the block rendering the empty div) to render the same
initials fallback used in the main board instead of the empty div — compute
initials from member.name and render the same styled element/classNames used for
the main board initials so both boards are consistent (also apply this same
change to the similar fallback at the other advisory-board location referenced
around the later check for profileImage).
- Around line 345-353: The current loadAllBoards function inside the useEffect
is awaiting each board sequentially; change it to run in parallel by replacing
the for-loop with a Promise.all over boards.map(board =>
loadBoardMembers(board.id)) and await that Promise.all, ensuring this change is
made inside the same useEffect and referencing loadAllBoards, loadBoardMembers,
boards and useEffect; also consider whether boards should be added to the effect
dependency array if boards can change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c38041fa-f029-44fc-9e8d-38e8fe3bd175

📥 Commits

Reviewing files that changed from the base of the PR and between 511d533 and c8a362f.

⛔ Files ignored due to path filters (9)
  • public/images/batches_group_pictures/SS22.jpg is excluded by !**/*.jpg
  • public/images/batches_group_pictures/SS23.JPG is excluded by !**/*.jpg
  • public/images/batches_group_pictures/SS24.jpg is excluded by !**/*.jpg
  • public/images/batches_group_pictures/SS25.jpg is excluded by !**/*.jpg
  • public/images/batches_group_pictures/WS21.jpg is excluded by !**/*.jpg
  • public/images/batches_group_pictures/WS22.jpg is excluded by !**/*.jpg
  • public/images/batches_group_pictures/WS23.JPG is excluded by !**/*.jpg
  • public/images/batches_group_pictures/WS24.JPG is excluded by !**/*.jpg
  • public/images/batches_group_pictures/WS25.JPG is excluded by !**/*.jpg
📒 Files selected for processing (3)
  • app/api/board/route.ts
  • app/api/members/batch/[batchId]/route.ts
  • app/members/page.tsx

Comment thread app/api/board/route.ts
const url = new URL(request.url)
const termStartYears = url.searchParams.get('termStartYears') || '2024,2025'

const API_KEY = process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER'
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

API key fallback masks configuration errors and may leak placeholder.

If STARTMUNICH_API_KEY is not set, requests proceed with 'YOUR_API_KEY_PLACEHOLDER' which will fail at the upstream API. This silently hides a configuration issue. Consider failing fast or logging a warning when the key is missing.

Proposed fix
-  const API_KEY = process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER'
+  const API_KEY = process.env.STARTMUNICH_API_KEY
+  if (!API_KEY) {
+    console.error('STARTMUNICH_API_KEY environment variable is not set')
+    return NextResponse.json({ error: 'Server configuration error' }, { status: 500 })
+  }
📝 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
const API_KEY = process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER'
const API_KEY = process.env.STARTMUNICH_API_KEY
if (!API_KEY) {
console.error('STARTMUNICH_API_KEY environment variable is not set')
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 })
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/board/route.ts` at line 9, The code currently sets const API_KEY =
process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER', which masks
missing configuration; change this to fail fast by checking
process.env.STARTMUNICH_API_KEY and either throw an Error or log a clear error
and return a 5xx response during initialization/use instead of using the
placeholder. Locate the API_KEY constant and replace the fallback behavior with
an explicit check that raises an exception (or logs and halts request handling)
when STARTMUNICH_API_KEY is absent so consumers cannot proceed with the
placeholder value.


const apiBatch = resolveApiBatch(batchId)

const API_KEY = process.env.STARTMUNICH_API_KEY || 'YOUR_API_KEY_PLACEHOLDER'
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

Same API key fallback issue as the board route.

Consider validating the presence of the API key and returning an appropriate error, similar to the suggestion for app/api/board/route.ts.

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

In `@app/api/members/batch/`[batchId]/route.ts at line 66, Remove the hardcoded
fallback API key by not assigning 'YOUR_API_KEY_PLACEHOLDER' to API_KEY; instead
read process.env.STARTMUNICH_API_KEY into API_KEY and validate it at the start
of the route handler (the GET/POST export in
app/api/members/batch/[batchId]/route.ts). If API_KEY is missing or empty,
return an appropriate HTTP error response (e.g., 401/500 with a clear message)
before making any downstream requests, and ensure any logs reference API_KEY
absence for easier debugging.

study: member.study || member.field || member.degree,
university: member.university || member.school,
company: member.company || member.employer,
linkedinUrl: member.linkedinUrl || member.linkedin || member.linkedin_profile || member.linkedinUrl || null,
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

Duplicate field access: member.linkedinUrl appears twice.

This looks like a copy-paste oversight. The second member.linkedinUrl at the end is redundant.

Proposed fix
-      linkedinUrl: member.linkedinUrl || member.linkedin || member.linkedin_profile || member.linkedinUrl || null,
+      linkedinUrl: member.linkedinUrl || member.linkedin || member.linkedin_profile || null,
📝 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
linkedinUrl: member.linkedinUrl || member.linkedin || member.linkedin_profile || member.linkedinUrl || null,
linkedinUrl: member.linkedinUrl || member.linkedin || member.linkedin_profile || null,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/members/batch/`[batchId]/route.ts at line 172, The object
construction for linkedinUrl contains a duplicate access to member.linkedinUrl;
remove the redundant final `member.linkedinUrl` and keep a clear fallback chain
(e.g., assign linkedinUrl using member.linkedinUrl || member.linkedin ||
member.linkedin_profile || null) so the value resolution is correct and not
repeated; update the expression in the code that builds the member object (the
property labeled linkedinUrl) accordingly.

Comment thread app/members/page.tsx
Comment on lines +120 to +130
console.log('API Response data:', data)
if (Array.isArray(data) && data.length > 0) {
// Log first few members to check imageUrl
console.log('First member imageUrl:', data[0]?.imageUrl)
console.log('Checking if placeholder:', isPlaceholderImage(data[0]?.imageUrl))
// Transform API response to add profileImage field (clean up placeholder images)
const transformedData = data.map((member: Member) => ({
...member,
profileImage: isPlaceholderImage(member.imageUrl) ? undefined : member.imageUrl
}))
console.log('Transformed data:', transformedData)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove debug console.log statements before merging.

Multiple console.log calls for debugging API responses and image URLs should be removed for production code.

Proposed fix
           if (Array.isArray(data) && data.length > 0) {
-              // Log first few members to check imageUrl
-              console.log('First member imageUrl:', data[0]?.imageUrl)
-              console.log('Checking if placeholder:', isPlaceholderImage(data[0]?.imageUrl))
               // Transform API response to add profileImage field (clean up placeholder images)
               const transformedData = data.map((member: Member) => ({
                 ...member,
                 profileImage: isPlaceholderImage(member.imageUrl) ? undefined : member.imageUrl
               }))
-              console.log('Transformed data:', transformedData)
               setBatchMembers(transformedData)

Also remove line 120:

-            console.log('API Response data:', data)
📝 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
console.log('API Response data:', data)
if (Array.isArray(data) && data.length > 0) {
// Log first few members to check imageUrl
console.log('First member imageUrl:', data[0]?.imageUrl)
console.log('Checking if placeholder:', isPlaceholderImage(data[0]?.imageUrl))
// Transform API response to add profileImage field (clean up placeholder images)
const transformedData = data.map((member: Member) => ({
...member,
profileImage: isPlaceholderImage(member.imageUrl) ? undefined : member.imageUrl
}))
console.log('Transformed data:', transformedData)
if (Array.isArray(data) && data.length > 0) {
// Transform API response to add profileImage field (clean up placeholder images)
const transformedData = data.map((member: Member) => ({
...member,
profileImage: isPlaceholderImage(member.imageUrl) ? undefined : member.imageUrl
}))
setBatchMembers(transformedData)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/members/page.tsx` around lines 120 - 130, Remove the temporary debug
console.log calls in app/members/page.tsx that inspect the API response and
image URLs (the logs around "API Response data:", "First member imageUrl:",
"Checking if placeholder:", and "Transformed data:"); keep the transformation
logic that maps Member to add profileImage using isPlaceholderImage but delete
the console.log statements so only the const transformedData = data.map((member:
Member) => ({ ... })) and related production code remain.

Comment thread app/members/page.tsx
Comment on lines +339 to +353
useEffect(() => {
if (expandedBoard) {
loadBoardMembers(expandedBoard)
}
}, [expandedBoard])

useEffect(() => {
const loadAllBoards = async () => {
for (const board of boards) {
await loadBoardMembers(board.id)
}
}

void loadAllBoards()
}, [])
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there are eslint rules for exhaustive-deps that might catch this
fd -e json -e js "eslint" --max-depth 2 --exec cat {} 2>/dev/null | grep -i "exhaustive-deps" || echo "No eslint config found or rule not configured"

Repository: startmunich/website-special-pages

Length of output: 122


🏁 Script executed:

#!/bin/bash
# Get the full context around lines 339-360 and the loadBoardMembers function
wc -l app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 102


🏁 Script executed:

#!/bin/bash
# Read the problematic section
sed -n '330,365p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 954


🏁 Script executed:

#!/bin/bash
# Find the loadBoardMembers function definition
rg -n "loadBoardMembers" app/members/page.tsx | head -20

Repository: startmunich/website-special-pages

Length of output: 223


🏁 Script executed:

#!/bin/bash
# Get the loadBoardMembers function implementation (lines 239+)
sed -n '239,320p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 2897


🏁 Script executed:

#!/bin/bash
# Check the context around the loadBoardMembers function to see if it's declared before or after boards state
sed -n '235,242p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 247


🏁 Script executed:

#!/bin/bash
# Check where setBoards is called to see if boards state changes after initial load
rg -n "setBoards" app/members/page.tsx | head -10

Repository: startmunich/website-special-pages

Length of output: 186


🏁 Script executed:

#!/bin/bash
# Get broader context around the board initialization and effects
sed -n '60,75p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 701


🏁 Script executed:

#!/bin/bash
# Check how many times setBoards is called and in what context
rg -B 2 -A 2 "setBoards" app/members/page.tsx | head -40

Repository: startmunich/website-special-pages

Length of output: 334


🏁 Script executed:

#!/bin/bash
# Check for console.log statements in the file
rg -n "console\.(log|warn|error)" app/members/page.tsx | grep -v "console.warn\|console.error"

Repository: startmunich/website-special-pages

Length of output: 372


🏁 Script executed:

#!/bin/bash
# Check lines around 120-124, 130 mentioned in scratchpad for console.log
sed -n '115,135p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 1227


🏁 Script executed:

#!/bin/bash
# Verify the dependency array issue by checking if boards state could change
# Look for scenarios where boards is updated and expandedBoard might also be active
rg -n "setExpandedBoard" app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 413


🏁 Script executed:

#!/bin/bash
# Check the entire useEffect blocks and their full context
sed -n '337,360p' app/members/page.tsx

Repository: startmunich/website-special-pages

Length of output: 538


Add missing dependencies to useEffect hooks and remove debug logs.

The first useEffect (lines 339-344) calls loadBoardMembers, which reads from the boards state via closure. Since boards can change (updated at line 305), missing boards from the dependency array creates a stale closure—when expandedBoard changes after boards has been updated, the effect will use an outdated reference. Add boards to the dependency array: [expandedBoard, boards].

The second useEffect (lines 345-353) has empty dependencies [] but references boards through loadAllBoards. This is less critical if the intent is to load all boards only once on mount, but the pattern is fragile and should be documented or adjusted to [boards] if subsequent board updates should trigger reloads.

Additionally, remove the debug console.log statements at lines 120, 123, 124, and 130 before merging.

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

In `@app/members/page.tsx` around lines 339 - 353, The first useEffect that calls
loadBoardMembers should include boards in its dependency array to avoid a stale
closure—change its dependencies to [expandedBoard, boards]; the second useEffect
that defines loadAllBoards currently has an empty dependency array but
references boards, so either document the intent to run only once or change its
dependency to [boards] so it re-runs when boards updates (the symbols to modify
are loadAllBoards, loadBoardMembers and the useEffect wrappers); finally remove
the temporary debug console.log statements scattered in this file (the debug
logs that were added around earlier board loading logic) before merging.

Comment thread app/members/page.tsx
Comment on lines +1036 to +1039
href={member.linkedinUrl || '#'}
target={member.linkedinUrl ? "_blank" : undefined}
rel={member.linkedinUrl ? "noopener noreferrer" : undefined}
className={`group relative overflow-hidden transition-all duration-300 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-[#d0006f] rounded-lg hover:scale-105 ${member.linkedinUrl ? 'cursor-pointer' : 'cursor-default'} z-10 aspect-square`}
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

Anchor with href="#" scrolls to top when linkedinUrl is missing.

When member.linkedinUrl is falsy, the anchor gets href="#" which causes the page to scroll to top on click. Consider using a <div> or <span> for non-linked members, or use event.preventDefault().

Proposed fix using conditional rendering
-                          {batchMembers.map((member) => (
-                            <a
-                              key={member.id}
-                              href={member.linkedinUrl || '#'}
-                              target={member.linkedinUrl ? "_blank" : undefined}
-                              rel={member.linkedinUrl ? "noopener noreferrer" : undefined}
-                              className={`group relative overflow-hidden transition-all duration-300 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-[`#d0006f`] rounded-lg hover:scale-105 ${member.linkedinUrl ? 'cursor-pointer' : 'cursor-default'} z-10 aspect-square`}
-                            >
+                          {batchMembers.map((member) => {
+                            const CardWrapper = member.linkedinUrl ? 'a' : 'div'
+                            const linkProps = member.linkedinUrl
+                              ? { href: member.linkedinUrl, target: "_blank", rel: "noopener noreferrer" }
+                              : {}
+                            return (
+                              <CardWrapper
+                                key={member.id}
+                                {...linkProps}
+                                className={`group relative overflow-hidden transition-all duration-300 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-[`#d0006f`] rounded-lg hover:scale-105 ${member.linkedinUrl ? 'cursor-pointer' : 'cursor-default'} z-10 aspect-square`}
+                              >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/members/page.tsx` around lines 1036 - 1039, The anchor currently uses
href="#" when member.linkedinUrl is missing, causing page scroll-to-top; update
the JSX around the element that uses member.linkedinUrl so you conditionally
render a real <a> when member.linkedinUrl is truthy and render a non-anchor
element (e.g., <div> or <span>) with the exact same classes/structure when
falsy, preserving cursor/default styles and accessibility (role/aria-disabled if
needed), or alternatively attach an onClick that calls event.preventDefault()
when rendering the anchor without a real URL; target symbols to change: the JSX
element that sets href={member.linkedinUrl || '#'} and the conditional use of
member.linkedinUrl for target/rel/className.

@SimonBurmer SimonBurmer merged commit f656ed2 into main Mar 27, 2026
3 checks passed
This was referenced Mar 28, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 5, 2026
Merged
@SimonBurmer SimonBurmer deleted the ft_member branch April 20, 2026 22:08
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.

2 participants