[#30] changed logic to load datas to get all events from calendars

This commit is contained in:
Camille Moussu
2025-07-15 14:25:44 +02:00
parent 03e56bd4f6
commit de22a6edfb
10 changed files with 62 additions and 56 deletions
-9
View File
@@ -19,12 +19,3 @@
.App-link { .App-link {
color: #61dafb; color: #61dafb;
} }
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
+20 -13
View File
@@ -41,7 +41,9 @@ export default function CalendarApp() {
Object.keys(userPersonnalCalendars).forEach((value, id) => { Object.keys(userPersonnalCalendars).forEach((value, id) => {
if (userPersonnalCalendars[id].events) { if (userPersonnalCalendars[id].events) {
personnalEvents = personnalEvents.concat( personnalEvents = personnalEvents.concat(
userPersonnalCalendars[id].events Object.keys(userPersonnalCalendars[id].events).map(
(eventid) => userPersonnalCalendars[id].events[eventid]
)
); );
} }
}); });
@@ -50,20 +52,27 @@ export default function CalendarApp() {
); );
const fetchedIdsRef = useRef<Set<string>>(new Set()); const fetchedIdsRef = useRef<Set<string>>(new Set());
const calendarRange = getCalendarRange(selectedDate);
// Create a stable string key for the range
const rangeKey = `${formatDateToYYYYMMDDTHHMMSS(
calendarRange.start
)}_${formatDateToYYYYMMDDTHHMMSS(calendarRange.end)}`;
let filteredEvents: CalendarEvent[] = []; let filteredEvents: CalendarEvent[] = [];
selectedCalendars.forEach((id) => { selectedCalendars.forEach((id) => {
filteredEvents = filteredEvents.concat(calendars[id].events); filteredEvents = filteredEvents
.concat(
Object.keys(calendars[id].events).map(
(eventid) => calendars[id].events[eventid]
)
)
.filter((event) => !(event.status === "CANCELLED"));
}); });
useEffect(() => { useEffect(() => {
selectedCalendars.forEach((id) => { selectedCalendars.forEach((id) => {
const events = calendars[id]?.events ?? []; if (!pending && rangeKey) {
const isEmpty = events.length === 0;
const notFetched = !fetchedIdsRef.current.has(id);
const calendarRange = getCalendarRange(selectedDate);
if (isEmpty && notFetched && !pending) {
dispatch( dispatch(
getCalendarDetailAsync({ getCalendarDetailAsync({
access_token: tokens.access_token, access_token: tokens.access_token,
@@ -74,10 +83,9 @@ export default function CalendarApp() {
}, },
}) })
); );
fetchedIdsRef.current.add(id);
} }
}); });
}, [selectedCalendars, calendars, pending, tokens.access_token, dispatch]); }, [rangeKey, selectedCalendars]);
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null); const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const [anchorElCal, setAnchorElCal] = useState<HTMLElement | null>(null); const [anchorElCal, setAnchorElCal] = useState<HTMLElement | null>(null);
@@ -156,7 +164,6 @@ export default function CalendarApp() {
eventDate.getDate() === date.getDate() eventDate.getDate() === date.getDate()
); );
}); });
console.log(date, hasEvents);
return hasEvents ? <div className="event-dot" /> : null; return hasEvents ? <div className="event-dot" /> : null;
}} }}
/> />
@@ -191,7 +198,7 @@ export default function CalendarApp() {
weekNumberFormat={{ week: "long" }} weekNumberFormat={{ week: "long" }}
slotDuration={"00:30:00"} slotDuration={"00:30:00"}
slotLabelInterval={"00:30:00"} slotLabelInterval={"00:30:00"}
scrollTime={"07:00:00"} scrollTime={"09:00:00"}
allDayText="" allDayText=""
slotLabelFormat={{ slotLabelFormat={{
hour: "2-digit", hour: "2-digit",
-4
View File
@@ -79,7 +79,3 @@
left: 1511px; left: 1511px;
gap: 24px; gap: 24px;
} }
/* Responsive for mobile */
@media (max-width: 768px) {
}
-1
View File
@@ -19,7 +19,6 @@ export async function getCalendar(
opaque_token: string, opaque_token: string,
match: { start: string; end: string } match: { start: string; end: string }
) { ) {
console.log(match)
const response = await fetch( const response = await fetch(
`${(window as any).CALENDAR_BASE_URL}/dav/calendars/${id}.json`, `${(window as any).CALENDAR_BASE_URL}/dav/calendars/${id}.json`,
{ {
+18 -18
View File
@@ -24,7 +24,7 @@ export const getCalendarsListAsync = createAsyncThunk<
: cal._links.self.href.replace("/calendars/", "").replace(".json", ""); : cal._links.self.href.replace("/calendars/", "").replace(".json", "");
const color = cal["apple:color"]; const color = cal["apple:color"];
importedCalendars[id] = { id, name, description, color, events: [] }; importedCalendars[id] = { id, name, description, color, events: {} };
} }
return importedCalendars; return importedCalendars;
@@ -36,10 +36,12 @@ export const getCalendarDetailAsync = createAsyncThunk<
>("calendars/getCalendarDetails", async ({ access_token, calId, match }) => { >("calendars/getCalendarDetails", async ({ access_token, calId, match }) => {
const calendar = await getCalendar(calId, access_token, match); const calendar = await getCalendar(calId, access_token, match);
const color = calendar["apple:color"]; const color = calendar["apple:color"];
const events: CalendarEvent[] = calendar._embedded["dav:item"].map( const events: CalendarEvent[] = calendar._embedded["dav:item"].flatMap(
(eventdata: any) => { (eventdata: any) => {
const datas = eventdata.data[2][0][1]; const vevents = eventdata.data[2] as any[][]; // array of ['vevent', RawEntry[], []]
return parseCalendarEvent(datas, color, calId); return vevents.map((vevent: any[]) => {
return parseCalendarEvent(vevent[1], color, calId);
});
} }
); );
@@ -56,28 +58,25 @@ const CalendarSlice = createSlice({
state.list[id].name = action.payload.name; state.list[id].name = action.payload.name;
state.list[id].color = action.payload.color; state.list[id].color = action.payload.color;
state.list[id].description = action.payload.description; state.list[id].description = action.payload.description;
state.list[id].events = []; state.list[id].events = {};
}, },
addEvent: ( addEvent: (
state, state,
action: PayloadAction<{ calendarUid: string; event: CalendarEvent }> action: PayloadAction<{ calendarUid: string; event: CalendarEvent }>
) => { ) => {
if (!state.list[action.payload.calendarUid].events) { if (!state.list[action.payload.calendarUid].events) {
state.list[action.payload.calendarUid].events = []; state.list[action.payload.calendarUid].events = {};
} }
state.list[action.payload.calendarUid].events.push(action.payload.event); state.list[action.payload.calendarUid].events[action.payload.event.uid] =
action.payload.event;
}, },
removeEvent: ( removeEvent: (
state, state,
action: PayloadAction<{ calendarUid: string; eventUid: string }> action: PayloadAction<{ calendarUid: string; eventUid: string }>
) => { ) => {
state.list[action.payload.calendarUid as string].events = state.list[ delete state.list[action.payload.calendarUid].events[
action.payload.calendarUid action.payload.eventUid
].events.filter((event) => { ];
if (event.uid !== action.payload.calendarUid) {
return event;
}
});
}, },
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
@@ -101,14 +100,15 @@ const CalendarSlice = createSlice({
if (!state.list[action.payload.calId]) { if (!state.list[action.payload.calId]) {
state.list[action.payload.calId] = { state.list[action.payload.calId] = {
id: action.payload.calId, id: action.payload.calId,
events: [] as CalendarEvent[], events: {},
} as Calendars; } as Calendars;
} }
action.payload.events.forEach((event) => { action.payload.events.forEach((event) => {
state.list[action.payload.calId].events.push(event); state.list[action.payload.calId].events[event.uid] = event;
}); });
state.list[action.payload.calId].events.forEach((event) => { Object.keys(state.list[action.payload.calId].events).forEach((id) => {
event.color = state.list[action.payload.calId].color; state.list[action.payload.calId].events[id].color =
state.list[action.payload.calId].color;
}); });
} }
) )
+1 -1
View File
@@ -8,5 +8,5 @@ export interface Calendars {
description?: string; description?: string;
calscale?: string; calscale?: string;
version?: string; version?: string;
events: CalendarEvent[]; events: Record<string, CalendarEvent>;
} }
+1
View File
@@ -17,4 +17,5 @@ export interface CalendarEvent {
color?: string; color?: string;
allday?: Boolean; allday?: Boolean;
error?: string; error?: string;
status?: string;
} }
+13 -7
View File
@@ -18,18 +18,24 @@ export default function ImportAlert() {
return ( return (
<> <>
{Object.keys(calendars).map((calendarId) => {Object.keys(calendars).map((calendarId) =>
calendars[calendarId].events Object.keys(calendars[calendarId].events)
.filter((event) => event.error) .filter((id) => calendars[calendarId].events[id].error)
.map((event) => { .map((id) => {
const isVisible = visibleAlerts[event.uid] ?? true; // default to visible const isVisible =
visibleAlerts[calendars[calendarId].events[id].uid] ?? true; // default to visible
return ( return (
<Collapse in={isVisible} key={event.uid}> <Collapse
in={isVisible}
key={calendars[calendarId].events[id].uid}
>
<Alert <Alert
severity="error" severity="error"
onClose={() => toggleEventAlert(event.uid)} onClose={() =>
toggleEventAlert(calendars[calendarId].events[id].uid)
}
> >
{event.error} {calendars[calendarId].events[id].error}
</Alert> </Alert>
</Collapse> </Collapse>
); );
+9
View File
@@ -9,6 +9,7 @@ export function parseCalendarEvent(
calendarid: string calendarid: string
): CalendarEvent { ): CalendarEvent {
const event: Partial<CalendarEvent> = { color, attendee: [] }; const event: Partial<CalendarEvent> = { color, attendee: [] };
let recurrenceId;
for (const [key, params, type, value] of data) { for (const [key, params, type, value] of data) {
switch (key.toLowerCase()) { switch (key.toLowerCase()) {
@@ -61,8 +62,16 @@ export function parseCalendarEvent(
case "sequence": case "sequence":
event.sequence = Number(value); event.sequence = Number(value);
break; break;
case "recurrence-id":
recurrenceId = value;
break;
case "status":
event.status = String(value);
} }
} }
if (recurrenceId && event.uid) {
event.uid = `${event.uid}/${recurrenceId}`;
}
if (!event.uid || !event.start) { if (!event.uid || !event.start) {
console.error( console.error(
-3
View File
@@ -4,7 +4,6 @@ import { Provider } from "react-redux";
import App from "./App"; import App from "./App";
import { store } from "./app/store"; import { store } from "./app/store";
import reportWebVitals from "./reportWebVitals";
const container = document.getElementById("root")!; const container = document.getElementById("root")!;
const root = createRoot(container); const root = createRoot(container);
@@ -15,5 +14,3 @@ root.render(
</Provider> </Provider>
</React.StrictMode> </React.StrictMode>
); );
reportWebVitals();