[Customer Portal][FE][Web] Enhance Timezone Handling, Type Safety, Infinite Query Typing, and UI/UX Improvements in Customer Portal - #454
Conversation
Import the InfiniteData type and update the JSDoc and function signature for usePostDeploymentProductsSearchInfinite to return UseInfiniteQueryResult<InfiniteData<DeployedProductsResponsePayload>, Error>. This is a type-only change to accurately reflect the paginated/infinite query result shape returned by useInfiniteQuery.
Import the InfiniteData type and update the JSDoc and function signature of usePostProjectDeploymentsSearchInfinite to return UseInfiniteQueryResult<InfiniteData<ProjectDeploymentsListResponse>, Error>. This aligns the declared return type with react-query's useInfiniteQuery wrapping of paginated results and improves type accuracy for consumers.
Explicitly cast tempFilters[field.id] to string for the Select value prop. tempFilters is typed as Record<string, unknown>, so the cast ensures the value matches Select<string> expectations and satisfies TypeScript type checking.
Relax the type of the `filters` prop to `Record<string, string | number | undefined>` so optional/absent filter entries are supported and TypeScript callers that may leave filters unset don't error. No runtime behavior changes.
Introduce a CasesTableFilterValues interface to explicitly type filter entries (statusId, severityId, issueTypes, deploymentId) as string|number|undefined. Use this type for the filters state and for the computed effectiveFilters to improve type safety and clarify the optional deploymentId handling when includeDeploymentFilter is false.
Replace the previous useGetDeployments query with usePostProjectDeploymentsSearchInfinite to support paginated/infinite loading of deployments. The change initializes the infinite query with pageSize: 10 and enabled based on projectId, flattens pages into a deploymentsList, and passes that list to the component. Added callback props and flags for pagination: onLoadMoreDeployments (calls fetchNextPage guarded by hasNextPage and !isFetchingNextPage), hasMoreDeployments, and isFetchingMoreDeployments.
Remove the isActiveFilterPrimitive function from support.ts. This cleans up dead/unused code that checked whether a filter value was active (non-empty string, number, or boolean). No other logic was changed in this file.
Add DOMPurify import and start adding a dangerouslySetInnerHTML prop to the Typography that renders the security report. The intent is to render sanitized HTML from uploaded reports to avoid XSS (using DOMPurify), but the inserted dangerouslySetInnerHTML line in this diff is incomplete and should be completed to call DOMPurify.sanitize(...) with the report content to ensure safe rendering.
Read location.state via useLocation and derive a returnTo value, then update the back button to navigate to returnTo when present (falling back to navigating up ".."). This adds useLocation to imports and introduces a typed optional returnTo extraction to preserve caller navigation intent.
Introduce operationsPath and pass it as navigation state so service/change request list and detail routes know how to return to the Operations page. Also simplify payload construction by always including activeServiceRequests/activeChangeRequests when enabled (using ?? 0) instead of conditionally spreading undefined values. This ensures consistent numeric values and preserves a returnTo path for downstream navigation.
Import DOMPurify and render the header copy using dangerouslySetInnerHTML with DOMPurify.sanitize (defense-in-depth against XSS). Also extract returnTo from location.state and update the back button to navigate to returnTo when present (falling back to ".."), and include a biome-ignore lint comment for the intentional use of dangerouslySetInnerHTML.
When handling the back action, check location.state for an optional returnTo string and navigate there if present. If returnTo is not provided, fall back to the existing logic that derives the base path from the current pathname (operations vs support). Includes a narrow TypeScript type assertion for location.state.
When handling the back action in CaseDetailsPage, read a returnTo value from location.state and navigate to it if present. This adds a typed check and early return so callers can redirect back to an arbitrary referrer; existing behavior for engagement routes and the default project navigation is preserved.
Import DOMPurify and replace the old stripHtmlTags fallback with a renderHtmlContent helper that sanitizes and dangerously sets HTML (with a biome-ignore lint comment) and shows appropriate fallback text when fields are empty. Add handling for location.state.returnTo so the back button can navigate to a provided return path. Refactor multiple sections (description, impact, service outage, communication/rollback/test plans) to use the new renderer and simplify the Service Outage UI layout.
Read an optional returnTo URL from useLocation state and have the back button navigate to it when present. Import DOMPurify and replace the header Typography text with a sanitized dangerouslySetInnerHTML render to ensure any HTML is safe (keeps component="div" and a biome-ignore lint comment).
Modify ConversationDetailsPage handleBack to check for a returnTo value on location.state and navigate there if present. If no returnTo is provided, existing fallback behavior (history length / projectId routing) remains unchanged. Adds a type assertion for location.state and an early return after navigation.
Add a new isServiceRequestDetailsPage boolean in AppLayout to match service-requests detail routes (both project-scoped and global, under support or operations). Include this flag in isDetailsStylePage so service request detail pages use the details-style layout.
Extract returnTo from location.state and make the back button navigate to it when present; fall back to the parent route otherwise. Import DOMPurify and replace the subtitle Typography string with a sanitized dangerouslySetInnerHTML rendering (with a biome-ignore lint comment) to safely support HTML content in the subtitle. Changes are localized to ChangeRequestsPage.tsx.
Import DOMPurify and render the announcements description using dangerouslySetInnerHTML with DOMPurify.sanitize. This replaces the plain Typography text with a sanitized HTML string (static/trusted copy) and adds a lint ignore comment for the intentional use of dangerouslySetInnerHTML to ensure safe rendering.
Introduce supportPath and pass { returnTo: supportPath } into navigations from SupportPage (view my/all cases, case detail, view my/all conversations, conversation detail). Also preserve conversationSummary when navigating to a conversation. This enables target pages to navigate back to the support page.
Use formatUtcToLocal to render preferredTimes in the selected scheduling timezone for UI display. Updated formatPreferredTimes to accept an optional userTimeZone and replaced the backend-only formatter. Added userTimeZone prop to CallRequestCard and passed it to the formatter so displayed times reflect the user's chosen timezone.
Wrap state updates in queueMicrotask to avoid synchronous state changes during render, and thread userTimeZone through preferred-time conversion helpers. Also adjust effect/dependency lists (add userTimeZone) and reference minTick inside the memo to ensure proper recomputation. These changes ensure correct local/UTC conversions and prevent React timing/update issues.
Pass userTimeZone into datetime conversion helpers and include it in relevant effect/callback dependencies so preferred times are computed in the user's timezone. Add void minDatetimeTick to the minDatetimeLocal memo (and include minDatetimeTick in deps) to force recompute when the tick changes. Defer form state updates with queueMicrotask in a couple places to avoid synchronous update ordering issues. Minor cleanup of mapping/return logic in the preferred times normalization.
Pass a returnTo state (location.pathname + location.search) when linking to related change requests so the UI can navigate back. Also remove the conditional rendering block that displayed the "Request type" for service requests (isServiceRequest && !isSecurityReportAnalysis). No other UI logic changed.
Replace ad-hoc string assembly/parsing with timezone-aware helpers for call request datetime handling. callRequestPreferredTimeFromDatetimeLocal now uses datetimeLocalWallTimeToUtcMs and returns a real UTC ISO string; callRequestApiPreferredTimeToDatetimeLocal delegates to toDatetimeLocalInTimeZoneFromApiString. Both functions accept an optional profileTimeZone parameter. Removes legacy regex-based assembly/parsing and centralizes conversion logic to improve correctness across time zones.
📝 WalkthroughWalkthroughThis PR updates React Query infinite-query type signatures, improves HTML sanitization with DOMPurify across multiple pages, implements timezone-aware datetime conversions for call scheduling, adds navigation state tracking (returnTo) across support and case pages, refines filter type definitions, adjusts deployment fetching to use infinite scroll pagination, and adds layout detection for service request details pages. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
apps/customer-portal/webapp/src/pages/AllCasesPage.tsx (2)
101-104:⚠️ Potential issue | 🟠 MajorDeployments query should be permission/readiness-gated.
At Line 103,
enabled: !!projectIdstill triggers deployments fetches before project context is ready and for users without deployment access.Based on learnings: In `apps/customer-portal/webapp/src/pages/AllCasesPage.tsx` (PR `#453`), this query should be gated by `projectDetailsReady && permissions.hasDeployments` to avoid unnecessary/forbidden calls.🔧 Proposed fix
const deploymentsQuery = usePostProjectDeploymentsSearchInfinite(projectId || "", { pageSize: 10, - enabled: !!projectId, + enabled: !!projectId && projectDetailsReady && permissions.hasDeployments, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/pages/AllCasesPage.tsx` around lines 101 - 104, The deployments query currently enables fetches when only projectId is truthy; change the enabled flag on usePostProjectDeploymentsSearchInfinite (where deploymentsQuery is created) to gate requests until projectDetailsReady is true and the user has deployment access by using: enabled: projectDetailsReady && permissions.hasDeployments && !!projectId (keeping existing pageSize and other options).
155-159:⚠️ Potential issue | 🟠 MajorPage loader can remain stuck when stats request errors.
At Line 158,
!!projectId && !hasStatsResponsekeepsisStatsLoadingtrue even whenisStatsErroris true.Based on learnings: In `apps/customer-portal/webapp/src/pages/AllCasesPage.tsx` (PR `#436`), this missing `!isStatsError` guard causes the page-level loader to hang indefinitely on stats failures.🔧 Proposed fix
const isStatsLoading = isProjectContextLoading || isStatsQueryLoading || - (!!projectId && !hasStatsResponse); + (!!projectId && !hasStatsResponse && !isStatsError);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/pages/AllCasesPage.tsx` around lines 155 - 159, The isStatsLoading expression (const isStatsLoading = ...) incorrectly keeps the page loader active when a stats request errors because it evaluates (!!projectId && !hasStatsResponse) without checking isStatsError; update the condition used to compute isStatsLoading (the const named isStatsLoading in AllCasesPage.tsx) to include a guard that ensures !isStatsError (e.g., require !isStatsError alongside !hasStatsResponse) so that when isStatsError is true the loader will not remain stuck.apps/customer-portal/webapp/src/api/usePostDeploymentProductsSearch.ts (1)
58-62:⚠️ Potential issue | 🟠 MajorControlled pagination is being overridden by caller input.
request?.paginationis spread afteroffset/limit, so stale caller values can silently replace the intended page parameters and cause repeated/incorrect pages.Based on learnings: In `apps/customer-portal/webapp/src/api/usePostDeploymentProductsSearch.ts` (PR `#453`), spreading caller pagination after `offset`/`limit` breaks controlled pagination and should be reversed.🔧 Proposed fix
const payload: DeployedProductSearchRequest = { ...(request ?? {}), pagination: { - offset, - limit, ...(request?.pagination ?? {}), + offset, + limit, }, };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/api/usePostDeploymentProductsSearch.ts` around lines 58 - 62, The pagination object currently sets offset and limit then spreads request?.pagination which lets caller-supplied offset/limit override controlled values; in the usePostDeploymentProductsSearch code change the spread order so pagination merges like {...(request?.pagination ?? {}), offset, limit} (or place offset/limit after the spread) to ensure the internal offset and limit take precedence over request?.pagination and prevent stale caller page values from replacing controlled pagination.apps/customer-portal/webapp/src/api/usePostProjectDeploymentsSearch.ts (1)
52-58:⚠️ Potential issue | 🟠 MajorLet the controlled page arguments override caller pagination.
request?.paginationis still spread afteroffset/limit, so any caller-provided pagination can overwrite the page param. That breaks bothusePostProjectDeploymentsSearchInfiniteandusePostProjectDeploymentsSearchAllby re-requesting the same page or walking duplicate offsets.Based on learnings, in `apps/customer-portal/webapp/src/api/usePostProjectDeploymentsSearch.ts`, `request?.pagination` must be spread before `offset` and `limit` so the controlled page arguments always win.Suggested fix
const payload: DeploymentSearchRequest = { ...(request ?? {}), pagination: { - offset, - limit, ...(request?.pagination ?? {}), + offset, + limit, }, };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/api/usePostProjectDeploymentsSearch.ts` around lines 52 - 58, The payload builds a DeploymentSearchRequest where request?.pagination is currently spread after controlled offset/limit allowing callers to overwrite page args; fix by spreading request?.pagination before offset and limit so controlled page arguments (offset, limit) always override—update the payload construction in usePostProjectDeploymentsSearch.ts (the DeploymentSearchRequest payload object) to merge ...(request?.pagination ?? {}) first, then set offset and limit.apps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestDetailsPage.tsx (1)
685-687:⚠️ Potential issue | 🟡 MinorFormat the approval timestamps before rendering.
The header already uses
formatDateTime(), but the Approval Information card still prints raw API timestamps. That leaves this page with mixed timestamp formats and bypasses the fix in one of the most visible metadata sections.Based on learnings, in `apps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestDetailsPage.tsx`, `changeRequest.createdOn` is already formatted in the header and should not be rendered as a raw API string in the Approval Information card.Suggested fix
<Typography variant="body2"> - {changeRequest.createdOn} + {changeRequest.createdOn + ? formatDateTime(changeRequest.createdOn) + : "Not available"} </Typography> @@ <Typography variant="body2"> - {changeRequest.approvedOn || "Not available"} + {changeRequest.approvedOn + ? formatDateTime(changeRequest.approvedOn) + : "Not available"} </Typography>Also applies to: 714-715
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestDetailsPage.tsx` around lines 685 - 687, The Approval Information card is rendering raw API timestamps (e.g., changeRequest.createdOn and other timestamp fields in the same card) while the header uses formatDateTime(); update the card to call formatDateTime(...) for those fields instead of printing raw strings. Locate the Approval Information block in ChangeRequestDetailsPage and replace direct uses of changeRequest.createdOn (and the other timestamp props referenced near the same area) with formatDateTime(changeRequest.createdOn) (and formatDateTime for each timestamp) so all displayed timestamps use the same formatted output.
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/components/common/filter-panel/FilterPopover.tsx (1)
182-182: Type cast improves Select compatibility; consider applying same pattern to TextField.The explicit
as stringcast correctly ensures theSelect<string>component receives a string value. However, theTextFieldat line 228 uses the same pattern without the cast:value={tempFilters[field.id] || ""}For consistency and type safety, consider applying the same cast there as well.
♻️ Suggested consistency fix
<TextField key={field.id} - value={tempFilters[field.id] || ""} + value={(tempFilters[field.id] as string) || ""} onChange={handleTextChange(field.id)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/common/filter-panel/FilterPopover.tsx` at line 182, The TextField value uses tempFilters[field.id] without a type assertion, which is inconsistent with the Select<string> usage and can cause type mismatches; update the TextField's value expression in FilterPopover.tsx to mirror the Select usage by casting to string (e.g., use (tempFilters[field.id] as string) || "") so the TextField receives a properly typed string; locate the TextField render block that references tempFilters and field.id and apply the same cast pattern for consistency and type safety.apps/customer-portal/webapp/src/components/support/case-details/calls-tab/ApproveCallRequestModal.tsx (1)
122-128: Consider using a clearer pattern for theminTickdependency.The
void minTick;statement works but is non-obvious. A brief comment would clarify intent.💡 Suggested improvement for clarity
const minDatetimeLocal = useMemo( () => { - void minTick; + void minTick; // Reference to trigger recomputation every minute return computeMinScheduleDatetimeLocalForTimeZone(null, userTimeZone); }, [userTimeZone, minTick], );🤖 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/calls-tab/ApproveCallRequestModal.tsx` around lines 122 - 128, The useMemo for minDatetimeLocal currently includes a non-obvious "void minTick;" to force minTick into the dependency array; replace this with a clearer pattern: explicitly reference minTick in the memo body or add a one-line comment explaining that minTick is used solely to re-evaluate the memo when the tick changes (e.g., "/* depend on minTick to refresh value */"), so update the compute block that sets minDatetimeLocal (the useMemo that calls computeMinScheduleDatetimeLocalForTimeZone with userTimeZone) to either directly use minTick in its computation or add the explanatory comment and keep minTick in the dependency list for clarity.
🤖 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/pages/ServiceRequestsPage.tsx`:
- Line 71: The primary Back/header button in ServiceRequestsPage is still
calling navigate("..") and ignores the previously computed returnTo variable;
update those button handlers (the normal header Back button and the primary Back
button used on success/error paths) to use the same logic as the error-state
button by calling navigate(returnTo ?? "..") (i.e., prefer returnTo when
present, fallback to ".."). Locate usages of navigate("..") within the
ServiceRequestsPage component and replace them with navigate(returnTo ?? ".."),
ensuring they reference the existing returnTo variable declared near the top of
the component.
- Around line 103-106: The deployments query is enabled too early; change the
usePostProjectDeploymentsSearchInfinite call so it only runs when the page has
finished readiness checks and the user is allowed to use deployment filters —
i.e. update the options for usePostProjectDeploymentsSearchInfinite (the
deploymentsQuery invocation) to set enabled to a conjunction of projectId,
projectDetailsReady, and the permission/feature flag used by this page (e.g.
canUseDeploymentFilter or deploymentsAllowed) so the hook only fires when all
readiness/permission guards are true.
---
Outside diff comments:
In `@apps/customer-portal/webapp/src/api/usePostDeploymentProductsSearch.ts`:
- Around line 58-62: The pagination object currently sets offset and limit then
spreads request?.pagination which lets caller-supplied offset/limit override
controlled values; in the usePostDeploymentProductsSearch code change the spread
order so pagination merges like {...(request?.pagination ?? {}), offset, limit}
(or place offset/limit after the spread) to ensure the internal offset and limit
take precedence over request?.pagination and prevent stale caller page values
from replacing controlled pagination.
In `@apps/customer-portal/webapp/src/api/usePostProjectDeploymentsSearch.ts`:
- Around line 52-58: The payload builds a DeploymentSearchRequest where
request?.pagination is currently spread after controlled offset/limit allowing
callers to overwrite page args; fix by spreading request?.pagination before
offset and limit so controlled page arguments (offset, limit) always
override—update the payload construction in usePostProjectDeploymentsSearch.ts
(the DeploymentSearchRequest payload object) to merge ...(request?.pagination ??
{}) first, then set offset and limit.
In `@apps/customer-portal/webapp/src/pages/AllCasesPage.tsx`:
- Around line 101-104: The deployments query currently enables fetches when only
projectId is truthy; change the enabled flag on
usePostProjectDeploymentsSearchInfinite (where deploymentsQuery is created) to
gate requests until projectDetailsReady is true and the user has deployment
access by using: enabled: projectDetailsReady && permissions.hasDeployments &&
!!projectId (keeping existing pageSize and other options).
- Around line 155-159: The isStatsLoading expression (const isStatsLoading =
...) incorrectly keeps the page loader active when a stats request errors
because it evaluates (!!projectId && !hasStatsResponse) without checking
isStatsError; update the condition used to compute isStatsLoading (the const
named isStatsLoading in AllCasesPage.tsx) to include a guard that ensures
!isStatsError (e.g., require !isStatsError alongside !hasStatsResponse) so that
when isStatsError is true the loader will not remain stuck.
In
`@apps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestDetailsPage.tsx`:
- Around line 685-687: The Approval Information card is rendering raw API
timestamps (e.g., changeRequest.createdOn and other timestamp fields in the same
card) while the header uses formatDateTime(); update the card to call
formatDateTime(...) for those fields instead of printing raw strings. Locate the
Approval Information block in ChangeRequestDetailsPage and replace direct uses
of changeRequest.createdOn (and the other timestamp props referenced near the
same area) with formatDateTime(changeRequest.createdOn) (and formatDateTime for
each timestamp) so all displayed timestamps use the same formatted output.
---
Nitpick comments:
In
`@apps/customer-portal/webapp/src/components/common/filter-panel/FilterPopover.tsx`:
- Line 182: The TextField value uses tempFilters[field.id] without a type
assertion, which is inconsistent with the Select<string> usage and can cause
type mismatches; update the TextField's value expression in FilterPopover.tsx to
mirror the Select usage by casting to string (e.g., use (tempFilters[field.id]
as string) || "") so the TextField receives a properly typed string; locate the
TextField render block that references tempFilters and field.id and apply the
same cast pattern for consistency and type safety.
In
`@apps/customer-portal/webapp/src/components/support/case-details/calls-tab/ApproveCallRequestModal.tsx`:
- Around line 122-128: The useMemo for minDatetimeLocal currently includes a
non-obvious "void minTick;" to force minTick into the dependency array; replace
this with a clearer pattern: explicitly reference minTick in the memo body or
add a one-line comment explaining that minTick is used solely to re-evaluate the
memo when the tick changes (e.g., "/* depend on minTick to refresh value */"),
so update the compute block that sets minDatetimeLocal (the useMemo that calls
computeMinScheduleDatetimeLocalForTimeZone with userTimeZone) to either directly
use minTick in its computation or add the explanatory comment and keep minTick
in the dependency list for clarity.
🪄 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: 2369e4c7-55fc-48fd-b2db-832301dfc20b
📒 Files selected for processing (23)
apps/customer-portal/webapp/src/api/usePostDeploymentProductsSearch.tsapps/customer-portal/webapp/src/api/usePostProjectDeploymentsSearch.tsapps/customer-portal/webapp/src/components/common/filter-panel/FilterPopover.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsxapps/customer-portal/webapp/src/components/security/SecurityReportAnalysis.tsxapps/customer-portal/webapp/src/components/support/case-details/calls-tab/ApproveCallRequestModal.tsxapps/customer-portal/webapp/src/components/support/case-details/calls-tab/CallRequestCard.tsxapps/customer-portal/webapp/src/components/support/case-details/calls-tab/RequestCallModal.tsxapps/customer-portal/webapp/src/components/support/case-details/details-tab/CaseDetailsDetailsPanel.tsxapps/customer-portal/webapp/src/layouts/AppLayout.tsxapps/customer-portal/webapp/src/pages/AllCasesPage.tsxapps/customer-portal/webapp/src/pages/AllConversationsPage.tsxapps/customer-portal/webapp/src/pages/AnnouncementsPage.tsxapps/customer-portal/webapp/src/pages/CaseDetailsPage.tsxapps/customer-portal/webapp/src/pages/ConversationDetailsPage.tsxapps/customer-portal/webapp/src/pages/OperationsPage.tsxapps/customer-portal/webapp/src/pages/ServiceRequestDetailsPage.tsxapps/customer-portal/webapp/src/pages/ServiceRequestsPage.tsxapps/customer-portal/webapp/src/pages/SupportPage.tsxapps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestDetailsPage.tsxapps/customer-portal/webapp/src/pages/support/change-requests/ChangeRequestsPage.tsxapps/customer-portal/webapp/src/utils/support.ts
923b235
into
wso2-open-operations:dev-app-customer-portal-v1.0.x
Description
Closes (https://github.com/wso2-enterprise/digiops-cs/issues/1497, https://github.com/wso2-enterprise/digiops-cs/issues/1520)
This pull request introduces several improvements and bug fixes across the customer portal webapp, focusing on timezone handling for call scheduling, filter state typing, infinite query typing, and minor UI/UX adjustments. The most significant changes are grouped below:
Timezone Handling and Call Scheduling Improvements
RequestCallModal,ApproveCallRequestModal) and call request display (CallRequestCard) to consistently handle and display preferred times in the user's selected timezone. This includes passinguserTimeZoneto formatting and conversion utilities, ensuring accurate time representation and conversion throughout the scheduling flow. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14]Type Safety and Filter Improvements
string | number | undefined, reducing type errors and improving clarity. This includes the introduction of aCasesTableFilterValuesinterface and updates to filter-related props and state. [1] [2] [3] [4]FilterPopovercomponent to ensure select values are treated as strings, preventing runtime issues with filter value types.API Query Typing
usePostDeploymentProductsSearchInfinite,usePostProjectDeploymentsSearchInfinite) to correctly type their return values asUseInfiniteQueryResult<InfiniteData<...>, Error>, aligning with React Query's expectations for paginated data. [1] [2] [3] [4]UI/UX and Security
SecurityReportAnalysisby sanitizing content withDOMPurifybefore injecting it withdangerouslySetInnerHTML. [1] [2]returnTostate with navigation links, and removed a redundant "Request type" section for service requests. [1] [2]Miscellaneous
useLocationinAllCasesPage.tsxto support navigation or state-related logic.