405 back reload token with synctokens (#436)
* [#405] added syncToken in calendar params and fetch with sync token * [#405] changed reload to work with sync-token * [#405] fixup promise handling, added calendar adding and removing hanlding with refresh * [#405] fixed event expansion calls * [#405 & refactor] added helperfunction to get base event uid + refactored synctoken updates management * [#405] added pMap lib to process event expansion * [#405] added flag for no synctoken / new synctoken
This commit is contained in:
@@ -10,7 +10,7 @@ import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import EventPopover from "../../features/Events/EventModal";
|
||||
import { CalendarEvent } from "../../features/Events/EventsTypes";
|
||||
import CalendarSelection from "./CalendarSelection";
|
||||
import { getCalendarDetailAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { getCalendarDetailAsync } from "../../features/Calendars/services/getCalendarDetailAsync";
|
||||
import ImportAlert from "../../features/Events/ImportAlert";
|
||||
import {
|
||||
formatDateToYYYYMMDDTHHMMSS,
|
||||
@@ -44,6 +44,7 @@ import viLocale from "@fullcalendar/core/locales/vi";
|
||||
import SearchResultsPage from "../../features/Search/SearchResultsPage";
|
||||
import { setTimeZone } from "../../features/Settings/SettingsSlice";
|
||||
import { browserDefaultTimeZone } from "../../utils/timezone";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
const localeMap: Record<string, any> = {
|
||||
fr: frLocale,
|
||||
@@ -152,7 +153,7 @@ export default function CalendarApp({
|
||||
setSelectedCalendars(valid);
|
||||
} else {
|
||||
const personalCalendarIds = calendarIds.filter(
|
||||
(id) => id.split("/")[0] === userId
|
||||
(id) => extractEventBaseUuid(id) === userId
|
||||
);
|
||||
setSelectedCalendars(personalCalendarIds);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { refreshCalendars } from "../Event/utils/eventUtils";
|
||||
import { ErrorSnackbar } from "../Error/ErrorSnackbar";
|
||||
|
||||
import SettingsPage from "../../features/Settings/SettingsPage";
|
||||
import SearchResultsPage from "../../features/Search/SearchResultsPage";
|
||||
|
||||
export default function CalendarLayout() {
|
||||
const calendarRef = useRef<any>(null);
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ImportTab } from "./ImportTab";
|
||||
import { SettingsTab } from "./SettingsTab";
|
||||
import { defaultColors } from "./utils/calendarColorsUtils";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
function CalendarPopover({
|
||||
open,
|
||||
@@ -32,7 +33,9 @@ function CalendarPopover({
|
||||
const userId =
|
||||
useAppSelector((state) => state.user.userData?.openpaasId) ?? "";
|
||||
const calendars = useAppSelector((state) => state.calendars.list);
|
||||
const isOwn = calendar ? calendar?.id.split("/")[0] === userId : true;
|
||||
const isOwn = calendar?.id
|
||||
? extractEventBaseUuid(calendar.id) === userId
|
||||
: true;
|
||||
|
||||
// existing calendar params
|
||||
const [name, setName] = useState("");
|
||||
|
||||
@@ -22,6 +22,7 @@ import { removeCalendarAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
|
||||
import { trimLongTextWithoutSpace } from "../../utils/textUtils";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
function CalendarAccordion({
|
||||
title,
|
||||
@@ -112,13 +113,13 @@ export default function CalendarSelection({
|
||||
const calendars = useAppSelector((state) => state.calendars.list);
|
||||
|
||||
const personalCalendars = Object.keys(calendars || {}).filter(
|
||||
(id) => id.split("/")[0] === userId
|
||||
(id) => extractEventBaseUuid(id) === userId
|
||||
);
|
||||
const delegatedCalendars = Object.keys(calendars || {}).filter(
|
||||
(id) => id.split("/")[0] !== userId && calendars[id]?.delegated
|
||||
(id) => extractEventBaseUuid(id) !== userId && calendars[id]?.delegated
|
||||
);
|
||||
const sharedCalendars = Object.keys(calendars || {}).filter(
|
||||
(id) => id.split("/")[0] !== userId && !calendars?.[id]?.delegated
|
||||
(id) => extractEventBaseUuid(id) !== userId && !calendars?.[id]?.delegated
|
||||
);
|
||||
|
||||
const handleCalendarToggle = (name: string) => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useAppSelector } from "../../app/hooks";
|
||||
import { CalendarItemList } from "./CalendarItemList";
|
||||
import { SettingsTab } from "./SettingsTab";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
export function ImportTab({
|
||||
userId,
|
||||
@@ -44,7 +45,7 @@ export function ImportTab({
|
||||
const [importUrl, setImportUrl] = useState("");
|
||||
const calendars = useAppSelector((state) => state.calendars.list);
|
||||
const personalCalendars = Object.values(calendars).filter(
|
||||
(cal) => cal.id.split("/")[0] === userId
|
||||
(cal) => extractEventBaseUuid(cal.id) === userId
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
getCalendarRange,
|
||||
} from "../../utils/dateUtils";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { getCalendarDetailAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { getCalendarDetailAsync } from "../../features/Calendars/services/getCalendarDetailAsync";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { setView } from "../../features/Settings/SettingsSlice";
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useAppSelector } from "../../app/hooks";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import { AddDescButton } from "../Event/AddDescButton";
|
||||
import { ColorPicker } from "./CalendarColorPicker";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
export function SettingsTab({
|
||||
name,
|
||||
@@ -41,7 +42,7 @@ export function SettingsTab({
|
||||
const [toggleDesc, setToggleDesc] = useState(Boolean(description));
|
||||
const userId =
|
||||
useAppSelector((state) => state.user.userData?.openpaasId) ?? "";
|
||||
const isOwn = calendar ? calendar.id.split("/")[0] === userId : true;
|
||||
const isOwn = calendar ? extractEventBaseUuid(calendar.id) === userId : true;
|
||||
|
||||
useEffect(() => {
|
||||
if (description) setToggleDesc(true);
|
||||
|
||||
@@ -4,13 +4,13 @@ import { CalendarEvent } from "../../../features/Events/EventsTypes";
|
||||
import { Calendar } from "../../../features/Calendars/CalendarTypes";
|
||||
import { getDeltaInMilliseconds } from "../../../utils/dateUtils";
|
||||
import {
|
||||
getCalendarDetailAsync,
|
||||
getEventAsync,
|
||||
putEventAsync,
|
||||
updateEventInstanceAsync,
|
||||
updateEventLocal,
|
||||
updateSeriesAsync,
|
||||
} from "../../../features/Calendars/CalendarSlice";
|
||||
import { getCalendarDetailAsync } from "../../../features/Calendars/services/getCalendarDetailAsync";
|
||||
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
|
||||
import { getEvent } from "../../../features/Events/EventApi";
|
||||
import { refreshCalendars } from "../../Event/utils/eventUtils";
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { CalendarEvent } from "../../../features/Events/EventsTypes";
|
||||
import { Calendar } from "../../../features/Calendars/CalendarTypes";
|
||||
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
|
||||
import { getCalendarDetailAsync } from "../../../features/Calendars/CalendarSlice";
|
||||
import { getCalendarDetailAsync } from "../../../features/Calendars/services/getCalendarDetailAsync";
|
||||
import { SlotLabelContentArg } from "@fullcalendar/core";
|
||||
import moment from "moment-timezone";
|
||||
import { refreshSingularCalendar } from "../../Event/utils/eventUtils";
|
||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { detectDateTimeFormat } from "../../Event/utils/dateTimeHelpers";
|
||||
import { extractEventBaseUuid } from "../../../utils/extractEventBaseUuid";
|
||||
|
||||
function convertEventDateTimeToISO(
|
||||
datetime: string,
|
||||
@@ -102,7 +103,7 @@ export const eventToFullCalendarFormat = (
|
||||
.map((e) => {
|
||||
const eventTimezone = e.timezone || "Etc/UTC";
|
||||
const isAllDay = e.allday ?? false;
|
||||
const isPersonnalEvent = e.calId.split("/")[0] === userId;
|
||||
const isPersonnalEvent = extractEventBaseUuid(e.calId) === userId;
|
||||
|
||||
const convertedEvent: any = {
|
||||
...e,
|
||||
|
||||
@@ -3,14 +3,14 @@ import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import { Avatar, Badge, Box, Typography } from "@linagora/twake-mui";
|
||||
import { stringToGradient } from "../../../utils/avatarUtils";
|
||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||
import {
|
||||
emptyEventsCal,
|
||||
getCalendarDetailAsync,
|
||||
getCalendarsListAsync,
|
||||
} from "../../../features/Calendars/CalendarSlice";
|
||||
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(
|
||||
a: userAttendee,
|
||||
@@ -108,55 +108,34 @@ export function stringAvatar(name: string) {
|
||||
}
|
||||
|
||||
export async function refreshCalendars(
|
||||
dispatch: ThunkDispatch<any, any, any>,
|
||||
dispatch: AppDispatch,
|
||||
calendars: Calendar[],
|
||||
calendarRange: { start: Date; end: Date },
|
||||
calendarRange: {
|
||||
start: Date;
|
||||
end: Date;
|
||||
},
|
||||
calType?: "temp"
|
||||
) {
|
||||
const isTestEnv = process.env.NODE_ENV === "test";
|
||||
if (process.env.NODE_ENV === "test") return;
|
||||
|
||||
if (!calType && !isTestEnv) {
|
||||
await dispatch(getCalendarsListAsync());
|
||||
}
|
||||
calType && dispatch(emptyEventsCal({ calType }));
|
||||
!calType && (await dispatch(getCalendarsListAsync()));
|
||||
|
||||
if (isTestEnv) {
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await Promise.all(
|
||||
calendars.map(
|
||||
async (cal) =>
|
||||
await dispatch(
|
||||
getCalendarDetailAsync({
|
||||
calId: cal.id,
|
||||
match: {
|
||||
start: formatDateToYYYYMMDDTHHMMSS(calendarRange.start),
|
||||
end: formatDateToYYYYMMDDTHHMMSS(calendarRange.end),
|
||||
},
|
||||
calType,
|
||||
})
|
||||
)
|
||||
const results = await Promise.allSettled(
|
||||
calendars.map((calendar) =>
|
||||
dispatch(
|
||||
refreshCalendarWithSyncToken({ calendar, calType, calendarRange })
|
||||
).unwrap()
|
||||
)
|
||||
);
|
||||
|
||||
// Check if any result is rejected and throw error
|
||||
for (const result of results) {
|
||||
if (result && typeof (result as any).unwrap === "function") {
|
||||
try {
|
||||
await (result as any).unwrap();
|
||||
} catch (unwrapError: any) {
|
||||
throw unwrapError;
|
||||
}
|
||||
} else if (result.type && (result.type as string).endsWith("/rejected")) {
|
||||
const rejectedResult = result as any;
|
||||
throw new Error(
|
||||
rejectedResult.error?.message ||
|
||||
rejectedResult.payload?.message ||
|
||||
"Failed to refresh calendar"
|
||||
results.forEach((result, index) => {
|
||||
if (result.status === "rejected") {
|
||||
console.error(
|
||||
`Failed to refresh calendar ${calendars[index].id}:`,
|
||||
result.reason
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function refreshSingularCalendar(
|
||||
|
||||
@@ -29,6 +29,7 @@ import UserSearch from "../Attendees/AttendeeSearch";
|
||||
import { CalendarItemList } from "../Calendar/CalendarItemList";
|
||||
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
||||
import { createAttendee } from "../../features/User/models/attendee.mapper";
|
||||
import { extractEventBaseUuid } from "../../utils/extractEventBaseUuid";
|
||||
|
||||
export default function SearchBar() {
|
||||
const { t } = useI18n();
|
||||
@@ -38,10 +39,10 @@ export default function SearchBar() {
|
||||
);
|
||||
const userId = useAppSelector((state) => state.user.userData?.openpaasId);
|
||||
const personnalCalendars = userId
|
||||
? calendars.filter((c) => c.id.split("/")[0] === userId)
|
||||
? calendars.filter((c) => extractEventBaseUuid(c.id) === userId)
|
||||
: [];
|
||||
const sharedCalendars = userId
|
||||
? calendars.filter((c) => c.id.split("/")[0] !== userId)
|
||||
? calendars.filter((c) => extractEventBaseUuid(c.id) !== userId)
|
||||
: calendars;
|
||||
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
Reference in New Issue
Block a user