Skip to content

fix(baseball): stop infinite loading on Events when coach has zero teams (#444)#641

Merged
njrini99-code merged 1 commit into
mainfrom
fix/baseball-444-auto
Jul 3, 2026
Merged

fix(baseball): stop infinite loading on Events when coach has zero teams (#444)#641
njrini99-code merged 1 commit into
mainfrom
fix/baseball-444-auto

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

What & why

EventsClient initialized loading to true but only called fetchEvents() when teams.length > 0. A showcase coach with no teams never cleared loading, leaving the Events page stuck on a skeleton forever with a perpetual "Loading…" subtitle (broken empty state for new showcase orgs).

Fix

One-file guard in src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx. In the fetch effect, when auth is ready (authLoading === false) and teams.length === 0, reset events to [] and set loading false so the page falls through to the existing honest empty state. No new fetch, no other files touched.

Acceptance criteria

  • When auth is ready and teams.length === 0, set loading false and show the empty state.
  • No perpetual "Loading…" subtitle/header.

🤖 Generated with Claude Code

…444)

EventsClient initialized `loading` to true but only ran fetchEvents() when
teams.length > 0. A showcase coach with no teams never cleared loading, so the
Events page was stuck on a skeleton forever with a "Loading…" subtitle.

Add an else branch: when auth is ready (authLoading === false) and the coach
has no teams, reset events to [] and set loading false so the page falls
through to the existing honest empty state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017VUauUXsm9aXegShmpJi5n
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
helmv3 Ready Ready Preview, Comment Jul 1, 2026 4:57pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@njrini99-code, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 07830a4b-6858-4d1b-877a-c45ab3ec1504

📥 Commits

Reviewing files that changed from the base of the PR and between 53697b3 and 482bbdd.

📒 Files selected for processing (1)
  • src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/baseball-444-auto
  • 🛠️ helm safety pass
  • 🛠️ dashboard ux pass
  • 🛠️ rls test pass

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix Events infinite loading when coach has zero teams

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Clear Events skeleton when auth is ready but coach has no teams
• Fall through to the existing empty state instead of spinning on loading
Diagram

graph TD
  A["Events page UI"] --> B["EventsClient"] --> C["Auth + teams state"] --> D{"Has teams?"}
  D -- "yes" --> E["fetchEvents()"] --> F["Render events list"]
  D -- "no (auth ready)" --> G["Set events=[]; loading=false"] --> H["Render empty state"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Derive loading state instead of setting it
  • ➕ Avoids forgetting to clear loading in edge cases (single source of truth)
  • ➕ Simplifies mental model: loading = authLoading || (teams>0 && eventsLoading)
  • ➖ Requires a slightly larger refactor touching state shape and render conditions
  • ➖ Higher risk of unintended UI behavior changes vs a targeted guard
2. Always call fetchEvents and let it handle empty teams
  • ➕ Centralizes the empty-teams behavior inside the fetch function
  • ➕ Reduces branching in the effect
  • ➖ May still do unnecessary work or require API semantics for empty team sets
  • ➖ Could introduce accidental requests if the fetch code isn’t carefully guarded

Recommendation: Keep the PR’s current approach: the explicit !authLoading &amp;&amp; teams.length === 0 branch is the smallest, lowest-risk fix that directly addresses the stuck-skeleton bug without changing fetch semantics or broader state management.

Files changed (1) +6 / -0

Bug fix (1) +6 / -0
EventsClient.tsxClear loading and events when auth is ready but no teams exist +6/-0

Clear loading and events when auth is ready but no teams exist

• Adds an else-branch in the fetch effect to handle coaches with zero teams once auth has finished loading. When 'teams.length === 0' and 'authLoading' is false, it resets 'events' to an empty array and sets 'loading' false so the page renders the existing empty state instead of an infinite skeleton.

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 93 rules

Grey Divider


Remediation recommended

1. No memory doc update 📘 Rule violation ⚙ Maintainability
Description
This change alters user-visible behavior by clearing the Events loading skeleton when `teams.length
=== 0, but there is no corresponding update to memory/features/*` docs and no explicit comment
explaining why a doc update is unnecessary.
Code

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[R174-179]

+    } else if (!authLoading) {
+      // Auth is ready but the coach has no teams (e.g. a new showcase org):
+      // clear the skeleton and fall through to the honest empty state instead
+      // of spinning on `loading` forever.
+      setEvents([]);
+      setLoading(false);
Relevance

⭐⭐ Medium

Mixed history: memory doc/registry updates were requested and partially accepted (PR296), but
doc-pointer churn often rejected.

PR-#296
PR-#623

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checklist requires that business-behavior changes be reflected in memory/features/* or
explicitly justified in-code. The added branch changes the Events page flow (no longer stuck loading
when there are zero teams), and the existing Calendar/Events feature doc describes empty-state
behavior but does not cover this updated edge-case behavior.

Rule 1519257: Update memory feature docs when changing business behavior
src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[174-179]
memory/features/calendar-events.md[91-98]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A user-visible behavior change was made (coaches with zero teams now exit loading and see the empty state), but the `memory/features/*` documentation was not updated and there is no explicit in-code rationale for omitting a doc update.

## Issue Context
PR adds a new branch that sets `events` to `[]` and `loading` to `false` when auth is ready and `teams.length === 0`, changing what users see on the Events page.

## Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[174-179]
- memory/features/calendar-events.md[91-98]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Teams-loading misread as empty 🐞 Bug ≡ Correctness
Description
The new else if (!authLoading) branch sets loading false whenever teams.length === 0, even if
teams are still being fetched, so coaches with teams can briefly see the “No upcoming events” empty
state before teams arrive. This occurs because useTeams() loads teams asynchronously and exposes
isLoading, but EventsClient doesn’t gate the empty-teams path on it.
Code

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[R174-180]

+    } else if (!authLoading) {
+      // Auth is ready but the coach has no teams (e.g. a new showcase org):
+      // clear the skeleton and fall through to the honest empty state instead
+      // of spinning on `loading` forever.
+      setEvents([]);
+      setLoading(false);
    }
Relevance

⭐⭐ Medium

No clear historical evidence on gating empty-state UI on teamsLoading/isLoading for teams hooks in
this repo.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
EventsClient uses teams.length to decide whether to fetch or clear loading, but useTeams()
fetches teams asynchronously and starts with an empty teams array; therefore teams.length === 0
can be a transient loading state, not a real “no teams” state. Another component in the repo
explicitly checks teamsLoading before treating teamIds.length === 0 as a real empty state,
demonstrating the intended pattern.

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[102-181]
src/hooks/use-teams.ts[12-99]
src/stores/team-store.ts[27-44]
src/components/baseball/showcase/OrgDashboard.tsx[48-82]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`EventsClient` treats `teams.length === 0` as a final state once `authLoading` is false, but `useTeams()` begins with `teams=[]` and fetches teams asynchronously. This can show the empty state briefly for coaches who actually have teams.

### Issue Context
`useTeams()` already exposes `isLoading`, and other pages (e.g. OrgDashboard) use it to avoid falling through to an empty state before team data is loaded.

### Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[102-181]

### Suggested change
1. Read `isLoading` from `useTeams()`:
  - `const { teams, isLoading: teamsLoading } = useTeams();`
2. Update the effect to avoid the empty-teams branch while teams are still loading:
  - If `teamsLoading` is true, do nothing (keep skeleton / loading state).
  - Only when `!teamsLoading && !authLoading && teams.length === 0`, clear events and set `loading` false.
3. Add `teamsLoading` to the effect dependency array.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Stale fetchError on no-teams 🐞 Bug ☼ Reliability
Description
When teams.length === 0, the new branch sets events and loading but does not reset
fetchError, so an old fetch error banner can persist even though the UI is now in an expected
no-teams empty state. This can happen if a fetch previously failed and teams later becomes empty in
the same session.
Code

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[R174-180]

+    } else if (!authLoading) {
+      // Auth is ready but the coach has no teams (e.g. a new showcase org):
+      // clear the skeleton and fall through to the honest empty state instead
+      // of spinning on `loading` forever.
+      setEvents([]);
+      setLoading(false);
    }
Relevance

⭐⭐ Medium

Team often rejects extra error-state handling tweaks (e.g. PR564), but this is a small UI
correctness fix.

PR-#564

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
fetchError is displayed before the empty state and is only cleared inside fetchEvents() via
setFetchError(null). The new empty-teams branch bypasses fetchEvents() and does not clear
fetchError, so any previously-set error can remain visible.

src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[133-170]
src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[172-180]
src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[371-399]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `teams.length === 0` path sets `events=[]` and `loading=false` but leaves any previous `fetchError` intact, so the error banner can remain visible in an expected empty state.

### Issue Context
`fetchError` is rendered regardless of `loading`, and is only cleared inside `fetchEvents()`.

### Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[133-181]
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[371-399]

### Suggested change
In the `teams.length === 0` branch (and/or alongside the `setEvents([])` call), add `setFetchError(null)` so the UI doesn’t retain a stale error when no fetch is being performed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +174 to +179
} else if (!authLoading) {
// Auth is ready but the coach has no teams (e.g. a new showcase org):
// clear the skeleton and fall through to the honest empty state instead
// of spinning on `loading` forever.
setEvents([]);
setLoading(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. No memory doc update 📘 Rule violation ⚙ Maintainability

This change alters user-visible behavior by clearing the Events loading skeleton when `teams.length
=== 0, but there is no corresponding update to memory/features/*` docs and no explicit comment
explaining why a doc update is unnecessary.
Agent Prompt
## Issue description
A user-visible behavior change was made (coaches with zero teams now exit loading and see the empty state), but the `memory/features/*` documentation was not updated and there is no explicit in-code rationale for omitting a doc update.

## Issue Context
PR adds a new branch that sets `events` to `[]` and `loading` to `false` when auth is ready and `teams.length === 0`, changing what users see on the Events page.

## Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[174-179]
- memory/features/calendar-events.md[91-98]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +174 to 180
} else if (!authLoading) {
// Auth is ready but the coach has no teams (e.g. a new showcase org):
// clear the skeleton and fall through to the honest empty state instead
// of spinning on `loading` forever.
setEvents([]);
setLoading(false);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Teams-loading misread as empty 🐞 Bug ≡ Correctness

The new else if (!authLoading) branch sets loading false whenever teams.length === 0, even if
teams are still being fetched, so coaches with teams can briefly see the “No upcoming events” empty
state before teams arrive. This occurs because useTeams() loads teams asynchronously and exposes
isLoading, but EventsClient doesn’t gate the empty-teams path on it.
Agent Prompt
### Issue description
`EventsClient` treats `teams.length === 0` as a final state once `authLoading` is false, but `useTeams()` begins with `teams=[]` and fetches teams asynchronously. This can show the empty state briefly for coaches who actually have teams.

### Issue Context
`useTeams()` already exposes `isLoading`, and other pages (e.g. OrgDashboard) use it to avoid falling through to an empty state before team data is loaded.

### Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[102-181]

### Suggested change
1. Read `isLoading` from `useTeams()`:
   - `const { teams, isLoading: teamsLoading } = useTeams();`
2. Update the effect to avoid the empty-teams branch while teams are still loading:
   - If `teamsLoading` is true, do nothing (keep skeleton / loading state).
   - Only when `!teamsLoading && !authLoading && teams.length === 0`, clear events and set `loading` false.
3. Add `teamsLoading` to the effect dependency array.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +174 to 180
} else if (!authLoading) {
// Auth is ready but the coach has no teams (e.g. a new showcase org):
// clear the skeleton and fall through to the honest empty state instead
// of spinning on `loading` forever.
setEvents([]);
setLoading(false);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

3. Stale fetcherror on no-teams 🐞 Bug ☼ Reliability

When teams.length === 0, the new branch sets events and loading but does not reset
fetchError, so an old fetch error banner can persist even though the UI is now in an expected
no-teams empty state. This can happen if a fetch previously failed and teams later becomes empty in
the same session.
Agent Prompt
### Issue description
The `teams.length === 0` path sets `events=[]` and `loading=false` but leaves any previous `fetchError` intact, so the error banner can remain visible in an expected empty state.

### Issue Context
`fetchError` is rendered regardless of `loading`, and is only cleared inside `fetchEvents()`.

### Fix Focus Areas
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[133-181]
- src/app/baseball/(dashboard)/dashboard/events/EventsClient.tsx[371-399]

### Suggested change
In the `teams.length === 0` branch (and/or alongside the `setEvents([])` call), add `setFetchError(null)` so the UI doesn’t retain a stale error when no fetch is being performed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@njrini99-code

Copy link
Copy Markdown
Owner Author

🤖 Mission Control — PR summary

Changes: Clears the Events page loading state when a (showcase) coach has zero teams, so it shows the empty state instead of an infinite skeleton. Closes #444.
Areas / risk: BaseballHelm Events client — low risk (adds an else-branch to reset events=[] / loading=false once auth is ready and there are no teams).
Watch: Empty state renders; no regression for coaches who do have teams.
CI: ❌ Unit tests, Supabase lint + RLS tests, Playwright (chromium) failing — review before merge. (lighthouse-preview is the known chronic non-blocking check.)
Note: Also bundled into the single-deploy batch #650.

@njrini99-code njrini99-code merged commit f330316 into main Jul 3, 2026
31 of 38 checks passed
@njrini99-code njrini99-code deleted the fix/baseball-444-auto branch July 3, 2026 01:13
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