diff --git a/apps/csm-portal/microapp/src/components/announcements/AnnouncementCard.tsx b/apps/csm-portal/microapp/src/components/announcements/AnnouncementCard.tsx index 1eb4d93d75..9ddd1bec13 100644 --- a/apps/csm-portal/microapp/src/components/announcements/AnnouncementCard.tsx +++ b/apps/csm-portal/microapp/src/components/announcements/AnnouncementCard.tsx @@ -27,7 +27,7 @@ export function AnnouncementCard({ item }: { item: CaseSummary }) { - + {item.number || "—"} diff --git a/apps/csm-portal/microapp/src/components/home/AssignedToMeSection.tsx b/apps/csm-portal/microapp/src/components/home/AssignedToMeSection.tsx index 99bb2a6e17..270309d361 100644 --- a/apps/csm-portal/microapp/src/components/home/AssignedToMeSection.tsx +++ b/apps/csm-portal/microapp/src/components/home/AssignedToMeSection.tsx @@ -14,21 +14,23 @@ // specific language governing permissions and limitations // under the License. -import { Button, Stack, Typography } from "@wso2/oxygen-ui"; +import { Card, Stack, Typography } from "@wso2/oxygen-ui"; import { useQuery } from "@tanstack/react-query"; -import { Link } from "react-router-dom"; import { currentUser } from "@src/services/currentUser"; import { dashboard } from "@src/services/dashboard"; import { CaseCard, CaseCardSkeleton } from "@components/support/CaseCard"; -import { EmptyState } from "@components/support/EmptyState"; import { ErrorState } from "@components/support/ErrorState"; +import { RefreshButton } from "./RefreshButton"; // The signed-in user's own non-closed cases — mirrors the webapp's "Assigned to me" widget // (apps/csm-portal/webapp/src/features/csm-dashboard/components/MyAssignedCases.tsx), capped to a -// short 5-item preview with a "View all" link out to Support, rather than paginated in place. +// short 5-item preview. No "View all" (Support already covers the full list) — instead a +// RefreshButton, same as the webapp's widget header. export function AssignedToMeSection() { const { data: currentUserId } = useQuery(currentUser.id()); - const { data, isPending, isError, refetch } = useQuery(dashboard.assignedToMe(currentUserId ?? null)); + const { data, isPending, isFetching, isError, dataUpdatedAt, refetch } = useQuery( + dashboard.assignedToMe(currentUserId ?? null), + ); const items = data?.items ?? []; @@ -36,12 +38,15 @@ export function AssignedToMeSection() { Assigned to me - + void refetch()} + isFetching={isFetching} + updatedAt={dataUpdatedAt} + label="Refresh assigned cases" + /> - {isLoading ? ( + {isPending ? ( {Array.from({ length: 3 }).map((_, index) => ( @@ -50,7 +55,14 @@ export function AssignedToMeSection() { ) : isError ? ( void refetch()} /> ) : items.length === 0 ? ( - + // Lighter than the shared EmptyState (no icon, less padding) — a big "nothing here" + // block reads as too prominent for the first thing on the home page — but still boxed + // in a card so it's clearly this section's content, not blank/broken-looking space. + + + No cases assigned to you. + + ) : ( {items.map((item) => ( diff --git a/apps/csm-portal/microapp/src/components/home/RefreshButton.tsx b/apps/csm-portal/microapp/src/components/home/RefreshButton.tsx new file mode 100644 index 0000000000..aae77b908c --- /dev/null +++ b/apps/csm-portal/microapp/src/components/home/RefreshButton.tsx @@ -0,0 +1,53 @@ +// Copyright (c) 2026 WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import { Box, IconButton, Tooltip, Typography } from "@wso2/oxygen-ui"; +import { RefreshCw } from "@wso2/oxygen-ui-icons-react"; +import { fromNow } from "@utils/dateTime"; + +interface RefreshButtonProps { + /** Re-runs the widget's query. Wire to the react-query `refetch`. */ + onRefresh: () => void; + /** True while a fetch is in flight; disables the control to avoid re-entrancy. */ + isFetching: boolean; + /** react-query `dataUpdatedAt` (ms). When set, shows a "Last refreshed" hint. */ + updatedAt?: number; + /** Accessible label / tooltip, e.g. "Refresh assigned cases". */ + label: string; +} + +// Reusable dashboard-widget refresh control — mirrors the webapp's RefreshButton +// (apps/csm-portal/webapp/src/features/csm-dashboard/components/RefreshButton.tsx): +// icon button + "Last refreshed X ago" hint, so refresh looks and behaves the same across apps. +export function RefreshButton({ onRefresh, isFetching, updatedAt, label }: RefreshButtonProps) { + return ( + + {updatedAt ? ( + + Last refreshed {fromNow(new Date(updatedAt))} + + ) : null} + + {/* span wrapper so the tooltip still shows while the button is disabled */} + + + + + + + + ); +} diff --git a/apps/csm-portal/microapp/src/components/support/CaseCard.tsx b/apps/csm-portal/microapp/src/components/support/CaseCard.tsx index 2a24374624..421d633440 100644 --- a/apps/csm-portal/microapp/src/components/support/CaseCard.tsx +++ b/apps/csm-portal/microapp/src/components/support/CaseCard.tsx @@ -50,13 +50,13 @@ export function CaseCard({ item }: { item: CaseSummary }) { - + Updated {fromNow(item.updatedOn)} - + {item.assignedEngineer?.name ?? "Unassigned"} diff --git a/apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx b/apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx index 50988c37f7..52c47b4343 100644 --- a/apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx +++ b/apps/csm-portal/microapp/src/pages/CaseDetailPage.tsx @@ -130,10 +130,10 @@ function CaseCommentsSection({ comments }: { comments: Comment[] }) { {comments.map((comment) => ( - + {comment.createdBy} - + {formatDate(comment.createdOn)} diff --git a/apps/csm-portal/microapp/src/pages/MorePage.tsx b/apps/csm-portal/microapp/src/pages/MorePage.tsx index 70ff989b1f..789720edc1 100644 --- a/apps/csm-portal/microapp/src/pages/MorePage.tsx +++ b/apps/csm-portal/microapp/src/pages/MorePage.tsx @@ -22,6 +22,7 @@ import { Clock, Megaphone, RefreshCw, + Settings, Shield, type LucideIcon, } from "@wso2/oxygen-ui-icons-react";