Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { api } from "@/utils/apiUtils";
|
||||
import { CalendarInput, CalendarList } from "./types/CalendarData";
|
||||
|
||||
export async function getCalendars(
|
||||
userId: string,
|
||||
scope: string = "personal=true&sharedDelegationStatus=accepted&sharedPublicSubscription=true&",
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
): Promise<CalendarList> {
|
||||
const calendars = await api
|
||||
.get(`dav/calendars/${userId}.json?${scope}`, {
|
||||
headers: {
|
||||
@@ -13,7 +14,7 @@ export async function getCalendars(
|
||||
signal,
|
||||
})
|
||||
.json();
|
||||
return calendars;
|
||||
return calendars as CalendarList;
|
||||
}
|
||||
|
||||
export async function getCalendar(
|
||||
@@ -59,7 +60,7 @@ export async function postCalendar(
|
||||
export async function addSharedCalendar(
|
||||
userId: string,
|
||||
calId: string,
|
||||
cal: Record<string, any>
|
||||
cal: CalendarInput
|
||||
) {
|
||||
const response = await api.post(`dav/calendars/${userId}.json`, {
|
||||
headers: {
|
||||
@@ -70,7 +71,7 @@ export async function addSharedCalendar(
|
||||
...cal.cal,
|
||||
"dav:name":
|
||||
cal.cal["dav:name"] === "#default"
|
||||
? cal.owner.displayName + "'s calendar"
|
||||
? (cal.owner?.displayName ?? "Unknown") + "'s calendar"
|
||||
: cal.cal["dav:name"],
|
||||
"calendarserver:source": {
|
||||
acl: cal.cal.acl,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getUserDetails } from "@/features/User/userAPI";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { addSharedCalendar } from "../CalendarApi";
|
||||
import { CalendarInput } from "../types/CalendarData";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
export const addSharedCalendarAsync = createAsyncThunk<
|
||||
@@ -14,14 +15,14 @@ export const addSharedCalendarAsync = createAsyncThunk<
|
||||
owner: string;
|
||||
ownerEmails: string[];
|
||||
},
|
||||
{ userId: string; calId: string; cal: Record<string, any> },
|
||||
{ userId: string; calId: string; cal: CalendarInput },
|
||||
{ rejectValue: RejectedError }
|
||||
>(
|
||||
"calendars/addSharedCalendar",
|
||||
async ({ userId, calId, cal }, { rejectWithValue }) => {
|
||||
try {
|
||||
await addSharedCalendar(userId, calId, cal);
|
||||
const ownerData: any = await getUserDetails(
|
||||
const ownerData = await getUserDetails(
|
||||
cal.cal._links.self.href
|
||||
.replace("/calendars/", "")
|
||||
.replace(".json", "")
|
||||
@@ -29,28 +30,25 @@ export const addSharedCalendarAsync = createAsyncThunk<
|
||||
);
|
||||
|
||||
return {
|
||||
calId: cal.cal._links.self.href
|
||||
.replace("/calendars/", "")
|
||||
calId: cal.cal._links.self?.href
|
||||
?.replace("/calendars/", "")
|
||||
.replace(".json", ""),
|
||||
color: cal.color,
|
||||
link: `/calendars/${userId}/${calId}.json`,
|
||||
desc: cal.cal["caldav:description"],
|
||||
desc: cal.cal["caldav:description"] ?? "",
|
||||
name:
|
||||
ownerData.id !== userId && cal.cal["dav:name"] === "#default"
|
||||
? `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
|
||||
ownerData.lastname
|
||||
ownerData.lastname ?? ""
|
||||
}` + "'s calendar"
|
||||
: cal.cal["dav:name"],
|
||||
: (cal.cal["dav:name"] ?? ""),
|
||||
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
|
||||
ownerData.lastname
|
||||
ownerData.lastname ?? ""
|
||||
}`,
|
||||
ownerEmails: ownerData.emails,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { getUserDetails } from "@/features/User/userAPI";
|
||||
import { userData } from "@/features/User/userDataTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { postCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
@@ -45,11 +44,8 @@ export const createCalendarAsync = createAsyncThunk<
|
||||
owner,
|
||||
ownerEmails: userData.email ? [userData.email] : [],
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { deleteEvent } from "@/features/Events/EventApi";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
@@ -13,11 +13,8 @@ export const deleteEventAsync = createAsyncThunk<
|
||||
try {
|
||||
await deleteEvent(eventURL);
|
||||
return { calId, eventId };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -11,12 +11,13 @@ export const deleteEventInstanceAsync = createAsyncThunk<
|
||||
{ rejectValue: RejectedError }
|
||||
>("calendars/delEventInstance", async ({ cal, event }, { rejectWithValue }) => {
|
||||
try {
|
||||
await deleteEventInstance(event, cal.ownerEmails?.[0]);
|
||||
await deleteEventInstance(event);
|
||||
return { calId: cal.id, eventId: event.uid };
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
const error = err as { response?: { status?: number } };
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
status: error.response?.status,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import {
|
||||
CalendarData,
|
||||
CalendarItem,
|
||||
} from "@/features/Calendars/types/CalendarData";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { extractCalendarEvents } from "../utils/extractCalendarEvents";
|
||||
import { defaultColors } from "@/components/Calendar/utils/calendarColorsUtils";
|
||||
|
||||
export const getCalendarDetailAsync = createAsyncThunk<
|
||||
{
|
||||
@@ -23,24 +28,27 @@ export const getCalendarDetailAsync = createAsyncThunk<
|
||||
"calendars/getCalendarDetails",
|
||||
async ({ calId, match, calType, signal }, { rejectWithValue }) => {
|
||||
try {
|
||||
const calendar = (await getCalendar(calId, match, signal)) as any;
|
||||
const calendar = (await getCalendar(
|
||||
calId,
|
||||
match,
|
||||
signal
|
||||
)) as CalendarData;
|
||||
|
||||
const color = calendar["apple:color"];
|
||||
const color = calendar["apple:color"]
|
||||
? { light: calendar["apple:color"], dark: calendar["apple:color"] }
|
||||
: defaultColors[0];
|
||||
const syncToken = calendar._embedded?.["sync-token"];
|
||||
|
||||
const items = calendar._embedded?.["dav:item"];
|
||||
const events: CalendarEvent[] = Array.isArray(items)
|
||||
? items.flatMap((item: any) =>
|
||||
? items.flatMap((item: CalendarItem) =>
|
||||
extractCalendarEvents(item, { calId, color })
|
||||
)
|
||||
: [];
|
||||
|
||||
return { calId, events, calType, syncToken };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
import { RootState } from "@/app/store";
|
||||
import { OpenPaasUserData } from "@/features/User/type/OpenPaasUserData";
|
||||
import { getOpenPaasUser, getUserDetails } from "@/features/User/userAPI";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getCalendars } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { CalendarData } from "../types/CalendarData";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { normalizeCalendar } from "../utils/normalizeCalendar";
|
||||
|
||||
export const getCalendarsListAsync = createAsyncThunk<
|
||||
{ importedCalendars: Record<string, Calendar>; errors: string },
|
||||
void,
|
||||
{ rejectValue: RejectedError; state: any }
|
||||
{ rejectValue: RejectedError; state: RootState }
|
||||
>("calendars/getCalendars", async (_, { rejectWithValue, getState }) => {
|
||||
const state = getState() as any;
|
||||
const state = getState();
|
||||
const existingCalendars = state.calendars.list || {};
|
||||
const existingUser = { id: state.user?.userData?.openpaasId || undefined };
|
||||
try {
|
||||
const fetchedCalendars: Record<string, Calendar> = {};
|
||||
const user = existingUser.id
|
||||
? existingUser
|
||||
: ((await getOpenPaasUser()) as Record<string, string>);
|
||||
const calendars = (await getCalendars(user.id)) as Record<string, any>;
|
||||
const rawCalendars = calendars._embedded["dav:calendar"] as Record<
|
||||
string,
|
||||
any
|
||||
>[];
|
||||
: ((await getOpenPaasUser()) as OpenPaasUserData);
|
||||
const calendars = await getCalendars(user.id);
|
||||
const rawCalendars = calendars._embedded["dav:calendar"];
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
const normalizedCalendars = rawCalendars.map((cal) =>
|
||||
const normalizedCalendars = rawCalendars.map((cal: CalendarData) =>
|
||||
normalizeCalendar(cal)
|
||||
);
|
||||
|
||||
@@ -34,14 +35,14 @@ export const getCalendarsListAsync = createAsyncThunk<
|
||||
new Set(normalizedCalendars.map(({ ownerId }) => ownerId).filter(Boolean))
|
||||
);
|
||||
|
||||
const ownerDataMap = new Map<string, any>();
|
||||
const ownerDataMap = new Map<string, OpenPaasUserData>();
|
||||
const OWNER_BATCH_SIZE = 20;
|
||||
|
||||
const fetchOwnerData = async (ownerId: string) => {
|
||||
try {
|
||||
const data = await getUserDetails(ownerId);
|
||||
ownerDataMap.set(ownerId, data);
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch user details for ${ownerId}:`, error);
|
||||
ownerDataMap.set(ownerId, {
|
||||
firstname: "",
|
||||
@@ -72,7 +73,7 @@ export const getCalendarsListAsync = createAsyncThunk<
|
||||
|
||||
const color = {
|
||||
light: cal["apple:color"] ?? "#006BD8",
|
||||
dark: cal["X-TWAKE-Dark-theme-color"] ?? "#FFF",
|
||||
dark: "#FFF",
|
||||
};
|
||||
fetchedCalendars[id] = {
|
||||
id,
|
||||
@@ -120,10 +121,11 @@ export const getCalendarsListAsync = createAsyncThunk<
|
||||
importedCalendars,
|
||||
errors: errors.join("\n"),
|
||||
};
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
const error = err as { response?: { status?: number } };
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
status: error.response?.status,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,10 +15,11 @@ export const getEventAsync = createAsyncThunk<
|
||||
calId: event.calId,
|
||||
event: response,
|
||||
};
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
const error = err as { response?: { status?: number } };
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
status: error.response?.status,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,8 +4,8 @@ import { getUserDetails } from "@/features/User/userAPI";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getCalendars } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
export const getTempCalendarsListAsync = createAsyncThunk<
|
||||
Record<string, Calendar>,
|
||||
@@ -20,10 +20,10 @@ export const getTempCalendarsListAsync = createAsyncThunk<
|
||||
`TRANSLATION:calendar.userDoesNotHaveValidId|name=${encodeURIComponent(username)}`
|
||||
);
|
||||
}
|
||||
const calendars = (await getCalendars(
|
||||
const calendars = await getCalendars(
|
||||
tempUser.openpaasId,
|
||||
"sharedPublic=true&"
|
||||
)) as Record<string, any>;
|
||||
);
|
||||
|
||||
const rawCalendars = calendars._embedded?.["dav:calendar"];
|
||||
if (!rawCalendars || rawCalendars.length === 0) {
|
||||
@@ -36,17 +36,20 @@ export const getTempCalendarsListAsync = createAsyncThunk<
|
||||
}
|
||||
|
||||
for (const cal of rawCalendars) {
|
||||
const name = cal["dav:name"];
|
||||
const description = cal["caldav:description"];
|
||||
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;
|
||||
? cal["calendarserver:source"]._links.self?.href
|
||||
: cal._links.self?.href;
|
||||
if (!source) {
|
||||
throw new Error("No source for calendar");
|
||||
}
|
||||
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]);
|
||||
const visibility = getCalendarVisibility(cal["acl"] ?? []);
|
||||
const ownerData = await getUserDetails(id.split("/")[0]);
|
||||
|
||||
importedCalendars[id] = {
|
||||
id,
|
||||
@@ -66,10 +69,11 @@ export const getTempCalendarsListAsync = createAsyncThunk<
|
||||
}
|
||||
|
||||
return importedCalendars;
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
const error = err as { response?: { status?: number } };
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
status: error.response?.status,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,10 +22,11 @@ export const importEventFromFileAsync = createAsyncThunk<
|
||||
});
|
||||
}
|
||||
await importEventFromFile(id, calLink);
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
const error = err as { response?: { status?: number } };
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
status: error.response?.status,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { moveEvent } from "@/features/Events/EventApi";
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { parseCalendarEvent } from "@/features/Events/eventUtils";
|
||||
import {
|
||||
computeWeekRange,
|
||||
formatDateToYYYYMMDDTHHMMSS,
|
||||
} from "@/utils/dateUtils";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
export const moveEventAsync = createAsyncThunk<
|
||||
{ calId: string },
|
||||
@@ -24,11 +18,8 @@ export const moveEventAsync = createAsyncThunk<
|
||||
return {
|
||||
calId: cal.id,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { updateAclCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
@@ -25,11 +25,8 @@ export const patchACLCalendarAsync = createAsyncThunk<
|
||||
calLink,
|
||||
request,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { proppatchCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
@@ -25,11 +25,8 @@ export const patchCalendarAsync = createAsyncThunk<
|
||||
calLink,
|
||||
patch,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { putEvent } from "@/features/Events/EventApi";
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
export const putEventAsync = createAsyncThunk<
|
||||
{ calId: string; calType?: "temp" },
|
||||
@@ -22,11 +22,8 @@ export const putEventAsync = createAsyncThunk<
|
||||
calId: cal.id,
|
||||
calType,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import pMap from "p-map";
|
||||
import { fetchSyncTokenChanges } from "../api/fetchSyncTokenChanges";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { expandEventFunction } from "../utils/expandEventFunction";
|
||||
import { processSyncUpdates } from "../utils/processSyncTokenUpdates";
|
||||
|
||||
@@ -70,11 +70,8 @@ export const refreshCalendarWithSyncToken = createAsyncThunk<
|
||||
syncToken: newSyncToken,
|
||||
syncStatus: newSyncToken ? "SUCCESS" : "NO_NEW_SYNC_TOKEN",
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { removeCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
@@ -20,11 +20,8 @@ export const removeCalendarAsync = createAsyncThunk<
|
||||
return {
|
||||
calId,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { putEventWithOverrides } from "@/features/Events/EventApi";
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
@@ -15,11 +15,8 @@ export const updateEventInstanceAsync = createAsyncThunk<
|
||||
try {
|
||||
await putEventWithOverrides(event, cal.ownerEmails?.[0]);
|
||||
return { calId: cal.id, event };
|
||||
} catch (err: any) {
|
||||
return rejectWithValue({
|
||||
message: formatReduxError(err),
|
||||
status: err.response?.status,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { updateSeries } from "@/features/Events/EventApi";
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { formatReduxError } from "@/utils/errorUtils";
|
||||
import { toRejectedError } from "@/utils/errorUtils";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { Calendar } from "../CalendarTypes";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
|
||||
export const updateSeriesAsync = createAsyncThunk<
|
||||
void,
|
||||
@@ -14,11 +14,8 @@ export const updateSeriesAsync = createAsyncThunk<
|
||||
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,
|
||||
});
|
||||
} catch (err) {
|
||||
return rejectWithValue(toRejectedError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Type for async thunk results
|
||||
export interface AsyncThunkResult {
|
||||
type: string;
|
||||
error?: { message?: string };
|
||||
payload?: { message?: string };
|
||||
unwrap?: () => Promise<unknown>;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { User } from "@/components/Attendees/PeopleSearch";
|
||||
import { CalDavLink } from "../api/types";
|
||||
|
||||
// Access control entry
|
||||
export interface AclEntry {
|
||||
privilege: string;
|
||||
principal: string;
|
||||
protected: boolean;
|
||||
}
|
||||
|
||||
// VObject property value can be various types
|
||||
export type VObjectValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| Date
|
||||
| Record<string, unknown>
|
||||
| null
|
||||
| RepetitionRule
|
||||
| undefined;
|
||||
|
||||
// VObject property tuple
|
||||
export type VObjectProperty = [
|
||||
string,
|
||||
Record<string, unknown>,
|
||||
string | Array<unknown>,
|
||||
VObjectValue,
|
||||
];
|
||||
|
||||
export type VCalComponent = [
|
||||
string,
|
||||
VObjectProperty[],
|
||||
VCalComponent[],
|
||||
...unknown[],
|
||||
];
|
||||
|
||||
export interface Organizer {
|
||||
cn?: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
// The `dav:item` object in _embedded
|
||||
export interface CalendarItem {
|
||||
_links: CalDavLink;
|
||||
etag: string;
|
||||
status: number;
|
||||
data: [
|
||||
"vcalendar",
|
||||
Array<
|
||||
VObjectProperty | [string, VObjectProperty[], unknown[]] // vevent array
|
||||
>,
|
||||
];
|
||||
}
|
||||
|
||||
// Main calendar data
|
||||
export interface CalendarData {
|
||||
_links: CalDavLink;
|
||||
"caldav:description"?: string;
|
||||
"dav:name"?: string;
|
||||
"apple:color"?: string;
|
||||
id?: string;
|
||||
acl?: AclEntry[];
|
||||
invite?: unknown;
|
||||
_embedded: {
|
||||
"sync-token": string;
|
||||
"dav:item": CalendarItem[];
|
||||
};
|
||||
"calendarserver:source"?: { _links: CalDavLink };
|
||||
"calendarserver:delegatedsource"?: string;
|
||||
}
|
||||
|
||||
export interface CalendarList {
|
||||
_embedded: { "dav:calendar": CalendarData[] };
|
||||
}
|
||||
|
||||
// Calendar input for forms or UI
|
||||
export interface CalendarInput {
|
||||
cal: CalendarData;
|
||||
color: Record<string, string>;
|
||||
owner?: User;
|
||||
}
|
||||
|
||||
// Vevent repetition rule
|
||||
export interface RepetitionRule {
|
||||
freq: string;
|
||||
interval?: number;
|
||||
count?: number;
|
||||
until?: string;
|
||||
byday?: string | string[];
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export function expandEventFunction(
|
||||
});
|
||||
return events;
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch event", eventUrl);
|
||||
console.error("Failed to fetch event", eventUrl, err);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { defaultColors } from "@/components/Calendar/utils/calendarColorsUtils";
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { parseCalendarEvent } from "@/features/Events/eventUtils";
|
||||
import { CalDavItem } from "../api/types";
|
||||
import { VCalComponent } from "../types/CalendarData";
|
||||
|
||||
export function extractCalendarEvents(
|
||||
item: CalDavItem,
|
||||
@@ -50,7 +51,7 @@ export function extractCalendarEvents(
|
||||
.filter(Boolean) as CalendarEvent[];
|
||||
}
|
||||
|
||||
function extractValarm(vevent: any[]) {
|
||||
function extractValarm(vevent: VCalComponent[]) {
|
||||
const subComponents = vevent[2];
|
||||
if (!Array.isArray(subComponents)) {
|
||||
return undefined;
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { getCalendarVisibility } from "@/components/Calendar/utils/calendarUtils";
|
||||
import { CalendarData } from "../types/CalendarData";
|
||||
|
||||
export function normalizeCalendar(rawCalendar: Record<string, any>) {
|
||||
export function normalizeCalendar(rawCalendar: CalendarData) {
|
||||
const description = rawCalendar["caldav:description"];
|
||||
let delegated = false;
|
||||
let source = rawCalendar["calendarserver:source"]
|
||||
? rawCalendar["calendarserver:source"]._links.self.href
|
||||
: rawCalendar._links.self.href;
|
||||
const link = rawCalendar._links.self.href;
|
||||
? rawCalendar["calendarserver:source"]._links.self?.href
|
||||
: rawCalendar._links.self?.href;
|
||||
const link = rawCalendar._links.self?.href;
|
||||
if (rawCalendar["calendarserver:delegatedsource"]) {
|
||||
source = rawCalendar["calendarserver:delegatedsource"];
|
||||
delegated = true;
|
||||
}
|
||||
if (!source) {
|
||||
throw new Error("No source for calendar");
|
||||
}
|
||||
const id = source.replace("/calendars/", "").replace(".json", "");
|
||||
const ownerId = id.split("/")[0];
|
||||
const visibility = getCalendarVisibility(rawCalendar["acl"]);
|
||||
const visibility = getCalendarVisibility(rawCalendar["acl"] ?? []);
|
||||
return {
|
||||
cal: rawCalendar,
|
||||
description,
|
||||
|
||||
@@ -30,6 +30,6 @@ export function processSyncUpdates(
|
||||
}
|
||||
|
||||
function extractFileNameFromHref(href: string): string {
|
||||
const fileNameMatch = href.match(/\/([^\/]+)\.ics$/); // CalDAV href are like /calendars/userID/CalendarID/EventId.ics
|
||||
const fileNameMatch = href.match(/\/([^/]+)\.ics$/); // CalDAV href are like /calendars/userID/CalendarID/EventId.ics
|
||||
return fileNameMatch ? fileNameMatch[1] : href;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user