[1] added state to add event to calendars
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export default async function getCalendars() {
|
||||
return {}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { useState } from "react";
|
||||
import { createCalendar } from "./CalendarSlice";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import {
|
||||
Popover,
|
||||
TextField,
|
||||
Button,
|
||||
Box,
|
||||
Typography,
|
||||
Select,
|
||||
ButtonGroup,
|
||||
} from "@mui/material";
|
||||
|
||||
function CalendarPopover({
|
||||
anchorEl,
|
||||
open,
|
||||
onClose,
|
||||
}: {
|
||||
anchorEl: HTMLElement | null;
|
||||
open: boolean;
|
||||
onClose: (Calendar: {}, reason: "backdropClick" | "escapeKeyDown") => void;
|
||||
}) {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [color, setColor] = useState("");
|
||||
const [timeZone, setTimeZone] = useState("");
|
||||
const timezones = Intl.supportedValuesOf?.("timeZone") || [];
|
||||
const handleSave = () => {
|
||||
|
||||
dispatch(createCalendar({ name, description, color }));
|
||||
onClose({}, "backdropClick");
|
||||
|
||||
// Reset
|
||||
setName("");
|
||||
setDescription("");
|
||||
};
|
||||
const palette = [
|
||||
"#D50000",
|
||||
"#E67C73",
|
||||
"#F4511E",
|
||||
"#F6BF26",
|
||||
"#33B679",
|
||||
"#0B8043",
|
||||
"#039BE5",
|
||||
"#3F51B5",
|
||||
"#7986CB",
|
||||
"#8E24AA",
|
||||
"#616161",
|
||||
];
|
||||
return (
|
||||
<Popover
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={onClose}
|
||||
anchorOrigin={{
|
||||
vertical: "center",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "center",
|
||||
horizontal: "center",
|
||||
}}
|
||||
>
|
||||
<Box p={2}>
|
||||
<Typography variant="h6" gutterBottom style={{backgroundColor:color}}>
|
||||
Create a Calendar
|
||||
</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
size="small"
|
||||
margin="dense"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
size="small"
|
||||
margin="dense"
|
||||
multiline
|
||||
rows={2}
|
||||
/>
|
||||
<ButtonGroup>
|
||||
{palette.map((color) => (
|
||||
<Button
|
||||
style={{ backgroundColor: color }}
|
||||
onClick={() => setColor(color)}
|
||||
/>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
<Select
|
||||
fullWidth
|
||||
label="timeZone"
|
||||
value={timeZone}
|
||||
onChange={(e) => setTimeZone(e.target.value)}
|
||||
>
|
||||
{timezones.map((zone: string) => (
|
||||
<div>{zone}</div>
|
||||
))}
|
||||
</Select>
|
||||
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => onClose({}, "backdropClick")}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="contained" onClick={handleSave}>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export default CalendarPopover;
|
||||
@@ -0,0 +1,39 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Calendars } from "./CalendarTypes";
|
||||
import { CalendarEvent } from "../Events/EventsTypes";
|
||||
|
||||
const CalendarSlice = createSlice({
|
||||
name: "calendars",
|
||||
initialState: {} as Record<string, Calendars>,
|
||||
reducers: {
|
||||
createCalendar: (state, action: PayloadAction<Record<string, string>>) => {
|
||||
const id = Date.now().toString(36);
|
||||
state[id] = {} as Calendars;
|
||||
state[id].name = action.payload.name;
|
||||
state[id].color = action.payload.color;
|
||||
state[id].description = action.payload.description;
|
||||
state[id].events = [];
|
||||
},
|
||||
addEvent: (
|
||||
state,
|
||||
action: PayloadAction<{ calendarUid: string; event: CalendarEvent }>
|
||||
) => {
|
||||
state[action.payload.calendarUid].events.push(action.payload.event);
|
||||
},
|
||||
removeEvent: (
|
||||
state,
|
||||
action: PayloadAction<{ calendarUid: string; eventUid: string }>
|
||||
) => {
|
||||
state[action.payload.calendarUid as string].events = state[
|
||||
action.payload.calendarUid
|
||||
].events.filter((event) => {
|
||||
if (event.uid !== action.payload.calendarUid) {
|
||||
return event;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { addEvent, removeEvent, createCalendar } = CalendarSlice.actions;
|
||||
export default CalendarSlice.reducer;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CalendarEvent } from "../Events/EventsTypes";
|
||||
|
||||
export interface Calendars {
|
||||
id: string;
|
||||
name: string;
|
||||
prodid: string;
|
||||
color: string;
|
||||
description: string;
|
||||
calscale?: string;
|
||||
version?: string;
|
||||
events: CalendarEvent[];
|
||||
}
|
||||
@@ -1,10 +1,17 @@
|
||||
// components/EventModal.tsx
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { addEvent } from "./EventsSlice";
|
||||
import { CalendarEvent } from "./EventsTypes";
|
||||
import { DateSelectArg } from "@fullcalendar/core";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import { Popover, TextField, Button, Box, Typography } from "@mui/material";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import {
|
||||
Popover,
|
||||
TextField,
|
||||
Button,
|
||||
Box,
|
||||
Typography,
|
||||
Select,
|
||||
MenuItem,
|
||||
} from "@mui/material";
|
||||
|
||||
function EventPopover({
|
||||
anchorEl,
|
||||
@@ -19,12 +26,14 @@ function EventPopover({
|
||||
}) {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [title, setTitle] = useState("");
|
||||
const organizer = useAppSelector((state) => state.user.organiserData);
|
||||
const calendars = useAppSelector((state) => state.calendars);
|
||||
const [summary, setSummary] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [location, setLocation] = useState("");
|
||||
const [calendar, setCalendar] = useState("");
|
||||
const [start, setStart] = useState("");
|
||||
const [end, setEnd] = useState("");
|
||||
const [calendarid, setCalendarid] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedRange) {
|
||||
@@ -35,21 +44,31 @@ function EventPopover({
|
||||
|
||||
const handleSave = () => {
|
||||
const newEvent: CalendarEvent = {
|
||||
title,
|
||||
start,
|
||||
end,
|
||||
calendar,
|
||||
extendedProps: {
|
||||
description,
|
||||
location,
|
||||
},
|
||||
summary,
|
||||
start: new Date(start),
|
||||
end: new Date(end),
|
||||
uid: Date.now().toString(36),
|
||||
description,
|
||||
location,
|
||||
organizer,
|
||||
attendee: [
|
||||
{
|
||||
cn: organizer.cn,
|
||||
cal_address: organizer.cal_address,
|
||||
partstat: "ACCEPTED",
|
||||
rsvp: "FALSE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
},
|
||||
],
|
||||
transp: "OPAQUE",
|
||||
};
|
||||
dispatch(addEvent(newEvent));
|
||||
console.log(newEvent)
|
||||
console.log(newEvent);
|
||||
onClose({}, "backdropClick");
|
||||
|
||||
// Reset
|
||||
setTitle("");
|
||||
setSummary("");
|
||||
setDescription("");
|
||||
setLocation("");
|
||||
};
|
||||
@@ -72,11 +91,16 @@ function EventPopover({
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Create Event
|
||||
</Typography>
|
||||
<Select onClick={(e) => console.log(e.target)}>
|
||||
{Object.keys(calendars).map((calendar) => (
|
||||
<MenuItem value={calendar}>{calendars[calendar].name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Title"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
label="summary"
|
||||
value={summary}
|
||||
onChange={(e) => setSummary(e.target.value)}
|
||||
size="small"
|
||||
margin="dense"
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// store/eventsSlice.ts
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { CalendarEvent } from "./EventsTypes";
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
// types/Event.ts
|
||||
import { userAttendee, userOrganiser } from "../User/userDataTypes";
|
||||
|
||||
export interface CalendarEvent {
|
||||
title: string;
|
||||
start: string; // ISO date
|
||||
end?: string;
|
||||
calendar:string;
|
||||
extendedProps?: {
|
||||
description?: string;
|
||||
location?: string;
|
||||
};
|
||||
uid: string;
|
||||
transp: string;
|
||||
start: Date; // ISO date
|
||||
end?: Date;
|
||||
class?: string;
|
||||
x_openpass_videoconference?: unknown;
|
||||
summary?: string;
|
||||
description?: string;
|
||||
location?: string;
|
||||
organizer: userOrganiser;
|
||||
attendee: userAttendee[];
|
||||
stamp?: Date;
|
||||
sequence?: Number;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Callback } from "./oidcAuth";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import { push } from "redux-first-history";
|
||||
import { setUserData } from "./userSlice";
|
||||
import { Loading } from "../../components/Loading/Loading";
|
||||
@@ -12,9 +11,6 @@ export function CallbackResume() {
|
||||
const saved = sessionStorage.getItem("redirectState")
|
||||
? JSON.parse(sessionStorage.getItem("redirectState")!)
|
||||
: null;
|
||||
const [tokens, setTokens] = useState<any>();
|
||||
const [userInfo, setUserInfo] = useState<any>();
|
||||
const location = useAppSelector((state) => state.router.location);
|
||||
useEffect(() => {
|
||||
if (hasRun.current) {
|
||||
return;
|
||||
@@ -24,8 +20,6 @@ export function CallbackResume() {
|
||||
try {
|
||||
const data = await Callback(saved?.code_verifier, saved?.state);
|
||||
console.log("data:", data);
|
||||
setTokens(data?.tokenSet);
|
||||
setUserInfo(data?.userinfo);
|
||||
dispatch(setUserData(data?.userinfo));
|
||||
sessionStorage.removeItem("redirectState");
|
||||
// Redirect to main page after successful callback
|
||||
|
||||
@@ -22,7 +22,6 @@ export async function getClientConfig() {
|
||||
}
|
||||
|
||||
export async function Auth() {
|
||||
console.log("bap");
|
||||
let code_verifier = client.randomPKCECodeVerifier();
|
||||
let code_challenge = await client.calculatePKCECodeChallenge(code_verifier);
|
||||
const openIdClientConfig = await getClientConfig();
|
||||
|
||||
@@ -3,3 +3,17 @@ export interface userData {
|
||||
sid: string;
|
||||
sub: string;
|
||||
}
|
||||
|
||||
export interface userOrganiser {
|
||||
cn: string;
|
||||
cal_address: string;
|
||||
}
|
||||
|
||||
export interface userAttendee {
|
||||
cn: string;
|
||||
cal_address: string;
|
||||
partstat: string;
|
||||
rsvp: string;
|
||||
role: string;
|
||||
cutype: string;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { userData } from "./userDataTypes";
|
||||
import { userData, userOrganiser } from "./userDataTypes";
|
||||
|
||||
export const userSlice = createSlice({
|
||||
name: "user",
|
||||
initialState: {
|
||||
userData: null as unknown as userData,
|
||||
organiserData: null as unknown as userOrganiser,
|
||||
},
|
||||
reducers: {
|
||||
setUserData: (state, action) => {
|
||||
state.userData = action.payload;
|
||||
if (!state.organiserData) {
|
||||
state.organiserData = {} as userOrganiser;
|
||||
}
|
||||
state.organiserData.cn = action.payload.sub;
|
||||
state.organiserData.cal_address = `mailto:${action.payload.email}`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user