Calendar subscription naming (#235)
Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
// __test__/features/calendars/calendarApi.test.ts
|
// __test__/features/calendars/calendarApi.test.ts
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
addSharedCalendar,
|
||||||
getCalendar,
|
getCalendar,
|
||||||
getCalendars,
|
getCalendars,
|
||||||
postCalendar,
|
postCalendar,
|
||||||
@@ -112,4 +113,43 @@ describe("Calendar API", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("When adding a sharedCal with #default as a name a new name is sent to the back", async () => {
|
||||||
|
const mockApiPost = jest.spyOn(api, "post");
|
||||||
|
|
||||||
|
const calData = {
|
||||||
|
cal: {
|
||||||
|
id: "cal123",
|
||||||
|
"dav:name": "#default",
|
||||||
|
"apple:color": "#FF5733",
|
||||||
|
"caldav:description": "Default calendar",
|
||||||
|
acl: [],
|
||||||
|
invite: [],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: "/calendars/owner123/cal123.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
displayName: "John Doe",
|
||||||
|
email: "john.doe@example.com",
|
||||||
|
openpaasId: "owner123",
|
||||||
|
},
|
||||||
|
color: "#FF5733",
|
||||||
|
};
|
||||||
|
|
||||||
|
await addSharedCalendar("currentUserId", "newCalId123", calData);
|
||||||
|
|
||||||
|
expect(mockApiPost).toHaveBeenCalledWith(
|
||||||
|
"dav/calendars/currentUserId.json",
|
||||||
|
expect.objectContaining({
|
||||||
|
body: expect.stringContaining('"dav:name":"John Doe\'s calendar"'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const callBody = JSON.parse(String(mockApiPost.mock.calls[0][1]?.body));
|
||||||
|
expect(callBody["dav:name"]).toBe("John Doe's calendar");
|
||||||
|
expect(callBody["dav:name"]).not.toBe("#default");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,10 @@
|
|||||||
padding-left 5px
|
padding-left 5px
|
||||||
height 100%
|
height 100%
|
||||||
flex-direction column
|
flex-direction column
|
||||||
overflow auto
|
overflow-y: hidden
|
||||||
|
|
||||||
|
.sidebar:hover
|
||||||
|
overflow-y: auto
|
||||||
|
|
||||||
.declined-event
|
.declined-event
|
||||||
opacity 0.7
|
opacity 0.7
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ function CalendarItem({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="body1">{cal.cal["dav:name"]}</Typography>
|
<Typography variant="body1">
|
||||||
|
{cal.cal["dav:name"] === "#default"
|
||||||
|
? cal.owner.displayName + "'s calendar"
|
||||||
|
: cal.cal["dav:name"]}
|
||||||
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary">
|
<Typography variant="body2" color="textSecondary">
|
||||||
{cal.owner.email}
|
{cal.owner.email}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import IconButton from "@mui/material/IconButton";
|
|||||||
import Checkbox from "@mui/material/Checkbox";
|
import Checkbox from "@mui/material/Checkbox";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
import CalendarSearch from "./CalendarSearch";
|
import CalendarSearch from "./CalendarSearch";
|
||||||
import { Divider, Menu, MenuItem } from "@mui/material";
|
import { Divider, ListItem, Menu, MenuItem } from "@mui/material";
|
||||||
import { removeCalendarAsync } from "../../features/Calendars/CalendarSlice";
|
import { removeCalendarAsync } from "../../features/Calendars/CalendarSlice";
|
||||||
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
|
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
|
||||||
|
|
||||||
@@ -41,13 +41,24 @@ function CalendarAccordion({
|
|||||||
if (calendars.length === 0 && !defaultExpanded) return null;
|
if (calendars.length === 0 && !defaultExpanded) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion defaultExpanded={defaultExpanded} expanded={expended}>
|
<Accordion
|
||||||
|
defaultExpanded={defaultExpanded}
|
||||||
|
expanded={expended}
|
||||||
|
style={{ width: "100%", padding: 0, margin: 0, boxShadow: "none" }}
|
||||||
|
>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
aria-controls={`${title}-content`}
|
aria-controls={`${title}-content`}
|
||||||
id={`${title}-header`}
|
id={`${title}-header`}
|
||||||
className="calendarListHeader"
|
className="calendarListHeader"
|
||||||
onClick={() => setExpended(!expended)}
|
onClick={() => setExpended(!expended)}
|
||||||
|
sx={{
|
||||||
|
"& .MuiAccordionSummary-content": {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Typography component="h3">{title}</Typography>
|
<Typography component="h3">{title}</Typography>
|
||||||
{showAddButton && (
|
{showAddButton && (
|
||||||
@@ -62,7 +73,7 @@ function CalendarAccordion({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails style={{ textAlign: "left", padding: 0 }}>
|
||||||
{calendars.map((id) => (
|
{calendars.map((id) => (
|
||||||
<CalendarSelector
|
<CalendarSelector
|
||||||
key={id}
|
key={id}
|
||||||
@@ -214,7 +225,24 @@ function CalendarSelector({
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<ListItem
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
transition: "background-color 0.2s ease",
|
||||||
|
padding: "8px 24px 8px 16px",
|
||||||
|
"& .MoreBtn": {
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#F3F3F6",
|
||||||
|
"& .MoreBtn": {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<label>
|
<label>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
sx={{
|
sx={{
|
||||||
@@ -227,10 +255,14 @@ function CalendarSelector({
|
|||||||
/>
|
/>
|
||||||
{calendars[id].name}
|
{calendars[id].name}
|
||||||
</label>
|
</label>
|
||||||
<IconButton onClick={handleClick}>
|
<IconButton
|
||||||
|
className="MoreBtn"
|
||||||
|
onClick={handleClick}
|
||||||
|
style={{ alignSelf: "end" }}
|
||||||
|
>
|
||||||
<MoreVertIcon />
|
<MoreVertIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</ListItem>
|
||||||
<Menu id={id} anchorEl={anchorEl} open={open} onClose={handleClose}>
|
<Menu id={id} anchorEl={anchorEl} open={open} onClose={handleClose}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ export async function addSharedCalendar(
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id: calId,
|
id: calId,
|
||||||
...cal.cal,
|
...cal.cal,
|
||||||
|
"dav:name":
|
||||||
|
cal.cal["dav:name"] === "#default"
|
||||||
|
? cal.owner.displayName + "'s calendar"
|
||||||
|
: cal.cal["dav:name"],
|
||||||
"calendarserver:source": {
|
"calendarserver:source": {
|
||||||
acl: cal.cal.acl,
|
acl: cal.cal.acl,
|
||||||
calendarHomeId: cal.cal.id,
|
calendarHomeId: cal.cal.id,
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ export const getCalendarsListAsync = createAsyncThunk<
|
|||||||
const rawCalendars = calendars._embedded["dav:calendar"];
|
const rawCalendars = calendars._embedded["dav:calendar"];
|
||||||
|
|
||||||
for (const cal of rawCalendars) {
|
for (const cal of rawCalendars) {
|
||||||
const name = cal["dav:name"];
|
|
||||||
const description = cal["caldav:description"];
|
const description = cal["caldav:description"];
|
||||||
let delegated = false;
|
let delegated = false;
|
||||||
let source = cal["calendarserver:source"]
|
let source = cal["calendarserver:source"]
|
||||||
@@ -51,8 +50,16 @@ export const getCalendarsListAsync = createAsyncThunk<
|
|||||||
delegated = true;
|
delegated = true;
|
||||||
}
|
}
|
||||||
const id = source.replace("/calendars/", "").replace(".json", "");
|
const id = source.replace("/calendars/", "").replace(".json", "");
|
||||||
|
const ownerId = id.split("/")[0];
|
||||||
const visibility = getCalendarVisibility(cal["acl"]);
|
const visibility = getCalendarVisibility(cal["acl"]);
|
||||||
const ownerData: any = await getUserDetails(id.split("/")[0]);
|
const ownerData: any = await getUserDetails(ownerId);
|
||||||
|
const name =
|
||||||
|
ownerId !== user.id && cal["dav:name"] === "#default"
|
||||||
|
? `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
|
||||||
|
ownerData.lastname
|
||||||
|
}` + "'s calendar"
|
||||||
|
: cal["dav:name"];
|
||||||
|
|
||||||
const color = {
|
const color = {
|
||||||
light: cal["apple:color"] ?? "#006BD8",
|
light: cal["apple:color"] ?? "#006BD8",
|
||||||
dark: cal["X-TWAKE-Dark-theme-color"] ?? "#FFF",
|
dark: cal["X-TWAKE-Dark-theme-color"] ?? "#FFF",
|
||||||
@@ -370,7 +377,12 @@ export const addSharedCalendarAsync = createAsyncThunk<
|
|||||||
},
|
},
|
||||||
link: `/calendars/${userId}/${calId}.json`,
|
link: `/calendars/${userId}/${calId}.json`,
|
||||||
desc: cal.cal["caldav:description"],
|
desc: cal.cal["caldav:description"],
|
||||||
name: cal.cal["dav:name"],
|
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} ` : ""}${
|
owner: `${ownerData.firstname ? `${ownerData.firstname} ` : ""}${
|
||||||
ownerData.lastname
|
ownerData.lastname
|
||||||
}`,
|
}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user