[Customer Portal][FE][Web] Implement Project Hub Empty State and Refactor Test Suite - #129
Conversation
Add a dedicated empty-state UI to ProjectHub: import EmptyIcon and replace the plain "No projects available." message with a centered Box containing EmptyIcon. Update the header and subtitle to conditionally display more helpful copy when there are no projects, while keeping the original text for non-empty states. Improves UX for users with no projects.
Replace imported mockProjects with an inline testProjects array and update numerous test mocks and assertions. Adjust mocked component import paths (project-card and skeleton), add mocks for IconButton, Tooltip, TriangleAlert, and EmptyIcon, and introduce a mock useLoader. Wrap rendered ProjectHub in MemoryRouter in tests. Update useGetProjects and useLogger mock module paths and adapt expectations (skeleton counts, project card counts, specific text checks, and tooltip/empty-state assertions). Also add logger assertions and clear mocks in beforeEach.
Introduce EmptyIcon React component (TypeScript) under customer-portal webapp common empty-state. The component renders a detailed SVG illustration (multiple paths and gradients), accepts SVGProps<SVGSVGElement> and spreads props onto the <svg>, and is exported as the default. File includes WSO2 Apache-2.0 license header and provides a reusable empty-state icon for the app.
📝 WalkthroughWalkthroughAdds a new typed React SVG component EmptyIcon and integrates it into ProjectHub to render a custom empty-state when no projects exist; tests are updated to cover the new UI, routing context, and loader mocks. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 1
🤖 Fix all issues with AI agents
In `@apps/customer-portal/webapp/src/pages/ProjectHub.tsx`:
- Around line 222-234: The header/subtitle currently check only projects.length
and thus show "No Projects Yet" during loading/error; update the render logic in
the ProjectHub component to base the empty-state condition on a
loaded-and-successful fetch (e.g., data exists and !isLoading and !isError)
instead of just projects.length === 0; modify the two Typography blocks that
reference projects.length (and any local variable derived from data like
projects) to use a predicate such as ( !isLoading && !isError && projects.length
=== 0 ) for the empty text and the inverse for the non-empty text, and ensure
loading skeletons and error UI remain shown when isLoading or isError are true.
🧹 Nitpick comments (4)
apps/customer-portal/webapp/src/components/common/empty-state/EmptyIcon.tsx (2)
25-32: Consider adding accessibility attributes to the SVG.The SVG lacks
role="img"and anaria-label(oraria-hidden="true"if purely decorative). Since this is an illustrative empty-state icon, marking it as decorative would be appropriate.Suggested improvement
const EmptyIcon = (props: SVGProps<SVGSVGElement>): JSX.Element => ( <svg width="268" height="229" viewBox="0 0 268 229" fill="none" xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" {...props} >
133-211: Hardcoded gradient IDs could collide if multiple instances are rendered.The gradient IDs (e.g.,
paint0_linear_1857_52) are global to the DOM. If twoEmptyIconcomponents are ever rendered on the same page, the second instance's<path>elements would reference the first instance's gradients, potentially causing visual issues. This is low risk for an empty-state illustration but worth noting for reusability.A common pattern is to generate a unique prefix (e.g., via
useId()) and prepend it to gradient IDs.apps/customer-portal/webapp/src/pages/ProjectHub.tsx (1)
124-124: The!projectsguard is redundant.
projectsis derived fromuseMemowith a fallback of[](line 47), so it can never be falsy.projects.length === 0alone suffices.- if (!projects || projects.length === 0) { + if (projects.length === 0) {apps/customer-portal/webapp/src/pages/__tests__/ProjectHub.test.tsx (1)
189-208: Error-state assertion relies on unmockedErrorIndicatorinternals.The test asserts
screen.getByTestId("tooltip")to verify the error state, butErrorIndicatorisn't explicitly mocked. This means the assertion depends onErrorIndicator's internal use of the mockedTooltipcomponent. IfErrorIndicatoris refactored, this test breaks without the error state actually changing.Consider adding an explicit mock for
ErrorIndicator:vi.mock("@components/common/error-indicator/ErrorIndicator", () => ({ default: ({ entityName }: any) => ( <div data-testid="error-indicator">{entityName}</div> ), }));Then assert on
screen.getByTestId("error-indicator")instead.
There was a problem hiding this comment.
Pull request overview
This PR improves the Project Hub empty state by introducing a dedicated EmptyIcon component, updating the Project Hub UI messaging when no projects are available, and adjusting the Project Hub tests/mocks to reflect the new UI and dependencies.
Changes:
- Added a new
EmptyIconSVG React component for empty-state visuals. - Updated
ProjectHubto render the new empty-state icon and conditional header/subtitle messaging. - Refactored
ProjectHubtests to use in-file project fixtures, add router wrapping, and expand mocks forErrorIndicatordependencies.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| apps/customer-portal/webapp/src/pages/ProjectHub.tsx | Adds EmptyIcon and conditional empty-state messaging in the Project Hub UI. |
| apps/customer-portal/webapp/src/components/common/empty-state/EmptyIcon.tsx | Introduces the SVG-based empty-state icon component. |
| apps/customer-portal/webapp/src/pages/tests/ProjectHub.test.tsx | Updates tests/mocks to validate the new empty state and updated error indicator behavior. |
Comments suppressed due to low confidence (1)
apps/customer-portal/webapp/src/pages/tests/ProjectHub.test.tsx:206
- This assertion only checks that some Tooltip rendered. Since the Tooltip mock preserves the
titleprop, it would be more robust to assert the actual error tooltip content (e.g., that the tooltiptitleequals "Failed to fetch projects data") so the test fails ifErrorIndicatorstops rendering or is wired to the wrong entityName.
expect(screen.getByTestId("tooltip")).toBeInTheDocument();
await waitFor(() => {
expect(mockLogger.error).toHaveBeenCalledWith(
expect.stringContaining("Failed to load projects"),
);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Simplify the empty-list guard in ProjectHub.tsx by removing the unnecessary `!projects` falsy check and only checking `projects.length === 0`. This reflects that `projects` is guaranteed to be defined (non-nullable) in this component and keeps the condition concise.
Add accessibility attributes to the decorative EmptyIcon SVG (aria-hidden and focusable=false) and change ProjectHub header/subtitle logic so the "No Projects Yet" message only appears when not loading, not auth-loading, and no error. This prevents the empty-state text from showing while data or auth state is still loading. Updated tests to assert the empty message is not present during loading and to expect the "Select Your Project" heading instead.
7d6b6f1
into
wso2-open-operations:customer-portal-milestone-1
Description
This pull request introduces an improved empty state experience for the Project Hub page by adding a new
EmptyIconcomponent, updating the UI to use this icon when there are no projects, and enhancing the test coverage to reflect these changes. Additionally, the test setup has been refactored for better reliability and maintainability.User Interface Improvements:
EmptyIconSVG React component to visually represent the empty state in the Project Hub (EmptyIcon.tsx).EmptyIconand improved messaging when there are no projects, providing a more user-friendly empty state (ProjectHub.tsx). [1] [2] [3]Testing and Test Infrastructure:
EmptyIconcomponent, and ensure accurate rendering with the new empty state UI (ProjectHub.test.tsx). [1] [2] [3]ProjectHub.test.tsx). [1] [2] [3] [4]Summary by CodeRabbit
New Features
Tests