Skip to content

Feat/add chat details - #250

Merged
sacheeramesh merged 2 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-chat-details
Feb 24, 2026
Merged

sacheeramesh merged 2 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-chat-details

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Feb 24, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter �N/A� plus brief explanation of why there�s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type �Sent� when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type �N/A� and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for viewing paginated conversation messages within support cases with automatic pagination and message history retrieval.
  • Bug Fixes

    • Fixed an issue where empty or whitespace-only product labels would incorrectly display in the case details panel.

Prefer deployedProduct.label for product display when it contains non-empty trimmed text; fall back to product otherwise. Introduce CaseDetailsDeployedProduct and update CaseDetails.deployedProduct to use this shape. Add ConversationMessage and ConversationMessagesResponse models to represent conversation messages, and add CONVERSATION_MESSAGES to ApiQueryKeys.
Introduce useGetConversationMessages hook that uses useInfiniteQuery to fetch conversation messages (GET /conversations/{conversationId}/messages) with limit/offset pagination. The hook uses useAsgardeo for auth state, useAuthApiClient as the authenticated fetch client, and useLogger for debug logs. It validates CUSTOMER_PORTAL_BACKEND_BASE_URL, defaults pageSize to 10 (configurable), enables the query only when signed in and a conversationId is present, sets a 5-minute staleTime, and computes next offsets via getNextPageParam. Errors are thrown for missing configuration or non-OK responses.
@dileepapeiris dileepapeiris self-assigned this Feb 24, 2026
@coderabbitai

coderabbitai Bot commented Feb 24, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces a new React hook for fetching paginated conversation messages with infinite query support, including authentication validation via ASGardeo. It adds supporting API constants and response types for conversation data, and refines product label rendering to avoid displaying empty values.

Changes

Cohort / File(s) Summary
Conversation Messages Fetching
apps/customer-portal/webapp/src/api/useGetConversationMessages.ts, apps/customer-portal/webapp/src/constants/apiConstants.ts, apps/customer-portal/webapp/src/models/responses.ts
Introduces new hook for paginated conversation message retrieval with infinite query, authentication checks, and logging. Adds CONVERSATION_MESSAGES API query key and new response types: CaseDetailsDeployedProduct, ConversationMessage, and ConversationMessagesResponse.
Product Display Refinement
apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx
Conditionally renders deployed product label only when non-empty after trimming to prevent displaying whitespace-only values.

Sequence Diagram(s)

sequenceDiagram
    participant Component as React Component
    participant Hook as useGetConversationMessages
    participant Auth as ASGardeo
    participant Query as TanStack Query
    participant API as Backend API

    Component->>Hook: Call with conversationId
    Hook->>Auth: Check if user signed in & auth loaded
    alt Auth Valid
        Query->>Query: Check cache & stale status
        Query->>API: GET /conversations/{id}/messages?limit=10&offset=0
        API-->>Query: ConversationMessagesResponse
        Query->>Hook: Return infinite query result
        Hook-->>Component: InfiniteData with paginated messages
    else Auth Invalid/Loading
        Hook-->>Component: Query disabled, no request
    end
    
    alt User Requests Next Page
        Component->>Hook: Call fetchNextPage()
        Hook->>Query: Advance offset, fetch next batch
        Query->>API: GET with new offset parameter
        API-->>Query: Additional messages
        Query-->>Hook: Merge with existing data
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

Type/Improvement, App/Customer Portal, Area/Frontend, Platform/Web

Suggested reviewers

  • Rashmika998

Poem

🐰 Hop, hop, conversations flow,
With pagination's gentle glow,
Messages fetched page by page,
Auth guards each backend stage,
Empty labels fade from sight! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is entirely empty—it contains only the template placeholders with no actual content filled in for any required sections like Purpose, Goals, Approach, or other details. Complete all required sections of the description template with concrete details about the feature's purpose, implementation approach, goals, and relevant artifacts.
Title check ❓ Inconclusive The title 'Feat/add chat details' is vague and does not clearly convey the specific changes made. It lacks detail about what chat details are being added or what functionality is being implemented. Revise the title to be more specific about the main change, such as 'Add conversation messages hook and API support for chat details' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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

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 and usage tips.

