Skip to content

fix(baseball): mobile bottom-nav clipped at 320/390px on every coach route - #899

Merged
njrini99-code merged 1 commit into
mainfrom
fix/baseball-mobile-clip
Jul 17, 2026
Merged

fix(baseball): mobile bottom-nav clipped at 320/390px on every coach route#899
njrini99-code merged 1 commit into
mainfrom
fix/baseball-mobile-clip

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Found by tonight's cloud E2E sweep: every baseball coach route failed the mobile-viewport fit check with "Home" [left -2, right 66] vs viewport 320 — a standing regression on main (pre-dates #894; the 20:31 and 00:47 main-push runs both failed the same way).

Root cause: FairwayBottomNav's five flex-1 tab columns have the implicit flex min-width: auto floor and no min-w-0, so truncate never engages; the row's minimum content width exceeds 320/390px, and justify-around falls back to center on negative free space — shifting the first tab ("Home") 2px past the left viewport edge. One of five items (the "More" button) already carried min-w-0, which is how this slipped through.

Fix: min-w-0 on each destination li + Link (mirroring the More button). No structural changes.

Also improves the unhandledRejection handler's reporting (raw reason logged before Error synthesis; synthetic errors named UnhandledRejection with the original reason in Bridge metadata) so dev code frames stop pointing at instrumentation.ts.

Validation: typecheck + eslint clean; this PR's own Playwright run re-executes the failing mobile-viewports.spec.ts assertions in CI — that check going green is the proof.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MMdviLDsAg2YYJ8adsM6fg

…dRejection reporting

Every baseball coach route failed e2e mobile-viewport checks with
'"Home" [left -2]': FairwayBottomNav's five flex-1 tab columns lacked
min-w-0, so truncate never engaged, the row's content minimum exceeded
the viewport, and justify-around's negative-free-space fallback centered
the overflowing row — pushing the first tab 2px off-screen. Added
min-w-0 to each li and Link (the More button already had it, masking
the bug for one of five items).

Also: unhandledRejection handler now logs the raw reason before
synthesizing an Error (name 'UnhandledRejection', reason threaded into
Bridge metadata) so Next dev code frames stop blaming instrumentation.ts
for every non-Error rejection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMdviLDsAg2YYJ8adsM6fg
@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
helmv3 Ignored Ignored Preview Jul 17, 2026 4:17am

Request Review

@supabase

supabase Bot commented Jul 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project qmnssrrolpinvwjjnufo because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • Bug Fixes
    • Improved bottom navigation sizing so tab labels and the “More” option shrink and truncate correctly on smaller screens.
    • Enhanced error reporting for unhandled promise rejections, including clearer details when failures contain non-standard error values.

Walkthrough

The pull request updates bottom navigation flex sizing for constrained layouts and expands process-level unhandled rejection diagnostics with preserved non-Error rejection metadata.

Changes

Bottom navigation sizing

Layer / File(s) Summary
Tab column flex shrinking
src/components/fairway/app-shell/FairwayBottomNav.tsx:137-158,195
Destination and More tab wrappers now use min-w-0 flex-1, with inline documentation describing flex shrinking and label truncation.

Unhandled rejection diagnostics

