[#4] added delegated calendars
This commit is contained in:
@@ -0,0 +1,193 @@
|
|||||||
|
import { CalendarApi } from "@fullcalendar/core";
|
||||||
|
import { jest } from "@jest/globals";
|
||||||
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
|
import "@testing-library/jest-dom";
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import * as appHooks from "../../src/app/hooks";
|
||||||
|
import CalendarApp from "../../src/components/Calendar/Calendar";
|
||||||
|
import { renderWithProviders } from "../utils/Renderwithproviders";
|
||||||
|
import CalendarSelection from "../../src/components/Calendar/CalendarSelection";
|
||||||
|
|
||||||
|
describe("CalendarSelection", () => {
|
||||||
|
const today = new Date();
|
||||||
|
const start = new Date(today);
|
||||||
|
start.setHours(10, 0, 0, 0);
|
||||||
|
const end = new Date(today);
|
||||||
|
end.setHours(11, 0, 0, 0);
|
||||||
|
|
||||||
|
it("renders the all the calendars in list", async () => {
|
||||||
|
const preloadedState = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "user1",
|
||||||
|
},
|
||||||
|
tokens: { accessToken: "token" }, // required to avoid redirect
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"user1/cal1": {
|
||||||
|
name: "Calendar personnal",
|
||||||
|
id: "user1/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["alice@example.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "user1/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Alice",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"user2/cal1": {
|
||||||
|
name: "Calendar delegated",
|
||||||
|
delegated: true,
|
||||||
|
id: "user2/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["alice@example.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "user2/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Alice",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"user3/cal1": {
|
||||||
|
name: "Calendar shared",
|
||||||
|
id: "user3/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["alice@example.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "user3/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Alice",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
renderWithProviders(<CalendarApp />, preloadedState);
|
||||||
|
expect(screen.getByText("personnalCalendars")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("delegatedCalendars")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("sharedCalendars")).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByLabelText("Calendar personnal")).toBeInTheDocument();
|
||||||
|
expect(screen.getByLabelText("Calendar delegated")).toBeInTheDocument();
|
||||||
|
expect(screen.getByLabelText("Calendar shared")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it("renders only personnal calendars in list", async () => {
|
||||||
|
const preloadedState = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "user1",
|
||||||
|
},
|
||||||
|
tokens: { accessToken: "token" }, // required to avoid redirect
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"user1/cal1": {
|
||||||
|
name: "Calendar personnal",
|
||||||
|
id: "user1/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["alice@example.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "user1/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Alice",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
renderWithProviders(<CalendarApp />, preloadedState);
|
||||||
|
expect(screen.getByText("personnalCalendars")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("delegatedCalendars")).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("sharedCalendars")).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByLabelText("Calendar personnal")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -7,11 +7,18 @@ export default function CalendarSelection({
|
|||||||
selectedCalendars: string[];
|
selectedCalendars: string[];
|
||||||
setSelectedCalendars: Function;
|
setSelectedCalendars: Function;
|
||||||
}) {
|
}) {
|
||||||
const tokens = useAppSelector((state) => state.user.tokens);
|
|
||||||
const userId = useAppSelector((state) => state.user.userData.openpaasId);
|
const userId = useAppSelector((state) => state.user.userData.openpaasId);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const calendars = useAppSelector((state) => state.calendars.list);
|
const calendars = useAppSelector((state) => state.calendars.list);
|
||||||
|
const personnalCalendars = Object.keys(calendars).filter(
|
||||||
|
(id) => id.split("/")[0] === userId
|
||||||
|
);
|
||||||
|
const delegatedCalendars = Object.keys(calendars).filter(
|
||||||
|
(id) => id.split("/")[0] !== userId && calendars[id].delegated
|
||||||
|
);
|
||||||
|
const sharedCalendars = Object.keys(calendars).filter(
|
||||||
|
(id) => id.split("/")[0] !== userId && !calendars[id].delegated
|
||||||
|
);
|
||||||
const handleCalendarToggle = (name: string) => {
|
const handleCalendarToggle = (name: string) => {
|
||||||
setSelectedCalendars((prev: string[]) =>
|
setSelectedCalendars((prev: string[]) =>
|
||||||
prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name]
|
prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name]
|
||||||
@@ -21,27 +28,8 @@ export default function CalendarSelection({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>personnalCalendars</h3>
|
<h3>personnalCalendars</h3>
|
||||||
{Object.keys(calendars)
|
{personnalCalendars.map((id) => {
|
||||||
.filter((id) => id.split("/")[0] === userId)
|
return (
|
||||||
.map((id) => {
|
|
||||||
return (
|
|
||||||
<div key={id}>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
style={{ backgroundColor: calendars[id].color }}
|
|
||||||
checked={selectedCalendars.includes(id)}
|
|
||||||
onChange={() => handleCalendarToggle(id)}
|
|
||||||
/>
|
|
||||||
{calendars[id].name}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<h3>sharedCalendars</h3>
|
|
||||||
{Object.keys(calendars)
|
|
||||||
.filter((id) => id.split("/")[0] !== userId)
|
|
||||||
.map((id) => (
|
|
||||||
<div key={id}>
|
<div key={id}>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
@@ -53,7 +41,44 @@ export default function CalendarSelection({
|
|||||||
{calendars[id].name}
|
{calendars[id].name}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
|
{delegatedCalendars.length > 0 && (
|
||||||
|
<>
|
||||||
|
<h3>delegatedCalendars</h3>
|
||||||
|
{delegatedCalendars.map((id) => (
|
||||||
|
<div key={id}>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
style={{ backgroundColor: calendars[id].color }}
|
||||||
|
checked={selectedCalendars.includes(id)}
|
||||||
|
onChange={() => handleCalendarToggle(id)}
|
||||||
|
/>
|
||||||
|
{calendars[id].name}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{sharedCalendars.length > 0 && (
|
||||||
|
<>
|
||||||
|
<h3>sharedCalendars</h3>
|
||||||
|
{sharedCalendars.map((id) => (
|
||||||
|
<div key={id}>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
style={{ backgroundColor: calendars[id].color }}
|
||||||
|
checked={selectedCalendars.includes(id)}
|
||||||
|
onChange={() => handleCalendarToggle(id)}
|
||||||
|
/>
|
||||||
|
{calendars[id].name}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { getOpenPaasUser, getUserDetails } from "../User/userAPI";
|
|||||||
import { parseCalendarEvent } from "../Events/eventUtils";
|
import { parseCalendarEvent } from "../Events/eventUtils";
|
||||||
import { deleteEvent, putEvent } from "../Events/EventApi";
|
import { deleteEvent, putEvent } from "../Events/EventApi";
|
||||||
import { formatDateToYYYYMMDDTHHMMSS } from "../../utils/dateUtils";
|
import { formatDateToYYYYMMDDTHHMMSS } from "../../utils/dateUtils";
|
||||||
import { responsiveFontSizes } from "@mui/material";
|
|
||||||
|
|
||||||
export const getCalendarsListAsync = createAsyncThunk<
|
export const getCalendarsListAsync = createAsyncThunk<
|
||||||
Record<string, Calendars> // Return type
|
Record<string, Calendars> // Return type
|
||||||
@@ -19,11 +18,17 @@ export const getCalendarsListAsync = createAsyncThunk<
|
|||||||
for (const cal of rawCalendars) {
|
for (const cal of rawCalendars) {
|
||||||
const name = cal["dav:name"];
|
const name = cal["dav:name"];
|
||||||
const description = cal["dav:description"];
|
const description = cal["dav:description"];
|
||||||
const id = cal["calendarserver:source"]
|
let delegated = false;
|
||||||
|
let source = cal["calendarserver:source"]
|
||||||
? cal["calendarserver:source"]._links.self.href
|
? cal["calendarserver:source"]._links.self.href
|
||||||
.replace("/calendars/", "")
|
: cal._links.self.href;
|
||||||
.replace(".json", "")
|
if (cal["calendarserver:delegatedsource"]) {
|
||||||
: cal._links.self.href.replace("/calendars/", "").replace(".json", "");
|
source = cal["calendarserver:delegatedsource"];
|
||||||
|
delegated = true;
|
||||||
|
}
|
||||||
|
console.log(source);
|
||||||
|
const id = source.replace("/calendars/", "").replace(".json", "");
|
||||||
|
|
||||||
const ownerData: any = await getUserDetails(id.split("/")[0]);
|
const ownerData: any = await getUserDetails(id.split("/")[0]);
|
||||||
const color = cal["apple:color"];
|
const color = cal["apple:color"];
|
||||||
importedCalendars[id] = {
|
importedCalendars[id] = {
|
||||||
@@ -31,6 +36,7 @@ export const getCalendarsListAsync = createAsyncThunk<
|
|||||||
name,
|
name,
|
||||||
ownerEmails: ownerData.emails,
|
ownerEmails: ownerData.emails,
|
||||||
description,
|
description,
|
||||||
|
delegated,
|
||||||
color,
|
color,
|
||||||
events: {},
|
events: {},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CalendarEvent } from "../Events/EventsTypes";
|
|||||||
export interface Calendars {
|
export interface Calendars {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
delegated?: boolean;
|
||||||
prodid?: string;
|
prodid?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
ownerEmails?: string[];
|
ownerEmails?: string[];
|
||||||
|
|||||||
Reference in New Issue
Block a user