Skip to content

[Customer portal] [web] Add user profile editing modal with phone number and time zone support - #304

Merged
Rashmika998 merged 8 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/-add-user-details-profile-section
Mar 6, 2026
Merged

Rashmika998 merged 8 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/-add-user-details-profile-section

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Mar 6, 2026 •

Copy link
Copy Markdown
Contributor

Description

This pull request introduces a new user profile editing feature for the customer portal, allowing users to update their phone number and time zone from a modal dialog. It also refactors the security report analysis case filtering logic to simplify user-scoped queries and adds supporting API types and constants.

User Profile Editing Feature:

  • Added a reusable UserProfileModal component that displays the user's profile information and allows editing of phone number and time zone, with PATCH support to /users/me and user feedback banners.
  • Introduced the usePatchUserMe hook to handle PATCH requests for updating the current user's profile, including proper error handling and cache invalidation.
  • Integrated the profile modal into the UserProfile dropdown menu, enabling users to open the modal from the header. [1] [2] [3]
  • Added a comprehensive list of time zone options for the profile edit dropdown in a new constants file.

API and Model Enhancements:

  • Defined new request and response types for user profile editing (PatchUserMeRequest) and added optional fields for phoneNumber and avatar in UserDetails. [1] [2]

Security Report Analysis Refactor:

  • Simplified the logic for filtering cases assigned to the current user by leveraging a new createdByMe filter parameter, removing the need to fetch user details and perform client-side filtering. [1] [2] [3] [4] [5]

Other Model Additions:

  • Added types for PATCHing change requests (PatchChangeRequestRequest, PatchChangeRequestResponse). [1] [2]

These changes enhance user experience by enabling profile customization and streamline backend filtering for case analysis.


User Profile Editing:

  • Added UserProfileModal component for viewing and editing user profile (phone number, time zone) with PATCH support and success/error banners.
  • Created usePatchUserMe hook for PATCH /users/me API integration and error handling.
  • Integrated modal into header's UserProfile dropdown with a new "Profile" menu item. [1] [2] [3]
  • Added TIME_ZONE_OPTIONS constant for dropdown selection.

API & Model Updates:

  • Added PatchUserMeRequest type and extended UserDetails with phoneNumber and avatar fields. [1] [2]

Security Report Analysis Refactor:

  • Refactored filtering logic to use a backend createdByMe filter, removing manual user-based case filtering. [1] [2] [3] [4] [5]

Other Model Additions:

  • Added types for PATCH change requests (PatchChangeRequestRequest, PatchChangeRequestResponse). [1] [2]

Summary by CodeRabbit

  • New Features
    • Users can now edit their profile information, including phone number and time zone preferences
    • Added a new profile modal accessible from the user menu for convenient profile management
    • Extended user profiles to display and store additional information

Introduce a new React hook (apps/customer-portal/webapp/src/api/usePatchUserMe.ts) that provides a react-query mutation for PATCH /users/me. The hook uses Asgardeo auth and an auth-enabled fetch client, validates sign-in state and backend base URL, serializes the request body, parses and surfaces server error messages, and invalidates the "userDetails" query on success.
Add a 'Profile' item to the header user menu and render a UserProfileModal when selected. Introduces useState to manage the modal open state, imports the User icon and UserProfileModal, and wraps the UserMenu in a fragment to include the modal alongside the menu. Existing logout behavior remains unchanged.
Introduce a new UserProfileModal React component that displays user details (avatar, name, email) fetched via useGetUserDetails and lets users edit phone number and time zone. Only changed fields are sent to the server using usePatchUserMe; success and error banners are shown via context. The modal shows a loading state, disables closing/actions while the patch is pending, and uses TIME_ZONE_OPTIONS and Oxygen UI components for form controls.
Stop fetching current user and remove client-side owner-scoped case filtering. The useGetUserDetails import and ownerScopedCases logic were removed; cases are now taken directly from the paginated query (renamed allCases -> displayedCases). A createdByMe flag is passed to the project cases query when viewMode === "my" so server-side filtering is applied, and viewMode was added to the query deps and memo deps to keep results in sync. Pagination and other filters remain unchanged.
Introduce TIME_ZONE_OPTIONS in apps/customer-portal/webapp/src/constants/timeZoneConstants.ts to provide a curated list of time zone strings for the user profile edit dropdown. The file includes the project license header and exports the array as a readonly tuple (`as const`) so callers can rely on a fixed set of options (including a "System (Asia/Colombo)" entry and WSO2/Colombo).
Introduce two request-body interfaces in apps/customer-portal/webapp/src/models/requests.ts: PatchChangeRequestRequest for PATCH /change-requests/:id (plannedStartOn: string) and PatchUserMeRequest for PATCH /users/me (optional phoneNumber and timeZone). These types document the payloads used when updating a change request's planned start and when patching the current user's profile (only changed fields should be included).
Add optional phoneNumber and avatar fields to UserDetails (string | null) to carry contact and avatar data. Introduce PatchChangeRequestResponse interface for PATCH /change-requests/:id responses, containing id, updatedBy, and updatedOn to model update metadata.
@coderabbitai

