ability to register a shared calendar (#118)

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
Camille Moussu
2025-09-22 20:45:02 +02:00
committed by GitHub
parent 8122772bec
commit cd724a30a0
12 changed files with 721 additions and 136 deletions
+36 -9
View File
@@ -1,15 +1,15 @@
import { api } from "../../utils/apiUtils";
export async function getCalendars(userId: string) {
export async function getCalendars(
userId: string,
scope: string = "personal=true&sharedDelegationStatus=accepted&sharedPublicSubscription=true&withRights=true"
) {
const calendars = await api
.get(
`dav/calendars/${userId}.json?personal=true&sharedDelegationStatus=accepted&sharedPublicSubscription=true&withRights=true`,
{
headers: {
Accept: "application/calendar+json",
},
}
)
.get(`dav/calendars/${userId}.json?${scope}`, {
headers: {
Accept: "application/calendar+json",
},
})
.json();
return calendars;
}
@@ -52,6 +52,33 @@ export async function postCalendar(
return response;
}
export async function addSharedCalendar(
userId: string,
calId: string,
cal: Record<string, any>
) {
const response = await api.post(`dav/calendars/${userId}.json`, {
headers: {
Accept: "application/json, text/plain, */*",
},
body: JSON.stringify({
id: calId,
...cal.cal,
"calendarserver:source": {
acl: cal.cal.acl,
calendarHomeId: cal.cal.id,
color: cal.cal["apple:color"],
description: cal.cal["caldav:description"],
href: cal.cal._links.self.href,
id: cal.cal.id,
invite: cal.cal.invite,
name: cal.cal["dav:name"],
},
}),
});
return response;
}
export async function proppatchCalendar(
calLink: string,
patch: { name: string; desc: string; color: string }
+6 -9
View File
@@ -12,6 +12,7 @@ import {
Typography,
ButtonGroup,
} from "@mui/material";
import { ColorPicker } from "../../components/Calendar/CalendarColorPicker";
import { Calendars } from "./CalendarTypes";
function CalendarPopover({
@@ -128,15 +129,11 @@ function CalendarPopover({
multiline
rows={2}
/>
<ButtonGroup>
{palette.map((c) => (
<Button
key={c}
style={{ backgroundColor: c }}
onClick={() => setColor(c)}
/>
))}
</ButtonGroup>
<ColorPicker
onChange={(color) => setColor(color)}
selectedColor={color}
/>
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
<Button
variant="outlined"
+75 -3
View File
@@ -2,6 +2,7 @@ import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { Calendars } from "./CalendarTypes";
import { CalendarEvent } from "../Events/EventsTypes";
import {
addSharedCalendar,
getCalendar,
getCalendars,
postCalendar,
@@ -184,11 +185,64 @@ export const deleteEventAsync = createAsyncThunk<
});
export const createCalendarAsync = createAsyncThunk<
{ userId: string; calId: string; color: string; name: string; desc: string }, // Return type
{
userId: string;
calId: string;
color: string;
name: string;
desc: string;
owner: string;
ownerEmails: string[];
}, // Return type
{ userId: string; calId: string; color: string; name: string; desc: string } // Arg type
>("calendars/createCalendar", async ({ userId, calId, color, name, desc }) => {
const response = await postCalendar(userId, calId, color, name, desc);
return { 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,
};
});
export const addSharedCalendarAsync = createAsyncThunk<
{
calId: string;
color: string;
name: string;
desc: string;
owner: string;
ownerEmails: string[];
}, // Return type
{ userId: string; calId: string; cal: Record<string, any> } // Arg type
>("calendars/addSharedCalendar", async ({ userId, calId, cal }) => {
const response = 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.cal["apple:color"],
desc: cal.cal["caldav:description"],
name: cal.cal["dav:name"],
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
ownerData.lastname
}`,
ownerEmails: ownerData.emails,
};
});
const CalendarSlice = createSlice({
@@ -363,7 +417,10 @@ const CalendarSlice = createSlice({
id: `${action.payload.userId}/${action.payload.calId}`,
description: action.payload.desc,
name: action.payload.name,
} as unknown as Calendars;
owner: action.payload.owner,
ownerEmails: action.payload.ownerEmails,
events: {},
} as Calendars;
})
.addCase(patchCalendarAsync.fulfilled, (state, action) => {
state.pending = false;
@@ -391,6 +448,18 @@ const CalendarSlice = createSlice({
};
}
})
.addCase(addSharedCalendarAsync.fulfilled, (state, action) => {
state.pending = false;
state.list[action.payload.calId] = {
color: action.payload.color,
id: action.payload.calId,
description: action.payload.desc,
name: action.payload.name,
events: {},
owner: action.payload.owner,
ownerEmails: action.payload.ownerEmails,
} as Calendars;
})
.addCase(getCalendarDetailAsync.pending, (state) => {
state.pending = true;
})
@@ -414,6 +483,9 @@ const CalendarSlice = createSlice({
})
.addCase(createCalendarAsync.pending, (state) => {
state.pending = true;
})
.addCase(addSharedCalendarAsync.pending, (state) => {
state.pending = true;
});
},
});
+1 -4
View File
@@ -391,10 +391,7 @@ export default function EventDisplayModal({
{isOwn && (
<AttendeeSelector
attendees={attendees}
setAttendees={(value: userAttendee[]) => {
const newAttendeeList = attendees.concat(value);
setAttendees(newAttendeeList);
}}
setAttendees={setAttendees}
/>
)}
+13 -2
View File
@@ -5,12 +5,22 @@ export async function getOpenPaasUser() {
return user;
}
export async function searchUsers(query: string) {
export async function searchUsers(
query: string,
objectTypes: string[] = ["user", "contact"]
): Promise<
{
email: string;
displayName: string;
avatarUrl: string;
openpaasId: string;
}[]
> {
const response: any[] = await api
.post(`api/people/search`, {
body: JSON.stringify({
limit: 10,
objectTypes: ["user", "group", "contact", "ldap"],
objectTypes,
q: query,
}),
})
@@ -21,6 +31,7 @@ export async function searchUsers(query: string) {
displayName:
user.names?.[0]?.displayName || user.emailAddresses?.[0]?.value,
avatarUrl: user.photos?.[0]?.url || "",
openpaasId: user.id || "",
}));
}