Skip to content

Add mobile case workspace routes - #191

Merged
monicafernii97-cmd merged 3 commits into
mainfrom
codex/mobile-workspace-route
Jul 1, 2026
Merged

monicafernii97-cmd merged 3 commits into
mainfrom
codex/mobile-workspace-route

Conversation

@monicafernii97-cmd

@monicafernii97-cmd monicafernii97-cmd commented Jun 30, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • adds /case/[caseId]/workspace mobile route
  • adds full mobile key facts, timeline, and summary routes
  • adds mobile case workspace sections in the contract order: snapshot, facts carousel, timeline snapshot, observed patterns, narrative preview, sticky Generate Report CTA
  • adds typed mobile workspace data adapter for this route skeleton
  • updates the mobile contract checklist for Phase 2 progress

Validation

  • npx.cmd eslint src/components/case-mobile src/app/case src/lib/mobile/caseWorkspaceData.ts
  • npx.cmd tsc --noEmit
  • NEXT_PUBLIC_CONVEX_URL=https://placeholder.convex.cloud npm.cmd run build

Notes

  • Local Playwright route hydration could not complete without valid Clerk credentials. The route compiles and builds, and Vercel preview will run with project env.
  • CodeRabbit CLI remains blocked locally because the installed command depends on WSL and this machine has no WSL distribution installed; relying on GitHub CodeRabbit review for this PR.

Summary by CodeRabbit

  • New Features
    • Added mobile-first case workspace views for workspace, Key Facts, timeline, and summary, each with its own mobile layout.
    • Introduced mobile UI components including a case snapshot card, facts carousel/list, timeline with filter chips, observed patterns, narrative preview, and a full summary screen.
    • Added mobile navigation controls (top bar with drawer, workspace actions bottom sheet) and a sticky “Generate Report” button.
  • Chores
    • Updated the mobile interaction contract checklist to mark implemented Phase 2 items as completed.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b6f9b58-5d57-4b2c-a8ec-7d12186edfed

📥 Commits

Reviewing files that changed from the base of the PR and between f199fae and 1a1df44.

📒 Files selected for processing (2)
  • src/components/case-mobile/MobileCaseWorkspace.tsx
  • src/lib/mobile/mobileTypes.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/case-mobile/MobileCaseWorkspace.tsx
📜 Recent review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: Unit & Regression Tests
  • GitHub Check: Production Build
  • GitHub Check: TypeScript Check
  • GitHub Check: ESLint
🔇 Additional comments (1)
src/lib/mobile/mobileTypes.ts (1)

15-15: LGTM!


📝 Walkthrough

Walkthrough

This PR adds mobile workspace, facts, timeline, and summary route pages, new mobile UI components, sample workspace data, a timeline category type, and an updated mobile interaction checklist.

Changes

Mobile Case Workspace Feature

Layer / File(s) Summary
Sample workspace data source
src/lib/mobile/caseWorkspaceData.ts, src/lib/mobile/mobileTypes.ts
Defines MobileCaseWorkspaceData, adds a category field to timeline events, and returns sample facts, timeline events, patterns, and summary text from getMobileCaseWorkspaceData(caseId).
Mobile workspace components
src/components/case-mobile/MobileCaseSnapshotCard.tsx, MobileCaseWorkspace.tsx, MobileFactsCarousel.tsx, MobileFactsList.tsx, MobileNarrativePreview.tsx, MobilePatternsSection.tsx, MobileTimelineSnapshot.tsx, MobileTimelineScreen.tsx, MobileFullSummaryScreen.tsx, MobileGenerateReportBar.tsx, index.ts
Adds the mobile workspace shell, snapshot and section components, detail top bar, generate-report bar, summary screen, timeline screen, and barrel exports.
Mobile route pages
src/app/case/[caseId]/workspace/page.tsx, facts/page.tsx, timeline/page.tsx, workspace/summary/page.tsx
Adds async route pages that await promised params, fetch workspace data, and render the mobile workspace, facts, timeline, and summary screens.
Checklist update
docs/mobile-interaction-contract-checklist.md
Marks most Phase 2 mobile route checklist items as completed, leaving layout verification pending.

Sequence Diagram(s)

