refactor(platform): improve conversations page loading states#561
Conversation
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 SummaryThis PR refactors the conversations page loading states to provide better user feedback during data fetching. Key changes:
Implementation notes:
Confidence Score: 4/5
|
| 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
Last reviewed commit: e54f0c6
📝 WalkthroughWalkthroughThis PR refactors the conversations UI's skeleton and loading state handling across multiple layers. The skeleton components are reorganized into separate Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
services/platform/app/features/conversations/components/conversations-skeleton.tsxservices/platform/app/features/conversations/components/conversations.tsxservices/platform/app/routes/dashboard/$id/conversations.tsxservices/platform/app/routes/dashboard/$id/conversations/$status.tsx
Summary
deriveBodyStatestate machine to distinguish between empty, loading-counts, loading-data, and ready statesConversationsListSkeletonandConversationPanelSkeletonfor more accurate loading placeholdersTest plan
Summary by CodeRabbit
New Features
Improvements