@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: 1

🧹 Nitpick comments (3)
apps/customer-portal/webapp/src/api/useGetConversationMessages.ts (1)

85-91: getNextPageParam can loop if the server returns limit: 0.

nextOffset = lastPage.offset + lastPage.limit — if the server ever returns limit: 0 and totalRecords > 0, nextOffset equals lastPage.offset and the condition nextOffset < totalRecords remains true, returning the same offset on every call. A simple progress guard eliminates this:

♻️ Proposed fix
     getNextPageParam: (lastPage) => {
       const nextOffset = lastPage.offset + lastPage.limit;
-      if (nextOffset >= lastPage.totalRecords) {
+      if (lastPage.limit <= 0 || nextOffset >= lastPage.totalRecords) {
         return undefined;
       }
       return nextOffset;
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/customer-portal/webapp/src/api/useGetConversationMessages.ts` around
lines 85 - 91, The pagination logic in getNextPageParam (in
useGetConversationMessages) can loop if the server returns lastPage.limit === 0;
modify the implementation to guard against non‑progressing pages by returning
undefined when lastPage.limit <= 0 or when computed nextOffset is less than or
equal to lastPage.offset (i.e., no progress), otherwise return nextOffset as
currently done.
apps/customer-portal/webapp/src/models/responses.ts (1)

437-453: ConversationMessage / ConversationMessagesResponse are near-duplicates of CaseComment / CaseCommentsResponse.

The two pairs are structurally identical except that hasInlineAttachments and inlineAttachments are required in ConversationMessage but optional in CaseComment. If the API contract warrants this distinction, a shared base interface would eliminate the repetition:

♻️ Suggested refactor — shared base type
+/** Shared fields between CaseComment and ConversationMessage. */
+export interface BaseComment {
+  id: string;
+  content: string;
+  type: string;
+  createdOn: string;
+  createdBy: string;
+  isEscalated: boolean;
+}

-export interface CaseComment {
-  id: string;
-  content: string;
-  type: string;
-  createdOn: string;
-  createdBy: string;
-  isEscalated: boolean;
-  /** Whether this comment has inline images. */
-  hasInlineAttachments?: boolean;
-  /** Inline attachments for images in content (img src replacement). */
-  inlineAttachments?: CaseCommentInlineAttachment[];
-}
+export interface CaseComment extends BaseComment {
+  hasInlineAttachments?: boolean;
+  inlineAttachments?: CaseCommentInlineAttachment[];
+}

-export interface ConversationMessage {
-  id: string;
-  content: string;
-  type: string;
-  createdOn: string;
-  createdBy: string;
-  isEscalated: boolean;
-  hasInlineAttachments: boolean;
-  inlineAttachments: CaseCommentInlineAttachment[];
-}
+export interface ConversationMessage extends BaseComment {
+  hasInlineAttachments: boolean;
+  inlineAttachments: CaseCommentInlineAttachment[];
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/customer-portal/webapp/src/models/responses.ts` around lines 437 - 453,
ConversationMessage and CaseComment are duplicated types; create a shared base
interface (e.g., BaseComment) capturing common fields (id, content, type,
createdOn, createdBy, isEscalated, plus inline attachment fields) and then have
ConversationMessage and CaseComment extend that base, making
hasInlineAttachments and inlineAttachments optional on CaseComment if the API
requires; similarly replace duplicated response types with a generic
CommentResponse<T extends BaseComment> or have ConversationMessagesResponse and
CaseCommentsResponse reuse the same shape (comments: BaseComment[] / T[],
totalRecords, offset, limit) so you remove the repeated property definitions
while retaining the existing names and optionality for
hasInlineAttachments/inlineAttachments and the CaseCommentInlineAttachment type.
apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx (1)

220-224: Simplify the label trim guard — it checks trimmed length but renders the untrimmed value.

?.trim?.() uses unnecessary optional-call syntax (?.()) on .trim, which is always a method on a string. More critically, the expression trims to determine emptiness but then passes data.deployedProduct.label (untrimmed) to formatValue. The compact form below is both idiomatic and consistent:

♻️ Proposed simplification
-              {formatValue(
-                data?.deployedProduct?.label?.trim?.()?.length
-                  ? data.deployedProduct.label
-                  : null,
-              )}
+              {formatValue(data?.deployedProduct?.label?.trim() || null)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx`
around lines 220 - 224, In CaseDetailsDetailsPanel near the use of formatValue,
the guard uses optional-call on .trim and checks trimmed length but then passes
the untrimmed label; change it to check and pass the trimmed string (and keep
optional chaining for deployedProduct/label). Concretely, replace the current
expression so formatValue receives either label.trim() when label exists and has
nonempty trimmed length, or null otherwise, while removing the unnecessary ?.()
on .trim and ensuring you reference data.deployedProduct.label consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/customer-portal/webapp/src/api/useGetConversationMessages.ts`:
- Line 80: The debug line in useGetConversationMessages.ts currently logs the
full ConversationMessagesResponse (variable data) including comments[].content
and comments[].createdBy; remove or replace that raw data log to avoid leaking
PII and instead log only non-sensitive metadata (e.g., number of comments,
pagination offset/limit, and any request id). Update the logger.debug call in
useGetConversationMessages (where it logs "[useGetConversationMessages] Data
received:") to omit data and log a small metadata object (count, offset/limit)
or a concise message, and ensure no raw `data`, `comments[].content`, or
`comments[].createdBy` values are emitted to logs.

---

Nitpick comments:
In `@apps/customer-portal/webapp/src/api/useGetConversationMessages.ts`:
- Around line 85-91: The pagination logic in getNextPageParam (in
useGetConversationMessages) can loop if the server returns lastPage.limit === 0;
modify the implementation to guard against non‑progressing pages by returning
undefined when lastPage.limit <= 0 or when computed nextOffset is less than or
equal to lastPage.offset (i.e., no progress), otherwise return nextOffset as
currently done.

In
`@apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx`:
- Around line 220-224: In CaseDetailsDetailsPanel near the use of formatValue,
the guard uses optional-call on .trim and checks trimmed length but then passes
the untrimmed label; change it to check and pass the trimmed string (and keep
optional chaining for deployedProduct/label). Concretely, replace the current
expression so formatValue receives either label.trim() when label exists and has
nonempty trimmed length, or null otherwise, while removing the unnecessary ?.()
on .trim and ensuring you reference data.deployedProduct.label consistently.

In `@apps/customer-portal/webapp/src/models/responses.ts`:
- Around line 437-453: ConversationMessage and CaseComment are duplicated types;
create a shared base interface (e.g., BaseComment) capturing common fields (id,
content, type, createdOn, createdBy, isEscalated, plus inline attachment fields)
and then have ConversationMessage and CaseComment extend that base, making
hasInlineAttachments and inlineAttachments optional on CaseComment if the API
requires; similarly replace duplicated response types with a generic
CommentResponse<T extends BaseComment> or have ConversationMessagesResponse and
CaseCommentsResponse reuse the same shape (comments: BaseComment[] / T[],
totalRecords, offset, limit) so you remove the repeated property definitions
while retaining the existing names and optionality for
hasInlineAttachments/inlineAttachments and the CaseCommentInlineAttachment type.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 236ebf6 and b9a5ac6.

📒 Files selected for processing (4)
  • apps/customer-portal/webapp/src/api/useGetConversationMessages.ts
  • apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx
  • apps/customer-portal/webapp/src/constants/apiConstants.ts
  • apps/customer-portal/webapp/src/models/responses.ts

Comment thread apps/customer-portal/webapp/src/api/useGetConversationMessages.ts
@sacheeramesh
sacheeramesh merged commit de42344 into wso2-open-operations:customer-portal-milestone-1 Feb 24, 2026
1 check passed
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