Refactor imports (#470)

This commit is contained in:
Camille Moussu
2026-01-20 17:33:30 +01:00
committed by GitHub
parent aeb8670895
commit 23d50f250d
149 changed files with 1439 additions and 1374 deletions
+18 -18
View File
@@ -1,15 +1,14 @@
import CalendarApp from "@/components/Calendar/Calendar";
import CalendarLayout from "@/components/Calendar/CalendarLayout";
import * as calendarDetailThunks from "@/features/Calendars/services";
import * as servicesModule from "@/features/Calendars/services";
import { searchUsers } from "@/features/User/userAPI";
import { act, fireEvent, screen, waitFor } from "@testing-library/react"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import CalendarApp from "../../src/components/Calendar/Calendar";
import * as eventThunks from "../../src/features/Calendars/CalendarSlice";
import { renderWithProviders } from "../utils/Renderwithproviders";
import { searchUsers } from "../../src/features/User/userAPI";
import * as calendarDetailThunks from "../../src/features/Calendars/services/getCalendarDetailAsync";
import { useRef } from "react";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import CalendarLayout from "../../src/components/Calendar/CalendarLayout"; import { useRef } from "react";
jest.mock("../../src/features/User/userAPI"); import { renderWithProviders } from "../utils/Renderwithproviders";
jest.mock("@/features/User/userAPI");
const mockedSearchUsers = searchUsers as jest.MockedFunction< const mockedSearchUsers = searchUsers as jest.MockedFunction<
typeof searchUsers typeof searchUsers
>; >;
@@ -348,7 +347,7 @@ describe("calendar Availability search", () => {
it("imports temporary calendars when selecting new users", async () => { it("imports temporary calendars when selecting new users", async () => {
const spy = jest const spy = jest
.spyOn(eventThunks, "getTempCalendarsListAsync") .spyOn(servicesModule, "getTempCalendarsListAsync")
.mockImplementation((payload) => { .mockImplementation((payload) => {
return () => Promise.resolve(payload) as any; return () => Promise.resolve(payload) as any;
}); });
@@ -389,7 +388,7 @@ describe("calendar Availability search", () => {
}, },
]); ]);
const spy = jest const spy = jest
.spyOn(eventThunks, "getTempCalendarsListAsync") .spyOn(servicesModule, "getTempCalendarsListAsync")
.mockImplementation((payload) => { .mockImplementation((payload) => {
return () => Promise.resolve(payload) as any; return () => Promise.resolve(payload) as any;
}); });
@@ -411,7 +410,7 @@ describe("calendar Availability search", () => {
it("open window with attendees filled after temp search on create event button click", async () => { it("open window with attendees filled after temp search on create event button click", async () => {
const spy = jest const spy = jest
.spyOn(eventThunks, "getTempCalendarsListAsync") .spyOn(servicesModule, "getTempCalendarsListAsync")
.mockImplementation((payload) => { .mockImplementation((payload) => {
return () => Promise.resolve(payload) as any; return () => Promise.resolve(payload) as any;
}); });
@@ -455,7 +454,7 @@ describe("calendar Availability search", () => {
it("open window with attendees filled after temp search on enter in temp input", async () => { it("open window with attendees filled after temp search on enter in temp input", async () => {
const spy = jest const spy = jest
.spyOn(eventThunks, "getTempCalendarsListAsync") .spyOn(servicesModule, "getTempCalendarsListAsync")
.mockImplementation((payload) => { .mockImplementation((payload) => {
return () => Promise.resolve(payload) as any; return () => Promise.resolve(payload) as any;
}); });
@@ -696,10 +695,10 @@ describe("calendar Availability search", () => {
); );
const selectedCalls = spy.mock.calls.filter( const selectedCalls = spy.mock.calls.filter(
(call) => call[0].calId === "user1/cal1" (call: { calId: string }[]) => call[0].calId === "user1/cal1"
); );
const hiddenCalls = spy.mock.calls.filter( const hiddenCalls = spy.mock.calls.filter(
(call) => (call: { calId: string }[]) =>
call[0].calId === "user1/cal2" || call[0].calId === "user1/cal3" call[0].calId === "user1/cal2" || call[0].calId === "user1/cal3"
); );
@@ -729,12 +728,13 @@ describe("calendar Availability search", () => {
); );
const callsForCal1 = spy.mock.calls.filter( const callsForCal1 = spy.mock.calls.filter(
(call) => call[0].calId === "user1/cal1" (call: { calId: string }[]) => call[0].calId === "user1/cal1"
); );
const uniqueRanges = new Set( const uniqueRanges = new Set(
callsForCal1.map( callsForCal1.map(
(call) => `${call[0].match.start}_${call[0].match.end}` (call: { match: { end: string; start: string } }[]) =>
`${call[0].match.start}_${call[0].match.end}`
) )
); );
+7 -7
View File
@@ -1,13 +1,13 @@
import { fireEvent, screen, waitFor, act } from "@testing-library/react"; import CalendarSearch from "@/components/Calendar/CalendarSearch";
import * as CalendarApi from "@/features/Calendars/CalendarApi";
import * as CalendarSlice from "@/features/Calendars/services";
import { searchUsers } from "@/features/User/userAPI";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import CalendarSearch from "../../src/components/Calendar/CalendarSearch";
import * as CalendarApi from "../../src/features/Calendars/CalendarApi";
import * as CalendarSlice from "../../src/features/Calendars/CalendarSlice";
import { searchUsers } from "../../src/features/User/userAPI";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
jest.mock("../../src/features/User/userAPI"); jest.mock("@/features/User/userAPI");
jest.mock("../../src/features/Calendars/CalendarApi"); jest.mock("@/features/Calendars/CalendarApi");
const mockedSearchUsers = searchUsers as jest.MockedFunction< const mockedSearchUsers = searchUsers as jest.MockedFunction<
typeof searchUsers typeof searchUsers
@@ -1,9 +1,9 @@
import { screen, fireEvent, waitFor, cleanup } from "@testing-library/react"; import CalendarSelection from "@/components/Calendar/CalendarSelection";
import * as calendarThunks from "@/features/Calendars/services";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import CalendarSelection from "../../src/components/Calendar/CalendarSelection"; import { cleanup, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../utils/Renderwithproviders";
import * as calendarThunks from "../../src/features/Calendars/CalendarSlice";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../utils/Renderwithproviders";
describe("CalendarSelection", () => { describe("CalendarSelection", () => {
beforeEach(() => { beforeEach(() => {
+7 -7
View File
@@ -1,15 +1,15 @@
import { import {
screen, DateTimeFields,
fireEvent, DateTimeFieldsProps,
waitFor, } from "@/components/Event/components/DateTimeFields";
import {
act, act,
fireEvent,
render, render,
screen,
waitFor,
} from "@testing-library/react"; } from "@testing-library/react";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import {
DateTimeFieldsProps,
DateTimeFields,
} from "../../src/components/Event/components/DateTimeFields";
jest.mock("twake-i18n", () => ({ jest.mock("twake-i18n", () => ({
useI18n: () => ({ useI18n: () => ({
+6 -5
View File
@@ -1,8 +1,9 @@
import { RootState } from "@/app/store";
import EventDuplication from "@/components/Event/EventDuplicate";
import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import EventPopover from "@/features/Events/EventModal";
import { fireEvent, screen, waitFor } from "@testing-library/react"; import { fireEvent, screen, waitFor } from "@testing-library/react";
import EventDuplication from "../../src/components/Event/EventDuplicate";
import EventPopover from "../../src/features/Events/EventModal";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
import EventPreviewModal from "../../src/features/Events/EventDisplayPreview";
const day = new Date(); const day = new Date();
const preloadedState = { const preloadedState = {
@@ -58,7 +59,7 @@ const preloadedState = {
}, },
pending: false, pending: false,
}, },
}; } as unknown as RootState;
describe("EventDuplication", () => { describe("EventDuplication", () => {
it("calls onOpenDuplicate when button clicked", () => { it("calls onOpenDuplicate when button clicked", () => {
@@ -155,7 +156,7 @@ describe("EventDisplayModal", () => {
expect( expect(
screen.getByDisplayValue( screen.getByDisplayValue(
preloadedState.calendars.list["667037022b752d0026472254/cal1"].events preloadedState.calendars.list["667037022b752d0026472254/cal1"].events
.event1.title .event1.title as string
) )
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -4,7 +4,7 @@ import {
DATETIME_WITH_SECONDS_LENGTH, DATETIME_WITH_SECONDS_LENGTH,
DATETIME_FORMAT_WITH_SECONDS, DATETIME_FORMAT_WITH_SECONDS,
DATETIME_FORMAT_WITHOUT_SECONDS, DATETIME_FORMAT_WITHOUT_SECONDS,
} from "../../../../src/components/Event/utils/dateTimeHelpers"; } from "@/components/Event/utils/dateTimeHelpers";
describe("dateTimeHelpers", () => { describe("dateTimeHelpers", () => {
describe("Constants", () => { describe("Constants", () => {
@@ -1,6 +1,6 @@
import CalendarLayout from "@/components/Calendar/CalendarLayout";
import { act, fireEvent, screen, waitFor } from "@testing-library/react"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
import CalendarLayout from "../../src/components/Calendar/CalendarLayout";
describe("Event Error Handling", () => { describe("Event Error Handling", () => {
beforeEach(() => { beforeEach(() => {
+10 -10
View File
@@ -1,6 +1,14 @@
import * as appHooks from "@/app/hooks";
import { AppDispatch } from "@/app/store";
import CalendarApp from "@/components/Calendar/Calendar";
import {
createEventHandlers,
EventHandlersProps,
} from "@/components/Calendar/handlers/eventHandlers";
import * as eventThunks from "@/features/Calendars/services";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import { CalendarApi } from "@fullcalendar/core"; import { CalendarApi } from "@fullcalendar/core";
import { jest } from "@jest/globals"; import { jest } from "@jest/globals";
import { ThunkDispatch } from "@reduxjs/toolkit";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { import {
act, act,
@@ -9,15 +17,7 @@ import {
waitFor, waitFor,
within, within,
} from "@testing-library/react"; } from "@testing-library/react";
import * as appHooks from "../../src/app/hooks";
import * as eventThunks from "../../src/features/Calendars/CalendarSlice";
import CalendarApp from "../../src/components/Calendar/Calendar";
import EventUpdateModal from "../../src/features/Events/EventUpdateModal";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
import {
createEventHandlers,
EventHandlersProps,
} from "../../src/components/Calendar/handlers/eventHandlers";
describe("CalendarApp integration", () => { describe("CalendarApp integration", () => {
const today = new Date(); const today = new Date();
@@ -28,7 +28,7 @@ describe("CalendarApp integration", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
const dispatch = jest.fn() as ThunkDispatch<any, any, any>; const dispatch = jest.fn() as AppDispatch;
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch); jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
}); });
+3 -3
View File
@@ -1,8 +1,8 @@
import { act, fireEvent, screen, waitFor } from "@testing-library/react"; import { Menubar } from "@/components/Menubar/Menubar";
import * as oidcAuth from "@/features/User/oidcAuth";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { Menubar } from "../../src/components/Menubar/Menubar"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
import * as oidcAuth from "../../src/features/User/oidcAuth";
describe("Calendar App Component Display Tests", () => { describe("Calendar App Component Display Tests", () => {
const preloadedState = { const preloadedState = {
@@ -1,15 +1,15 @@
import { renderWithProviders } from "../utils/Renderwithproviders"; import * as appHooks from "@/app/hooks";
import { screen } from "@testing-library/react"; import { AppDispatch } from "@/app/store";
import CalendarApp from "@/components/Calendar/Calendar";
import { jest } from "@jest/globals"; import { jest } from "@jest/globals";
import CalendarApp from "../../src/components/Calendar/Calendar"; import { screen } from "@testing-library/react";
import * as appHooks from "../../src/app/hooks"; import { renderWithProviders } from "../utils/Renderwithproviders";
import { ThunkDispatch } from "@reduxjs/toolkit";
describe("MiniCalendar", () => { describe("MiniCalendar", () => {
const day = new Date(); const day = new Date();
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
const dispatch = jest.fn() as ThunkDispatch<any, any, any>; const dispatch = jest.fn() as AppDispatch;
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch); jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
jest.useFakeTimers().clearAllTimers(); jest.useFakeTimers().clearAllTimers();
}); });
+4 -7
View File
@@ -1,13 +1,10 @@
import { screen, fireEvent, waitFor, act } from "@testing-library/react"; import { PeopleSearch, User } from "@/components/Attendees/PeopleSearch";
import { searchUsers } from "@/features/User/userAPI";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import {
User,
PeopleSearch,
} from "../../src/components/Attendees/PeopleSearch";
import { renderWithProviders } from "../utils/Renderwithproviders"; import { renderWithProviders } from "../utils/Renderwithproviders";
import { searchUsers } from "../../src/features/User/userAPI";
jest.mock("../../src/features/User/userAPI"); jest.mock("@/features/User/userAPI");
const mockedSearchUsers = searchUsers as jest.MockedFunction< const mockedSearchUsers = searchUsers as jest.MockedFunction<
typeof searchUsers typeof searchUsers
>; >;
+6 -9
View File
@@ -1,13 +1,10 @@
import { screen, fireEvent, waitFor, act } from "@testing-library/react"; import RepeatEvent from "@/components/Event/EventRepeat";
import userEvent from "@testing-library/user-event"; import * as eventThunks from "@/features/Calendars/services";
import { renderWithProviders } from "../utils/Renderwithproviders"; import EventPopover from "@/features/Events/EventModal";
import RepeatEvent from "../../src/components/Event/EventRepeat"; import { RepetitionObject } from "@/features/Events/EventsTypes";
import EventPopover from "../../src/features/Events/EventModal";
import { RepetitionObject } from "../../src/features/Events/EventsTypes";
import { DateSelectArg } from "@fullcalendar/core"; import { DateSelectArg } from "@fullcalendar/core";
import { formatDateToYYYYMMDDTHHMMSS } from "../../src/utils/dateUtils"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import * as eventThunks from "../../src/features/Calendars/CalendarSlice"; import { renderWithProviders } from "../utils/Renderwithproviders";
import * as apiUtils from "../../src/utils/apiUtils";
const baseRepetition: RepetitionObject = { const baseRepetition: RepetitionObject = {
freq: "", freq: "",
@@ -1,8 +1,7 @@
import { ResponsiveDialog } from "@/components/Dialog";
import { Button, TextField, TwakeMuiThemeProvider } from "@linagora/twake-mui";
import { fireEvent, render, screen } from "@testing-library/react"; import { fireEvent, render, screen } from "@testing-library/react";
import React from "react"; import React from "react";
import { ResponsiveDialog } from "../../src/components/Dialog";
import { Button, TextField } from "@linagora/twake-mui";
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
describe("ResponsiveDialog", () => { describe("ResponsiveDialog", () => {
const mockOnClose = jest.fn(); const mockOnClose = jest.fn();
@@ -1,5 +1,3 @@
// __test__/features/calendars/calendarApi.test.ts
import { import {
addSharedCalendar, addSharedCalendar,
exportCalendar, exportCalendar,
@@ -9,12 +7,12 @@ import {
postCalendar, postCalendar,
proppatchCalendar, proppatchCalendar,
removeCalendar, removeCalendar,
} from "../../../src/features/Calendars/CalendarApi"; } from "@/features/Calendars/CalendarApi";
import { clientConfig } from "../../../src/features/User/oidcAuth"; import { clientConfig } from "@/features/User/oidcAuth";
import { api } from "../../../src/utils/apiUtils"; import { api } from "@/utils/apiUtils";
clientConfig.url = "https://example.com"; clientConfig.url = "https://example.com";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
describe("Calendar API", () => { describe("Calendar API", () => {
afterEach(() => { afterEach(() => {
@@ -1,11 +1,11 @@
import { screen, fireEvent, waitFor } from "@testing-library/react"; import CalendarPopover from "@/components/Calendar/CalendarModal";
import CalendarPopover from "../../../src/components/Calendar/CalendarModal"; import { getSecretLink } from "@/features/Calendars/CalendarApi";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import * as eventThunks from "@/features/Calendars/services";
import { fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
import { Calendar } from "../../../src/features/Calendars/CalendarTypes";
import { getSecretLink } from "../../../src/features/Calendars/CalendarApi";
jest.mock("../../../src/features/Calendars/CalendarApi", () => ({ jest.mock("@/features/Calendars/CalendarApi", () => ({
getSecretLink: jest.fn(), getSecretLink: jest.fn(),
})); }));
@@ -108,7 +108,7 @@ describe("CalendarPopover (editing mode)", () => {
link: "/calendars/user/cal1", link: "/calendars/user/cal1",
name: "Work Calendar", name: "Work Calendar",
description: "Team meetings", description: "Team meetings",
color: "#33B679", color: { light: "#33B679" },
owner: "alice", owner: "alice",
ownerEmails: ["alice@example.com"], ownerEmails: ["alice@example.com"],
visibility: "public", visibility: "public",
@@ -181,7 +181,7 @@ describe("CalendarPopover (editing mode)", () => {
calId: "user1/cal1", calId: "user1/cal1",
calLink: "/calendars/user/cal1", calLink: "/calendars/user/cal1",
patch: { patch: {
color: "#33B679", color: { light: "#33B679" },
desc: "Team meetings", desc: "Team meetings",
name: "Updated Calendar", name: "Updated Calendar",
}, },
@@ -213,7 +213,7 @@ describe("CalendarPopover - Tabs Scenarios", () => {
link: "/calendars/user1/cal1.json", link: "/calendars/user1/cal1.json",
name: "Work Calendar", name: "Work Calendar",
description: "Team meetings", description: "Team meetings",
color: "#33B679", color: { light: "#33B679" },
owner: "alice", owner: "alice",
ownerEmails: ["alice@example.com"], ownerEmails: ["alice@example.com"],
visibility: "public", visibility: "public",
@@ -1,37 +1,36 @@
import * as calAPI from "@/features/Calendars/CalendarApi";
import reducer, { import reducer, {
addEvent, addEvent,
removeEvent,
createCalendar, createCalendar,
updateEventLocal, removeEvent,
removeTempCal, removeTempCal,
getTempCalendarsListAsync, updateEventLocal,
putEventAsync, } from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import {
addSharedCalendarAsync,
createCalendarAsync,
deleteEventAsync,
getCalendarDetailAsync,
getCalendarsListAsync,
getEventAsync, getEventAsync,
patchCalendarAsync, getTempCalendarsListAsync,
removeCalendarAsync,
moveEventAsync, moveEventAsync,
patchACLCalendarAsync, patchACLCalendarAsync,
createCalendarAsync, patchCalendarAsync,
addSharedCalendarAsync, putEventAsync,
deleteEventAsync, removeCalendarAsync,
} from "../../../src/features/Calendars/CalendarSlice"; } from "@/features/Calendars/services";
import { getCalendarsListAsync } from "../../../src/features/Calendars/services/getCalendarsListAsync"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import { getCalendarDetailAsync } from "../../../src/features/Calendars/services/getCalendarDetailAsync"; import * as userAPI from "@/features/User/userAPI";
import userReducer, { setUserData } from "@/features/User/userSlice";
import * as calAPI from "../../../src/features/Calendars/CalendarApi";
import * as userAPI from "../../../src/features/User/userAPI";
import { configureStore } from "@reduxjs/toolkit"; import { configureStore } from "@reduxjs/toolkit";
import { Calendar } from "../../../src/features/Calendars/CalendarTypes";
import { CalendarEvent } from "../../../src/features/Events/EventsTypes";
import { setUserData } from "../../../src/features/User/userSlice";
import userReducer from "../../../src/features/User/userSlice";
jest.mock("../../../src/features/Calendars/CalendarApi"); jest.mock("@/features/Calendars/CalendarApi");
jest.mock("../../../src/features/User/userAPI"); jest.mock("@/features/User/userAPI");
jest.mock("../../../src/features/Events/EventApi"); jest.mock("@/features/Events/EventApi");
jest.mock("../../../src/features/Events/eventUtils"); jest.mock("@/features/Events/eventUtils");
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
describe("CalendarSlice", () => { describe("CalendarSlice", () => {
const initialState = { const initialState = {
@@ -1,10 +1,10 @@
import CalendarApp from "@/components/Calendar/Calendar";
import * as calendarUtils from "@/components/Calendar/utils/calendarUtils";
import { updateSlotLabelVisibility } from "@/components/Calendar/utils/calendarUtils";
import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import { CalendarEvent } from "@/features/Events/EventsTypes";
import * as SettingsSlice from "@/features/Settings/SettingsSlice";
import { fireEvent, screen, waitFor } from "@testing-library/react"; import { fireEvent, screen, waitFor } from "@testing-library/react";
import CalendarApp from "../../../src/components/Calendar/Calendar";
import { updateSlotLabelVisibility } from "../../../src/components/Calendar/utils/calendarUtils";
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview";
import * as SettingsSlice from "../../../src/features/Settings/SettingsSlice";
import * as calendarUtils from "../../../src/components/Calendar/utils/calendarUtils";
import { CalendarEvent } from "../../../src/features/Events/EventsTypes";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
describe("Calendar - Timezone Integration", () => { describe("Calendar - Timezone Integration", () => {
@@ -199,7 +199,6 @@ describe("EventDisplayPreview - Timezone Display", () => {
onClose={mockOnClose} onClose={mockOnClose}
eventId="allDayEvent" eventId="allDayEvent"
calId="user1/cal1" calId="user1/cal1"
event={allDayEvent}
/>, />,
baseState baseState
); );
@@ -236,7 +235,6 @@ describe("EventDisplayPreview - Timezone Display", () => {
eventId="event1" eventId="event1"
calId="user1/cal1" calId="user1/cal1"
onClose={mockOnClose} onClose={mockOnClose}
event={baseEvent}
/>, />,
state state
); );
@@ -1,5 +1,5 @@
import { screen, fireEvent, waitFor, cleanup } from "@testing-library/react"; import { TimezoneSelector } from "@/components/Calendar/TimezoneSelector";
import { TimezoneSelector } from "../../../src/components/Calendar/TimezoneSelector"; import { cleanup, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
describe("TimezoneSelector", () => { describe("TimezoneSelector", () => {
@@ -1,16 +1,16 @@
import { configureStore } from "@reduxjs/toolkit"; import * as fetchSyncTokenChanges from "@/features/Calendars/api/fetchSyncTokenChanges";
import reducer from "../../../../src/features/Calendars/CalendarSlice"; import reducer from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { import {
refreshCalendarWithSyncToken, refreshCalendarWithSyncToken,
SyncTokenUpdates, SyncTokenUpdates,
} from "../../../../src/features/Calendars/services/refreshCalendar"; } from "@/features/Calendars/services/refreshCalendar";
import { Calendar } from "../../../../src/features/Calendars/CalendarTypes"; import * as EventApi from "@/features/Events/EventApi";
import { CalendarEvent } from "../../../../src/features/Events/EventsTypes"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import * as fetchSyncTokenChanges from "../../../../src/features/Calendars/api/fetchSyncTokenChanges"; import { configureStore } from "@reduxjs/toolkit";
import * as EventApi from "../../../../src/features/Events/EventApi";
jest.mock("../../../../src/features/Calendars/api/fetchSyncTokenChanges"); jest.mock("@/features/Calendars/api/fetchSyncTokenChanges");
jest.mock("../../../../src/features/Events/EventApi"); jest.mock("@/features/Events/EventApi");
describe("refreshCalendarWithSyncToken", () => { describe("refreshCalendarWithSyncToken", () => {
const mockCalendar: Calendar = { const mockCalendar: Calendar = {
@@ -1,4 +1,4 @@
import { EventErrorHandler } from "../../../src/components/Error/EventErrorHandler"; import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
describe("EventErrorHandler", () => { describe("EventErrorHandler", () => {
it("calls the callback when a new error is reported", () => { it("calls the callback when a new error is reported", () => {
+9 -8
View File
@@ -1,17 +1,18 @@
import { import {
putEvent,
moveEvent,
deleteEvent, deleteEvent,
importEventFromFile, importEventFromFile,
moveEvent,
putEvent,
searchEvent, searchEvent,
} from "../../../src/features/Events/EventApi"; } from "@/features/Events/EventApi";
import { CalendarEvent } from "../../../src/features/Events/EventsTypes"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import { calendarEventToJCal } from "../../../src/features/Events/eventUtils"; import { calendarEventToJCal } from "@/features/Events/eventUtils";
import { clientConfig } from "../../../src/features/User/oidcAuth"; import { clientConfig } from "@/features/User/oidcAuth";
import { api } from "../../../src/utils/apiUtils"; import { api } from "@/utils/apiUtils";
clientConfig.url = "https://example.com"; clientConfig.url = "https://example.com";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
const day = new Date(); const day = new Date();
+18 -17
View File
@@ -1,23 +1,24 @@
import * as appHooks from "@/app/hooks";
import { AppDispatch } from "@/app/store";
import { InfoRow } from "@/components/Event/InfoRow";
import { LONG_DATE_FORMAT } from "@/components/Event/utils/dateTimeFormatters";
import {
stringAvatar,
stringToColor,
} from "@/components/Event/utils/eventUtils";
import * as calendarSlice from "@/features/Calendars/CalendarSlice";
import * as eventThunks from "@/features/Calendars/services";
import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import { import {
screen,
fireEvent,
waitFor,
act, act,
cleanup, cleanup,
fireEvent,
screen,
waitFor,
} from "@testing-library/react"; } from "@testing-library/react";
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import EventUpdateModal from "../../../src/features/Events/EventUpdateModal";
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview";
import { InfoRow } from "../../../src/components/Event/InfoRow";
import {
stringToColor,
stringAvatar,
} from "../../../src/components/Event/utils/eventUtils";
import * as appHooks from "../../../src/app/hooks";
import { ThunkDispatch } from "@reduxjs/toolkit";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { LONG_DATE_FORMAT } from "../../../src/components/Event/utils/dateTimeFormatters"; import { renderWithProviders } from "../../utils/Renderwithproviders";
describe("Event Preview Display", () => { describe("Event Preview Display", () => {
const mockOnClose = jest.fn(); const mockOnClose = jest.fn();
@@ -747,7 +748,7 @@ describe("Event Preview Display", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
const dispatch = jest.fn() as ThunkDispatch<any, any, any>; const dispatch = jest.fn() as AppDispatch;
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch); jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
}); });
@@ -1831,7 +1832,7 @@ describe("Event Full Display", () => {
(promise as any).unwrap = () => promise; (promise as any).unwrap = () => promise;
return () => promise as any; return () => promise as any;
}); });
const spyRemove = jest.spyOn(eventThunks, "removeEvent"); const spyRemove = jest.spyOn(calendarSlice, "removeEvent");
const testDate = new Date("2025-01-15T10:00:00.000Z"); const testDate = new Date("2025-01-15T10:00:00.000Z");
const testEndDate = new Date("2025-01-15T11:00:00.000Z"); const testEndDate = new Date("2025-01-15T11:00:00.000Z");
+4 -4
View File
@@ -1,12 +1,12 @@
import * as eventThunks from "@/features/Calendars/services";
import EventPopover from "@/features/Events/EventModal";
import { api } from "@/utils/apiUtils";
import { DateSelectArg } from "@fullcalendar/core"; import { DateSelectArg } from "@fullcalendar/core";
import { act, fireEvent, screen, waitFor } from "@testing-library/react"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
import EventPopover from "../../../src/features/Events/EventModal";
import { api } from "../../../src/utils/apiUtils";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
describe("EventPopover", () => { describe("EventPopover", () => {
beforeEach(() => { beforeEach(() => {
@@ -1,26 +1,25 @@
import { screen, fireEvent, waitFor, act } from "@testing-library/react"; import { RootState } from "@/app/store";
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import EventUpdateModal from "../../../src/features/Events/EventUpdateModal";
import { EditModeDialog } from "../../../src/components/Event/EditModeDialog";
import * as EventApi from "../../../src/features/Events/EventApi";
import { import {
createEventHandlers, createEventHandlers,
EventHandlersProps, EventHandlersProps,
} from "../../../src/components/Calendar/handlers/eventHandlers"; } from "@/components/Calendar/handlers/eventHandlers";
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview"; import { EditModeDialog } from "@/components/Event/EditModeDialog";
import * as eventThunks from "@/features/Calendars/services";
import * as EventApi from "@/features/Events/EventApi";
import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import preview from "jest-preview";
import { renderWithProviders } from "../../utils/Renderwithproviders";
jest.mock("../../../src/components/Event/utils/eventUtils", () => { jest.mock("@/components/Event/utils/eventUtils", () => {
const actual = jest.requireActual( const actual = jest.requireActual("@/components/Event/utils/eventUtils");
"../../../src/components/Event/utils/eventUtils"
);
return { return {
...actual, ...actual,
refreshCalendars: jest.fn(() => Promise.resolve()), refreshCalendars: jest.fn(() => Promise.resolve()),
refreshSingularCalendar: jest.fn(() => Promise.resolve()), refreshSingularCalendar: jest.fn(() => Promise.resolve()),
}; };
}); });
import preview from "jest-preview";
const mockOnClose = jest.fn(); const mockOnClose = jest.fn();
const day = new Date("2025-03-15T10:00:00Z"); const day = new Date("2025-03-15T10:00:00Z");
@@ -102,7 +101,7 @@ const basePreloadedState = {
pending: false, pending: false,
templist: {}, templist: {},
}, },
}; } as unknown as RootState;
describe("EditModeDialog Component", () => { describe("EditModeDialog Component", () => {
beforeEach(() => { beforeEach(() => {
@@ -946,7 +945,7 @@ describe("handleRSVP function", () => {
const { const {
handleRSVP, handleRSVP,
} = require("../../../src/components/Event/eventHandlers/eventHandlers"); } = require("@/components/Event/eventHandlers/eventHandlers");
jest.spyOn(eventThunks, "putEventAsync").mockImplementation((payload) => { jest.spyOn(eventThunks, "putEventAsync").mockImplementation((payload) => {
const promise = Promise.resolve(payload); const promise = Promise.resolve(payload);
@@ -992,7 +991,7 @@ describe("handleDelete function", () => {
const { const {
handleDelete, handleDelete,
} = require("../../../src/components/Event/eventHandlers/eventHandlers"); } = require("@/components/Event/eventHandlers/eventHandlers");
jest jest
.spyOn(eventThunks, "deleteEventAsync") .spyOn(eventThunks, "deleteEventAsync")
@@ -1028,7 +1027,7 @@ describe("handleDelete function", () => {
const { const {
handleDelete, handleDelete,
} = require("../../../src/components/Event/eventHandlers/eventHandlers"); } = require("@/components/Event/eventHandlers/eventHandlers");
jest jest
.spyOn(eventThunks, "deleteEventInstanceAsync") .spyOn(eventThunks, "deleteEventInstanceAsync")
@@ -1059,7 +1058,7 @@ describe("handleDelete function", () => {
const { const {
handleDelete, handleDelete,
} = require("../../../src/components/Event/eventHandlers/eventHandlers"); } = require("@/components/Event/eventHandlers/eventHandlers");
jest jest
.spyOn(eventThunks, "deleteEventAsync") .spyOn(eventThunks, "deleteEventAsync")
@@ -1,12 +1,12 @@
import { screen, fireEvent, waitFor, act } from "@testing-library/react"; import * as eventUtils from "@/components/Event/utils/eventUtils";
import * as CalendarApi from "@/features/Calendars/CalendarApi";
import * as EventApi from "@/features/Events/EventApi";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
import EventUpdateModal from "../../../src/features/Events/EventUpdateModal";
import * as EventApi from "../../../src/features/Events/EventApi";
import * as CalendarApi from "../../../src/features/Calendars/CalendarApi";
import * as eventUtils from "../../../src/components/Event/utils/eventUtils";
jest.mock("../../../src/features/Events/EventApi"); jest.mock("@/features/Events/EventApi");
jest.mock("../../../src/features/Calendars/CalendarApi"); jest.mock("@/features/Calendars/CalendarApi");
describe("EventUpdateModal Timezone Handling", () => { describe("EventUpdateModal Timezone Handling", () => {
const mockOnClose = jest.fn(); const mockOnClose = jest.fn();
@@ -1,7 +1,6 @@
import { screen, fireEvent } from "@testing-library/react"; import ImportAlert from "@/features/Events/ImportAlert";
import { fireEvent, screen } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
import ImportAlert from "../../../src/features/Events/ImportAlert";
import { clearError } from "../../../src/features/Calendars/CalendarSlice";
// Mock the ErrorSnackbar component since we want to test ImportAlert logic, // Mock the ErrorSnackbar component since we want to test ImportAlert logic,
// but we can also test integration if we don't mock it. // but we can also test integration if we don't mock it.
+16 -15
View File
@@ -1,21 +1,22 @@
import * as appHooks from "@/app/hooks";
import CalendarLayout from "@/components/Calendar/CalendarLayout";
import * as calendarUtils from "@/components/Calendar/utils/calendarUtils";
import * as eventUtils from "@/components/Event/utils/eventUtils";
import * as CalendarSlice from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import * as eventThunks from "@/features/Calendars/services";
import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import EventPopover from "@/features/Events/EventModal";
import { CalendarEvent } from "@/features/Events/EventsTypes";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import * as userApi from "@/features/User/userAPI";
import { DateSelectArg } from "@fullcalendar/core";
import { jest } from "@jest/globals"; import { jest } from "@jest/globals";
import { ThunkDispatch } from "@reduxjs/toolkit"; import { ThunkDispatch } from "@reduxjs/toolkit";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { screen, waitFor, fireEvent, act } from "@testing-library/react"; import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import * as appHooks from "../../../src/app/hooks";
import * as eventUtils from "../../../src/components/Event/utils/eventUtils";
import * as userApi from "../../../src/features/User/userAPI";
import * as calendarUtils from "../../../src/components/Calendar/utils/calendarUtils";
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview";
import EventPopover from "../../../src/features/Events/EventModal";
import EventUpdateModal from "../../../src/features/Events/EventUpdateModal";
import CalendarLayout from "../../../src/components/Calendar/CalendarLayout";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import { SpiedFunction } from "jest-mock"; import { SpiedFunction } from "jest-mock";
import { Calendar } from "../../../src/features/Calendars/CalendarTypes"; import { renderWithProviders } from "../../utils/Renderwithproviders";
import { CalendarEvent } from "../../../src/features/Events/EventsTypes";
import { DateSelectArg } from "@fullcalendar/core";
describe("Update tempcalendars called with correct params", () => { describe("Update tempcalendars called with correct params", () => {
const today = new Date(); const today = new Date();
@@ -612,7 +613,7 @@ describe("Update tempcalendars called with correct params", () => {
}); });
it("should call emptyEventsCal with correct params before refreshing", async () => { it("should call emptyEventsCal with correct params before refreshing", async () => {
const emptyEventsCalSpy = jest.spyOn(eventThunks, "emptyEventsCal"); const emptyEventsCalSpy = jest.spyOn(CalendarSlice, "emptyEventsCal");
const preloadedState = createPreloadedState(true); const preloadedState = createPreloadedState(true);
+4 -8
View File
@@ -1,16 +1,12 @@
import { import { CalendarEvent, RepetitionObject } from "@/features/Events/EventsTypes";
CalendarEvent,
RepetitionObject,
} from "../../../src/features/Events/EventsTypes";
import { import {
calendarEventToJCal, calendarEventToJCal,
parseCalendarEvent,
combineMasterDateWithFormTime, combineMasterDateWithFormTime,
detectRecurringEventChanges,
normalizeRepetition, normalizeRepetition,
normalizeTimezone, normalizeTimezone,
detectRecurringEventChanges, parseCalendarEvent,
} from "../../../src/features/Events/eventUtils"; } from "@/features/Events/eventUtils";
import { TIMEZONES } from "../../../src/utils/timezone-data";
describe("parseCalendarEvent", () => { describe("parseCalendarEvent", () => {
const baseColor = { light: "#00FF00" }; const baseColor = { light: "#00FF00" };
@@ -1,8 +1,8 @@
import SearchBar from "@/components/Menubar/EventSearchBar";
import * as searchThunk from "@/features/Search/SearchSlice";
import { fireEvent, screen, waitFor } from "@testing-library/react"; import { fireEvent, screen, waitFor } from "@testing-library/react";
import SearchBar from "../../../src/components/Menubar/EventSearchBar";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import * as searchThunk from "../../../src/features/Search/SearchSlice";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "../../utils/Renderwithproviders";
describe("EventSearchBar", () => { describe("EventSearchBar", () => {
const today = new Date(); const today = new Date();
@@ -1,5 +1,5 @@
import SearchResultsPage from "@/features/Search/SearchResultsPage";
import { screen } from "@testing-library/react"; import { screen } from "@testing-library/react";
import SearchResultsPage from "../../../src/features/Search/SearchResultsPage";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
describe("SearchResultsPage", () => { describe("SearchResultsPage", () => {
@@ -1,13 +1,12 @@
// SearchSlice.test.ts import * as EventApi from "@/features/Events/EventApi";
import { configureStore } from "@reduxjs/toolkit";
import searchResultReducer, { import searchResultReducer, {
searchEventsAsync, searchEventsAsync,
setResults,
setHits, setHits,
} from "../../../src/features/Search/SearchSlice"; setResults,
import * as EventApi from "../../../src/features/Events/EventApi"; } from "@/features/Search/SearchSlice";
import { configureStore } from "@reduxjs/toolkit";
jest.mock("../../../src/features/Events/EventApi"); jest.mock("@/features/Events/EventApi");
describe("SearchSlice", () => { describe("SearchSlice", () => {
let store: any; let store: any;
@@ -1,19 +1,19 @@
import { configureStore } from "@reduxjs/toolkit"; import SettingsPage from "@/features/Settings/SettingsPage";
import { fireEvent, screen, waitFor } from "@testing-library/react";
import SettingsPage from "../../../src/features/Settings/SettingsPage";
import settingsReducer, { import settingsReducer, {
setIsBrowserDefaultTimeZone, setIsBrowserDefaultTimeZone,
setTimeZone, setTimeZone,
} from "../../../src/features/Settings/SettingsSlice"; } from "@/features/Settings/SettingsSlice";
import userReducer, { import userReducer, {
getOpenPaasUserDataAsync, getOpenPaasUserDataAsync,
setTimezone as setUserTimeZone, setTimezone as setUserTimeZone,
} from "../../../src/features/User/userSlice"; } from "@/features/User/userSlice";
import { api } from "../../../src/utils/apiUtils"; import { api } from "@/utils/apiUtils";
import { browserDefaultTimeZone } from "../../../src/utils/timezone"; import { browserDefaultTimeZone } from "@/utils/timezone";
import { configureStore } from "@reduxjs/toolkit";
import { fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
describe("Timezone synchronization after getOpenPaasUserDataAsync", () => { describe("Timezone synchronization after getOpenPaasUserDataAsync", () => {
let apiGetSpy: jest.SpyInstance; let apiGetSpy: jest.SpyInstance;
@@ -1,10 +1,10 @@
import { fireEvent, screen, waitFor } from "@testing-library/react"; import SettingsPage from "@/features/Settings/SettingsPage";
import { api } from "@/utils/apiUtils";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import SettingsPage from "../../../src/features/Settings/SettingsPage"; import { fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
import { api } from "../../../src/utils/apiUtils";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
describe("SettingsPage", () => { describe("SettingsPage", () => {
beforeEach(() => { beforeEach(() => {
+8 -8
View File
@@ -1,12 +1,12 @@
import * as appHooks from "@/app/hooks";
import { AppDispatch } from "@/app/store";
import HandleLogin from "@/features/User/HandleLogin";
import * as oidcAuth from "@/features/User/oidcAuth";
import { clientConfig } from "@/features/User/oidcAuth";
import * as apiUtils from "@/utils/apiUtils";
import { screen, waitFor } from "@testing-library/react"; import { screen, waitFor } from "@testing-library/react";
import thunk, { ThunkDispatch } from "redux-thunk";
import HandleLogin from "../../../src/features/User/HandleLogin";
import * as oidcAuth from "../../../src/features/User/oidcAuth";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import { clientConfig } from "../../../src/features/User/oidcAuth";
import * as apiUtils from "../../../src/utils/apiUtils";
import * as appHooks from "../../../src/app/hooks";
import { push } from "redux-first-history"; import { push } from "redux-first-history";
import { renderWithProviders } from "../../utils/Renderwithproviders";
clientConfig.url = "https://example.com"; clientConfig.url = "https://example.com";
@@ -14,7 +14,7 @@ describe("HandleLogin", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
jest.spyOn(apiUtils, "redirectTo").mockImplementation(() => {}); jest.spyOn(apiUtils, "redirectTo").mockImplementation(() => {});
const dispatch = jest.fn() as ThunkDispatch<any, any, any>; const dispatch = jest.fn() as AppDispatch;
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch); jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
sessionStorage.clear(); sessionStorage.clear();
}); });
+13 -17
View File
@@ -1,28 +1,27 @@
// __test__/features/user/CallbackResume.test.tsx import { useAppDispatch } from "@/app/hooks";
import { render, waitFor } from "@testing-library/react"; import { getCalendarsListAsync } from "@/features/Calendars/services/getCalendarsListAsync";
import { CallbackResume } from "../../../src/features/User/LoginCallback"; import { CallbackResume } from "@/features/User/LoginCallback";
import { useAppDispatch } from "../../../src/app/hooks"; import * as oidcAuth from "@/features/User/oidcAuth";
import * as oidcAuth from "../../../src/features/User/oidcAuth";
import { push } from "redux-first-history";
import { import {
getOpenPaasUserDataAsync,
setTokens, setTokens,
setUserData, setUserData,
getOpenPaasUserDataAsync, } from "@/features/User/userSlice";
} from "../../../src/features/User/userSlice"; import { render, waitFor } from "@testing-library/react";
import { getCalendarsListAsync } from "../../../src/features/Calendars/services/getCalendarsListAsync"; import { push } from "redux-first-history";
import { renderWithProviders } from "../../utils/Renderwithproviders"; import { renderWithProviders } from "../../utils/Renderwithproviders";
// Mocks // Mocks
jest.mock("../../../src/app/hooks", () => ({ jest.mock("@/app/hooks", () => ({
useAppDispatch: jest.fn(), useAppDispatch: jest.fn(),
useAppSelector: jest.fn(() => ({})), useAppSelector: jest.fn(() => ({})),
})); }));
jest.mock("../../../src/features/User/oidcAuth", () => ({ jest.mock("@/features/User/oidcAuth", () => ({
Callback: jest.fn(), Callback: jest.fn(),
})); }));
jest.mock("../../../src/features/User/userSlice", () => { jest.mock("@/features/User/userSlice", () => {
const mockGetUser = Object.assign( const mockGetUser = Object.assign(
jest.fn(() => ({ type: "GET_USER_ID" })), jest.fn(() => ({ type: "GET_USER_ID" })),
{ {
@@ -39,9 +38,7 @@ jest.mock("../../../src/features/User/userSlice", () => {
}; };
}); });
jest.mock( jest.mock("@/features/Calendars/services/getCalendarsListAsync", () => {
"../../../src/features/Calendars/services/getCalendarsListAsync",
() => {
const mockGetCalendars = Object.assign( const mockGetCalendars = Object.assign(
jest.fn(() => ({ type: "GET_CALENDARS" })), jest.fn(() => ({ type: "GET_CALENDARS" })),
{ {
@@ -54,8 +51,7 @@ jest.mock(
return { return {
getCalendarsListAsync: mockGetCalendars, getCalendarsListAsync: mockGetCalendars,
}; };
} });
);
describe("CallbackResume", () => { describe("CallbackResume", () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
+5 -5
View File
@@ -1,13 +1,13 @@
// __tests__/auth.test.ts // __tests__/auth.test.ts
import * as client from "openid-client";
import { import {
Auth,
Callback,
clientConfig, clientConfig,
getClientConfig, getClientConfig,
Auth,
Logout, Logout,
Callback, } from "@/features/User/oidcAuth";
} from "../../../src/features/User/oidcAuth"; import * as apiUtils from "@/utils/apiUtils";
import * as apiUtils from "../../../src/utils/apiUtils"; import * as client from "openid-client";
clientConfig.url = "https://example.com"; clientConfig.url = "https://example.com";
const localAdress = "https://local.exemple.com"; const localAdress = "https://local.exemple.com";
+4 -4
View File
@@ -1,11 +1,11 @@
import { clientConfig } from "../../../src/features/User/oidcAuth"; import { clientConfig } from "@/features/User/oidcAuth";
import { import {
getOpenPaasUser, getOpenPaasUser,
updateUserConfigurations, updateUserConfigurations,
} from "../../../src/features/User/userAPI"; } from "@/features/User/userAPI";
import { api } from "../../../src/utils/apiUtils"; import { api } from "@/utils/apiUtils";
jest.mock("../../../src/utils/apiUtils"); jest.mock("@/utils/apiUtils");
clientConfig.url = "https://example.com"; clientConfig.url = "https://example.com";
@@ -1,11 +1,11 @@
import { cleanup, render, waitFor, act } from "@testing-library/react"; import { setSelectedCalendars } from "@/utils/storage/setSelectedCalendars";
import { Provider } from "react-redux";
import { configureStore } from "@reduxjs/toolkit";
import { createWebSocketConnection } from "@/websocket/connection/createConnection"; import { createWebSocketConnection } from "@/websocket/connection/createConnection";
import { registerToCalendars } from "@/websocket/operations/registerToCalendars"; import { registerToCalendars } from "@/websocket/operations/registerToCalendars";
import { unregisterToCalendars } from "@/websocket/operations/unregisterToCalendars"; import { unregisterToCalendars } from "@/websocket/operations/unregisterToCalendars";
import { WebSocketGate } from "@/websocket/WebSocketGate"; import { WebSocketGate } from "@/websocket/WebSocketGate";
import { setSelectedCalendars } from "@/utils/storage/setSelectedCalendars"; import { configureStore } from "@reduxjs/toolkit";
import { act, cleanup, render, waitFor } from "@testing-library/react";
import { Provider } from "react-redux";
jest.mock("@/websocket/connection/createConnection"); jest.mock("@/websocket/connection/createConnection");
jest.mock("@/websocket/operations/registerToCalendars"); jest.mock("@/websocket/operations/registerToCalendars");
@@ -1,7 +1,7 @@
import { waitFor } from "@testing-library/dom";
import { fetchWebSocketTicket } from "@/websocket/api/fetchWebSocketTicket"; import { fetchWebSocketTicket } from "@/websocket/api/fetchWebSocketTicket";
import { createWebSocketConnection } from "@/websocket/connection/createConnection"; import { createWebSocketConnection } from "@/websocket/connection/createConnection";
import { WS_INBOUND_EVENTS } from "@/websocket/protocols"; import { WS_INBOUND_EVENTS } from "@/websocket/protocols";
import { waitFor } from "@testing-library/dom";
import { setupWebsocket } from "./utils/setupWebsocket"; import { setupWebsocket } from "./utils/setupWebsocket";
jest.mock("@/websocket/api/fetchWebSocketTicket"); jest.mock("@/websocket/api/fetchWebSocketTicket");
@@ -1,8 +1,8 @@
import { updateCalendars } from "@/websocket/messaging/updateCalendars";
import { refreshCalendarWithSyncToken } from "@/features/Calendars/services/refreshCalendar";
import { RootState, store } from "@/app/store"; import { RootState, store } from "@/app/store";
import { WS_INBOUND_EVENTS } from "@/websocket/protocols"; import { refreshCalendarWithSyncToken } from "@/features/Calendars/services/refreshCalendar";
import { getDisplayedCalendarRange } from "@/utils/CalendarRangeManager"; import { getDisplayedCalendarRange } from "@/utils/CalendarRangeManager";
import { updateCalendars } from "@/websocket/messaging/updateCalendars";
import { WS_INBOUND_EVENTS } from "@/websocket/protocols";
import { waitFor } from "@testing-library/dom"; import { waitFor } from "@testing-library/dom";
jest.mock("@/features/Calendars/services/refreshCalendar"); jest.mock("@/features/Calendars/services/refreshCalendar");
@@ -1,5 +1,5 @@
import { WS_INBOUND_EVENTS } from "@/websocket/protocols";
import { parseMessage } from "@/websocket/messaging/parseMessage"; import { parseMessage } from "@/websocket/messaging/parseMessage";
import { WS_INBOUND_EVENTS } from "@/websocket/protocols";
describe("parseMessage", () => { describe("parseMessage", () => {
it("should return empty set for non-object messages", () => { it("should return empty set for non-object messages", () => {
@@ -1,5 +1,3 @@
// src/websocket/__tests__/unregisterToCalendars.test.ts
import { unregisterToCalendars } from "@/websocket/operations/unregisterToCalendars"; import { unregisterToCalendars } from "@/websocket/operations/unregisterToCalendars";
describe("unregisterToCalendars", () => { describe("unregisterToCalendars", () => {
+3 -3
View File
@@ -1,9 +1,9 @@
import { import {
getDisplayedDate,
setDisplayedDateAndRange,
calendarRangeManager, calendarRangeManager,
getDisplayedCalendarRange, getDisplayedCalendarRange,
} from "../../src/utils/CalendarRangeManager"; getDisplayedDate,
setDisplayedDateAndRange,
} from "@/utils/CalendarRangeManager";
describe("CalendarRangeManager", () => { describe("CalendarRangeManager", () => {
beforeEach(() => { beforeEach(() => {
+3 -3
View File
@@ -1,12 +1,12 @@
import type { AppStore, RootState } from "@/app/store";
import { setupStore } from "@/app/store";
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
import type { RenderOptions } from "@testing-library/react"; import type { RenderOptions } from "@testing-library/react";
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import React, { PropsWithChildren } from "react"; import React, { PropsWithChildren } from "react";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { I18nContext } from "twake-i18n"; import { I18nContext } from "twake-i18n";
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
import type { AppStore, RootState } from "../../src/app/store";
import { setupStore } from "../../src/app/store";
interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> { interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {
preloadedState?: Partial<RootState>; preloadedState?: Partial<RootState>;
store?: AppStore; store?: AppStore;
+1 -1
View File
@@ -1,4 +1,4 @@
import { getInitials, stringToGradient } from "../../src/utils/avatarUtils"; import { getInitials, stringToGradient } from "@/utils/avatarUtils";
jest.mock("@linagora/twake-mui", () => ({ jest.mock("@linagora/twake-mui", () => ({
nameToColor: jest.fn((name: string) => { nameToColor: jest.fn((name: string) => {
+1 -1
View File
@@ -1,4 +1,4 @@
import { getCalendarVisibility } from "../../src/components/Calendar/utils/calendarUtils"; import { getCalendarVisibility } from "@/components/Calendar/utils/calendarUtils";
interface AclEntry { interface AclEntry {
privilege: string; privilege: string;
+1 -1
View File
@@ -1,4 +1,4 @@
import { getCalendarRange } from "../../src/utils/dateUtils"; import { getCalendarRange } from "@/utils/dateUtils";
describe("getCalendarRange", () => { describe("getCalendarRange", () => {
it("Nov 2025 (5 weeks): 2025-10-27 to 2025-11-30", () => { it("Nov 2025 (5 weeks): 2025-10-27 to 2025-11-30", () => {
+3 -3
View File
@@ -1,6 +1,6 @@
import { findCalendarById } from "../../src/utils/findCalendarById"; import { RootState } from "@/app/store";
import { Calendar } from "../../src/features/Calendars/CalendarTypes"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { RootState } from "../../src/app/store"; import { findCalendarById } from "@/utils";
describe("findCalendarById", () => { describe("findCalendarById", () => {
const mockCalendar1: Calendar = { const mockCalendar1: Calendar = {
+2 -2
View File
@@ -1,5 +1,5 @@
import { getUserDisplayName } from "../../src/utils/userUtils"; import { userData } from "@/features/User/userDataTypes";
import { userData } from "../../src/features/User/userDataTypes"; import { getUserDisplayName } from "@/utils/userUtils";
describe("userUtils", () => { describe("userUtils", () => {
describe("getUserDisplayName", () => { describe("getUserDisplayName", () => {
+13 -13
View File
@@ -1,18 +1,19 @@
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
import { Suspense, useEffect } from "react"; import { Suspense, useEffect } from "react";
import { Route, Routes } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
import { HistoryRouter as Router } from "redux-first-history/rr6";
import { CallbackResume } from "./features/User/LoginCallback";
import { history } from "./app/store";
import "./App.styl";
import { Loading } from "./components/Loading/Loading";
import HandleLogin from "./features/User/HandleLogin";
import CalendarLayout from "./components/Calendar/CalendarLayout";
import { Error } from "./components/Error/Error";
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
import { useAppDispatch, useAppSelector } from "./app/hooks";
import { push } from "redux-first-history"; import { push } from "redux-first-history";
import { HistoryRouter as Router } from "redux-first-history/rr6";
import "./App.styl";
import { useAppDispatch, useAppSelector } from "./app/hooks";
import { history } from "./app/store";
import CalendarLayout from "./components/Calendar/CalendarLayout";
import { Error as ErrorPage } from "./components/Error/Error";
import { ErrorSnackbar } from "./components/Error/ErrorSnackbar"; import { ErrorSnackbar } from "./components/Error/ErrorSnackbar";
import { Loading } from "./components/Loading/Loading";
import { AVAILABLE_LANGUAGES } from "./features/Settings/constants"; import { AVAILABLE_LANGUAGES } from "./features/Settings/constants";
import HandleLogin from "./features/User/HandleLogin";
import { CallbackResume } from "./features/User/LoginCallback";
import { WebSocketGate } from "./websocket/WebSocketGate";
import { import {
enGB, enGB,
@@ -21,12 +22,11 @@ import {
vi as viLocale, vi as viLocale,
} from "date-fns/locale"; } from "date-fns/locale";
import I18n from "twake-i18n";
import en from "./locales/en.json"; import en from "./locales/en.json";
import fr from "./locales/fr.json"; import fr from "./locales/fr.json";
import ru from "./locales/ru.json"; import ru from "./locales/ru.json";
import vi from "./locales/vi.json"; import vi from "./locales/vi.json";
import I18n from "twake-i18n";
import { WebSocketGate } from "./websocket/WebSocketGate";
const locale = { en, fr, ru, vi }; const locale = { en, fr, ru, vi };
const dateLocales = { en: enGB, fr: frLocale, ru: ruLocale, vi: viLocale }; const dateLocales = { en: enGB, fr: frLocale, ru: ruLocale, vi: viLocale };
@@ -75,7 +75,7 @@ function App() {
<Route path="/" element={<HandleLogin />} /> <Route path="/" element={<HandleLogin />} />
<Route path="/calendar" element={<CalendarLayout />} /> <Route path="/calendar" element={<CalendarLayout />} />
<Route path="/callback" element={<CallbackResume />} /> <Route path="/callback" element={<CallbackResume />} />
<Route path="/error" element={<Error />} /> <Route path="/error" element={<ErrorPage />} />
</Routes> </Routes>
</Router> </Router>
<ErrorSnackbar error={error} type="user" /> <ErrorSnackbar error={error} type="user" />
+1 -1
View File
@@ -1,5 +1,5 @@
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store"; import type { AppDispatch, RootState } from "./store";
export const useAppDispatch = useDispatch.withTypes<AppDispatch>(); export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>(); export const useAppSelector = useSelector.withTypes<RootState>();
+5 -5
View File
@@ -1,10 +1,10 @@
import eventsCalendar from "@/features/Calendars/CalendarSlice";
import searchResultReducer from "@/features/Search/SearchSlice";
import settingsReducer from "@/features/Settings/SettingsSlice";
import userReducer from "@/features/User/userSlice";
import { combineReducers, configureStore } from "@reduxjs/toolkit"; import { combineReducers, configureStore } from "@reduxjs/toolkit";
import userReducer from "../features/User/userSlice";
import settingsReducer from "../features/Settings/SettingsSlice";
import searchResultReducer from "../features/Search/SearchSlice";
import eventsCalendar from "../features/Calendars/CalendarSlice";
import { createReduxHistoryContext } from "redux-first-history";
import { createBrowserHistory } from "history"; import { createBrowserHistory } from "history";
import { createReduxHistoryContext } from "redux-first-history";
const { createReduxHistory, routerMiddleware, routerReducer } = const { createReduxHistory, routerMiddleware, routerReducer } =
createReduxHistoryContext({ history: createBrowserHistory() }); createReduxHistoryContext({ history: createBrowserHistory() });
+3 -3
View File
@@ -1,10 +1,10 @@
import { userAttendee } from "@/features/User/models/attendee";
import { createAttendee } from "@/features/User/models/attendee.mapper";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { userAttendee } from "../../features/User/models/attendee";
import { createAttendee } from "../../features/User/models/attendee.mapper";
import { import {
ExtendedAutocompleteRenderInputParams,
PeopleSearch, PeopleSearch,
User, User,
ExtendedAutocompleteRenderInputParams,
} from "./PeopleSearch"; } from "./PeopleSearch";
export default function UserSearch({ export default function UserSearch({
+12 -10
View File
@@ -1,28 +1,30 @@
import { getAccessiblePair } from "@/components/Calendar/utils/calendarColorsUtils";
import { stringAvatar } from "@/components/Event/utils/eventUtils";
import { SnackbarAlert } from "@/components/Loading/SnackBarAlert";
import { searchUsers } from "@/features/User/userAPI";
import { import {
Autocomplete, Autocomplete,
type AutocompleteRenderInputParams,
Avatar, Avatar,
Chip,
CircularProgress, CircularProgress,
ListItem, ListItem,
ListItemAvatar, ListItemAvatar,
ListItemText, ListItemText,
PaperProps,
PopperProps,
TextField, TextField,
useTheme,
type AutocompleteRenderInputParams,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { stringAvatar } from "../Event/utils/eventUtils"; import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
import { import {
type ReactNode, HTMLAttributes,
useCallback, useCallback,
useEffect, useEffect,
useState, useState,
HTMLAttributes, type ReactNode,
} from "react"; } from "react";
import { searchUsers } from "../../features/User/userAPI";
import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
import { Chip, useTheme } from "@linagora/twake-mui";
import { getAccessiblePair } from "../Calendar/utils/calendarColorsUtils";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { SnackbarAlert } from "../Loading/SnackBarAlert";
import { PopperProps, PaperProps } from "@linagora/twake-mui";
export interface User { export interface User {
email: string; email: string;
+16 -17
View File
@@ -1,25 +1,24 @@
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";
import {
Box,
IconButton,
TextField,
Button,
Typography,
InputAdornment,
Backdrop,
CircularProgress,
} from "@linagora/twake-mui";
import { useState, useEffect } from "react";
import { import {
exportCalendar, exportCalendar,
getSecretLink, getSecretLink,
} from "../../features/Calendars/CalendarApi"; } from "@/features/Calendars/CalendarApi";
import { Calendar } from "../../features/Calendars/CalendarTypes"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { FieldWithLabel } from "../Event/components/FieldWithLabel"; import {
import { SnackbarAlert } from "../Loading/SnackBarAlert"; Box,
Button,
CircularProgress,
IconButton,
InputAdornment,
TextField,
Typography,
} from "@linagora/twake-mui";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";
import { useEffect, useState } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { ErrorSnackbar } from "../Error/ErrorSnackbar"; import { ErrorSnackbar } from "../Error/ErrorSnackbar";
import { FieldWithLabel } from "../Event/components/FieldWithLabel";
import { SnackbarAlert } from "../Loading/SnackBarAlert";
export function AccessTab({ calendar }: { calendar: Calendar }) { export function AccessTab({ calendar }: { calendar: Calendar }) {
const { t } = useI18n(); const { t } = useI18n();
+41 -42
View File
@@ -1,52 +1,51 @@
import FullCalendar from "@fullcalendar/react"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import dayGridPlugin from "@fullcalendar/daygrid"; import { getCalendarDetailAsync } from "@/features/Calendars/services";
import timeGridPlugin from "@fullcalendar/timegrid"; import EventPreviewModal from "@/features/Events/EventDisplayPreview";
import interactionPlugin from "@fullcalendar/interaction"; import EventPopover from "@/features/Events/EventModal";
import { CalendarApi, DateSelectArg } from "@fullcalendar/core"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import "./Calendar.styl"; import ImportAlert from "@/features/Events/ImportAlert";
import "./CustomCalendar.styl"; import SearchResultsPage from "@/features/Search/SearchResultsPage";
import { MutableRefObject, useEffect, useMemo, useRef, useState } from "react"; import { setTimeZone } from "@/features/Settings/SettingsSlice";
import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { setDisplayedDateAndRange } from "@/utils/CalendarRangeManager";
import EventPopover from "../../features/Events/EventModal";
import { CalendarEvent } from "../../features/Events/EventsTypes";
import CalendarSelection from "./CalendarSelection";
import { getCalendarDetailAsync } from "../../features/Calendars/services/getCalendarDetailAsync";
import ImportAlert from "../../features/Events/ImportAlert";
import { import {
formatDateToYYYYMMDDTHHMMSS, formatDateToYYYYMMDDTHHMMSS,
getCalendarRange, getCalendarRange,
} from "@/utils/dateUtils"; } from "@/utils/dateUtils";
import { push } from "redux-first-history"; import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import EventPreviewModal from "../../features/Events/EventDisplayPreview"; import { setSelectedCalendars as setSelectedCalendarsToStorage } from "@/utils/storage/setSelectedCalendars";
import AddIcon from "@mui/icons-material/Add"; import { browserDefaultTimeZone } from "@/utils/timezone";
import { TempCalendarsInput } from "./TempCalendarsInput"; import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
import { Button, Box, radius } from "@linagora/twake-mui";
import {
updateSlotLabelVisibility,
eventToFullCalendarFormat,
extractEvents,
} from "./utils/calendarUtils";
import { useCalendarEventHandlers } from "./hooks/useCalendarEventHandlers";
import { useCalendarViewHandlers } from "./hooks/useCalendarViewHandlers";
import { EditModeDialog } from "../Event/EditModeDialog";
import { EventErrorHandler } from "../Error/EventErrorHandler";
import { EventErrorSnackbar } from "../Error/ErrorSnackbar";
import momentTimezonePlugin from "@fullcalendar/moment-timezone";
import { TimezoneSelector } from "./TimezoneSelector";
import { MiniCalendar } from "./MiniCalendar";
import { User } from "../Attendees/PeopleSearch";
import { useTheme } from "@linagora/twake-mui";
import { updateDarkColor } from "./utils/calendarColorsUtils";
import { useI18n } from "twake-i18n";
import frLocale from "@fullcalendar/core/locales/fr"; import frLocale from "@fullcalendar/core/locales/fr";
import ruLocale from "@fullcalendar/core/locales/ru"; import ruLocale from "@fullcalendar/core/locales/ru";
import viLocale from "@fullcalendar/core/locales/vi"; import viLocale from "@fullcalendar/core/locales/vi";
import SearchResultsPage from "../../features/Search/SearchResultsPage"; import dayGridPlugin from "@fullcalendar/daygrid";
import { setTimeZone } from "../../features/Settings/SettingsSlice"; import interactionPlugin from "@fullcalendar/interaction";
import { browserDefaultTimeZone } from "@/utils/timezone"; import momentTimezonePlugin from "@fullcalendar/moment-timezone";
import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid"; import FullCalendar from "@fullcalendar/react";
import { setSelectedCalendars as setSelectedCalendarsToStorage } from "@/utils/storage/setSelectedCalendars"; import timeGridPlugin from "@fullcalendar/timegrid";
import { setDisplayedDateAndRange } from "@/utils/CalendarRangeManager"; import { Box, Button, radius, useTheme } from "@linagora/twake-mui";
import AddIcon from "@mui/icons-material/Add";
import { MutableRefObject, useEffect, useMemo, useRef, useState } from "react";
import { push } from "redux-first-history";
import { useI18n } from "twake-i18n";
import { User } from "../Attendees/PeopleSearch";
import { EventErrorSnackbar } from "../Error/ErrorSnackbar";
import { EventErrorHandler } from "../Error/EventErrorHandler";
import { EditModeDialog } from "../Event/EditModeDialog";
import "./Calendar.styl";
import CalendarSelection from "./CalendarSelection";
import "./CustomCalendar.styl";
import { useCalendarEventHandlers } from "./hooks/useCalendarEventHandlers";
import { useCalendarViewHandlers } from "./hooks/useCalendarViewHandlers";
import { MiniCalendar } from "./MiniCalendar";
import { TempCalendarsInput } from "./TempCalendarsInput";
import { TimezoneSelector } from "./TimezoneSelector";
import { updateDarkColor } from "./utils/calendarColorsUtils";
import {
eventToFullCalendarFormat,
extractEvents,
updateSlotLabelVisibility,
} from "./utils/calendarUtils";
const localeMap: Record<string, any> = { const localeMap: Record<string, any> = {
fr: frLocale, fr: frLocale,
+2 -2
View File
@@ -1,6 +1,6 @@
import React from "react"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { MenuItem } from "@linagora/twake-mui"; import { MenuItem } from "@linagora/twake-mui";
import { Calendar } from "../../features/Calendars/CalendarTypes"; import React from "react";
import { CalendarName } from "./CalendarName"; import { CalendarName } from "./CalendarName";
export function CalendarItemList( export function CalendarItemList(
+6 -8
View File
@@ -1,13 +1,11 @@
import { useRef, useState, useEffect } from "react"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import SettingsPage from "@/features/Settings/SettingsPage";
import { getCalendarRange } from "@/utils/dateUtils";
import { useEffect, useRef, useState } from "react";
import { ErrorSnackbar } from "../Error/ErrorSnackbar";
import { refreshCalendars } from "../Event/utils/eventUtils";
import { Menubar, MenubarProps } from "../Menubar/Menubar"; import { Menubar, MenubarProps } from "../Menubar/Menubar";
import CalendarApp from "./Calendar"; import CalendarApp from "./Calendar";
import { useAppDispatch } from "../../app/hooks";
import { getCalendarRange } from "../../utils/dateUtils";
import { useAppSelector } from "../../app/hooks";
import { refreshCalendars } from "../Event/utils/eventUtils";
import { ErrorSnackbar } from "../Error/ErrorSnackbar";
import SettingsPage from "../../features/Settings/SettingsPage";
export default function CalendarLayout() { export default function CalendarLayout() {
const calendarRef = useRef<any>(null); const calendarRef = useRef<any>(null);
+7 -7
View File
@@ -1,20 +1,20 @@
import { Button, Tab, Tabs } from "@linagora/twake-mui"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { useEffect, useState } from "react"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { import {
createCalendarAsync, createCalendarAsync,
importEventFromFileAsync, importEventFromFileAsync,
patchACLCalendarAsync, patchACLCalendarAsync,
patchCalendarAsync, patchCalendarAsync,
} from "../../features/Calendars/CalendarSlice"; } from "@/features/Calendars/services";
import { Calendar } from "../../features/Calendars/CalendarTypes"; import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { Button, Tab, Tabs } from "@linagora/twake-mui";
import { useEffect, useState } from "react";
import { useI18n } from "twake-i18n";
import { ResponsiveDialog } from "../Dialog"; import { ResponsiveDialog } from "../Dialog";
import { AccessTab } from "./AccessTab"; import { AccessTab } from "./AccessTab";
import { ImportTab } from "./ImportTab"; import { ImportTab } from "./ImportTab";
import { SettingsTab } from "./SettingsTab"; import { SettingsTab } from "./SettingsTab";
import { defaultColors } from "./utils/calendarColorsUtils"; import { defaultColors } from "./utils/calendarColorsUtils";
import { useI18n } from "twake-i18n";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
function CalendarPopover({ function CalendarPopover({
open, open,
+1 -1
View File
@@ -1,5 +1,5 @@
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { Box, Typography } from "@linagora/twake-mui"; import { Box, Typography } from "@linagora/twake-mui";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import SquareRoundedIcon from "@mui/icons-material/SquareRounded"; import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
export function CalendarName({ calendar }: { calendar: Calendar }) { export function CalendarName({ calendar }: { calendar: Calendar }) {
return ( return (
+8 -8
View File
@@ -1,22 +1,22 @@
import CloseIcon from "@mui/icons-material/Close"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { getCalendars } from "@/features/Calendars/CalendarApi";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { addSharedCalendarAsync } from "@/features/Calendars/services";
import { import {
Avatar, Avatar,
Box, Box,
Button, Button,
IconButton, IconButton,
Typography,
TextField, TextField,
Typography,
useTheme, useTheme,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { useI18n } from "twake-i18n"; import CloseIcon from "@mui/icons-material/Close";
import { stringAvatar } from "../Event/utils/eventUtils";
import { useState } from "react"; import { useState } from "react";
import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { useI18n } from "twake-i18n";
import { getCalendars } from "../../features/Calendars/CalendarApi";
import { addSharedCalendarAsync } from "../../features/Calendars/CalendarSlice";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { PeopleSearch, User } from "../Attendees/PeopleSearch"; import { PeopleSearch, User } from "../Attendees/PeopleSearch";
import { ResponsiveDialog } from "../Dialog"; import { ResponsiveDialog } from "../Dialog";
import { stringAvatar } from "../Event/utils/eventUtils";
import { ColorPicker } from "./CalendarColorPicker"; import { ColorPicker } from "./CalendarColorPicker";
import { defaultColors, getAccessiblePair } from "./utils/calendarColorsUtils"; import { defaultColors, getAccessiblePair } from "./utils/calendarColorsUtils";
+12 -12
View File
@@ -1,28 +1,28 @@
import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { removeCalendarAsync } from "@/features/Calendars/services";
import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { trimLongTextWithoutSpace } from "@/utils/textUtils";
import { import {
Accordion, Accordion,
AccordionDetails, AccordionDetails,
AccordionSummary, AccordionSummary,
Typography,
IconButton,
Checkbox, Checkbox,
Divider, Divider,
IconButton,
ListItem, ListItem,
Menu, Menu,
MenuItem, MenuItem,
Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import AddIcon from "@mui/icons-material/Add"; import AddIcon from "@mui/icons-material/Add";
import { useState, useMemo, useEffect } from "react";
import CalendarPopover from "./CalendarModal";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import MoreVertIcon from "@mui/icons-material/MoreVert";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import CalendarSearch from "./CalendarSearch"; import MoreVertIcon from "@mui/icons-material/MoreVert";
import { removeCalendarAsync } from "../../features/Calendars/CalendarSlice"; import { useEffect, useMemo, useState } from "react";
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
import { trimLongTextWithoutSpace } from "../../utils/textUtils";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid"; import CalendarPopover from "./CalendarModal";
import CalendarSearch from "./CalendarSearch";
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
function CalendarAccordion({ function CalendarAccordion({
title, title,
@@ -1,12 +1,12 @@
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { import {
Button,
Dialog, Dialog,
DialogTitle, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
DialogActions, DialogTitle,
Button,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
export function DeleteCalendarDialog({ export function DeleteCalendarDialog({
+3 -5
View File
@@ -1,3 +1,5 @@
import { useAppSelector } from "@/app/hooks";
import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { import {
Box, Box,
Button, Button,
@@ -6,16 +8,12 @@ import {
MenuItem, MenuItem,
Select, Select,
TextField, TextField,
ToggleButton,
ToggleButtonGroup,
Typography, Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useAppSelector } from "../../app/hooks"; import { useI18n } from "twake-i18n";
import { CalendarItemList } from "./CalendarItemList"; import { CalendarItemList } from "./CalendarItemList";
import { SettingsTab } from "./SettingsTab"; import { SettingsTab } from "./SettingsTab";
import { useI18n } from "twake-i18n";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
export function ImportTab({ export function ImportTab({
userId, userId,
+8 -8
View File
@@ -1,17 +1,17 @@
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment"; import { getCalendarDetailAsync } from "@/features/Calendars/services";
import { DateCalendar } from "@mui/x-date-pickers"; import { setView } from "@/features/Settings/SettingsSlice";
import moment from "moment";
import { import {
computeStartOfTheWeek, computeStartOfTheWeek,
formatDateToYYYYMMDDTHHMMSS, formatDateToYYYYMMDDTHHMMSS,
getCalendarRange, getCalendarRange,
} from "../../utils/dateUtils"; } from "@/utils/dateUtils";
import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { DateCalendar } from "@mui/x-date-pickers";
import { getCalendarDetailAsync } from "../../features/Calendars/services/getCalendarDetailAsync"; import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import moment from "moment";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { setView } from "../../features/Settings/SettingsSlice";
export function MiniCalendar({ export function MiniCalendar({
calendarRef, calendarRef,
+6 -8
View File
@@ -1,21 +1,19 @@
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted"; import { useAppSelector } from "@/app/hooks";
import LockOutlineIcon from "@mui/icons-material/LockOutline"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import PublicIcon from "@mui/icons-material/Public"; import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { import {
Box, Box,
Button,
TextField, TextField,
ToggleButton, ToggleButton,
ToggleButtonGroup, ToggleButtonGroup,
Typography, Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import LockOutlineIcon from "@mui/icons-material/LockOutline";
import PublicIcon from "@mui/icons-material/Public";
import { useEffect, useState } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { useState, useEffect } from "react";
import { useAppSelector } from "../../app/hooks";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { AddDescButton } from "../Event/AddDescButton"; import { AddDescButton } from "../Event/AddDescButton";
import { ColorPicker } from "./CalendarColorPicker"; import { ColorPicker } from "./CalendarColorPicker";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
export function SettingsTab({ export function SettingsTab({
name, name,
+7 -10
View File
@@ -1,15 +1,12 @@
import { useTheme } from "@linagora/twake-mui"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { removeTempCal } from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { getTempCalendarsListAsync } from "@/features/Calendars/services";
import { setView } from "@/features/Settings/SettingsSlice";
import { TextField, useTheme } from "@linagora/twake-mui";
import { useRef } from "react"; import { useRef } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { PeopleSearch, User } from "../Attendees/PeopleSearch";
import {
getTempCalendarsListAsync,
removeTempCal,
} from "../../features/Calendars/CalendarSlice";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { setView } from "../../features/Settings/SettingsSlice";
import { TextField } from "@linagora/twake-mui";
import { User, PeopleSearch } from "../Attendees/PeopleSearch";
import { getAccessiblePair } from "./utils/calendarColorsUtils"; import { getAccessiblePair } from "./utils/calendarColorsUtils";
const requestControllers = new Map<string, AbortController>(); const requestControllers = new Map<string, AbortController>();
+3 -3
View File
@@ -1,9 +1,9 @@
import { browserDefaultTimeZone } from "@/utils/timezone";
import { TIMEZONES } from "@/utils/timezone-data";
import { Button, Popover } from "@linagora/twake-mui"; import { Button, Popover } from "@linagora/twake-mui";
import { useI18n } from "twake-i18n";
import moment from "moment"; import moment from "moment";
import { MouseEvent, useMemo, useState } from "react"; import { MouseEvent, useMemo, useState } from "react";
import { browserDefaultTimeZone } from "../../utils/timezone"; import { useI18n } from "twake-i18n";
import { TIMEZONES } from "../../utils/timezone-data";
import { TimezoneAutocomplete } from "../Timezone/TimezoneAutocomplete"; import { TimezoneAutocomplete } from "../Timezone/TimezoneAutocomplete";
interface TimezoneSelectProps { interface TimezoneSelectProps {
@@ -1,24 +1,25 @@
import { DateSelectArg } from "@fullcalendar/core"; import { User } from "@/components/Attendees/PeopleSearch";
import { CalendarApi } from "@fullcalendar/core"; import { formatLocalDateTime } from "@/components/Event/utils/dateTimeFormatters";
import { CalendarEvent } from "../../../features/Events/EventsTypes"; import { refreshCalendars } from "@/components/Event/utils/eventUtils";
import { Calendar } from "../../../features/Calendars/CalendarTypes"; import { updateEventLocal } from "@/features/Calendars/CalendarSlice";
import { getDeltaInMilliseconds } from "../../../utils/dateUtils"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { import {
getCalendarDetailAsync,
getEventAsync, getEventAsync,
putEventAsync, putEventAsync,
updateEventInstanceAsync, updateEventInstanceAsync,
updateEventLocal,
updateSeriesAsync, updateSeriesAsync,
} from "../../../features/Calendars/CalendarSlice"; } from "@/features/Calendars/services";
import { getCalendarDetailAsync } from "../../../features/Calendars/services/getCalendarDetailAsync"; import { getEvent } from "@/features/Events/EventApi";
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import { getEvent } from "../../../features/Events/EventApi"; import { userAttendee } from "@/features/User/models/attendee";
import { refreshCalendars } from "../../Event/utils/eventUtils"; import { createAttendee } from "@/features/User/models/attendee.mapper";
import {
formatDateToYYYYMMDDTHHMMSS,
getDeltaInMilliseconds,
} from "@/utils/dateUtils";
import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
import { updateTempCalendar } from "../utils/calendarUtils"; import { updateTempCalendar } from "../utils/calendarUtils";
import { User } from "../../Attendees/PeopleSearch";
import { formatLocalDateTime } from "../../Event/utils/dateTimeFormatters";
import { userAttendee } from "../../../features/User/models/attendee";
import { createAttendee } from "../../../features/User/models/attendee.mapper";
export interface EventHandlersProps { export interface EventHandlersProps {
setSelectedRange: (range: DateSelectArg | null) => void; setSelectedRange: (range: DateSelectArg | null) => void;
@@ -1,10 +1,10 @@
import React from "react"; import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
import { EventChip } from "@/components/Event/EventChip/EventChip";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { userAttendee } from "@/features/User/models/attendee";
import { CalendarApi, NowIndicatorContentArg } from "@fullcalendar/core"; import { CalendarApi, NowIndicatorContentArg } from "@fullcalendar/core";
import React from "react";
import { createMouseHandlers } from "./mouseHandlers"; import { createMouseHandlers } from "./mouseHandlers";
import { userAttendee } from "../../../features/User/models/attendee";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { EventErrorHandler } from "../../Error/EventErrorHandler";
import { EventChip } from "../../Event/EventChip/EventChip";
export interface ViewHandlersProps { export interface ViewHandlersProps {
calendarRef: React.RefObject<CalendarApi | null>; calendarRef: React.RefObject<CalendarApi | null>;
@@ -1,12 +1,12 @@
import { AppDispatch } from "@/app/store";
import { updateCalColor } from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { darken, getContrastRatio, lighten, Theme } from "@linagora/twake-mui"; import { darken, getContrastRatio, lighten, Theme } from "@linagora/twake-mui";
import { ThunkDispatch } from "@reduxjs/toolkit";
import { updateCalColor } from "../../../features/Calendars/CalendarSlice";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
export function updateDarkColor( export function updateDarkColor(
calendars: Record<string, Calendar>, calendars: Record<string, Calendar>,
theme: Theme, theme: Theme,
dispatch: ThunkDispatch<any, any, any> dispatch: AppDispatch
) { ) {
Object.values(calendars).forEach((cal) => { Object.values(calendars).forEach((cal) => {
if (!cal?.color?.light || typeof cal.color.light !== "string") return; if (!cal?.color?.light || typeof cal.color.light !== "string") return;
@@ -1,14 +1,14 @@
import { CalendarEvent } from "../../../features/Events/EventsTypes"; import { detectDateTimeFormat } from "@/components/Event/utils/dateTimeHelpers";
import { Calendar } from "../../../features/Calendars/CalendarTypes"; import { refreshSingularCalendar } from "@/components/Event/utils/eventUtils";
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { getCalendarDetailAsync } from "../../../features/Calendars/services/getCalendarDetailAsync"; import { getCalendarDetailAsync } from "@/features/Calendars/services";
import { CalendarEvent } from "@/features/Events/EventsTypes";
import { formatDateToYYYYMMDDTHHMMSS } from "@/utils/dateUtils";
import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { SlotLabelContentArg } from "@fullcalendar/core"; import { SlotLabelContentArg } from "@fullcalendar/core";
import moment from "moment-timezone";
import { refreshSingularCalendar } from "../../Event/utils/eventUtils";
import { ThunkDispatch } from "@reduxjs/toolkit"; import { ThunkDispatch } from "@reduxjs/toolkit";
import moment from "moment-timezone";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { detectDateTimeFormat } from "../../Event/utils/dateTimeHelpers";
import { extractEventBaseUuid } from "../../../utils/extractEventBaseUuid";
function convertEventDateTimeToISO( function convertEventDateTimeToISO(
datetime: string, datetime: string,
+2 -2
View File
@@ -18,7 +18,7 @@ A highly reusable dialog component that supports both normal and expanded (fulls
## Basic Usage ## Basic Usage
```tsx ```tsx
import { ResponsiveDialog } from "../../components/Dialog"; import { ResponsiveDialog } from "@/components/Dialog";
import { useState } from "react"; import { useState } from "react";
function MyComponent() { function MyComponent() {
@@ -199,7 +199,7 @@ All `sx` props are **merged** with base styles, not overridden:
Full type inference and validation: Full type inference and validation:
```tsx ```tsx
import { ResponsiveDialog } from "../../components/Dialog"; import { ResponsiveDialog } from "@/components/Dialog";
// All props are type-checked // All props are type-checked
<ResponsiveDialog <ResponsiveDialog
+2 -2
View File
@@ -1,16 +1,16 @@
import { import {
Box,
Dialog, Dialog,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentProps, DialogContentProps,
DialogProps,
DialogTitle, DialogTitle,
DialogTitleProps, DialogTitleProps,
DialogProps,
IconButton, IconButton,
Stack, Stack,
SxProps, SxProps,
Theme, Theme,
Box,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
+3 -3
View File
@@ -1,5 +1,4 @@
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import ReplayIcon from "@mui/icons-material/Replay";
import { import {
Box, Box,
Button, Button,
@@ -8,9 +7,10 @@ import {
Stack, Stack,
Typography, Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import ReplayIcon from "@mui/icons-material/Replay";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { push } from "redux-first-history"; import { push } from "redux-first-history";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
export function Error() { export function Error() {
+4 -4
View File
@@ -1,7 +1,7 @@
import { Snackbar, Alert, Button } from "@linagora/twake-mui"; import { useAppDispatch } from "@/app/hooks";
import { useAppDispatch } from "../../app/hooks"; import { clearError as calendarClearError } from "@/features/Calendars/CalendarSlice";
import { clearError as calendarClearError } from "../../features/Calendars/CalendarSlice"; import { clearError as userClearError } from "@/features/User/userSlice";
import { clearError as userClearError } from "../../features/User/userSlice"; import { Alert, Button, Snackbar } from "@linagora/twake-mui";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
export function ErrorSnackbar({ export function ErrorSnackbar({
+1 -1
View File
@@ -1,7 +1,7 @@
import { Box, Button, TextField } from "@linagora/twake-mui"; import { Box, Button, TextField } from "@linagora/twake-mui";
import { Description as DescriptionIcon } from "@mui/icons-material";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { FieldWithLabel } from "./components/FieldWithLabel"; import { FieldWithLabel } from "./components/FieldWithLabel";
import { Description as DescriptionIcon } from "@mui/icons-material";
export function AddDescButton({ export function AddDescButton({
showDescription, showDescription,
+1 -1
View File
@@ -1,3 +1,4 @@
import { CalendarEvent } from "@/features/Events/EventsTypes";
import { import {
Button, Button,
ButtonGroup, ButtonGroup,
@@ -9,7 +10,6 @@ import {
Radio, Radio,
RadioGroup, RadioGroup,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { CalendarEvent } from "../../features/Events/EventsTypes";
import { useState } from "react"; import { useState } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
@@ -1,6 +1,6 @@
import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
import { Card, Typography } from "@linagora/twake-mui"; import { Card, Typography } from "@linagora/twake-mui";
import { useRef, useEffect } from "react"; import { useEffect, useRef } from "react";
import { EventErrorHandler } from "../../Error/EventErrorHandler";
export function ErrorEventChip({ export function ErrorEventChip({
event, event,
+1 -2
View File
@@ -6,7 +6,7 @@ import {
CardHeader, CardHeader,
Typography, Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import React, { useEffect, useRef, useState } from "react"; import { useRef } from "react";
import { stringAvatar } from "../utils/eventUtils"; import { stringAvatar } from "../utils/eventUtils";
import { ErrorEventChip } from "./ErrorEventChip"; import { ErrorEventChip } from "./ErrorEventChip";
import { import {
@@ -21,7 +21,6 @@ import {
IconDisplayConfig, IconDisplayConfig,
useCompactMode, useCompactMode,
} from "./EventChipUtils"; } from "./EventChipUtils";
import { SimpleEventChip } from "./SimpleEventChip";
const PRIVATE_CLASSIFICATIONS = ["PRIVATE", "CONFIDENTIAL"]; const PRIVATE_CLASSIFICATIONS = ["PRIVATE", "CONFIDENTIAL"];
@@ -1,12 +1,12 @@
import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { userAttendee } from "@/features/User/models/attendee";
import { getContrastRatio } from "@linagora/twake-mui";
import CancelIcon from "@mui/icons-material/Cancel"; import CancelIcon from "@mui/icons-material/Cancel";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import LockOutlineIcon from "@mui/icons-material/LockOutline"; import LockOutlineIcon from "@mui/icons-material/LockOutline";
import { Box, getContrastRatio } from "@linagora/twake-mui";
import moment from "moment"; import moment from "moment";
import React, { useLayoutEffect, useState } from "react"; import React, { useLayoutEffect, useState } from "react";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { userAttendee } from "../../../features/User/models/attendee";
import { EventErrorHandler } from "../../Error/EventErrorHandler";
import { EVENT_DURATION } from "./EventChip"; import { EVENT_DURATION } from "./EventChip";
const COMPACT_WIDTH_THRESHOLD = 100; const COMPACT_WIDTH_THRESHOLD = 100;
@@ -1,4 +1,3 @@
import React from "react";
import { Card, Typography } from "@linagora/twake-mui"; import { Card, Typography } from "@linagora/twake-mui";
export function SimpleEventChip({ title }: { title: string }) { export function SimpleEventChip({ title }: { title: string }) {
+1 -1
View File
@@ -1,5 +1,5 @@
import { CalendarEvent } from "@/features/Events/EventsTypes";
import { MenuItem } from "@linagora/twake-mui"; import { MenuItem } from "@linagora/twake-mui";
import { CalendarEvent } from "../../features/Events/EventsTypes";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
export default function EventDuplication({ export default function EventDuplication({
+21 -26
View File
@@ -1,4 +1,11 @@
import React from "react"; import { Calendar } from "@/features/Calendars/CalendarTypes";
import { RepetitionObject } from "@/features/Events/EventsTypes";
import { userAttendee } from "@/features/User/models/attendee";
import iconCamera from "@/static/images/icon-camera.svg";
import {
addVideoConferenceToDescription,
generateMeetingLink,
} from "@/utils/videoConferenceUtils";
import { import {
Box, Box,
Button, Button,
@@ -6,45 +13,33 @@ import {
FormControl, FormControl,
FormControlLabel, FormControlLabel,
IconButton, IconButton,
InputLabel,
MenuItem, MenuItem,
Select, Select,
SelectChangeEvent, SelectChangeEvent,
TextField, TextField,
ToggleButtonGroup,
ToggleButton, ToggleButton,
ToggleButtonGroup,
Typography, Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { import {
Description as DescriptionIcon,
Public as PublicIcon,
VideocamOutlined as VideocamOutlinedIcon,
ContentCopy as CopyIcon,
Close as DeleteIcon, Close as DeleteIcon,
ContentCopy as CopyIcon,
Public as PublicIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import iconCamera from "../../static/images/icon-camera.svg";
import LockOutlineIcon from "@mui/icons-material/LockOutline"; import LockOutlineIcon from "@mui/icons-material/LockOutline";
import AttendeeSelector from "../Attendees/AttendeeSearch"; import React from "react";
import RepeatEvent from "./EventRepeat";
import { RepetitionObject } from "../../features/Events/EventsTypes";
import { userAttendee } from "../../features/User/models/attendee";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import {
generateMeetingLink,
addVideoConferenceToDescription,
} from "../../utils/videoConferenceUtils";
import { TimezoneAutocomplete } from "../Timezone/TimezoneAutocomplete";
import { CalendarItemList } from "../Calendar/CalendarItemList";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { FieldWithLabel } from "./components/FieldWithLabel"; import AttendeeSelector from "../Attendees/AttendeeSearch";
import { DateTimeFields } from "./components/DateTimeFields"; import { CalendarItemList } from "../Calendar/CalendarItemList";
import { useAllDayToggle } from "./hooks/useAllDayToggle";
import { splitDateTime, combineDateTime } from "./utils/dateTimeHelpers";
import {} from "./utils/dateRules";
import {} from "./utils/dateTimeFormatters";
import { validateEventForm } from "./utils/formValidation";
import { SnackbarAlert } from "../Loading/SnackBarAlert"; import { SnackbarAlert } from "../Loading/SnackBarAlert";
import { TimezoneAutocomplete } from "../Timezone/TimezoneAutocomplete";
import { AddDescButton } from "./AddDescButton"; import { AddDescButton } from "./AddDescButton";
import { DateTimeFields } from "./components/DateTimeFields";
import { FieldWithLabel } from "./components/FieldWithLabel";
import RepeatEvent from "./EventRepeat";
import { useAllDayToggle } from "./hooks/useAllDayToggle";
import { combineDateTime, splitDateTime } from "./utils/dateTimeHelpers";
import { validateEventForm } from "./utils/formValidation";
interface EventFormFieldsProps { interface EventFormFieldsProps {
// Form state // Form state
+8 -8
View File
@@ -1,20 +1,20 @@
import { RepetitionObject } from "@/features/Events/EventsTypes";
import { import {
FormControl,
Select,
SelectChangeEvent,
MenuItem,
Box, Box,
Stack,
Typography,
TextField,
Checkbox, Checkbox,
FormControl,
FormControlLabel, FormControlLabel,
FormGroup, FormGroup,
MenuItem,
Radio, Radio,
RadioGroup, RadioGroup,
Select,
SelectChangeEvent,
Stack,
TextField,
Typography,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { RepetitionObject } from "../../features/Events/EventsTypes";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
export default function RepeatEvent({ export default function RepeatEvent({
+1 -1
View File
@@ -1,5 +1,5 @@
import { Box, Link, Typography } from "@linagora/twake-mui";
import React from "react"; import React from "react";
import { Box, Typography, Link } from "@linagora/twake-mui";
type InfoRowProps = { type InfoRowProps = {
icon: React.ReactNode; icon: React.ReactNode;
@@ -1,25 +1,27 @@
import React, { useMemo } from "react"; import { Box, TextFieldProps, Typography } from "@linagora/twake-mui";
import { Box, Typography } from "@linagora/twake-mui";
import { TextFieldProps } from "@linagora/twake-mui";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { DatePickerFieldProps } from "@mui/x-date-pickers/DatePicker";
import { TimePicker } from "@mui/x-date-pickers/TimePicker";
import { TimePickerFieldProps } from "@mui/x-date-pickers/TimePicker";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import {
DatePicker,
DatePickerFieldProps,
} from "@mui/x-date-pickers/DatePicker";
import { PickerValue } from "@mui/x-date-pickers/internals";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import {
TimePicker,
TimePickerFieldProps,
} from "@mui/x-date-pickers/TimePicker";
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { useI18n } from "twake-i18n";
import { LONG_DATE_FORMAT } from "../utils/dateTimeFormatters";
import "dayjs/locale/fr";
import "dayjs/locale/en"; import "dayjs/locale/en";
import "dayjs/locale/fr";
import "dayjs/locale/ru"; import "dayjs/locale/ru";
import "dayjs/locale/vi"; import "dayjs/locale/vi";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { PickerValue } from "@mui/x-date-pickers/internals"; import React, { useMemo } from "react";
import { useI18n } from "twake-i18n";
import { LONG_DATE_FORMAT } from "../utils/dateTimeFormatters";
import { dtDate, dtTime, toDateTime } from "../utils/dateTimeHelpers"; import { dtDate, dtTime, toDateTime } from "../utils/dateTimeHelpers";
import { ReadOnlyDateField } from "./ReadOnlyPickerField";
import { EditableTimeField } from "./EditableTimeField"; import { EditableTimeField } from "./EditableTimeField";
import { ReadOnlyDateField } from "./ReadOnlyPickerField";
dayjs.extend(customParseFormat); dayjs.extend(customParseFormat);
@@ -1,20 +1,20 @@
import React, { useState, useRef, useEffect, useCallback } from "react";
import { TextField } from "@linagora/twake-mui"; import { TextField } from "@linagora/twake-mui";
import {
useParsedFormat,
usePickerActionsContext,
usePickerContext,
useSplitFieldProps,
} from "@mui/x-date-pickers/hooks";
import { PickerFieldProps } from "@mui/x-date-pickers/models";
import { TimePickerFieldProps } from "@mui/x-date-pickers/TimePicker";
import { import {
PickerFieldAdapter, PickerFieldAdapter,
PickerValidationScope, PickerValidationScope,
useValidation, useValidation,
validateTime, validateTime,
} from "@mui/x-date-pickers/validation"; } from "@mui/x-date-pickers/validation";
import { import { Dayjs } from "dayjs";
useSplitFieldProps, import React, { useCallback, useEffect, useRef, useState } from "react";
useParsedFormat,
usePickerContext,
usePickerActionsContext,
} from "@mui/x-date-pickers/hooks";
import { PickerFieldProps } from "@mui/x-date-pickers/models";
import { TimePickerFieldProps } from "@mui/x-date-pickers/TimePicker";
import dayjs, { Dayjs } from "dayjs";
import { parseTimeInput } from "../utils/dateTimeHelpers"; import { parseTimeInput } from "../utils/dateTimeHelpers";
type FieldType = "date" | "time" | "date-time"; type FieldType = "date" | "time" | "date-time";
@@ -1,5 +1,5 @@
import { Box, SxProps, Theme, Typography } from "@linagora/twake-mui";
import React from "react"; import React from "react";
import { Box, Typography, SxProps, Theme } from "@linagora/twake-mui";
/** /**
* Helper component for field with label * Helper component for field with label
@@ -1,18 +1,17 @@
import React from "react";
import { TextField } from "@linagora/twake-mui"; import { TextField } from "@linagora/twake-mui";
import { DatePickerFieldProps } from "@mui/x-date-pickers/DatePicker";
import {
useParsedFormat,
usePickerContext,
useSplitFieldProps,
} from "@mui/x-date-pickers/hooks";
import { PickerFieldProps } from "@mui/x-date-pickers/models";
import { import {
PickerFieldAdapter, PickerFieldAdapter,
PickerValidationScope, PickerValidationScope,
useValidation, useValidation,
validateDate, validateDate,
} from "@mui/x-date-pickers/validation"; } from "@mui/x-date-pickers/validation";
import {
useSplitFieldProps,
useParsedFormat,
usePickerContext,
} from "@mui/x-date-pickers/hooks";
import { PickerFieldProps } from "@mui/x-date-pickers/models";
import { DatePickerFieldProps } from "@mui/x-date-pickers/DatePicker";
type FieldType = "date" | "time" | "date-time"; type FieldType = "date" | "time" | "date-time";
@@ -1,18 +1,18 @@
import { ThunkDispatch } from "@reduxjs/toolkit"; import { AppDispatch } from "@/app/store";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import { import {
updateEventInstanceAsync,
putEventAsync,
deleteEventInstanceAsync,
deleteEventAsync, deleteEventAsync,
} from "../../../features/Calendars/CalendarSlice"; deleteEventInstanceAsync,
import { Calendar } from "../../../features/Calendars/CalendarTypes"; putEventAsync,
import { updateSeriesPartstat } from "../../../features/Events/EventApi"; updateEventInstanceAsync,
import { CalendarEvent } from "../../../features/Events/EventsTypes"; } from "@/features/Calendars/services";
import { PartStat } from "../../../features/User/models/attendee"; import { updateSeriesPartstat } from "@/features/Events/EventApi";
import { createAttendee } from "../../../features/User/models/attendee.mapper"; import { CalendarEvent } from "@/features/Events/EventsTypes";
import { userData } from "../../../features/User/userDataTypes"; import { PartStat } from "@/features/User/models/attendee";
import { buildFamilyName } from "../../../utils/buildFamilyName"; import { createAttendee } from "@/features/User/models/attendee.mapper";
import { getCalendarRange } from "../../../utils/dateUtils"; import { userData } from "@/features/User/userDataTypes";
import { buildFamilyName } from "@/utils/buildFamilyName";
import { getCalendarRange } from "@/utils/dateUtils";
import { refreshCalendars } from "../utils/eventUtils"; import { refreshCalendars } from "../utils/eventUtils";
function updateEventAttendees( function updateEventAttendees(
@@ -70,7 +70,7 @@ function updateEventAttendees(
} }
async function handleSoloRSVP( async function handleSoloRSVP(
dispatch: ThunkDispatch<any, any, any>, dispatch: AppDispatch,
calendar: Calendar, calendar: Calendar,
event: CalendarEvent event: CalendarEvent
) { ) {
@@ -78,7 +78,7 @@ async function handleSoloRSVP(
} }
async function handleAllRSVP( async function handleAllRSVP(
dispatch: ThunkDispatch<any, any, any>, dispatch: AppDispatch,
event: CalendarEvent, event: CalendarEvent,
userEmail: string, userEmail: string,
rsvp: PartStat, rsvp: PartStat,
@@ -90,7 +90,7 @@ async function handleAllRSVP(
} }
async function handleDefaultRSVP( async function handleDefaultRSVP(
dispatch: ThunkDispatch<any, any, any>, dispatch: AppDispatch,
calendar: Calendar, calendar: Calendar,
newEvent: CalendarEvent newEvent: CalendarEvent
) { ) {
@@ -98,7 +98,7 @@ async function handleDefaultRSVP(
} }
export async function handleRSVP( export async function handleRSVP(
dispatch: ThunkDispatch<any, any, any>, dispatch: AppDispatch,
calendar: Calendar, calendar: Calendar,
user: userData | undefined, user: userData | undefined,
event: CalendarEvent, event: CalendarEvent,
@@ -1,6 +1,5 @@
import React from "react"; import React from "react";
import { combineDateTime } from "../utils/dateTimeHelpers"; import { combineDateTime } from "../utils/dateTimeHelpers";
import { getRoundedCurrentTime } from "../utils/dateTimeFormatters";
/** /**
* Parameters for all-day toggle hook * Parameters for all-day toggle hook
@@ -1,6 +1,6 @@
import moment from "moment-timezone";
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat"; import customParseFormat from "dayjs/plugin/customParseFormat";
import moment from "moment-timezone";
dayjs.extend(customParseFormat); dayjs.extend(customParseFormat);
+13 -12
View File
@@ -1,16 +1,17 @@
import { AppDispatch } from "@/app/store";
import { emptyEventsCal } from "@/features/Calendars/CalendarSlice";
import { Calendar } from "@/features/Calendars/CalendarTypes";
import {
getCalendarDetailAsync,
getCalendarsListAsync,
refreshCalendarWithSyncToken,
} from "@/features/Calendars/services";
import { userAttendee } from "@/features/User/models/attendee";
import { getInitials, stringToGradient } from "@/utils/avatarUtils";
import { formatDateToYYYYMMDDTHHMMSS } from "@/utils/dateUtils";
import { Avatar, Badge, Box, Typography } from "@linagora/twake-mui";
import CancelIcon from "@mui/icons-material/Cancel"; import CancelIcon from "@mui/icons-material/Cancel";
import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import { Avatar, Badge, Box, Typography } from "@linagora/twake-mui";
import { stringToGradient, getInitials } from "../../../utils/avatarUtils";
import { ThunkDispatch } from "@reduxjs/toolkit";
import { emptyEventsCal } from "../../../features/Calendars/CalendarSlice";
import { getCalendarsListAsync } from "../../../features/Calendars/services/getCalendarsListAsync";
import { getCalendarDetailAsync } from "../../../features/Calendars/services/getCalendarDetailAsync";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { userAttendee } from "../../../features/User/models/attendee";
import { refreshCalendarWithSyncToken } from "../../../features/Calendars/services/refreshCalendar";
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
import { AppDispatch } from "../../../app/store";
export function renderAttendeeBadge( export function renderAttendeeBadge(
a: userAttendee, a: userAttendee,
@@ -139,7 +140,7 @@ export async function refreshCalendars(
} }
export async function refreshSingularCalendar( export async function refreshSingularCalendar(
dispatch: ThunkDispatch<any, any, any>, dispatch: AppDispatch,
calendar: Calendar, calendar: Calendar,
calendarRange: { start: Date; end: Date }, calendarRange: { start: Date; end: Date },
calType?: "temp" calType?: "temp"
+1 -1
View File
@@ -1,5 +1,5 @@
import { Alert, Snackbar } from "@linagora/twake-mui";
import type { AlertColor } from "@linagora/twake-mui"; import type { AlertColor } from "@linagora/twake-mui";
import { Alert, Snackbar } from "@linagora/twake-mui";
export function SnackbarAlert({ export function SnackbarAlert({
open, open,
+9 -9
View File
@@ -1,3 +1,9 @@
import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { searchEventsAsync } from "@/features/Search/SearchSlice";
import { setView } from "@/features/Settings/SettingsSlice";
import { userAttendee } from "@/features/User/models/attendee";
import { createAttendee } from "@/features/User/models/attendee.mapper";
import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { import {
Box, Box,
Button, Button,
@@ -14,22 +20,16 @@ import {
Stack, Stack,
TextField, TextField,
Typography, Typography,
type AutocompleteRenderInputParams,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { type AutocompleteRenderInputParams } from "@linagora/twake-mui";
import { useRef, useState, useEffect } from "react";
import HighlightOffIcon from "@mui/icons-material/HighlightOff"; import HighlightOffIcon from "@mui/icons-material/HighlightOff";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import TuneIcon from "@mui/icons-material/Tune"; import TuneIcon from "@mui/icons-material/Tune";
import { useEffect, useRef, useState } from "react";
import { useI18n } from "twake-i18n"; import { useI18n } from "twake-i18n";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { searchEventsAsync } from "../../features/Search/SearchSlice";
import { setView } from "../../features/Settings/SettingsSlice";
import { userAttendee } from "../../features/User/models/attendee";
import UserSearch from "../Attendees/AttendeeSearch"; import UserSearch from "../Attendees/AttendeeSearch";
import { CalendarItemList } from "../Calendar/CalendarItemList";
import { PeopleSearch, User } from "../Attendees/PeopleSearch"; import { PeopleSearch, User } from "../Attendees/PeopleSearch";
import { createAttendee } from "../../features/User/models/attendee.mapper"; import { CalendarItemList } from "../Calendar/CalendarItemList";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
export default function SearchBar() { export default function SearchBar() {
const { t } = useI18n(); const { t } = useI18n();
+23 -23
View File
@@ -1,33 +1,30 @@
import React, { useEffect, useState } from "react"; import { useAppDispatch, useAppSelector } from "@/app/hooks";
import logo from "../../static/header-logo.svg"; import { setView } from "@/features/Settings/SettingsSlice";
import AppsIcon from "@mui/icons-material/Apps"; import { Logout } from "@/features/User/oidcAuth";
import RefreshIcon from "@mui/icons-material/Refresh"; import logo from "@/static/header-logo.svg";
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; import { getInitials, stringToGradient } from "@/utils/avatarUtils";
import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import { getUserDisplayName } from "@/utils/userUtils";
import SettingsIcon from "@mui/icons-material/Settings"; import { CalendarApi } from "@fullcalendar/core";
import LogoutIcon from "@mui/icons-material/Logout";
import "./Menubar.styl";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { stringToGradient, getInitials } from "../../utils/avatarUtils";
import { import {
Avatar, Avatar,
Box,
Button,
ButtonGroup,
Divider,
FormControl,
IconButton, IconButton,
Popover,
Menu, Menu,
MenuItem, MenuItem,
ButtonGroup, Popover,
Button,
Select, Select,
FormControl,
Typography, Typography,
Box,
Divider,
} from "@linagora/twake-mui"; } from "@linagora/twake-mui";
import { push } from "redux-first-history"; import AppsIcon from "@mui/icons-material/Apps";
import { CalendarApi } from "@fullcalendar/core"; import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
import { useI18n } from "twake-i18n"; import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import { setView } from "../../features/Settings/SettingsSlice"; import LogoutIcon from "@mui/icons-material/Logout";
import { getUserDisplayName } from "../../utils/userUtils"; import RefreshIcon from "@mui/icons-material/Refresh";
import SettingsIcon from "@mui/icons-material/Settings";
import { format } from "date-fns"; import { format } from "date-fns";
import { import {
enGB, enGB,
@@ -35,8 +32,11 @@ import {
ru as ruLocale, ru as ruLocale,
vi as viLocale, vi as viLocale,
} from "date-fns/locale"; } from "date-fns/locale";
import React, { useEffect, useState } from "react";
import { push } from "redux-first-history";
import { useI18n } from "twake-i18n";
import SearchBar from "./EventSearchBar"; import SearchBar from "./EventSearchBar";
import { Logout } from "../../features/User/oidcAuth"; import "./Menubar.styl";
const dateLocales = { en: enGB, fr: frLocale, ru: ruLocale, vi: viLocale }; const dateLocales = { en: enGB, fr: frLocale, ru: ruLocale, vi: viLocale };
export type AppIconProps = { export type AppIconProps = {
+1 -1
View File
@@ -1,4 +1,4 @@
import { api } from "../../utils/apiUtils"; import { api } from "@/utils/apiUtils";
export async function getCalendars( export async function getCalendars(
userId: string, userId: string,
+22 -488
View File
@@ -1,40 +1,27 @@
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { extractEventBaseUuid } from "@/utils/extractEventBaseUuid";
import { Calendar } from "./CalendarTypes"; import { browserDefaultTimeZone } from "@/utils/timezone";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { CalendarEvent } from "../Events/EventsTypes"; import { CalendarEvent } from "../Events/EventsTypes";
import { Calendar } from "./CalendarTypes";
import { import {
addSharedCalendar, addSharedCalendarAsync,
getCalendar, createCalendarAsync,
getCalendars, deleteEventAsync,
postCalendar, deleteEventInstanceAsync,
proppatchCalendar, getCalendarDetailAsync,
removeCalendar, getCalendarsListAsync,
updateAclCalendar, getEventAsync,
} from "./CalendarApi"; getTempCalendarsListAsync,
import { getUserDetails } from "../User/userAPI"; importEventFromFileAsync,
import { parseCalendarEvent } from "../Events/eventUtils"; moveEventAsync,
import { patchACLCalendarAsync,
deleteEvent, patchCalendarAsync,
deleteEventInstance, putEventAsync,
getEvent, refreshCalendarWithSyncToken,
importEventFromFile, removeCalendarAsync,
moveEvent, updateEventInstanceAsync,
putEvent, updateSeriesAsync,
putEventWithOverrides, } from "./services";
updateSeries,
} from "../Events/EventApi";
import {
computeWeekRange,
formatDateToYYYYMMDDTHHMMSS,
} from "../../utils/dateUtils";
import { User } from "../../components/Attendees/PeopleSearch";
import { getCalendarVisibility } from "../../components/Calendar/utils/calendarUtils";
import { importFile } from "../../utils/apiUtils";
import { formatReduxError } from "../../utils/errorUtils";
import { browserDefaultTimeZone } from "../../utils/timezone";
import { getCalendarDetailAsync } from "./services/getCalendarDetailAsync";
import { refreshCalendarWithSyncToken } from "./services/refreshCalendar";
import { getCalendarsListAsync } from "./services/getCalendarsListAsync";
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
// Define error type for rejected actions // Define error type for rejected actions
export interface RejectedError { export interface RejectedError {
@@ -42,459 +29,6 @@ export interface RejectedError {
status?: number; status?: number;
} }
export const getTempCalendarsListAsync = createAsyncThunk<
Record<string, Calendar>,
User,
{ rejectValue: RejectedError }
>("calendars/getTempCalendars", async (tempUser, { rejectWithValue }) => {
try {
const importedCalendars: Record<string, Calendar> = {};
const calendars = (await getCalendars(
tempUser.openpaasId ?? "",
"sharedPublic=true&"
)) as Record<string, any>;
const rawCalendars = calendars._embedded?.["dav:calendar"];
if (!rawCalendars || rawCalendars.length === 0) {
const userName = tempUser.displayName || tempUser.email || "User";
// Format: TRANSLATION:key|param1=value1
const encodedName = encodeURIComponent(userName);
throw new Error(
`TRANSLATION:calendar.userDoesNotHavePublicCalendars|name=${encodedName}`
);
}
for (const cal of rawCalendars) {
const name = cal["dav:name"];
const description = cal["caldav:description"];
const delegated = cal["calendarserver:delegatedsource"] ? true : false;
const source = cal["calendarserver:source"]
? cal["calendarserver:source"]._links.self.href
: cal._links.self.href;
const link = cal._links.self.href;
const id = source.replace("/calendars/", "").replace(".json", "");
const visibility = getCalendarVisibility(cal["acl"]);
const ownerData: any = await getUserDetails(id.split("/")[0]);
importedCalendars[id] = {
id,
name,
link,
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${ownerData.lastname}`,
ownerEmails: ownerData.emails,
description,
delegated,
color: {
light: tempUser.color?.light ?? "#a8a8a8ff",
dark: tempUser.color?.dark ?? "#a8a8a8ff",
},
visibility,
events: {},
};
}
return importedCalendars;
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
});
export const putEventAsync = createAsyncThunk<
{ calId: string; events: CalendarEvent[]; calType?: "temp" },
{ cal: Calendar; newEvent: CalendarEvent; calType?: "temp" },
{ rejectValue: RejectedError }
>(
"calendars/putEvent",
async ({ cal, newEvent, calType }, { rejectWithValue }) => {
try {
await putEvent(
newEvent,
cal.ownerEmails ? cal.ownerEmails[0] : undefined
);
const eventDate = new Date(newEvent.start);
const { start: weekStart, end: weekEnd } = computeWeekRange(eventDate);
const calEvents = (await getCalendar(cal.id, {
start: formatDateToYYYYMMDDTHHMMSS(weekStart),
end: formatDateToYYYYMMDDTHHMMSS(weekEnd),
})) as Record<string, any>;
const events: CalendarEvent[] = calEvents._embedded["dav:item"].flatMap(
(eventdata: any) => {
const vevents = eventdata.data[2] as any[][];
const eventURL = eventdata._links.self.href;
const valarm = eventdata.data[2][0][2][0];
return vevents.map((vevent: any[]) => {
return parseCalendarEvent(
vevent[1],
cal.color ?? {},
cal.id,
eventURL,
valarm
);
});
}
);
return {
calId: cal.id,
events,
calType,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const getEventAsync = createAsyncThunk<
{ calId: string; event: CalendarEvent },
CalendarEvent,
{ rejectValue: RejectedError }
>("calendars/getEvent", async (event, { rejectWithValue }) => {
try {
const response: CalendarEvent = await getEvent(event);
return {
calId: event.calId,
event: response,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
});
export const patchCalendarAsync = createAsyncThunk<
{
calId: string;
calLink: string;
patch: { name: string; desc: string; color: Record<string, string> };
},
{
calId: string;
calLink: string;
patch: { name: string; desc: string; color: Record<string, string> };
},
{ rejectValue: RejectedError }
>(
"calendars/patchCalendar",
async ({ calId, calLink, patch }, { rejectWithValue }) => {
try {
await proppatchCalendar(calLink, patch);
return {
calId,
calLink,
patch,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const removeCalendarAsync = createAsyncThunk<
{
calId: string;
},
{
calId: string;
calLink: string;
},
{ rejectValue: RejectedError }
>(
"calendars/removeCalendar",
async ({ calId, calLink }, { rejectWithValue }) => {
try {
await removeCalendar(calLink);
return {
calId,
calLink,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const moveEventAsync = createAsyncThunk<
{ calId: string; events: CalendarEvent[] },
{ cal: Calendar; newEvent: CalendarEvent; newURL: string },
{ rejectValue: RejectedError }
>(
"calendars/moveEvent",
async ({ cal, newEvent, newURL }, { rejectWithValue }) => {
try {
await moveEvent(newEvent, newURL);
const eventDate = new Date(newEvent.start);
const { start: weekStart, end: weekEnd } = computeWeekRange(eventDate);
const calEvents = (await getCalendar(cal.id, {
start: formatDateToYYYYMMDDTHHMMSS(weekStart),
end: formatDateToYYYYMMDDTHHMMSS(weekEnd),
})) as Record<string, any>;
const events: CalendarEvent[] = calEvents._embedded["dav:item"].flatMap(
(eventdata: any) => {
const vevents = eventdata.data[2] as any[][];
const eventURL = eventdata._links.self.href;
return vevents.map((vevent: any[]) => {
return parseCalendarEvent(
vevent[1],
cal.color ?? {},
cal.id,
eventURL
);
});
}
);
return {
calId: cal.id,
events,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const patchACLCalendarAsync = createAsyncThunk<
{
calId: string;
calLink: string;
request: string;
},
{
calId: string;
calLink: string;
request: string;
},
{ rejectValue: RejectedError }
>(
"calendars/requestACLCalendar",
async ({ calId, calLink, request }, { rejectWithValue }) => {
try {
const response = await updateAclCalendar(calLink, request);
return {
calId,
calLink,
request,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const deleteEventAsync = createAsyncThunk<
{ calId: string; eventId: string },
{ calId: string; eventId: string; eventURL: string },
{ rejectValue: RejectedError }
>(
"calendars/delEvent",
async ({ calId, eventId, eventURL }, { rejectWithValue }) => {
try {
await deleteEvent(eventURL);
return { calId, eventId };
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const deleteEventInstanceAsync = createAsyncThunk<
{ calId: string; eventId: string },
{ cal: Calendar; event: CalendarEvent },
{ rejectValue: RejectedError }
>("calendars/delEventInstance", async ({ cal, event }, { rejectWithValue }) => {
try {
await deleteEventInstance(event, cal.ownerEmails?.[0]);
return { calId: cal.id, eventId: event.uid };
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
});
export const updateEventInstanceAsync = createAsyncThunk<
{ calId: string; event: CalendarEvent },
{ cal: Calendar; event: CalendarEvent },
{ rejectValue: RejectedError }
>(
"calendars/updateEventInstance",
async ({ cal, event }, { rejectWithValue }) => {
try {
await putEventWithOverrides(event, cal.ownerEmails?.[0]);
return { calId: cal.id, event };
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const updateSeriesAsync = createAsyncThunk<
void,
{ cal: Calendar; event: CalendarEvent; removeOverrides?: boolean },
{ rejectValue: RejectedError }
>(
"calendars/updateSeries",
async ({ cal, event, removeOverrides = true }, { rejectWithValue }) => {
try {
await updateSeries(event, cal.ownerEmails?.[0], removeOverrides);
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const createCalendarAsync = createAsyncThunk<
{
userId: string;
calId: string;
color: Record<string, string>;
name: string;
desc: string;
owner: string;
ownerEmails: string[];
},
{
userId: string;
calId: string;
color: Record<string, string>;
name: string;
desc: string;
},
{ rejectValue: RejectedError }
>(
"calendars/createCalendar",
async ({ userId, calId, color, name, desc }, { rejectWithValue }) => {
try {
await postCalendar(userId, calId, color, name, desc);
const ownerData: any = await getUserDetails(userId.split("/")[0]);
return {
userId,
calId,
color,
name,
desc,
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
ownerData.lastname
}`,
ownerEmails: ownerData.emails,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const addSharedCalendarAsync = createAsyncThunk<
{
calId: string;
color: Record<string, string>;
link: string;
name: string;
desc: string;
owner: string;
ownerEmails: string[];
},
{ userId: string; calId: string; cal: Record<string, any> },
{ rejectValue: RejectedError }
>(
"calendars/addSharedCalendar",
async ({ userId, calId, cal }, { rejectWithValue }) => {
try {
await addSharedCalendar(userId, calId, cal);
const ownerData: any = await getUserDetails(
cal.cal._links.self.href
.replace("/calendars/", "")
.replace(".json", "")
.split("/")[0]
);
return {
calId: cal.cal._links.self.href
.replace("/calendars/", "")
.replace(".json", ""),
color: cal.color,
link: `/calendars/${userId}/${calId}.json`,
desc: cal.cal["caldav:description"],
name:
ownerData.id !== userId && cal.cal["dav:name"] === "#default"
? `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
ownerData.lastname
}` + "'s calendar"
: cal.cal["dav:name"],
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
ownerData.lastname
}`,
ownerEmails: ownerData.emails,
};
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
}
);
export const importEventFromFileAsync = createAsyncThunk<
void,
{
calLink: string;
file: File;
},
{ rejectValue: RejectedError }
>("calendars/importEvent", async ({ calLink, file }, { rejectWithValue }) => {
try {
const id = ((await importFile(file)) as Record<string, string>)._id;
const response = await importEventFromFile(id, calLink);
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
});
const CalendarSlice = createSlice({ const CalendarSlice = createSlice({
name: "calendars", name: "calendars",
initialState: { initialState: {
@@ -1,4 +1,4 @@
import { api } from "../../../utils/apiUtils"; import { api } from "@/utils/apiUtils";
import { Calendar } from "../CalendarTypes"; import { Calendar } from "../CalendarTypes";
import { DavSyncResponse } from "./types"; import { DavSyncResponse } from "./types";

Some files were not shown because too many files have changed in this diff Show More