Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
@@ -16,12 +15,10 @@ import { useI18n } from "twake-i18n";
|
||||
export function EditModeDialog({
|
||||
type,
|
||||
setOpen,
|
||||
event,
|
||||
eventAction,
|
||||
}: {
|
||||
type: string | null;
|
||||
setOpen: (e: string | null) => void;
|
||||
event: CalendarEvent;
|
||||
eventAction: (type: "solo" | "all" | undefined) => void;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
|
||||
import { EventContentArg } from "@fullcalendar/core";
|
||||
import { Card, Typography } from "@linagora/twake-mui";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
@@ -7,18 +8,30 @@ export function ErrorEventChip({
|
||||
errorHandler,
|
||||
error,
|
||||
}: {
|
||||
event: any;
|
||||
event: EventContentArg["event"];
|
||||
errorHandler: EventErrorHandler;
|
||||
error: any;
|
||||
error: unknown;
|
||||
}) {
|
||||
const hasReported = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasReported.current) {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: `${error.class} error during rendering ${event._def.extendedProps.uid || event.id}`;
|
||||
let message: string;
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else if (
|
||||
typeof error === "object" &&
|
||||
error !== null &&
|
||||
"class" in error
|
||||
) {
|
||||
message = `${String(
|
||||
(error as { class: string }).class
|
||||
)} error during rendering ${event._def.extendedProps.uid || event.id}`;
|
||||
} else {
|
||||
message = `Unknown error during rendering ${event._def.extendedProps.uid || event.id}`;
|
||||
}
|
||||
|
||||
errorHandler.reportError(
|
||||
event._def.extendedProps.uid || event.id,
|
||||
message
|
||||
|
||||
@@ -59,7 +59,7 @@ export function EventChip({
|
||||
const ownerEmails = new Set(
|
||||
calendar.ownerEmails?.map((e) => e.toLowerCase())
|
||||
);
|
||||
const delegated = calendar.delegated;
|
||||
// const delegated = calendar.delegated;
|
||||
|
||||
// Determine owner attendee
|
||||
const ownerAttendee = getOwnerAttendee(attendees, ownerEmails);
|
||||
@@ -258,7 +258,7 @@ export function EventChip({
|
||||
!event._def.extendedProps.allday &&
|
||||
event._def.extendedProps.organizer &&
|
||||
!showCompact &&
|
||||
(window as any).displayOrgAvatar && (
|
||||
window.displayOrgAvatar && (
|
||||
<Avatar
|
||||
children={OrganizerAvatar.children}
|
||||
color={OrganizerAvatar.color}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { EventErrorHandler } from "@/components/Error/EventErrorHandler";
|
||||
import { Calendar } from "@/features/Calendars/CalendarTypes";
|
||||
import { userAttendee } from "@/features/User/models/attendee";
|
||||
import { EventContentArg } from "@fullcalendar/core";
|
||||
import { getContrastRatio } from "@linagora/twake-mui";
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
|
||||
@@ -12,7 +13,7 @@ import { EVENT_DURATION } from "./EventChip";
|
||||
const COMPACT_WIDTH_THRESHOLD = 100;
|
||||
|
||||
export interface EventChipProps {
|
||||
arg: any;
|
||||
arg: EventContentArg["event"];
|
||||
calendars: Record<string, Calendar>;
|
||||
tempcalendars: Record<string, Calendar>;
|
||||
errorHandler: EventErrorHandler;
|
||||
@@ -23,9 +24,9 @@ export interface IconDisplayConfig {
|
||||
needAction: boolean;
|
||||
private: boolean;
|
||||
}
|
||||
export function getEventDuration(event: any): number {
|
||||
return moment(event._instance.range.end).diff(
|
||||
moment(event._instance.range.start),
|
||||
export function getEventDuration(event: EventContentArg["event"]): number {
|
||||
return moment(event._instance?.range.end).diff(
|
||||
moment(event._instance?.range.start),
|
||||
"minutes"
|
||||
);
|
||||
}
|
||||
@@ -34,7 +35,10 @@ export function getBestColor(colors: { light: string; dark: string }): string {
|
||||
const contrastToLight = getContrastRatio(colors?.light, "#fff");
|
||||
return contrastToDark > contrastToLight ? colors?.dark : colors?.light;
|
||||
}
|
||||
export function getEventTimes(event: any, timeZone: string) {
|
||||
export function getEventTimes(
|
||||
event: EventContentArg["event"],
|
||||
timeZone: string
|
||||
) {
|
||||
return {
|
||||
startTime: moment.tz(event.start, timeZone).format("HH:mm"),
|
||||
endTime: moment.tz(event.end, timeZone).format("HH:mm"),
|
||||
@@ -52,7 +56,7 @@ export function getOwnerAttendee(
|
||||
export function getTitleStyle(
|
||||
bestColor: string,
|
||||
partstat?: string,
|
||||
calendar?: any
|
||||
calendar?: Calendar
|
||||
): React.CSSProperties {
|
||||
const baseStyle: React.CSSProperties = {
|
||||
fontFamily: "Roboto",
|
||||
@@ -122,7 +126,7 @@ export function getCardStyle(
|
||||
bestColor: string,
|
||||
eventLength: number,
|
||||
partstat?: string,
|
||||
calendar?: any
|
||||
calendar?: Calendar
|
||||
): React.CSSProperties {
|
||||
const baseStyle: React.CSSProperties = getCardVariantStyle(
|
||||
getEventVariant(eventLength),
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import { CalendarEvent } from "@/features/Events/EventsTypes";
|
||||
import { MenuItem } from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
|
||||
export default function EventDuplication({
|
||||
onClose,
|
||||
event,
|
||||
onOpenDuplicate,
|
||||
}: {
|
||||
onClose: Function;
|
||||
event: CalendarEvent;
|
||||
onOpenDuplicate?: () => void;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -21,17 +21,15 @@ import {
|
||||
ToggleButton,
|
||||
ToggleButtonGroup,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@linagora/twake-mui";
|
||||
import { alpha } from "@mui/material/styles";
|
||||
import {
|
||||
Close as DeleteIcon,
|
||||
ContentCopy as CopyIcon,
|
||||
Public as PublicIcon,
|
||||
LocationOn as LocationIcon,
|
||||
Public as PublicIcon,
|
||||
} from "@mui/icons-material";
|
||||
import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
|
||||
import LockOutlineIcon from "@mui/icons-material/LockOutline";
|
||||
import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
|
||||
import React from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import AttendeeSelector from "../Attendees/AttendeeSearch";
|
||||
@@ -163,7 +161,6 @@ export default function EventFormFields({
|
||||
onHasEndDateChangedChange,
|
||||
}: EventFormFieldsProps) {
|
||||
const { t } = useI18n();
|
||||
const theme = useTheme();
|
||||
|
||||
// Internal state for 4 separate fields
|
||||
const [startDate, setStartDate] = React.useState("");
|
||||
@@ -377,7 +374,6 @@ export default function EventFormFields({
|
||||
showMore,
|
||||
});
|
||||
}, [
|
||||
title,
|
||||
startDate,
|
||||
startTime,
|
||||
endDate,
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function RepeatEvent({
|
||||
}: {
|
||||
repetition: RepetitionObject;
|
||||
eventStart: Date;
|
||||
setRepetition: Function;
|
||||
setRepetition: (repetition: RepetitionObject) => void;
|
||||
isOwn?: boolean;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -83,7 +83,6 @@ export const DateTimeFields: React.FC<DateTimeFieldsProps> = ({
|
||||
showMore,
|
||||
hasEndDateChanged,
|
||||
showEndDate,
|
||||
onToggleEndDate,
|
||||
validation,
|
||||
onStartDateChange,
|
||||
onStartTimeChange,
|
||||
|
||||
@@ -88,7 +88,7 @@ export const DateTimeSummary: React.FC<DateTimeSummaryProps> = ({
|
||||
const offset = getTimezoneOffset(tz, dateForOffset);
|
||||
const tzName = tz.replace(/_/g, " ");
|
||||
return `(${offset}) ${tzName}`;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return tz.replace(/_/g, " ");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,12 +19,12 @@ import { parseTimeInput } from "../utils/dateTimeHelpers";
|
||||
|
||||
type FieldType = "date" | "time" | "date-time";
|
||||
|
||||
type GenericPickerFieldProps = PickerFieldProps<any, any, any> & {
|
||||
type GenericPickerFieldProps = PickerFieldProps<Dayjs, false, false> & {
|
||||
fieldType: FieldType;
|
||||
validator: (
|
||||
value: any,
|
||||
value: Dayjs | null,
|
||||
context: PickerValidationScope,
|
||||
adapter: PickerFieldAdapter<any>
|
||||
adapter: PickerFieldAdapter<Dayjs>
|
||||
) => string | null;
|
||||
};
|
||||
|
||||
@@ -223,7 +223,7 @@ function EditableTimePickerField(props: GenericPickerFieldProps) {
|
||||
dispatchCloseOtherPickers();
|
||||
};
|
||||
|
||||
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
const handleBlur = (_e: React.FocusEvent<HTMLInputElement>) => {
|
||||
// If dropdown is open, don't parse input
|
||||
// MUI will handle selection and sync value via useEffect
|
||||
if (pickerContext.open) {
|
||||
|
||||
@@ -12,15 +12,16 @@ import {
|
||||
useValidation,
|
||||
validateDate,
|
||||
} from "@mui/x-date-pickers/validation";
|
||||
import { Dayjs } from "dayjs";
|
||||
|
||||
type FieldType = "date" | "time" | "date-time";
|
||||
|
||||
type GenericPickerFieldProps = PickerFieldProps<any, any, any> & {
|
||||
type GenericPickerFieldProps = PickerFieldProps<Dayjs, false, false> & {
|
||||
fieldType: FieldType;
|
||||
validator: (
|
||||
value: any,
|
||||
value: Dayjs | null,
|
||||
context: PickerValidationScope,
|
||||
adapter: PickerFieldAdapter<any>
|
||||
adapter: PickerFieldAdapter<Dayjs>
|
||||
) => string | null;
|
||||
};
|
||||
|
||||
|
||||
@@ -119,28 +119,18 @@ export async function handleRSVP(
|
||||
export function handleDelete(
|
||||
isRecurring: boolean,
|
||||
typeOfAction: "solo" | "all" | undefined,
|
||||
onClose: (event: {}, reason: "backdropClick" | "escapeKeyDown") => void,
|
||||
dispatch: Function,
|
||||
onClose: (event: unknown, reason: "backdropClick" | "escapeKeyDown") => void,
|
||||
dispatch: AppDispatch,
|
||||
calendar: Calendar,
|
||||
event: CalendarEvent,
|
||||
calId: string,
|
||||
eventId: string
|
||||
) {
|
||||
if (isRecurring) {
|
||||
onClose({}, "backdropClick");
|
||||
if (typeOfAction === "solo") {
|
||||
dispatch(deleteEventInstanceAsync({ cal: calendar, event }));
|
||||
} else {
|
||||
dispatch(
|
||||
deleteEventAsync({
|
||||
calId,
|
||||
eventId,
|
||||
eventURL: event.URL,
|
||||
})
|
||||
);
|
||||
}
|
||||
onClose({}, "backdropClick");
|
||||
|
||||
if (isRecurring && typeOfAction === "solo") {
|
||||
dispatch(deleteEventInstanceAsync({ cal: calendar, event }));
|
||||
} else {
|
||||
onClose({}, "backdropClick");
|
||||
dispatch(
|
||||
deleteEventAsync({
|
||||
calId,
|
||||
|
||||
@@ -16,7 +16,7 @@ import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
export function renderAttendeeBadge(
|
||||
a: userAttendee,
|
||||
key: string,
|
||||
t: Function,
|
||||
t: (key: string) => string,
|
||||
isFull?: boolean,
|
||||
isOrganizer?: boolean
|
||||
) {
|
||||
@@ -110,7 +110,9 @@ export async function refreshCalendars(
|
||||
) {
|
||||
if (process.env.NODE_ENV === "test") return;
|
||||
|
||||
!calType && (await dispatch(getCalendarsListAsync()));
|
||||
if (!calType) {
|
||||
await dispatch(getCalendarsListAsync());
|
||||
}
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
calendars.map((calendar) =>
|
||||
|
||||
Reference in New Issue
Block a user