Skip to content

[Customer Portal][FE][Web] Standardize Assigned Engineer Data Model and UI Display Logic - #159

Merged
v15a1 merged 9 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/fix-case-dfetails-page
Feb 16, 2026
Merged

v15a1 merged 9 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/fix-case-dfetails-page

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor

Description

This pull request standardizes how assigned engineer data is handled and displayed throughout the customer portal app. It introduces a new AssignedEngineerValue type and utility functions for extracting and formatting engineer names and initials. This results in more consistent UI behavior, improved handling of null/undefined values, and cleaner code in components and tests.

Key changes include:

Refactoring and Type Improvements:

  • Introduced the AssignedEngineerValue type and utility functions like getAssignedEngineerLabel and getInitials in @utils/support, and updated all relevant components to use these for displaying assigned engineer information. [1] [2] [3]

  • Updated the mock data in mockData.ts and test files to use the new assigned engineer object structure instead of plain strings, ensuring consistency in test and demo data. [1] [2] [3] [4] [5] [6] [7]

UI and Logic Consistency:

  • Refactored components (CasesList, AllCasesList, OutstandingCasesList, CaseDetailsDetailsPanel, CaseDetailsActionRow, etc.) to use the new utility functions for extracting and displaying engineer names and initials, and improved logic to hide the engineer section when no engineer is assigned. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

Testing Enhancements:

  • Updated and expanded test cases to cover new engineer object types, improved display logic, and ensured correct behavior when assigned engineer values are null or undefined. [1] [2] [3] [4] [5]

Component API Changes:

  • Changed component prop types to accept AssignedEngineerValue instead of just strings, enforcing type safety and consistency across the codebase. [1] [2]

These changes improve code maintainability, UI consistency, and type safety throughout the application.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Assigned Engineer field is now hidden when no engineer is assigned, reducing clutter in the UI.
  • Refactor

    • Improved consistency in how assigned engineer information is formatted and displayed across all support components.
    • Enhanced assigned engineer data handling to support flexible data formats while maintaining a consistent user experience.

Replace inline logic that derived avatar initials and displayed the assigned engineer with getInitials and formatValue from @utils/support. This simplifies CasesList, centralizes formatting behavior for engineer names/initials, and improves readability by removing duplicated string-manipulation code (added import for the new helpers).
Replace the inline logic that extracted the assignedEngineer label with a call to getAssignedEngineerLabel. Added the helper import and removed the temporary raw variable and type checks, simplifying and centralizing the label formatting logic.
Import AssignedEngineerValue type and update the helper to accept it. Rename the existing string test for clarity and add tests covering object shapes ({ id, label } and { id, name }) to verify label/name rendering and computed initials. Keeps the existing null case test intact.
Add a test to ensure the engineer section is hidden when assignedEngineer is null/undefined and verify Manage case status and status label remain visible. Rename/adjust the existing loading test to cover the isLoading state with an assigned engineer (checks skeletons while retaining action elements). Minor test cleanup and rendering updates with ThemeProvider.
Change AssignedEngineerDisplay prop to use AssignedEngineerValue from @utils/support for stronger typing. Update the CaseDetailsDetailsPanel test: rename the test to reflect hiding the Assigned Engineer when null and add an assertion that the "Assigned Engineer" label is not rendered when the value is null.
Guard rendering of Assigned Engineer UI using getAssignedEngineerLabel. Adds conditional checks in CaseDetailsDetailsPanel (both blocks) to skip the Assigned Engineer section when no engineer is set. In CaseDetailsActionRow, the assignedEngineer prop type was updated to AssignedEngineerValue and hasEngineer is derived via getAssignedEngineerLabel; the avatar, name, role caption and divider are now rendered only if an engineer exists while still showing loading skeletons as needed. This avoids empty/placeholder UI when no engineer is assigned.
Replace inline assignedEngineer parsing in OutstandingCasesList with getAssignedEngineerLabel and import it. Update unit test and mock data to use a consistent assignedEngineer object ({id, label}) across CaseListItem entries, and set mockCaseDetails.assignedEngineer to an object as well. These changes standardize the assignedEngineer shape and simplify rendering/tooltip logic.
Add unit tests to cover object-shaped inputs for support utils: formatValue now has tests for { id, label } and { id, name } shapes (including empty label/name -> "--"). getInitials gains tests to derive initials from those same object shapes. Also minor formatting cleanup in richTextEditor.test.ts (reflow expect call).
Update types and utilities to handle assignedEngineer being either a string or an object ({ id, label?, name? }).

