Skip to content

[Customer Portal][FE][Web] Integrate Project Search API and Implement Resilient Error Handling - #91

Merged
Rashmika998 merged 23 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-projects-search-api
Feb 5, 2026
Merged

Rashmika998 merged 23 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-projects-search-api

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Feb 4, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

This PR focuses on the robust integration of the useGetProjects API across the primary application interfaces (ProjectHub, Header, and ProjectSwitcher). It transitions the data fetching model from infinite scrolling to a standardized query structure and introduces a comprehensive error-handling strategy with granular visual indicators.

Goals

  • Stabilize Data Fetching: Ensure API hooks only fire when the authentication SDK is fully initialized and the user is signed in.
  • Implement Visual Fail-safes: Introduce ErrorIndicator components within cards and dropdowns to gracefully handle partial API failures.
  • Streamline UX: Implement automatic redirection for users with a single project to reduce unnecessary navigation steps.
  • Simplify Architecture: Refactor the project listing logic to use a standard query response, removing unused infinite scroll complexity.

Approach

  • Auth-Guarded Logic: Updated useGetProjects and useGetUserDetails with strict enabled conditions (isSignedIn && !isAuthLoading), preventing "SDK not initialized" errors.
  • Error Propagation: Introduced isError and isStatsError props. If the API fails, ProjectCardStats and ProjectCardBadges now render a "Failed to load" tooltip and icon instead of empty or broken values.
  • Header Resilience: The ProjectSwitcher now detects fetch errors and replaces the dropdown menu with a small-scale ErrorIndicator.
  • UX Optimization: Added logic in ProjectHub to detect if the result set contains exactly one project; if so, the user is automatically navigated to that project's dashboard.
  • Component Refinement: Updated ErrorIndicator to support a 16px icon size for seamless integration into dense UI areas like stats rows.

User stories

  • Reliable Access: As a user, I want the app to wait for my login to complete before trying to load my projects to avoid error messages.
  • Graceful Failure: As a user, if some project statistics fail to load, I want to see a clear indicator (with a tooltip) rather than broken numbers or an empty screen.
  • Quick Start: As a user with only one project, I want to be taken directly to my dashboard instead of having to select my only project from a list.

Walkthrough

This PR integrates the project search API with the core UI. It refactors the fetching logic to align with standard query responses, adds auth-state guards to API hooks, and implements visual error indicators across the Header, Project Switcher, and Project Cards. It also includes an automatic redirect for single-project users and updated unit tests for all scenarios.

Changes

Cohort File(s) Summary
API Hooks useGetProjects.ts, useGetUserDetails.ts Added auth guards to enabled conditions; fixed request body construction.
Project Hub ProjectHub.tsx Switched to standard query; added single-project redirect and stats error handling.
Header Suite Header.tsx, ProjectSwitcher.tsx Propagated error/loading states from API to switcher; added ErrorIndicator logic.
Project Card ProjectCard.tsx, Stats.tsx, Badges.tsx Implemented isStatsError UI to show "Failed to load" tooltips during failures.
UI Components ErrorIndicator.tsx Updated default icon sizing for small-scale card usage.
Tests ProjectHub.test.tsx, Header.test.tsx, etc. Comprehensive updates for auth-mocking, error states, and redirect logic.

Sequence Diagram

sequenceDiagram
    participant SDK as Auth SDK
    participant Hub as ProjectHub
    participant API as useGetProjects
    participant Router as React Router

    Hub->>SDK: Check auth state
    Note over Hub, API: enabled: isSignedIn && !isAuthLoading
    SDK-->>Hub: Auth Ready (Signed In)
    Hub->>API: Fetch Projects
    API-->>Hub: Return Results (1 Project Found)
    
    alt Single Project Case
        Hub->>Router: Navigate to /:projectId/dashboard
    else Multiple Projects Case
        Hub-->>User: Render Project List
    end

    alt API Error Case
        API-->>Hub: Fetch Error
        Hub->>Hub: Set isStatsError(true)
        Hub-->>User: Show "Failed to load" on Card Stats
    end
Loading

Automation tests

  • Integration tests:
    • ProjectHub: Verified the single-project redirect logic and auth-loading states.
    • Header: Verified that loading and error states from both Auth and API are combined and passed to the switcher.
  • Unit tests:
    • ProjectCard: Verified that isStatsError correctly renders the ErrorIndicator in both badges and stats sections.
    • ProjectSwitcher: Confirmed the dropdown is replaced by an error icon when the fetch fails.
  • Mocks: Updated UserProfile and Header tests to support new authentication mock structures.

