Skip to content

[Customer Portal][FE][Web] Implement Outstanding Cases component on Support page - #101

Merged
Rashmika998 merged 11 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-support-outstanding-cases-chat-history-v1
Feb 9, 2026
Merged

Rashmika998 merged 11 commits into
wso2-open-operations:customer-portal-milestone-1from
dileepapeiris:feat/add-support-outstanding-cases-chat-history-v1

Conversation

@dileepapeiris

@dileepapeiris dileepapeiris commented Feb 9, 2026 •

Copy link
Copy Markdown
Contributor

Overview

This PR enhances the Support dashboard by introducing the Outstanding Cases overview and building the foundation for chat history retrieval. It combines UI component development, API hook implementation (supporting both mock and real environments), and utility updates for status mapping and time formatting.

image image

Key Changes

1. Outstanding Cases UI

  • Components: Created SupportOverviewCard, OutstandingCasesList, and OutstandingCasesSkeleton.
  • Integration: Added the Outstanding Cases card to the SupportPage, fetching a limited, sorted list of project cases.
  • UX: Implemented skeleton loading states and empty states for cases.

2. Chat History API & Infrastructure

  • Hook: useGetChatHistory with dual-mode support (switches between mock data and real backend calls via VITE_USE_MOCK_DATA).
  • Auth: Integrated with Auth Service to retrieve and attach ID tokens for real API requests.
  • Models: Defined ChatHistoryItem and ChatHistoryResponse interfaces.

3. Utilities & Theming

  • Colors: Updated getStatusColor mappings for "open" and "awaiting" statuses.
  • Shared Utils: Added resolveColorFromTheme for consistent styling and formatRelativeTime for human-readable timestamps.

4. Testing

  • Hooks: Unit tests for useGetChatHistory covering loading, error, mock, and authenticated fetch scenarios.
  • Components: Render tests for the card footer, skeleton, and case list logic.

Logic Flow (Chat History Fetching)

sequenceDiagram
  participant UI as SupportPage / Hook Consumer
  participant Hook as useGetChatHistory
  participant Auth as AuthProvider
  participant API as Backend API
  participant Logger as Logger

  UI->>Hook: call useGetChatHistory(projectId)
  
  alt Mock Mode Enabled
    Hook->>Logger: debug "using mock"
    Hook-->>UI: return mockChatHistory (after delay)
  else Real Backend Mode
    Hook->>Auth: request id token
    Auth-->>Hook: id token / auth state
    Hook->>API: GET /chat-history?projectId (Auth Header)
    alt Success
        API-->>Hook: 200 JSON Response
        Hook-->>UI: parsed ChatHistoryResponse
    else Error
        API-->>Hook: Error Response
        Hook->>Logger: Error logs
        Hook-->>UI: throw error
    end
  end
Loading

🛠 File Summary

Cohort Key Files
API/Hooks useGetChatHistory.ts, apiConstants.ts
UI Components SupportOverviewCard.tsx, OutstandingCasesList.tsx, OutstandingCasesSkeleton.tsx
Pages SupportPage.tsx
Models/Mocks responses.ts, mockData.ts, mockFunctions.ts
Utilities support.ts, casesTable.ts
Tests useGetChatHistory.test.tsx, SupportOverviewCard.test.tsx, OutstandingCasesList.test.tsx

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Outstanding Cases" card to the Support page displaying active support cases with priority levels, severity indicators, assigned engineers, and creation times.
    • Support cases load asynchronously with a skeleton loading state.
  • Bug Fixes

    • Corrected status color indicators for case statuses.

