Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions frontend/src/components/dashboard/dashboard-view.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ vi.mock("@/lib/soroban", () => ({
getTokenAddress: vi.fn((symbol: string) => symbol),
toSorobanErrorMessage: vi.fn((e) => String(e)),
fetchTokenBalanceDisplay: vi.fn().mockResolvedValue("1000"),
TOKEN_ADDRESSES: { XLM: "CXLM" },
}));

vi.mock("@/lib/stellar", () => ({
Expand Down Expand Up @@ -73,6 +74,10 @@ vi.mock("./StreamDetailsModal", () => ({
StreamDetailsModal: () => <div data-testid="details-modal" />,
}));

vi.mock("./CashflowProjectionChart", () => ({
CashflowProjectionChart: () => <div data-testid="cashflow-chart" />,
}));

vi.mock("../ui/Button", () => ({
Button: ({
children,
Expand Down Expand Up @@ -216,4 +221,73 @@ describe("DashboardView + useDashboard cache integration", () => {
callsBeforeRetry,
);
}, 20000);

it("hides the Paused tab count badge when there are zero paused streams", async () => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});

render(
<QueryClientProvider client={queryClient}>
<DashboardView session={session} onDisconnect={vi.fn()} />
</QueryClientProvider>,
);

await waitFor(() =>
expect(screen.getByText(/start your first stream/i)).toBeInTheDocument(),
);

expect(screen.queryByTestId("paused-tab-badge")).toBeNull();
});

it("displays the exact count badge next to the Paused tab when paused streams exist", async () => {
const makeBackendStream = (id: string, streamId: number, isPaused: boolean) => ({
id,
streamId,
sender: PUBLIC_KEY,
recipient: "GRECIPIENT0000000000000000000000000000000000000000000000",
tokenAddress: "CXLM",
ratePerSecond: "100",
depositedAmount: "100000000",
withdrawnAmount: "0",
startTime: 1_700_000_000,
lastUpdateTime: 1_700_000_000,
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
isActive: true,
isPaused,
events: [],
});

const outgoing = [
makeBackendStream("out-1", 101, true),
makeBackendStream("out-2", 102, false),
];
const incoming = [
makeBackendStream("in-1", 201, true),
makeBackendStream("in-2", 202, true),
];

vi.stubGlobal(
"fetch",
vi.fn(async (input: RequestInfo | URL) => {
const url = String(input);
return jsonResponse(url.includes("sender=") ? outgoing : incoming);
}),
);

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});

render(
<QueryClientProvider client={queryClient}>
<DashboardView session={session} onDisconnect={vi.fn()} />
</QueryClientProvider>,
);

const badge = await screen.findByTestId("paused-tab-badge");
expect(badge).toHaveTextContent("3");
expect(badge).toHaveAttribute("aria-label", "3 paused streams");
});
});
22 changes: 20 additions & 2 deletions frontend/src/components/dashboard/dashboard-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,15 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
[snapshot],
);

const pausedCount = React.useMemo(
() =>
[
...(snapshot?.outgoingStreams ?? []),
...(snapshot?.incomingStreams ?? []),
].filter((stream) => stream.status === "Paused").length,
[snapshot],
);

// Keep the keyboard-selected row visible as j/k move the highlight.
React.useEffect(() => {
if (!selectedStreamId) return;
Expand Down Expand Up @@ -981,7 +990,7 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
<button
key={item.id}
type="button"
className="sidebar-item"
className="sidebar-item flex items-center justify-between"
data-active={activeTab === item.id ? "true" : undefined}
aria-current={activeTab === item.id ? "page" : undefined}
onClick={() => {
Expand All @@ -990,7 +999,16 @@ export function DashboardView({ session, onDisconnect }: DashboardViewProps) {
router.replace(`?${params.toString()}`);
}}
>
{item.label}
<span>{item.label}</span>
{item.id === "paused" && pausedCount > 0 && (
<span
data-testid="paused-tab-badge"
aria-label={`${pausedCount} paused ${pausedCount === 1 ? "stream" : "streams"}`}
className="ml-2 inline-flex items-center justify-center rounded-full bg-amber-500/15 px-2 py-0.5 text-xs font-semibold text-amber-600 dark:bg-amber-500/20 dark:text-amber-400"
>
{pausedCount}
</span>
)}
</button>
))}
</nav>
Expand Down
Loading