Layer / File(s) Summary
Rejection logging context
src/instrumentation.ts:323-332,341-368
logProcessErrorToBridge accepts optional metadata, while non-Error unhandled rejections are logged with their raw reason, a named synthetic error, Sentry capture, and Bridge metadata.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 12
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and uses the required baseball scope while matching the bottom-nav fix.
Description check ✅ Passed The description is directly related to the navigation clipping and unhandledRejection changes in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Service-Role In Client Bundles ✅ Passed PASS: changed hunks in FairwayBottomNav.tsx:134-192 and instrumentation.ts:320-360 contain no SUPABASE_SERVICE_ROLE_KEY or service-role Supabase client creation.
Rls Coverage On New Tables ✅ Passed No migrations changed in HEAD; only src/components/fairway/app-shell/FairwayBottomNav.tsx and src/instrumentation.ts were modified, so the RLS check is not applicable.
Auth Check In Server Actions ✅ Passed PASS: HEAD changes only FairwayBottomNav.tsx and instrumentation.ts; no changed src/app//actions//*.ts files, so the auth check is not applicable.
Sport-Prefixed Table Names ✅ Passed PASS: changed TS/TSX files only touch nav markup and error logging; no .from() or Supabase table queries found in either file (FairwayBottomNav.tsx:137-211, instrumentation.ts:323-377).
No Destructive Writes ✅ Passed No changed save/submit/sync code exists; the only delete calls are request-scrubbing in instrumentation.ts:50-57, with no table DELETE→INSERT pattern.
No Edits To Historical Migrations ✅ Passed git diff --name-status shows only src/components/fairway/app-shell/FairwayBottomNav.tsx and src/instrumentation.ts; no supabase/migrations/ paths changed.
Conventional Commits ✅ Passed HEAD squash subject fix(baseball): mobile bottom-nav clip at 320/390px + clearer unhandledRejection reporting matches the required Conventional Commits regex.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/baseball-mobile-clip
  • 🛠️ helm safety pass
  • 🛠️ dashboard ux pass
  • 🛠️ rls test pass

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.1)

ast-grep could not parse rule config: /ast-grep-rules/../git/.coderabbit/ast-grep/no-explicit-any.yml

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/components/fairway/app-shell/FairwayBottomNav.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

src/instrumentation.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/instrumentation.ts`:
- Around line 359-368: Update the non-Error handling in the unhandled rejection
handler before Sentry.captureException: safely serialize object reasons with
circular-reference and BigInt handling so the synthetic Error message preserves
distinguishing details, attach the raw rejection reason to Sentry extra context,
and pass a sanitized, serializable metadata value to logProcessErrorToBridge
instead of the raw object. Preserve the existing Error-reason path and
UnhandledRejection naming.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 81658d7b-ecd7-4497-b7bb-69a1dbd46472

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb2595 and 9f053a4.

📒 Files selected for processing (2)
  • src/components/fairway/app-shell/FairwayBottomNav.tsx
  • src/instrumentation.ts

Comment thread src/instrumentation.ts
Comment on lines +359 to +368
console.error('[instrumentation] unhandledRejection: non-Error reason', reason);
error = new Error(`${String(reason)} (unhandled promise rejection with a non-Error reason)`);
error.name = 'UnhandledRejection';
}
Sentry.captureException(error);
logProcessErrorToBridge('process.unhandledRejection', error);
logProcessErrorToBridge(
'process.unhandledRejection',
error,
reason instanceof Error ? undefined : { reason }
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent Sentry grouping collapse and Bridge logging failures for object rejections.

When reason is an object, String(reason) evaluates to "[object Object]". Because the stack trace for this synthetic Error always points to this handler, Sentry will incorrectly group all non-Error object rejections into a single issue. Additionally, if the raw reason object contains circular references or BigInts (common in HTTP client rejections), JSON.parse(JSON.stringify(...)) inside logServerException's normalizeContext will synchronously throw, completely dropping the Bridge log.

Safely serialize the object for the error message to ensure distinct Sentry grouping, attach the raw object to Sentry's extra context, and ensure the metadata passed to Bridge is stripped of unserializable values.

🛠️ Proposed fix to safely serialize rejection reasons
       console.error('[instrumentation] unhandledRejection: non-Error reason', reason);
-      error = new Error(`${String(reason)} (unhandled promise rejection with a non-Error reason)`);
+      
+      let prefix = String(reason);
+      if (typeof reason === 'object' && reason !== null) {
+        try {
+          prefix = JSON.stringify(reason);
+        } catch {
+          prefix = '[Unserializable Object]';
+        }
+      }
+      
+      error = new Error(`${prefix} (unhandled promise rejection with a non-Error reason)`);
       error.name = 'UnhandledRejection';
     }
-    Sentry.captureException(error);
+    
+    Sentry.captureException(error, {
+      extra: reason instanceof Error ? undefined : { reason }
+    });
+
+    let safeMetadata: Record<string, unknown> | undefined;
+    if (!(reason instanceof Error)) {
+      try {
+        safeMetadata = { reason: JSON.parse(JSON.stringify(reason)) };
+      } catch {
+        safeMetadata = { reason: String(reason) };
+      }
+    }
+
     logProcessErrorToBridge(
       'process.unhandledRejection',
       error,
-      reason instanceof Error ? undefined : { reason }
+      safeMetadata
     );
📝 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.error('[instrumentation] unhandledRejection: non-Error reason', reason);
error = new Error(`${String(reason)} (unhandled promise rejection with a non-Error reason)`);
error.name = 'UnhandledRejection';
}
Sentry.captureException(error);
logProcessErrorToBridge('process.unhandledRejection', error);
logProcessErrorToBridge(
'process.unhandledRejection',
error,
reason instanceof Error ? undefined : { reason }
);
console.error('[instrumentation] unhandledRejection: non-Error reason', reason);
let prefix = String(reason);
if (typeof reason === 'object' && reason !== null) {
try {
prefix = JSON.stringify(reason);
} catch {
prefix = '[Unserializable Object]';
}
}
error = new Error(`${prefix} (unhandled promise rejection with a non-Error reason)`);
error.name = 'UnhandledRejection';
}
Sentry.captureException(error, {
extra: reason instanceof Error ? undefined : { reason }
});
let safeMetadata: Record<string, unknown> | undefined;
if (!(reason instanceof Error)) {
try {
safeMetadata = { reason: JSON.parse(JSON.stringify(reason)) };
} catch {
safeMetadata = { reason: String(reason) };
}
}
logProcessErrorToBridge(
'process.unhandledRejection',
error,
safeMetadata
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/instrumentation.ts` around lines 359 - 368, Update the non-Error handling
in the unhandled rejection handler before Sentry.captureException: safely
serialize object reasons with circular-reference and BigInt handling so the
synthetic Error message preserves distinguishing details, attach the raw
rejection reason to Sentry extra context, and pass a sanitized, serializable
metadata value to logProcessErrorToBridge instead of the raw object. Preserve
the existing Error-reason path and UnhandledRejection naming.