Add a new support utilities file to the customer-portal webapp. Exposes resolveColorFromTheme(path, theme) which resolves a color from theme.palette using a dot-separated path (falls back to the input path if not found), and formatRelativeTime(date) which formats a Date or date string into human-readable relative times ("just now", "X minutes/hours/days/months/years ago") and returns "--" for invalid or undefined dates.
Correct inverted color mappings in getStatusColor: 'open' now returns info.main (was primary.main) and 'awaiting' now returns primary.main (was info.main). Aligns status color outputs with the intended design/spec.
Introduce OutstandingCasesList, a new React component to render outstanding support case rows for the customer portal overview card. Handles loading via OutstandingCasesSkeleton and shows an empty state message. Uses theme-aware colors (getStatusColor/getPriorityColor + resolveColorFromTheme), formats relative times, displays assigned engineer tooltip, and composes UI with @wso2/oxygen-ui Form/Card components and Chip.
Add unit tests for OutstandingCasesList (apps/customer-portal/webapp/src/components/support/support-overview-cards/__tests__/OutstandingCasesList.test.tsx). Tests use vitest and @testing-library/react and cover empty state rendering and rendering of case details (case number, title, severity, status, assigned engineer and relative created time) using a mocked CaseListItem.
Add unit tests for the SupportOverviewCard component using Vitest and React Testing Library. Tests verify rendering of title, subtitle, icon, children and footer button, and assert that the onFooterClick handler is called when the footer button is clicked.
Introduce a new reusable SupportOverviewCard React component (TypeScript) for support overview sections such as Outstanding Cases and Chat History. The component accepts title, subtitle, icon, children, footer CTA label and handler, and supports an iconVariant (orange|blue) to drive palette and icon color. Built with WSO2 Oxygen UI primitives and theme-aware styling, it renders a header with icon, content area for children, and a full-width footer button with an arrow icon.
Introduce OutstandingCasesSkeleton.tsx to provide a loading state for the outstanding cases list. The new component renders five placeholder cards using @wso2/oxygen-ui Box, Form.CardButton and Skeleton variants (text, circular, rounded) and applies layout styles via sx. Includes Apache 2.0 license header.
Introduce SUPPORT_OVERVIEW_CASES_LIMIT (value 5) in supportConstants.ts to control how many outstanding cases are shown on support overview cards. Provides a single source of truth for the UI limit and documents intent with an inline comment.
Fetch and display recent project cases on the Support page. Added useNavigate and useGetProjectCases with SUPPORT_OVERVIEW_CASES_LIMIT to load latest cases (sorted by createdOn). Introduced a SupportOverviewCard inside a Grid, showing an "Outstanding Cases" section with FileText icon and an OutstandingCasesList child; footer button navigates to the dashboard. Also wired isCasesLoading into the UI and preserved existing support stats and chat banner.
@dileepapeiris
dileepapeiris requested a review from Copilot February 9, 2026 02:03
@dileepapeiris dileepapeiris self-assigned this Feb 9, 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 App/Customer Portal Area/Frontend Platform/Web labels Feb 9, 2026
@coderabbitai

coderabbitai Bot commented Feb 9, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds new React components (OutstandingCasesList, OutstandingCasesSkeleton, SupportOverviewCard) to the customer portal's support overview section, including utility functions for time formatting and theme color resolution. Integrates case data fetching and display into SupportPage with loading states and minor color mapping adjustments.

Changes

Cohort / File(s) Summary
Outstanding Cases Components
apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx, OutstandingCasesSkeleton.tsx
New list component rendering support cases as cards with header, title, status, and meta details; skeleton component for loading state. Uses theme-aware styling and relative time formatting.
Support Overview Card Component
apps/customer-portal/webapp/src/components/support/support-overview-cards/SupportOverviewCard.tsx
Reusable card wrapper with icon, title, subtitle, content area, divider, and footer button; supports themed variants (orange/blue) with color palette mapping.
Component Tests
apps/customer-portal/webapp/src/components/support/support-overview-cards/__tests__/OutstandingCasesList.test.tsx, SupportOverviewCard.test.tsx
Test suites validating component rendering, data display, and callback invocation for new cards and list components.
Utility Functions
apps/customer-portal/webapp/src/utils/support.ts
New exported functions: formatRelativeTime (converts dates to human-readable relative time) and resolveColorFromTheme (resolves theme palette colors via dot-separated paths).
Case Utilities & Tests
apps/customer-portal/webapp/src/utils/casesTable.ts, __tests__/casesTable.test.ts
Color mapping swap in getStatusColor: "open" now returns "info.main" and "awaiting" returns "primary.main"; added default fallback; tests updated accordingly.
Support Page Integration
apps/customer-portal/webapp/src/pages/SupportPage.tsx
Integrated new components with case fetching via useGetProjectCases hook; added routing navigation and grid layout for outstanding cases card and list.
Support Constants
apps/customer-portal/webapp/src/constants/supportConstants.ts
Added new exported constant SUPPORT_OVERVIEW_CASES_LIMIT set to 5 for pagination limit.

Sequence Diagram

