[#397 bis] added participation management on event from thunderbird (#432)

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
Camille Moussu
2026-01-07 11:45:17 +01:00
committed by GitHub
parent e59d878e6c
commit 9ff75056c7
47 changed files with 550 additions and 366 deletions
+2 -2
View File
@@ -15,13 +15,13 @@ import {
exportCalendar,
getSecretLink,
} from "../../features/Calendars/CalendarApi";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { FieldWithLabel } from "../Event/components/FieldWithLabel";
import { SnackbarAlert } from "../Loading/SnackBarAlert";
import { useI18n } from "twake-i18n";
import { ErrorSnackbar } from "../Error/ErrorSnackbar";
export function AccessTab({ calendar }: { calendar: Calendars }) {
export function AccessTab({ calendar }: { calendar: Calendar }) {
const { t } = useI18n();
const calDAVLink = `${(window as any).CALENDAR_BASE_URL}${calendar.link.replace(".json", "")}`;
+2 -2
View File
@@ -1,10 +1,10 @@
import React from "react";
import { MenuItem } from "@mui/material";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { CalendarName } from "./CalendarName";
export function CalendarItemList(
userPersonalCalendars: Calendars[]
userPersonalCalendars: Calendar[]
): React.ReactNode {
return Object.values(userPersonalCalendars).map((calendar) => (
<MenuItem key={calendar.id} value={calendar.id}>
+2 -2
View File
@@ -7,7 +7,7 @@ import {
patchACLCalendarAsync,
patchCalendarAsync,
} from "../../features/Calendars/CalendarSlice";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { ResponsiveDialog } from "../Dialog";
import { AccessTab } from "./AccessTab";
import { ImportTab } from "./ImportTab";
@@ -25,7 +25,7 @@ function CalendarPopover({
event: object | null,
reason: "backdropClick" | "escapeKeyDown"
) => void;
calendar?: Calendars;
calendar?: Calendar;
}) {
const { t } = useI18n();
const dispatch = useAppDispatch();
+2 -2
View File
@@ -1,7 +1,7 @@
import { Box, Typography } from "@mui/material";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
export function CalendarName({ calendar }: { calendar: Calendars }) {
export function CalendarName({ calendar }: { calendar: Calendar }) {
return (
<Box style={{ display: "flex", flexDirection: "row", gap: 8 }}>
<SquareRoundedIcon
+2 -2
View File
@@ -10,7 +10,7 @@ import { useState } from "react";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { getCalendars } from "../../features/Calendars/CalendarApi";
import { addSharedCalendarAsync } from "../../features/Calendars/CalendarSlice";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import TextField from "@mui/material/TextField";
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
import { ResponsiveDialog } from "../Dialog";
@@ -93,7 +93,7 @@ function SelectedCalendarsList({
onRemove,
onColorChange,
}: {
calendars: Record<string, Calendars>;
calendars: Record<string, Calendar>;
selectedCal: CalendarWithOwner[];
onRemove: (cal: CalendarWithOwner) => void;
onColorChange: (
@@ -6,7 +6,7 @@ import { useAppDispatch, useAppSelector } from "../../app/hooks";
import AddIcon from "@mui/icons-material/Add";
import { useState, useMemo, useEffect } from "react";
import CalendarPopover from "./CalendarModal";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import MoreVertIcon from "@mui/icons-material/MoreVert";
import IconButton from "@mui/material/IconButton";
import Checkbox from "@mui/material/Checkbox";
@@ -206,7 +206,7 @@ function CalendarSelector({
handleCalendarToggle,
setOpen,
}: {
calendars: Record<string, Calendars>;
calendars: Record<string, Calendar>;
id: string;
isPersonal: boolean;
selectedCalendars: string[];
@@ -1,5 +1,5 @@
import Dialog from "@mui/material/Dialog";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
@@ -17,7 +17,7 @@ export function DeleteCalendarDialog({
}: {
deletePopupOpen: boolean;
setDeletePopupOpen: (e: boolean) => void;
calendars: Record<string, Calendars>;
calendars: Record<string, Calendar>;
id: string;
isPersonal: boolean;
handleDeleteConfirm: () => void;
+2 -2
View File
@@ -12,7 +12,7 @@ import {
import { useI18n } from "twake-i18n";
import { useState, useEffect } from "react";
import { useAppSelector } from "../../app/hooks";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { AddDescButton } from "../Event/AddDescButton";
import { ColorPicker } from "./CalendarColorPicker";
@@ -35,7 +35,7 @@ export function SettingsTab({
setColor: Function;
visibility: "public" | "private";
setVisibility: Function;
calendar?: Calendars;
calendar?: Calendar;
}) {
const { t } = useI18n();
const [toggleDesc, setToggleDesc] = useState(Boolean(description));
@@ -6,7 +6,7 @@ import {
getTempCalendarsListAsync,
removeTempCal,
} from "../../features/Calendars/CalendarSlice";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { Calendar } from "../../features/Calendars/CalendarTypes";
import { setView } from "../../features/Settings/SettingsSlice";
import TextField from "@mui/material/TextField";
import { User, PeopleSearch } from "../Attendees/PeopleSearch";
@@ -134,7 +134,7 @@ function getCalendarsFromUsersDelta(
return { calendarsToImport, calendarsToToggle };
}
function buildEmailToCalendarMap(calRecord: Record<string, Calendars>) {
function buildEmailToCalendarMap(calRecord: Record<string, Calendar>) {
const map = new Map<string, string[]>();
for (const [id, cal] of Object.entries(calRecord)) {
cal.ownerEmails?.forEach((email) => {
@@ -1,7 +1,7 @@
import { DateSelectArg } from "@fullcalendar/core";
import { CalendarApi } from "@fullcalendar/core";
import { CalendarEvent } from "../../../features/Events/EventsTypes";
import { Calendars } from "../../../features/Calendars/CalendarTypes";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { getDeltaInMilliseconds } from "../../../utils/dateUtils";
import {
getCalendarDetailAsync,
@@ -17,21 +17,22 @@ import { refreshCalendars } from "../../Event/utils/eventUtils";
import { updateTempCalendar } from "../utils/calendarUtils";
import { User } from "../../Attendees/PeopleSearch";
import { formatLocalDateTime } from "../../Event/utils/dateTimeFormatters";
import { userAttendee } from "../../../features/User/userDataTypes";
import { userAttendee } from "../../../features/User/models/attendee";
import { createAttendee } from "../../../features/User/models/attendee.mapper";
export interface EventHandlersProps {
setSelectedRange: (range: DateSelectArg | null) => void;
setAnchorEl: (el: HTMLElement | null) => void;
calendarRef: React.RefObject<CalendarApi | null>;
selectedCalendars: string[];
tempcalendars: Record<string, Calendars>;
tempcalendars: Record<string, Calendar>;
calendarRange: { start: Date; end: Date };
dispatch: any;
setOpenEventDisplay: (open: boolean) => void;
setEventDisplayedId: (id: string) => void;
setEventDisplayedCalId: (id: string) => void;
setEventDisplayedTemp: (temp: boolean) => void;
calendars: Record<string, Calendars>;
calendars: Record<string, Calendar>;
setSelectedEvent: (event: CalendarEvent) => void;
setAfterChoiceFunc: (func: Function) => void;
setOpenEditModePopup: (open: string) => void;
@@ -72,14 +73,13 @@ export const createEventHandlers = (props: EventHandlersProps) => {
end: selectInfo?.end
? formatLocalDateTime(selectInfo?.end, timezone)
: "",
attendee: tempUsers.map((u) => ({
cn: u.displayName,
cal_address: u.email,
partstat: "NEED-ACTION",
role: "REQ-PARTICIPANT",
rsvp: "TRUE",
cutype: "INDIVIDUAL",
})),
attendee: tempUsers.map((user) =>
createAttendee({
cal_address: user.email,
cn: user.displayName,
rsvp: "TRUE",
})
),
} as CalendarEvent;
setTempEvent(newEvent);
@@ -1,8 +1,8 @@
import React from "react";
import { CalendarApi, NowIndicatorContentArg } from "@fullcalendar/core";
import { createMouseHandlers } from "./mouseHandlers";
import { userAttendee } from "../../../features/User/userDataTypes";
import { Calendars } from "../../../features/Calendars/CalendarTypes";
import { userAttendee } from "../../../features/User/models/attendee";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { EventErrorHandler } from "../../Error/EventErrorHandler";
import { EventChip } from "../../Event/EventChip/EventChip";
@@ -11,8 +11,8 @@ export interface ViewHandlersProps {
setSelectedDate: (date: Date) => void;
setSelectedMiniDate: (date: Date) => void;
onViewChange?: (view: string) => void;
calendars: Record<string, Calendars>;
tempcalendars: Record<string, Calendars>;
calendars: Record<string, Calendar>;
tempcalendars: Record<string, Calendar>;
errorHandler: EventErrorHandler;
}
@@ -1,10 +1,10 @@
import { darken, getContrastRatio, lighten, Theme } from "@mui/material";
import { ThunkDispatch } from "@reduxjs/toolkit";
import { updateCalColor } from "../../../features/Calendars/CalendarSlice";
import { Calendars } from "../../../features/Calendars/CalendarTypes";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
export function updateDarkColor(
calendars: Record<string, Calendars>,
calendars: Record<string, Calendar>,
theme: Theme,
dispatch: ThunkDispatch<any, any, any>
) {
@@ -1,5 +1,5 @@
import { CalendarEvent } from "../../../features/Events/EventsTypes";
import { Calendars } from "../../../features/Calendars/CalendarTypes";
import { Calendar } from "../../../features/Calendars/CalendarTypes";
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
import { getCalendarDetailAsync } from "../../../features/Calendars/CalendarSlice";
import { SlotLabelContentArg } from "@fullcalendar/core";
@@ -140,7 +140,7 @@ export const eventToFullCalendarFormat = (
export const extractEvents = (
selectedCalendars: string[],
calendars: Record<string, Calendars>,
calendars: Record<string, Calendar>,
userAddress?: string,
hideDeclinedEvents?: boolean | null
) => {
@@ -272,7 +272,7 @@ export function getCalendarVisibility(acl: AclEntry[]): "private" | "public" {
}
export async function updateTempCalendar(
tempcalendars: Record<string, Calendars>,
tempcalendars: Record<string, Calendar>,
event: CalendarEvent,
dispatch: ThunkDispatch<any, any, any>,
calendarRange: { start: Date; end: Date }