Skip to content

refactor(platform): improve conversations page loading states#561

Merged
Israeltheminer merged 2 commits into
mainfrom
refactor/conversations-loading-states
Feb 24, 2026
Merged

refactor(platform): improve conversations page loading states#561
Israeltheminer merged 2 commits into
mainfrom
refactor/conversations-loading-states

Conversation

@Israeltheminer
Copy link
Copy Markdown
Collaborator

@Israeltheminer Israeltheminer commented Feb 24, 2026

Summary

  • Introduce deriveBodyState state machine to distinguish between empty, loading-counts, loading-data, and ready states
  • Split skeleton into ConversationsListSkeleton and ConversationPanelSkeleton for more accurate loading placeholders
  • Prefetch paginated conversations data in route loader for faster initial render

Test plan

  • Verify empty state shows correctly when organization has no conversations
  • Verify skeleton shows correct row count when count is known but data is loading
  • Verify smooth transition from skeleton to real content
  • Verify conversation status tabs work correctly with prefetched data

Summary by CodeRabbit

  • New Features

    • Skeleton loading screens for conversation list and panel views
  • Improvements

    • Input controls now disabled during data loading to prevent accidental interactions
    • Enhanced empty state handling for conversations
    • More accurate conversation count tracking across different statuses

Introduce deriveBodyState state machine to distinguish between empty, loading,
and ready states. Split skeleton into list and panel variants. Prefetch
paginated conversations data in route loader.
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 24, 2026

Greptile Summary

This PR refactors the conversations page loading states to provide better user feedback during data fetching.

Key changes:

  • Split skeleton components into ConversationsListSkeleton and ConversationPanelSkeleton for independent rendering
  • Introduced deriveBodyState state machine that distinguishes between empty (totalConversationCount === 0), loading (counts unknown), skeleton (count known), and data-ready states
  • Added prefetching for paginated conversations data in the route loader alongside existing count prefetching
  • Disabled checkbox and search interactions during loading states to prevent user confusion

Implementation notes:

  • The state machine correctly handles the undefined → number transition for counts
  • All four status counts are fetched to calculate totalConversationCount, which determines whether to show the empty state vs loading/skeleton
  • The checkbox and search input are disabled during loading, providing clear visual feedback that interactions aren't available yet

Confidence Score: 4/5

  • This PR is safe to merge with minor considerations around UX behavior
  • The implementation is solid with a well-designed state machine and proper loading state handling. The prefetching strategy improves performance, and the skeleton splitting provides better UX. The main consideration is ensuring the loading state behavior feels correct to users, particularly the disabled interactions during data fetch.
  • Pay attention to conversations.tsx for the state machine logic and $status.tsx for the multi-count fetching pattern

Important Files Changed

Filename Overview
services/platform/app/features/conversations/components/conversations.tsx Introduced deriveBodyState state machine to handle loading states, added conditional rendering for skeletons, and disabled interactions during loading
services/platform/app/routes/dashboard/$id/conversations/$status.tsx Added paginated data prefetching in loader, fetched all status counts to compute totalConversationCount for empty state detection

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start([Route Loader]) --> Prefetch[Prefetch counts & paginated data]
    Prefetch --> Component[Conversations Component]
    
    Component --> DeriveState{deriveBodyState}
    
    DeriveState --> CheckTotal{totalConversationCount === 0?}
    CheckTotal -->|Yes| Empty[Show ActivateConversationsEmptyState]
    CheckTotal -->|No| CheckLoading{paginatedStatus === 'LoadingFirstPage'?}
    
    CheckLoading -->|No| ShowData[Show ConversationsList & ConversationPanel]
    CheckLoading -->|Yes| CheckCount{conversationCount > 0?}
    
    CheckCount -->|Yes| Skeleton[Show skeletons with known row count]
    CheckCount -->|No/undefined| Loading[Show skeletons with default rows]
    
    Skeleton --> DisableUI[Disable checkbox & search]
    Loading --> DisableUI
    
    DisableUI --> WaitData[Wait for data]
    WaitData --> ShowData
Loading

Last reviewed commit: e54f0c6

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 24, 2026

📝 Walkthrough

Walkthrough

This PR refactors the conversations UI's skeleton and loading state handling across multiple layers. The skeleton components are reorganized into separate ConversationsListSkeleton and ConversationPanelSkeleton components with adjusted defaults. The main Conversations component introduces a body-state machine to uniformly manage empty, loading, skeleton, and data states. Route loaders are converted from async to synchronous, and the ConversationsStatusPage now computes per-status conversation counts and a total count, which are passed to the Conversations component to drive improved state-driven rendering.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(platform): improve conversations page loading states' directly matches the main changes, which involve refactoring the conversations loading UI with a new state machine (deriveBodyState) and split skeleton components.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/conversations-loading-states

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@services/platform/app/features/conversations/components/conversations-skeleton.tsx`:
- Around line 51-68: The hardcoded fixed widths on the Skeleton components
(w-96, w-80, w-72) can overflow narrow viewports inside the max-w-3xl container;
update these Skeleton instances to use responsive widths such as w-full with a
max-width constraint (e.g., w-full max-w-[384px] or w-full max-w-sm) or
conditional classes like sm:w-96 md:w-80 so they shrink on mobile, keeping the
existing Skeleton elements and class names (Skeleton, and the specific instances
with w-96/w-80/w-72) otherwise unchanged.

In `@services/platform/app/features/conversations/components/conversations.tsx`:
- Around line 148-153: The skeletonRows calculation can produce 0 when
deriveBodyState returns 'loading' and conversationCount === 0; update the
skeletonRows logic in conversations.tsx (where bodyState, skeletonRows, and
conversationCount are used) to ensure at least one skeleton row when showing a
loading state — e.g. compute the current value via Math.min(conversationCount ??
3, 8) and then, if bodyState === 'loading' and that value is 0, set skeletonRows
= 1 (or use Math.max(1, computedValue)) so the left skeleton list never renders
zero rows while the right panel shows a skeleton.

In `@services/platform/app/routes/dashboard/`$id/conversations/$status.tsx:
- Around line 41-49: The loader is prefetching using the raw URL segment
params.status which can diverge from the DB/selector key used by
useListConversationsPaginated; compute the same mappedStatus used by
conversationStatusMap/useListConversationsPaginated (e.g., mappedStatus =
conversationStatusMap[params.status] or the mapping helper) and pass
mappedStatus into the convexQuery/listConversationsPaginated prefetchQuery so
the cache key matches what useListConversationsPaginated (mappedStatus) will
read; keep the existing isValidStatus check on the raw param if needed but use
the mapped value for the prefetch call and any pagination params.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2015851 and e54f0c6.

📒 Files selected for processing (4)
  • services/platform/app/features/conversations/components/conversations-skeleton.tsx
  • services/platform/app/features/conversations/components/conversations.tsx
  • services/platform/app/routes/dashboard/$id/conversations.tsx
  • services/platform/app/routes/dashboard/$id/conversations/$status.tsx

@Israeltheminer Israeltheminer merged commit efdca65 into main Feb 24, 2026
9 checks passed
@Israeltheminer Israeltheminer deleted the refactor/conversations-loading-states branch February 24, 2026 23:46
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