refactor: stabilize calendar loading effects and menubar redirect

- Memoize calendar range strings and stabilize effect deps
- Guard updateDarkColor to avoid dispatch loops
- Add resilient cache-clear handling with refs
- Memoize calendar/temp ids to prevent rerenders
- Update event handler hooks with missing deps
- Add guards and dependency fixes across Calendar effects
This commit is contained in:
lenhanphung
2025-11-07 16:42:06 +07:00
committed by Benoit TELLIER
parent 990e290066
commit ffe204d60b
13 changed files with 650 additions and 163 deletions
+11 -11
View File
@@ -40,8 +40,16 @@ interface RejectedError {
export const getCalendarsListAsync = createAsyncThunk<
{ importedCalendars: Record<string, Calendars>; errors: string }, // Return type
void, // Arg type
{ rejectValue: RejectedError } // ThunkAPI config
>("calendars/getCalendars", async (_, { rejectWithValue }) => {
{ rejectValue: RejectedError; state: any } // ThunkAPI config
>("calendars/getCalendars", async (_, { rejectWithValue, getState }) => {
const state = getState() as any;
if (Object.keys(state.calendars.list).length > 0) {
return {
importedCalendars: state.calendars.list,
errors: "",
};
}
try {
const importedCalendars: Record<string, Calendars> = {};
const user = (await getOpenPaasUser()) as Record<string, string>;
@@ -106,15 +114,7 @@ export const getCalendarsListAsync = createAsyncThunk<
}
normalizedCalendars.forEach(
({
cal,
description,
delegated,
link,
id,
ownerId,
visibility,
}) => {
({ cal, description, delegated, link, id, ownerId, visibility }) => {
const ownerData = ownerDataMap.get(ownerId) || {
firstname: "",
lastname: "Unknown User",
+2 -2
View File
@@ -59,10 +59,10 @@ function EventPopover({
const selectPersonalCalendars = createSelector(
(state: any) => state.calendars,
(calendars: any) =>
Object.keys(calendars.list)
Object.keys(calendars.list || {})
.map((id) => {
if (id.split("/")[0] === userId) {
return calendars.list[id];
return calendars.list?.[id];
}
return {} as Calendars;
})
+2 -2
View File
@@ -17,8 +17,8 @@ export default function ImportAlert() {
return (
<>
{Object.keys(calendars).map((calendarId) =>
calendars[calendarId]?.events
{Object.keys(calendars || {}).map((calendarId) =>
calendars?.[calendarId]?.events
? Object.keys(calendars[calendarId]?.events)
.filter((id) => calendars[calendarId]?.events[id].error)
.map((id) => {
+39 -30
View File
@@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useRef } from "react";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { Auth } from "./oidcAuth";
import { Loading } from "../../components/Loading/Loading";
@@ -11,41 +11,50 @@ export function HandleLogin() {
const userData = useAppSelector((state) => state.user);
const calendars = useAppSelector((state) => state.calendars);
const dispatch = useAppDispatch();
const hasInitiatedRef = useRef(false);
const calendarsLoadingRef = useRef(false);
useEffect(() => {
if (hasInitiatedRef.current) return;
if (userData.userData) return;
if (Object.keys(calendars.list).length > 0) return;
if (calendarsLoadingRef.current) return;
hasInitiatedRef.current = true;
const initiateLogin = async () => {
if (!userData.userData) {
const savedToken = sessionStorage.getItem("tokenSet")
? JSON.parse(sessionStorage.getItem("tokenSet")!)
: null;
const savedUser = sessionStorage.getItem("userData")
? JSON.parse(sessionStorage.getItem("userData")!)
: null;
const savedToken = sessionStorage.getItem("tokenSet")
? JSON.parse(sessionStorage.getItem("tokenSet")!)
: null;
const savedUser = sessionStorage.getItem("userData")
? JSON.parse(sessionStorage.getItem("userData")!)
: null;
if (savedToken && savedUser) {
dispatch(setTokens(savedToken));
dispatch(setUserData(savedUser));
await dispatch(getOpenPaasUserDataAsync());
await dispatch(getCalendarsListAsync());
dispatch(push("/calendar"));
return;
}
const loginurl = await Auth();
sessionStorage.setItem(
"redirectState",
JSON.stringify({
code_verifier: loginurl.code_verifier,
state: loginurl.state,
})
);
redirectTo(loginurl.redirectTo);
if (savedToken && savedUser) {
dispatch(setTokens(savedToken));
dispatch(setUserData(savedUser));
await dispatch(getOpenPaasUserDataAsync());
calendarsLoadingRef.current = true;
await dispatch(getCalendarsListAsync());
calendarsLoadingRef.current = false;
dispatch(push("/calendar"));
return;
}
const loginurl = await Auth();
sessionStorage.setItem(
"redirectState",
JSON.stringify({
code_verifier: loginurl.code_verifier,
state: loginurl.state,
})
);
redirectTo(loginurl.redirectTo);
};
initiateLogin();
}, [userData, dispatch]);
}, [userData.userData, calendars.list, dispatch]);
useEffect(() => {
if (userData.error) {
dispatch(push("/error"));
@@ -53,7 +62,7 @@ export function HandleLogin() {
if (!calendars.pending && !userData.loading && !userData.error) {
dispatch(push("/calendar"));
}
}, [calendars.pending, userData.loading]);
}, [calendars.pending, userData.loading, userData.error, dispatch]);
return <Loading />;
}
+7 -2
View File
@@ -1,6 +1,6 @@
import { useEffect, useRef } from "react";
import { Callback } from "./oidcAuth";
import { useAppDispatch } from "../../app/hooks";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { push } from "redux-first-history";
import { getOpenPaasUserDataAsync, setTokens, setUserData } from "./userSlice";
import { Loading } from "../../components/Loading/Loading";
@@ -9,6 +9,7 @@ import { getCalendarsListAsync } from "../Calendars/CalendarSlice";
export function CallbackResume() {
const dispatch = useAppDispatch();
const hasRun = useRef(false);
const calendarsLoadingRef = useRef(false);
const saved = sessionStorage.getItem("redirectState")
? JSON.parse(sessionStorage.getItem("redirectState")!)
: null;
@@ -23,7 +24,11 @@ export function CallbackResume() {
dispatch(setUserData(data?.userinfo));
dispatch(setTokens(data?.tokenSet));
await dispatch(getOpenPaasUserDataAsync());
await dispatch(getCalendarsListAsync());
if (!calendarsLoadingRef.current) {
calendarsLoadingRef.current = true;
await dispatch(getCalendarsListAsync());
calendarsLoadingRef.current = false;
}
sessionStorage.removeItem("redirectState");
sessionStorage.setItem("tokenSet", JSON.stringify(data?.tokenSet));