diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx
new file mode 100644
index 0000000..d8004e9
--- /dev/null
+++ b/src/components/Calendar.tsx
@@ -0,0 +1,121 @@
+import * as React from "react"
+import { dowToString } from "../lib/utils";
+import type { Event, SecretsCalendar } from "../lib/interfaces";
+import * as styles from "../styles/containers/Calendar.module.css"
+
+const CALENDAR_REFRESH_INTERVAL = 15 * 60 * 1000;
+const CALENDAR_TOKEN_REFRESH_INTERVAL = 45 * 60 * 1000;
+
+function daysDifference(date1: Date, date2: Date) {
+ if (date1.getTime() > date2.getTime()) {
+ let tmp = date2;
+ date2 = date1;
+ date1 = tmp;
+ }
+ return Math.ceil((date2.getTime() - date1.getTime()) / 1000 / 60 / 60 / 24);
+}
+
+const Calendar = ({ secrets }: { secrets: SecretsCalendar }) => {
+ const [token, setToken] = React.useState("")
+ const [events, setEvents] = React.useState([])
+
+ React.useEffect(() => {
+ requestToken().then(pullCalendar)
+ const calendarInterval = setInterval(pullCalendar, CALENDAR_REFRESH_INTERVAL);
+ const calendarTokenInterval = setInterval(requestToken, CALENDAR_TOKEN_REFRESH_INTERVAL);
+
+ return () => {
+ clearInterval(calendarInterval);
+ clearInterval(calendarTokenInterval);
+ }
+ }, [])
+
+ const processEventData = (events: Event[]) => {
+ const eventTable = [];
+ let lastDate = "";
+ let i = 0;
+ for (const event of events) {
+ const startDate = new Date(event.start.date ? event.start.date : event.start.dateTime)
+ const startDateString = `${startDate.getFullYear()}${startDate.getMonth()}${startDate.getDate()}`
+ if (startDateString !== lastDate) {
+ lastDate = startDateString;
+ const dayDiff = daysDifference(new Date(), startDate);
+ let dayDiffString: string;
+ switch (dayDiff) {
+ case 0: dayDiffString = "Heute"
+ break;
+ case 1: dayDiffString = "Morgen"
+ break;
+ default: dayDiffString = `${dayDiff} Tage`;
+ break;
+ }
+ eventTable.push(
+
+ {dowToString(startDate.getDay())}, {startDate.getDate()}. {startDate.getMonth() + 1}
+ ({dayDiffString})
+ |
+ );
+ }
+
+ if (event.start.date) {
+ eventTable.push(
+ {event.summary} |
+ );
+ } else {
+ eventTable.push(
+
+ {event.summary} |
+ {startDate.getHours()}:{startDate.getMinutes().toString().padStart(2, "0")} |
+
+ )
+ }
+ }
+ return eventTable;
+ }
+
+ const requestToken = async () => {
+ const response = await fetch("https://accounts.google.com/o/oauth2/token", {
+ method: "POST",
+ body: JSON.stringify({
+ grant_type: "refresh_token",
+ refresh_token: secrets.refreshToken,
+ client_id: secrets.clientId,
+ clientSecret: secrets.clientSecret
+ })
+ });
+ const token = await response.json();
+ setToken(token.access_token);
+ return token.access_token;
+ }
+
+ const pullCalendar = async (provToken: string) => {
+ const correctToken = provToken || token;
+ if (!correctToken || correctToken === "") return;
+
+ const timeMin = new Date();
+ timeMin.setHours(timeMin.getHours() - 1);
+ const params = new URLSearchParams({
+ orderBy: "startTime",
+ fields: "items(creator,start,summary)",
+ singleEvents: "true",
+ maxResults: "10",
+ timeMin: timeMin.toISOString(),
+ key: (secrets.apiKey as string)
+ });
+
+ const response = await fetch(`https://www.googleapis.com/calendar/v3/calendars/${secrets.calendarId}/events?${params.toString()}`, {
+ headers: { Authorization: `Bearer ${correctToken}` }
+ });
+ const events = await response.json();
+ setEvents(processEventData(events.items));
+ }
+
+ return
+
+}
+
+export default Calendar;
\ No newline at end of file
diff --git a/src/components/WeatherAndTime.tsx b/src/components/WeatherAndTime.tsx
index 35f8f2b..3b09cec 100644
--- a/src/components/WeatherAndTime.tsx
+++ b/src/components/WeatherAndTime.tsx
@@ -1,46 +1,16 @@
import * as React from "react"
-import type { WeatherInfo } from "../lib/interfaces";
+import { dowToString, monthToString } from "../lib/utils";
+import type { SecretsWeather, WeatherInfo } from "../lib/interfaces";
import * as styles from "../styles/containers/WeatherAndTime.module.css";
const WEATHER_REFRESH_INTERVAL = 15 * 60 * 1000;
-function dowToString(dow: number) {
- switch (dow) {
- case 0: return "Sonntag";
- case 1: return "Montag";
- case 2: return "Dienstag";
- case 3: return "Mittwoch";
- case 4: return "Donnerstag";
- case 5: return "Freitag";
- case 6: return "Samstag";
- default: return;
- }
-}
-
-function monthToString(month: number) {
- switch (month) {
- case 0: return "Januar";
- case 1: return "Februar";
- case 2: return "März";
- case 3: return "April";
- case 4: return "Mail";
- case 5: return "Juni";
- case 6: return "Juli";
- case 7: return "August";
- case 8: return "September";
- case 9: return "Oktober";
- case 10: return "November";
- case 11: return "Dezember";
- default: return;
- }
-}
-
function getWeatherIcon(icon: string) {
const ImportedIcon = require(`../images/weather/${icon}.svg`);
return
}
-const WeatherAndTimeContainer = ({ apiKey, coords }) => {
+const WeatherAndTime = ({ secrets }: { secrets: SecretsWeather }) => {
const [date, setDate] = React.useState(new Date());
const [weather, setWeather] = React.useState({
currently: {
@@ -77,7 +47,7 @@ const WeatherAndTimeContainer = ({ apiKey, coords }) => {
}, [])
const pullWeather = () => {
- fetch(`https://api.pirateweather.net/forecast/${apiKey}/${coords}?exclude=minutely,hourly&lang=de&units=ca`)
+ fetch(`https://api.pirateweather.net/forecast/${secrets.apiKey}/${secrets.coords}?exclude=minutely,hourly&lang=de&units=ca`)
.then(resp => resp.json())
.then(setWeather);
}
@@ -135,4 +105,4 @@ const WeatherAndTimeContainer = ({ apiKey, coords }) => {
)
}
-export default WeatherAndTimeContainer;
\ No newline at end of file
+export default WeatherAndTime;
\ No newline at end of file
diff --git a/src/lib/interfaces.ts b/src/lib/interfaces.ts
index 3bdf8db..37eb94f 100644
--- a/src/lib/interfaces.ts
+++ b/src/lib/interfaces.ts
@@ -1,3 +1,16 @@
+export interface SecretsWeather {
+ apiKey: string;
+ coords: string;
+}
+
+export interface SecretsCalendar {
+ apiKey: string;
+ calendarId: string;
+ clientId: string;
+ clientSecret: string;
+ refreshToken: string;
+}
+
export interface WeatherInfo {
currently: {
icon: string;
@@ -12,4 +25,9 @@ export interface WeatherInfo {
temperatureLow: number;
}[]
}
+}
+
+export interface Event {
+ start: { dateTime: string; date?: string; };
+ summary: string;
}
\ No newline at end of file
diff --git a/src/lib/types.d.ts b/src/lib/types.d.ts
index a3f3afb..dff4fc6 100644
--- a/src/lib/types.d.ts
+++ b/src/lib/types.d.ts
@@ -1,4 +1,4 @@
declare module '*.css' {
- const content: {[className: string]: string};
- export = content;
- }
\ No newline at end of file
+ const content: { [className: string]: string };
+ export = content;
+}
\ No newline at end of file
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..6d94904
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,30 @@
+export function dowToString(dow: number) {
+ switch (dow) {
+ case 0: return "Sonntag";
+ case 1: return "Montag";
+ case 2: return "Dienstag";
+ case 3: return "Mittwoch";
+ case 4: return "Donnerstag";
+ case 5: return "Freitag";
+ case 6: return "Samstag";
+ default: return;
+ }
+}
+
+export function monthToString(month: number) {
+ switch (month) {
+ case 0: return "Januar";
+ case 1: return "Februar";
+ case 2: return "März";
+ case 3: return "April";
+ case 4: return "Mail";
+ case 5: return "Juni";
+ case 6: return "Juli";
+ case 7: return "August";
+ case 8: return "September";
+ case 9: return "Oktober";
+ case 10: return "November";
+ case 11: return "Dezember";
+ default: return;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index d48bcce..fdc212c 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,5 +1,6 @@
import * as React from "react"
import secrets from "../../secrets.json"
+import Calendar from "../components/Calendar";
import WeatherAndTimeContainer from "../components/WeatherAndTime"
function importAll(r) {
@@ -29,7 +30,8 @@ const IndexPage = () => {
}
return (
-
+
+
)
}
diff --git a/src/styles/containers/Calendar.module.css b/src/styles/containers/Calendar.module.css
new file mode 100644
index 0000000..797355a
--- /dev/null
+++ b/src/styles/containers/Calendar.module.css
@@ -0,0 +1,27 @@
+.container {
+ grid-area: calendar;
+}
+.container table {
+ width: 100%;
+ border-collapse: collapse;
+}
+.calendarDateHeader {
+ font-weight: bold;
+ font-size: 2vh;
+ background: rgba(0, 0, 0, .1);
+}
+.calendarDateHeaderSub {
+ font-size: 1.5vh;
+ padding-top: 0.4vh;
+ float: right;
+}
+.container table td {
+ padding: 5px;
+}
+.container tr td:first-of-type {
+ width: 100%;
+}
+.container tr.calendarEntry {
+ border-top: 1px solid #000000;
+ font-size: 1.8vh;
+}
\ No newline at end of file