sequenceDiagram
  participant MobileWorkspacePage
  participant getMobileCaseWorkspaceData
  participant MobileCaseWorkspace
  participant MobileFactsCarousel
  participant MobileGenerateReportBar

  MobileWorkspacePage->>getMobileCaseWorkspaceData: load workspace data for caseId
  getMobileCaseWorkspaceData-->>MobileWorkspacePage: MobileCaseWorkspaceData
  MobileWorkspacePage->>MobileCaseWorkspace: render workspace with data
  MobileCaseWorkspace->>MobileFactsCarousel: render key facts
  MobileCaseWorkspace->>MobileGenerateReportBar: render sticky report CTA
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

Hop hop, a workspace built anew,
Facts and timelines, patterns too 🐇
Cards stack neat from top to base,
A sticky button starts the chase
"Generate Report!" — off we race! 📱✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding mobile case workspace routes.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
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.
✨ 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 codex/mobile-workspace-route

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


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

@vercel

vercel Bot commented Jun 30, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
nexx-app Ready Ready Preview, Comment Jul 1, 2026 1:40am

Request Review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
src/components/case-mobile/MobilePatternsSection.tsx (1)

31-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer event.id for the list key when available.

The upstream MobilePattern.supportingEvents type includes an optional id field, but the key here is a composite of date and description, which could collide for two distinct events sharing the same date/description text.

