import { useEffect, useState } from "react";
import { deleteEventAsync, putEventAsync } from "../Calendars/CalendarSlice";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import AttendeeSelector from "../../components/Attendees/AttendeeSearch";
import {
Popover,
Button,
Box,
Typography,
ButtonGroup,
Card,
CardContent,
Divider,
IconButton,
Avatar,
Badge,
Modal,
TextField,
CardHeader,
FormControl,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
Checkbox,
FormControlLabel,
CardActions,
Link,
} from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import CloseIcon from "@mui/icons-material/Close";
import VideocamIcon from "@mui/icons-material/Videocam";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import CircleIcon from "@mui/icons-material/Circle";
import CancelIcon from "@mui/icons-material/Cancel";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import { userAttendee } from "../User/userDataTypes";
import { TIMEZONES } from "../../utils/timezone-data";
import { Calendars } from "../Calendars/CalendarTypes";
import { CalendarEvent } from "./EventsTypes";
import { isValidUrl } from "../../utils/apiUtils";
import { formatLocalDateTime } from "./EventModal";
export default function EventDisplayModal({
eventId,
calId,
open,
onClose,
}: {
eventId: string;
calId: string;
open: boolean;
onClose: (event: {}, reason: "backdropClick" | "escapeKeyDown") => void;
}) {
const dispatch = useAppDispatch();
const calendar = useAppSelector((state) => state.calendars.list[calId]);
const event = useAppSelector(
(state) => state.calendars.list[calId]?.events[eventId]
);
const user = useAppSelector((state) => state.user);
const [showAllAttendees, setShowAllAttendees] = useState(false);
const [showMore, setShowMore] = useState(false);
const calendars = useAppSelector((state) =>
Object.values(state.calendars.list)
);
const userPersonnalCalendars: Calendars[] = calendars.filter(
(c) => c.id?.split("/")[0] === user.userData.openpaasId
);
// Form state
const [title, setTitle] = useState(event?.title ?? "");
const [description, setDescription] = useState(event?.description ?? "");
const [location, setLocation] = useState(event?.location ?? "");
const [start, setStart] = useState(
formatLocalDateTime(new Date(event?.start ?? Date.now()))
);
const [end, setEnd] = useState(
formatLocalDateTime(new Date(event?.end ?? Date.now()))
);
const [allday, setAllDay] = useState(event?.allday);
const [repetition, setRepetition] = useState(event?.repetition ?? "");
const [alarm, setAlarm] = useState("");
const [eventClass, setEventClass] = useState(event?.class ?? "PUBLIC");
const [timezone, setTimezone] = useState(event?.timezone ?? "UTC");
const [calendarid, setCalendarid] = useState(
event?.calId.split("/")[0] === user.userData.openpaasId
? userPersonnalCalendars.findIndex((cal) => cal.id === calId)
: calendars.findIndex((cal) => cal.id === calId)
);
const [attendees, setAttendees] = useState(
(event?.attendee || []).filter(
(a) => a.cal_address !== event?.organizer?.cal_address
)
);
const currentUserAttendee = event?.attendee?.find(
(person) => person.cal_address === user.userData.email
);
const organizer = event?.attendee?.find(
(a) => a.cal_address === event?.organizer?.cal_address
);
const isOwn = organizer?.cal_address === user.userData.email;
const isOwnCal = userPersonnalCalendars.find((cal) => cal.id === calId);
const attendeeDisplayLimit = 3;
useEffect(() => {
if (!event || !calendar) {
onClose({}, "backdropClick");
}
}, [event, calendar, onClose]);
if (!event || !calendar) return null;
function handleRSVP(rsvp: string) {
const newEvent = {
...event,
attendee: event.attendee?.map((a) =>
a.cal_address === user.userData.email ? { ...a, partstat: rsvp } : a
),
};
dispatch(putEventAsync({ cal: calendar, newEvent }));
onClose({}, "backdropClick");
}
const handleSave = () => {
const newEventUID = crypto.randomUUID();
const newEvent: CalendarEvent = {
calId,
title,
URL: event.URL ?? `/calendars/${calId}/${newEventUID}.ics`,
start: new Date(start),
end: new Date(end),
allday,
uid: event.uid ?? newEventUID,
description,
location,
repetition,
class: eventClass,
organizer: event.organizer,
timezone,
attendee: [
{
cn: event.organizer?.cn,
cal_address: event.organizer?.cal_address ?? "",
partstat: "ACCEPTED",
rsvp: "FALSE",
role: "CHAIR",
cutype: "INDIVIDUAL",
},
...attendees,
],
transp: "OPAQUE",
color: userPersonnalCalendars[calendarid]?.color,
};
dispatch(
putEventAsync({
cal: userPersonnalCalendars[calendarid],
newEvent,
})
);
onClose({}, "backdropClick");
};
const calList =
event.calId.split("/")[0] === user.userData.openpaasId
? Object.keys(userPersonnalCalendars).map((calendar, index) => (
))
: Object.keys(calendars).map((calendar, index) => (
));
return (
{/* Close button */}
onClose({}, "backdropClick")}>
{/* Title */}
setTitle(e.target.value)}
size="small"
margin="dense"
/>
{/* RSVP */}
{currentUserAttendee && isOwnCal && (
)}
{/* Calendar selector */}
Calendar
{/* Dates */}
setStart(formatLocalDateTime(new Date(e.target.value)))
}
size="small"
margin="dense"
InputLabelProps={{ shrink: true }}
/>
setEnd(formatLocalDateTime(new Date(e.target.value)))
}
size="small"
margin="dense"
InputLabelProps={{ shrink: true }}
/>
setAllDay(!allday)}
/>
}
label="All day"
/>
{/* Description & Location */}
setDescription(e.target.value)}
size="small"
margin="dense"
multiline
rows={2}
/>
setLocation(e.target.value)}
size="small"
margin="dense"
/>
{/* Video */}
{event.x_openpass_videoconference && (
}
text="Video conference available"
data={event.x_openpass_videoconference}
/>
)}
{/* Attendees */}
{event.attendee?.length > 0 && (
Attendees:
{organizer && renderAttendeeBadge(organizer, "org", true)}
{(showAllAttendees
? attendees
: attendees.slice(0, attendeeDisplayLimit)
).map((a, idx) => (
{renderAttendeeBadge(a, idx.toString())}
{
const newAttendeesList = [...attendees];
setAttendees(newAttendeesList.splice(idx, 1));
console.log(attendees, newAttendeesList);
}}
>
))}
{attendees.length > attendeeDisplayLimit && (
setShowAllAttendees(!showAllAttendees)}
>
{showAllAttendees
? "Show less"
: `Show more (${
attendees.length - attendeeDisplayLimit
} more)`}
)}
)}
{/* Extended options */}
{showMore && (
<>
Repetition
Alarm
Class
is Busy
{/* Error */}
{event.error && (
}
text={event.error}
error
/>
)}
>
)}
{
onClose({}, "backdropClick");
dispatch(
deleteEventAsync({ calId, eventId, eventURL: event.URL })
);
}}
>
{isOwn && (
)}
);
}
export function InfoRow({
icon,
text,
error = false,
data,
}: {
icon: React.ReactNode;
text: string;
error?: boolean;
data?: string;
}) {
return (
{icon}
{isValidUrl(data) && {text}}
);
}
export function renderAttendeeBadge(
a: userAttendee,
key: string,
isOrganizer?: boolean
) {
const classIcon =
a.partstat === "ACCEPTED" ? (
) : a.partstat === "DECLINED" ? (
) : null;
return (
{classIcon}
)
}
>
{a.cn || a.cal_address}
{isOrganizer && (
Organizer
)}
);
}
export function stringToColor(string: string) {
let hash = 0;
for (let i = 0; i < string.length; i++) {
hash = string.charCodeAt(i) + ((hash << 5) - hash);
}
let color = "#";
for (let i = 0; i < 3; i++) {
const value = (hash >> (i * 8)) & 0xff;
color += `00${value.toString(16)}`.slice(-2);
}
return color;
}
export function stringAvatar(name: string) {
return {
sx: { width: 24, height: 24, fontSize: 18, bgcolor: stringToColor(name) },
children: name[0],
};
}