[#1] getting the calendars from the api
This commit is contained in:
@@ -6,3 +6,4 @@ REACT_APP_SSO_REDIRECT_URI="https://example.com/callback"
|
||||
REACT_APP_SSO_RESPONSE_TYPE="code"
|
||||
REACT_APP_SSO_CODE_CHALLENGE_METHOD="S256"
|
||||
REACT_APP_SSO_POST_LOGOUT_REDIRECT="http://example.com?logout=1"
|
||||
REACT_APP_CALENDAR_BASE_URL="https://calendar.example.com"
|
||||
@@ -7,19 +7,29 @@ import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
|
||||
import ReactCalendar from "react-calendar";
|
||||
import "./Calendar.css";
|
||||
import { useRef, useState } from "react";
|
||||
import { useAppSelector } from "../../app/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import EventPopover from "../../features/Events/EventModal";
|
||||
import CalendarPopover from "../../features/Calendars/CalendarModal";
|
||||
import { CalendarEvent } from "../../features/Events/EventsTypes";
|
||||
import {
|
||||
getCalendar,
|
||||
getCalendars,
|
||||
} from "../../features/Calendars/CalendarApi";
|
||||
import { access } from "node:fs";
|
||||
import getOpenPaasUserId from "../../features/User/userAPI";
|
||||
import { getCalendarsAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { Calendars } from "../../features/Calendars/CalendarTypes";
|
||||
import { parseCalendarEvent } from "../../features/Events/eventUtils";
|
||||
|
||||
export default function CalendarApp() {
|
||||
const calendarRef = useRef<CalendarApi | null>(null);
|
||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||
const tokens = useAppSelector((state) => state.user.tokens);
|
||||
const calendars = useAppSelector((state) => state.calendars);
|
||||
const [selectedCalendars, setSelectedCalendars] = useState(
|
||||
Object.keys(calendars).map((id) => id)
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
let filteredEvents: CalendarEvent[] = [];
|
||||
selectedCalendars.forEach((id) => {
|
||||
filteredEvents = filteredEvents.concat(calendars[id].events);
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
export default async function getCalendars() {
|
||||
return {}
|
||||
import { cp } from "node:fs";
|
||||
|
||||
export async function getCalendars(userId: string, opaque_token: string) {
|
||||
const response = await fetch(
|
||||
`${process.env.REACT_APP_CALENDAR_BASE_URL}/dav/calendars/${userId}.json?personal=true&sharedDelegationStatus=accepted&sharedPublicSubscription=true&withRights=true`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/calendar+json",
|
||||
Authorization: `Bearer ${opaque_token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
const calendars = await response.json();
|
||||
return calendars;
|
||||
}
|
||||
|
||||
export async function getCalendar(id: string, opaque_token: string) {
|
||||
const response = await fetch(
|
||||
`${process.env.REACT_APP_CALENDAR_BASE_URL}/dav/calendars/${id}/${id}.json`,
|
||||
{
|
||||
method: "REPORT",
|
||||
headers: {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
Authorization: `Bearer ${opaque_token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
match: { start: "20250525T000000", end: "20250708T000000" },
|
||||
}),
|
||||
}
|
||||
);
|
||||
const calendar = await response.json();
|
||||
return calendar;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Calendars } from "./CalendarTypes";
|
||||
import { CalendarEvent } from "../Events/EventsTypes";
|
||||
import { getCalendar, getCalendars } from "./CalendarApi";
|
||||
import getOpenPaasUserId from "../User/userAPI";
|
||||
import { parseCalendarEvent } from "../Events/eventUtils";
|
||||
|
||||
export const getCalendarsAsync = createAsyncThunk<
|
||||
Record<string, Calendars>, // Return type
|
||||
string // Arg type (access_token)
|
||||
>("calendars/getCalendars", async (access_token: string) => {
|
||||
const importedCalendars: Record<string, Calendars> = {};
|
||||
const user = await getOpenPaasUserId(access_token);
|
||||
const calendars = await getCalendars(user.id, access_token);
|
||||
const rawCalendars = calendars._embedded["dav:calendar"];
|
||||
|
||||
for (const cal of rawCalendars) {
|
||||
const name = cal["dav:name"];
|
||||
const description = cal["dav:description"];
|
||||
const id = cal["calendarserver:source"]
|
||||
? cal["calendarserver:source"]._links.self.href
|
||||
.replace("/calendars/", "")
|
||||
.replace(".json", "")
|
||||
.split("/")[0]
|
||||
: cal._links.self.href
|
||||
.replace("/calendars/", "")
|
||||
.replace(".json", "")
|
||||
.split("/")[0];
|
||||
|
||||
const color = cal["apple:color"];
|
||||
const calendarDetails = await getCalendar(id, access_token);
|
||||
const events = calendarDetails._embedded["dav:item"].map(
|
||||
(eventdata: any) => {
|
||||
const datas = eventdata.data[2][0][1];
|
||||
return parseCalendarEvent(datas, color);
|
||||
}
|
||||
);
|
||||
|
||||
importedCalendars[id] = { id, name, description, color, events };
|
||||
}
|
||||
|
||||
return importedCalendars;
|
||||
});
|
||||
|
||||
const CalendarSlice = createSlice({
|
||||
name: "calendars",
|
||||
@@ -18,7 +58,7 @@ const CalendarSlice = createSlice({
|
||||
state,
|
||||
action: PayloadAction<{ calendarUid: string; event: CalendarEvent }>
|
||||
) => {
|
||||
console.log(action.payload)
|
||||
console.log(action.payload);
|
||||
if (!state[action.payload.calendarUid].events) {
|
||||
state[action.payload.calendarUid].events = [];
|
||||
}
|
||||
@@ -37,6 +77,19 @@ const CalendarSlice = createSlice({
|
||||
});
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(
|
||||
getCalendarsAsync.fulfilled,
|
||||
(state, action: PayloadAction<Record<string, Calendars>>) => {
|
||||
console.log("ony est!!!!: ", action.payload);
|
||||
console.log(Object.keys(action.payload));
|
||||
Object.keys(action.payload).forEach((id) => {
|
||||
console.log(id);
|
||||
state[id] = action.payload[id];
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export const { addEvent, removeEvent, createCalendar } = CalendarSlice.actions;
|
||||
|
||||
@@ -3,9 +3,9 @@ import { CalendarEvent } from "../Events/EventsTypes";
|
||||
export interface Calendars {
|
||||
id: string;
|
||||
name: string;
|
||||
prodid: string;
|
||||
prodid?: string;
|
||||
color: string;
|
||||
description: string;
|
||||
description?: string;
|
||||
calscale?: string;
|
||||
version?: string;
|
||||
events: CalendarEvent[];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { userAttendee, userOrganiser } from "../User/userDataTypes";
|
||||
|
||||
export interface CalendarEvent {
|
||||
uid: string;
|
||||
transp: string;
|
||||
transp?: string;
|
||||
start: Date; // ISO date
|
||||
end?: Date;
|
||||
class?: string;
|
||||
@@ -10,9 +10,10 @@ export interface CalendarEvent {
|
||||
title?: string;
|
||||
description?: string;
|
||||
location?: string;
|
||||
organizer: userOrganiser;
|
||||
organizer?: userOrganiser;
|
||||
attendee: userAttendee[];
|
||||
stamp?: Date;
|
||||
sequence?: Number;
|
||||
color?: string;
|
||||
allday?:Boolean
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { userAttendee } from "../User/userDataTypes";
|
||||
import { CalendarEvent } from "./EventsTypes";
|
||||
|
||||
type RawEntry = [string, Record<string, string>, string, any];
|
||||
|
||||
export function parseCalendarEvent(
|
||||
data: RawEntry[],
|
||||
color: string
|
||||
): CalendarEvent {
|
||||
const event: Partial<CalendarEvent> = { color, attendee: [] };
|
||||
|
||||
for (const [key, params, type, value] of data) {
|
||||
switch (key.toLowerCase()) {
|
||||
case "uid":
|
||||
event.uid = value;
|
||||
break;
|
||||
case "transp":
|
||||
event.transp = value;
|
||||
break;
|
||||
case "dtstart":
|
||||
event.start = value;
|
||||
break;
|
||||
case "dtend":
|
||||
event.end = value;
|
||||
break;
|
||||
case "class":
|
||||
event.class = value;
|
||||
break;
|
||||
case "x-openpaas-videoconference":
|
||||
event.x_openpass_videoconference = value;
|
||||
break;
|
||||
case "summary":
|
||||
event.title = value;
|
||||
break;
|
||||
case "description":
|
||||
event.description = value;
|
||||
break;
|
||||
case "location":
|
||||
event.location = value;
|
||||
break;
|
||||
case "organizer":
|
||||
event.organizer = {
|
||||
cn: params?.cn || "",
|
||||
cal_address: value.replace(/^mailto:/, ""),
|
||||
};
|
||||
break;
|
||||
case "attendee":
|
||||
(event.attendee as userAttendee[]).push({
|
||||
cn: params?.cn || "",
|
||||
cal_address: value.replace(/^mailto:/, ""),
|
||||
partstat: params?.partstat || "",
|
||||
rsvp: params?.rsvp || "",
|
||||
role: params?.role || "",
|
||||
cutype: params?.cutype || "",
|
||||
});
|
||||
break;
|
||||
case "dtstamp":
|
||||
event.stamp = new Date(value);
|
||||
break;
|
||||
case "sequence":
|
||||
event.sequence = Number(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event.uid || !event.start) {
|
||||
console.log(event);
|
||||
throw new Error(`Missing required event fields`);
|
||||
}
|
||||
|
||||
return event as CalendarEvent;
|
||||
}
|
||||
@@ -2,8 +2,9 @@ import { useEffect, useRef } from "react";
|
||||
import { Callback } from "./oidcAuth";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import { push } from "redux-first-history";
|
||||
import { setUserData } from "./userSlice";
|
||||
import { setTokens, setUserData } from "./userSlice";
|
||||
import { Loading } from "../../components/Loading/Loading";
|
||||
import { getCalendarsAsync } from "../Calendars/CalendarSlice";
|
||||
|
||||
export function CallbackResume() {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -21,6 +22,8 @@ export function CallbackResume() {
|
||||
const data = await Callback(saved?.code_verifier, saved?.state);
|
||||
console.log("data:", data);
|
||||
dispatch(setUserData(data?.userinfo));
|
||||
dispatch(setTokens(data?.tokenSet));
|
||||
dispatch(getCalendarsAsync(data?.tokenSet.access_token || ""));
|
||||
sessionStorage.removeItem("redirectState");
|
||||
// Redirect to main page after successful callback
|
||||
dispatch(push("/"));
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export default async function getOpenPaasUserId(opaque_token: string) {
|
||||
const response = await fetch(
|
||||
`${process.env.REACT_APP_CALENDAR_BASE_URL}/api/user`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${opaque_token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
const user = await response.json();
|
||||
return user;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export const userSlice = createSlice({
|
||||
initialState: {
|
||||
userData: null as unknown as userData,
|
||||
organiserData: null as unknown as userOrganiser,
|
||||
tokens: null as unknown as Record<string, string>,
|
||||
},
|
||||
reducers: {
|
||||
setUserData: (state, action) => {
|
||||
@@ -16,10 +17,14 @@ export const userSlice = createSlice({
|
||||
state.organiserData.cn = action.payload.sub;
|
||||
state.organiserData.cal_address = `mailto:${action.payload.email}`;
|
||||
},
|
||||
setTokens: (state, action) => {
|
||||
console.log(state.tokens);
|
||||
state.tokens = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { setUserData } = userSlice.actions;
|
||||
export const { setUserData, setTokens } = userSlice.actions;
|
||||
|
||||
export default userSlice.reducer;
|
||||
|
||||
Reference in New Issue
Block a user