♻️ Proposed fix
-                {pattern.supportingEvents.slice(0, 3).map((event) => (
-                  <p key={`${event.date}-${event.description}`} className="text-xs leading-5 text-neutral-600">
+                {pattern.supportingEvents.slice(0, 3).map((event, index) => (
+                  <p key={event.id ?? `${event.date}-${event.description}-${index}`} className="text-xs leading-5 text-neutral-600">
🤖 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/components/case-mobile/MobilePatternsSection.tsx` around lines 31 - 35,
The supporting events list in MobilePatternsSection currently uses a composite
key from date and description, which can collide for distinct items. Update the
map over pattern.supportingEvents to prefer event.id when present, and only fall
back to the existing composite key when id is missing. Keep the change localized
to the supportingEvents rendering in MobilePatternsSection and preserve the
current display output.
src/components/case-mobile/MobileFullSummaryScreen.tsx (1)

10-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use index-based keys instead of key={paragraph}.

If fullSummary ever contains two identical paragraphs (e.g., a repeated boilerplate line), React will receive duplicate keys, causing a console warning and unreliable reconciliation.

♻️ Proposed fix
-        {text.split('\n\n').map((paragraph) => (
-          <p key={paragraph} className="text-sm leading-7 text-neutral-700">
+        {text.split('\n\n').map((paragraph, index) => (
+          <p key={index} className="text-sm leading-7 text-neutral-700">
             {paragraph}
           </p>
         ))}
🤖 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/components/case-mobile/MobileFullSummaryScreen.tsx` around lines 10 - 14,
The paragraph list in MobileFullSummaryScreen currently uses the paragraph text
as the React key, which can collide when duplicate paragraphs appear. Update the
map over text.split('\n\n') to use an index-based key in this render path,
keeping the existing <p> element and className intact so each paragraph gets a
stable unique key from its position.
🤖 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/components/case-mobile/index.ts`:
- Around line 1-10: The barrel in case-mobile is missing the
MobileCaseDetailTopBar export, which is already defined in MobileCaseWorkspace
and consumed via `@/components/case-mobile` by the case pages. Update
src/components/case-mobile/index.ts to re-export MobileCaseDetailTopBar
alongside the existing exports so the imports in facts/page.tsx,
timeline/page.tsx, and workspace/summary/page.tsx resolve correctly.

In `@src/components/case-mobile/MobileCaseWorkspace.tsx`:
- Around line 13-20: Avoid the circular dependency caused by importing sibling
components through the barrel in MobileCaseWorkspace; replace the `./index`
import with direct imports from each component’s own module so
`MobileCaseWorkspace` no longer depends on
`src/components/case-mobile/index.ts`. Update the imports for
`MobileCaseSnapshotCard`, `MobileFactsCarousel`, `MobileGenerateReportBar`,
`MobileNarrativePreview`, `MobilePatternsSection`, and `MobileTimelineSnapshot`
to point at their respective files.

In `@src/components/case-mobile/MobileNarrativePreview.tsx`:
- Line 15: The gradient overlay in MobileNarrativePreview should use the
Tailwind v4 linear gradient utility instead of the removed bg-gradient-to-*
class. Update the class on the absolute bottom fade element to use
bg-linear-to-t while keeping the same direction and color stops, so the preview
still fades into transparent correctly.

In `@src/components/case-mobile/MobileTimelineScreen.tsx`:
- Around line 11-19: The filter logic in filters and eventMatchesFilter is
relying on title text for Calls and Exchange, but MobileTimelineEvent.sourceType
does not include those categories, so those chips produce empty or inconsistent
results. Update eventMatchesFilter to use a real sourceType-to-filter mapping
that matches the intended taxonomy from mobileTypes.ts, and ensure Calls and
Exchange are mapped to the correct underlying event types instead of falling
back to event.title matching; also resolve the current overlap between Court and
Evidence so each filter has distinct, predictable matches.

---

Nitpick comments:
In `@src/components/case-mobile/MobileFullSummaryScreen.tsx`:
- Around line 10-14: The paragraph list in MobileFullSummaryScreen currently
uses the paragraph text as the React key, which can collide when duplicate
paragraphs appear. Update the map over text.split('\n\n') to use an index-based
key in this render path, keeping the existing <p> element and className intact
so each paragraph gets a stable unique key from its position.

In `@src/components/case-mobile/MobilePatternsSection.tsx`:
- Around line 31-35: The supporting events list in MobilePatternsSection
currently uses a composite key from date and description, which can collide for
distinct items. Update the map over pattern.supportingEvents to prefer event.id
when present, and only fall back to the existing composite key when id is
missing. Keep the change localized to the supportingEvents rendering in
MobilePatternsSection and preserve the current display output.
🪄 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: 800a9c22-1983-49d6-9b68-bf1e7f6750fa

📥 Commits

Reviewing files that changed from the base of the PR and between b50b323 and 9c8c7c0.

📒 Files selected for processing (17)
  • docs/mobile-interaction-contract-checklist.md
  • src/app/case/[caseId]/facts/page.tsx
  • src/app/case/[caseId]/timeline/page.tsx
  • src/app/case/[caseId]/workspace/page.tsx
  • src/app/case/[caseId]/workspace/summary/page.tsx
  • src/components/case-mobile/MobileCaseSnapshotCard.tsx
  • src/components/case-mobile/MobileCaseWorkspace.tsx
  • src/components/case-mobile/MobileFactsCarousel.tsx
  • src/components/case-mobile/MobileFactsList.tsx
  • src/components/case-mobile/MobileFullSummaryScreen.tsx
  • src/components/case-mobile/MobileGenerateReportBar.tsx
  • src/components/case-mobile/MobileNarrativePreview.tsx
  • src/components/case-mobile/MobilePatternsSection.tsx
  • src/components/case-mobile/MobileTimelineScreen.tsx
  • src/components/case-mobile/MobileTimelineSnapshot.tsx
  • src/components/case-mobile/index.ts
  • src/lib/mobile/caseWorkspaceData.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Production Build
🔇 Additional comments (22)
src/app/case/[caseId]/timeline/page.tsx (2)

1-1: Same barrel-export issue as facts/page.tsx.

Depends on MobileCaseDetailTopBar being re-exported from @/components/case-mobile (see comment on src/components/case-mobile/index.ts).


4-21: LGTM otherwise.

src/app/case/[caseId]/workspace/summary/page.tsx (2)

1-1: Same barrel-export issue as facts/page.tsx.

Depends on MobileCaseDetailTopBar being re-exported from @/components/case-mobile (see comment on src/components/case-mobile/index.ts).


16-16: 📐 Maintainability & Code Quality | 💤 Low value

Verify the 7rem bottom padding is intentional here.

This page doesn't render a sticky MobileGenerateReportBar (unlike the main workspace page), yet uses a larger bottom-safe-area offset (7rem) than the facts/timeline pages (3rem). If there's no sticky footer on this screen, the extra padding may just be unused whitespace.

src/lib/mobile/caseWorkspaceData.ts (2)

1-96: LGTM!


98-115: LGTM!

The fullSummary join separator correctly matches the consumer's split contract. Renders fullSummary by splitting the provided text on double-newlines ('\n\n') into paragraph <p> elements.

src/app/case/[caseId]/facts/page.tsx (2)

1-1: Will fail to compile until barrel export is fixed.

This import depends on MobileCaseDetailTopBar being re-exported from @/components/case-mobile, which is currently missing (see comment on src/components/case-mobile/index.ts).


4-21: LGTM otherwise — params handling, data fetch, and layout look correct.

src/components/case-mobile/MobileCaseSnapshotCard.tsx (2)

1-39: LGTM!


26-26: 🎯 Functional Correctness

No duplicate <h1> here
MobileTopBar renders title inside a <span>, so MobileCaseWorkspace does not add another heading. The only <h1> on this screen is MobileCaseSnapshotCard.

			> Likely an incorrect or invalid review comment.
src/components/case-mobile/MobileCaseWorkspace.tsx (3)

53-64: 🎯 Functional Correctness | 💤 Low value

Inert action buttons: "Select case" and "More actions" have no handler.

onTitleAction={() => undefined} (Line 54) and the "More actions" MobileIconButton instances (Lines 61-63, 115-117) have no onClick. They render as interactive controls but do nothing when activated, which can confuse users/screen-reader users expecting an action.

Also applies to: 109-118


88-92: 🎯 Functional Correctness

Generate Report just appends a query param — confirm downstream handling.

onGenerateReport pushes ?report=1 onto the current workspace route. No code in this PR reads that query param, so it's unclear what effect this has. Confirm this is wired up for a later phase rather than a no-op.


1-12: LGTM!

Also applies to: 22-52, 67-95, 97-121

src/components/case-mobile/MobileFactsCarousel.tsx (1)

1-61: LGTM!

src/components/case-mobile/MobileFactsList.tsx (1)

1-24: LGTM!

src/components/case-mobile/MobilePatternsSection.tsx (1)

1-30: LGTM!

Also applies to: 36-47

src/components/case-mobile/MobileTimelineSnapshot.tsx (1)

1-46: LGTM!

src/components/case-mobile/MobileNarrativePreview.tsx (1)

1-26: LGTM!

src/components/case-mobile/MobileTimelineScreen.tsx (1)

38-53: LGTM!

src/components/case-mobile/MobileGenerateReportBar.tsx (1)

1-19: LGTM!

src/app/case/[caseId]/workspace/page.tsx (1)

1-14: LGTM!

docs/mobile-interaction-contract-checklist.md (1)

37-51: LGTM!

Comment thread src/components/case-mobile/index.ts
Comment thread src/components/case-mobile/MobileCaseWorkspace.tsx Outdated
Comment thread src/components/case-mobile/MobileNarrativePreview.tsx Outdated
Comment thread src/components/case-mobile/MobileTimelineScreen.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/components/case-mobile/MobileCaseWorkspace.tsx (2)

106-127: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

MobileCaseDetailTopBar left and right actions both navigate to the same route.

left ("Go back") and right ("Open workspace") both call router.push(\/case/${caseId}/workspace`). Presenting two icons for an identical destination is confusing, and using router.pushfor "Go back" (rather thanrouter.back()`) forces a fixed target regardless of navigation history, which may not match user expectation of a back button.

💡 Consider differentiating the two actions
       left={
-        <MobileIconButton label="Go back" onClick={() => router.push(`/case/${caseId}/workspace`)}>
+        <MobileIconButton label="Go back" onClick={() => router.back()}>
           <ArrowLeft aria-hidden="true" className="h-5 w-5" />
         </MobileIconButton>
       }
🤖 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/components/case-mobile/MobileCaseWorkspace.tsx` around lines 106 - 127,
In MobileCaseDetailTopBar, the left “Go back” action and the right “Open
workspace” action currently both navigate to the same workspace route. Update
the component so the left control uses the Router’s back behavior
(router.back()) or another true return action, while keeping the right control
as the explicit workspace navigation via router.push. Use the
MobileCaseDetailTopBar and MobileIconButton handlers to make the two actions
clearly distinct.

49-64: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Left and right top-bar buttons perform the identical action.

Both left ("Open menu") and right ("Open case navigation") buttons call setIsDrawerOpen(true) with different icons (Menu vs MoreHorizontal). This is redundant from a UX perspective — two buttons, same effect, different affordance implied by icon/label.

🤖 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/components/case-mobile/MobileCaseWorkspace.tsx` around lines 49 - 64, The
MobileCaseWorkspace top bar currently renders two buttons with different
labels/icons but the same onClick behavior, which is redundant. Update the left
and right actions in MobileCaseWorkspace so they represent distinct
interactions, or remove one if only a single drawer toggle is needed; use the
existing setIsDrawerOpen handler and the MobileIconButton/MobileTopBar props to
wire each button to a unique action.
🤖 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.

Nitpick comments:
In `@src/components/case-mobile/MobileCaseWorkspace.tsx`:
- Around line 106-127: In MobileCaseDetailTopBar, the left “Go back” action and
the right “Open workspace” action currently both navigate to the same workspace
route. Update the component so the left control uses the Router’s back behavior
(router.back()) or another true return action, while keeping the right control
as the explicit workspace navigation via router.push. Use the
MobileCaseDetailTopBar and MobileIconButton handlers to make the two actions
clearly distinct.
- Around line 49-64: The MobileCaseWorkspace top bar currently renders two
buttons with different labels/icons but the same onClick behavior, which is
redundant. Update the left and right actions in MobileCaseWorkspace so they
represent distinct interactions, or remove one if only a single drawer toggle is
needed; use the existing setIsDrawerOpen handler and the
MobileIconButton/MobileTopBar props to wire each button to a unique action.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dcb6a1d7-8cff-4f2f-a2f4-150ef5160e60

📥 Commits

Reviewing files that changed from the base of the PR and between 9c8c7c0 and f199fae.

📒 Files selected for processing (8)
  • src/components/case-mobile/MobileCaseWorkspace.tsx
  • src/components/case-mobile/MobileFullSummaryScreen.tsx
  • src/components/case-mobile/MobileNarrativePreview.tsx
  • src/components/case-mobile/MobilePatternsSection.tsx
  • src/components/case-mobile/MobileTimelineScreen.tsx
  • src/components/case-mobile/index.ts
  • src/lib/mobile/caseWorkspaceData.ts
  • src/lib/mobile/mobileTypes.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/case-mobile/index.ts
  • src/components/case-mobile/MobilePatternsSection.tsx
  • src/components/case-mobile/MobileFullSummaryScreen.tsx
  • src/components/case-mobile/MobileNarrativePreview.tsx
  • src/lib/mobile/caseWorkspaceData.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Production Build
  • GitHub Check: Unit & Regression Tests
🔇 Additional comments (4)
src/lib/mobile/mobileTypes.ts (1)

15-15: LGTM!

src/components/case-mobile/MobileCaseWorkspace.tsx (2)

13-18: Circular-dependency fix confirmed.

Imports are now pulled directly from sibling files instead of ./index, resolving the previously flagged circular dependency.


43-98: LGTM!

src/components/case-mobile/MobileTimelineScreen.tsx (1)

13-21: 🎯 Functional Correctness

Filter logic now aligns with MobileTimelineEvent.category, resolving the prior Calls/Exchange bug.

The category-based mapping matches the mobileTypes.ts union correctly, and the Court/Evidence overlap is resolved. However, Calls (line 17) and Exchange (line 18) check event.category only, with no sourceType fallback — unlike Messages, Court, and Evidence. If the sample/production data provider (caseWorkspaceData.ts) doesn't consistently populate category for pin/timeline-sourced events, these two filters will silently return empty result sets, similar to the original bug this replaces.

#!/bin/bash
# Verify that sample timeline data populates `category` for events intended to match 'call'/'exchange' filters.
fd 'caseWorkspaceData.ts' src/lib/mobile -x cat -n {}

@monicafernii97-cmd
monicafernii97-cmd merged commit 9f17bea into main Jul 1, 2026
7 checks passed
@monicafernii97-cmd
monicafernii97-cmd deleted the codex/mobile-workspace-route branch July 1, 2026 01:44

This branch was successfully deployed

1 active deployment
Preview — 1a1df447 Deployed Jul 1, 2026 by vercel[bot]
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