+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- schedule.id}
- onReordered={reordered => {
- const activeSchedule = getActiveSchedule();
- const activeIndex = reordered.findIndex(s => s.id === activeSchedule.id);
+
+
+
+
+
+ schedule.id}
+ onReordered={reordered => {
+ const activeSchedule = getActiveSchedule();
+ const activeIndex = reordered.findIndex(s => s.id === activeSchedule.id);
- // don't care about the promise
- UserScheduleStore.set('schedules', reordered);
- UserScheduleStore.set('activeIndex', activeIndex);
- }}
- gap={10}
- >
- {(schedule, handleProps) => (
- {
- switchSchedule(schedule.id);
- }}
- dragHandleProps={handleProps}
- />
- )}
-
-
-
- {activeSchedule?.courses?.length === 0 && (
-
-
- {funny}
-
-
- (No courses added)
-
-
- )}
-
- {activeSchedule?.courses?.length > 0 && (
-
{
- activeSchedule.courses = reordered;
- replaceSchedule(getActiveSchedule(), activeSchedule);
+ // don't care about the promise
+ UserScheduleStore.set('schedules', reordered);
+ UserScheduleStore.set('activeIndex', activeIndex);
+ }}
+ gap={10}
+ >
+ {(schedule, handleProps) => (
+ {
+ switchSchedule(schedule.id);
}}
- itemKey={e => e.uniqueId}
- gap={10}
- >
- {(course, handleProps) => (
-
- )}
-
+ dragHandleProps={handleProps}
+ />
)}
+
+
+
createSchedule('New Schedule')}
+ >
+
+
-
-
- {enableCourseStatusChips && (
- <>
-
-
-
- >
- )}
-
- {enableCourseRefreshing && (
-
-
- DATA LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
-
- {
- setIsRefreshing(true);
- }}
- >
-
-
-
+
+
+ {activeSchedule?.courses?.length === 0 && (
+
+
+ {funny}
+
+
+ (No courses added)
+
+
+ )}
+
+ {activeSchedule?.courses?.length > 0 && (
+
{
+ activeSchedule.courses = reordered;
+ replaceSchedule(getActiveSchedule(), activeSchedule);
+ }}
+ itemKey={e => e.uniqueId}
+ gap={10}
+ >
+ {(course, handleProps) => (
+
)}
-
+
+ )}
+
+
+
+ {enableCourseStatusChips && (
+ <>
+
+
+
+ >
+ )}
-
-
+ {enableDataRefreshing && (
+
+
+ LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
+
+ {/* {
+ setIsRefreshing(true);
+ }}
+ >
+
+ */}
+
+ )}
+
+
);
}
diff --git a/src/views/components/ReportIssueMain.tsx b/src/views/components/ReportIssueMain.tsx
new file mode 100644
index 000000000..372df3e39
--- /dev/null
+++ b/src/views/components/ReportIssueMain.tsx
@@ -0,0 +1,120 @@
+import 'uno.css';
+
+import { captureFeedback } from '@sentry/react';
+import React, { useState } from 'react';
+
+import { Button } from './common/Button';
+import Text from './common/Text/Text';
+
+/**
+ * ReportIssueMain component renders a feedback form for users to submit their email and feedback.
+ *
+ * @returns The rendered component.
+ */
+export default function ReportIssueMain(): JSX.Element {
+ const [email, setEmail] = useState('');
+ const [feedback, setFeedback] = useState('');
+ const [isSubmitted, setIsSubmitted] = useState(false);
+
+ const submitFeedback = async () => {
+ if (!email || !feedback) {
+ throw new Error('Email and feedback are required');
+ }
+ // Here you would typically send the feedback to a server
+ await captureFeedback(
+ {
+ message: feedback || 'No feedback provided',
+ email,
+ tags: {
+ version: chrome.runtime.getManifest().version,
+ },
+ },
+ {
+ includeReplay: false,
+ }
+ );
+
+ // Reset form fields and close the dialog
+ setEmail('');
+ setFeedback('');
+ setIsSubmitted(true);
+ };
+
+ if (isSubmitted) {
+ return (
+
+
+ Thank you
+
+
+ Your feedback has been submitted. You may close this window.
+
+ window.close()}>
+ Done
+
+
+ );
+ }
+
+ if (isSubmitted) {
+ return (
+
+
{`Hook'em Horns!`}
+
Your feedback is music to our ears. Thanks for helping us improve!
+
window.close()}
+ >
+ Close
+
+
+ );
+ }
+
+ return (
+
+
Longhorn Feedback
+
Help us make UT Registration Plus even better!
+
+
+
+ );
+}
diff --git a/src/views/components/Settings.tsx b/src/views/components/Settings.tsx
deleted file mode 100644
index 9ded32bc9..000000000
--- a/src/views/components/Settings.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-
-type Props = {
- className?: string;
-};
-
-/**
- * Component to hold everything for the settings page
- * @param props className
- * @returns The content for the settings page
- */
-export default function Settings({ className }: Props): JSX.Element {
- // TODO: Implement the settings page
- return
this will be finished laterrrrrrr
;
-}
diff --git a/src/views/components/calendar/Calendar.tsx b/src/views/components/calendar/Calendar.tsx
index 7cd5799b3..c1ad86dd3 100644
--- a/src/views/components/calendar/Calendar.tsx
+++ b/src/views/components/calendar/Calendar.tsx
@@ -8,6 +8,7 @@ import ImportantLinks from '@views/components/calendar/ImportantLinks';
import Divider from '@views/components/common/Divider';
import CourseCatalogInjectedPopup from '@views/components/injected/CourseCatalogInjectedPopup/CourseCatalogInjectedPopup';
import { CalendarContext } from '@views/contexts/CalendarContext';
+import useCourseFromUrl from '@views/hooks/useCourseFromUrl';
import { useFlattenedCourseSchedule } from '@views/hooks/useFlattenedCourseSchedule';
import { MessageListener } from 'chrome-extension-toolkit';
import React, { useEffect, useState } from 'react';
@@ -21,21 +22,7 @@ import TeamLinks from './TeamLinks';
export default function Calendar(): JSX.Element {
const { courseCells, activeSchedule } = useFlattenedCourseSchedule();
- const [course, setCourse] = useState
((): Course | null => {
- const urlParams = new URLSearchParams(window.location.search);
- const uniqueIdRaw = urlParams.get('uniqueId');
- if (uniqueIdRaw === null) return null;
-
- const uniqueId = Number(uniqueIdRaw);
- const course = activeSchedule.courses.find(course => course.uniqueId === uniqueId);
- if (course === undefined) return null;
-
- urlParams.delete('uniqueId');
- const newUrl = `${window.location.pathname}?${urlParams}`.replace(/\?$/, '');
- window.history.replaceState({}, '', newUrl);
-
- return course;
- });
+ const [course, setCourse] = useState(useCourseFromUrl());
const [showPopup, setShowPopup] = useState(course !== null);
const [showSidebar, setShowSidebar] = useState(true);
@@ -94,6 +81,8 @@ export default function Calendar(): JSX.Element {