- Add logo click handler to navigate to current week view from any view (month, day, or week) - Update MainTitle component to accept calendarRef and view change callbacks - Implement handleLogoClick that changes view to week and navigates to current week - Add comprehensive test cases for logo click behavior from all view types Co-authored-by: Lê Nhân Phụng <lenhanphung@Phung-Mac-M4.local>
This commit is contained in:
@@ -760,3 +760,219 @@ describe("Menubar logout flow", () => {
|
|||||||
expect(sessionStorage.length).toBe(0);
|
expect(sessionStorage.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Logo click navigation to current week", () => {
|
||||||
|
const preloadedState = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
family_name: "Doe",
|
||||||
|
name: "John",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
view: "calendar",
|
||||||
|
language: "en",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
(window as any).appList = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates to week view and current week when clicking logo from month view", async () => {
|
||||||
|
const mockChangeView = jest.fn();
|
||||||
|
const mockToday = jest.fn();
|
||||||
|
const mockGetDate = jest.fn(() => new Date());
|
||||||
|
const mockCalendarApi = {
|
||||||
|
changeView: mockChangeView,
|
||||||
|
today: mockToday,
|
||||||
|
getDate: mockGetDate,
|
||||||
|
};
|
||||||
|
const mockCalendarRef = { current: mockCalendarApi as any };
|
||||||
|
const mockOnRefresh = jest.fn();
|
||||||
|
const mockOnViewChange = jest.fn();
|
||||||
|
const mockOnDateChange = jest.fn();
|
||||||
|
const mockCurrentDate = new Date("2024-04-15");
|
||||||
|
|
||||||
|
const { store } = renderWithProviders(
|
||||||
|
<Menubar
|
||||||
|
calendarRef={mockCalendarRef}
|
||||||
|
onRefresh={mockOnRefresh}
|
||||||
|
currentDate={mockCurrentDate}
|
||||||
|
currentView="dayGridMonth"
|
||||||
|
onViewChange={mockOnViewChange}
|
||||||
|
onDateChange={mockOnDateChange}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoElement = screen.getByAltText("menubar.logoAlt");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(logoElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(store.getState().settings.view).toBe("calendar");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockChangeView).toHaveBeenCalledWith("timeGridWeek");
|
||||||
|
expect(mockToday).toHaveBeenCalled();
|
||||||
|
expect(mockOnViewChange).toHaveBeenCalledWith("timeGridWeek");
|
||||||
|
expect(mockOnDateChange).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates to week view and current week when clicking logo from day view", async () => {
|
||||||
|
const mockChangeView = jest.fn();
|
||||||
|
const mockToday = jest.fn();
|
||||||
|
const mockGetDate = jest.fn(() => new Date());
|
||||||
|
const mockCalendarApi = {
|
||||||
|
changeView: mockChangeView,
|
||||||
|
today: mockToday,
|
||||||
|
getDate: mockGetDate,
|
||||||
|
};
|
||||||
|
const mockCalendarRef = { current: mockCalendarApi as any };
|
||||||
|
const mockOnRefresh = jest.fn();
|
||||||
|
const mockOnViewChange = jest.fn();
|
||||||
|
const mockOnDateChange = jest.fn();
|
||||||
|
const mockCurrentDate = new Date("2024-04-15");
|
||||||
|
|
||||||
|
const { store } = renderWithProviders(
|
||||||
|
<Menubar
|
||||||
|
calendarRef={mockCalendarRef}
|
||||||
|
onRefresh={mockOnRefresh}
|
||||||
|
currentDate={mockCurrentDate}
|
||||||
|
currentView="timeGridDay"
|
||||||
|
onViewChange={mockOnViewChange}
|
||||||
|
onDateChange={mockOnDateChange}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoElement = screen.getByAltText("menubar.logoAlt");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(logoElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(store.getState().settings.view).toBe("calendar");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockChangeView).toHaveBeenCalledWith("timeGridWeek");
|
||||||
|
expect(mockToday).toHaveBeenCalled();
|
||||||
|
expect(mockOnViewChange).toHaveBeenCalledWith("timeGridWeek");
|
||||||
|
expect(mockOnDateChange).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates to current week when clicking logo from week view (not current week)", async () => {
|
||||||
|
const mockChangeView = jest.fn();
|
||||||
|
const mockToday = jest.fn();
|
||||||
|
const mockGetDate = jest.fn(() => new Date());
|
||||||
|
const mockCalendarApi = {
|
||||||
|
changeView: mockChangeView,
|
||||||
|
today: mockToday,
|
||||||
|
getDate: mockGetDate,
|
||||||
|
};
|
||||||
|
const mockCalendarRef = { current: mockCalendarApi as any };
|
||||||
|
const mockOnRefresh = jest.fn();
|
||||||
|
const mockOnViewChange = jest.fn();
|
||||||
|
const mockOnDateChange = jest.fn();
|
||||||
|
const mockCurrentDate = new Date("2024-04-15");
|
||||||
|
|
||||||
|
const { store } = renderWithProviders(
|
||||||
|
<Menubar
|
||||||
|
calendarRef={mockCalendarRef}
|
||||||
|
onRefresh={mockOnRefresh}
|
||||||
|
currentDate={mockCurrentDate}
|
||||||
|
currentView="timeGridWeek"
|
||||||
|
onViewChange={mockOnViewChange}
|
||||||
|
onDateChange={mockOnDateChange}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoElement = screen.getByAltText("menubar.logoAlt");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(logoElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(store.getState().settings.view).toBe("calendar");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockChangeView).not.toHaveBeenCalled();
|
||||||
|
expect(mockToday).toHaveBeenCalled();
|
||||||
|
expect(mockOnDateChange).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not crash when calendarRef.current is null", async () => {
|
||||||
|
const mockCalendarRef = { current: null };
|
||||||
|
const mockOnRefresh = jest.fn();
|
||||||
|
const mockOnViewChange = jest.fn();
|
||||||
|
const mockOnDateChange = jest.fn();
|
||||||
|
const mockCurrentDate = new Date("2024-04-15");
|
||||||
|
|
||||||
|
const { store } = renderWithProviders(
|
||||||
|
<Menubar
|
||||||
|
calendarRef={mockCalendarRef}
|
||||||
|
onRefresh={mockOnRefresh}
|
||||||
|
currentDate={mockCurrentDate}
|
||||||
|
currentView="dayGridMonth"
|
||||||
|
onViewChange={mockOnViewChange}
|
||||||
|
onDateChange={mockOnDateChange}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoElement = screen.getByAltText("menubar.logoAlt");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(logoElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(store.getState().settings.view).toBe("calendar");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockOnViewChange).not.toHaveBeenCalled();
|
||||||
|
expect(mockOnDateChange).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles missing onViewChange and onDateChange callbacks", async () => {
|
||||||
|
const mockChangeView = jest.fn();
|
||||||
|
const mockToday = jest.fn();
|
||||||
|
const mockGetDate = jest.fn(() => new Date());
|
||||||
|
const mockCalendarApi = {
|
||||||
|
changeView: mockChangeView,
|
||||||
|
today: mockToday,
|
||||||
|
getDate: mockGetDate,
|
||||||
|
};
|
||||||
|
const mockCalendarRef = { current: mockCalendarApi as any };
|
||||||
|
const mockOnRefresh = jest.fn();
|
||||||
|
const mockCurrentDate = new Date("2024-04-15");
|
||||||
|
|
||||||
|
const { store } = renderWithProviders(
|
||||||
|
<Menubar
|
||||||
|
calendarRef={mockCalendarRef}
|
||||||
|
onRefresh={mockOnRefresh}
|
||||||
|
currentDate={mockCurrentDate}
|
||||||
|
currentView="dayGridMonth"
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoElement = screen.getByAltText("menubar.logoAlt");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(logoElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(store.getState().settings.view).toBe("calendar");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockChangeView).toHaveBeenCalledWith("timeGridWeek");
|
||||||
|
expect(mockToday).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -160,7 +160,12 @@ export function Menubar({
|
|||||||
<header className="menubar">
|
<header className="menubar">
|
||||||
<div className="left-menu">
|
<div className="left-menu">
|
||||||
<div className="menu-items">
|
<div className="menu-items">
|
||||||
<MainTitle />
|
<MainTitle
|
||||||
|
calendarRef={calendarRef}
|
||||||
|
currentView={currentView}
|
||||||
|
onViewChange={onViewChange}
|
||||||
|
onDateChange={onDateChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="menu-items">
|
<div className="menu-items">
|
||||||
<div className="navigation-controls">
|
<div className="navigation-controls">
|
||||||
@@ -365,16 +370,49 @@ export function Menubar({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MainTitle() {
|
export type MainTitleProps = {
|
||||||
|
calendarRef: React.RefObject<CalendarApi | null>;
|
||||||
|
currentView: string;
|
||||||
|
onViewChange?: (view: string) => void;
|
||||||
|
onDateChange?: (date: Date) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function MainTitle({
|
||||||
|
calendarRef,
|
||||||
|
currentView,
|
||||||
|
onViewChange,
|
||||||
|
onDateChange,
|
||||||
|
}: MainTitleProps) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const handleLogoClick = async () => {
|
||||||
|
if (!calendarRef.current) return;
|
||||||
|
|
||||||
|
await dispatch(setView("calendar"));
|
||||||
|
|
||||||
|
if (currentView !== "timeGridWeek") {
|
||||||
|
calendarRef.current.changeView("timeGridWeek");
|
||||||
|
if (onViewChange) {
|
||||||
|
onViewChange("timeGridWeek");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calendarRef.current.today();
|
||||||
|
|
||||||
|
if (onDateChange) {
|
||||||
|
const newDate = calendarRef.current.getDate();
|
||||||
|
onDateChange(newDate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="menubar-item tc-home">
|
<div className="menubar-item tc-home">
|
||||||
<img
|
<img
|
||||||
className="logo"
|
className="logo"
|
||||||
src={logo}
|
src={logo}
|
||||||
alt={t("menubar.logoAlt")}
|
alt={t("menubar.logoAlt")}
|
||||||
onClick={() => dispatch(setView("calendar"))}
|
onClick={handleLogoClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user