From ccd173247ce17e8fc60d5e2cf47d322040e5857f Mon Sep 17 00:00:00 2001 From: "K.Dileepa Thushan Peiris" Date: Tue, 17 Feb 2026 10:36:07 +0530 Subject: [PATCH 1/8] Comment out unused app shell nav items Temporarily comment out several navigation items in apps/customer-portal/webapp/src/constants/appLayoutConstants.ts (engagements, legal-contracts, and community). This hides these entries from the app shell navigation (wrapped in a block comment) while those features or labels are pending changes or cleanup. --- .../webapp/src/constants/appLayoutConstants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/customer-portal/webapp/src/constants/appLayoutConstants.ts b/apps/customer-portal/webapp/src/constants/appLayoutConstants.ts index 1b05abdb16..7c7c587b0d 100644 --- a/apps/customer-portal/webapp/src/constants/appLayoutConstants.ts +++ b/apps/customer-portal/webapp/src/constants/appLayoutConstants.ts @@ -51,7 +51,7 @@ export const APP_SHELL_NAV_ITEMS: AppShellNavItem[] = [ path: "security-center", icon: Shield, }, - { + /* { id: "engagements", label: "Engagements", path: "engagements", @@ -63,7 +63,7 @@ export const APP_SHELL_NAV_ITEMS: AppShellNavItem[] = [ path: "legal-contracts", icon: FileText, }, - { id: "community", label: "Community", path: "community", icon: Users }, + { id: "community", label: "Community", path: "community", icon: Users }, */ { id: "announcements", label: "Announcements", From 688f01d287510f03151ec61ed056d334c2b13d45 Mon Sep 17 00:00:00 2001 From: "K.Dileepa Thushan Peiris" Date: Tue, 17 Feb 2026 10:36:17 +0530 Subject: [PATCH 2/8] Remove border and shadow styles from ChatMessageCard Remove explicit `border`, `borderRadius`, and `boxShadow` overrides from the ChatMessageCard Box styles in apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ChatMessageCard.tsx. This cleans up styling so the component uses the theme/default container styles instead of forced overrides, improving visual consistency and simplifying the component. --- .../support/case-details/activity-tab/ChatMessageCard.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ChatMessageCard.tsx b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ChatMessageCard.tsx index 4b673dadb5..8c06151bc0 100644 --- a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ChatMessageCard.tsx +++ b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ChatMessageCard.tsx @@ -56,9 +56,6 @@ export default function ChatMessageCard({ p: 1.5, maxWidth: "100%", bgcolor: isCurrentUser ? primaryBg : "background.paper", - border: "none", - borderRadius: 0, - boxShadow: "none", }} > Date: Tue, 17 Feb 2026 10:36:27 +0530 Subject: [PATCH 3/8] Replace comment TextField with rich-text Editor Swap the plain TextField for the rich-text Editor component to allow formatted comments. Add a resetTrigger state to clear the editor after a successful post and adjust the empty-check to treat HTML placeholders (e.g. "


") as empty. Move layout to a column with the Editor in a relative box and overlay the send IconButton in the bottom-right with updated styling. Preserve pending state visuals with CircularProgress and keep authentication/disabled logic intact. Also tidy imports to remove TextField and add Editor. --- .../activity-tab/ActivityCommentInput.tsx | 92 +++++++++++-------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx index 850c3a56af..979c39c985 100644 --- a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx +++ b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx @@ -14,17 +14,13 @@ // specific language governing permissions and limitations // under the License. -import { - Box, - CircularProgress, - IconButton, - TextField, -} from "@wso2/oxygen-ui"; +import { Box, CircularProgress, IconButton } from "@wso2/oxygen-ui"; import { Send } from "@wso2/oxygen-ui-icons-react"; import { useState } from "react"; import { usePostComment } from "@api/usePostComment"; import { useAsgardeo } from "@asgardeo/react"; import { useErrorBanner } from "@context/error-banner/ErrorBannerContext"; +import Editor from "@components/common/rich-text-editor/Editor"; import type { JSX } from "react"; export interface ActivityCommentInputProps { @@ -32,7 +28,7 @@ export interface ActivityCommentInputProps { } /** - * Fixed (non-scrollable) input row with text field and send button. + * Input row with text field and send button. * Posts comment via usePostComment; on success invalidates and refetches comments. * * @param {ActivityCommentInputProps} props - caseId for POST. @@ -42,6 +38,7 @@ export default function ActivityCommentInput({ caseId, }: ActivityCommentInputProps): JSX.Element { const [value, setValue] = useState(""); + const [resetTrigger, setResetTrigger] = useState(0); const postComment = usePostComment(); const { isSignedIn, isLoading: isAuthLoading } = useAsgardeo(); const { showError } = useErrorBanner(); @@ -49,12 +46,18 @@ export default function ActivityCommentInput({ const isDisabled = !isSignedIn || isAuthLoading || postComment.isPending; const handleSend = () => { - if (!value.trim() || isDisabled) return; - const content = value.trim(); + const trimmedValue = value.trim(); + // Check if it's effectively empty (e.g., "


") + const isEffectivelyEmpty = !trimmedValue || trimmedValue === "


"; + if (isEffectivelyEmpty || isDisabled) return; + postComment.mutate( - { caseId, body: { content } }, + { caseId, body: { content: trimmedValue } }, { - onSuccess: () => setValue(""), + onSuccess: () => { + setValue(""); + setResetTrigger((prev) => prev + 1); + }, onError: (error: unknown) => { const message = error instanceof Error && error.message @@ -70,38 +73,53 @@ export default function ActivityCommentInput({ - setValue(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault(); - handleSend(); - } - }} - /> - - {postComment.isPending ? ( - - ) : ( - - )} - + + + +

" || isDisabled} + onClick={handleSend} + color="warning" + aria-label="Send comment" + sx={{ + bgcolor: "background.paper", + "&:hover": { bgcolor: "action.hover" }, + boxShadow: 1, + width: 32, + height: 32, + }} + > + {postComment.isPending ? ( + + ) : ( + + )} +
+
+
); } From eadbf761e232c13acf513fc321357c1ca14bb75f Mon Sep 17 00:00:00 2001 From: "K.Dileepa Thushan Peiris" Date: Tue, 17 Feb 2026 10:36:35 +0530 Subject: [PATCH 4/8] Disable SubscriptionWidget in sidebar footer Comment out the SubscriptionWidget in SideBar.tsx to remove it from the sidebar footer UI. This temporarily hides the subscription component; re-enable it by uncommenting the line. Affected file: apps/customer-portal/webapp/src/components/common/side-nav-bar/SideBar.tsx. --- .../webapp/src/components/common/side-nav-bar/SideBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/webapp/src/components/common/side-nav-bar/SideBar.tsx b/apps/customer-portal/webapp/src/components/common/side-nav-bar/SideBar.tsx index 30de31530e..f806a9d360 100644 --- a/apps/customer-portal/webapp/src/components/common/side-nav-bar/SideBar.tsx +++ b/apps/customer-portal/webapp/src/components/common/side-nav-bar/SideBar.tsx @@ -80,7 +80,7 @@ export default function SideBar({ {/* sidebar footer items */} - + {/* */} Date: Tue, 17 Feb 2026 10:36:48 +0530 Subject: [PATCH 5/8] Add resetTrigger, minHeight and toolbar toggle Introduce an internal ResetPlugin and a resetTrigger prop to allow externally clearing the editor (editor root is cleared when resetTrigger > 0). Add configurable minHeight (number or string) with proper px conversion and a showToolbar boolean to conditionally render the toolbar and divider. Wire the ResetPlugin into the plugin chain and propagate the new props through the Editor component to support layout and reset control. --- .../common/rich-text-editor/Editor.tsx | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx b/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx index 43f829c0d2..505e1ce942 100644 --- a/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx +++ b/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx @@ -111,6 +111,24 @@ const OnChangeHTMLPlugin = ({ ); }; +/** + * Internal component to handle resetting the editor. + */ +const ResetPlugin = ({ resetTrigger }: { resetTrigger?: number }) => { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + if (resetTrigger !== undefined && resetTrigger > 0) { + editor.update(() => { + const root = $getRoot(); + root.clear(); + }); + } + }, [editor, resetTrigger]); + + return null; +}; + /** Static editor config (namespace, nodes, theme). */ const DEFAULT_EDITOR_CONFIG = { namespace: "MyEditor", @@ -147,6 +165,9 @@ const Editor = ({ disabled = false, value, onChange, + resetTrigger, + minHeight = 150, + showToolbar = true, }: { onAttachmentClick?: () => void; attachments?: File[]; @@ -154,6 +175,9 @@ const Editor = ({ disabled?: boolean; value?: string; onChange?: (html: string) => void; + resetTrigger?: number; + minHeight?: number | string; + showToolbar?: boolean; }): JSX.Element => { const oxygenTheme = useTheme(); const logger = useLogger(); @@ -220,15 +244,23 @@ const Editor = ({ }} > - - + {showToolbar && ( + <> + + + + )} + {attachments.length > 0 && ( <> From 3a348d045ef2dc562662a637eea3063686d2fb8e Mon Sep 17 00:00:00 2001 From: "K.Dileepa Thushan Peiris" Date: Tue, 17 Feb 2026 10:49:56 +0530 Subject: [PATCH 6/8] Clarify ActivityCommentInput editor/reset behavior Update comments in ActivityCommentInput to reflect use of the shared rich-text Editor and that comments are posted via usePostComment. Add an inline note explaining that the local value is reset immediately on success for UI responsiveness, while ResetPlugin will clear the Lexical editor later and OnChangeHTMLPlugin may repopulate the value with an empty paragraph. --- .../case-details/activity-tab/ActivityCommentInput.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx index 979c39c985..2fe01dbcc0 100644 --- a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx +++ b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx @@ -28,8 +28,8 @@ export interface ActivityCommentInputProps { } /** - * Input row with text field and send button. - * Posts comment via usePostComment; on success invalidates and refetches comments. + * Input row with rich-text editor and send button. + * Uses the shared Editor component and posts comments via usePostComment; on success invalidates and refetches comments. * * @param {ActivityCommentInputProps} props - caseId for POST. * @returns {JSX.Element} The comment input component. @@ -55,6 +55,9 @@ export default function ActivityCommentInput({ { caseId, body: { content: trimmedValue } }, { onSuccess: () => { + // Immediately reset the local value state for UI responsiveness. + // ResetPlugin will eventually clear the Lexical editor, which triggers + // OnChangeHTMLPlugin to repopulate this value with an empty paragraph ("


"). setValue(""); setResetTrigger((prev) => prev + 1); }, From 6f18ca1bfba5254b37ab47e73c7ac9d10ef90921 Mon Sep 17 00:00:00 2001 From: "K.Dileepa Thushan Peiris" Date: Tue, 17 Feb 2026 10:52:59 +0530 Subject: [PATCH 7/8] Add Editor placeholder and use in comments Expose a placeholder prop on the rich-text Editor and pass a default prompt from ActivityCommentInput so the comment editor shows "Write a comment...". Also cleaned up a couple of redundant inline comments around empty-content checks and reset behavior. Affects Editor.tsx and ActivityCommentInput.tsx. --- .../webapp/src/components/common/rich-text-editor/Editor.tsx | 1 + .../case-details/activity-tab/ActivityCommentInput.tsx | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx b/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx index 505e1ce942..2de191b91f 100644 --- a/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx +++ b/apps/customer-portal/webapp/src/components/common/rich-text-editor/Editor.tsx @@ -178,6 +178,7 @@ const Editor = ({ resetTrigger?: number; minHeight?: number | string; showToolbar?: boolean; + placeholder?: string; }): JSX.Element => { const oxygenTheme = useTheme(); const logger = useLogger(); diff --git a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx index 2fe01dbcc0..d5cec4cf64 100644 --- a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx +++ b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx @@ -47,7 +47,6 @@ export default function ActivityCommentInput({ const handleSend = () => { const trimmedValue = value.trim(); - // Check if it's effectively empty (e.g., "


") const isEffectivelyEmpty = !trimmedValue || trimmedValue === "


"; if (isEffectivelyEmpty || isDisabled) return; @@ -55,9 +54,6 @@ export default function ActivityCommentInput({ { caseId, body: { content: trimmedValue } }, { onSuccess: () => { - // Immediately reset the local value state for UI responsiveness. - // ResetPlugin will eventually clear the Lexical editor, which triggers - // OnChangeHTMLPlugin to repopulate this value with an empty paragraph ("


"). setValue(""); setResetTrigger((prev) => prev + 1); }, @@ -91,6 +87,7 @@ export default function ActivityCommentInput({ resetTrigger={resetTrigger} minHeight={40} showToolbar={true} + placeholder="Write a comment..." /> Date: Tue, 17 Feb 2026 10:55:40 +0530 Subject: [PATCH 8/8] Use stripHtml to detect empty comment Import stripHtml and use it to determine if the editor content is effectively empty (covers HTML-only content like


). Replace the previous ad-hoc checks with stripHtml(value).length === 0, trim the value when sending, and update the IconButton disabled condition accordingly. This simplifies empty-content detection and avoids false-positives from HTML markup. --- .../case-details/activity-tab/ActivityCommentInput.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx index d5cec4cf64..98061825a6 100644 --- a/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx +++ b/apps/customer-portal/webapp/src/components/support/case-details/activity-tab/ActivityCommentInput.tsx @@ -20,6 +20,7 @@ import { useState } from "react"; import { usePostComment } from "@api/usePostComment"; import { useAsgardeo } from "@asgardeo/react"; import { useErrorBanner } from "@context/error-banner/ErrorBannerContext"; +import { stripHtml } from "@utils/support"; import Editor from "@components/common/rich-text-editor/Editor"; import type { JSX } from "react"; @@ -46,12 +47,10 @@ export default function ActivityCommentInput({ const isDisabled = !isSignedIn || isAuthLoading || postComment.isPending; const handleSend = () => { - const trimmedValue = value.trim(); - const isEffectivelyEmpty = !trimmedValue || trimmedValue === "


"; - if (isEffectivelyEmpty || isDisabled) return; + if (stripHtml(value).length === 0 || isDisabled) return; postComment.mutate( - { caseId, body: { content: trimmedValue } }, + { caseId, body: { content: value.trim() } }, { onSuccess: () => { setValue(""); @@ -100,7 +99,7 @@ export default function ActivityCommentInput({ }} >

" || isDisabled} + disabled={stripHtml(value).length === 0 || isDisabled} onClick={handleSend} color="warning" aria-label="Send comment"