sequenceDiagram
    participant SupportPage
    participant useGetProjectCases
    participant OutstandingCasesList
    participant OutstandingCasesSkeleton

    SupportPage->>useGetProjectCases: fetch cases (limit: 5, sort: createdOn desc)
    useGetProjectCases-->>SupportPage: return cases data + isLoading state

    alt isLoading = true
        SupportPage->>OutstandingCasesSkeleton: render skeleton cards
        OutstandingCasesSkeleton-->>SupportPage: display loading placeholders
    else cases exist
        SupportPage->>OutstandingCasesList: pass cases + loading state
        OutstandingCasesList->>OutstandingCasesList: render case cards with details
        OutstandingCasesList-->>SupportPage: display case list
    else no cases
        OutstandingCasesList->>OutstandingCasesList: render empty state message
        OutstandingCasesList-->>SupportPage: display "No outstanding cases."
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Type/UX

Suggested reviewers

  • v15a1
  • cloby99
  • Rashmika998

Poem

🐰 A rabbit hops through the support trees,
Carrying cases with utmost ease!
Cards and skeletons dance in the light,
With colors and times all perfectly bright.
The list now displays, oh what a delight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description provides comprehensive coverage of key changes, objectives, logic flow, and file organization, though it deviates from the repository's template structure. While the description is detailed and informative, it does not follow the required template sections (Purpose, Goals, Approach, Release note, Documentation, etc.). Consider restructuring to align with the template for consistency.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing the Outstanding Cases component on the Support page, which is the primary focus of this PR.
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 docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉


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.

@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

🤖 Fix all issues with AI agents
In
`@apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx`:
- Around line 108-119: The Typography that renders c.title in
OutstandingCasesList currently uses overflow: "hidden" and textOverflow:
"ellipsis" but omits whiteSpace, so the ellipsis never appears; update the sx
object on that Typography (inside Form.CardContent) to include whiteSpace:
"nowrap" so textOverflow: "ellipsis" works (optionally ensure the container has
a constrained width if needed).

In `@apps/customer-portal/webapp/src/utils/support.ts`:
- Around line 24-33: The file references the Theme type in resolveColorFromTheme
but never imports it; add a type import for Theme at the top of the file (after
the license header) from your UI library (the same module other files use for
Theme, e.g. import { Theme } from '@mui/material/styles') so
resolveColorFromTheme(path: string, theme: Theme) compiles.
🧹 Nitpick comments (10)
apps/customer-portal/webapp/src/utils/support.ts (1)

41-73: formatRelativeTime looks correct overall; note the approximate month/year buckets.

The 30-day-month approximation is standard for relative-time displays and acceptable here. Edge-case: negative diffInSeconds (future dates) will fall through all guards and display a negative year/month count (e.g., "-1 years ago"). Consider returning a fallback for future dates if that's a realistic input.

apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesSkeleton.tsx (1)

28-28: Replace magic number 5 with SUPPORT_OVERVIEW_CASES_LIMIT.

This value duplicates the constant defined in supportConstants.ts. Using the constant ensures both stay in sync.

