Skip to content

[Customer Portal][FE][Web] Enhance Markdown Rendering and Case Activity Timeline with Better Error Handling - #519

Merged
Rashmika998 merged 11 commits into
wso2-open-operations:dev-app-customer-portalfrom
dileepapeiris:idle-timer
Apr 20, 2026
Merged

Rashmika998 merged 11 commits into
wso2-open-operations:dev-app-customer-portalfrom
dileepapeiris:idle-timer

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor

Description

This pull request introduces support for GitHub Flavored Markdown (GFM) rendering in the customer portal webapp and improves error handling in the support case activity panel. The main changes include adding the remark-gfm package and its dependencies, and refactoring the CaseDetailsActivityPanel to merge conversation messages with case comments and handle API errors more consistently.

image image

Markdown rendering enhancements:

  • Added the remark-gfm package to package.json and updated pnpm-lock.yaml to include remark-gfm and all required dependencies for GitHub Flavored Markdown support. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]

Support case activity panel improvements:

  • Refactored CaseDetailsActivityPanel to merge both case comments and conversation messages into a single, chronologically ordered timeline, improving the completeness of the activity feed. [1] [2]
  • Updated loading and error state handling in CaseDetailsActivityPanel to show a consistent error UI using the new ApiErrorState component. [1] [2] [3]

Error handling:

  • Added a new ApiErrorState component to standardize API error display across the app, with support for 401, 403, and 500 errors.

These changes lay the groundwork for improved Markdown rendering in the UI and provide a more robust and user-friendly experience when loading support case activities.

Summary by CodeRabbit

  • New Features

    • Added markdown formatting support (including tables, links, and GitHub-flavored markdown) for chat messages and case comments.
    • Integrated conversation message history alongside case comments in activity views.
    • Enhanced error display states with detailed error information across support pages.
  • Chores

    • Added remark-gfm dependency for markdown processing.

Introduce throwIfApiNotOk(response, fallbackMessage) to throw an ApiError for non-OK fetch responses while preserving any backend-provided message. The helper clones and attempts to parse the JSON body to extract a string `message`, falls back to a composed message when absent, and returns silently for OK responses.
Add remark-gfm@^4.0.1 to apps/customer-portal/webapp/package.json to enable GitHub Flavored Markdown (GFM) support for react-markdown in the customer portal webapp.
Short-circuits SupportPage rendering on API errors by aggregating hook errors (stats/cases/conversations) and rendering ApiErrorState with a fallback message. Refactors CaseDetails.conversation from unknown to IdLabelRef|null and exposes error or conversationId props across several support component prop types (CaseDetailsDetailsPanelProps, CallsPanelProps, CaseDetailsContentProps, CaseDetailsTabPanelsProps, CaseDetailsActivityPanelProps). Also adds optional markdown props to ChatMessageCardProps (markdownContent, renderAsMarkdown) to support rendering message content. These changes improve error handling and type-safety for support UI components.
Introduce ApiErrorState component (apps/customer-portal/webapp/src/components/error/ApiErrorState.tsx) to provide a consistent API error UI for support pages and panels. It dispatches to Error401Page and Error403Page for unauthorized/forbidden errors using helpers from @utils/ApiError, and falls back to a 500-style view with a customizable message and container styling. Includes license header and typed props for error, fallbackMessage, and containerSx.
Merge conversation messages into case activity timeline and improve rendering and error handling. Added useGetConversationMessages and merged its comments with case comments (sorted by createdOn/id). Updated loading/error logic to consider conversation fetches and surface API errors using ApiErrorState. ChatMessageCard now supports rendering markdown (ReactMarkdown + remark-gfm) with safe link handling and table styling; CommentBubble selects bot/‘novera’ comments to render as markdown. Attachments and calls panels now display ApiErrorState on errors; CallsErrorState was refactored to accept an error prop. Miscellaneous styling tweaks for message content.
Replace inline error UIs with ApiErrorState across support components and pages: ConversationKnowledgeRecommendations and ConversationDetailsPage now import and render ApiErrorState, and data-fetch hooks have their `error` returned and forwarded where needed (also passed into CaseDetailsPage child). Add GitHub Flavored Markdown table support in ChatMessageBubble by importing remark-gfm, registering it with ReactMarkdown, and adding styled table/thead/tbody/tr/th/td renderers with responsive scrolling.
Replace custom error UI (Error500Page and inline markup) with ApiErrorState across case details components. Add an early return in CaseDetailsContent to render ApiErrorState when isError and error are present, and thread the error prop through CaseDetailsTabPanels to CaseDetailsDetailsPanel, CaseDetailsActivityPanel (also passing conversationId), and CallsPanel so they can render consistent API error states.
Update pnpm-lock.yaml to include remark-gfm and its associated GitHub-Flavored-Markdown packages and lock metadata. Changes add remark-gfm to importers and add related packages (remark-stringify, mdast-util-gfm and helpers, micromark GFM extensions, markdown-table, escape-string-regexp, etc.) along with their snapshots and dependency entries so the lockfile reflects the new GFM processing dependencies. No source files were modified.
Delete the throwIfApiNotOk helper from ApiError.ts. This removes the function that parsed Response bodies and threw an ApiError for non-OK fetch responses; callers should rely on existing error utilities (e.g. getApiErrorMessage) or implement alternative handling.
@coderabbitai