coderabbitai Bot commented Mar 6, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 039ed4c5-6b80-4eab-b2bc-88bae1bf693a

📥 Commits

Reviewing files that changed from the base of the PR and between a643be6 and f6165d1.

📒 Files selected for processing (1)
  • apps/customer-portal/webapp/src/models/responses.ts

📝 Walkthrough

Walkthrough

This pull request introduces a user profile modal feature enabling customers to view and edit their profile information, including phone number and time zone. It includes a new React Query mutation hook for patching user details, a new modal component, updated data models with additional user fields, and refactoring to remove redundant user detail dependencies.

Changes

Cohort / File(s) Summary
User Profile API Integration
apps/customer-portal/webapp/src/api/usePatchUserMe.ts
New React Query mutation hook that sends PATCH requests to /users/me with validation, error handling, and automatic cache invalidation of user details on success.
User Profile UI Components
apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx, apps/customer-portal/webapp/src/components/common/header/UserProfileModal.tsx
New UserProfileModal component for viewing and editing user details (phone number, time zone) with loading states, success/error feedback, and change detection. UserProfile component updated to open the modal via new menu item.
Data Models & Constants
apps/customer-portal/webapp/src/models/responses.ts, apps/customer-portal/webapp/src/constants/timeZoneConstants.ts
UserDetails interface extended with optional phoneNumber and avatar fields. New PatchChangeRequestResponse interface added. New TIME_ZONE_OPTIONS constant provides dropdown options for time zone selection.
Security Component Refactoring
apps/customer-portal/webapp/src/components/security/SecurityReportAnalysis.tsx
Removed dependency on useGetUserDetails hook by replacing owner-scoped filtering with a viewMode-based filter parameter (createdByMe) passed to the backend request, simplifying client-side logic.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as UserProfile Component
    participant Modal as UserProfileModal
    participant QueryHook as React Query Hook
    participant API as Backend API
    participant Cache as Query Cache

    User->>UI: Click Profile menu item
    UI->>Modal: Set open = true
    activate Modal
    Modal->>QueryHook: useGetUserDetails() fetch
    QueryHook->>API: GET /users/me
    API-->>QueryHook: User details response
    QueryHook->>Cache: Store user data
    QueryHook-->>Modal: Return user data
    Modal->>Modal: Render form with fetched data
    deactivate Modal
    
    User->>Modal: Edit phone number / time zone
    Modal->>Modal: Update local state (editable fields)
    User->>Modal: Click Save
    activate Modal
    Modal->>Modal: Compute payload (changed fields only)
    Modal->>QueryHook: usePatchUserMe(payload)
    QueryHook->>API: PATCH /users/me with payload
    API->>API: Update user profile
    API-->>QueryHook: 200 OK
    QueryHook->>Cache: Invalidate userDetails query
    Cache->>API: Refetch user data
    API-->>Cache: Updated user details
    QueryHook-->>Modal: Success
    Modal->>Modal: Show success banner
    Modal->>Modal: Close modal
    deactivate Modal
    Modal-->>UI: onClose callback
    UI->>UI: Set open = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • shayanmalinda

Poem

