[Customer Portal][FE][Web] Implement chat history component on Support page - #102
Conversation
Collapse the Grid element props into a single-line declaration and remove the explicit sx={{ mb: 3 }} styling. This simplifies the component markup in apps/customer-portal/webapp/src/components/support/cases-overview-stats/CasesOverviewStatCard.tsx without changing functionality.
Remove the `mb: 8` style from the Paper component in NoveraChatBanner to eliminate the extra bottom margin and adjust spacing/alignment. No functional logic changes.
Add a new unit test file for the ChatHistoryList component (apps/customer-portal/webapp/src/components/support/support-overview-cards/__tests__/ChatHistoryList.test.tsx). Tests verify empty state rendering, display of chat titles, metadata (time, messages, KB articles) and status, presence of View/Resume buttons, and that the onItemAction callback is invoked with the correct chatId and action. Tests use vitest and React Testing Library with mocked chat items.
Add a new vitest test file at apps/customer-portal/webapp/src/utils/__tests__/support.test.ts that validates support utility functions. Tests cover getChatStatusAction (status->action mapping), getChatStatusChipSx and getChatStatusRowSx (styling outputs per status), and formatRelativeTime (handling undefined, just now, minutes/hours/days ago).
Add a Chat History overview card to the Support page. Imports useGetChatHistory, ChatHistoryList and SUPPORT_OVERVIEW_CHAT_LIMIT; fetches recent chat history (sliced to the configured limit) and exposes loading state. Adds a new SupportOverviewCard for "Chat History" that navigates to the full chat view and passes chatId when an item is selected. Also updates the Outstanding Cases subtitle to use the cases limit constant, replaces Box with Stack and adjusts Grid spacing and flex styles to ensure cards stretch consistently.
Add React import and several mocks to stabilize SupportPage unit tests: mock @asgardeo/react to avoid ESM buffer import errors, provide simplified @wso2/oxygen-ui theme utilities, mock API hooks (useGetProjectCases, useGetChatHistory), and replace complex overview card components with lightweight test doubles. Also add a new test asserting Outstanding Cases and Chat History overview cards render when data is loaded. These changes make the test suite independent of heavy UI/provider trees and external ESM issues.
Introduce SUPPORT_OVERVIEW_CHAT_LIMIT (value 5) to control how many chat history items are shown on support overview cards. Mirrors the existing SUPPORT_OVERVIEW_CASES_LIMIT for consistency.
Add typed sx support to SupportOverviewCard by importing SxProps and Theme and adding an optional sx?: SxProps<Theme> prop. Apply sx (spread) to the root Box and set height/width to 100% so the card can expand to its container; also make the content Box flex: 1 and full width. These changes let consumers customize styling via the sx prop and ensure consistent full-size layout.
Add width: "100%" to the Box container in OutstandingCasesSkeleton.tsx so the skeleton cards span the full available width and avoid layout collapse. This is a small styling tweak to ensure consistent layout of the support overview skeleton items.
Prevent long case titles from breaking the layout in OutstandingCasesList: add width: "100%" to the outer container, wrap the Typography in a Box with minWidth: 0, and apply textOverflow/ellipsis and -webkit-line-clamp styling to limit titles to a single truncated line.
Introduce ChatHistorySkeleton.tsx: a React component that renders a list of loading skeletons for the support chat history using @wso2/oxygen-ui components. It generates placeholders based on SUPPORT_OVERVIEW_CHAT_LIMIT and uses non-interactive Form.CardButton items to visually match the chat list while data is loading.
Introduce ChatHistoryList React component to render support chat history in the customer portal. The component accepts items, isLoading, and onItemAction props, shows a skeleton when loading, an empty state when no items, and maps each ChatHistoryItem to a clickable card with title, metadata, status chip (theme-resolved color), and an action button (View or Resume). Uses support utility functions (ChatAction, getChatStatusAction/getChatStatusColor/getChatActionColor, resolveColorFromTheme), Oxygen UI components, and a ChatHistorySkeleton.
Introduce chat status/action utilities in utils/support.ts: add ChatAction constants, ChatAction/ChatStatusAction types, and helper functions getChatStatusAction, getChatActionColor, and getChatStatusColor to centralize mapping of statuses to actions and palette colors. Simplify imports and adjust JSDoc comments. Also remove an explicit borderColor: "transparent" from the OutstandingCasesList chip styling to clean up the component's appearance.
Replace assertions for getChatStatusChipSx/getChatStatusRowSx with tests for the new getChatStatusColor helper in support utils. Tests now verify returned theme color tokens: Resolved => success.main, Still Open => info.main, Abandoned => error.main, and fallback => secondary.main, reflecting a refactor to return color keys instead of full sx objects.
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughAdds a Chat History feature and related UI to the Support page, introduces chat-related constants and utilities, extends SupportOverviewCard with external styling, adjusts local spacing/styling in several support components, and adds unit tests for new chat UI and utilities. Changes
Sequence DiagramsequenceDiagram
participant User as User
participant Page as SupportPage
participant Hook as useGetChatHistory
participant API as Chat API
participant List as ChatHistoryList
User->>Page: open Support page
Page->>Hook: request chat history (limit)
Hook->>API: GET /chat-history
API-->>Hook: chat items
Hook-->>Page: provides items & loading
Page->>List: render items / isLoading
Note right of List: shows skeleton if loading\nor item cards if loaded
User->>List: click item or action button
List-->>Page: onItemAction(chatId, action)
Page->>Page: navigate to chat view/resume
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/customer-portal/webapp/src/pages/__tests__/SupportPage.test.tsx (1)
33-55:⚠️ Potential issue | 🟡 MinorDuplicate
vi.mock("@asgardeo/react")— only one will take effect.
@asgardeo/reactis mocked twice with different return shapes: lines 34-36 return{ isLoading: false, isSignedIn: true }while lines 50-55 return{ isLoading: false, state: { isAuthenticated: true } }. Sincevi.mockcalls are hoisted, the last declaration wins, making the first mock dead code. Consolidate into a single mock with the correct shape.🐛 Proposed fix — remove the duplicate
-// Mock `@asgardeo/react` to avoid ESM buffer import errors in vitest -vi.mock("@asgardeo/react", () => ({ - useAsgardeo: () => ({ isLoading: false, isSignedIn: true }), -})); - // Mock useLogger const mockLogger = {
🤖 Fix all issues with AI agents
In
`@apps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsx`:
- Around line 128-144: Update the pluralization for item.messages and
item.kbArticles in ChatHistoryList.tsx so the UI shows "1 message" / "1 KB
article" when count === 1 and the plural otherwise; locate the JSX that renders
{item.messages} messages and {item.kbArticles} KB articles and replace each with
a conditional/string expression that chooses singular ("message", "KB article")
when the value === 1 and plural ("messages", "KB articles") otherwise,
preserving the numeric value display.
In `@apps/customer-portal/webapp/src/pages/SupportPage.tsx`:
- Around line 119-125: The onItemAction callback for ChatHistoryList currently
ignores the action parameter; update the handler in SupportPage.tsx to either
(A) preserve the simplified signature by changing ChatHistoryList's prop to
onItemAction={(chatId) => navigate("chat", { state: { chatId } })} or (B) wire
the action through: accept (chatId, action) and branch on action (e.g., if
action === "resume" navigate("chat", { state: { chatId, resume: true } }) else
navigate("chat", { state: { chatId } })), ensuring you update the
ChatHistoryList prop type/use sites to match the chosen signature; references:
ChatHistoryList, onItemAction, navigate, "chat", chatId.
🧹 Nitpick comments (4)
apps/customer-portal/webapp/src/utils/support.ts (1)
24-26:ChatActiontype andChatStatusActionare identical — consider dropping one.
ChatAction(line 24) resolves to"view" | "resume", which is exactly whatChatStatusAction(line 26) declares. Having both can confuse consumers about which to import. Consider removingChatStatusActionand usingChatActioneverywhere (or vice versa).♻️ Suggested simplification
export const ChatAction = { VIEW: "view", RESUME: "resume", } as const; export type ChatAction = (typeof ChatAction)[keyof typeof ChatAction]; -export type ChatStatusAction = "view" | "resume";Then update function signatures to use
ChatActioninstead ofChatStatusAction.apps/customer-portal/webapp/src/components/support/support-overview-cards/SupportOverviewCard.tsx (1)
65-74:...sxspread doesn't handle allSxPropsforms correctly.
SxProps<Theme>can be an object, an array of objects, or a callback(theme) => …. Spreading with...sxonly works for the plain-object case. If a caller passes an array or callback, the merge silently breaks.Since this is an internal component and callers are unlikely to pass non-object forms, this is low risk — but worth noting for correctness.
♻️ Safer merge using an array
<Paper - sx={{ - p: 2.5, - display: "flex", - flexDirection: "column", - gap: 2, - height: "100%", - width: "100%", - ...sx, - }} + sx={[ + { + p: 2.5, + display: "flex", + flexDirection: "column", + gap: 2, + height: "100%", + width: "100%", + }, + ...(Array.isArray(sx) ? sx : [sx]), + ]} >apps/customer-portal/webapp/src/utils/__tests__/support.test.ts (1)
24-80: Consider adding tests forgetChatActionColorandresolveColorFromTheme.These two exported utilities from
support.tsaren't covered here.getChatActionColoris trivial butresolveColorFromThemehas a reduce-based path traversal that would benefit from edge-case tests (e.g., invalid path, missing palette key).apps/customer-portal/webapp/src/pages/SupportPage.tsx (1)
60-67: Client-side slicing of chat history — consider server-side limiting if the API supports it.All chat history is fetched and then sliced to
SUPPORT_OVERVIEW_CHAT_LIMITon the client. If the API or hook supports alimitparameter (similar touseGetProjectCases), passing it would avoid transferring unnecessary data.
Replace absolute/alias imports with relative paths to ensure correct module resolution in runtime and tests (App.tsx, AppWithConfig.tsx, main.tsx, AuthGuard.test.tsx). Also improve ChatHistoryList copy by pluralizing "message(s)" and "KB article(s)" correctly based on count.
….com/dileepapeiris/cs-tools into feat/add-support-novera-chat-history
There was a problem hiding this comment.
Pull request overview
Implements a Chat History overview component on the Customer Portal Support page, including UI layout adjustments and supporting utility functions/tests.
Changes:
- Added Chat History overview card + list/skeleton components and wired it into
SupportPage. - Extended support utilities with chat action/status helpers and added unit tests.
- Refined support overview card layouts (full-height cards, improved truncation) and updated page/test mocks accordingly.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/customer-portal/webapp/src/utils/support.ts | Adds chat status/action helpers and color mapping utilities. |
| apps/customer-portal/webapp/src/utils/tests/support.test.ts | Unit tests for support utility helpers. |
| apps/customer-portal/webapp/src/pages/SupportPage.tsx | Integrates chat history data into Support page and updates layout. |
| apps/customer-portal/webapp/src/pages/tests/SupportPage.test.tsx | Updates SupportPage tests/mocks for new chat history card and Oxygen UI usage. |
| apps/customer-portal/webapp/src/constants/supportConstants.ts | Adds SUPPORT_OVERVIEW_CHAT_LIMIT. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistoryList.tsx | New Chat History list UI with status chip + action control. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/ChatHistorySkeleton.tsx | New skeleton state for chat history list. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/tests/ChatHistoryList.test.tsx | Tests for ChatHistoryList rendering and actions. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/SupportOverviewCard.tsx | Adds sx support and adjusts layout to stretch/fill card height. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx | Improves width handling and title truncation. |
| apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesSkeleton.tsx | Ensures skeleton list fills available width. |
| apps/customer-portal/webapp/src/components/support/novera-ai-assistant/novera-chat-banner/NoveraChatBanner.tsx | Adjusts spacing (removes bottom margin). |
| apps/customer-portal/webapp/src/components/support/cases-overview-stats/CasesOverviewStatCard.tsx | Simplifies grid spacing/margins. |
Comments suppressed due to low confidence (1)
apps/customer-portal/webapp/src/pages/tests/SupportPage.test.tsx:55
- This file declares
vi.mock("@asgardeo/react", ...)twice. The second mock overrides the first and the returned shape is inconsistent (e.g., missingisSignedIn/ token getters), which can lead to hard-to-diagnose test failures when any code path hitsuseAsgardeo(). Keep a single mock that matches the shape expected by the hooks/components under test.
// Mock @asgardeo/react to avoid ESM buffer import errors in vitest
vi.mock("@asgardeo/react", () => ({
useAsgardeo: () => ({ isLoading: false, isSignedIn: true }),
}));
// Mock useLogger
const mockLogger = {
debug: vi.fn(),
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
};
vi.mock("@hooks/useLogger", () => ({
useLogger: () => mockLogger,
}));
// Mock @asgardeo/react
vi.mock("@asgardeo/react", () => ({
useAsgardeo: () => ({
isLoading: false,
state: { isAuthenticated: true },
}),
}));
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Change Paper's sx prop to an array so caller sx (object or array) is merged safely into the base styles. Update SupportPage tests: remove unnecessary React import (use modern JSX runtime type import), add a mock for Stack to prevent missing-component test failures, and normalize/mock paths for useGetProjectCases and useGetChatHistory. These changes fix styling composition and stabilize tests against component/mocking changes.
Introduce ChatActionState union type ('primary' | 'info' | 'success' | 'warning' | 'error') and update getChatActionColor to return ChatActionState instead of an inline union. Centralizes action color states for reuse and improves type consistency.
Replace custom Form.CardButton/CardContent/CardActions with MUI Card/CardContent/CardActions in chat history list, add hover/cursor styles, and compute chip colors via theme function. Extract ChatAction and ChatStatus constants/types to supportConstants and update support utils to use them (including getChatStatusAction/getChatActionColor/getChatStatusColor). Update tests to reference the new constants and validate action/color behavior.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/customer-portal/webapp/src/utils/support.ts`:
- Around line 64-76: getChatStatusColor is performing a case-insensitive check
but compares the lowercased `normalized` string against mixed-case constants, so
none of the includes checks match; fix by lowercasing the ChatStatus constant
values before comparing (e.g., use ChatStatus.RESOLVED.toLowerCase(),
ChatStatus.STILL_OPEN.toLowerCase(), ChatStatus.ABANDONED.toLowerCase()) inside
getChatStatusColor so the includes checks succeed and return the correct color.
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/utils/support.ts (2)
52-63: Duplicate JSDoc block.There are two consecutive JSDoc comments for
getChatStatusColor. Remove the first one (lines 52-57).Proposed fix
-/** - * Returns the color path for a chat status. - * - * `@param` status - Chat status string. - * `@returns` {string} Palette color path. - */ /** * Returns the color for a chat status chip. *
20-25: Consider aligningChatActionStatewith MUI's palette options or reusing an existing type.
ChatActionStatemirrors MUI's color prop options. If the project already has such a type (e.g., from Oxygen UI), consider reusing it to avoid drift. Otherwise, the definition is fine as-is.
Ensure comparisons use lowercase ChatStatus values when checking a normalized status string. Previously the code compared a lowercased input against the enum constants directly (mismatch), so each ChatStatus is now lowercased before calling includes(), fixing status-to-color mapping for resolved, still_open, and abandoned states.
Replace the Material-UI Card wrapper with the Form.CardButton component for chat history items. Removed the Card import, added Form to the MUI import list and imported CardButton from @wso2/oxygen-ui. Updated JSX to render <Form.CardButton> (preserving sx and onClick) instead of <Card> to use the card-as-button component.
e8ee2b8
into
wso2-open-operations:customer-portal-milestone-1
Overview
Following the implementation of the Chat History API, this PR introduces the user-facing Chat History section on the Support page. It includes new display components, skeleton loading states, and specialized utility logic to handle chat statuses (View vs. Resume). Additionally, it refines the overall layout of the Support page for a more cohesive and responsive user experience.
Key Features
1. Chat History UI
ChatHistoryList: A new component that renders a list of recent chats. It dynamically determines whether a user should "View" (completed chats) or "Resume" (active chats) based on status.ChatHistorySkeleton: Provides a smooth loading experience using placeholder cards that match the chat list layout.2. Layout & Styling Improvements
CasesOverviewStatCard,NoveraChatBanner, andOutstandingCasesto create a unified grid.OutstandingCasesListwith better text truncation (ellipsis) to ensure long case titles don't break the layout.SupportOverviewCardto support custom styling via thesxprop, allowing for full-width and flexbox configurations.3. Integration & Constants
SupportPageIntegration: Connected theuseGetChatHistoryhook to the new UI components.SUPPORT_OVERVIEW_CHAT_LIMITto ensure the overview remains concise.Interaction Flow
sequenceDiagram actor User participant SupportPage participant useGetChatHistory participant API participant ChatHistoryList User->>SupportPage: Load support page SupportPage->>useGetChatHistory: Fetch chat history (limit: 5) useGetChatHistory->>API: GET /api/chat-history API-->>useGetChatHistory: Return chat items useGetChatHistory-->>SupportPage: Provide chat data & loading state SupportPage->>ChatHistoryList: Render with items & callbacks ChatHistoryList-->>SupportPage: Display chat list (or skeleton if loading) User->>ChatHistoryList: Click "View" or "Resume" ChatHistoryList->>SupportPage: onItemAction(chatId, action) SupportPage->>SupportPage: Navigate to chat details/room🛠 File Summary
ChatHistoryList.tsx,ChatHistorySkeleton.tsxSupportOverviewCard.tsx,OutstandingCasesList.tsx,NoveraChatBanner.tsxSupportPage.tsxsupport.ts,supportConstants.tsChatHistoryList.test.tsx,SupportPage.test.tsx,support.test.ts🧪 Testing Coverage
ChatHistoryListfor empty states, loading states, and correct action callback triggers.SupportPagecorrectly renders both the Outstanding Cases and Chat History cards simultaneously.Summary by CodeRabbit
New Features
Style
Tests
Summary by CodeRabbit
Release Notes
New Features
Style