Summary by CodeRabbit

  • New Features

    • New full-page login experience with mock/real API toggle, animated background, and supportive visuals.
    • Route protection requiring sign-in and a dedicated sign-in page.
    • User profile now displays fetched user details and avatar.
    • Project cards and switcher show explicit error indicators when stats or projects fail to load.
  • Improvements

    • Updated authentication integration and simplified project loading flow.
    • Added a persistent mock-mode toggle for easier testing and local development.

Adjust ProjectHub to match a simplified projects response and improve auth handling. Removed the auto-pagination effect and switched to using projectsResponse.projects directly. Added Asgardeo auth loading into the skeleton/loading state so the UI waits for auth, and wired MockConfig to set the ProjectCard isStatsError flag when mocks are disabled. Also added imports for navigation and providers and left a commented-out single-project auto-navigation snippet for future use.
Add and wire up mocks for useAsgardeo and useMockConfig, and update the ProjectCard mock to surface an isStatsError attribute via data-stats-error. Set sensible default mock returns in beforeEach (auth not loading, mocks enabled, projects returned). Add tests for auth-loading skeletons and for isStatsError behavior when mock config is enabled/disabled. Adjust mocked getProjects data shape in tests (use projects directly) and simplify some existing tests; remove the fetchNextPage test. Overall improves coverage and handles auth/config variations in ProjectHub tests.
Introduce an optional isError prop and import ErrorIndicator. When isError is true, render ErrorIndicator for Open Cases and Active Chats instead of their numeric values, preserving the existing typography/styling otherwise. This surfaces error states in the project card stats UI.
Add an optional isError prop and import ErrorIndicator in ProjectCardBadges. When isError is true, render ErrorIndicator for the status instead of the status Chip; otherwise continue rendering the status Chip with getStatusColor. This surfaces status load errors in the project card UI.
Expose an optional isStatsError prop on ProjectCardProps, destructure it in the component, and forward it as isError to ProjectCardBadges and ProjectCardStats so child components can render an error state for stats.
Add a mock for the ErrorIndicator component and a new test in ProjectCardStats.test.tsx that verifies error indicators are shown when isError is true (for "Open Cases" and "Active Chats") and that numeric counts are not rendered. This supplements existing tests for counts and formatted date.
Mock the ErrorIndicator component in ProjectCardBadges tests and add a test that verifies the error indicator is rendered when isError is true, while the status chip is not displayed. Updates the ProjectCardBadges.test.tsx to improve coverage for error rendering behavior.
Update mocked ProjectCardBadges and ProjectCardStats to accept an isError prop and render 'Error'/'No Error' accordingly. Add a new test that renders ProjectCard with isStatsError=true and asserts the badges and stats sub-components receive and display the error state.
Import MockConfigProvider and expand useAsgardeo destructure to include isSignedIn and isLoading (aliased to isAuthLoading). Update user rendering logic to show the loading state while authentication is loading, and fall back to the error user if no user data is available. Also tidy ternary formatting for readability.
Replace useInfiniteQuery with useQuery in useGetProjects. Integrate Asgardeo auth to obtain ID token and add MockConfigProvider support to return paginated mock data (with API_MOCK_DELAY). Update queryKey to include mock flag, simplify pagination to offset/limit, and remove infinite pagination handlers. Implement real backend POST to /projects/search with Authorization and error handling, add logger messages, and gate execution via an enabled flag (mock enabled or user signed in and auth not loading).
Use isSignedIn and isLoading (aliased to isAuthLoading) from useAsgardeo and update the react-query `enabled` flag so the request only runs when mock mode is active or the user is signed in and auth loading has finished. This prevents the user details fetch from firing prematurely while authentication state is still being determined.
Set a default size prop ('small') for ErrorIndicator and compute an iconSize (16/24/32 for small/medium/large). Pass the computed iconSize to TriangleAlert and use the size prop directly on IconButton (removing the redundant fallback). This ensures consistent visual scaling and prevents undefined size values.
Add a mock for useAsgardeo and extend the ProjectSwitcher test mock to include an isError prop (exposed via data-error). Add tests to verify that Header forwards auth loading (isLoading from useAsgardeo) to ProjectSwitcher and that search projects errors set isError on ProjectSwitcher. Also adjust mocked ProjectSwitcher props handling to assert these behaviors.
Mock the ErrorIndicator component and add a unit test for ProjectSwitcher to verify the error state. The test ensures that when isError is true the error-indicator is rendered (showing "Error: Projects") and the project select is not displayed.
Update UserProfile unit tests to use mockUserDetails and introduce explicit hook mocks. Added mocks for useAsgardeo, MockConfigProvider, and useGetUserDetails and a beforeEach to clear and set default mock returns. Replaced previous assertions to check firstName/lastName/email/timeZone/id and added new test cases for: authenticated rendering, not-signed-in with mocks disabled (should not render), rendering when mocks are enabled, and handling of a failing user fetch. Removed the old useLogger mock and adjusted imports accordingly.
Import useAsgardeo and include its loading state to avoid showing project UI while auth is initializing. Remove pagination/fetchNextPage logic and adapt projects access to use projectsResponse.projects instead of pages.flatMap; update the useMemo dependency accordingly. Also surface isError to the ProjectSwitcher and combine isLoading with auth loading for accurate loading state.
Import ErrorIndicator and add an isError prop to ProjectSwitcher. When isError is true the component renders a styled error box containing ErrorIndicator for the "Projects" entity (preserving the existing loading branch). This surfaces project load failures in the header switcher UI.
@dileepapeiris dileepapeiris self-assigned this Feb 4, 2026
@dileepapeiris
dileepapeiris requested a review from Copilot February 4, 2026 20:30
@coderabbitai