🐰 A profile modal hops into view,
With phone and time zone options too,
The cache invalidates with grace,
User details refresh in place,
Edit, save, and off we go! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the main objectives and changes, but lacks several required template sections including Purpose, Goals, Approach, User stories, Release note, Documentation, Training, Certification, Marketing, Test details, Security checks, and Learning sections. Complete the PR description by filling out missing template sections: add Purpose (linked issues), Goals, Approach with UI screenshots, User stories, Release note, Documentation links, Training/Certification/Marketing status, test coverage, security checks, and Learning section.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the primary change: adding a user profile editing modal with support for phone number and time zone in the customer portal web app.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dileepapeiris dileepapeiris changed the title Feat/ add user details profile section [Customer portal] [web] Add user profile editing modal with phone number and time zone support Mar 6, 2026
@dileepapeiris dileepapeiris self-assigned this Mar 6, 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 Mar 6, 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

🧹 Nitpick comments (3)
apps/customer-portal/webapp/src/components/common/header/UserProfileModal.tsx (3)

70-75: Consider resetting mutation state when modal reopens.

The useEffect resets form fields when the modal opens, but if a previous save attempt failed, the mutation's error state persists. Consider calling patchUserMe.reset() when the modal opens to clear stale error/success states.

♻️ Suggested improvement
   useEffect(() => {
     if (open && userDetails) {
       setPhoneNumber(userDetails.phoneNumber ?? "");
       setTimeZone(userDetails.timeZone ?? "");
+      patchUserMe.reset();
     }
-  }, [open, userDetails]);
+  }, [open, userDetails, patchUserMe]);
🤖 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/header/UserProfileModal.tsx`
around lines 70 - 75, The useEffect that resets form fields on modal open (the
effect depending on open and userDetails and calling setPhoneNumber and
setTimeZone) does not clear the mutation state, so stale errors/success from
patchUserMe persist; update that effect to call patchUserMe.reset() when open is
true (before or after setting the fields) to clear mutation
error/success/loading state so each modal open starts fresh.

177-191: Handle case where user's current time zone is not in the options list.

If userDetails.timeZone contains a value not present in TIME_ZONE_OPTIONS, the Select component will display an empty selection, which may confuse users. Consider adding the current value to the options if it's missing.

♻️ Suggested approach
+  const effectiveTimeZoneOptions = userDetails?.timeZone && 
+    !TIME_ZONE_OPTIONS.includes(userDetails.timeZone as typeof TIME_ZONE_OPTIONS[number])
+      ? [userDetails.timeZone, ...TIME_ZONE_OPTIONS]
+      : TIME_ZONE_OPTIONS;
+
   <Select
     labelId="profile-timezone-label"
     label="Time Zone"
     value={timeZone}
     onChange={handleTimeZoneChange}
   >
-    {TIME_ZONE_OPTIONS.map((tz) => (
+    {effectiveTimeZoneOptions.map((tz) => (
       <MenuItem key={tz} value={tz}>
         {tz}
       </MenuItem>
     ))}
   </Select>
🤖 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/header/UserProfileModal.tsx`
around lines 177 - 191, The Select for time zones can show empty when
userDetails.timeZone isn't in TIME_ZONE_OPTIONS; update the rendering logic
around TIME_ZONE_OPTIONS and the Select (value={timeZone}, handleTimeZoneChange)
to ensure the current user timeZone is included: if userDetails.timeZone (or
state timeZone) is not found in TIME_ZONE_OPTIONS, create an extra MenuItem for
that value (e.g., prepend/append or derive a combined list used for mapping) so
the Select always has an option matching the current value and displays it
correctly.

169-175: Consider adding basic phone number validation.

The phone number field accepts any input without validation. Consider adding a pattern or validation to guide users toward valid phone number formats.

