Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -10,6 +10,13 @@ jest.mock("@/features/Calendars/services/helpers");
|
||||
jest.mock("@/features/Calendars/CalendarApi");
|
||||
jest.mock("@/utils/errorUtils");
|
||||
jest.mock("@/features/Calendars/utils/normalizeCalendar");
|
||||
jest.mock("@/utils/getAccessiblePair", () => ({
|
||||
getAccessiblePair: jest.fn().mockReturnValue("#FFF"),
|
||||
}));
|
||||
|
||||
jest.mock("@mui/material/styles", () => ({
|
||||
createTheme: jest.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
const mockedGetOpenPaasUser = getOpenPaasUser as jest.Mock;
|
||||
const mockedFetchOwnerData = fetchOwnerData as jest.Mock;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getAccessiblePair } from "@/components/Calendar/utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
import { stringAvatar } from "@/components/Event/utils/eventUtils";
|
||||
import { useUserSearch } from "./useUserSearch";
|
||||
import { SnackbarAlert } from "@/components/Loading/SnackBarAlert";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getAccessiblePair } from "@/components/Calendar/utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
import { useUserSearch } from "./useUserSearch";
|
||||
import { ResourceIcon } from "./ResourceIcon";
|
||||
import { SnackbarAlert } from "@/components/Loading/SnackBarAlert";
|
||||
|
||||
@@ -20,7 +20,7 @@ import interactionPlugin from "@fullcalendar/interaction";
|
||||
import momentTimezonePlugin from "@fullcalendar/moment-timezone";
|
||||
import FullCalendar from "@fullcalendar/react";
|
||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||
import { Box, Button, radius, useTheme } from "@linagora/twake-mui";
|
||||
import { Box, Button, radius } from "@linagora/twake-mui";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { MutableRefObject, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
@@ -38,7 +38,6 @@ import { useCalendarViewHandlers } from "./hooks/useCalendarViewHandlers";
|
||||
import { MiniCalendar } from "./MiniCalendar";
|
||||
import { TempCalendarsInput } from "./TempCalendarsInput";
|
||||
import { TimezoneSelector } from "./TimezoneSelector";
|
||||
import { updateDarkColor } from "./utils/calendarColorsUtils";
|
||||
import {
|
||||
eventToFullCalendarFormat,
|
||||
extractEvents,
|
||||
@@ -75,7 +74,6 @@ export default function CalendarApp({
|
||||
const userId =
|
||||
useAppSelector((state) => state.user.userData?.openpaasId) ?? "";
|
||||
const dispatch = useAppDispatch();
|
||||
const theme = useTheme();
|
||||
const view = useAppSelector((state) => state.settings.view);
|
||||
const userData = useAppSelector((state) => state.user.userData);
|
||||
const workingDays = useAppSelector(
|
||||
@@ -103,13 +101,6 @@ export default function CalendarApp({
|
||||
const [selectedCalendars, setSelectedCalendars] =
|
||||
useState<string[]>(storedCalendars);
|
||||
|
||||
const calendarLightSignature = useMemo(() => {
|
||||
return Object.values(calendars || {})
|
||||
.map((cal) => `${cal.id}:${cal.color?.light ?? ""}`)
|
||||
.sort()
|
||||
.join("|");
|
||||
}, [calendars]);
|
||||
|
||||
const calendarIdsString = useMemo(
|
||||
() =>
|
||||
Object.keys(calendars || {})
|
||||
@@ -167,22 +158,6 @@ export default function CalendarApp({
|
||||
}
|
||||
}, [selectedCalendars, calendarIds.length]);
|
||||
|
||||
const prevCalendarLightSignature = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!calendarLightSignature) {
|
||||
prevCalendarLightSignature.current = calendarLightSignature;
|
||||
return;
|
||||
}
|
||||
|
||||
if (prevCalendarLightSignature.current === calendarLightSignature) {
|
||||
return;
|
||||
}
|
||||
|
||||
prevCalendarLightSignature.current = calendarLightSignature;
|
||||
updateDarkColor(calendars || {}, theme, dispatch);
|
||||
}, [calendarLightSignature, calendars, theme, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (calendarIds.length === 0) return;
|
||||
const validCalendarIds = new Set(calendarIds);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { useState, useEffect } from "react";
|
||||
import { HexColorPicker } from "react-colorful";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { getAccessiblePair } from "./utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
import { defaultColors } from "@/utils/defaultColors";
|
||||
|
||||
export function ColorPicker({
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useRef, useState } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { ResponsiveDialog } from "../Dialog";
|
||||
import { ColorPicker } from "./CalendarColorPicker";
|
||||
import { getAccessiblePair } from "./utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
import { defaultColors } from "@/utils/defaultColors";
|
||||
import { addCalendarResourceAsync } from "@/features/Calendars/api/addCalendarResourceAsync";
|
||||
import { Resource, ResourceSearch } from "../Attendees/ResourceSearch";
|
||||
|
||||
@@ -20,7 +20,7 @@ import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
||||
import { ResponsiveDialog } from "../Dialog";
|
||||
import { stringAvatar } from "../Event/utils/eventUtils";
|
||||
import { ColorPicker } from "./CalendarColorPicker";
|
||||
import { getAccessiblePair } from "./utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
import { defaultColors } from "@/utils/defaultColors";
|
||||
|
||||
interface CalendarWithOwner {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { TextField, useTheme } from "@linagora/twake-mui";
|
||||
import { useRef } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
||||
import { getAccessiblePair } from "./utils/calendarColorsUtils";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
|
||||
const requestControllers = new Map<string, AbortController>();
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import { AppDispatch } from "@/app/store";
|
||||
import { updateCalColor } from "@/features/Calendars/CalendarSlice";
|
||||
import { Calendar } from "@/features/Calendars/CalendarTypes";
|
||||
import { darken, getContrastRatio, lighten, Theme } from "@linagora/twake-mui";
|
||||
import { defaultColors } from "@/utils/defaultColors";
|
||||
|
||||
export function updateDarkColor(
|
||||
calendars: Record<string, Calendar>,
|
||||
theme: Theme,
|
||||
dispatch: AppDispatch
|
||||
) {
|
||||
Object.values(calendars).forEach((cal) => {
|
||||
if (!cal?.color?.light || typeof cal.color.light !== "string") return;
|
||||
const baseColor = cal.color.light;
|
||||
|
||||
const isDefault = Object.values(defaultColors).find(
|
||||
(c) => c.light === baseColor
|
||||
);
|
||||
const darkColor = isDefault
|
||||
? isDefault.dark
|
||||
: getAccessiblePair(baseColor, theme);
|
||||
|
||||
if (cal.color?.dark === darkColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
updateCalColor({
|
||||
id: cal.id,
|
||||
color: { light: baseColor, dark: darkColor },
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAccessiblePair(baseColor: string, theme: Theme): string {
|
||||
if (typeof baseColor !== "string") {
|
||||
return theme.palette.getContrastText("#000");
|
||||
}
|
||||
|
||||
const contrastToBlack = getContrastRatio(baseColor, "#000");
|
||||
const contrastToWhite = getContrastRatio(baseColor, "#fff");
|
||||
const isLight = contrastToBlack > contrastToWhite;
|
||||
|
||||
const adjusted = isLight ? darken(baseColor, 0.6) : lighten(baseColor, 0.7);
|
||||
|
||||
// Check if contrast meets 4.5
|
||||
const contrast = getContrastRatio(baseColor, adjusted);
|
||||
if (contrast >= 4.5) return adjusted;
|
||||
|
||||
if (isLight) {
|
||||
return "#ffffffff";
|
||||
}
|
||||
|
||||
return theme.palette.getContrastText(baseColor);
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { getCalendar } from "../CalendarApi";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { extractCalendarEvents } from "../utils/extractCalendarEvents";
|
||||
import { defaultColors } from "@/utils/defaultColors";
|
||||
import { type RootState } from "@/app/store";
|
||||
|
||||
export const getCalendarDetailAsync = createAsyncThunk<
|
||||
@@ -42,16 +41,15 @@ export const getCalendarDetailAsync = createAsyncThunk<
|
||||
match,
|
||||
signal
|
||||
)) as CalendarData;
|
||||
|
||||
const color = calendar["apple:color"]
|
||||
? { light: calendar["apple:color"], dark: calendar["apple:color"] }
|
||||
: defaultColors[0];
|
||||
const syncToken = calendar._embedded?.["sync-token"];
|
||||
|
||||
const items = calendar._embedded?.["dav:item"];
|
||||
const events: CalendarEvent[] = Array.isArray(items)
|
||||
? items.flatMap((item: CalendarItem) =>
|
||||
extractCalendarEvents(item, { cal: calendarStored, color })
|
||||
extractCalendarEvents(item, {
|
||||
cal: calendarStored,
|
||||
color: calendarStored.color,
|
||||
})
|
||||
)
|
||||
: [];
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import { CalendarData } from "../types/CalendarData";
|
||||
import { RejectedError } from "../types/RejectedError";
|
||||
import { normalizeCalendar } from "../utils/normalizeCalendar";
|
||||
import { fetchOwnerData } from "./helpers";
|
||||
import { createTheme } from "@mui/material/styles";
|
||||
import { getAccessiblePair } from "@/utils/getAccessiblePair";
|
||||
|
||||
const theme = createTheme();
|
||||
|
||||
export const getCalendarsListAsync = createAsyncThunk<
|
||||
{ importedCalendars: Record<string, Calendar>; errors: string },
|
||||
@@ -77,10 +81,11 @@ export const getCalendarsListAsync = createAsyncThunk<
|
||||
emails: [],
|
||||
};
|
||||
|
||||
const color = cal["apple:color"]
|
||||
const rawColor = cal["apple:color"];
|
||||
const color = rawColor
|
||||
? {
|
||||
light: cal["apple:color"],
|
||||
dark: "#fff",
|
||||
light: rawColor,
|
||||
dark: getAccessiblePair(rawColor, theme),
|
||||
}
|
||||
: defaultColors[0];
|
||||
|
||||
@@ -126,10 +131,6 @@ export const getCalendarsListAsync = createAsyncThunk<
|
||||
if (fetchedCal) {
|
||||
importedCalendars[id] = {
|
||||
...fetchedCal,
|
||||
color: {
|
||||
...existingCal.color,
|
||||
light: fetchedCal.color?.light,
|
||||
},
|
||||
events: existingCal.events || {},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { darken, getContrastRatio, lighten, Theme } from "@linagora/twake-mui";
|
||||
|
||||
export function getAccessiblePair(baseColor: string, theme: Theme): string {
|
||||
if (typeof baseColor !== "string") {
|
||||
return theme.palette.getContrastText("#000");
|
||||
}
|
||||
|
||||
const contrastToBlack = getContrastRatio(baseColor, "#000");
|
||||
const contrastToWhite = getContrastRatio(baseColor, "#fff");
|
||||
const isLight = contrastToBlack > contrastToWhite;
|
||||
|
||||
const adjusted = isLight ? darken(baseColor, 0.6) : lighten(baseColor, 0.7);
|
||||
|
||||
// Check if contrast meets 4.5
|
||||
const contrast = getContrastRatio(baseColor, adjusted);
|
||||
if (contrast >= 4.5) return adjusted;
|
||||
|
||||
if (isLight) {
|
||||
return "#ffffffff";
|
||||
}
|
||||
|
||||
return theme.palette.getContrastText(baseColor);
|
||||
}
|
||||
Reference in New Issue
Block a user