import React from "react";
import {
Box,
Button,
Checkbox,
FormControl,
FormControlLabel,
IconButton,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
TextField,
Typography,
ToggleButtonGroup,
ToggleButton,
} from "@mui/material";
import {
Description as DescriptionIcon,
Public as PublicIcon,
Lock as LockIcon,
CameraAlt as VideocamIcon,
ContentCopy as CopyIcon,
Close as DeleteIcon,
} from "@mui/icons-material";
import AttendeeSelector from "../Attendees/AttendeeSearch";
import RepeatEvent from "./EventRepeat";
import { RepetitionObject } from "../../features/Events/EventsTypes";
import { userAttendee } from "../../features/User/userDataTypes";
import { Calendars } from "../../features/Calendars/CalendarTypes";
import {
generateMeetingLink,
addVideoConferenceToDescription,
} from "../../utils/videoConferenceUtils";
// Helper component for field with label
export const FieldWithLabel = React.memo(
({
label,
isExpanded,
children,
}: {
label: string;
isExpanded: boolean;
children: React.ReactNode;
}) => {
if (!isExpanded) {
// Normal mode: label on top
return (
{label}
{children}
);
}
// Extended mode: label on left
return (
{label}
{children}
);
}
);
FieldWithLabel.displayName = "FieldWithLabel";
interface EventFormFieldsProps {
// Form state
title: string;
setTitle: (title: string) => void;
description: string;
setDescription: (description: string) => void;
location: string;
setLocation: (location: string) => void;
start: string;
setStart: (start: string) => void;
end: string;
setEnd: (end: string) => void;
allday: boolean;
setAllDay: (allday: boolean) => void;
repetition: RepetitionObject;
setRepetition: (repetition: RepetitionObject) => void;
typeOfAction?: "solo" | "all";
attendees: userAttendee[];
setAttendees: (attendees: userAttendee[]) => void;
alarm: string;
setAlarm: (alarm: string) => void;
busy: string;
setBusy: (busy: string) => void;
eventClass: string;
setEventClass: (eventClass: string) => void;
timezone: string;
setTimezone: (timezone: string) => void;
calendarid: number;
setCalendarid: (calendarid: number) => void;
hasVideoConference: boolean;
setHasVideoConference: (hasVideoConference: boolean) => void;
meetingLink: string | null;
setMeetingLink: (meetingLink: string | null) => void;
// UI state
showMore: boolean;
showDescription: boolean;
setShowDescription: (showDescription: boolean) => void;
showRepeat: boolean;
setShowRepeat: (showRepeat: boolean) => void;
// Data
userPersonnalCalendars: Calendars[];
timezoneList: {
zones: string[];
browserTz: string;
getTimezoneOffset: (tzName: string) => string;
};
// Event handlers
onStartChange?: (newStart: string) => void;
onEndChange?: (newEnd: string) => void;
onAllDayChange?: (newAllDay: boolean) => void;
onCalendarChange?: (newCalendarId: number) => void;
}
export default function EventFormFields({
title,
setTitle,
description,
setDescription,
location,
setLocation,
start,
setStart,
end,
setEnd,
allday,
setAllDay,
repetition,
setRepetition,
typeOfAction,
attendees,
setAttendees,
alarm,
setAlarm,
busy,
setBusy,
eventClass,
setEventClass,
timezone,
setTimezone,
calendarid,
setCalendarid,
hasVideoConference,
setHasVideoConference,
meetingLink,
setMeetingLink,
showMore,
showDescription,
setShowDescription,
showRepeat,
setShowRepeat,
userPersonnalCalendars,
timezoneList,
onStartChange,
onEndChange,
onAllDayChange,
onCalendarChange,
}: EventFormFieldsProps) {
const handleAddVideoConference = () => {
const newMeetingLink = generateMeetingLink();
const updatedDescription = addVideoConferenceToDescription(
description,
newMeetingLink
);
setDescription(updatedDescription);
setHasVideoConference(true);
setMeetingLink(newMeetingLink);
};
const handleCopyMeetingLink = async () => {
if (meetingLink) {
try {
await navigator.clipboard.writeText(meetingLink);
} catch (err) {
console.error("Failed to copy link:", err);
}
}
};
const handleDeleteVideoConference = () => {
// Remove video conference footer from description
const updatedDescription = description.replace(
/\nVisio: https?:\/\/[^\s]+/,
""
);
setDescription(updatedDescription);
setHasVideoConference(false);
setMeetingLink(null);
};
const handleStartChange = (newStart: string) => {
setStart(newStart);
onStartChange?.(newStart);
};
const handleEndChange = (newEnd: string) => {
setEnd(newEnd);
onEndChange?.(newEnd);
};
const handleAllDayChange = (newAllDay: boolean) => {
setAllDay(newAllDay);
onAllDayChange?.(newAllDay);
};
const handleCalendarChange = (newCalendarId: number) => {
setCalendarid(newCalendarId);
onCalendarChange?.(newCalendarId);
};
return (
<>
setTitle(e.target.value)}
size="small"
margin="dense"
/>
}
onClick={() => setShowDescription(true)}
size="small"
sx={{
textTransform: "none",
color: "text.secondary",
display: showDescription ? "none" : "flex",
}}
>
Add description
{showDescription && (
setDescription(e.target.value)}
size="small"
margin="dense"
multiline
rows={2}
/>
)}
{showMore && (
Start
)}
handleStartChange(e.target.value)}
size="small"
margin="dense"
InputLabelProps={{ shrink: true }}
/>
{showMore && (
End
)}
handleEndChange(e.target.value)}
size="small"
margin="dense"
InputLabelProps={{ shrink: true }}
/>
{
const endDate = new Date(end);
const startDate = new Date(start);
const newAllDay = !allday;
setAllDay(newAllDay);
if (endDate.getDate() === startDate.getDate()) {
endDate.setDate(startDate.getDate() + 1);
setEnd(formatLocalDateTime(endDate));
}
handleAllDayChange(newAllDay);
}}
/>
}
label="All day"
/>
{
const newShowRepeat = !showRepeat;
setShowRepeat(newShowRepeat);
if (newShowRepeat) {
setRepetition({
freq: "daily",
interval: 1,
occurrences: 0,
endDate: "",
byday: null,
} as RepetitionObject);
} else {
setRepetition({
freq: "",
interval: 1,
occurrences: 0,
endDate: "",
byday: null,
} as RepetitionObject);
}
}}
/>
}
label="Repeat"
/>
{showRepeat && (
)}
}
onClick={handleAddVideoConference}
size="medium"
sx={{
textTransform: "none",
color: "text.secondary",
display: hasVideoConference ? "none" : "flex",
}}
>
Add Visio conference
{hasVideoConference && meetingLink && (
<>
}
onClick={() => window.open(meetingLink, "_blank")}
size="medium"
variant="contained"
sx={{
textTransform: "none",
mr: 1,
}}
>
Join Visio conference
>
)}
setLocation(e.target.value)}
size="small"
margin="dense"
/>
{!showMore && (
Calendar
)}
{/* Extended options */}
{showMore && (
<>
{
if (newValue !== null) {
setEventClass(newValue);
}
}}
size="small"
>
All
Participants
>
)}
>
);
}
export function formatLocalDateTime(date: Date): string {
const pad = (n: number) => n.toString().padStart(2, "0");
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
date.getDate()
)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
}
export function formatDateTimeInTimezone(
isoString: string,
timezone: string
): string {
// Parse the ISO string as UTC
const utcDate = new Date(isoString);
// Format the date in the target timezone
const formatter = new Intl.DateTimeFormat("en-CA", {
timeZone: timezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
const parts = formatter.formatToParts(utcDate);
const getValue = (type: string) =>
parts.find((p) => p.type === type)?.value || "";
return `${getValue("year")}-${getValue("month")}-${getValue("day")}T${getValue("hour")}:${getValue("minute")}`;
}