[#31] fixed sending data
This commit is contained in:
@@ -100,7 +100,6 @@ export default function CalendarApp() {
|
||||
|
||||
const handleDateSelect = (selectInfo: DateSelectArg) => {
|
||||
setSelectedRange(selectInfo);
|
||||
console.log(selectInfo);
|
||||
setAnchorEl(document.body); // fallback: we could use selectInfo.jsEvent.target if from a click
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CalendarEvent } from "../Events/EventsTypes";
|
||||
import { getCalendar, getCalendars } from "./CalendarApi";
|
||||
import getOpenPaasUserId from "../User/userAPI";
|
||||
import { parseCalendarEvent } from "../Events/eventUtils";
|
||||
import { getEvent, putEvent } from "../Events/EventApi";
|
||||
import { putEvent } from "../Events/EventApi";
|
||||
import { formatDateToYYYYMMDDTHHMMSS } from "../../utils/dateUtils";
|
||||
|
||||
export const getCalendarsListAsync = createAsyncThunk<
|
||||
@@ -50,18 +50,28 @@ export const getCalendarDetailAsync = createAsyncThunk<
|
||||
});
|
||||
|
||||
export const putEventAsync = createAsyncThunk<
|
||||
{ calId: string; event: CalendarEvent }, // Return type
|
||||
{ calId: string; events: CalendarEvent[] }, // Return type
|
||||
{ cal: Calendars; newEvent: CalendarEvent } // Arg type
|
||||
>("calendars/putEvent", async ({ cal, newEvent }) => {
|
||||
const response = await putEvent(cal, newEvent);
|
||||
const now = new Date();
|
||||
const event = (await getCalendar(cal.id, {
|
||||
start: formatDateToYYYYMMDDTHHMMSS(now),
|
||||
end: formatDateToYYYYMMDDTHHMMSS(new Date(now.getDate() + 1)),
|
||||
const calEvents = (await getCalendar(cal.id, {
|
||||
start: formatDateToYYYYMMDDTHHMMSS(newEvent.start),
|
||||
end: formatDateToYYYYMMDDTHHMMSS(
|
||||
new Date(newEvent.start.getTime() + 86400000)
|
||||
),
|
||||
})) as Record<string, any>;
|
||||
const events: CalendarEvent[] = calEvents._embedded["dav:item"].flatMap(
|
||||
(eventdata: any) => {
|
||||
const vevents = eventdata.data[2] as any[][];
|
||||
return vevents.map((vevent: any[]) => {
|
||||
return parseCalendarEvent(vevent[1], cal.color ?? "", cal.id);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
calId: cal.id,
|
||||
event: parseCalendarEvent([event[1]], "", cal.id),
|
||||
events,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -133,7 +143,7 @@ const CalendarSlice = createSlice({
|
||||
putEventAsync.fulfilled,
|
||||
(
|
||||
state,
|
||||
action: PayloadAction<{ calId: string; event: CalendarEvent }>
|
||||
action: PayloadAction<{ calId: string; events: CalendarEvent[] }>
|
||||
) => {
|
||||
state.pending = false;
|
||||
if (!state.list[action.payload.calId]) {
|
||||
@@ -142,11 +152,13 @@ const CalendarSlice = createSlice({
|
||||
events: {},
|
||||
} as Calendars;
|
||||
}
|
||||
state.list[action.payload.calId].events[action.payload.event.uid] =
|
||||
action.payload.event;
|
||||
state.list[action.payload.calId].events[
|
||||
action.payload.event.uid
|
||||
].color = state.list[action.payload.calId].color;
|
||||
action.payload.events.forEach((event) => {
|
||||
state.list[action.payload.calId].events[event.uid] = event;
|
||||
});
|
||||
Object.keys(state.list[action.payload.calId].events).forEach((id) => {
|
||||
state.list[action.payload.calId].events[id].color =
|
||||
state.list[action.payload.calId].color;
|
||||
});
|
||||
}
|
||||
)
|
||||
.addCase(getCalendarDetailAsync.pending, (state) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { api } from "../../utils/apiUtils";
|
||||
import { Calendars } from "../Calendars/CalendarTypes";
|
||||
import { CalendarEvent } from "./EventsTypes";
|
||||
import { calendarEventToICal, calendarEventToJCal } from "./eventUtils";
|
||||
import { calendarEventToJCal } from "./eventUtils";
|
||||
|
||||
export async function putEvent(cal: Calendars, event: CalendarEvent) {
|
||||
const response = await api(
|
||||
`dav/calendars/${cal.id}/${event.uid.split(".")[0]}.isc`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(calendarEventToICal(cal, event)),
|
||||
body: JSON.stringify(calendarEventToJCal(event)),
|
||||
headers: {
|
||||
"content-type": "text/calendar; charset=utf-8",
|
||||
},
|
||||
@@ -16,10 +16,3 @@ export async function putEvent(cal: Calendars, event: CalendarEvent) {
|
||||
).json();
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function getEvent(calID: string, eventID: string) {
|
||||
const response = await api
|
||||
.get(`dav/calendars/${calID}/${eventID}.ics`)
|
||||
.json();
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -62,8 +62,6 @@ function EventPopover({
|
||||
}, [selectedRange]);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!calendarid) return; // Prevent crash if no calendar is selected
|
||||
|
||||
const newEvent: CalendarEvent = {
|
||||
title,
|
||||
start: new Date(start),
|
||||
@@ -86,12 +84,7 @@ function EventPopover({
|
||||
transp: "OPAQUE",
|
||||
color: userPersonnalCalendars[calendarid]?.color,
|
||||
};
|
||||
// dispatch(
|
||||
// addEvent({
|
||||
// calendarUid: userPersonnalCalendars[calendarid]?.id,
|
||||
// event: newEvent,
|
||||
// })
|
||||
// );
|
||||
|
||||
dispatch(
|
||||
putEventAsync({
|
||||
cal: userPersonnalCalendars[calendarid],
|
||||
@@ -208,11 +201,7 @@ function EventPopover({
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSave}
|
||||
disabled={!(calendarid ?? false) || !title}
|
||||
>
|
||||
<Button variant="contained" onClick={handleSave} disabled={!title}>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
@@ -87,19 +87,14 @@ export function parseCalendarEvent(
|
||||
}
|
||||
|
||||
export function calendarEventToJCal(event: CalendarEvent): any[] {
|
||||
const tzid = event.timezone ?? "UTC"; // Fallback to UTC if no timezone provided
|
||||
const tzid = event.timezone; // Fallback to UTC if no timezone provided
|
||||
|
||||
const vevent: any[] = [
|
||||
"vevent",
|
||||
[
|
||||
["uid", {}, "text", event.uid],
|
||||
["transp", {}, "text", event.transp ?? "OPAQUE"],
|
||||
[
|
||||
"dtstart",
|
||||
{ tzid },
|
||||
"date-time",
|
||||
event.start.toISOString().split(".")[0],
|
||||
],
|
||||
["dtstart", { tzid }, "date-time", formatDateToICal(event.start)],
|
||||
["class", {}, "text", event.class ?? "PUBLIC"],
|
||||
[
|
||||
"x-openpaas-videoconference",
|
||||
@@ -117,7 +112,7 @@ export function calendarEventToJCal(event: CalendarEvent): any[] {
|
||||
"dtend",
|
||||
{ tzid },
|
||||
"date-time",
|
||||
event.start.toISOString().split(".")[0],
|
||||
formatDateToICal(event.end),
|
||||
]);
|
||||
}
|
||||
if (event.organizer) {
|
||||
@@ -125,9 +120,15 @@ export function calendarEventToJCal(event: CalendarEvent): any[] {
|
||||
"organizer",
|
||||
{ cn: event.organizer.cn },
|
||||
"cal-address",
|
||||
`mailto:${event.organizer.cal_address}`,
|
||||
event.organizer.cal_address,
|
||||
]);
|
||||
}
|
||||
if (event.location) {
|
||||
vevent[1].push(["location", {}, "text", event.location]);
|
||||
}
|
||||
if (event.description) {
|
||||
vevent[1].push(["description", {}, "text", event.description]);
|
||||
}
|
||||
|
||||
event.attendee.forEach((att) => {
|
||||
vevent[1].push([
|
||||
@@ -140,18 +141,19 @@ export function calendarEventToJCal(event: CalendarEvent): any[] {
|
||||
cutype: att.cutype,
|
||||
},
|
||||
"cal-address",
|
||||
`mailto:${att.cal_address}`,
|
||||
att.cal_address,
|
||||
]);
|
||||
});
|
||||
|
||||
const vtimezone: any[] = ["vtimezone", [["tzid", {}, "text", tzid]], []];
|
||||
|
||||
return ["vcalendar", [], [vevent, vtimezone]];
|
||||
const vtimezone = new ICAL.Timezone({
|
||||
component: TIMEZONES.zones[event.timezone].ics,
|
||||
tzid: event.timezone,
|
||||
});
|
||||
return ["vcalendar", [], [vevent, vtimezone.component.jCal]];
|
||||
}
|
||||
|
||||
function formatDateToICal(date: Date, tz?: string) {
|
||||
function formatDateToICal(date: Date) {
|
||||
// Format date like: 20250214T110000 (local time)
|
||||
// If tz is provided, use TZID param in DTSTART/DTEND
|
||||
|
||||
const pad = (n: number) => n.toString().padStart(2, "0");
|
||||
const year = date.getFullYear();
|
||||
const month = pad(date.getMonth() + 1);
|
||||
@@ -161,61 +163,3 @@ function formatDateToICal(date: Date, tz?: string) {
|
||||
const seconds = pad(date.getSeconds());
|
||||
return `${year}${month}${day}T${hours}${minutes}${seconds}`;
|
||||
}
|
||||
|
||||
export function calendarEventToICal(
|
||||
cal: Calendars,
|
||||
event: CalendarEvent
|
||||
): string {
|
||||
const lines = [];
|
||||
lines.push("BEGIN:VCALENDAR");
|
||||
lines.push("VERSION:2.0");
|
||||
lines.push("PRODID:-//Sabre//Sabre VObject 4.1.3//EN");
|
||||
if (cal.calscale) lines.push(`CALSCALE:${cal.calscale}`);
|
||||
if (cal.version) lines.push(`VERSION:${cal.version}`);
|
||||
|
||||
lines.push(TIMEZONES.zones[event.timezone].ics);
|
||||
lines.push("BEGIN:VEVENT");
|
||||
lines.push(`UID:${event.uid}`);
|
||||
|
||||
if (event.transp) lines.push(`TRANSP:${event.transp.toUpperCase()}`);
|
||||
if (event.start)
|
||||
lines.push(
|
||||
`DTSTART${event.timezone ? `;TZID=${event.timezone}` : ""}:` +
|
||||
formatDateToICal(event.start)
|
||||
);
|
||||
if (event.end)
|
||||
lines.push(
|
||||
`DTEND${event.timezone ? `;TZID=${event.timezone}` : ""}:` +
|
||||
formatDateToICal(event.end)
|
||||
);
|
||||
lines.push(`DTSTAMP:${ICAL.Time.now().toICALString()}`);
|
||||
|
||||
if (event.class) lines.push(`CLASS:${event.class.toUpperCase()}`);
|
||||
if (event.x_openpass_videoconference !== undefined)
|
||||
lines.push(
|
||||
`X-OPENPAAS-VIDEOCONFERENCE:${event.x_openpass_videoconference || ""}`
|
||||
);
|
||||
if (event.title) lines.push(`SUMMARY:${event.title}`);
|
||||
if (event.description) lines.push(`DESCRIPTION:${event.description}`);
|
||||
if (event.location) lines.push(`LOCATION:${event.location}`);
|
||||
|
||||
if (event.organizer) {
|
||||
lines.push(
|
||||
`ORGANIZER;CN=${event.organizer.cn}:${event.organizer.cal_address}`
|
||||
);
|
||||
}
|
||||
|
||||
event.attendee.forEach((att) => {
|
||||
lines.push(
|
||||
`ATTENDEE;PARTSTAT=${att.partstat};RSVP=${att.rsvp};ROLE=${att.role};CUTYPE=${att.cutype};CN=${att.cn}:${att.cal_address}`
|
||||
);
|
||||
});
|
||||
|
||||
if (event.stamp) lines.push(`DTSTAMP:${formatDateToICal(event.stamp)}Z`);
|
||||
if (event.sequence !== undefined) lines.push(`SEQUENCE:${event.sequence}`);
|
||||
|
||||
lines.push("END:VEVENT");
|
||||
lines.push("END:VCALENDAR\n");
|
||||
console.debug(lines.join("\r\n"));
|
||||
return lines.join("\r\n");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
export const TIMEZONES = {
|
||||
export interface TimeZones {
|
||||
version: string;
|
||||
aliases: Record<string, { aliasTo: string }>;
|
||||
zones: Record<
|
||||
string,
|
||||
{
|
||||
ics: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
export const TIMEZONES: TimeZones = {
|
||||
version: "2.2016c",
|
||||
aliases: {
|
||||
"AUS Central Standard Time": {
|
||||
|
||||
Reference in New Issue
Block a user