- models/responses.ts: broaden assignedEngineer types in CaseListItem and CaseDetails to accept objects with optional label or name.
- utils/support.ts: add AssignedEngineerValue type, getAssignedEngineerDisplayValue helper, and getAssignedEngineerLabel. Update formatValue and getInitials to extract display text from assignedEngineer objects and fall back to "--" for empty values.

This ensures robust display/initials extraction for API responses that return either strings or {id,label} / {id,name} objects.
@coderabbitai

coderabbitai Bot commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR refactors how the assignedEngineer field is handled across the customer portal webapp. It introduces a new structured object type to replace string-only representation, updates utility functions to handle both string and object formats, modifies components to use new helper functions for consistent display, and updates corresponding tests and mock data.

Changes

Cohort / File(s) Summary
Type System & Core Utilities
apps/customer-portal/webapp/src/models/responses.ts, apps/customer-portal/webapp/src/utils/support.ts
Updated assignedEngineer field in CaseListItem and CaseDetails to accept string | { id: string; label?: string; name?: string } | null. Added AssignedEngineerValue type, getAssignedEngineerLabel() helper, and expanded formatValue() and getInitials() to handle object structures.
Case List Components
apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesList.tsx, apps/customer-portal/webapp/src/components/support/all-cases/AllCasesList.tsx, apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx
Replaced inline engineer label extraction with getAssignedEngineerLabel() utility calls. Updated to use formatValue() and getInitials() for consistent display handling.
Case Details Components
apps/customer-portal/webapp/src/components/support/case-details/details-tab/AssignedEngineerDisplay.tsx, apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx, apps/customer-portal/webapp/src/components/support/case-details/header/CaseDetailsActionRow.tsx
Updated props to accept AssignedEngineerValue. Added conditional rendering based on getAssignedEngineerLabel() results. Refactored avatar, label, and display logic to handle object and string representations.
Component Tests
apps/customer-portal/webapp/src/components/.../\_\_tests\_\_/*.test.tsx, apps/customer-portal/webapp/src/utils/\_\_tests\_\_/support.test.ts
Extended test coverage for object shapes { id, label } and { id, name }. Updated AssignedEngineerDisplay.test.tsx and CaseDetailsActionRow.test.tsx to validate new rendering behavior. Added utility tests for formatValue() and getInitials() with object inputs.
Mock Data & Utilities
apps/customer-portal/webapp/src/models/mockData.ts, apps/customer-portal/webapp/src/utils/\_\_tests\_\_/richTextEditor.test.ts
Updated mock assignedEngineer values from strings to objects with id and label/name properties. Reformatted richTextEditor test assertion without logic changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

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

Suggested reviewers

  • Rashmika998
  • shayanmalinda
  • v15a1

Poem

🐰 A hop through helpers, from string to shape,
Engineers now wear their objects with grace,
Labels and names in the code dance free,
Initials and values unified, you see!
The portal now speaks in a cleaner refrain,
No more tangled logic, just clarity's reign. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is well-structured and covers key changes, but does not follow the required template sections (Purpose, Goals, Approach, User stories, Release note, Documentation, etc.). Update the description to follow the repository's required template structure, including sections for Purpose, Goals, Approach, Release note, Documentation, Testing, and other applicable sections.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: standardizing the assigned engineer data model and UI display logic across the customer portal.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into customer-portal-milestone-1

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 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.

@dileepapeiris dileepapeiris self-assigned this Feb 16, 2026
@dileepapeiris dileepapeiris changed the title Feat/fix case dfetails page [Customer Portal][FE][Web] Standardize Assigned Engineer Data Model and UI Display Logic Feb 16, 2026

@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.

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/components/support/support-overview-cards/__tests__/OutstandingCasesList.test.tsx (1)

22-25: ⚠️ Potential issue | 🔴 Critical

Incomplete mock — getAssignedEngineerLabel and resolveColorFromTheme are missing.

The vi.mock("@utils/support", ...) factory only provides formatRelativeTime and stripHtml. The component also imports and calls getAssignedEngineerLabel (line 161) and resolveColorFromTheme (line 77), which will be undefined under this mock, causing the test to fail at runtime.

Either include all used exports in the mock factory, or use importOriginal to preserve un-mocked exports:

🐛 Proposed fix using importOriginal
-vi.mock("@utils/support", () => ({
-  formatRelativeTime: vi.fn(() => "2 hours ago"),
-  stripHtml: vi.fn((html) => html),
-}));
+vi.mock("@utils/support", async (importOriginal) => {
+  const actual = await importOriginal<typeof import("@utils/support")>();
+  return {
+    ...actual,
+    formatRelativeTime: vi.fn(() => "2 hours ago"),
+    stripHtml: vi.fn((html: string) => html),
+  };
+});
🧹 Nitpick comments (5)
apps/customer-portal/webapp/src/utils/__tests__/support.test.ts (1)

431-442: Consider adding a direct test for getAssignedEngineerLabel.

getAssignedEngineerLabel is exported and used by multiple components (e.g., CaseDetailsActionRow, AllCasesList, OutstandingCasesList) but has no direct test coverage here — it's only indirectly exercised through formatValue and getInitials. A few targeted assertions (string input, object with label, object with name only, null) would strengthen confidence.

apps/customer-portal/webapp/src/models/mockData.ts (1)

1462-1465: mockCaseDetails uses { id, name } shape — consistent with CaseDetails API.

Note that name: "dileepapp@wso2.com" will cause getInitials to return "D" (single initial from email). This is fine for mock/demo purposes, but worth noting that if the real API returns emails as names, the initials display may not be user-friendly (e.g., avatar shows "D" instead of meaningful initials).

apps/customer-portal/webapp/src/components/support/case-details/details-tab/__tests__/AssignedEngineerDisplay.test.tsx (1)

38-48: Good coverage of the new object shapes.

The new tests for { id, label } and { id, name } variants align well with the AssignedEngineerValue type. Consider also adding a test for the edge case { id: "eng-1" } (object with neither label nor name) to verify fallback behavior.

apps/customer-portal/webapp/src/components/support/case-details/header/CaseDetailsActionRow.tsx (2)

36-41: Merge type and value imports from the same module.

Minor nit: the type import and value imports from @utils/support can be consolidated into a single import statement.

Proposed merge
-import type { AssignedEngineerValue } from "@utils/support";
-import {
-  formatValue,
-  getAssignedEngineerLabel,
-  getAvailableCaseActions,
-} from "@utils/support";
+import {
+  type AssignedEngineerValue,
+  formatValue,
+  getAssignedEngineerLabel,
+  getAvailableCaseActions,
+} from "@utils/support";

66-68: Remove redundant engineerInitials prop and compute internally.

The caller (CaseDetailsContent.tsx) already computes engineerInitials = getInitials(assignedEngineer) before passing it. Since getInitials can accept the same AssignedEngineerValue type, derive initials internally within the component instead of accepting it as a prop. This prevents inconsistency and reduces prop surface area. Will require importing getInitials from @utils/support and updating tests.

Copilot AI 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.

Pull request overview

This PR standardizes how “assigned engineer” data coming from the support/cases APIs is represented and rendered across the customer portal UI by introducing a shared AssignedEngineerValue type plus helper utilities for label/initial extraction, then refactoring components and tests to use them.

Changes:

  • Added AssignedEngineerValue along with getAssignedEngineerLabel, and expanded formatValue/getInitials to support assigned-engineer objects.
  • Refactored multiple UI surfaces (case lists + case details) to consistently display/hide assigned engineer information based on the derived label.
  • Updated mock data and tests to use the new assigned engineer object shape and added/updated test cases accordingly.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
apps/customer-portal/webapp/src/utils/support.ts Introduces AssignedEngineerValue and shared helpers for label/initials + extends formatValue/getInitials.
apps/customer-portal/webapp/src/utils/tests/support.test.ts Adds tests for assigned engineer object handling in formatValue/getInitials.
apps/customer-portal/webapp/src/utils/tests/richTextEditor.test.ts Minor test formatting change.
apps/customer-portal/webapp/src/models/responses.ts Updates response typings for assignedEngineer to allow { id, label?, name? }.
apps/customer-portal/webapp/src/models/mockData.ts Updates mock case data to use the assigned engineer object shape.
apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx Uses getAssignedEngineerLabel to render “Assigned to …” consistently.
apps/customer-portal/webapp/src/components/support/support-overview-cards/tests/OutstandingCasesList.test.tsx Updates mocks to the assigned engineer object shape.
apps/customer-portal/webapp/src/components/support/case-details/header/CaseDetailsActionRow.tsx Hides the engineer section when no engineer label is present; adopts AssignedEngineerValue.
apps/customer-portal/webapp/src/components/support/case-details/header/tests/CaseDetailsActionRow.test.tsx Updates expectations to match new hide/show behavior.
apps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsx Conditionally renders “Assigned Engineer” blocks using getAssignedEngineerLabel.
apps/customer-portal/webapp/src/components/support/case-details/details-tab/tests/CaseDetailsDetailsPanel.test.tsx Updates assertions to validate assigned engineer section hiding.
apps/customer-portal/webapp/src/components/support/case-details/details-tab/AssignedEngineerDisplay.tsx Updates prop type to AssignedEngineerValue and relies on shared formatting/initials helpers.
apps/customer-portal/webapp/src/components/support/case-details/details-tab/tests/AssignedEngineerDisplay.test.tsx Adds coverage for string vs {id,label} vs {id,name} assigned engineer inputs.
apps/customer-portal/webapp/src/components/support/all-cases/AllCasesList.tsx Uses getAssignedEngineerLabel instead of ad-hoc parsing.
apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesList.tsx Uses getInitials/formatValue for assigned engineer rendering in the dashboard table.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/customer-portal/webapp/src/utils/support.ts
Comment thread apps/customer-portal/webapp/src/utils/__tests__/support.test.ts
@dileepapeiris dileepapeiris added Type/New Feature Represents a request or task for a new feature Type/Improvement Marks enhancements or improvements to existing features Type/UX Refers to user experience-related tasks or issues App/Customer Portal Area/Frontend Platform/Web labels Feb 16, 2026
@dileepapeiris dileepapeiris moved this from Todo to Done in Customer Portal Development Feb 16, 2026
* @param value - Assigned engineer from API.
* @returns {string} Display label or empty string if null/undefined.
*/
export function getAssignedEngineerLabel(value: AssignedEngineerValue): string {

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.

@dileepapeiris is getAssignedEngineerLabel used to render components? If so are you using an empty string comparison (e.g., getAssignedEngineerLabel(someValue) === "" && <Component />)?

* @returns {string} Display string.
*/
export function formatValue(value: string | number | null | undefined): string {
export function formatValue(

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.

I think we can make this:

export function formatValue(
  value: AssignedEngineerValue | number,
): string {

Check and verify this later. Safer if and when the AssignedEngineerValue object structure changes

const initials = name
export function getInitials(
name:
| string

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.

ditto, use the predefined object if applicable

@dileepapeiris

Copy link
Copy Markdown
Contributor Author

Those changes will be addressed in upcoming PRs

@v15a1 v15a1 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.

As discussed offline, the suggested changes will be addressed in upcoming PRs. LGTM

@v15a1
v15a1 merged commit efeb64c into wso2-open-operations:customer-portal-milestone-1 Feb 16, 2026
6 of 7 checks passed
@dileepapeiris dileepapeiris moved this from Done to Staging Deployed in Customer Portal Development Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

App/Customer Portal Area/Frontend Platform/Web Type/Improvement Marks enhancements or improvements to existing features Type/New Feature Represents a request or task for a new feature Type/UX Refers to user experience-related tasks or issues

Projects

Status: Staging Deployed

Development

Successfully merging this pull request may close these issues.

3 participants