Files
workavia-calendar-front/src/components/Calendar/TempCalendarsInput.tsx
T
Camille Moussu 2c78a037a9 allow external attendees (#141)
* [#122] added external attendees

* fixup! [#122] added external attendees

* fixup! [#122] added external attendees

* Update src/components/Attendees/AttendeeSearch.tsx

---------

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
Co-authored-by: Benoit TELLIER <btellier@linagora.com>
2025-09-25 11:25:22 +02:00

162 lines
4.4 KiB
TypeScript

import { useState, useRef, useMemo } from "react";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import {
getTempCalendarsListAsync,
removeTempCal,
} from "../../features/Calendars/CalendarSlice";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import { CalendarEvent } from "../../features/Events/EventsTypes";
import { User, PeopleSearch } from "../Attendees/PeopleSearch";
const requestControllers = new Map<string, AbortController>();
export function TempCalendarsInput({
setAnchorEl,
setTempEvent,
selectedCalendars,
setSelectedCalendars,
}: {
setAnchorEl: Function;
setTempEvent: Function;
selectedCalendars: string[];
setSelectedCalendars: Function;
}) {
const [tempUsers, setTempUsers] = useState<User[]>([]);
const dispatch = useAppDispatch();
const tempcalendars =
useAppSelector((state) => state.calendars.templist) ?? {};
const calendars = useAppSelector((state) => state.calendars.list);
const prevUsersRef = useRef<User[]>([]);
const userColors = new Map<string, string>();
const handleUserChange = async (_: any, users: User[]) => {
setTempUsers(users);
const prevUsers = prevUsersRef.current;
const addedUsers = users.filter(
(u) => !prevUsers.some((p) => p.email === u.email)
);
const removedUsers = prevUsers.filter(
(p) => !users.some((u) => u.email === p.email)
);
prevUsersRef.current = users;
const { calendarsToImport, calendarsToToggle } = getCalendarsFromUsersDelta(
addedUsers,
buildEmailToCalendarMap(calendars),
selectedCalendars
);
if (calendarsToImport.length > 0) {
for (const user of calendarsToImport) {
const controller = new AbortController();
requestControllers.set(user.email, controller);
if (!userColors.has(user.email)) {
const existingColors = new Set(userColors.values());
userColors.set(user.email, generateUserColor(existingColors));
}
user.color = userColors.get(user.email)!;
dispatch(
getTempCalendarsListAsync(user, { signal: controller.signal })
);
}
}
if (calendarsToToggle.length > 0) {
setSelectedCalendars((prev: string[]) => [
...new Set([...prev, ...calendarsToToggle]),
]);
}
for (const user of removedUsers) {
const controller = requestControllers.get(user.email);
if (controller) {
controller.abort();
requestControllers.delete(user.email);
}
const calIds = buildEmailToCalendarMap(tempcalendars).get(user.email);
calIds?.forEach((id) => dispatch(removeTempCal(id)));
}
};
const handleToggleEventPreview = () => {
const newEvent: CalendarEvent = {
title: "New Event",
attendee: tempUsers.map((u) => ({
cn: u.displayName,
cal_address: u.email,
partstat: "NEED-ACTION",
role: "REQ-PARTICIPANT",
rsvp: "TRUE",
cutype: "INDIVIDUAL",
})),
} as CalendarEvent;
setTempEvent(newEvent);
setAnchorEl(document.body);
};
return (
<PeopleSearch
objectTypes={["user"]}
selectedUsers={tempUsers}
onChange={handleUserChange}
onToggleEventPreview={handleToggleEventPreview}
/>
);
}
function getCalendarsFromUsersDelta(
addedUsers: User[],
emailToCalendarId: Map<string, string[]>,
selectedCalendars: string[]
) {
const selectedSet = new Set(selectedCalendars);
const calendarsToImport: User[] = [];
const calendarsToToggle: string[] = [];
for (const user of addedUsers) {
const calIds = emailToCalendarId.get(user.email) ?? [];
if (!calIds || calIds.every((calId) => !selectedSet.has(calId))) {
calendarsToImport.push(user);
} else {
// calIds.forEach((calId) => calendarsToToggle.push(calId));
}
}
return { calendarsToImport, calendarsToToggle };
}
function buildEmailToCalendarMap(calRecord: Record<string, Calendars>) {
const map = new Map<string, string[]>();
for (const [id, cal] of Object.entries(calRecord)) {
cal.ownerEmails?.forEach((email) => {
const existing = map.get(email);
if (existing) {
existing.push(id);
} else {
map.set(email, [id]);
}
});
}
return map;
}
function generateUserColor(existingColors: Set<string>): string {
let color: string;
do {
const hue = Math.floor(Math.random() * 360);
color = `hsl(${hue}, 70%, 50%)`;
} while (existingColors.has(color));
return color;
}