diff --git a/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.test.tsx b/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.test.tsx
index b04e522321..a5d83c0ca6 100644
--- a/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.test.tsx
+++ b/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.test.tsx
@@ -1,8 +1,17 @@
import userEvent from "@testing-library/user-event";
-import { EventIdSchema } from "@core/types/domain-primitives";
+import {
+ type Calendar,
+ getCalendarCapabilities,
+} from "@core/types/calendar.contracts";
+import {
+ CalendarIdSchema,
+ EventIdSchema,
+ TimeZoneSchema,
+} from "@core/types/domain-primitives";
import { type Event, EventScheduleSchema } from "@core/types/event.contracts";
import dayjs from "@core/util/date/dayjs";
import {
+ act,
cleanup,
fireEvent,
render,
@@ -10,6 +19,9 @@ import {
waitFor,
} from "@web/__tests__/__mocks__/mock.render";
import { createMockEvent } from "@web/__tests__/utils/factories/event.factory";
+import { createCompassQueryClient } from "@web/api/query-client";
+import { calendarQueryKeys } from "@web/calendars/calendar.query";
+import { setCalendarVisibility } from "@web/calendars/calendar-visibility.store";
import { draftActions, useDraftStore } from "@web/events/stores/draft.store";
import { formatStartsIn, UpNextCard } from "./UpNextCard";
import { useUpNextEventShortcut } from "./useUpNextEvent";
@@ -18,6 +30,21 @@ import "@testing-library/jest-dom";
const SOON_EVENT_ID = "aaaaaaaaaaaaaaaaaaaaaaaa";
const LATER_EVENT_ID = "bbbbbbbbbbbbbbbbbbbbbbbb";
+const CALENDAR_ID = CalendarIdSchema.parse("cccccccccccccccccccccccc");
+const CALENDAR: Calendar = {
+ id: CALENDAR_ID,
+ name: "Work",
+ description: "",
+ timeZone: TimeZoneSchema.parse("America/Denver"),
+ foregroundColor: "#000000",
+ backgroundColor: "#3b82f6",
+ provider: "google",
+ access: "owner",
+ capabilities: getCalendarCapabilities("owner"),
+ isPrimary: false,
+ isVisible: true,
+ isActive: true,
+};
// Events are built relative to the real clock because the card's whole job is
// comparing today's events against "now".
@@ -84,7 +111,7 @@ describe("UpNextCard", () => {
expect(screen.getByText("N")).toBeInTheDocument();
});
- it("renders nothing when today has no upcoming timed events", () => {
+ it("keeps its slot with an all-clear state when today has no upcoming timed events", () => {
render(, {
events: [
// Already underway, so nothing is "up next".
@@ -101,12 +128,48 @@ describe("UpNextCard", () => {
],
});
- expect(screen.queryByRole("region", { name: "Up next" })).toBeNull();
- expect(
- screen.queryByText("Nothing scheduled — press C to add an event."),
- ).toBeNull();
+ expect(screen.getByRole("region", { name: "Up next" })).toBeInTheDocument();
+ expect(screen.getByText("All clear")).toBeInTheDocument();
expect(screen.queryByText("Past Event")).toBeNull();
expect(screen.queryByText("All Day Event")).toBeNull();
+ expect(screen.queryByRole("button", { name: /up next:/i })).toBeNull();
+ });
+
+ it("keeps its card while hiding the calendar with the only upcoming event", async () => {
+ const queryClient = createCompassQueryClient();
+ queryClient.setQueryData(calendarQueryKeys.all, [CALENDAR]);
+
+ render(, {
+ events: [
+ createMockEvent({
+ id: EventIdSchema.parse(SOON_EVENT_ID),
+ calendarId: CALENDAR_ID,
+ content: { kind: "details", title: "Soon Event", description: "" },
+ schedule: EventScheduleSchema.parse({
+ kind: "timed",
+ start: dayjs().add(30, "minute").format(),
+ end: dayjs().add(60, "minute").format(),
+ timeZone: "UTC",
+ }),
+ }),
+ ],
+ queryClient,
+ });
+
+ expect(
+ screen.getByRole("button", { name: /up next: soon event/i }),
+ ).toBeInTheDocument();
+
+ act(() => {
+ expect(setCalendarVisibility(CALENDAR_ID, false)).toBe(true);
+ });
+
+ await waitFor(() => {
+ expect(
+ screen.getByRole("region", { name: "Up next" }),
+ ).toBeInTheDocument();
+ expect(screen.getByText("All clear")).toBeInTheDocument();
+ });
});
it("opens the event's details in the sidebar when clicked", async () => {
diff --git a/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.tsx b/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.tsx
index 47771e198d..bd1971e4d7 100644
--- a/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.tsx
+++ b/packages/web/src/components/Sidebar/UpNextCard/UpNextCard.tsx
@@ -29,29 +29,32 @@ export function formatStartsIn(start: Dayjs, now: Dayjs): string {
*/
export const UpNextCard: FC = () => {
const { now, openEventDetails, upNext } = useUpNextEvent();
-
- if (!upNext) {
- return null;
- }
-
- const countdown = formatStartsIn(dayjs(upNext.startDate), now);
+ const countdown = upNext
+ ? formatStartsIn(dayjs(upNext.startDate), now)
+ : undefined;
return (
-
+ {upNext ? (
+
+ ) : (
+
+ All clear
+
+ )}
);
};