coderabbitai Bot commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces Markdown/GFM rendering support and unified error handling across the support portal. A new ApiErrorState component replaces inline error UI, the remark-gfm library enables GitHub-flavored markdown in chat, and error objects are propagated through component hierarchies alongside boolean flags. Chat messages conditionally render markdown or HTML based on source type, and conversation context is threaded into activity panels.

Changes

Cohort / File(s) Summary
Dependency & Core Error Component
apps/customer-portal/webapp/package.json, apps/customer-portal/webapp/src/components/error/ApiErrorState.tsx
Added remark-gfm dependency and created new ApiErrorState component for consistent error UI display with optional error objects and fallback messages.
Markdown Rendering in Chat
apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx, CommentBubble.tsx, apps/customer-portal/webapp/src/features/support/components/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsx
Added markdown rendering support with remark-gfm, conditional rendering logic based on source type, custom table/link component mappings, and GFM-specific styling.
Error State Refactoring
apps/customer-portal/webapp/src/features/support/components/case-details/calls-tab/CallsErrorState.tsx, apps/customer-portal/webapp/src/features/support/components/case-details/attachments-tab/CaseDetailsAttachmentsPanel.tsx, apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsDetailsPanel.tsx, apps/customer-portal/webapp/src/features/support/components/knowledge-base/ConversationKnowledgeRecommendations.tsx, apps/customer-portal/webapp/src/features/support/pages/ConversationDetailsPage.tsx, apps/customer-portal/webapp/src/features/support/pages/SupportPage.tsx
Replaced generic error messages with ApiErrorState, added error object destructuring from hooks, and enabled detailed error UI rendering.
Activity Panel Conversation Support
apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CaseDetailsActivityPanel.tsx
Added conversationId prop, integrated dual data fetching (case comments + conversation messages), merged timelines with field normalization, and updated loading/error control flow.
Error Propagation Infrastructure
apps/customer-portal/webapp/src/features/support/components/case-details/header/CaseDetailsTabPanels.tsx, apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsContent.tsx, apps/customer-portal/webapp/src/features/support/pages/CaseDetailsPage.tsx, apps/customer-portal/webapp/src/features/support/calls-tab/CallsPanel.tsx
Threaded error objects through component hierarchy, added early error-return paths, extracted conversationId from case data, and forwarded error context to child panels.
Type Definitions
apps/customer-portal/webapp/src/features/support/types/cases.ts, apps/customer-portal/webapp/src/features/support/types/supportComponents.ts
Updated CaseDetails.conversation type from unknown to IdLabelRef | null and extended component prop types with optional error, markdownContent, renderAsMarkdown, and conversationId fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

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

Suggested reviewers

  • Rashmika998
  • cloby99
  • v15a1

Poem

🐰 A markdown journey, oh what a sight!
GFM tables rendering just right,
Errors now caught with graceful display,
Conversations flow in a cleaner way,
From chat to case, the support flows bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides context and implementation details but lacks several required template sections and specificity in others. Add missing sections: Purpose/Goals should clearly state resolved issues with links, Approach should detail implementation strategy, User stories and Release notes should be specific, Documentation/Training/Certification/Marketing/Automation/Security/Samples/Migrations sections need completion or N/A explanations.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: Markdown rendering enhancements and improved error handling with a unified ApiErrorState component.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% 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 unit tests (beta)
  • Create PR with unit tests

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 changed the title Idle timer [Customer Portal][FE][Web] Enhance Markdown Rendering and Case Activity Timeline with Better Error Handling Apr 20, 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.

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 (3)
apps/customer-portal/webapp/src/features/support/pages/CaseDetailsPage.tsx (1)