🤖 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/header/UserProfileModal.tsx`
around lines 169 - 175, The Phone Number TextField in UserProfileModal currently
accepts any input; add basic validation to enforce a phone format and provide
user feedback by updating handlePhoneChange or adding a validatePhone helper
used by the TextField. Implement a simple regex (e.g., allow digits, optional +,
spaces, dashes, length checks) to set a validation state like isPhoneValid and
an error message, pass error={!!isPhoneValidError} and
helperText={isPhoneValidError} to the TextField, and prevent submitting invalid
phone numbers in the component's submit/save handler (or disable the save
button) so invalid phone inputs are rejected or corrected. Ensure references:
TextField, phoneNumber, handlePhoneChange, and the component UserProfileModal
are updated accordingly.
🤖 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/constants/timeZoneConstants.ts`:
- Around line 18-151: The TIME_ZONE_OPTIONS array contains non-standard or
deprecated identifiers: replace the non-IANA "System (Asia/Colombo)" entry with
a canonical sentinel like "SYSTEM_DEFAULT" (or move to a separate SYSTEM_DEFAULT
constant), rename "Europe/Kiev" to the canonical "Europe/Kyiv", and remove the
invalid/duplicate entries "WSO2/Colombo", "Hongkong" (duplicate of
"Asia/Hong_Kong"), and the ambiguous "PST" (since "America/Los_Angeles" is
present); update the TIME_ZONE_OPTIONS declaration accordingly so only valid
IANA zones (and the explicit SYSTEM_DEFAULT token if needed) remain.

In `@apps/customer-portal/webapp/src/models/responses.ts`:
- Around line 376-381: The interface PatchChangeRequestResponse is currently
unused; either delete the PatchChangeRequestResponse declaration to remove
dead/orphaned code, or if it's intentionally reserved, leave it but add a short
comment above PatchChangeRequestResponse referencing the planned work or ticket
ID and why it is kept (so future reviewers understand it's intentional).

---

Nitpick comments:
In
`@apps/customer-portal/webapp/src/components/common/header/UserProfileModal.tsx`:
- Around line 70-75: The useEffect that resets form fields on modal open (the
effect depending on open and userDetails and calling setPhoneNumber and
setTimeZone) does not clear the mutation state, so stale errors/success from
patchUserMe persist; update that effect to call patchUserMe.reset() when open is
true (before or after setting the fields) to clear mutation
error/success/loading state so each modal open starts fresh.
- Around line 177-191: The Select for time zones can show empty when
userDetails.timeZone isn't in TIME_ZONE_OPTIONS; update the rendering logic
around TIME_ZONE_OPTIONS and the Select (value={timeZone}, handleTimeZoneChange)
to ensure the current user timeZone is included: if userDetails.timeZone (or
state timeZone) is not found in TIME_ZONE_OPTIONS, create an extra MenuItem for
that value (e.g., prepend/append or derive a combined list used for mapping) so
the Select always has an option matching the current value and displays it
correctly.
- Around line 169-175: The Phone Number TextField in UserProfileModal currently
accepts any input; add basic validation to enforce a phone format and provide
user feedback by updating handlePhoneChange or adding a validatePhone helper
used by the TextField. Implement a simple regex (e.g., allow digits, optional +,
spaces, dashes, length checks) to set a validation state like isPhoneValid and
an error message, pass error={!!isPhoneValidError} and
helperText={isPhoneValidError} to the TextField, and prevent submitting invalid
phone numbers in the component's submit/save handler (or disable the save
button) so invalid phone inputs are rejected or corrected. Ensure references:
TextField, phoneNumber, handlePhoneChange, and the component UserProfileModal
are updated accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3453d9ed-d10a-471c-9514-6ab622ce3f31

📥 Commits

Reviewing files that changed from the base of the PR and between 4d78d94 and a643be6.

📒 Files selected for processing (7)
  • apps/customer-portal/webapp/src/api/usePatchUserMe.ts
  • apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx
  • apps/customer-portal/webapp/src/components/common/header/UserProfileModal.tsx
  • apps/customer-portal/webapp/src/components/security/SecurityReportAnalysis.tsx
  • apps/customer-portal/webapp/src/constants/timeZoneConstants.ts
  • apps/customer-portal/webapp/src/models/requests.ts
  • apps/customer-portal/webapp/src/models/responses.ts

Comment thread apps/customer-portal/webapp/src/constants/timeZoneConstants.ts
Comment thread apps/customer-portal/webapp/src/models/responses.ts
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