diff --git a/src/stories/components/calendar/CalendarBottomBar.stories.tsx b/src/stories/components/calendar/CalendarBottomBar.stories.tsx
index 10b90746..743841af 100644
--- a/src/stories/components/calendar/CalendarBottomBar.stories.tsx
+++ b/src/stories/components/calendar/CalendarBottomBar.stories.tsx
@@ -92,6 +92,7 @@ export const Default: Story = {
status: examplePsyCourse.status,
},
],
+ calendarRef: { current: null },
},
render: props => (
diff --git a/src/views/components/calendar/Calendar/Calendar.tsx b/src/views/components/calendar/Calendar/Calendar.tsx
index f32f4132..5f8bbcf3 100644
--- a/src/views/components/calendar/Calendar/Calendar.tsx
+++ b/src/views/components/calendar/Calendar/Calendar.tsx
@@ -6,7 +6,7 @@ import { CalendarSchedules } from '@views/components/calendar/CalendarSchedules/
import ImportantLinks from '@views/components/calendar/ImportantLinks';
import CourseCatalogInjectedPopup from '@views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup';
import { useFlattenedCourseSchedule } from '@views/hooks/useFlattenedCourseSchedule';
-import React from 'react';
+import React, { useRef } from 'react';
import { ExampleCourse } from 'src/stories/components/PopupCourseBlock.stories';
export const flags = ['WR', 'QR', 'GC', 'CD', 'E', 'II'];
@@ -20,6 +20,7 @@ interface Props {
* @returns
*/
export function Calendar(): JSX.Element {
+ const calendarRef = useRef(null);
const { courseCells, activeSchedule } = useFlattenedCourseSchedule();
const [course, setCourse] = React.useState(null);
@@ -38,11 +39,11 @@ export function Calendar(): JSX.Element {
diff --git a/src/views/components/calendar/CalendarBottomBar/CalendarBottomBar.tsx b/src/views/components/calendar/CalendarBottomBar/CalendarBottomBar.tsx
index e769836e..05190fb1 100644
--- a/src/views/components/calendar/CalendarBottomBar/CalendarBottomBar.tsx
+++ b/src/views/components/calendar/CalendarBottomBar/CalendarBottomBar.tsx
@@ -1,21 +1,113 @@
-import type { CalendarCourseCellProps } from '@views/components/calendar/CalendarCourseCell/CalendarCourseCell';
-import CalendarCourseBlock from '@views/components/calendar/CalendarCourseCell/CalendarCourseCell';
+import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
import { Button } from '@views/components/common/Button/Button';
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
+import { toPng } from 'html-to-image';
import React from 'react';
import CalendarMonthIcon from '~icons/material-symbols/calendar-month';
import ImageIcon from '~icons/material-symbols/image';
+import type { CalendarCourseCellProps } from '../CalendarCourseCell/CalendarCourseCell';
+import CalendarCourseBlock from '../CalendarCourseCell/CalendarCourseCell';
+
+const CAL_MAP = {
+ Sunday: 'SU',
+ Monday: 'MO',
+ Tuesday: 'TU',
+ Wednesday: 'WE',
+ Thursday: 'TH',
+ Friday: 'FR',
+ Saturday: 'SA',
+};
+
type CalendarBottomBarProps = {
courses?: CalendarCourseCellProps[];
+ calendarRef: React.RefObject;
};
+async function getSchedule() {
+ const schedules = await UserScheduleStore.get('schedules');
+ const activeIndex = await UserScheduleStore.get('activeIndex');
+ const schedule = schedules[activeIndex];
+ return schedule;
+}
+
/**
*
*/
-export const CalendarBottomBar = ({ courses }: CalendarBottomBarProps): JSX.Element => {
+export const CalendarBottomBar = ({ courses, calendarRef }: CalendarBottomBarProps): JSX.Element => {
+ const saveAsPng = () => {
+ if (calendarRef.current) {
+ toPng(calendarRef.current, { cacheBust: true })
+ .then(dataUrl => {
+ const link = document.createElement('a');
+ link.download = 'my-calendar.png';
+ link.href = dataUrl;
+ link.click();
+ })
+ .catch(err => {
+ console.log(err);
+ });
+ }
+ };
+
+ function formatToHHMMSS(minutes) {
+ const hours = String(Math.floor(minutes / 60)).padStart(2, '0');
+ const mins = String(minutes % 60).padStart(2, '0');
+ return `${hours}${mins}00`;
+ }
+
+ function downloadICS(data) {
+ const blob = new Blob([data], { type: 'text/calendar' });
+ const url = URL.createObjectURL(blob);
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = 'schedule.ics';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ }
+
+ const saveAsCal = async () => {
+ const schedule = await getSchedule(); // Assumes this fetches the current active schedule
+
+ let icsString = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nX-WR-CALNAME:My Schedule\n';
+
+ schedule.courses.forEach(course => {
+ course.schedule.meetings.forEach(meeting => {
+ const { startTime, endTime, days, location } = meeting;
+
+ // Format start and end times to HHMMSS
+ const formattedStartTime = formatToHHMMSS(startTime);
+ const formattedEndTime = formatToHHMMSS(endTime);
+
+ // Map days to ICS compatible format
+ console.log(days);
+ const icsDays = days.map(day => CAL_MAP[day]).join(',');
+ console.log(icsDays);
+
+ // Assuming course has date started and ended, adapt as necessary
+ const year = new Date().getFullYear(); // Example year, adapt accordingly
+ // Example event date, adapt startDate according to your needs
+ const startDate = `20240101T${formattedStartTime}`;
+ const endDate = `20240101T${formattedEndTime}`;
+
+ icsString += `BEGIN:VEVENT\n`;
+ icsString += `DTSTART:${startDate}\n`;
+ icsString += `DTEND:${endDate}\n`;
+ icsString += `RRULE:FREQ=WEEKLY;BYDAY=${icsDays}\n`;
+ icsString += `SUMMARY:${course.fullName}\n`;
+ icsString += `LOCATION:${location.building} ${location.room}\n`;
+ icsString += `END:VEVENT\n`;
+ });
+ });
+
+ icsString += 'END:VCALENDAR';
+
+ downloadICS(icsString);
+ };
+
if (courses?.length === -1) console.log('foo'); // dumb line to make eslint happy
return (
@@ -34,10 +126,10 @@ export const CalendarBottomBar = ({ courses }: CalendarBottomBarProps): JSX.Elem
-
diff --git a/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx b/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx
index 36e29995..59afe4bf 100644
--- a/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx
+++ b/src/views/components/calendar/CalendarGrid/CalendarGrid.tsx
@@ -22,6 +22,8 @@ interface Props {
* Grid of CalendarGridCell components forming the user's course schedule calendar view
* @param props
*/
+// function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren): JSX.Element {
+// const [grid, setGrid] = useState([]);
function CalendarGrid({ courseCells, saturdayClass, setCourse }: React.PropsWithChildren): JSX.Element {
// const [grid, setGrid] = useState([]);
const calendarRef = useRef(null); // Create a ref for the calendar grid