From 68e1e840a07e8b83b0336ecf20bc94bfe4c79cdb Mon Sep 17 00:00:00 2001 From: Dejan Date: Thu, 3 Oct 2024 23:37:25 +0200 Subject: [PATCH 01/14] - Introduced a google-calendar-utils.js and function to fetch Google calendar events for the provided token - Handled the response from the google calendar api to work with the eventData model for firebase --- calendar-integration/google-calendar-utils.js | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 calendar-integration/google-calendar-utils.js diff --git a/calendar-integration/google-calendar-utils.js b/calendar-integration/google-calendar-utils.js new file mode 100644 index 0000000..0b7bbd6 --- /dev/null +++ b/calendar-integration/google-calendar-utils.js @@ -0,0 +1,66 @@ +export async function fetchGoogleCalendarEvents(token) { + + const response = await fetch( + 'https://www.googleapis.com/calendar/v3/calendars/primary/events', + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + const data = await response.json(); + const googleEvents = []; + data.items?.forEach((item) => { + + let isAllDay = false; + const start = item.start; + let startDateTime; + if (start !== undefined) { + + const timezone = start.timeZone; + if (start.dateTime) { + const stringDate = start.dateTime; + startDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); + } else { + const stringDate = start.date; + startDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); + isAllDay = true; + } + } + + const end = item.end; + let endDateTime; + if (end !== undefined) { + const timezone = end.timeZone; + if (end.dateTime) { + const stringDate = end.dateTime; + endDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); + } else { + const stringDate = end.date; + endDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); + } + } + + const googleEvent = { + id: item.id, + title: item.summary, + startDate: startDateTime, + endDate: endDateTime, + allDay: isAllDay + }; + googleEvents.push(googleEvent); + }); + + return googleEvents; +} + +const options = { + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + timeZoneName: "short" +}; \ No newline at end of file From ba74025589ffd37f22838bb6ca46bfe43e924ee6 Mon Sep 17 00:00:00 2001 From: Dejan Date: Fri, 4 Oct 2024 01:04:11 +0200 Subject: [PATCH 02/14] - Introduced a button for syncing Google calendar - Implemented saving of the google event data in db - Added start date to the google calendar fetch api endpoint --- calendar-integration/google-calendar-utils.js | 127 ++++++++++-------- .../pages/settings/CalendarSettingsPage.tsx | 51 ++++++- 2 files changed, 117 insertions(+), 61 deletions(-) diff --git a/calendar-integration/google-calendar-utils.js b/calendar-integration/google-calendar-utils.js index 0b7bbd6..93a1e75 100644 --- a/calendar-integration/google-calendar-utils.js +++ b/calendar-integration/google-calendar-utils.js @@ -1,66 +1,75 @@ -export async function fetchGoogleCalendarEvents(token) { +export async function fetchGoogleCalendarEvents(token, startDate) { + const response = await fetch( + `https://www.googleapis.com/calendar/v3/calendars/primary/events?single_events=true&time_min=${startDate}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); - const response = await fetch( - 'https://www.googleapis.com/calendar/v3/calendars/primary/events', - { - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); + const data = await response.json(); + const googleEvents = []; + data.items?.forEach((item) => { + let isAllDay = false; + const start = item.start; + let startDateTime; + if (start !== undefined) { + const timezone = start.timeZone; + if (start.dateTime) { + const stringDate = start.dateTime; + startDateTime = new Date(stringDate).toLocaleString("en-us", { + ...options, + timeZone: timezone, + }); + } else { + const stringDate = start.date; + startDateTime = new Date(stringDate).toLocaleString("en-us", { + ...options, + timeZone: timezone, + }); + isAllDay = true; + } + } - const data = await response.json(); - const googleEvents = []; - data.items?.forEach((item) => { + const end = item.end; + let endDateTime; + if (end !== undefined) { + const timezone = end.timeZone; + if (end.dateTime) { + const stringDate = end.dateTime; + endDateTime = new Date(stringDate).toLocaleString("en-us", { + ...options, + timeZone: timezone, + }); + } else { + const stringDate = end.date; + endDateTime = new Date(stringDate).toLocaleString("en-us", { + ...options, + timeZone: timezone, + }); + } + } - let isAllDay = false; - const start = item.start; - let startDateTime; - if (start !== undefined) { + const googleEvent = { + id: item.id, + title: item.summary, + startDate: startDateTime, + endDate: endDateTime, + allDay: isAllDay, + }; + googleEvents.push(googleEvent); + }); - const timezone = start.timeZone; - if (start.dateTime) { - const stringDate = start.dateTime; - startDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); - } else { - const stringDate = start.date; - startDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); - isAllDay = true; - } - } - - const end = item.end; - let endDateTime; - if (end !== undefined) { - const timezone = end.timeZone; - if (end.dateTime) { - const stringDate = end.dateTime; - endDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); - } else { - const stringDate = end.date; - endDateTime = new Date(stringDate).toLocaleString("en-us", {...options, timeZone: timezone}); - } - } - - const googleEvent = { - id: item.id, - title: item.summary, - startDate: startDateTime, - endDate: endDateTime, - allDay: isAllDay - }; - googleEvents.push(googleEvent); - }); - - return googleEvents; + return googleEvents; } const options = { - year: "numeric", - month: "long", - day: "numeric", - hour: "numeric", - minute: "numeric", - second: "numeric", - timeZoneName: "short" -}; \ No newline at end of file + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + timeZoneName: "short", +}; diff --git a/components/pages/settings/CalendarSettingsPage.tsx b/components/pages/settings/CalendarSettingsPage.tsx index ecf575d..9cdf553 100644 --- a/components/pages/settings/CalendarSettingsPage.tsx +++ b/components/pages/settings/CalendarSettingsPage.tsx @@ -1,21 +1,41 @@ import { AntDesign, Ionicons } from "@expo/vector-icons"; import React, { useState } from "react"; -import { Button, View, Text, Checkbox } from "react-native-ui-lib"; +import { Button, Checkbox, Text, View } from "react-native-ui-lib"; import { StyleSheet } from "react-native"; import { colorMap } from "@/contexts/SettingsContext"; import { TouchableOpacity } from "react-native-gesture-handler"; +import { fetchGoogleCalendarEvents } from "@/calendar-integration/google-calendar-utils"; +import { useCreateEvent } from "@/hooks/firebase/useCreateEvent"; const CalendarSettingsPage = (props: { setSelectedPage: (page: number) => void; }) => { const [selectedColor, setSelectedColor] = useState(colorMap.pink); const [startDate, setStartDate] = useState(true); + + const { mutateAsync: createEvent } = useCreateEvent(); + + // Note: user token for the correct provider is needed + const fetchAndSaveGoogleEvents = (token: string) => { + const timeMin = new Date(new Date().setHours(0, 0, 0, 0)).toISOString(); + + fetchGoogleCalendarEvents(token, timeMin).then((response) => { + response?.forEach((item) => saveData(item)); + }); + }; + + async function saveData(item) { + await createEvent(item); + } + return ( props.setSelectedPage(0)}> - Return to main settings + + Return to main settings + Calendar settings @@ -90,6 +110,33 @@ const CalendarSettingsPage = (props: { + + Calendars + {/** Note: Should check for the user if it has connected calendars **/} + +