@njrini99-code

Copy link
Copy Markdown
Owner Author

🤖 Mission Control — PR summary

What it changes

  • FairwayBottomNav: adds min-w-0 to each of the five tab <li>/<Link> columns so truncate finally engages. Fixes every baseball coach route failing the e2e mobile-viewport check (the first "Home" tab was pushed ~2px off-screen at 320/390px because the flex row's content-minimum exceeded the viewport and justify-around's negative-free-space fallback centered the overflow).
  • Instrumentation: the unhandledRejection handler now logs the raw reason before synthesizing an Error (name UnhandledRejection, reason threaded into Bridge metadata), so Next dev code-frames stop blaming instrumentation.ts for every non-Error rejection.

Risk / areas

  • Baseball mobile bottom nav (all coach routes) — layout-only change, low risk.
  • Global error instrumentation / Helm Bridge grouping — the reason-logging change touches how rejections are reported.

Reviewers should watch

  • No truncation regression at wider breakpoints (tablet/desktop tab row).
  • Bridge error fingerprint / metadata shape for unhandled rejections stays backward-compatible.

CI: all required checks green — TypeScript, ESLint, unit, Next build, Supabase RLS, Playwright a11y smoke, semgrep/ast-grep, CodeQL. ✅ (BLOCKED state is awaiting the required human review, not a CI failure.)

@njrini99-code
njrini99-code merged commit e7900b0 into main Jul 17, 2026
43 checks passed
@njrini99-code
njrini99-code deleted the fix/baseball-mobile-clip branch July 17, 2026 10:36
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