Proposed fix
+import { SUPPORT_OVERVIEW_CASES_LIMIT } from "@constants/supportConstants";
-      {Array.from({ length: 5 }).map((_, index) => (
+      {Array.from({ length: SUPPORT_OVERVIEW_CASES_LIMIT }).map((_, index) => (
apps/customer-portal/webapp/src/components/support/support-overview-cards/__tests__/OutstandingCasesList.test.tsx (1)

39-53: Consider adding a test for the loading state (isLoading={true}).

The component renders OutstandingCasesSkeleton when isLoading is true, but this path isn't tested. A quick test asserting skeleton presence would improve coverage of the component's three states (loading, empty, populated).

apps/customer-portal/webapp/src/api/__tests__/useGetChatHistory.test.tsx (2)

140-170: window.config restoration is not failure-safe.

If the test throws before line 169, window.config won't be restored, potentially polluting subsequent tests. Consider using afterEach or wrapping in try/finally.

♻️ Suggested improvement
   it("should fetch real data when mock is disabled", async () => {
     mockIsMockEnabled = false;
     const mockResponse = { /* ... */ };
 
     const originalConfig = window.config;
-    window.config = {
-      CUSTOMER_PORTAL_BACKEND_BASE_URL: "https://api.test",
-    } as typeof window.config;
-
-    vi.stubGlobal(
-      "fetch",
-      vi.fn().mockResolvedValue({
-        ok: true,
-        json: () => Promise.resolve(mockResponse),
-        status: 200,
-      } as Response),
-    );
-
-    const { result } = renderHook(
-      () => useGetChatHistory("project-1"),
-      { wrapper },
-    );
-
-    await waitFor(() => expect(result.current.isSuccess).toBe(true));
-
-    expect(result.current.data).toEqual(mockResponse);
-    expect(mockGetIdToken).toHaveBeenCalled();
-    expect(mockLogger.debug).toHaveBeenCalledWith(
-      expect.stringContaining(
-        "Fetching chat history for project ID: project-1, mock: false",
-      ),
-    );
-
-    window.config = originalConfig;
+    try {
+      window.config = {
+        CUSTOMER_PORTAL_BACKEND_BASE_URL: "https://api.test",
+      } as typeof window.config;
+
+      vi.stubGlobal(
+        "fetch",
+        vi.fn().mockResolvedValue({
+          ok: true,
+          json: () => Promise.resolve(mockResponse),
+          status: 200,
+        } as Response),
+      );
+
+      const { result } = renderHook(
+        () => useGetChatHistory("project-1"),
+        { wrapper },
+      );
+
+      await waitFor(() => expect(result.current.isSuccess).toBe(true));
+
+      expect(result.current.data).toEqual(mockResponse);
+      expect(mockGetIdToken).toHaveBeenCalled();
+    } finally {
+      window.config = originalConfig;
+    }
   });

The same applies to the error-handling test at lines 172–201.


66-69: Redundant manual mock clearing.

Lines 66–67 manually clear mockLogger.debug and mockLogger.error, but vi.clearAllMocks() on line 69 already clears all mocks. The manual calls are unnecessary.

apps/customer-portal/webapp/src/pages/SupportPage.tsx (1)

20-20: MessageSquare is imported but unused.

MessageSquare is imported on line 20 but not referenced anywhere in the JSX. If it's intended for a future chat history card, consider deferring the import until it's needed.

apps/customer-portal/webapp/src/components/support/support-overview-cards/SupportOverviewCard.tsx (4)

106-119: Footer button color is hardcoded to "warning" regardless of iconVariant.

This component is documented as a generic card for multiple sections (Outstanding Cases, Chat History). When used with iconVariant="blue", the header icon gets blue/info styling, but the footer CTA remains orange/warning—visually inconsistent. Consider deriving the button color from the variant.

♻️ Suggested fix
       <Button
         fullWidth
         variant="text"
-        color="warning"
+        color={paletteKey}
         onClick={onFooterClick}
         endIcon={<ArrowRight size={16} />}

98-105: Consider using the Divider component instead of an empty Box with a border.

An empty Box solely for a horizontal rule is less semantic. Oxygen UI's Divider conveys the same intent more clearly and keeps the markup consistent with the design system.

♻️ Suggested fix

Add Divider to the existing import:

 import {
   Box,
   Button,
+  Divider,
   Paper,
   Typography,
   alpha,
   colors,
   useTheme,
 } from "@wso2/oxygen-ui";

Replace the empty Box:

-      <Box
-        sx={{
-          borderTop: 1,
-          borderColor: "divider",
-          pt: 2,
-          mt: 1,
-        }}
-      />
+      <Divider sx={{ mt: 1 }} />

55-58: Icon color bypasses the theme while the background references it.

iconColor uses hardcoded colors.blue[600]/colors.orange[600], but the chip background (line 74) derives from theme.palette[paletteKey]. In a custom or dark theme, these could diverge. For consistency, consider pulling the icon color from the theme palette as well (e.g., theme.palette[paletteKey].main or .dark).


69-92: Nested Paper for the icon chip may render with unintended elevation/shadow.

The inner Paper (line 70) used as the icon background container inherits the default Paper elevation. If a flat look is intended, explicitly set elevation={0} to avoid a subtle shadow.

♻️ Suggested fix
         <Paper
+          elevation={0}
           sx={{
             width: 40,
             height: 40,

Comment thread apps/customer-portal/webapp/src/utils/support.ts

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

Implements a new “Outstanding Cases” overview card on the Support page (Customer Portal webapp) and introduces supporting UI utilities and data-fetching/mocking for related support features (including chat history).

Changes:

  • Add SupportOverviewCard + OutstandingCasesList (with skeleton + tests) and render it on SupportPage with a limited, sorted cases fetch.
  • Introduce shared support utils for theme color resolution and relative time formatting.
  • Add chat history response models, mock data/functions, and a useGetChatHistory React Query hook with tests.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
apps/customer-portal/webapp/src/utils/support.ts New support utilities (theme color resolution, relative time formatting).
apps/customer-portal/webapp/src/utils/casesTable.ts Adjust status-to-color mapping used by case UI.
apps/customer-portal/webapp/src/pages/SupportPage.tsx Fetch latest cases and render Outstanding Cases overview card.
apps/customer-portal/webapp/src/models/responses.ts Add chat history response typings.
apps/customer-portal/webapp/src/models/mockFunctions.ts Add mock chat history accessor for API hook.
apps/customer-portal/webapp/src/models/mockData.ts Add mock chat history dataset.
apps/customer-portal/webapp/src/constants/supportConstants.ts Add overview cases limit constant.
apps/customer-portal/webapp/src/constants/apiConstants.ts Add React Query key for chat history.
apps/customer-portal/webapp/src/components/support/support-overview-cards/SupportOverviewCard.tsx New reusable overview card component.
apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesList.tsx New Outstanding Cases list UI (status chip, severity dot, relative time).
apps/customer-portal/webapp/src/components/support/support-overview-cards/OutstandingCasesSkeleton.tsx Loading skeleton for the Outstanding Cases list.
apps/customer-portal/webapp/src/components/support/support-overview-cards/tests/SupportOverviewCard.test.tsx Unit tests for overview card component.
apps/customer-portal/webapp/src/components/support/support-overview-cards/tests/OutstandingCasesList.test.tsx Unit tests for Outstanding Cases list component.
apps/customer-portal/webapp/src/api/useGetChatHistory.ts New API hook for fetching (or mocking) chat history.
apps/customer-portal/webapp/src/api/tests/useGetChatHistory.test.tsx Unit tests for useGetChatHistory.

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

Comment thread apps/customer-portal/webapp/src/pages/SupportPage.tsx
Comment thread apps/customer-portal/webapp/src/pages/SupportPage.tsx
Comment thread apps/customer-portal/webapp/src/utils/casesTable.ts
Comment thread apps/customer-portal/webapp/src/utils/support.ts
Comment thread apps/customer-portal/webapp/src/pages/SupportPage.tsx
Use SUPPORT_OVERVIEW_CASES_LIMIT for skeleton rendering and remove unnecessary cursor styles and overflow ellipsis in the outstanding cases components. Update the assigned engineer label to “Assigned to {name}” and import OutstandingCasesList in SupportPage. Adjust unit tests for getStatusColor to reflect swapped expectations for "Open" and "Awaiting Response". Add missing colors/SxProps/Theme imports in support utilities.

@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

🤖 Fix all issues with AI agents
In `@apps/customer-portal/webapp/src/pages/SupportPage.tsx`:
- Around line 87-100: Handle fetch errors from useGetProjectCases by checking
the hook's isError (e.g., isCasesError) and surface it: log the error
(console.error or app logger) and render an error state inside the
SupportOverviewCard (e.g., replace OutstandingCasesList with an inline error
message or pass an error prop so OutstandingCasesList can show an error UI)
while preserving loading behavior for isCasesLoading; also replace the hardcoded
subtitle "Latest 5 support tickets" with a dynamic string using
SUPPORT_OVERVIEW_CASES_LIMIT (e.g., `Latest ${SUPPORT_OVERVIEW_CASES_LIMIT}
support tickets`) so the text stays in sync with the limit.

In `@apps/customer-portal/webapp/src/utils/support.ts`:
- Around line 42-74: formatRelativeTime currently returns negative "ago" strings
for future dates; add a guard after computing diffInSeconds in
formatRelativeTime to handle future inputs (date or string) by returning a safe
value (e.g., "just now" or a clear future-facing message) when diffInSeconds is
negative rather than proceeding to compute minutes/hours/days; update logic
around the diffInSeconds/diffInMinutes/diffInHours variables so future dates
never produce "-N ... ago".
🧹 Nitpick comments (2)
apps/customer-portal/webapp/src/pages/SupportPage.tsx (1)

20-20: Unused import: MessageSquare.

MessageSquare is imported but never referenced in this file. It's likely intended for a future "Chat History" card, but leaving it here adds noise.

apps/customer-portal/webapp/src/utils/support.ts (1)

17-17: Unused imports: colors and SxProps.

Neither colors nor SxProps is referenced anywhere in this file. They may have been left over from an earlier iteration.

Proposed fix
-import { colors, type SxProps, type Theme } from "@wso2/oxygen-ui";
+import type { Theme } from "@wso2/oxygen-ui";

Comment thread apps/customer-portal/webapp/src/pages/SupportPage.tsx
Comment thread apps/customer-portal/webapp/src/utils/support.ts

@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

@Rashmika998
Rashmika998 merged commit 2198aed into wso2-open-operations:customer-portal-milestone-1 Feb 9, 2026
1 check passed
@dileepapeiris dileepapeiris moved this from Done to Staging Deployed in Customer Portal Development Feb 10, 2026
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

Projects

Status: Staging Deployed

Development

Successfully merging this pull request may close these issues.

3 participants