[Customer Portal][FE][Web] Improve Settings State Persistence, Success Banner Handling, and Dashboard Cleanup - #599
Conversation
Reformat JSX and style objects for readability and consistency in ChatMessageBubble.tsx (multi-line imports, useMemo, sx props, and ReactMarkdown props). Replace the previous Typography rendering for message.thinkingSteps with a Box + MarkdownContent so thinking steps are rendered as markdown (styled p/li) for correct wrapping and styling. Overall small tidy-up to improve markdown handling and code clarity.
Use createdByFullName in case comment data and prefer it when rendering author names (fall back to createdBy or "Unknown"). Simplify name handling by removing manual first/last concatenation. Update Settings UI: import alpha and switch SettingsAiAssistant visuals from grey to blue accents with alpha transparency, adjust avatar/icon colors and remove avatar border. Also increase vertical spacing on SettingsPage (gap 1 -> 3) for improved layout.
Remove the derived visibleResolvedSections and the entire rendering block for resolved items shown in outstanding mode. The resolvedSections variable is retained with a void statement to avoid unused-variable linting. This cleans up the dashboard by removing the resolved-items accordion, counts, lists, navigation buttons, and the "No resolved items found" fallback.
Change the color for CaseStatus.SOLUTION_PROPOSED from colors.purple[900] to colors.purple[300]. This makes the status display a lighter purple to improve visibility and better align with the UI design.
Replace the previous CardHeader-based skeleton with a simpler, stacked layout using Stack and Box. Added Stack to imports, removed the CardHeader and various individual Skeleton nodes, and reorganized the skeleton into explicit Header (internalId/number/status), Content (title + description) and Footer (assigned engineer + relative time) sections with adjusted skeleton sizes. Also removed the explicit minHeight to let the new layout size naturally.
Introduce two new sessionStorage keys and helper functions to persist small UI state across a page reload: PENDING_SETTINGS_TAB_KEY and PENDING_SUCCESS_MESSAGE_KEY. Adds setPendingSettingsTab / consumePendingSettingsTab and setPendingSuccessMessage / consumePendingSuccessMessage to store, read and clear a pending settings tab id and a pending success message respectively. All operations use try/catch to safely handle storage errors and remove items when consumed.
Read any pending settings tab stored in settingsStorage when SettingsPage mounts and apply it to the active tab. Adds useEffect and imports consumePendingSettingsTab, preserving the existing default (USERS) when no pending value is present.
Replace in-place refetch flow with a pending-state + full reload approach for AI assistant toggles. Removed infinite projects refetch and SuccessBanner usage; notifyPatchSuccess now stores pending settings tab and success message via settingsStorage (setPendingSettingsTab, setPendingSuccessMessage) and calls window.location.reload() to let the app pick up updated project state. Updated imports accordingly and simplified notifyPatchSuccess usage.
Prefer cr.case.internalId when mapping changeRequests so the internalId reflects the associated case if present (falling back to cr.internalId). Also simplify SERVICENOW_REDIRECT_RESOLVE_ERROR text to a more generic "Something went wrong" message.
GetHelpDropdown: add Stack import and return a compact skeleton row (buttons + divider) when projects list is busy to improve loading UX. SuccessBannerContext: import and call consumePendingSuccessMessage on mount; if a pending message exists, show it and bump the key so persisted success banners are displayed after navigation. ChangeRequestsListSkeleton: refine skeleton layout to better mirror the final row (add state dot + label, pipes and spacing tweaks, and adjust several skeleton widths) for a more accurate placeholder representation.
📝 WalkthroughWalkthroughThis pull request introduces a reload-based state persistence pattern for settings changes, refactors skeleton layouts across support and operations UI components, updates comment author display logic, removes resolved items rendering from dashboard view, and enhances chat message markdown support. Changes span state management, UI components, and utility functions. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant SettingsUI as Settings AI Assistant<br/>Component
participant Storage as sessionStorage
participant Reload as Page Reload
participant SettingsPage as Settings Page
participant SuccessBanner as Success Banner<br/>Context
User->>SettingsUI: Click patch/save settings
SettingsUI->>Storage: setPendingSettingsTab("ai")
SettingsUI->>Storage: setPendingSuccessMessage(message)
SettingsUI->>Reload: window.location.reload()
Reload->>SettingsPage: Page initialization
SettingsPage->>Storage: consumePendingSettingsTab()
Storage-->>SettingsPage: "ai" (clears storage)
SettingsPage->>SettingsPage: Override activeTab state
Reload->>SuccessBanner: Banner provider mounts
SuccessBanner->>Storage: consumePendingSuccessMessage()
Storage-->>SuccessBanner: message (clears storage)
SuccessBanner->>SuccessBanner: Set banner message & trigger display
SettingsPage-->>User: Displays "AI" tab active
SuccessBanner-->>User: Shows success notification
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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: 3
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/features/dashboard/pages/DashboardItemsPage.tsx (1)
264-367: 🛠️ Refactor suggestion | 🟠 MajorRemove dead resolved-items code or actually render it.
The Resolved Items UI was removed, but five
useGetProjectCasesPage/useGetChangeRequestsqueries (lines 264-367), allresolved*derived values (lines 402-444), and theresolvedSectionsarray (lines 625-701) remain. They still fire network requests inoutstanding-interactionsmode (each enabled gate still evaluatesisOutstandingMode && hasResolvedStatusIds && permissions.*), andresolvedSectionsis then discarded withvoid resolvedSections;on line 713. This wastes bandwidth and React Query cache, and leavesexpandedSectionsinitialized with"resolved-*"keys (lines 455-459) that nothing toggles.If the intent is to keep the UI hidden for now, gate the resolved queries (and section state) on a render flag rather than always-on, or drop them entirely until the UI is reintroduced.
Also applies to: 625-713
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx` around lines 264 - 367, The resolved-items queries and state are dead: remove or gate them so they don't run when the UI is hidden. Either (A) fully remove the resolved queries (the useGetProjectCasesPage and useGetChangeRequests calls that populate resolvedCasesData / resolvedSrData / resolvedSraData / resolvedEngData / resolvedCrData and their isLoading/isError vars), delete the resolvedSections array and the useState initialization that seeds expandedSections with "resolved-*" keys, and remove the stray void resolvedSections; line, or (B) introduce a single render flag (e.g., renderResolved) and use it in the queries' options.enabled and when initializing/including "resolved-*" keys in expandedSections so the queries never run and the sections are not part of state while the UI is hidden (update references to resolvedSections, resolved* variables, and expandedSections accordingly).
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx (1)
224-229: Dead loading branch insideMenu.With the early return at lines 162-174,
GetHelpDropdownContentnever reaches this<Menu>whileisProjectsListBusyistrue(the trigger Button is not rendered, soanchorElcannot be set and the Menu cannot be open). TheisProjectsListBusy ? <Skeleton …/> : menuItems.map(...)branch on lines 224-229 is now unreachable and can be simplified to justmenuItems.map(...).♻️ Proposed simplification
- {isProjectsListBusy ? ( - <Box sx={{ px: 2, py: 1.5, width: 224 }}> - <Skeleton variant="rounded" height={48} sx={{ mb: 1 }} /> - <Skeleton variant="rounded" height={48} sx={{ mb: 1 }} /> - <Skeleton variant="rounded" height={48} /> - </Box> - ) : ( - menuItems.map((item, index) => ( + {menuItems.map((item, index) => ( <Box key={item.id}> {index > 0 && ( <Divider variant="middle" component="li" sx={{ listStyle: "none" }} /> )} <MenuItem onClick={item.onClick}> … </MenuItem> </Box> - )) - )} + ))}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx` around lines 224 - 229, The conditional rendering inside the Menu that checks isProjectsListBusy is dead code because GetHelpDropdownContent returns early when the projects list is busy; remove the ternary (isProjectsListBusy ? <Skeleton...> : menuItems.map(...)) and simplify the Menu body to always render menuItems.map(...) (use the existing menuItems array/map logic). Also remove any now-unused references to isProjectsListBusy within GetHelpDropdownContent/Menu to keep the component tidy.apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts (1)
112-118: Consider tighteningtabIdto theSettingsPageTabIdenum.
setPendingSettingsTab(tabId: string)accepts any string and is then read back inSettingsPage.tsxas theactiveTabvalue. AlthoughsafeActiveTab/displayTabuseresolveSettingsPageTabId(...)to recover from unknown values, accepting a typed enum here would prevent typos at the call site (e.g.SettingsAiAssistant.tsxcurrently passes the literal"ai"). Optional refinement, no behavioural impact.♻️ Suggested refinement
-export function setPendingSettingsTab(tabId: string): void { +import type { SettingsPageTabId } from "@features/settings/types/settings"; + +export function setPendingSettingsTab(tabId: SettingsPageTabId | string): void { try { sessionStorage.setItem(PENDING_SETTINGS_TAB_KEY, tabId); } catch { return; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts` around lines 112 - 118, Change setPendingSettingsTab to accept the typed enum SettingsPageTabId instead of a plain string: update the function signature setPendingSettingsTab(tabId: SettingsPageTabId): void, keep storing tabId as a string to sessionStorage using PENDING_SETTINGS_TAB_KEY, and update all callers (e.g. the literal "ai" in SettingsAiAssistant.tsx) to pass a SettingsPageTabId value. You can still read/resolve it in SettingsPage.tsx with resolveSettingsPageTabId as before; this change just prevents typos at call sites.
🤖 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/features/project-hub/constants/projectHubConstants.ts`:
- Around line 87-88: Replace the generic SERVICENOW_REDIRECT_RESOLVE_ERROR
string with the original, actionable message to restore user clarity: change the
value of SERVICENOW_REDIRECT_RESOLVE_ERROR to "Unable to resolve the case.
Please try again." so the constant used by redirect error handling provides a
specific problem statement and next step.
In
`@apps/customer-portal/webapp/src/features/settings/components/SettingsAiAssistant.tsx`:
- Around line 84-91: The notifyPatchSuccess function currently calls
window.location.reload() which force-reloads the app; remove that reload and
instead call showSuccess(getAiAssistantPatchSuccessMessage(kind)) directly,
relying on usePatchProject's onSuccess invalidations of [PROJECT_DETAILS,
projectId] and [PROJECTS] plus useGetProjectDetails (staleTime: 0) to refresh
projectHasAgent; also remove or stop using the pending-state helpers
setPendingSettingsTab and setPendingSuccessMessage (and related
settingsStorage/consumePending plumbing) for this flow since they become
unnecessary. Ensure notifyPatchSuccess still sets any immediate UI state only if
needed, but do not trigger a full-page reload.
In `@apps/customer-portal/webapp/src/features/settings/pages/SettingsPage.tsx`:
- Around line 44-50: Init activeTab using a lazy initializer that calls
consumePendingSettingsTab so the initial render uses the pending tab (instead of
starting at SettingsPageTabId.USERS and switching after paint), and add a useRef
guard to avoid consuming-and-deleting the pending key twice under StrictMode;
replace the current useState call (activeTab, setActiveTab) with useState(() =>
consumePendingSettingsTab() ?? SettingsPageTabId.USERS) and create a ref (e.g.,
consumedRef) to ensure consumePendingSettingsTab is only invoked once (or move
the consume into the lazy initializer and still use a ref to prevent
double-consume), then remove the now-unnecessary useEffect import and effect
that previously called consumePendingSettingsTab.
---
Outside diff comments:
In
`@apps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsx`:
- Around line 264-367: The resolved-items queries and state are dead: remove or
gate them so they don't run when the UI is hidden. Either (A) fully remove the
resolved queries (the useGetProjectCasesPage and useGetChangeRequests calls that
populate resolvedCasesData / resolvedSrData / resolvedSraData / resolvedEngData
/ resolvedCrData and their isLoading/isError vars), delete the resolvedSections
array and the useState initialization that seeds expandedSections with
"resolved-*" keys, and remove the stray void resolvedSections; line, or (B)
introduce a single render flag (e.g., renderResolved) and use it in the queries'
options.enabled and when initializing/including "resolved-*" keys in
expandedSections so the queries never run and the sections are not part of state
while the UI is hidden (update references to resolvedSections, resolved*
variables, and expandedSections accordingly).
---
Nitpick comments:
In `@apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsx`:
- Around line 224-229: The conditional rendering inside the Menu that checks
isProjectsListBusy is dead code because GetHelpDropdownContent returns early
when the projects list is busy; remove the ternary (isProjectsListBusy ?
<Skeleton...> : menuItems.map(...)) and simplify the Menu body to always render
menuItems.map(...) (use the existing menuItems array/map logic). Also remove any
now-unused references to isProjectsListBusy within GetHelpDropdownContent/Menu
to keep the component tidy.
In `@apps/customer-portal/webapp/src/features/settings/utils/settingsStorage.ts`:
- Around line 112-118: Change setPendingSettingsTab to accept the typed enum
SettingsPageTabId instead of a plain string: update the function signature
setPendingSettingsTab(tabId: SettingsPageTabId): void, keep storing tabId as a
string to sessionStorage using PENDING_SETTINGS_TAB_KEY, and update all callers
(e.g. the literal "ai" in SettingsAiAssistant.tsx) to pass a SettingsPageTabId
value. You can still read/resolve it in SettingsPage.tsx with
resolveSettingsPageTabId as before; this change just prevents typos at call
sites.
🪄 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: e73d4c6e-7ea3-4b04-9163-8f3a7666b128
📒 Files selected for processing (16)
apps/customer-portal/webapp/src/components/header/GetHelpDropdown.tsxapps/customer-portal/webapp/src/context/success-banner/SuccessBannerContext.tsxapps/customer-portal/webapp/src/features/dashboard/pages/DashboardItemsPage.tsxapps/customer-portal/webapp/src/features/operations/components/change-requests/ChangeRequestsListSkeleton.tsxapps/customer-portal/webapp/src/features/operations/pages/OperationsPage.tsxapps/customer-portal/webapp/src/features/project-hub/constants/projectHubConstants.tsapps/customer-portal/webapp/src/features/settings/components/SettingsAiAssistant.tsxapps/customer-portal/webapp/src/features/settings/pages/SettingsPage.tsxapps/customer-portal/webapp/src/features/settings/utils/settingsStorage.tsapps/customer-portal/webapp/src/features/support/api/useGetCaseComments.tsapps/customer-portal/webapp/src/features/support/components/case-details/activity-tab/CommentBubble.tsxapps/customer-portal/webapp/src/features/support/components/novera-ai-assistant/novera-chat-page/ChatMessageBubble.tsxapps/customer-portal/webapp/src/features/support/components/support-overview-cards/OutstandingCasesSkeleton.tsxapps/customer-portal/webapp/src/features/support/pages/DescribeIssuePage.tsxapps/customer-portal/webapp/src/features/support/types/cases.tsapps/customer-portal/webapp/src/features/support/utils/support.ts
Description
This pull request introduces several improvements to user experience and state management in the customer portal, particularly around the Settings and Dashboard pages. The most significant changes include implementing cross-page success banner and tab state persistence using session storage, enhancing loading skeletons for better UI feedback, and refining the display logic for dashboard sections.
State Persistence and Success Banner Improvements:
settingsStorage.tsto store and retrieve pending success messages and active settings tab across page reloads, enabling smoother UX when actions require a reload.SuccessBannerContextto consume and display any pending success message after a reload.SettingsAiAssistant.tsxto use the new session storage utilities for success messages and tab selection, removing the need for direct banner calls and project list refetching [1] [2] [3].SettingsPage.tsxto restore the active tab from session storage after reloads, ensuring users return to the correct tab.UI/UX Enhancements:
ChangeRequestsListSkeleton.tsxfor more accurate visual feedback [1] [2].Dashboard and Operations Page Logic:
internalIdin change requests to prefer the case'sinternalIdif available.Miscellaneous:
These updates collectively enhance the user experience by making settings changes more intuitive, improving feedback during loading states, and decluttering key pages.
Summary by CodeRabbit
New Features
Improvements
UI Updates