coderabbitai Bot commented Feb 4, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR migrates auth to @asgardeo/react, adds an AuthGuard and mock-config provider, creates a full login page (multiple components), converts projects fetching from infinite to standard queries with mock support, and introduces ErrorIndicator-driven error paths across header, project cards, and related tests.

Changes

Cohort / File(s) Summary
Dependencies & Auth Config
apps/customer-portal/webapp/package.json, apps/customer-portal/webapp/src/config/authConfig.ts
Replaced legacy Asgardeo deps with @asgardeo/react ^0.10.0 and replaced constant auth config with getAuthConfig()/AuthConfig and runtime env validation.
App Shell & Routing
apps/customer-portal/webapp/src/App.tsx, apps/customer-portal/webapp/src/AppWithConfig.tsx, apps/customer-portal/webapp/src/layouts/AppLayout.tsx
Reworked routing to separate public (/login) and protected routes, introduced AsgardeoProvider/MockConfigProvider wrappers, and made AppLayout accept optional children.
Auth Guard
apps/customer-portal/webapp/src/AuthGuard.tsx, apps/customer-portal/webapp/src/__tests__/AuthGuard.test.tsx
Added AuthGuard to enforce auth for protected routes, manage global loader via LoaderContext, redirect unauthenticated users to /login, and included tests covering loading/signed-in/redirect scenarios.
Mock Config
apps/customer-portal/webapp/src/providers/MockConfigProvider.tsx, apps/customer-portal/webapp/src/providers/__tests__/MockConfigProvider.test.tsx
New MockConfigProvider + useMockConfig for toggling mock APIs with localStorage persistence and SSR-safety; tests for init, persistence, and misuse.
Login Page & Components
apps/customer-portal/webapp/src/pages/LoginPage.tsx, apps/customer-portal/webapp/src/components/login-page/*
Added LoginPage and subcomponents: LoginBox (mock/real toggle + sign-in), LoginSlogan, LoginBackground, LoginFooter, ParticleBackground; plus unit tests for these components.
Auth & User Details Hooks
apps/customer-portal/webapp/src/api/useGetUserDetails.ts, apps/customer-portal/webapp/src/config/authConfig.ts
New useGetUserDetails hook with mock support and Asgardeo token usage; auth config refactor (see above).
Projects API & Page
apps/customer-portal/webapp/src/api/useGetProjects.ts, apps/customer-portal/webapp/src/pages/ProjectHub.tsx, apps/customer-portal/webapp/src/pages/__tests__/ProjectHub.test.tsx
Converted projects hook from useInfiniteQuery to useQuery, added mock-mode path and auth gating; ProjectHub updated to use simplified response shape and wire isStatsError from mock state; tests updated accordingly.
Error Indicator & Error Paths
apps/customer-portal/webapp/src/components/common/errorIndicator/ErrorIndicator.tsx, apps/customer-portal/webapp/src/components/common/header/ProjectSwitcher.tsx, apps/customer-portal/webapp/src/components/projectHub/projectCard/*
Added ErrorIndicator component and propagated isError/isStatsError props to ProjectSwitcher, ProjectCardBadges, ProjectCardStats and their tests to render error UI.
Header, Actions & UserProfile
apps/customer-portal/webapp/src/components/common/header/{Header,Actions,UserProfile}.tsx, apps/customer-portal/webapp/src/components/common/header/__tests__/*
Actions gained showUserProfile prop; Header and UserProfile integrated with Asgardeo and useGetUserDetails, updated loading/error handling and tests updated to reflect auth/mock states.
Models & Constants
apps/customer-portal/webapp/src/models/responses.ts, apps/customer-portal/webapp/src/models/mockData.ts, apps/customer-portal/webapp/src/constants/loginScreenConstants.tsx
Added UserDetails interface, removed role/status from UserProfile, replaced mockUser with mockUserDetails, and added login screen slogan constants.
Tests & Mocks
apps/customer-portal/webapp/src/components/**/__tests__/*, other tests listed in PR
Expanded test coverage across AuthGuard, header, login page, project card components, and mocks updated to accept new props and behaviors (isError/isStatsError/isAuthLoading).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant App
    participant AuthGuard
    participant Asgardeo as AsgardeoProvider
    participant Backend

    User->>Browser: Navigate to protected route (/projects)
    Browser->>App: Route request
    App->>AuthGuard: Evaluate access
    AuthGuard->>Asgardeo: useAsgardeo() -> isLoading / isSignedIn
    Asgardeo-->>AuthGuard: auth state
    alt not signed in
        AuthGuard->>AuthGuard: ensure loader hidden
        AuthGuard->>Browser: Redirect to /login (preserve return state)
        Browser->>App: Render LoginPage
        User->>LoginPage: Click "Continue with Real APIs"
        LoginPage->>Asgardeo: signIn()
        Asgardeo->>Backend: Auth flow -> token
        Backend-->>Asgardeo: JWT
        Asgardeo->>Browser: store token, redirect back
    else signed in
        AuthGuard->>App: Render protected routes
        App->>Backend: Fetch projects (useGetProjects uses token or mock)
        Backend-->>App: Projects data
        App->>User: Render dashboard (ProjectHub, ProjectCard, etc.)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Suggested reviewers

  • v15a1
  • cloby99
  • Rashmika998

Poem

🐰 I hopped through routes both safe and new,
Switched to Asgardeo, signed in true,
Particles twinkled, mock toggles played,
Errors now show where fetches frayed,
The portal hums — the rabbit's pleased! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: integrating the Project Search API and implementing error handling across the Customer Portal frontend.
Description check ✅ Passed The description comprehensively covers Purpose, Goals, Approach, User Stories, and includes a detailed Walkthrough with a sequence diagram and changes table. However, it is missing required sections: Release note, Documentation, Training, Certification, Marketing, Samples, Related PRs, Migrations, Test environment, and Security checks.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 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 added Type/New Feature Represents a request or task for a new feature Type/Improvement Marks enhancements or improvements to existing features Type/UX Refers to user experience-related tasks or issues App/Customer Portal Area/Frontend Platform/Web labels Feb 4, 2026
@dileepapeiris dileepapeiris moved this from Todo to Done in Customer Portal Development Feb 4, 2026

Copilot AI 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.

Pull request overview

This PR migrates the authentication system from @asgardeo/auth-react to @asgardeo/react, refactors the project fetching logic from infinite scrolling to standard queries, and introduces comprehensive error handling with visual indicators across the application. It also adds a new login page with mock API support and implements auth guards to protect routes.

Changes:

  • Migrated from @asgardeo/auth-react to @asgardeo/react package and implemented AuthGuard for route protection
  • Refactored useGetProjects from infinite query to standard query pattern with auth-based enabled conditions
  • Added ErrorIndicator components throughout the UI to display API fetch failures gracefully
  • Introduced login page with mock/real API selection and MockConfigProvider for state management

Reviewed changes

Copilot reviewed 39 out of 43 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
package.json Updated Asgardeo package dependency from @asgardeo/auth-react to @asgardeo/react
AppWithConfig.tsx Migrated to AsgardeoProvider and added MockConfigProvider wrapper
App.tsx Added AuthGuard wrapper around protected routes and new /login public route
AuthGuard.tsx New authentication guard component that redirects unauthenticated users
authConfig.ts Refactored config validation with improved error messaging
useGetProjects.ts Migrated from infinite query to standard query with mock support and auth guards
useGetUserDetails.ts New hook for fetching user details with mock support
ProjectHub.tsx Added auth loading checks and stats error handling (single-project redirect commented out)
Header.tsx Removed infinite scroll logic, added auth loading state and error propagation
ProjectSwitcher.tsx Added error state rendering with ErrorIndicator
UserProfile.tsx Implemented dynamic user rendering with loading/error states
ProjectCard.tsx, ProjectCardStats.tsx, ProjectCardBadges.tsx Added isStatsError prop with error indicator support
ErrorIndicator.tsx New reusable component for displaying fetch errors with tooltips
LoginPage.tsx, LoginBox.tsx, LoginSlogan.tsx, etc. New login page components with mock API selection
MockConfigProvider.tsx New context provider for managing mock mode state with localStorage persistence
AppLayout.tsx Added optional children prop support
responses.ts Split UserProfile into separate UserDetails interface
Various test files Updated tests to mock new auth hooks and verify error handling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/customer-portal/webapp/src/layouts/AppLayout.tsx
Comment thread apps/customer-portal/webapp/src/pages/ProjectHub.tsx
Comment thread apps/customer-portal/webapp/src/api/useGetProjects.ts
Comment thread apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx Outdated
Comment thread apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx Outdated
Comment thread apps/customer-portal/webapp/src/pages/ProjectHub.tsx Outdated

@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: 10

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/components/common/header/__tests__/Header.test.tsx (1)

289-315: ⚠️ Potential issue | 🟡 Minor

Remove stale tests for infinite query behavior.

These tests reference fetchNextPage and hasNextPage, which are useInfiniteQuery return values. According to the PR changes, useGetProjects was converted to use useQuery, and looking at Header.tsx (lines 51-55 in the external context), the component only destructures data, isLoading, and isError — it no longer uses fetchNextPage or hasNextPage.

These tests pass only because the mock provides these values, but they're testing phantom behavior that doesn't exist in the component.

🧹 Proposed fix: Remove stale tests
-  it("should call fetchNextPage if hasNextPage is true", () => {
-    mockUseSearchProjects.mockReturnValue({
-      data: { pages: [{ projects: mockProjects }] },
-      fetchNextPage: mockFetchNextPage,
-      hasNextPage: true,
-      isFetchingNextPage: false,
-      isError: false,
-    });
-
-    render(<Header onToggleSidebar={mockOnToggleSidebar} />);
-
-    expect(mockFetchNextPage).toHaveBeenCalled();
-  });
-
-  it("should NOT call fetchNextPage if isError is true", () => {
-    mockUseSearchProjects.mockReturnValue({
-      data: { pages: [{ projects: mockProjects }] },
-      fetchNextPage: mockFetchNextPage,
-      hasNextPage: true,
-      isFetchingNextPage: false,
-      isError: true,
-    });
-
-    render(<Header onToggleSidebar={mockOnToggleSidebar} />);
-
-    expect(mockFetchNextPage).not.toHaveBeenCalled();
-  });

Also consider updating the mock return structure at lines 108-117 and 187-195 to match the new useQuery return shape (removing fetchNextPage, hasNextPage, isFetchingNextPage, and pages).

🤖 Fix all issues with AI agents
In `@apps/customer-portal/webapp/package.json`:
- Line 13: The dependency entry for "@asgardeo/react" in package.json uses a
non-existent version "^0.10.0"; update that dependency to a valid published
version (for example change to "^0.6.30") or verify the package name if a
different package was intended, then run npm install to confirm the fix; locate
the dependency in package.json (the "@asgardeo/react" entry) and replace the
version string accordingly.

In `@apps/customer-portal/webapp/src/api/useGetProjects.ts`:
- Around line 88-100: The POST to `${baseUrl}/projects/search` currently sends
an empty body (const body = {}) causing pagination/search to be ignored; update
the request payload in useGetProjects.ts to include the searchData object (or
explicitly include its pagination fields like limit and offset and any filters)
so the real API receives the same parameters used by the mock path; ensure the
fetch call's body is JSON.stringify(searchData) (or a merged object if
additional metadata is required) and keep Authorization and header usage as-is.

In `@apps/customer-portal/webapp/src/api/useGetUserDetails.ts`:
- Around line 34-81: The query key in useGetUserDetails (queryKey:
["userDetails", isMockEnabled]) is missing a per-user identifier, causing cached
data from one user to be served to another; update useGetUserDetails to include
a stable user identifier in the queryKey (e.g., decode the id token returned by
getIdToken() to extract the subject/user id or call a helper that returns
currentUserId and use queryKey: ["userDetails", currentUserId, isMockEnabled])
and adjust the enabled logic to depend on that id (enabled: isMockEnabled ||
(isSignedIn && !isAuthLoading && !!currentUserId)); alternatively, ensure
signOut() calls queryClient.invalidateQueries(["userDetails"]) (or a broader
user-scoped namespace) to clear user-specific caches—apply the same pattern to
all other user-scoped queries.

In `@apps/customer-portal/webapp/src/AuthGuard.tsx`:
- Around line 42-46: The AuthGuard currently falls through to return <Outlet />
while isLoading is true, allowing protected content to flash; update the
AuthGuard component to explicitly handle the loading state by returning null or
a placeholder/loading component when isLoading is true (before checking
isSignedIn), so only when isLoading is false do you evaluate isSignedIn and
either Navigate to "/login" or render <Outlet />; refer to the isLoading and
isSignedIn checks in AuthGuard and the usage of Navigate and Outlet to locate
where to add the early return for the loading state.

In
`@apps/customer-portal/webapp/src/components/common/header/__tests__/UserProfile.test.tsx`:
- Around line 68-76: The test currently asserts for fields not rendered by
UserProfile; update the assertions in UserProfile.test.tsx to check that
UserMenu receives the combined name and email only: replace separate
firstName/lastName expects with a single expect for the combined name string
built from mockUserDetails (e.g., `${mockUserDetails.firstName}
${mockUserDetails.lastName}`.trim()), keep the expect for mockUserDetails.email,
and remove assertions for timeZone and id since UserProfile only passes name,
email, and avatar to UserMenu.

In `@apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx`:
- Around line 68-71: The errorUser object is missing the email property which
makes it inconsistent with loadingUser and can break UserMenu; update the
errorUser definition (the constant named errorUser) to include an email field
matching the other placeholders (e.g., a placeholder/error indicator or empty
string) so it has name, email, and avatar properties like loadingUser, ensuring
UserMenu receives a consistent shape.

In `@apps/customer-portal/webapp/src/config/authConfig.ts`:
- Line 57: authConfig is being initialized at module load via the exported
constant authConfig = getAuthConfig(), which causes the app to crash before
MockConfigProvider can be set up when auth env vars are missing; change this to
lazy initialization by removing the eager export and instead call
getAuthConfig() at runtime where needed (e.g., inside AppWithConfig.tsx or a new
wrapper component) so the call happens after MockConfigProvider is mounted or
after you detect mock mode; update usages that import authConfig to call
getAuthConfig() (or receive the result via props/context) and ensure
getAuthConfig() errors are handled locally so missing env vars don't throw
during module evaluation.

In `@apps/customer-portal/webapp/src/layouts/AppLayout.tsx`:
- Around line 32-36: AppLayoutProps references React.ReactNode but React isn't
imported, causing a TS compile error; update the file to import the type
directly (e.g., add an import type for ReactNode from 'react') and then use
ReactNode in the interface (or keep React.ReactNode after importing React) so
the AppLayoutProps and the AppLayout component compile correctly; target the
interface AppLayoutProps and the AppLayout function signature to ensure the type
is resolved.

In `@apps/customer-portal/webapp/src/pages/LoginPage.tsx`:
- Around line 40-43: The inline style object in LoginPage uses invalid flex
values alignItems: "top" and justifyContent: "left"; update the style where
these properties are set (the style block applied to the LoginPage container) to
use valid flex values, e.g., replace both with "flex-start" (alignItems:
"flex-start", justifyContent: "flex-start") so the flex layout honors the
intended top-left alignment.

In `@apps/customer-portal/webapp/src/pages/ProjectHub.tsx`:
- Line 159: The prop isStatsError is currently set using inverted mock-mode
logic (isStatsError={!isMockEnabled}), causing production to always show error
states; change the ProjectHub usage to pass a real stats error flag instead:
either wire up the actual stats API error state (e.g., a useState/useSelector
like statsError and pass isStatsError={statsError}) or, if the stats endpoint
isn't implemented yet, set isStatsError={false} until you add real error
handling; update any related data fetching hook (e.g., the fetch or useEffect
that loads stats) to set the chosen statsError variable when the API fails so
the prop reflects real failure.
🧹 Nitpick comments (5)
apps/customer-portal/webapp/src/layouts/AppLayout.tsx (1)

104-108: Prefer nullish coalescing for children fallback.

Using children || ... will treat valid falsy children (0, "", false) as absent. ?? only falls back when children is null/undefined.

🔧 Suggested tweak
-              {children || (
+              {children ?? (
                 <Outlet
                   context={{ sidebarCollapsed: shellState.sidebarCollapsed }}
                 />
               )}
apps/customer-portal/webapp/src/components/login-page/ParticleBackground.tsx (1)

19-108: Respect prefers-reduced-motion to avoid forced animation.
Consider skipping the animation when users request reduced motion.

♿ Suggested change (respect reduced motion)
 useEffect(() => {
+  const prefersReducedMotion = window.matchMedia(
+    "(prefers-reduced-motion: reduce)",
+  ).matches;
+  if (prefersReducedMotion) return;
+
   const canvas = canvasRef.current;
   if (!canvas) return;
apps/customer-portal/webapp/src/pages/ProjectHub.tsx (1)

35-35: Remove unused import and commented code.

navigate is imported but only referenced in commented-out code (lines 49-53). Either implement the single-project redirect feature or remove both the import and the commented code.

Proposed fix
-import { useNavigate } from "react-router";
...
-  const navigate = useNavigate();
...
-  // useEffect(() => {
-  //   if (!isLoading && !isError && projects.length === 1) {
-  //     navigate(`/${projects[0].id}/dashboard`);
-  //   }
-  // }, [projects, isLoading, isError, navigate]);

Also applies to: 49-53

apps/customer-portal/webapp/src/components/common/header/UserProfile.tsx (1)

35-37: Remove unused destructured variables.

isSignedIn and isMockEnabled are destructured but never used in this component.

Proposed fix
-  const { signOut, isSignedIn, isLoading: isAuthLoading } = useAsgardeo();
-  const { isMockEnabled } = useMockConfig();
+  const { signOut, isLoading: isAuthLoading } = useAsgardeo();
+  useMockConfig(); // Ensure provider context is available

If useMockConfig() isn't needed at all, remove line 36 entirely along with the import on line 20.

apps/customer-portal/webapp/src/components/common/header/__tests__/Header.test.tsx (1)

108-122: Mock return structure doesn't match the new useQuery return shape.

The mock returns data: { pages: [{ projects: mockProjects }] }, which is the useInfiniteQuery structure. Since the hook was converted to useQuery, it now returns data: { projects, offset, limit, totalRecords } directly (matching SearchProjectsResponse).

The tests may still pass if the component gracefully handles missing properties, but the mock should accurately reflect the actual data structure for reliable testing.

♻️ Proposed fix to align mock with useQuery return shape
 const mockUseSearchProjects = vi.fn(() => ({
   data: {
-    pages: [{ projects: mockProjects }],
+    projects: mockProjects,
+    offset: 0,
+    limit: 100,
+    totalRecords: mockProjects.length,
   },
-  fetchNextPage: mockFetchNextPage,
-  hasNextPage: false,
-  isFetchingNextPage: false,
+  isLoading: false,
   isError: false,
 })) as any;

Apply the same change to the beforeEach block at lines 187-195.

Comment thread apps/customer-portal/webapp/package.json
Comment thread apps/customer-portal/webapp/src/api/useGetProjects.ts
Comment thread apps/customer-portal/webapp/src/api/useGetUserDetails.ts
Comment thread apps/customer-portal/webapp/src/AuthGuard.tsx
Comment thread apps/customer-portal/webapp/src/config/authConfig.ts
Comment thread apps/customer-portal/webapp/src/layouts/AppLayout.tsx
Comment thread apps/customer-portal/webapp/src/pages/LoginPage.tsx
Comment thread apps/customer-portal/webapp/src/pages/ProjectHub.tsx
Remove the unused useNavigate import and its instantiation. Comment out the useEffect that automatically navigates to a single project's dashboard (with a TODO to re-enable in production) to prevent automatic redirection during development/testing.
Replace non-standard alignment values with proper flexbox values and normalize slogan text styling. LoginPage: change alignItems/justifyContent from "top"/"left" to "flex-start" to use valid CSS flexbox values. LoginSlogan: remove explicit fontWeight and reduce fontSize from 1.1rem to 1rem for consistent visual spacing.
Add an explicit ReactNode type import from react and update AppLayoutProps to use ReactNode instead of React.ReactNode in AppLayout.tsx. This is a type-only cleanup with no runtime behavior changes.
Enhance UserProfile unit tests by adding explicit mocks for UserMenu, Skeleton, icons, ErrorIndicator, and useLogger. Replace fragile text-based assertions with data-testid checks for combined user name and email. Add a loading test to assert skeleton rendering and an error test to assert the ErrorIndicator is shown when user fetch fails. Overall improves reliability and coverage of UserProfile behavior under loading/error/authenticated states.
Remove the unused useMockConfig import and its isMockEnabled reference, and stop destructuring isSignedIn from useAsgardeo. Also remove a couple of redundant comment lines to clean up unused code; no functional behavior changes are expected.

@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: 1

🤖 Fix all issues with AI agents
In `@apps/customer-portal/webapp/src/pages/ProjectHub.tsx`:
- Around line 47-52: The commented auto-navigation useEffect refers to navigate
but there is no useNavigate import or navigate variable in ProjectHub (the
symbols involved are useEffect, useNavigate, and navigate, and the state tokens
projects, isLoading, isError), so if uncommented it will throw a ReferenceError;
fix by either adding a commented import line for useNavigate from
react-router-dom immediately above the commented block or updating the TODO to
explicitly state that useNavigate must be imported and navigate must be
initialized (e.g., const navigate = useNavigate()) before uncommenting the
block; ensure the instructions mention the exact symbols useNavigate and
navigate so future maintainers know what to add.
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/components/login-page/LoginSlogan.tsx (1)

21-49: Minor styling inconsistency: inline style vs sx prop.

Line 40 uses an inline style prop while the rest of the component consistently uses the sx prop. For consistency, consider using Box from @wso2/oxygen-ui with sx instead.

♻️ Suggested refactor for consistency
-import { Stack, Typography } from "@wso2/oxygen-ui";
+import { Box, Stack, Typography } from "@wso2/oxygen-ui";
-            <div style={{ display: "flex", alignItems: "center" }}>
-              {item.icon}
-            </div>
+            <Box sx={{ display: "flex", alignItems: "center" }}>
+              {item.icon}
+            </Box>
apps/customer-portal/webapp/src/components/common/header/__tests__/UserProfile.test.tsx (1)

112-118: Consider adding a test for useGetUserDetails loading state.

The current test only covers auth loading (isLoading: true from useAsgardeo). If the component also shows skeletons when useGetUserDetails.isLoading is true (while auth is complete), consider adding a separate test case for that scenario:

it("should render skeletons when user details are loading", () => {
  mockUseAsgardeo.mockReturnValue({ isSignedIn: true, isLoading: false });
  mockUseGetUserDetails.mockReturnValue({
    data: null,
    isLoading: true,
    isError: false,
  });
  render(<UserProfile />);
  expect(screen.getAllByTestId("skeleton")).toHaveLength(2);
});

This ensures both loading paths are verified independently.

Comment thread apps/customer-portal/webapp/src/pages/ProjectHub.tsx

@Rashmika998 Rashmika998 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.

LGTM
directory refactor and path changes will be tracked under #89

@Rashmika998
Rashmika998 merged commit c89225d into wso2-open-operations:customer-portal-milestone-1 Feb 5, 2026
1 check passed
@dileepapeiris

Copy link
Copy Markdown
Contributor Author

LGTM directory refactor and path changes will be tracked under #89

Those changes were addressed via #94 and #95

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/UX Refers to user experience-related tasks or issues

Projects

Status: Staging Deployed

Development

Successfully merging this pull request may close these issues.

3 participants