71-134: ⚠️ Potential issue | 🟡 Minor

Possible duplicate error surfacing.

error is now passed into CaseDetailsContent, which (per the snippet at CaseDetailsContent.tsx:210-221) will render ApiErrorState in-page on isError && error. Meanwhile the existing useEffect at lines 71–80 still calls showError("Could not load case details."), so users see both the full-page 401/403/500 error state and a toast/banner for the same failure. Consider dropping the banner (or suppressing it when ApiErrorState will render) to avoid the duplicate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/customer-portal/webapp/src/features/support/pages/CaseDetailsPage.tsx`
around lines 71 - 134, The page currently shows both an in-page ApiErrorState
and a toast/banners by calling showError from the useEffect; update the
useEffect that checks isError to only call showError when the in-page error
component (CaseDetailsContent -> ApiErrorState) will NOT render (i.e., suppress
the banner when error is present). Concretely, modify the useEffect around
useEffect(() => { ... }, [isError, showError]) to check error (the same error
prop passed into CaseDetailsContent) and only call showError("Could not load
case details.") when isError is true and error is falsy (or when the conditions
for ApiErrorState are false), so you no longer surface duplicate error UI
between useEffect/showError and CaseDetailsContent -> ApiErrorState.
apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsContent.tsx (1)

210-235: ⚠️ Potential issue | 🔴 Critical

Move the new error return below the remaining hook.

Line 210 now returns before the useEffect on Line 223. If isError && error changes between renders, this component calls fewer hooks and can crash with React’s hook-order error. Keep all hooks before conditional returns.

🐛 Proposed fix
-  if (isError && error) {
-    return (
-      <ApiErrorState
-        error={error}
-        fallbackMessage={
-          isServiceRequest
-            ? "Failed to load service request details."
-            : "Failed to load case details."
-        }
-      />
-    );
-  }
-
   useEffect(() => {
     if (!suppressFloatingNoveraOnActivityTab) {
       return;
     }
@@
     setHideForDetailsActivityTab,
   ]);
+
+  if (isError && error) {
+    return (
+      <ApiErrorState
+        error={error}
+        fallbackMessage={
+          isServiceRequest
+            ? "Failed to load service request details."
+            : "Failed to load case details."
+        }
+      />
+    );
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsContent.tsx`
around lines 210 - 235, The early return that renders ApiErrorState when isError
&& error is currently placed before the useEffect hook, which can change hook
order across renders; move the conditional block that returns the ApiErrorState
(the check using isError and error and the ApiErrorState component) so that all
hooks (including the useEffect that references
suppressFloatingNoveraOnActivityTab, resolvedPanelIndex, and
setHideForDetailsActivityTab) are declared first, and only after those hooks run
perform the conditional return; ensure references to ApiErrorState and the
existing fallbackMessage logic remain unchanged.
apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx (1)

119-140: ⚠️ Potential issue | 🟡 Minor

Make markdown-rendered image previews keyboard-accessible.

Markdown can now render images into the same preview flow, but preview activation is still click-only and images are not focusable. Add delegated keydown handling for Enter/Space plus tabIndex, role, and an accessible label on rendered images. Based on learnings, the ChatMessageCard image fullscreen preview is pointer-only and should add delegated handleKeyDown, tabIndex=0, role="button", aria-label, and cleanup.

