[#64] added creation modal to list and api call
This commit is contained in:
committed by
Benoit TELLIER
parent
d1140a47b2
commit
9d43c15ee0
@@ -14,6 +14,7 @@ import { CalendarEvent } from "../../features/Events/EventsTypes";
|
||||
import CalendarSelection from "./CalendarSelection";
|
||||
import {
|
||||
getCalendarDetailAsync,
|
||||
getCalendarsListAsync,
|
||||
getEventAsync,
|
||||
putEventAsync,
|
||||
updateEventLocal,
|
||||
@@ -92,13 +93,15 @@ export default function CalendarApp() {
|
||||
|
||||
let filteredEvents: CalendarEvent[] = [];
|
||||
selectedCalendars.forEach((id) => {
|
||||
filteredEvents = filteredEvents
|
||||
.concat(
|
||||
Object.keys(calendars[id].events).map(
|
||||
(eventid) => calendars[id].events[eventid]
|
||||
if (calendars[id].events) {
|
||||
filteredEvents = filteredEvents
|
||||
.concat(
|
||||
Object.keys(calendars[id].events).map(
|
||||
(eventid) => calendars[id].events[eventid]
|
||||
)
|
||||
)
|
||||
)
|
||||
.filter((event) => !(event.status === "CANCELLED"));
|
||||
.filter((event) => !(event.status === "CANCELLED"));
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -125,7 +128,6 @@ export default function CalendarApp() {
|
||||
const [openEventDisplay, setOpenEventDisplay] = useState(false);
|
||||
const [eventDisplayedId, setEventDisplayedId] = useState("");
|
||||
const [eventDisplayedCalId, setEventDisplayedCalId] = useState("");
|
||||
const [anchorElCal, setAnchorElCal] = useState<HTMLElement | null>(null);
|
||||
const [selectedRange, setSelectedRange] = useState<DateSelectArg | null>(
|
||||
null
|
||||
);
|
||||
@@ -248,7 +250,6 @@ export default function CalendarApp() {
|
||||
selectedCalendars={selectedCalendars}
|
||||
setSelectedCalendars={setSelectedCalendars}
|
||||
/>
|
||||
<button onClick={() => setAnchorElCal(document.body)}>+</button>
|
||||
</div>
|
||||
<div className="calendar">
|
||||
<ImportAlert />
|
||||
@@ -270,7 +271,8 @@ export default function CalendarApp() {
|
||||
customButtons={{
|
||||
refresh: {
|
||||
text: "↻",
|
||||
click: () => {
|
||||
click: async () => {
|
||||
await dispatch(getCalendarsListAsync());
|
||||
selectedCalendars.forEach((id) => {
|
||||
if (!pending && rangeKey) {
|
||||
dispatch(
|
||||
@@ -521,11 +523,6 @@ export default function CalendarApp() {
|
||||
setSelectedRange={setSelectedRange}
|
||||
calendarRef={calendarRef}
|
||||
/>
|
||||
<CalendarPopover
|
||||
anchorEl={anchorElCal}
|
||||
open={Boolean(anchorElCal)}
|
||||
onClose={() => setAnchorElCal(null)}
|
||||
/>
|
||||
{openEventDisplay && eventDisplayedId && eventDisplayedCalId && (
|
||||
<EventPreviewModal
|
||||
eventId={eventDisplayedId}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Button } from "@mui/material";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { useEffect, useState } from "react";
|
||||
import CalendarPopover from "../../features/Calendars/CalendarModal";
|
||||
|
||||
export default function CalendarSelection({
|
||||
selectedCalendars,
|
||||
@@ -24,32 +28,20 @@ export default function CalendarSelection({
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {}, [calendars]);
|
||||
const [anchorElCal, setAnchorElCal] = useState<HTMLElement | null>(null);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Personnal Calendars</h3>
|
||||
</span>
|
||||
{personnalCalendars.map((id) => {
|
||||
return (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{delegatedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Delegated Calendars</h3>
|
||||
</span>
|
||||
{delegatedCalendars.map((id) => (
|
||||
<>
|
||||
<div>
|
||||
<div className="calendarListHeader">
|
||||
<h3>Personnal Calendars</h3>
|
||||
<Button onClick={() => setAnchorElCal(document.body)}>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
</div>
|
||||
{personnalCalendars.map((id) => {
|
||||
return (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
@@ -61,29 +53,54 @@ export default function CalendarSelection({
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{sharedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Shared Calendars</h3>
|
||||
</span>
|
||||
{sharedCalendars.map((id) => (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{delegatedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Delegated Calendars</h3>
|
||||
</span>
|
||||
{delegatedCalendars.map((id) => (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{sharedCalendars.length > 0 && (
|
||||
<>
|
||||
<span className="calendarListHeader">
|
||||
<h3>Shared Calendars</h3>
|
||||
</span>
|
||||
{sharedCalendars.map((id) => (
|
||||
<div key={id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={{ backgroundColor: calendars[id].color }}
|
||||
checked={selectedCalendars.includes(id)}
|
||||
onChange={() => handleCalendarToggle(id)}
|
||||
/>
|
||||
{calendars[id].name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<CalendarPopover
|
||||
anchorEl={anchorElCal}
|
||||
open={Boolean(anchorElCal)}
|
||||
onClose={() => setAnchorElCal(null)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,3 +30,24 @@ export async function getCalendar(
|
||||
const calendar = await response.json();
|
||||
return calendar;
|
||||
}
|
||||
|
||||
export async function postCalendar(
|
||||
userId: string,
|
||||
calId: string,
|
||||
color: string,
|
||||
name: string,
|
||||
desc: string
|
||||
) {
|
||||
const response = await api.post(`dav/calendars/${userId}.json`, {
|
||||
headers: {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: calId,
|
||||
"dav:name": name,
|
||||
"apple:color": color,
|
||||
"caldav:description": desc,
|
||||
}),
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { createCalendar } from "./CalendarSlice";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import { createCalendar, createCalendarAsync } from "./CalendarSlice";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import {
|
||||
Popover,
|
||||
TextField,
|
||||
@@ -21,14 +21,18 @@ function CalendarPopover({
|
||||
onClose: (Calendar: {}, reason: "backdropClick" | "escapeKeyDown") => void;
|
||||
}) {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const userId =
|
||||
useAppSelector((state) => state.user.userData.openpaasId) ?? "";
|
||||
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 }));
|
||||
const calId = crypto.randomUUID();
|
||||
dispatch(
|
||||
createCalendarAsync({ name, desc: description, color, userId, calId })
|
||||
);
|
||||
onClose({}, "backdropClick");
|
||||
|
||||
// Reset
|
||||
@@ -68,7 +72,7 @@ function CalendarPopover({
|
||||
gutterBottom
|
||||
style={{ backgroundColor: color }}
|
||||
>
|
||||
Create a Calendar
|
||||
Calendar configuration
|
||||
</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Calendars } from "./CalendarTypes";
|
||||
import { CalendarEvent } from "../Events/EventsTypes";
|
||||
import { getCalendar, getCalendars } from "./CalendarApi";
|
||||
import { getCalendar, getCalendars, postCalendar } from "./CalendarApi";
|
||||
import { getOpenPaasUser, getUserDetails } from "../User/userAPI";
|
||||
import { parseCalendarEvent } from "../Events/eventUtils";
|
||||
import { deleteEvent, getEvent, moveEvent, putEvent } from "../Events/EventApi";
|
||||
@@ -157,6 +157,14 @@ export const deleteEventAsync = createAsyncThunk<
|
||||
return { calId, eventId };
|
||||
});
|
||||
|
||||
export const createCalendarAsync = createAsyncThunk<
|
||||
{ userId: string; calId: string; color: string; name: string; desc: string }, // Return type
|
||||
{ userId: string; calId: string; color: string; name: string; desc: string } // Arg type
|
||||
>("calendars/createCalendar", async ({ userId, calId, color, name, desc }) => {
|
||||
const response = await postCalendar(userId, calId, color, name, desc);
|
||||
return { userId, calId, color, name, desc };
|
||||
});
|
||||
|
||||
const CalendarSlice = createSlice({
|
||||
name: "calendars",
|
||||
initialState: { list: {} as Record<string, Calendars>, pending: false },
|
||||
@@ -206,9 +214,7 @@ const CalendarSlice = createSlice({
|
||||
getCalendarsListAsync.fulfilled,
|
||||
(state, action: PayloadAction<Record<string, Calendars>>) => {
|
||||
state.pending = false;
|
||||
Object.keys(action.payload).forEach((id) => {
|
||||
state.list[id] = action.payload[id];
|
||||
});
|
||||
state.list = action.payload;
|
||||
}
|
||||
)
|
||||
.addCase(
|
||||
@@ -324,6 +330,15 @@ const CalendarSlice = createSlice({
|
||||
];
|
||||
}
|
||||
})
|
||||
.addCase(createCalendarAsync.fulfilled, (state, action) => {
|
||||
state.pending = false;
|
||||
state.list[`${action.payload.userId}/${action.payload.calId}`] = {
|
||||
color: action.payload.color,
|
||||
id: `${action.payload.userId}/${action.payload.calId}`,
|
||||
description: action.payload.desc,
|
||||
name: action.payload.name,
|
||||
} as unknown as Calendars;
|
||||
})
|
||||
.addCase(getCalendarDetailAsync.pending, (state) => {
|
||||
state.pending = true;
|
||||
})
|
||||
@@ -341,6 +356,9 @@ const CalendarSlice = createSlice({
|
||||
})
|
||||
.addCase(deleteEventAsync.pending, (state) => {
|
||||
state.pending = true;
|
||||
})
|
||||
.addCase(createCalendarAsync.pending, (state) => {
|
||||
state.pending = true;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,28 +18,30 @@ export default function ImportAlert() {
|
||||
return (
|
||||
<>
|
||||
{Object.keys(calendars).map((calendarId) =>
|
||||
Object.keys(calendars[calendarId].events)
|
||||
.filter((id) => calendars[calendarId].events[id].error)
|
||||
.map((id) => {
|
||||
const isVisible =
|
||||
visibleAlerts[calendars[calendarId].events[id].uid] ?? true; // default to visible
|
||||
calendars[calendarId]?.events
|
||||
? Object.keys(calendars[calendarId]?.events)
|
||||
.filter((id) => calendars[calendarId]?.events[id].error)
|
||||
.map((id) => {
|
||||
const isVisible =
|
||||
visibleAlerts[calendars[calendarId].events[id].uid] ?? true; // default to visible
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
in={isVisible}
|
||||
key={calendars[calendarId].events[id].uid}
|
||||
>
|
||||
<Alert
|
||||
severity="error"
|
||||
onClose={() =>
|
||||
toggleEventAlert(calendars[calendarId].events[id].uid)
|
||||
}
|
||||
>
|
||||
{calendars[calendarId].events[id].error}
|
||||
</Alert>
|
||||
</Collapse>
|
||||
);
|
||||
})
|
||||
return (
|
||||
<Collapse
|
||||
in={isVisible}
|
||||
key={calendars[calendarId].events[id].uid}
|
||||
>
|
||||
<Alert
|
||||
severity="error"
|
||||
onClose={() =>
|
||||
toggleEventAlert(calendars[calendarId].events[id].uid)
|
||||
}
|
||||
>
|
||||
{calendars[calendarId].events[id].error}
|
||||
</Alert>
|
||||
</Collapse>
|
||||
);
|
||||
})
|
||||
: []
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user