From 685162a58e9eb5f2b46d69a0e3cdc4b03015eb80 Mon Sep 17 00:00:00 2001
From: Eduardo Szeckir
Date: Wed, 17 May 2023 18:50:56 -0700
Subject: [PATCH 01/57] initial conversion to nextjs
---
package-lock.json | 45 ----------------
package.json | 2 -
pages/[[...app]].tsx | 52 -------------------
pages/_app.tsx | 20 ++++++-
pages/_document.tsx | 13 +++++
pages/calendar/[term].tsx | 5 ++
pages/calendar/index.tsx | 5 ++
pages/index.tsx | 5 ++
src/common/header/components/NavButtons.tsx | 16 +++---
src/common/header/components/TermSelect.tsx | 28 +++++-----
.../header/containers/HeaderContainer.tsx | 18 +++----
src/common/layouts/Page.tsx | 22 ++++----
.../layouts/sidebar/components/Card.tsx | 14 ++---
.../sidebar/components/CoursesList.tsx | 14 ++---
.../sidebar/components/SearchResults.tsx | 8 +--
.../sidebar/components/SubjectsList.tsx | 11 ++--
.../layouts/sidebar/variants/Courses.tsx | 34 ++++++------
.../sidebar/variants/SearchResults.tsx | 8 ++-
src/common/notFound/NotFound.tsx | 4 +-
src/pages/calendar/components/Section.tsx | 5 +-
src/pages/calendar/containers/Content.tsx | 3 +-
src/pages/calendar/index.tsx | 8 +--
src/routes.tsx | 2 +-
23 files changed, 151 insertions(+), 191 deletions(-)
delete mode 100644 pages/[[...app]].tsx
create mode 100644 pages/_document.tsx
create mode 100644 pages/calendar/[term].tsx
create mode 100644 pages/calendar/index.tsx
create mode 100644 pages/index.tsx
diff --git a/package-lock.json b/package-lock.json
index 29f4f4ce..ffcbf52f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,8 +34,6 @@
"react-icons": "^4.3.1",
"react-instantsearch-core": "^6.18.0",
"react-instantsearch-dom": "^6.18.0",
- "react-router": "^6.0.0-beta.0",
- "react-router-dom": "^6.0.0-beta.0",
"restful-react": "^15.9.3",
"rrule": "^2.6.4",
"sass": "^1.60.0",
@@ -17088,32 +17086,6 @@
}
}
},
- "node_modules/react-router": {
- "version": "6.0.0-beta.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.0.0-beta.0.tgz",
- "integrity": "sha512-VgMdfpVcmFQki/LZuLh8E/MNACekDetz4xqft+a6fBZvvJnVqKbLqebF7hyoawGrV1HcO5tVaUang2Og4W2j1Q==",
- "dependencies": {
- "prop-types": "^15.7.2"
- },
- "peerDependencies": {
- "history": ">=5",
- "react": ">=16.8"
- }
- },
- "node_modules/react-router-dom": {
- "version": "6.0.0-beta.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.0.0-beta.0.tgz",
- "integrity": "sha512-36yNNGMT8RB9FRPL9nKJi6HKDkgOakU+o/2hHpSzR6e37gN70MpOU6QQlmif4oAWWBwjyGc3ZNOMFCsFuHUY5w==",
- "dependencies": {
- "prop-types": "^15.7.2",
- "react-router": "6.0.0-beta.0"
- },
- "peerDependencies": {
- "history": ">=5",
- "react": ">=16.8",
- "react-dom": ">=16.8"
- }
- },
"node_modules/react-share": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-share/-/react-share-4.4.0.tgz",
@@ -32808,23 +32780,6 @@
"tslib": "^1.0.0"
}
},
- "react-router": {
- "version": "6.0.0-beta.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.0.0-beta.0.tgz",
- "integrity": "sha512-VgMdfpVcmFQki/LZuLh8E/MNACekDetz4xqft+a6fBZvvJnVqKbLqebF7hyoawGrV1HcO5tVaUang2Og4W2j1Q==",
- "requires": {
- "prop-types": "^15.7.2"
- }
- },
- "react-router-dom": {
- "version": "6.0.0-beta.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.0.0-beta.0.tgz",
- "integrity": "sha512-36yNNGMT8RB9FRPL9nKJi6HKDkgOakU+o/2hHpSzR6e37gN70MpOU6QQlmif4oAWWBwjyGc3ZNOMFCsFuHUY5w==",
- "requires": {
- "prop-types": "^15.7.2",
- "react-router": "6.0.0-beta.0"
- }
- },
"react-share": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/react-share/-/react-share-4.4.0.tgz",
diff --git a/package.json b/package.json
index 59a7e5fb..4553de5f 100644
--- a/package.json
+++ b/package.json
@@ -29,8 +29,6 @@
"react-icons": "^4.3.1",
"react-instantsearch-core": "^6.18.0",
"react-instantsearch-dom": "^6.18.0",
- "react-router": "^6.0.0-beta.0",
- "react-router-dom": "^6.0.0-beta.0",
"restful-react": "^15.9.3",
"rrule": "^2.6.4",
"sass": "^1.60.0",
diff --git a/pages/[[...app]].tsx b/pages/[[...app]].tsx
deleted file mode 100644
index 09ec7a7c..00000000
--- a/pages/[[...app]].tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { useEffect, useState } from 'react';
-
-import type { AppProps /*, AppContext */ } from 'next/app';
-import Head from 'next/head';
-
-import { App as CreateReactApp } from '../src/App';
-
-const Metadata = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
-
-function App({ Component, pageProps }: AppProps): JSX.Element {
- const [isMounted, setIsMounted] = useState(false);
-
- useEffect(() => {
- setIsMounted(true);
- }, []);
-
- if (!isMounted) {
- return (
-
-
-
- );
- }
-
- return (
- <>
-
-
- >
- );
-}
-export default App;
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 1d46e3e8..ae9c2a69 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,9 +1,27 @@
+import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
+import algoliasearch from 'algoliasearch';
import type { AppProps /*, AppContext */ } from 'next/app';
// React Big Calendar
+import { Helmet } from 'react-helmet';
import 'react-big-calendar/lib/sass/styles.scss';
+import { InstantSearch } from 'react-instantsearch-core';
import '../src/index.css';
+import { RestfulProvider } from 'restful-react';
+
+import { customTheme } from 'lib/theme';
+const searchClient = algoliasearch('CR92D3S394', '5477854d63b676fe021f8f83f5839a3a');
function App({ Component, pageProps }: AppProps): JSX.Element {
- return ;
+ return (
+
+
+
+
+
+ ;
+
+
+
+ );
}
export default App;
diff --git a/pages/_document.tsx b/pages/_document.tsx
new file mode 100644
index 00000000..e1e9cbbb
--- /dev/null
+++ b/pages/_document.tsx
@@ -0,0 +1,13 @@
+import { Html, Head, Main, NextScript } from 'next/document';
+
+export default function Document() {
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/pages/calendar/[term].tsx b/pages/calendar/[term].tsx
new file mode 100644
index 00000000..3785ec63
--- /dev/null
+++ b/pages/calendar/[term].tsx
@@ -0,0 +1,5 @@
+import { Calendar } from 'pages/calendar';
+
+export default function CalendarTermPage(): JSX.Element {
+ return ;
+}
diff --git a/pages/calendar/index.tsx b/pages/calendar/index.tsx
new file mode 100644
index 00000000..72921219
--- /dev/null
+++ b/pages/calendar/index.tsx
@@ -0,0 +1,5 @@
+import { Calendar } from 'pages/calendar';
+
+export default function CalendarPage(): JSX.Element {
+ return ;
+}
diff --git a/pages/index.tsx b/pages/index.tsx
new file mode 100644
index 00000000..6ebce3e2
--- /dev/null
+++ b/pages/index.tsx
@@ -0,0 +1,5 @@
+import { Home } from 'pages/home';
+
+export default function HomePage(): JSX.Element {
+ return ;
+}
diff --git a/src/common/header/components/NavButtons.tsx b/src/common/header/components/NavButtons.tsx
index 2ae9c550..587bf30f 100644
--- a/src/common/header/components/NavButtons.tsx
+++ b/src/common/header/components/NavButtons.tsx
@@ -1,25 +1,27 @@
import { Button, ButtonGroup, VStack, Divider } from '@chakra-ui/react';
-import { useNavigate, useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
import { getCurrentTerm } from 'lib/utils/terms';
export function NavButtons(): JSX.Element {
const smallScreen = useSmallScreen();
- const { term } = useParams();
+ const router = useRouter();
+ const { term } = router.query;
+ // const { term } = useParams();
- const navigate = useNavigate();
+ // const navigate = useNavigate();
const onClick = (event: React.MouseEvent) => {
const name = event.currentTarget.getAttribute('name');
if (name === 'calendar') {
- navigate(`/calendar/${term || getCurrentTerm()}`);
+ router.push(`/calendar/${term || getCurrentTerm()}`);
} else if (name === 'scheduler') {
- navigate(`/scheduler/${term || getCurrentTerm()}`);
+ router.push(`/scheduler/${term || getCurrentTerm()}`);
} else if (name === 'register') {
- navigate(`/registration/${term || getCurrentTerm()}`);
+ router.push(`/registration/${term || getCurrentTerm()}`);
} else if (name === 'booklist') {
- navigate(`/booklist/${term || getCurrentTerm()}`);
+ router.push(`/booklist/${term || getCurrentTerm()}`);
}
};
diff --git a/src/common/header/components/TermSelect.tsx b/src/common/header/components/TermSelect.tsx
index 727b15b1..2acc1088 100644
--- a/src/common/header/components/TermSelect.tsx
+++ b/src/common/header/components/TermSelect.tsx
@@ -1,8 +1,7 @@
import React from 'react';
import { Select } from '@chakra-ui/react';
-import { useMatch, useNavigate, useParams } from 'react-router';
-import { useSearchParams } from 'react-router-dom';
+import { useRouter } from 'next/router';
import { useSessionStorage } from 'lib/hooks/storage/useSessionStorage';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -11,33 +10,32 @@ import { getCurrentTerm, getReadableTerm } from 'lib/utils/terms';
const terms = ['202205', '202209', '202301'];
export function TermSelect(): JSX.Element {
- const { subject } = useParams();
+ const router = useRouter();
+ const { subject } = router.query;
const [selectedTerm, setTerm] = useSessionStorage('user:term', getCurrentTerm());
- const [searchParams] = useSearchParams();
+ const searchParams = new URLSearchParams(window.location.search);
const pid = searchParams.get('pid');
const mode = useDarkMode();
- const calendarMatch = useMatch('/calendar/*');
- const scheduleMatch = useMatch('/schedule/*');
- const registrationMatch = useMatch('/registration/*');
- const booklistMatch = useMatch('/booklist/*');
-
- const navigate = useNavigate();
+ const calendarMatch = router.pathname.startsWith('/calendar');
+ const scheduleMatch = router.pathname.startsWith('/schedule');
+ const registrationMatch = router.pathname.startsWith('/registration');
+ const booklistMatch = router.pathname.startsWith('/booklist');
const onChange = (event: React.ChangeEvent) => {
const name = event.target.value;
if (name) {
setTerm(name);
if (calendarMatch) {
- navigate({ pathname: `/calendar/${name}/${subject || ''}`, search: pid ? `?pid=${pid}` : undefined });
+ router.push(`/calendar/${name}/${subject || ''}${pid ? `?pid=${pid}` : ''}`);
} else if (scheduleMatch) {
- navigate(`/scheduler/${name}`);
+ router.push(`/schedule/${name}`);
} else if (registrationMatch) {
- navigate(`/registration/${name}`);
+ router.push(`/registration/${name}`);
} else if (booklistMatch) {
- navigate(`/booklist/${name}`);
+ router.push(`/booklist/${name}`);
} else {
- navigate(`/calendar/${name}`);
+ router.push(`/calendar/${name}`);
}
}
};
diff --git a/src/common/header/containers/HeaderContainer.tsx b/src/common/header/containers/HeaderContainer.tsx
index 172da589..be140e25 100644
--- a/src/common/header/containers/HeaderContainer.tsx
+++ b/src/common/header/containers/HeaderContainer.tsx
@@ -1,6 +1,6 @@
import { HamburgerIcon } from '@chakra-ui/icons';
import { Box, LinkBox, HStack, Spacer, Collapse, useDisclosure, VStack, IconButton, Text } from '@chakra-ui/react';
-import { Link } from 'react-router-dom';
+import Link from 'next/link';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
@@ -22,7 +22,7 @@ export function MobileHeaderContainer({ onSearchChange }: HeaderProps): JSX.Elem
data-testid="mobile-header"
>
-
+
{/*
LOGO WILL GO HERE
📅 The{' '}
-
+
Fall 2022
{' '}
and{' '}
-
+
Spring 2023
{' '}
calendars are now available. Happy scheduling!
@@ -87,8 +87,7 @@ export function HeaderContainer({ onSearchChange }: HeaderProps): JSX.Element {
) : (
-
- {/*
+ {/*
LOGO WILL GO HERE
*/}
-
+
+
CourseUp
-
-
+
+
diff --git a/src/common/layouts/Page.tsx b/src/common/layouts/Page.tsx
index edc9cce9..b9bd0193 100644
--- a/src/common/layouts/Page.tsx
+++ b/src/common/layouts/Page.tsx
@@ -1,8 +1,8 @@
import { PropsWithChildren, useEffect, useState } from 'react';
import { Flex } from '@chakra-ui/react';
+import { useRouter } from 'next/router';
import { Helmet } from 'react-helmet';
-import { useLocation, useMatch, useNavigate, useParams } from 'react-router';
import { Pagination } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
@@ -28,12 +28,11 @@ type Props = {
export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children }: PropsWithChildren) {
const [query, setQuery] = useState('');
const [savedTerm, setSavedTerm] = useSessionStorage('user:term', getCurrentTerm());
- const navigate = useNavigate();
- const location = useLocation();
- const { term, slug } = useParams();
const smallScreen = useSmallScreen();
+ const router = useRouter();
+ const { term, slug } = router.query;
- const route = location.pathname.split('/')[1];
+ const route = router.pathname.split('/')[1];
const handleSearchChange = (q: string) => {
setQuery(q);
@@ -47,16 +46,15 @@ export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children
}
}, [query, swiper]);
- const contest = useMatch('/contest');
useEffect(() => {
if (term) {
- setSavedTerm(term);
- } else if (route && !slug && !contest) {
- navigate(`/${route}/${savedTerm}`, { replace: true });
+ setSavedTerm(typeof term === 'string' ? term : term[0]);
+ } else if (route && !slug) {
+ router.push(`/${route}/${savedTerm}`, undefined, { shallow: true });
}
- }, [navigate, route, savedTerm, setSavedTerm, term, slug, contest]);
+ }, [route, savedTerm, setSavedTerm, term, slug, router]);
- return (
+ return typeof window !== 'undefined' ? (
<>
{!mobileSupport && }
@@ -104,5 +102,7 @@ export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children
>
+ ) : (
+ <>>
);
}
diff --git a/src/common/layouts/sidebar/components/Card.tsx b/src/common/layouts/sidebar/components/Card.tsx
index 0c8a9b60..c714e6df 100644
--- a/src/common/layouts/sidebar/components/Card.tsx
+++ b/src/common/layouts/sidebar/components/Card.tsx
@@ -2,7 +2,8 @@ import { PropsWithChildren, useCallback } from 'react';
import { ChevronRightIcon, AddIcon, InfoOutlineIcon, CloseIcon } from '@chakra-ui/icons';
import { Box, Text, Flex, VStack, IconButton } from '@chakra-ui/react';
-import { Link, useParams } from 'react-router-dom';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
import { useDarkMode } from 'lib/hooks/useDarkMode';
import { useSavedCourses } from 'lib/hooks/useSavedCourses';
@@ -45,23 +46,24 @@ export interface CardProps {
}
export function Card({ subject, title, code, selected, schedule, pid }: PropsWithChildren): JSX.Element {
- let { term } = useParams();
+ const router = useRouter();
+ const { term } = router.query;
const mode = useDarkMode();
const { addCourse, deleteCourse, contains } = useSavedCourses();
- const courseIsSaved = pid && contains(pid, term);
+ const courseIsSaved = pid && contains(pid, typeof term === 'string' ? term : term![0]);
const handleBookmarkClick = useCallback(() => {
if (code && pid) {
if (!courseIsSaved) {
- addCourse(term, subject, code, pid);
+ addCourse(typeof term === 'string' ? term : term![0], subject, code, pid);
} else {
deleteCourse({
subject,
code,
pid,
- term,
+ term: typeof term === 'string' ? term : term![0],
});
}
}
@@ -96,7 +98,7 @@ export function Card({ subject, title, code, selected, schedule, pid }: PropsWit
size="xs"
colorScheme="blue"
as={Link}
- to={`/calendar/${term}/${subject}?pid=${pid}`}
+ href={`/calendar/${term}/${subject}?pid=${pid}`}
/>
);
diff --git a/src/common/layouts/sidebar/components/CoursesList.tsx b/src/common/layouts/sidebar/components/CoursesList.tsx
index 3d5f23be..09eb613f 100644
--- a/src/common/layouts/sidebar/components/CoursesList.tsx
+++ b/src/common/layouts/sidebar/components/CoursesList.tsx
@@ -1,6 +1,7 @@
import { LinkBox } from '@chakra-ui/layout';
import { SlideFade } from '@chakra-ui/transition';
-import { Link, useMatch, useParams } from 'react-router-dom';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
import { Course } from 'lib/fetchers';
@@ -14,17 +15,18 @@ type CoursesListProps = {
};
export function CoursesList({ term, courses }: CoursesListProps): JSX.Element | null {
- const { subject } = useParams();
- const scheduleMatch = useMatch('/scheduler/*');
+ const router = useRouter();
+ const { subject } = router.query;
+ const scheduleMatch = router.pathname.startsWith('/scheduler');
- if (!courses || !courses[subject]) {
+ if (!courses || !courses[subject as string]) {
return null;
}
const createCard = (pid: string, code: string, subject: string, title: string) => {
if (!scheduleMatch)
return (
-
+
);
@@ -35,7 +37,7 @@ export function CoursesList({ term, courses }: CoursesListProps): JSX.Element |
return (
- {courses[subject].map(({ pid, code, subject, title }) => createCard(pid, code, subject, title))}
+ {courses[subject as string].map(({ pid, code, subject, title }) => createCard(pid, code, subject, title))}
);
}
diff --git a/src/common/layouts/sidebar/components/SearchResults.tsx b/src/common/layouts/sidebar/components/SearchResults.tsx
index 7a2525be..e4de782c 100644
--- a/src/common/layouts/sidebar/components/SearchResults.tsx
+++ b/src/common/layouts/sidebar/components/SearchResults.tsx
@@ -1,7 +1,7 @@
import { Box } from '@chakra-ui/react';
+import { useRouter } from 'next/router';
import { HitsProvided } from 'react-instantsearch-core';
import { connectHits } from 'react-instantsearch-dom';
-import { useMatch, useNavigate } from 'react-router-dom';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
@@ -17,9 +17,9 @@ type CourseRecord = {
type Props = { term: string } & HitsProvided;
const SearchResults = ({ hits, term }: Props) => {
- const scheduleMatch = useMatch('/scheduler/*');
const smallScreen = useSmallScreen();
- const navigate = useNavigate();
+ const router = useRouter();
+ const scheduleMatch = router.pathname.startsWith('/scheduler');
return (
<>
@@ -30,7 +30,7 @@ const SearchResults = ({ hits, term }: Props) => {
{
- navigate(`/calendar/${term}/${subject}?pid=${pid}`);
+ router.push(`/calendar/${term}/${subject}?pid=${pid}`);
smallScreen && window.location.reload();
}} // i do not like this, how else can we empty the search query onClick
data-pid={pid}
diff --git a/src/common/layouts/sidebar/components/SubjectsList.tsx b/src/common/layouts/sidebar/components/SubjectsList.tsx
index 46daba67..0d976123 100644
--- a/src/common/layouts/sidebar/components/SubjectsList.tsx
+++ b/src/common/layouts/sidebar/components/SubjectsList.tsx
@@ -1,6 +1,7 @@
import { LinkBox } from '@chakra-ui/layout';
import { Collapse } from '@chakra-ui/transition';
-import { Link, useLocation, useSearchParams } from 'react-router-dom';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
import { KualiSubject } from 'lib/fetchers';
@@ -19,9 +20,9 @@ type SubjectsListProps = {
};
export function SubjectsList({ term, subjects }: SubjectsListProps): JSX.Element {
- const [searchParams] = useSearchParams();
- const pid = searchParams.get('pid');
- const location = useLocation();
+ const urlSearchParams = new URLSearchParams(window.location.search);
+ const pid = urlSearchParams.get('pid');
+ const router = useRouter();
const route = location.pathname.split('/')[1];
@@ -30,7 +31,7 @@ export function SubjectsList({ term, subjects }: SubjectsListProps): JSX.Element
{subjects.map((subject, index) => (
Subjects
{smallScreen && pid && subject ? (
-
+
{subject}
@@ -167,19 +172,18 @@ export function Courses({ term }: Props): JSX.Element | null {
setFilter(s);
};
+ const isSubjectPath = location.pathname.split('/').length === 4;
+
return (
<>
{!smallScreen && }
{!loading && sortedSubjects && courses ? (
-
-
-
-
-
-
-
-
+ {isSubjectPath ? (
+
+ ) : (
+
+ )}
) : (
diff --git a/src/common/layouts/sidebar/variants/SearchResults.tsx b/src/common/layouts/sidebar/variants/SearchResults.tsx
index 1da80200..963cd0a9 100644
--- a/src/common/layouts/sidebar/variants/SearchResults.tsx
+++ b/src/common/layouts/sidebar/variants/SearchResults.tsx
@@ -1,5 +1,5 @@
import { Flex } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { getCurrentTerm } from 'lib/utils/terms';
@@ -7,7 +7,11 @@ import { CustomHits } from '../components/SearchResults';
import { TopBar } from '../components/TopBar';
export function SearchResults() {
- const { term } = useParams();
+ const router = useRouter();
+ const { term: routerTerm } = router.query;
+
+ const term = typeof routerTerm === 'string' ? routerTerm : routerTerm?.[0];
+
return (
<>
Search Results
diff --git a/src/common/notFound/NotFound.tsx b/src/common/notFound/NotFound.tsx
index 5b13d037..e2c3965d 100644
--- a/src/common/notFound/NotFound.tsx
+++ b/src/common/notFound/NotFound.tsx
@@ -2,8 +2,8 @@ import { PropsWithChildren } from 'react';
import { Container, Heading, Flex, Text } from '@chakra-ui/layout';
import { Button, Box } from '@chakra-ui/react';
+import Link from 'next/link';
import { HiOutlineCalendar } from 'react-icons/hi';
-import { Link } from 'react-router-dom';
import { useDarkMode } from 'lib/hooks/useDarkMode';
import { getReadableTerm } from 'lib/utils/terms';
@@ -31,7 +31,7 @@ export function NotFound({ children, term, timetable }: PropsWithChildren
width="auto"
leftIcon={}
as={Link}
- to={`/scheduler/${term}`}
+ href={`/scheduler/${term}`}
>
{`${getReadableTerm(term)}`} Timetable
diff --git a/src/pages/calendar/components/Section.tsx b/src/pages/calendar/components/Section.tsx
index 865b7c3b..5c8ead3f 100644
--- a/src/pages/calendar/components/Section.tsx
+++ b/src/pages/calendar/components/Section.tsx
@@ -10,7 +10,7 @@ import {
Badge,
Flex,
} from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { MeetingTimes, Seat } from 'lib/fetchers';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -135,7 +135,8 @@ export function SectionInfo({
}
}
- const { term } = useParams();
+ const router = useRouter();
+ const { term } = router.query;
const mode = useDarkMode();
return (
diff --git a/src/pages/calendar/containers/Content.tsx b/src/pages/calendar/containers/Content.tsx
index ea7081cd..94dac47e 100644
--- a/src/pages/calendar/containers/Content.tsx
+++ b/src/pages/calendar/containers/Content.tsx
@@ -16,7 +16,6 @@ import {
} from '@chakra-ui/react';
import { Helmet } from 'react-helmet';
import { MdDelete, MdAdd } from 'react-icons/md';
-import { useSearchParams } from 'react-router-dom';
import { Term, useGetCourse } from 'lib/fetchers';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -39,7 +38,7 @@ export type ContentProps = {
* Primary UI component for content
*/
export function Content({ term }: ContentProps): JSX.Element {
- const [searchParams] = useSearchParams();
+ const searchParams = new URLSearchParams(window.location.search);
const toast = useToast();
const { data, loading, error } = useGetCourse({ term, pid: searchParams.get('pid') || '' });
const smallScreen = useSmallScreen();
diff --git a/src/pages/calendar/index.tsx b/src/pages/calendar/index.tsx
index 010a769e..e017d20d 100644
--- a/src/pages/calendar/index.tsx
+++ b/src/pages/calendar/index.tsx
@@ -1,6 +1,5 @@
import { Box, Center, VStack } from '@chakra-ui/react';
-import { useParams } from 'react-router';
-import { useSearchParams } from 'react-router-dom';
+import { useRouter } from 'next/router';
import { Term } from 'lib/fetchers';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
@@ -13,9 +12,10 @@ import { Landing } from 'pages/home/containers/Landing';
import { Content } from './containers/Content';
export function Calendar(): JSX.Element {
- const { term } = useParams();
- const [searchParams] = useSearchParams();
const smallScreen = useSmallScreen();
+ const router = useRouter();
+ const { term } = router.query;
+ const searchParams = new URLSearchParams(router.asPath.split(/\?/)[1]);
const pid = searchParams.get('pid');
diff --git a/src/routes.tsx b/src/routes.tsx
index b485801b..69a86038 100644
--- a/src/routes.tsx
+++ b/src/routes.tsx
@@ -13,7 +13,7 @@ export function Routes(): JSX.Element {
return (
- } />
+ {/* } /> */}
} />
} />
} />
From 524b64d03ea02b5bf6c22bed377400b8186f21fa Mon Sep 17 00:00:00 2001
From: Eduardo Szeckir
Date: Sat, 17 Jun 2023 19:48:32 -0700
Subject: [PATCH 02/57] more changes and slow upgrades to nextjs
---
src/common/header/components/TermSelect.tsx | 4 +--
src/common/layouts/Page.tsx | 19 ++++++++----
.../layouts/sidebar/variants/Courses.tsx | 16 +++++-----
src/lib/hooks/useWindowSize.ts | 30 +++++++++++++++++++
src/pages/calendar/index.tsx | 2 +-
src/pages/home/index.tsx | 6 +++-
src/routes.tsx | 29 ------------------
7 files changed, 58 insertions(+), 48 deletions(-)
create mode 100644 src/lib/hooks/useWindowSize.ts
delete mode 100644 src/routes.tsx
diff --git a/src/common/header/components/TermSelect.tsx b/src/common/header/components/TermSelect.tsx
index 2acc1088..733904e3 100644
--- a/src/common/header/components/TermSelect.tsx
+++ b/src/common/header/components/TermSelect.tsx
@@ -11,10 +11,8 @@ const terms = ['202205', '202209', '202301'];
export function TermSelect(): JSX.Element {
const router = useRouter();
- const { subject } = router.query;
+ const { subject, pid } = router.query;
const [selectedTerm, setTerm] = useSessionStorage('user:term', getCurrentTerm());
- const searchParams = new URLSearchParams(window.location.search);
- const pid = searchParams.get('pid');
const mode = useDarkMode();
const calendarMatch = router.pathname.startsWith('/calendar');
diff --git a/src/common/layouts/Page.tsx b/src/common/layouts/Page.tsx
index b9bd0193..4547492c 100644
--- a/src/common/layouts/Page.tsx
+++ b/src/common/layouts/Page.tsx
@@ -10,6 +10,7 @@ import 'swiper/css/pagination';
import { useSessionStorage } from 'lib/hooks/storage/useSessionStorage';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
+import { useWindowSize } from 'lib/hooks/useWindowSize';
import { isMobile } from 'lib/utils/mobile';
import { getCurrentTerm } from 'lib/utils/terms';
@@ -18,14 +19,20 @@ import { Sidebar } from 'common/layouts/sidebar/containers/Sidebar';
import { SearchResults } from 'common/layouts/sidebar/variants/SearchResults';
import { Mobile } from 'common/mobile';
-type Props = {
+export type PageProps = {
title?: string;
leftSidebar?: JSX.Element;
rightSidebar?: JSX.Element;
mobileSupport?: boolean;
};
-export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children }: PropsWithChildren) {
+export default function Page({
+ title,
+ leftSidebar,
+ rightSidebar,
+ mobileSupport,
+ children,
+}: PropsWithChildren) {
const [query, setQuery] = useState('');
const [savedTerm, setSavedTerm] = useSessionStorage('user:term', getCurrentTerm());
const smallScreen = useSmallScreen();
@@ -54,10 +61,12 @@ export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children
}
}, [route, savedTerm, setSavedTerm, term, slug, router]);
- return typeof window !== 'undefined' ? (
+ const { height } = useWindowSize();
+
+ return (
<>
{!mobileSupport && }
-
+
{title}
@@ -102,7 +111,5 @@ export function Page({ title, leftSidebar, rightSidebar, mobileSupport, children
>
- ) : (
- <>>
);
}
diff --git a/src/common/layouts/sidebar/variants/Courses.tsx b/src/common/layouts/sidebar/variants/Courses.tsx
index f305f94a..b7420f0b 100644
--- a/src/common/layouts/sidebar/variants/Courses.tsx
+++ b/src/common/layouts/sidebar/variants/Courses.tsx
@@ -62,18 +62,16 @@ export function CoursesTopBar({ onFilter }: TopBarProps): JSX.Element {
const smallScreen = useSmallScreen();
const router = useRouter();
- const { term } = router.query;
+ const { term, pid } = router.query;
- const searchParams = new URLSearchParams(window.location.search);
+ //https://courseup.vikelabs.ca/calendar/202401/ACAN?pid=ByS23Pp7E
- const subject = location.pathname.split('/')[3];
- const route = location.pathname.split('/')[1];
-
- const pid = searchParams.get('pid');
+ const subject = router.asPath.split('/')[3];
+ const route = router.asPath.split('/')[1];
const { data, loading } = useGetCourse({
term: (term || getCurrentTerm()) as Term,
- pid: searchParams.get('pid') || '',
+ pid: typeof pid === 'string' ? pid : '',
});
return (
@@ -172,7 +170,9 @@ export function Courses({ term }: Props): JSX.Element | null {
setFilter(s);
};
- const isSubjectPath = location.pathname.split('/').length === 4;
+ const router = useRouter();
+
+ const isSubjectPath = router.asPath.split('/').length === 4;
return (
<>
diff --git a/src/lib/hooks/useWindowSize.ts b/src/lib/hooks/useWindowSize.ts
new file mode 100644
index 00000000..7a08c7a6
--- /dev/null
+++ b/src/lib/hooks/useWindowSize.ts
@@ -0,0 +1,30 @@
+import { useState, useEffect } from 'react';
+
+export const useWindowSize = () => {
+ const [windowSize, setWindowSize] = useState<{
+ width: number | undefined;
+ height: number | undefined;
+ }>({
+ width: undefined,
+ height: undefined,
+ });
+
+ useEffect(() => {
+ function handleResize() {
+ setWindowSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ }
+
+ window.addEventListener('resize', handleResize);
+
+ // Call handler right away so state gets updated with initial window size
+ handleResize();
+
+ // Remove event listener on cleanup
+ return () => window.removeEventListener('resize', handleResize);
+ }, []); // Empty array ensures that effect is only run on mount
+
+ return windowSize;
+};
diff --git a/src/pages/calendar/index.tsx b/src/pages/calendar/index.tsx
index e017d20d..9475e4b8 100644
--- a/src/pages/calendar/index.tsx
+++ b/src/pages/calendar/index.tsx
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
import { Term } from 'lib/fetchers';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
import { Courses, CoursesTopBar } from 'common/layouts/sidebar/variants/Courses';
import { Landing } from 'pages/home/containers/Landing';
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx
index 16e67939..422204af 100644
--- a/src/pages/home/index.tsx
+++ b/src/pages/home/index.tsx
@@ -1,6 +1,10 @@
import { Center } from '@chakra-ui/react';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
+
+// const Page = dynamic(() => import('common/layouts/Page') as Promise<{ default: React.ComponentType }>, {
+// ssr: false,
+// });
import { Landing } from './containers/Landing';
diff --git a/src/routes.tsx b/src/routes.tsx
deleted file mode 100644
index 69a86038..00000000
--- a/src/routes.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { BrowserRouter, Routes as ReactRouterRoutes, Route } from 'react-router-dom';
-
-import { Booklist } from 'pages/booklist';
-import { Calendar } from 'pages/calendar';
-import { Home } from 'pages/home';
-import { ImportTimetable } from 'pages/import';
-import { Registration } from 'pages/registration';
-import { Scheduler } from 'pages/scheduler';
-
-// TODO: use nested routes but it doesn't work right now
-
-export function Routes(): JSX.Element {
- return (
-
-
- {/* } /> */}
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
- } />
-
-
- );
-}
From 59f3382d29f7e6f169912df55ae885848a7bd1bc Mon Sep 17 00:00:00 2001
From: Eduardo Szeckir
Date: Sat, 17 Jun 2023 20:14:11 -0700
Subject: [PATCH 03/57] more change to using nextjs router
---
src/App.tsx | 95 -------------------
src/index.tsx | 7 --
src/lib/utils/jest/index.tsx | 11 +--
.../booklist/components/BooklistHeading.tsx | 5 +-
.../booklist/containers/BooklistContainer.tsx | 7 +-
.../import/components/ImportTimetable.tsx | 6 +-
.../import/components/ReplaceTimetable.tsx | 6 +-
.../import/components/TimetableCourseCard.tsx | 10 +-
src/pages/import/index.tsx | 7 +-
.../components/RegistrationHeading.tsx | 5 +-
.../containers/CourseContainer.tsx | 5 +-
.../containers/RegistrationContainer.tsx | 7 +-
src/pages/scheduler/components/CourseCard.tsx | 4 +-
.../components/share/ShareButton.tsx | 10 +-
.../containers/SchedulerContainer.tsx | 5 +-
src/pages/scheduler/index.tsx | 7 +-
16 files changed, 46 insertions(+), 151 deletions(-)
delete mode 100644 src/App.tsx
delete mode 100644 src/index.tsx
diff --git a/src/App.tsx b/src/App.tsx
deleted file mode 100644
index 1bb727f5..00000000
--- a/src/App.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import React from 'react';
-
-import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
-// import 'firebase/analytics';
-// import * as Sentry from '@sentry/react';
-// import { Integrations } from '@sentry/tracing';
-import algoliasearch from 'algoliasearch';
-// import firebase from 'firebase/app';
-import { Helmet } from 'react-helmet';
-import { InstantSearch } from 'react-instantsearch-dom';
-import { RestfulProvider } from 'restful-react';
-
-import { customTheme } from 'lib/theme';
-// import { migrateLocalStorage } from 'lib/utils/localStorageMigration';
-// import { logEvent } from 'lib/utils/logEvent';
-
-import { Feedback } from 'common/feedback';
-
-// import reportWebVitals from './reportWebVitals';
-import { Routes } from './routes';
-
-// const firebaseConfig =
-// process.env.REACT_APP_ENV === 'production'
-// ? {
-// apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
-// authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
-// projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
-// storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
-// messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
-// appId: process.env.REACT_APP_FIREBASE_APP_ID,
-// measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
-// }
-// : {
-// apiKey: 'AIzaSyBh3shP0neAHQCRrESGjQVfKpCdz2EbSEE',
-// authDomain: 'staging-clockwork.firebaseapp.com',
-// projectId: 'staging-clockwork',
-// storageBucket: 'staging-clockwork.appspot.com',
-// messagingSenderId: '53599730639',
-// appId: '1:53599730639:web:f31b0eeaf4f0529233f0ba',
-// measurementId: 'G-M645REB5LQ',
-// };
-
-// Sentry.init({
-// dsn: 'https://08218d366eab4945abe3e09054bc5cce@o551348.ingest.sentry.io/5674718',
-// integrations: [new Integrations.BrowserTracing()],
-// // Set tracesSampleRate to 1.0 to capture 100%
-// // of transactions for performance monitoring.
-// // We recommend adjusting this value in production
-// tracesSampleRate: 1.0,
-// release: process.env.REACT_APP_SENTRY_RELEASE,
-// });
-
-// // only enable Firebase if the required config values are present
-// if (process.env.NODE_ENV === 'production' || process.env.REACT_APP_ANALYTICS) {
-// firebase.initializeApp(firebaseConfig);
-// firebase.analytics();
-// }
-
-const searchClient = algoliasearch('CR92D3S394', '5477854d63b676fe021f8f83f5839a3a');
-
-const baseApiUrl = process.env.REACT_APP_API_URL;
-
-// migrateLocalStorage();
-
-export function App(): JSX.Element {
- return (
-
- {/* 'An error has occurred'>}> */}
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
- );
-}
-
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-// reportWebVitals(({ id, name, value }) => {
-// // logEvent('Web Vitals', {
-// // eventCategory: 'Web Vitals',
-// // eventAction: name,
-// // eventValue: Math.round(name === 'CLS' ? value * 1000 : value), // values must be integers
-// // eventLabel: id, // id unique to current page load
-// // nonInteraction: true, // avoids affecting bounce rate
-// // });
-// });
diff --git a/src/index.tsx b/src/index.tsx
deleted file mode 100644
index de02596a..00000000
--- a/src/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from 'react';
-
-import ReactDOM from 'react-dom';
-
-import { App } from 'App';
-
-ReactDOM.render(, document.getElementById('root'));
diff --git a/src/lib/utils/jest/index.tsx b/src/lib/utils/jest/index.tsx
index 61ccf359..b0a6c0ef 100644
--- a/src/lib/utils/jest/index.tsx
+++ b/src/lib/utils/jest/index.tsx
@@ -1,19 +1,11 @@
import { render } from '@testing-library/react';
import { InstantSearch } from 'react-instantsearch-core';
-import { BrowserRouter } from 'react-router-dom';
jest.mock('algoliasearch');
const searchClient = { search: jest.fn() };
-// borrowed from: https://testing-library.com/docs/example-react-router/
-export const renderWithRouter = (ui: JSX.Element, { route = '/' } = {}) => {
- window.history.pushState({}, 'Test page', route);
-
- return render(ui, { wrapper: BrowserRouter });
-};
-
// to be used if the component you are testing has the search field in it
export const renderWithSearch = (ui: JSX.Element) => {
return render(
@@ -30,7 +22,6 @@ export const renderWithSearchAndRouter = (ui: JSX.Element, { route = '/' } = {})
return render(
{ui}
- ,
- { wrapper: BrowserRouter }
+
);
};
diff --git a/src/pages/booklist/components/BooklistHeading.tsx b/src/pages/booklist/components/BooklistHeading.tsx
index 9c52add6..7fa19cde 100644
--- a/src/pages/booklist/components/BooklistHeading.tsx
+++ b/src/pages/booklist/components/BooklistHeading.tsx
@@ -1,10 +1,11 @@
import { Container, Divider, Flex, Heading, Text, Center, HStack } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { getReadableTerm } from 'lib/utils/terms';
export function BooklistHeading() {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as string;
const readableTerm = getReadableTerm(term);
return (
diff --git a/src/pages/booklist/containers/BooklistContainer.tsx b/src/pages/booklist/containers/BooklistContainer.tsx
index d9a3b595..f4c8639e 100644
--- a/src/pages/booklist/containers/BooklistContainer.tsx
+++ b/src/pages/booklist/containers/BooklistContainer.tsx
@@ -2,13 +2,13 @@ import { useEffect } from 'react';
import { Box } from '@chakra-ui/layout';
import { Center, Spinner, Text, VStack } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { Term } from 'lib/fetchers';
import { logEvent } from 'lib/utils/logEvent';
import { getReadableTerm } from 'lib/utils/terms';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
import { NotFound } from 'common/notFound/NotFound';
import { BooklistHeading } from '../components/BooklistHeading';
@@ -16,7 +16,8 @@ import { TextbookCard } from '../components/TextbookCard';
import { useTextbooks } from '../hooks/useTextbooks';
export function BooklistContainer(): JSX.Element | null {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as string;
const textbooks = useTextbooks(term as Term);
useEffect(() => {
diff --git a/src/pages/import/components/ImportTimetable.tsx b/src/pages/import/components/ImportTimetable.tsx
index 14c464bc..1dc1e5e2 100644
--- a/src/pages/import/components/ImportTimetable.tsx
+++ b/src/pages/import/components/ImportTimetable.tsx
@@ -16,8 +16,8 @@ import {
Alert,
AlertIcon,
} from '@chakra-ui/react';
+import { useRouter } from 'next/router';
import { BsPlusCircleFill } from 'react-icons/bs';
-import { useNavigate } from 'react-router';
import { Timetable } from 'lib/fetchers';
import { SavedCourse, useSavedCourses } from 'lib/hooks/useSavedCourses';
@@ -33,12 +33,12 @@ export function ImportTimetable({ loading, data }: { loading: boolean; data: Tim
const filteredCoursesList: SavedCourse[] = useMemo(() => [], []);
const [filteredCourses, setFilteredCourses] = useState(filteredCoursesList);
const [timetableTerm, setTimetableTerm] = useState('');
- const navigate = useNavigate();
+ const router = useRouter();
const handleImport = () => {
importCourses(data.courses, data.term);
onClose();
- navigate(`/scheduler/${timetableTerm}`);
+ router.push(`/scheduler/${timetableTerm}`);
toast({
title: 'Timetable imported!',
status: 'success',
diff --git a/src/pages/import/components/ReplaceTimetable.tsx b/src/pages/import/components/ReplaceTimetable.tsx
index 64da0917..abde9bb5 100644
--- a/src/pages/import/components/ReplaceTimetable.tsx
+++ b/src/pages/import/components/ReplaceTimetable.tsx
@@ -16,8 +16,8 @@ import {
Alert,
AlertIcon,
} from '@chakra-ui/react';
+import { useRouter } from 'next/router';
import { BsArrowRepeat } from 'react-icons/bs';
-import { useNavigate } from 'react-router';
import { Timetable } from 'lib/fetchers';
import { SavedCourse, useSavedCourses } from 'lib/hooks/useSavedCourses';
@@ -33,12 +33,12 @@ export function ReplaceTimetable({ loading, data }: { loading: boolean; data: Ti
const filteredCoursesList: SavedCourse[] = [];
const [filteredCourses, setFilteredCourses] = useState(filteredCoursesList);
const [timetableTerm, setTimetableTerm] = useState('');
- const navigate = useNavigate();
+ const router = useRouter();
const handleReplace = () => {
replaceCourses(data.courses, data.term);
onClose();
- navigate(`/scheduler/${timetableTerm}`);
+ router.push(`/scheduler/${timetableTerm}`);
toast({
title: 'Timetable replaced!',
status: 'success',
diff --git a/src/pages/import/components/TimetableCourseCard.tsx b/src/pages/import/components/TimetableCourseCard.tsx
index 89cfd8e5..7f90413e 100644
--- a/src/pages/import/components/TimetableCourseCard.tsx
+++ b/src/pages/import/components/TimetableCourseCard.tsx
@@ -2,7 +2,7 @@ import { useMemo, useState } from 'react';
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import { Box, Flex, VStack, Text, Skeleton, IconButton, Collapse, HStack } from '@chakra-ui/react';
-import { Link as RouterLink } from 'react-router-dom';
+import Link from 'next/link';
import { CourseDetails, Term, TimetableCourse, useGetCourse } from 'lib/fetchers';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -98,13 +98,7 @@ function TopRow({
-
+
{subject} {code}
diff --git a/src/pages/import/index.tsx b/src/pages/import/index.tsx
index 0b0110bb..565c2e58 100644
--- a/src/pages/import/index.tsx
+++ b/src/pages/import/index.tsx
@@ -1,13 +1,13 @@
import { useState } from 'react';
import { Spinner, VStack, Heading, HStack, Flex, Box, ButtonGroup, Button, Center } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { Timetable, useGetTimetable } from 'lib/fetchers';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
import { getReadableTerm } from 'lib/utils/terms';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
import { TopBar } from 'common/layouts/sidebar/components/TopBar';
import { Sidebar } from 'common/layouts/sidebar/containers/Sidebar';
@@ -16,7 +16,8 @@ import { TimetableActionButtons } from './components/TimetableActionButtons';
import { TimetableCourseCard } from './components/TimetableCourseCard';
export function ImportTimetable(): JSX.Element {
- const { slug } = useParams();
+ const router = useRouter();
+ const slug = router.query.slug as string;
const smallScreen = useSmallScreen();
const { loading, data } = useGetTimetable({ slug: slug });
diff --git a/src/pages/registration/components/RegistrationHeading.tsx b/src/pages/registration/components/RegistrationHeading.tsx
index 0caa2a3d..f345d47e 100644
--- a/src/pages/registration/components/RegistrationHeading.tsx
+++ b/src/pages/registration/components/RegistrationHeading.tsx
@@ -1,13 +1,14 @@
import { Container, Divider, Flex, Heading, ListItem, OrderedList, Text } from '@chakra-ui/layout';
import { Alert, AlertIcon, Button, Icon } from '@chakra-ui/react';
+import { useRouter } from 'next/router';
import { HiLink } from 'react-icons/hi';
import { IoCopyOutline } from 'react-icons/io5';
-import { useParams } from 'react-router';
import { getReadableTerm } from 'lib/utils/terms';
export function RegistrationHeading() {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as string;
return (
diff --git a/src/pages/registration/containers/CourseContainer.tsx b/src/pages/registration/containers/CourseContainer.tsx
index e9262cf1..b3333293 100644
--- a/src/pages/registration/containers/CourseContainer.tsx
+++ b/src/pages/registration/containers/CourseContainer.tsx
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { Container, Heading, VStack } from '@chakra-ui/layout';
import { Skeleton } from '@chakra-ui/skeleton';
import { Collapse } from '@chakra-ui/transition';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { useSeats, useSections, Term, Seat } from 'lib/fetchers';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -24,7 +24,8 @@ type Data = {
};
export function CourseContainer({ course }: Props) {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as Term;
const [data, setData] = useState<{ lab?: Data; lecture?: Data; tutorial?: Data }>({});
const termType = term as Term;
const mode = useDarkMode();
diff --git a/src/pages/registration/containers/RegistrationContainer.tsx b/src/pages/registration/containers/RegistrationContainer.tsx
index d6154f8c..416048db 100644
--- a/src/pages/registration/containers/RegistrationContainer.tsx
+++ b/src/pages/registration/containers/RegistrationContainer.tsx
@@ -1,10 +1,10 @@
import { Center, Spinner, Box } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { useSavedCourses } from 'lib/hooks/useSavedCourses';
import { getReadableTerm } from 'lib/utils/terms';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
import { NotFound } from 'common/notFound/NotFound';
import { RegistrationHeading } from '../components/RegistrationHeading';
@@ -12,7 +12,8 @@ import { RegistrationHeading } from '../components/RegistrationHeading';
import { CourseContainer } from './CourseContainer';
export function RegistrationContainer(): JSX.Element | null {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as string;
const { courses } = useSavedCourses();
// to avoid erroring out if term is not provided in URL
diff --git a/src/pages/scheduler/components/CourseCard.tsx b/src/pages/scheduler/components/CourseCard.tsx
index 4a194903..03290fac 100644
--- a/src/pages/scheduler/components/CourseCard.tsx
+++ b/src/pages/scheduler/components/CourseCard.tsx
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
import { ChevronDownIcon, ChevronUpIcon, CloseIcon } from '@chakra-ui/icons';
import { Box, Text, Flex, VStack, Checkbox, IconButton, BackgroundProps, Skeleton } from '@chakra-ui/react';
-import { Link } from 'react-router-dom';
+import Link from 'next/link';
import { Term, useGetCourse } from 'lib/fetchers';
import { useDarkMode } from 'lib/hooks/useDarkMode';
@@ -113,7 +113,7 @@ export function CourseCard({
textDecoration: 'underline',
}}
as={Link}
- to={`/calendar/${term}/${subject}?pid=${pid}`}
+ href={`/calendar/${term}/${subject}?pid=${pid}`}
>
{subject} {code}
diff --git a/src/pages/scheduler/components/share/ShareButton.tsx b/src/pages/scheduler/components/share/ShareButton.tsx
index 04fc82a1..042aeb8e 100644
--- a/src/pages/scheduler/components/share/ShareButton.tsx
+++ b/src/pages/scheduler/components/share/ShareButton.tsx
@@ -2,9 +2,9 @@ import { useState } from 'react';
import { Button, Icon, IconButton, useDisclosure } from '@chakra-ui/react';
import html2canvas from 'html2canvas';
+import { useRouter } from 'next/router';
import { FiCamera } from 'react-icons/fi';
import { IoShareOutline } from 'react-icons/io5';
-import { useMatch } from 'react-router';
import { CreateTimetableResponse, Term, TimetableCourse, TimetableReturn, useCreateTimetable } from 'lib/fetchers';
import { useSavedCourses } from 'lib/hooks/useSavedCourses';
@@ -15,7 +15,11 @@ import ScreenshotModal from '../ScreenshotModal';
import ShareTimetableModal from './ShareTimetableModal';
export function ShareButton({ term, disabled }: { term: Term; disabled: boolean }): JSX.Element | null {
- const importPage = useMatch('/s/:slug');
+ const router = useRouter();
+ // Matches `/s/:slug` and extracts the slug (import page)
+ const match = router.asPath.match(/\/s\/(.*)/);
+ const slug = match ? match[1] : '';
+
const smallScreen = useSmallScreen();
// opens the share timetable modal
@@ -115,7 +119,7 @@ export function ShareButton({ term, disabled }: { term: Term; disabled: boolean
});
};
- return importPage ? (
+ return slug ? (
<>>
) : (
<>
diff --git a/src/pages/scheduler/containers/SchedulerContainer.tsx b/src/pages/scheduler/containers/SchedulerContainer.tsx
index 98d6efde..d497076d 100644
--- a/src/pages/scheduler/containers/SchedulerContainer.tsx
+++ b/src/pages/scheduler/containers/SchedulerContainer.tsx
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { Box, Flex } from '@chakra-ui/react';
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { useSavedCourses } from 'lib/hooks/useSavedCourses';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
@@ -13,7 +13,8 @@ import { useGetCourseSections } from '../hooks/useCalendarEvents';
import { denormalizeCourseEvents } from '../hooks/useTransformedCalendarEvents';
export function SchedulerContainer(): JSX.Element {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as string;
// the user's saved courses
const { courses } = useSavedCourses();
// extend the list of courses with section information
diff --git a/src/pages/scheduler/index.tsx b/src/pages/scheduler/index.tsx
index 253c7659..41a22386 100644
--- a/src/pages/scheduler/index.tsx
+++ b/src/pages/scheduler/index.tsx
@@ -1,15 +1,16 @@
-import { useParams } from 'react-router';
+import { useRouter } from 'next/router';
import { Term } from 'lib/fetchers';
-import { Page } from 'common/layouts/Page';
+import Page from 'common/layouts/Page';
import { Courses } from 'common/layouts/sidebar/variants/Courses';
import { SchedulerSidebar } from './components/SchedulerSidebar';
import { SchedulerContainer } from './containers/SchedulerContainer';
export function Scheduler(): JSX.Element {
- const { term } = useParams();
+ const router = useRouter();
+ const term = router.query.term as Term;
return (
Date: Wed, 4 Oct 2023 16:35:19 -0700
Subject: [PATCH 04/57] fix seeding
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
prisma/seed.ts | 3 ++-
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ffcbf52f..9ba937b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,7 @@
"@prisma/client": "^4.3.1",
"@sentry/react": "^6.16.1",
"@sentry/tracing": "^6.16.1",
- "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.6",
+ "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.8",
"algoliasearch": "^4.11.0",
"cheerio": "^1.0.0-rc.10",
"date-fns": "^2.29.3",
@@ -5779,9 +5779,9 @@
}
},
"node_modules/@vikelabs/uvic-course-scraper": {
- "version": "1.0.0-alpha.7",
- "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.7.tgz",
- "integrity": "sha512-llaseelcpsIDw/Lf591x/38kvRANdyFRPx60CEKf3XerYcU4h85kK99bznKK3oc6PIJK0Z7mktDJ1xAOT/Yl5Q==",
+ "version": "1.0.0-alpha.8",
+ "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.8.tgz",
+ "integrity": "sha512-L0EY6UeqRs4qENcZlMETQIbzqEuw34erFbnLBHbDpcgg7HeG7ISEKd3k7gYVdjvMSJYDQSxYxZIYJRz3+NyP9Q==",
"dependencies": {
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
@@ -24149,9 +24149,9 @@
}
},
"@vikelabs/uvic-course-scraper": {
- "version": "1.0.0-alpha.7",
- "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.7.tgz",
- "integrity": "sha512-llaseelcpsIDw/Lf591x/38kvRANdyFRPx60CEKf3XerYcU4h85kK99bznKK3oc6PIJK0Z7mktDJ1xAOT/Yl5Q==",
+ "version": "1.0.0-alpha.8",
+ "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.8.tgz",
+ "integrity": "sha512-L0EY6UeqRs4qENcZlMETQIbzqEuw34erFbnLBHbDpcgg7HeG7ISEKd3k7gYVdjvMSJYDQSxYxZIYJRz3+NyP9Q==",
"requires": {
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
diff --git a/package.json b/package.json
index 4553de5f..394f5b4c 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"@prisma/client": "^4.3.1",
"@sentry/react": "^6.16.1",
"@sentry/tracing": "^6.16.1",
- "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.6",
+ "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.8",
"algoliasearch": "^4.11.0",
"cheerio": "^1.0.0-rc.10",
"date-fns": "^2.29.3",
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 834e67c6..7f9913be 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -1,10 +1,11 @@
+import makeFetchCookie from 'fetch-cookie';
+
import { getSearchResults, setTerm } from '@courseup/lib/banner';
import { Fetch } from '@courseup/lib/banner/fetch';
import { upsertCourses } from '@courseup/lib/courses';
import { range } from '@courseup/lib/fn';
import { upsertSections } from '@courseup/lib/sections';
import { Term } from '@courseup/lib/term';
-import makeFetchCookie from 'fetch-cookie';
const term = new Term().toString();
From 9a5a4ad2faeaba786fcb79284180e1882b3e192e Mon Sep 17 00:00:00 2001
From: Eduardo Szeckir
Date: Wed, 11 Oct 2023 17:16:16 -0700
Subject: [PATCH 05/57] adding more handling and new prisma versions
---
lib/courses/index.ts | 64 ++++++++-------
lib/validation/term.ts | 2 +
package-lock.json | 81 +++++++++----------
package.json | 6 +-
pages/calendar/[term]/[subject].tsx | 5 ++
prisma/schema.prisma | 6 +-
prisma/seed.ts | 1 +
src/common/header/components/TermSelect.tsx | 2 +-
.../header/containers/HeaderContainer.tsx | 37 +++++----
.../sidebar/components/CoursesList.tsx | 6 +-
.../sidebar/components/SubjectsList.tsx | 16 ++--
.../layouts/sidebar/variants/Courses.tsx | 4 +-
12 files changed, 126 insertions(+), 104 deletions(-)
create mode 100644 pages/calendar/[term]/[subject].tsx
diff --git a/lib/courses/index.ts b/lib/courses/index.ts
index a08f4b6a..e721e815 100644
--- a/lib/courses/index.ts
+++ b/lib/courses/index.ts
@@ -17,38 +17,40 @@ export async function getCourseDetailByPid(term: string, pid: string) {
export async function upsertCourses(term: string) {
const courses = await fetchCourses(term);
- await Promise.all(
- courses.map(async (course) => {
- const details = await fetchCourseDetailsByPid(term, course.pid);
- const data = {
- pid: details.pid,
- term,
- subject: course.subject,
- subjectDescription: details.subjectCode.description.replace(`(${course.subject})`, ''),
- code: course.code,
- title: details.title,
- description: details.description,
- dateStart: details.dateStart,
- credits: details.credits,
- hoursCatalog: details.hoursCatalog,
- preAndCorequisites: details.preAndCorequisites,
- preOrCorequisites: details.preOrCorequisites,
- formally: details.formerlyNotesText,
- };
- await prisma.course.upsert({
- where: {
- // eslint-disable-next-line camelcase
- term_subject_code: {
- term: term,
- subject: course.subject,
- code: course.code,
- },
+ console.log('fetched all courses', courses.length)
+ for (let i = 0; i=14.17"
+ "node": ">=16.13"
},
"peerDependencies": {
"prisma": "*"
@@ -4411,16 +4411,16 @@
}
},
"node_modules/@prisma/engines": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.3.1.tgz",
- "integrity": "sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==",
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.4.2.tgz",
+ "integrity": "sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g==",
"devOptional": true,
"hasInstallScript": true
},
"node_modules/@prisma/engines-version": {
- "version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b",
- "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b.tgz",
- "integrity": "sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw=="
+ "version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz",
+ "integrity": "sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA=="
},
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
@@ -5779,9 +5779,9 @@
}
},
"node_modules/@vikelabs/uvic-course-scraper": {
- "version": "1.0.0-alpha.8",
- "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.8.tgz",
- "integrity": "sha512-L0EY6UeqRs4qENcZlMETQIbzqEuw34erFbnLBHbDpcgg7HeG7ISEKd3k7gYVdjvMSJYDQSxYxZIYJRz3+NyP9Q==",
+ "version": "1.0.0-alpha.9",
+ "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.9.tgz",
+ "integrity": "sha512-Hsl3RpWchRcIN3ocVnebT7qHsauBWnPvjUywRZ1iHI8H3DgVi0OL/TyRK8Y7mJHbzW2e5PWBrWcfIpSlgCo/TQ==",
"dependencies": {
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
@@ -16632,20 +16632,19 @@
"dev": true
},
"node_modules/prisma": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.3.1.tgz",
- "integrity": "sha512-90xo06wtqil76Xsi3mNpc4Js3SdDRR5g4qb9h+4VWY4Y8iImJY6xc3PX+C9xxTSt1lr0Q89A0MLkJjd8ax6KiQ==",
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.4.2.tgz",
+ "integrity": "sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg==",
"devOptional": true,
"hasInstallScript": true,
"dependencies": {
- "@prisma/engines": "4.3.1"
+ "@prisma/engines": "5.4.2"
},
"bin": {
- "prisma": "build/index.js",
- "prisma2": "build/index.js"
+ "prisma": "build/index.js"
},
"engines": {
- "node": ">=14.17"
+ "node": ">=16.13"
}
},
"node_modules/promise-polyfill": {
@@ -23007,23 +23006,23 @@
"integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ=="
},
"@prisma/client": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.3.1.tgz",
- "integrity": "sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==",
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.4.2.tgz",
+ "integrity": "sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA==",
"requires": {
- "@prisma/engines-version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b"
+ "@prisma/engines-version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574"
}
},
"@prisma/engines": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.3.1.tgz",
- "integrity": "sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==",
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.4.2.tgz",
+ "integrity": "sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g==",
"devOptional": true
},
"@prisma/engines-version": {
- "version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b",
- "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b.tgz",
- "integrity": "sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw=="
+ "version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz",
+ "integrity": "sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA=="
},
"@protobufjs/aspromise": {
"version": "1.1.2",
@@ -24149,9 +24148,9 @@
}
},
"@vikelabs/uvic-course-scraper": {
- "version": "1.0.0-alpha.8",
- "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.8.tgz",
- "integrity": "sha512-L0EY6UeqRs4qENcZlMETQIbzqEuw34erFbnLBHbDpcgg7HeG7ISEKd3k7gYVdjvMSJYDQSxYxZIYJRz3+NyP9Q==",
+ "version": "1.0.0-alpha.9",
+ "resolved": "https://registry.npmjs.org/@vikelabs/uvic-course-scraper/-/uvic-course-scraper-1.0.0-alpha.9.tgz",
+ "integrity": "sha512-Hsl3RpWchRcIN3ocVnebT7qHsauBWnPvjUywRZ1iHI8H3DgVi0OL/TyRK8Y7mJHbzW2e5PWBrWcfIpSlgCo/TQ==",
"requires": {
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
@@ -32447,12 +32446,12 @@
}
},
"prisma": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.3.1.tgz",
- "integrity": "sha512-90xo06wtqil76Xsi3mNpc4Js3SdDRR5g4qb9h+4VWY4Y8iImJY6xc3PX+C9xxTSt1lr0Q89A0MLkJjd8ax6KiQ==",
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.4.2.tgz",
+ "integrity": "sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg==",
"devOptional": true,
"requires": {
- "@prisma/engines": "4.3.1"
+ "@prisma/engines": "5.4.2"
}
},
"promise-polyfill": {
diff --git a/package.json b/package.json
index 394f5b4c..e0b08e16 100644
--- a/package.json
+++ b/package.json
@@ -7,10 +7,10 @@
"@chakra-ui/react": "^1.8.6",
"@emotion/react": "^11.8.1",
"@emotion/styled": "^11.8.1",
- "@prisma/client": "^4.3.1",
+ "@prisma/client": "^5.4.2",
"@sentry/react": "^6.16.1",
"@sentry/tracing": "^6.16.1",
- "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.8",
+ "@vikelabs/uvic-course-scraper": "^1.0.0-alpha.9",
"algoliasearch": "^4.11.0",
"cheerio": "^1.0.0-rc.10",
"date-fns": "^2.29.3",
@@ -92,7 +92,7 @@
"jest-fetch-mock": "^3.0.3",
"node-fetch": "^2.6.7",
"prettier": "^2.8.4",
- "prisma": "^4.3.1",
+ "prisma": "^5.4.2",
"react-share": "^4.4.0",
"ts-node-dev": "^2.0.0",
"tsconfig-paths": "^4.1.0",
diff --git a/pages/calendar/[term]/[subject].tsx b/pages/calendar/[term]/[subject].tsx
new file mode 100644
index 00000000..72921219
--- /dev/null
+++ b/pages/calendar/[term]/[subject].tsx
@@ -0,0 +1,5 @@
+import { Calendar } from 'pages/calendar';
+
+export default function CalendarPage(): JSX.Element {
+ return ;
+}
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 5e1f3da4..282e42e5 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -6,8 +6,10 @@ generator client {
}
datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
+ provider = "postgresql"
+ url = env("POSTGRES_PRISMA_URL")
+ shadowDatabaseUrl = env("POSTGRES_URL_NON_POOLING")
+ directUrl = env("POSTGRES_URL_NON_POOLING")
}
model Course {
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 7f9913be..088d6ede 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -12,6 +12,7 @@ const term = new Term().toString();
export const main = async () => {
console.log('upserting courses for term', term);
await upsertCourses(term);
+ console.log('done upserting courses');
// establish a session for each request
const fc = makeFetchCookie(fetch) as Fetch;
diff --git a/src/common/header/components/TermSelect.tsx b/src/common/header/components/TermSelect.tsx
index 733904e3..d65271e3 100644
--- a/src/common/header/components/TermSelect.tsx
+++ b/src/common/header/components/TermSelect.tsx
@@ -7,7 +7,7 @@ import { useSessionStorage } from 'lib/hooks/storage/useSessionStorage';
import { useDarkMode } from 'lib/hooks/useDarkMode';
import { getCurrentTerm, getReadableTerm } from 'lib/utils/terms';
-const terms = ['202205', '202209', '202301'];
+const terms = ['202305', '202309', '202401'];
export function TermSelect(): JSX.Element {
const router = useRouter();
diff --git a/src/common/header/containers/HeaderContainer.tsx b/src/common/header/containers/HeaderContainer.tsx
index be140e25..4f0630b8 100644
--- a/src/common/header/containers/HeaderContainer.tsx
+++ b/src/common/header/containers/HeaderContainer.tsx
@@ -1,3 +1,5 @@
+import { useEffect, useState } from 'react';
+
import { HamburgerIcon } from '@chakra-ui/icons';
import { Box, LinkBox, HStack, Spacer, Collapse, useDisclosure, VStack, IconButton, Text } from '@chakra-ui/react';
import Link from 'next/link';
@@ -62,21 +64,26 @@ export interface HeaderProps {
*/
export function HeaderContainer({ onSearchChange }: HeaderProps): JSX.Element {
const smallScreen = useSmallScreen();
- const tips: Array = smallScreen
- ? [⚠️ Mobile is currently in beta.]
- : [
-
- 📅 The{' '}
-
- Fall 2022
- {' '}
- and{' '}
-
- Spring 2023
- {' '}
- calendars are now available. Happy scheduling!
- ,
- ];
+ const [tips, setTips] = useState>([]);
+
+ useEffect(() => {
+ setTips(smallScreen
+ ? [⚠️ Mobile is currently in beta.]
+ : [
+
+ 📅 The{' '}
+
+ Fall 2022
+ {' '}
+ and{' '}
+
+ Spring 2023
+ {' '}
+ calendars are now available. Happy scheduling!
+ ,
+ ])
+ }, [smallScreen])
+
return (
<>
diff --git a/src/common/layouts/sidebar/components/CoursesList.tsx b/src/common/layouts/sidebar/components/CoursesList.tsx
index 09eb613f..1d268286 100644
--- a/src/common/layouts/sidebar/components/CoursesList.tsx
+++ b/src/common/layouts/sidebar/components/CoursesList.tsx
@@ -26,9 +26,11 @@ export function CoursesList({ term, courses }: CoursesListProps): JSX.Element |
const createCard = (pid: string, code: string, subject: string, title: string) => {
if (!scheduleMatch)
return (
-
-
+
+
+
+
);
else if (scheduleMatch) {
return ;
diff --git a/src/common/layouts/sidebar/components/SubjectsList.tsx b/src/common/layouts/sidebar/components/SubjectsList.tsx
index 0d976123..9cda3757 100644
--- a/src/common/layouts/sidebar/components/SubjectsList.tsx
+++ b/src/common/layouts/sidebar/components/SubjectsList.tsx
@@ -20,25 +20,27 @@ type SubjectsListProps = {
};
export function SubjectsList({ term, subjects }: SubjectsListProps): JSX.Element {
- const urlSearchParams = new URLSearchParams(window.location.search);
- const pid = urlSearchParams.get('pid');
const router = useRouter();
+ const { pid } = router.query;
+ const route = router.pathname.split('/')[1];
- const route = location.pathname.split('/')[1];
+ console.log(route, term, subjects)
return (
{subjects.map((subject, index) => (
-
-
-
+
+
+
+
))}
);
diff --git a/src/common/layouts/sidebar/variants/Courses.tsx b/src/common/layouts/sidebar/variants/Courses.tsx
index b7420f0b..d6d43def 100644
--- a/src/common/layouts/sidebar/variants/Courses.tsx
+++ b/src/common/layouts/sidebar/variants/Courses.tsx
@@ -172,14 +172,14 @@ export function Courses({ term }: Props): JSX.Element | null {
const router = useRouter();
- const isSubjectPath = router.asPath.split('/').length === 4;
+ const { subject } = router.query;
return (
<>
{!smallScreen && }
{!loading && sortedSubjects && courses ? (
- {isSubjectPath ? (
+ {subject ? (
) : (
From 164f40b6d2ccdb2fe0bab4bdd6702b467d95ad8a Mon Sep 17 00:00:00 2001
From: Eduardo Szeckir
Date: Wed, 6 Dec 2023 17:29:29 -0800
Subject: [PATCH 06/57] adding more nextjs changes
---
.env | 1 +
components/explore/ExplorePage.tsx | 21 +++++
pages/_app.tsx | 27 ++++---
pages/explore.tsx | 31 +++++++
pages/explore/[subject].tsx | 23 ++++++
pages/index.tsx | 2 +-
.../header/components/MiscHeaderButtons.tsx | 6 +-
src/common/header/components/NavButtons.tsx | 61 +++++---------
src/common/header/components/SearchBar.tsx | 10 ++-
.../header/containers/HeaderContainer.tsx | 56 ++++++-------
src/common/layouts/Page.tsx | 15 ++--
.../layouts/sidebar/components/TopBar.tsx | 1 -
.../layouts/sidebar/variants/Courses.tsx | 1 -
src/index.css | 8 +-
src/pages/calendar/containers/Content.tsx | 2 +-
src/pages/home/containers/Landing.tsx | 81 ++++++++-----------
src/pages/home/index.tsx | 6 +-
17 files changed, 195 insertions(+), 157 deletions(-)
create mode 100644 components/explore/ExplorePage.tsx
create mode 100644 pages/explore.tsx
create mode 100644 pages/explore/[subject].tsx
diff --git a/.env b/.env
index d87f5713..19886d57 100644
--- a/.env
+++ b/.env
@@ -9,5 +9,6 @@ REACT_APP_BACKEND=nextjs
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://admin:admin@localhost:5432/postgres?schema=public"
+POSTGRES_PRISMA_URL="postgresql://admin:admin@localhost:5432/postgres?schema=public"
# For authentication when calling the data refresh endpoints
ACCESS_KEY="secret"
\ No newline at end of file
diff --git a/components/explore/ExplorePage.tsx b/components/explore/ExplorePage.tsx
new file mode 100644
index 00000000..3e3cb918
--- /dev/null
+++ b/components/explore/ExplorePage.tsx
@@ -0,0 +1,21 @@
+import { Box, Flex, Heading } from "@chakra-ui/react";
+
+import {SubjectsList} from "common/layouts/sidebar/components/SubjectsList";
+
+import { getSubjects } from "@courseup/lib/subjects";
+
+export default function ExplorePage({subjects}: {
+ subjects: {
+ subject: string,
+ title: string
+ }[]
+}): JSX.Element {
+
+ return
+ {subjects.map((subject) => (
+
+ {subject.title}
+
+ ))}
+
+}
\ No newline at end of file
diff --git a/pages/_app.tsx b/pages/_app.tsx
index ae9c2a69..d92cccf9 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,27 +1,34 @@
-import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
+// React Big Calendar
+import 'react-big-calendar/lib/sass/styles.scss';
+import '../src/index.css';
+
+import { ChakraProvider, ColorModeScript, Flex } from '@chakra-ui/react';
import algoliasearch from 'algoliasearch';
import type { AppProps /*, AppContext */ } from 'next/app';
-// React Big Calendar
import { Helmet } from 'react-helmet';
-import 'react-big-calendar/lib/sass/styles.scss';
import { InstantSearch } from 'react-instantsearch-core';
-import '../src/index.css';
import { RestfulProvider } from 'restful-react';
import { customTheme } from 'lib/theme';
+
+import { Header } from 'common/header';
+
const searchClient = algoliasearch('CR92D3S394', '5477854d63b676fe021f8f83f5839a3a');
function App({ Component, pageProps }: AppProps): JSX.Element {
return (
-
-
-
+
+
+
- ;
+
+
+
+
-
-
+
+
);
}
export default App;
diff --git a/pages/explore.tsx b/pages/explore.tsx
new file mode 100644
index 00000000..ca98911e
--- /dev/null
+++ b/pages/explore.tsx
@@ -0,0 +1,31 @@
+import { Box, VStack } from "@chakra-ui/react";
+import type { GetStaticProps } from "next";
+
+import { Search } from "common/header/components/SearchBar";
+
+import { getSubjects } from "@courseup/lib/subjects";
+
+
+import ExplorePage from "../components/explore/ExplorePage";
+
+
+export const getStaticProps = async () => {
+ const subjects = await getSubjects('202309');
+ return {
+ props: {
+ subjects
+ }
+ }
+};
+
+export default function ExplorePageContainer({subjects}: {
+ subjects: {
+ subject: string,
+ title: string
+ }[]
+}): JSX.Element {
+ return
+
+
+
+}
\ No newline at end of file
diff --git a/pages/explore/[subject].tsx b/pages/explore/[subject].tsx
new file mode 100644
index 00000000..08562c0f
--- /dev/null
+++ b/pages/explore/[subject].tsx
@@ -0,0 +1,23 @@
+import { Box, VStack } from "@chakra-ui/react";
+import type { GetStaticProps } from "next";
+
+import { Search } from "common/header/components/SearchBar";
+
+import { getSubjects } from "@courseup/lib/subjects";
+import { getCourseBySubjectCode } from "@courseup/lib/courses";
+
+export const getStaticProps = async () => {
+ const courses = getCourseBySubjectCode('202309', 'CSC');
+};
+
+export default function ExplorePageContainer({subjects}: {
+ subjects: {
+ subject: string,
+ title: string
+ }[]
+}): JSX.Element {
+ return
+
+
+
+}
\ No newline at end of file
diff --git a/pages/index.tsx b/pages/index.tsx
index 6ebce3e2..38f79013 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,5 +1,5 @@
import { Home } from 'pages/home';
export default function HomePage(): JSX.Element {
- return ;
+ return
}
diff --git a/src/common/header/components/MiscHeaderButtons.tsx b/src/common/header/components/MiscHeaderButtons.tsx
index f8e4bda4..b81d2800 100644
--- a/src/common/header/components/MiscHeaderButtons.tsx
+++ b/src/common/header/components/MiscHeaderButtons.tsx
@@ -15,9 +15,9 @@ export function MiscHeaderButtons(): JSX.Element {
as="a"
href="https://github.com/VikeLabs/courseup"
target="_blank"
- size="md"
+ size="sm"
colorScheme="none"
- fontSize="2.87em"
+ fontSize="2em"
isRound
aria-label="Open GitHub Repo"
color={mode('gray.400', 'gray.300')}
@@ -30,7 +30,7 @@ export function MiscHeaderButtons(): JSX.Element {
aria-label="toggle dark mode"
isRound
icon={mode(, )}
- size="md"
+ size="sm"
onClick={toggleColorMode}
colorScheme={mode('purple', 'orange')}
/>
diff --git a/src/common/header/components/NavButtons.tsx b/src/common/header/components/NavButtons.tsx
index 587bf30f..dca9fcf7 100644
--- a/src/common/header/components/NavButtons.tsx
+++ b/src/common/header/components/NavButtons.tsx
@@ -1,21 +1,19 @@
+'use client';
import { Button, ButtonGroup, VStack, Divider } from '@chakra-ui/react';
import { useRouter } from 'next/router';
+import { MdConfirmationNumber, MdLibraryBooks, MdOutlineCalendarViewMonth, MdOutlineConfirmationNumber, MdOutlineLibraryBooks, MdOutlineTravelExplore } from 'react-icons/md';
import { useSmallScreen } from 'lib/hooks/useSmallScreen';
import { getCurrentTerm } from 'lib/utils/terms';
export function NavButtons(): JSX.Element {
- const smallScreen = useSmallScreen();
const router = useRouter();
const { term } = router.query;
- // const { term } = useParams();
-
- // const navigate = useNavigate();
const onClick = (event: React.MouseEvent) => {
const name = event.currentTarget.getAttribute('name');
- if (name === 'calendar') {
- router.push(`/calendar/${term || getCurrentTerm()}`);
+ if (name === 'explore') {
+ router.push(`/explore`);
} else if (name === 'scheduler') {
router.push(`/scheduler/${term || getCurrentTerm()}`);
} else if (name === 'register') {
@@ -27,43 +25,20 @@ export function NavButtons(): JSX.Element {
return (
<>
- {smallScreen ? (
-
-
-
-
-
-
-
-
-
-
-
-
- ) : (
-
-
-
-
-
-
- )}
+
+ }>
+ Explore courses
+
+ }>
+ Timetables
+
+ }>
+ Register
+
+ }>
+ Booklist
+
+
>
);
}
diff --git a/src/common/header/components/SearchBar.tsx b/src/common/header/components/SearchBar.tsx
index fa2d8c0d..c33601b6 100644
--- a/src/common/header/components/SearchBar.tsx
+++ b/src/common/header/components/SearchBar.tsx
@@ -1,3 +1,4 @@
+'use client';
import React, { ChangeEvent } from 'react';
import { FormControl, FormLabel, Input, InputGroup } from '@chakra-ui/react';
@@ -15,7 +16,6 @@ type SearchBoxProps = {
};
function SearchBox({ currentRefinement, isSearchStalled, refine, onChange, onSubmit }: SearchBoxProps) {
- const smallScreen = useSmallScreen();
const handleChange = (e: ChangeEvent) => {
refine(e.currentTarget.value);
onChange && onChange(e.currentTarget.value);
@@ -27,15 +27,17 @@ function SearchBox({ currentRefinement, isSearchStalled, refine, onChange, onSub
};
return (
-