Also applies to: 221-229, 260-263

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx`
around lines 119 - 140, The click-only image preview needs keyboard
accessibility: add a delegated handleKeyDown alongside handleClick that listens
on contentRef for keydown events and, when event.target is an HTMLImageElement
and key is Enter or Space, prevents default and calls onImageClick with the
image src; also ensure rendered images get tabIndex=0, role="button" and an
aria-label (e.g., "Open image preview") at render time (update the markdown
image renderer or any render path that outputs <img>), and register/unregister
the keydown listener in the same useEffect cleanup as handleClick (update
references: handleClick, handleKeyDown, contentRef, onImageClick). Apply the
same delegated keydown + attribute changes to other image-rendering handlers
mentioned (the other markdown/render paths).
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/features/support/pages/ConversationDetailsPage.tsx (1)

281-286: Nit: redundant wrapper around ApiErrorState.

ApiErrorState already applies centered layout with py: 4 internally; the surrounding <Box sx={{ textAlign: "center", py: 6 }}> double-pads the error and may visually conflict with the 401/403 full-page variants that ApiErrorState can render. Consider dropping the wrapper (or moving to containerSx on ApiErrorState).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/features/support/pages/ConversationDetailsPage.tsx`
around lines 281 - 286, Remove the redundant Box wrapper around ApiErrorState in
ConversationDetailsPage: ApiErrorState already centers and applies internal
padding, so delete the surrounding <Box sx={{ textAlign: "center", py: 6 }}> (or
instead pass any needed styling via ApiErrorState's containerSx prop) to avoid
double padding and preserve correct full-page 401/403 variants.
apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx (1)

265-265: Add JSDoc documentation to htmlContent parameter requiring pre-sanitization.

The component accepts htmlContent without sanitizing it internally. While the only current call site (CommentBubble) sanitizes before passing, document the pre-sanitization requirement to prevent future unsafe usage.

Add a note to the JSDoc for ChatMessageCardProps clarifying that htmlContent must be sanitized by the caller before passing to ChatMessageCard (e.g., with DOMPurify).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx`
at line 265, Add JSDoc to the ChatMessageCardProps interface documenting that
the htmlContent prop passed into ChatMessageCard must be sanitized by the caller
(e.g., with DOMPurify) before use; update the JSDoc to mention that
ChatMessageCard uses dangerouslySetInnerHTML and does not perform sanitization
itself, and reference typical caller CommentBubble as an example of where
sanitization should occur so future callers know the precondition.
🤖 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/components/error/ApiErrorState.tsx`:
- Around line 45-58: ApiErrorState is inconsistenly applying containerSx: the
401/403 branches render Error401Page/Error403Page without applying containerSx
and the 500 branch uses object spread which can drop SxProps like
functions/arrays. Update ApiErrorState so all error branches pass the merged sx
using MUI's array form (e.g., sx={[ baseSx, containerSx ]}) instead of
{...containerSx}; specifically, when rendering Error401Page and Error403Page add
an sx prop that merges the same base Stack styles (py: 4 and any other container
base styles) with containerSx using an array, and replace the object spread in
the main Stack return with the same array-based sx merging.

In `@apps/customer-portal/webapp/src/features/support/pages/SupportPage.tsx`:
- Around line 133-141: The current early-return uses supportPageError =
statsError ?? casesError ?? chatError which hides healthy sections; revert to
per-card error handling by removing the early return around ApiErrorState so
CasesOverviewStatCard and SupportOverviewCard continue to receive their isError
/ isCasesError / isChatError props and render section-level errors;
alternatively, if you prefer a short-circuit, change the logic to only treat the
page as failed when all sub-queries fail (supportPageError = statsError &&
casesError && chatError) and only promote to ApiErrorState for auth failures
coming from the primary stats query (check statsError.isUnauthorizedError /
isForbiddenError before returning ApiErrorState).

---

Outside diff comments:
In
`@apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx`:
- Around line 119-140: The click-only image preview needs keyboard
accessibility: add a delegated handleKeyDown alongside handleClick that listens
on contentRef for keydown events and, when event.target is an HTMLImageElement
and key is Enter or Space, prevents default and calls onImageClick with the
image src; also ensure rendered images get tabIndex=0, role="button" and an
aria-label (e.g., "Open image preview") at render time (update the markdown
image renderer or any render path that outputs <img>), and register/unregister
the keydown listener in the same useEffect cleanup as handleClick (update
references: handleClick, handleKeyDown, contentRef, onImageClick). Apply the
same delegated keydown + attribute changes to other image-rendering handlers
mentioned (the other markdown/render paths).

In
`@apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsContent.tsx`:
- Around line 210-235: The early return that renders ApiErrorState when isError
&& error is currently placed before the useEffect hook, which can change hook
order across renders; move the conditional block that returns the ApiErrorState
(the check using isError and error and the ApiErrorState component) so that all
hooks (including the useEffect that references
suppressFloatingNoveraOnActivityTab, resolvedPanelIndex, and
setHideForDetailsActivityTab) are declared first, and only after those hooks run
perform the conditional return; ensure references to ApiErrorState and the
existing fallbackMessage logic remain unchanged.

In `@apps/customer-portal/webapp/src/features/support/pages/CaseDetailsPage.tsx`:
- Around line 71-134: The page currently shows both an in-page ApiErrorState and
a toast/banners by calling showError from the useEffect; update the useEffect
that checks isError to only call showError when the in-page error component
(CaseDetailsContent -> ApiErrorState) will NOT render (i.e., suppress the banner
when error is present). Concretely, modify the useEffect around useEffect(() =>
{ ... }, [isError, showError]) to check error (the same error prop passed into
CaseDetailsContent) and only call showError("Could not load case details.") when
isError is true and error is falsy (or when the conditions for ApiErrorState are
false), so you no longer surface duplicate error UI between useEffect/showError
and CaseDetailsContent -> ApiErrorState.

---

Nitpick comments:
In
`@apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx`:
- Line 265: Add JSDoc to the ChatMessageCardProps interface documenting that the
htmlContent prop passed into ChatMessageCard must be sanitized by the caller
(e.g., with DOMPurify) before use; update the JSDoc to mention that
ChatMessageCard uses dangerouslySetInnerHTML and does not perform sanitization
itself, and reference typical caller CommentBubble as an example of where
sanitization should occur so future callers know the precondition.

In
`@apps/customer-portal/webapp/src/features/support/pages/ConversationDetailsPage.tsx`:
- Around line 281-286: Remove the redundant Box wrapper around ApiErrorState in
ConversationDetailsPage: ApiErrorState already centers and applies internal
padding, so delete the surrounding <Box sx={{ textAlign: "center", py: 6 }}> (or
instead pass any needed styling via ApiErrorState's containerSx prop) to avoid
double padding and preserve correct full-page 401/403 variants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3d740d4-371d-4bec-8434-acd870846c30

📥 Commits

Reviewing files that changed from the base of the PR and between bac9160 and db3ffdb.

⛔ Files ignored due to path filters (1)
  • apps/customer-portal/webapp/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • apps/customer-portal/webapp/package.json
  • apps/customer-portal/webapp/src/components/error/ApiErrorState.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CaseDetailsActivityPanel.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/ChatMessageCard.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CommentBubble.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/attachments-tab/CaseDetailsAttachmentsPanel.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/calls-tab/CallsErrorState.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/calls-tab/CallsPanel.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsContent.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/details-tab/CaseDetailsDetailsPanel.tsx
  • apps/customer-portal/webapp/src/features/support/components/case-details/header/CaseDetailsTabPanels.tsx
  • apps/customer-portal/webapp/src/features/support/components/knowledge-base/ConversationKnowledgeRecommendations.tsx
  • apps/customer-portal/webapp/src/features/support/components/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsx
  • apps/customer-portal/webapp/src/features/support/pages/CaseDetailsPage.tsx
  • apps/customer-portal/webapp/src/features/support/pages/ConversationDetailsPage.tsx
  • apps/customer-portal/webapp/src/features/support/pages/SupportPage.tsx
  • apps/customer-portal/webapp/src/features/support/types/cases.ts
  • apps/customer-portal/webapp/src/features/support/types/supportComponents.ts

Comment thread apps/customer-portal/webapp/src/components/error/ApiErrorState.tsx Outdated
Comment thread apps/customer-portal/webapp/src/features/support/pages/SupportPage.tsx Outdated
Refactor error presentation and enhance image accessibility across support pages.

- ApiErrorState: normalize container styling by merging base SxProps and wrap 401/403/error pages in a Stack for consistent layout.
- ChatMessageCard: add markdown img renderer and set keyboard/ARIA attributes (tabindex, role, aria-label) for images; add keydown handler to open image preview on Enter/Space and a helper to set attributes for existing images.
- CaseDetailsContent: relocate ApiErrorState return to avoid interfering with existing effects/run order.
- CaseDetailsPage: avoid showing a duplicate banner when an in-page ApiErrorState is present by short-circuiting error notification and adding `error` to effect deps.
- ConversationDetailsPage: remove redundant centering wrapper around ApiErrorState.
- SupportPage: remove the global early ApiErrorState fallback to rely on component-level error handling.

These changes improve a11y for inline images and unify how API errors are displayed to reduce duplicate notifications and layout inconsistencies.
@dileepapeiris dileepapeiris self-assigned this Apr 20, 2026
@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/Task General task that does not fit into other categories Type/UX Refers to user experience-related tasks or issues App/Customer Portal Area/Frontend Platform/Web labels Apr 20, 2026
@Rashmika998
Rashmika998 merged commit a8e6da5 into wso2-open-operations:dev-app-customer-portal Apr 20, 2026
1 check passed
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/Task General task that does not fit into other categories Type/UX Refers to user experience-related tasks or issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants