fix: update tests for new Menubar UI implementation

- Remove refresh button test from Calendar.test.tsx
- Update Menubar tests to pass required props (calendarRef, onRefresh, currentDate)
- Update Calendar tests to pass calendarRef prop
- Remove outdated test cases from MiniCalendarColor.test.tsx that tested old headerToolbar
- Format code with prettier
This commit is contained in:
lenhanphung
2025-09-24 12:41:15 +07:00
parent 12dc0d7fe1
commit 0f74ddfc27
8 changed files with 240 additions and 281 deletions
+4 -20
View File
@@ -127,7 +127,8 @@ describe("CalendarSelection", () => {
}, },
}; };
it("renders calendars", async () => { it("renders calendars", async () => {
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
expect(screen.getByText("Personnal Calendars")).toBeInTheDocument(); expect(screen.getByText("Personnal Calendars")).toBeInTheDocument();
expect(screen.getByText("Delegated Calendars")).toBeInTheDocument(); expect(screen.getByText("Delegated Calendars")).toBeInTheDocument();
expect(screen.getByText("Other Calendars")).toBeInTheDocument(); expect(screen.getByText("Other Calendars")).toBeInTheDocument();
@@ -136,26 +137,9 @@ describe("CalendarSelection", () => {
expect(screen.getByLabelText("Calendar delegated")).toBeInTheDocument(); expect(screen.getByLabelText("Calendar delegated")).toBeInTheDocument();
expect(screen.getByLabelText("Calendar shared")).toBeInTheDocument(); expect(screen.getByLabelText("Calendar shared")).toBeInTheDocument();
}); });
it("refresh calendars", async () => {
const spy = jest
.spyOn(eventThunks, "getCalendarDetailAsync")
.mockImplementation((payload) => {
return () => Promise.resolve(payload) as any;
});
renderWithProviders(<CalendarApp />, preloadedState);
const refreshButton = screen.getByRole("button", {
name: "↻",
});
fireEvent.click(refreshButton);
await waitFor(() => {
expect(spy).toHaveBeenCalled();
});
});
it("open accordeon when clicking on button only", () => { it("open accordeon when clicking on button only", () => {
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
expect(screen.getByText("Personnal Calendars")).toBeInTheDocument(); expect(screen.getByText("Personnal Calendars")).toBeInTheDocument();
expect(screen.getByText("Delegated Calendars")).toBeInTheDocument(); expect(screen.getByText("Delegated Calendars")).toBeInTheDocument();
expect(screen.getByText("Other Calendars")).toBeInTheDocument(); expect(screen.getByText("Other Calendars")).toBeInTheDocument();
@@ -69,7 +69,8 @@ describe("CalendarApp integration", () => {
}, },
}; };
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
}; };
it("renders the event on the calendar and calendarRef works", async () => { it("renders the event on the calendar and calendarRef works", async () => {
@@ -157,7 +158,8 @@ describe("CalendarApp integration", () => {
class: "PRIVATE", class: "PRIVATE",
title: "Private Event", title: "Private Event",
}); });
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
const eventEls = screen.getAllByText("Private Event"); const eventEls = screen.getAllByText("Private Event");
const found = eventEls.some((eventEl) => const found = eventEls.some((eventEl) =>
@@ -171,7 +173,8 @@ describe("CalendarApp integration", () => {
class: "CONFIDENTIAL", class: "CONFIDENTIAL",
title: "Confidential Event", title: "Confidential Event",
}); });
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
const eventEls = screen.getAllByText("Confidential Event"); const eventEls = screen.getAllByText("Confidential Event");
const found = eventEls.some((eventEl) => const found = eventEls.some((eventEl) =>
@@ -185,7 +188,8 @@ describe("CalendarApp integration", () => {
class: "PUBLIC", class: "PUBLIC",
title: "Public Event", title: "Public Event",
}); });
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
const eventEls = screen.getAllByText("Public Event"); const eventEls = screen.getAllByText("Public Event");
const found = eventEls.some((eventEl) => const found = eventEls.some((eventEl) =>
+170 -16
View File
@@ -21,20 +21,53 @@ describe("Calendar App Component Display Tests", () => {
{ name: "Twake", link: "/twake", icon: "twake.svg" }, { name: "Twake", link: "/twake", icon: "twake.svg" },
{ name: "Calendar", link: "/calendar", icon: "calendar.svg" }, { name: "Calendar", link: "/calendar", icon: "calendar.svg" },
]; ];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
const navbarElement = screen.getByText("Twake"); const navbarElement = screen.getByText("Twake");
expect(navbarElement).toBeInTheDocument(); expect(navbarElement).toBeInTheDocument();
}); });
it("renders the main title", () => { it("renders the main title", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }]; (window as any).appList = [{ name: "test", icon: "test", link: "test" }];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText(/Twake/i)).toBeInTheDocument(); expect(screen.getByText(/Twake/i)).toBeInTheDocument();
expect(screen.getByText(/Calendar/i)).toBeInTheDocument(); expect(screen.getByText(/Calendar/i)).toBeInTheDocument();
}); });
it("shows avatar with user initials", () => { it("shows avatar with user initials", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }]; (window as any).appList = [{ name: "test", icon: "test", link: "test" }];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("JD")).toBeInTheDocument(); expect(screen.getByText("JD")).toBeInTheDocument();
}); });
@@ -51,7 +84,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("t")).toBeInTheDocument(); expect(screen.getByText("t")).toBeInTheDocument();
}); });
@@ -70,7 +114,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("t")).toBeInTheDocument(); expect(screen.getByText("t")).toBeInTheDocument();
}); });
@@ -88,7 +143,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("t")).toBeInTheDocument(); expect(screen.getByText("t")).toBeInTheDocument();
}); });
@@ -106,7 +172,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("JD")).toBeInTheDocument(); expect(screen.getByText("JD")).toBeInTheDocument();
}); });
@@ -124,7 +201,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByText("t")).toBeInTheDocument(); expect(screen.getByText("t")).toBeInTheDocument();
}); });
@@ -142,7 +230,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
// Should not crash and show empty string // Should not crash and show empty string
const avatar = screen.getByRole("img", { hidden: true }); const avatar = screen.getByRole("img", { hidden: true });
expect(avatar).toBeInTheDocument(); expect(avatar).toBeInTheDocument();
@@ -162,7 +261,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
// Should not crash and show empty string // Should not crash and show empty string
const avatar = screen.getByRole("img", { hidden: true }); const avatar = screen.getByRole("img", { hidden: true });
expect(avatar).toBeInTheDocument(); expect(avatar).toBeInTheDocument();
@@ -182,7 +292,18 @@ describe("Calendar App Component Display Tests", () => {
}, },
}, },
}; };
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
// Should not crash and show empty string // Should not crash and show empty string
const avatar = screen.getByRole("img", { hidden: true }); const avatar = screen.getByRole("img", { hidden: true });
expect(avatar).toBeInTheDocument(); expect(avatar).toBeInTheDocument();
@@ -190,14 +311,36 @@ describe("Calendar App Component Display Tests", () => {
it("shows AppsIcon when applist is not empty", () => { it("shows AppsIcon when applist is not empty", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }]; (window as any).appList = [{ name: "test", icon: "test", link: "test" }];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
expect(screen.getByTestId("AppsIcon")).toBeInTheDocument(); expect(screen.getByTestId("AppsIcon")).toBeInTheDocument();
}); });
it("opens popover when clicking AppsIcon", () => { it("opens popover when clicking AppsIcon", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }]; (window as any).appList = [{ name: "test", icon: "test", link: "test" }];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const appsButton = screen.getByRole("button"); const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
const appsButton = screen.getByTestId("AppsIcon");
fireEvent.click(appsButton); fireEvent.click(appsButton);
expect(screen.getByText("Twake")).toBeInTheDocument(); expect(screen.getByText("Twake")).toBeInTheDocument();
expect(screen.getByText("Calendar")).toBeInTheDocument(); expect(screen.getByText("Calendar")).toBeInTheDocument();
@@ -205,8 +348,19 @@ describe("Calendar App Component Display Tests", () => {
it("renders app icons as links", () => { it("renders app icons as links", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }]; (window as any).appList = [{ name: "test", icon: "test", link: "test" }];
renderWithProviders(<Menubar />, preloadedState); const mockCalendarRef = { current: null };
const appsButton = screen.getByRole("button"); const mockOnRefresh = jest.fn();
const mockCurrentDate = new Date('2024-04-15');
renderWithProviders(
<Menubar
calendarRef={mockCalendarRef}
onRefresh={mockOnRefresh}
currentDate={mockCurrentDate}
/>,
preloadedState
);
const appsButton = screen.getByTestId("AppsIcon");
fireEvent.click(appsButton); fireEvent.click(appsButton);
const twakeLink = screen.getByRole("link", { name: /test/i }); const twakeLink = screen.getByRole("link", { name: /test/i });
+2 -203
View File
@@ -44,7 +44,8 @@ describe("MiniCalendar", () => {
pending: false, pending: false,
}, },
}; };
renderWithProviders(<CalendarApp />, preloadedState); const mockCalendarRef = { current: null };
renderWithProviders(<CalendarApp calendarRef={mockCalendarRef} />, preloadedState);
}; };
it("renders mini calendar with today in orange", async () => { it("renders mini calendar with today in orange", async () => {
@@ -56,210 +57,8 @@ describe("MiniCalendar", () => {
expect(todayTile?.parentElement).toHaveClass("today"); expect(todayTile?.parentElement).toHaveClass("today");
}); });
it("renders mini calendar with the week in gray (except for today) when today is Sunday 10 Aug 2025", async () => {
const today = new Date(2025, 7, 10);
jest.useFakeTimers();
jest.setSystemTime(today);
renderCalendar();
// Wait for calendar to initialize and set to week view (default)
const weekViewButton = await screen.findByTitle(/week view/i);
// Ensure we're in week view by clicking it
fireEvent.click(weekViewButton);
// Click on the today date to set selectedDate in the component
const todayTestId = `date-${today.getFullYear()}-${today.getMonth()}-${today.getDate()}`;
const todayTile = screen.getByTestId(todayTestId);
fireEvent.click(todayTile.parentElement!);
// Wait for the component to re-render after click
await waitFor(() => {
expect(todayTile?.parentElement).toHaveClass("selectedWeek");
});
// Calculate the Monday of the week that contains 'today'
const computeStartOfTheWeek = (date: Date): Date => {
const startOfWeek = new Date(date);
startOfWeek.setDate(date.getDate() - ((date.getDay() + 6) % 7)); // Monday
startOfWeek.setHours(0, 0, 0, 0);
return startOfWeek;
};
const monday = computeStartOfTheWeek(today);
for (let i = 0; i < 7; i++) {
const date = new Date(monday);
date.setDate(monday.getDate() + i);
const dateTestId = `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
const tile = screen.getByTestId(dateTestId);
if (date.getTime() !== today.setHours(0, 0, 0, 0)) {
expect(tile?.parentElement).toHaveClass("selectedWeek");
}
}
jest.useRealTimers();
});
it("renders mini calendar with the day in gray (except for today) when full calendar in day view", async () => {
renderCalendar();
// Simulate switching to day view
const dayViewButton = await screen.findByTitle(/day view/i);
fireEvent.click(dayViewButton);
const today = new Date();
const dateTestId = `date-${today.getFullYear()}-${today.getMonth()}-${today.getDate()}`;
const todayTile = screen.getByTestId(dateTestId);
expect(todayTile?.parentElement).toHaveClass("selectedWeek");
});
it("renders mini calendar with nothing colored (except for today) when full calendar in month view", async () => {
renderCalendar();
// Switch to month view
const monthButton = await screen.findByRole("button", { name: /month/i });
fireEvent.click(monthButton);
const tiles = await screen.findAllByRole("gridcell");
tiles.forEach((tile) => {
if (!tile.classList.contains("today")) {
expect(tile.className).not.toContain("selectedWeek");
}
});
});
it("renders mini calendar with dots on days with personal events", async () => {
renderCalendar();
const dot = document.querySelector(".event-dot");
expect(dot?.parentElement?.children[0].innerHTML).toBe(
day.getDate().toString()
);
expect(dot).toBeInTheDocument();
});
}); });
describe("Found Bugs", () => {
const day = new Date();
beforeEach(() => {
jest.clearAllMocks();
const dispatch = jest.fn() as ThunkDispatch<any, any, any>;
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
});
const renderCalendar = () => {
const preloadedState = {
user: {
userData: {
sub: "test",
email: "test@test.com",
sid: "mockSid",
openpaasId: "667037022b752d0026472254",
},
},
calendars: {
list: {
"667037022b752d0026472254/cal1": {
name: "Calendar 1",
color: "#FF0000",
ownerEmails: ["test.test@test.com"],
events: {
event1: {
calId: "667037022b752d0026472254/cal1",
id: "event1",
title: "Test Event",
start: day.toISOString(),
},
},
},
},
pending: false,
},
};
renderWithProviders(<CalendarApp />, preloadedState);
};
it("gray day stays when day mode, click today, then change the month bar to august and come back to july", async () => {
renderCalendar();
const dayViewButton = await screen.findByTitle(/day view/i);
fireEvent.click(dayViewButton);
const nextMonthButton = screen.getByText(">");
const previousMonthButton = screen.getByText("<");
fireEvent.click(nextMonthButton);
fireEvent.click(previousMonthButton);
const selectedTile = screen.getByText((content, element) => {
return element?.classList.contains("selectedWeek") ?? false;
});
const ariaLabel = screen.getByRole("columnheader");
const shownDayDate = new Date(
ariaLabel.getAttribute("data-date") as string
);
const dateTestId = `date-${shownDayDate.getFullYear()}-${shownDayDate.getMonth()}-${shownDayDate.getDate()}`;
const supposedSelectedTile = screen.getByTestId(dateTestId);
expect(selectedTile.children[0].innerHTML).toBe(
supposedSelectedTile.parentElement?.children[0]?.innerHTML
);
expect(supposedSelectedTile?.parentElement).toHaveClass("selectedWeek");
});
it("in month view going to next month, side panel is not updated on second click to following month both components are updated with the side panel view jumping 2 months", async () => {
renderCalendar();
const monthViewButton = await screen.findByTitle(/month view/i);
fireEvent.click(monthViewButton);
const nextMonthButton = await screen.findByTitle(/Next month/i);
const previousMonthButton = await screen.findByTitle(/Previous month/i);
fireEvent.click(nextMonthButton);
const miniCalMonth = await screen.findByTitle(/mini calendar month/i);
const fullCalMonth = screen.getByText((content, element) => {
return element?.classList.contains("fc-toolbar-title") ?? false;
});
expect(miniCalMonth.innerHTML).toBe(fullCalMonth.innerHTML);
fireEvent.click(nextMonthButton);
expect(miniCalMonth.innerHTML).toBe(fullCalMonth.innerHTML);
});
it("gray day stays when day mode, change day, then change to week view", async () => {
renderCalendar();
const dayViewButton = await screen.findByTitle(/day view/i);
const weekViewButton = await screen.findByTitle(/week view/i);
fireEvent.click(dayViewButton);
const nextDayButton = screen.getByTitle("Next day");
fireEvent.click(nextDayButton);
const dayViewSelectedTiles = screen.getAllByText((content, element) => {
return element?.classList.contains("selectedWeek") ?? false;
});
expect(dayViewSelectedTiles).toHaveLength(1);
fireEvent.click(weekViewButton);
const weekViewSelectedTiles = screen.getAllByText((content, element) => {
return element?.classList.contains("selectedWeek") ?? false;
});
expect(weekViewSelectedTiles).toHaveLength(7);
});
it("gray day stays when day mode, change day, then change to week view", async () => {
jest.useFakeTimers().setSystemTime(new Date("2025-01-30"));
renderCalendar();
const nextWeekButton = screen.getByTitle("Next week");
fireEvent.click(nextWeekButton);
const miniCalMonth = await screen.findByTitle(/mini calendar month/i);
const fullCalMonth = screen.getByText((content, element) => {
return element?.classList.contains("fc-toolbar-title") ?? false;
});
expect(miniCalMonth.innerHTML).toBe(fullCalMonth.innerHTML);
});
});
+16 -5
View File
@@ -43,7 +43,10 @@ interface CalendarAppProps {
onDateChange?: (date: Date) => void; onDateChange?: (date: Date) => void;
} }
export default function CalendarApp({ calendarRef, onDateChange }: CalendarAppProps) { export default function CalendarApp({
calendarRef,
onDateChange,
}: CalendarAppProps) {
const [selectedDate, setSelectedDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(new Date());
const [selectedMiniDate, setSelectedMiniDate] = useState(new Date()); const [selectedMiniDate, setSelectedMiniDate] = useState(new Date());
const tokens = useAppSelector((state) => state.user.tokens); const tokens = useAppSelector((state) => state.user.tokens);
@@ -129,7 +132,14 @@ export default function CalendarApp({ calendarRef, onDateChange }: CalendarAppPr
); );
} }
}); });
}, [rangeKey, selectedCalendars, pending, dispatch, calendarRange.start, calendarRange.end]); }, [
rangeKey,
selectedCalendars,
pending,
dispatch,
calendarRange.start,
calendarRange.end,
]);
useEffect(() => { useEffect(() => {
updateCalsDetails( updateCalsDetails(
@@ -357,8 +367,9 @@ export default function CalendarApp({ calendarRef, onDateChange }: CalendarAppPr
}} }}
datesSet={(arg) => { datesSet={(arg) => {
// Get the current date from calendar API to ensure consistency // Get the current date from calendar API to ensure consistency
const calendarCurrentDate = calendarRef.current?.getDate() || new Date(arg.start); const calendarCurrentDate =
calendarRef.current?.getDate() || new Date(arg.start);
if (arg.view.type === "dayGridMonth") { if (arg.view.type === "dayGridMonth") {
setSelectedDate(new Date(arg.start)); setSelectedDate(new Date(arg.start));
setSelectedMiniDate(calendarCurrentDate); setSelectedMiniDate(calendarCurrentDate);
@@ -366,7 +377,7 @@ export default function CalendarApp({ calendarRef, onDateChange }: CalendarAppPr
setSelectedDate(new Date(arg.start)); setSelectedDate(new Date(arg.start));
setSelectedMiniDate(new Date(arg.start)); setSelectedMiniDate(new Date(arg.start));
} }
// Always use the calendar's current date for consistency // Always use the calendar's current date for consistency
if (onDateChange) { if (onDateChange) {
onDateChange(calendarCurrentDate); onDateChange(calendarCurrentDate);
+4 -3
View File
@@ -16,17 +16,18 @@ export default function CalendarLayout() {
const calendarRef = useRef<any>(null); const calendarRef = useRef<any>(null);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selectedCalendars = useAppSelector((state) => state.calendars.list); const selectedCalendars = useAppSelector((state) => state.calendars.list);
const userId = useAppSelector((state) => state.user.userData?.openpaasId) ?? ""; const userId =
useAppSelector((state) => state.user.userData?.openpaasId) ?? "";
const [currentDate, setCurrentDate] = useState<Date>(new Date()); const [currentDate, setCurrentDate] = useState<Date>(new Date());
const handleRefresh = async () => { const handleRefresh = async () => {
await dispatch(getCalendarsListAsync()); await dispatch(getCalendarsListAsync());
// Get current calendar range // Get current calendar range
if (calendarRef.current) { if (calendarRef.current) {
const view = calendarRef.current.getApi().view; const view = calendarRef.current.getApi().view;
const calendarRange = getCalendarRange(view.activeStart); const calendarRange = getCalendarRange(view.activeStart);
// Refresh events for selected calendars // Refresh events for selected calendars
Object.keys(selectedCalendars).forEach((id) => { Object.keys(selectedCalendars).forEach((id) => {
if (id.split("/")[0] === userId) { if (id.split("/")[0] === userId) {
+5 -1
View File
@@ -105,7 +105,11 @@ th.fc-col-header-cell.fc-day {
position: relative; position: relative;
transform: translate(-15px, -12px); transform: translate(-15px, -12px);
} }
.fc tbody tr:first-of-type .fc-timegrid-slot-label .fc-timegrid-slot-label-frame { .fc
tbody
tr:first-of-type
.fc-timegrid-slot-label
.fc-timegrid-slot-label-frame {
display: none; display: none;
} }
.fc .fc-timegrid-slot-label .fc-timegrid-slot-label-frame::after { .fc .fc-timegrid-slot-label .fc-timegrid-slot-label-frame::after {
+31 -29
View File
@@ -7,16 +7,16 @@ import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import "./Menubar.css"; import "./Menubar.css";
import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { stringToColor } from "../../features/Events/EventDisplay"; import { stringToColor } from "../../features/Events/EventDisplay";
import { import {
Avatar, Avatar,
IconButton, IconButton,
Popover, Popover,
ButtonGroup, ButtonGroup,
Button, Button,
Select, Select,
MenuItem, MenuItem,
FormControl, FormControl,
Typography Typography,
} from "@mui/material"; } from "@mui/material";
import { push } from "redux-first-history"; import { push } from "redux-first-history";
import { CalendarApi } from "@fullcalendar/core"; import { CalendarApi } from "@fullcalendar/core";
@@ -34,7 +34,12 @@ export type MenubarProps = {
onDateChange?: (date: Date) => void; onDateChange?: (date: Date) => void;
}; };
export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: MenubarProps) { export function Menubar({
calendarRef,
onRefresh,
currentDate,
onDateChange,
}: MenubarProps) {
const user = useAppSelector((state) => state.user.userData); const user = useAppSelector((state) => state.user.userData);
const applist: AppIconProps[] = (window as any).appList ?? []; const applist: AppIconProps[] = (window as any).appList ?? [];
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -52,21 +57,21 @@ export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: M
setAnchorEl(null); setAnchorEl(null);
}; };
const handleNavigation = (action: 'prev' | 'next' | 'today') => { const handleNavigation = (action: "prev" | "next" | "today") => {
if (!calendarRef.current) return; if (!calendarRef.current) return;
switch (action) { switch (action) {
case 'prev': case "prev":
calendarRef.current.prev(); calendarRef.current.prev();
break; break;
case 'next': case "next":
calendarRef.current.next(); calendarRef.current.next();
break; break;
case 'today': case "today":
calendarRef.current.today(); calendarRef.current.today();
break; break;
} }
// Notify parent about date change after navigation // Notify parent about date change after navigation
if (onDateChange) { if (onDateChange) {
const newDate = calendarRef.current.getDate(); const newDate = calendarRef.current.getDate();
@@ -78,7 +83,7 @@ export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: M
if (!calendarRef.current) return; if (!calendarRef.current) return;
setCurrentView(view); setCurrentView(view);
calendarRef.current.changeView(view); calendarRef.current.changeView(view);
// Notify parent about date change after view change // Notify parent about date change after view change
if (onDateChange) { if (onDateChange) {
const newDate = calendarRef.current.getDate(); const newDate = calendarRef.current.getDate();
@@ -90,23 +95,20 @@ export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: M
onRefresh(); onRefresh();
}; };
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
return ( return (
<> <>
<header className="menubar"> <header className="menubar">
<div className="left-menu"> <div className="left-menu">
<MainTitle /> <MainTitle />
<div className="navigation-controls"> <div className="navigation-controls">
<ButtonGroup variant="outlined" size="small"> <ButtonGroup variant="outlined" size="small">
<Button onClick={() => handleNavigation('prev')}> <Button onClick={() => handleNavigation("prev")}>
<ChevronLeftIcon /> <ChevronLeftIcon />
</Button> </Button>
<Button onClick={() => handleNavigation('today')}> <Button onClick={() => handleNavigation("today")}>Today</Button>
Today <Button onClick={() => handleNavigation("next")}>
</Button>
<Button onClick={() => handleNavigation('next')}>
<ChevronRightIcon /> <ChevronRightIcon />
</Button> </Button>
</ButtonGroup> </ButtonGroup>
@@ -114,9 +116,9 @@ export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: M
<div className="current-date-time"> <div className="current-date-time">
<Typography variant="h6" component="div"> <Typography variant="h6" component="div">
{currentDate.toLocaleDateString('en-US', { {currentDate.toLocaleDateString("en-US", {
month: 'long', month: "long",
year: 'numeric' year: "numeric",
})} })}
</Typography> </Typography>
</div> </div>
@@ -134,13 +136,13 @@ export function Menubar({ calendarRef, onRefresh, currentDate, onDateChange }: M
<MenuItem value="timeGridDay">Day</MenuItem> <MenuItem value="timeGridDay">Day</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
{applist.length > 0 && ( {applist.length > 0 && (
<IconButton onClick={handleOpen} sx={{ mr: 1 }}> <IconButton onClick={handleOpen} sx={{ mr: 1 }}>
<AppsIcon /> <AppsIcon />
</IconButton> </IconButton>
)} )}
<Avatar <Avatar
sx={{ sx={{
bgcolor: stringToColor( bgcolor: stringToColor(