Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b281d08
Add color palettes (#385)
emilyliublair Nov 4, 2025
1b1cc22
Added courseImport hook (#388)
raptor1820 Nov 4, 2025
d131d0c
fix getRandomColor to use palette
afazio1 Nov 4, 2025
1b4f51a
Daniel/superior seat display mechanism (#359)
DanielChee Sep 27, 2025
ddb63e6
Fix seating info style inconsistencies (#361)
afazio1 Sep 27, 2025
eeb3516
Implemented location picker component (#363)
raptor1820 Oct 26, 2025
1fa0527
Added Min Travel Time Option (#375)
idke64 Oct 26, 2025
eac3f87
combine all map functions and consts to folder
uma-anand Oct 26, 2025
79ba08c
Close Mobile Side Panel on Click (#369)
DanielChee Oct 26, 2025
9ccac7a
calendar size and CLOSE/OPEN refactor (#370)
DanielChee Oct 28, 2025
5373b8b
Add Plan to Take metric (#376)
lyangji1011 Nov 2, 2025
affd913
Added discard button to recurring event drafts (#373)
raptor1820 Nov 4, 2025
32cd3c3
Add color palettes (#385)
emilyliublair Nov 4, 2025
e59825f
Added courseImport hook (#388)
raptor1820 Nov 4, 2025
9760f91
fix getRandomColor to use palette
afazio1 Nov 4, 2025
e501258
disable discard button when input is empty + clear location
afazio1 Nov 4, 2025
c6e2190
Merge branch 'bog-f25-sprint3' into bog-f25-sprint4
afazio1 Nov 4, 2025
1a565f9
fix location marker on map
afazio1 Nov 4, 2025
965861a
Change 'Delivery Mode' to 'Class Format' (#394)
spencer-banko Nov 4, 2025
a6c320d
fix margin on map days
afazio1 Nov 4, 2025
4f8d75a
Sidebar locations (#405)
DanielChee Nov 11, 2025
4dd5a1c
Fix out of order days (#410)
afazio1 Nov 13, 2025
3628500
Overflowing Location Bug (#406)
DanielChee Nov 17, 2025
0701098
Oliver/issue 365 travel times backend (#374)
oliverxt Nov 17, 2025
8b54413
Import courses by link (#412)
afazio1 Nov 17, 2025
ba581b8
feat: show section-specific titles for 8803 (#384)
oliverxt Nov 18, 2025
c8c0f81
reset course and ratings flows
uma-anand Dec 27, 2025
5816811
Enable Course View Mode (#419)
uma-anand Dec 29, 2025
b87f6b9
Course Details Landing (#420)
uma-anand Dec 30, 2025
cec5bd6
Short Course Info Details (#421)
uma-anand Dec 31, 2025
c847b5c
Detailed section information (#425)
uma-anand Jan 27, 2026
6482c8a
Add light mode designs (#429)
emilyliublair Jan 31, 2026
7542781
Populate course and prof metrics (#431)
emilyliublair Feb 8, 2026
d718600
Add Course Info Modal (#433)
emilyliublair Feb 9, 2026
b13aafc
fix lint errors
uma-anand Feb 18, 2026
bd0a4fe
fix circular dependencies
uma-anand Feb 18, 2026
1f7f413
Merge branch 'main' into course-page-do-over
uma-anand Feb 18, 2026
dc27fb6
Add Major Restrictions (#443)
emilyliublair Apr 1, 2026
fe773b1
Fix UI Issue in ProfessorInfoCard (#445)
emilyliublair Apr 2, 2026
d3679ab
Merge branch 'main' into course-page-do-over
uma-anand Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
/tests/fixtures/**
/tests/performance/**
/tmp/**
/src/vendor/**
/src/vendor/**
src/utils/mapbox/scripts/
11 changes: 10 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,16 @@
// Disable false positives for render props
"react/no-unstable-nested-components": ["error", { "allowAsProps": true }],
// Allow code like `<>{children}</>` to convert React.ReactNode => React.ReactElement
"react/jsx-no-useless-fragment": ["error", { "allowExpressions": true }]
"react/jsx-no-useless-fragment": ["error", { "allowExpressions": true }],
// Use ts version of no shadow
"no-shadow": "off",
"@typescript-eslint/no-shadow": [
"error",
{
"ignoreTypeValueShadow": true,
"ignoreFunctionTypeParameterNameValueShadow": true
}
]
},
"overrides": [
{
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ yarn-error.log*
/.idea
/.vscode
.env

archive/
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@
"react-transition-group": "^4.4.2",
"react-virtualized": "^9.21.2",
"s-ago": "^2.2.0",
"swr": "^2.3.6",
"tslib": "2.3.0",
"use-local-storage-state": "^18.1.2",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@bitwarden/cli": "^2022.8.0",
Expand Down
9 changes: 9 additions & 0 deletions public/empty_course_details.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/ActionRow/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
padding: 4px;

.action-row-header {
padding: 4px;
padding: 5px;
display: flex;
align-items: center;

Expand Down
39 changes: 24 additions & 15 deletions src/components/App/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ import SponsorBanner from '../SponsorBanner';
import {
AppNavigationContext,
AppMobileNav,
NAV_TABS,
AppMobileNavDisplay,
SchedulerPageType,
} from './navigation';
import { classes } from '../../utils/misc';
import { AccountContextValue } from '../../contexts/account';
import { Term } from '../../types';
import CourseDetails from '../CourseDetails';
import SectionDetails from '../SectionDetails';

export const WEB_NAV_TABS = ['Scheduler', 'Map', 'Finals'];

/**
* Renders the actual content at the root of the app
Expand All @@ -26,18 +30,18 @@ import { Term } from '../../types';
* This component is memoized, so it only re-renders when its context changes.
*/
function AppContentBase(): React.ReactElement {
const { currentTabIndex, setTabIndex, openDrawer } =
const { currentTab, setTab, openDrawer, currentSchedulerPage } =
useContext(AppNavigationContext);
const captureRef = useRef<HTMLDivElement>(null);

return (
<>
<AppMobileNav captureRef={captureRef} />
<Header
currentTab={currentTabIndex}
onChangeTab={setTabIndex}
currentTab={currentTab}
onChangeTab={setTab}
onToggleMenu={openDrawer}
tabs={NAV_TABS}
tabs={WEB_NAV_TABS}
captureRef={captureRef}
/>
<SponsorBanner />
Expand All @@ -54,17 +58,22 @@ function AppContentBase(): React.ReactElement {
>
<div>
There was en error somewhere somewhere in the{' '}
{NAV_TABS[currentTabIndex] ?? '?'} tab and it can&apos;t
continue.
{currentTab ?? '?'} tab and it can&apos;t continue.
</div>
<div>Try refreshing the page to see if it fixes the issue.</div>
</ErrorDisplay>
</SkeletonContent>
)}
>
{currentTabIndex === 0 && <Scheduler />}
{currentTabIndex === 1 && <Map />}
{currentTabIndex === 2 && <Finals />}
{currentTab === 'Scheduler' && <Scheduler />}
{currentTab === 'Course details' &&
(currentSchedulerPage.type === SchedulerPageType.SECTION_DETAILS ? (
<SectionDetails courseId={currentSchedulerPage.courseId} />
) : (
<CourseDetails />
))}
{currentTab === 'Map' && <Map />}
{currentTab === 'Finals' && <Finals />}
{/* Fake calendar used to capture screenshots */}
<div className="capture-container" ref={captureRef}>
<Calendar className="fake-calendar" capture overlayCrns={[]} />
Expand Down Expand Up @@ -104,24 +113,24 @@ export function AppSkeleton({
accountState,
termsState,
}: AppSkeletonProps): React.ReactElement {
const { currentTabIndex, setTabIndex, openDrawer } =
useContext(AppNavigationContext);
const { currentTab, setTab, openDrawer } = useContext(AppNavigationContext);

return (
<>
<AppMobileNavDisplay />
<HeaderDisplay
currentTab={currentTabIndex}
onChangeTab={setTabIndex}
currentTab={currentTab}
onChangeTab={setTab}
onToggleMenu={openDrawer}
tabs={NAV_TABS}
tabs={WEB_NAV_TABS}
accountState={accountState ?? { type: 'loading' }}
termsState={
termsState == null
? { type: 'loading' }
: { type: 'loaded', ...termsState }
}
versionsState={{ type: 'loading' }}
paletteState={{ type: 'loading' }}
skeleton
/>
{children}
Expand Down
64 changes: 50 additions & 14 deletions src/components/App/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,35 @@ import useScreenWidth from '../../hooks/useScreenWidth';
import { ErrorWithFields } from '../../log';
import HeaderActionBar from '../HeaderActionBar';

export const NAV_TABS = ['Scheduler', 'Map', 'Finals'];
export const MOBILE_NAV_TABS = ['Scheduler', 'Course details', 'Map', 'Finals'];

export enum SchedulerPageType {
CALENDAR = 'calendar',
COURSE_DETAILS = 'course-details',
SECTION_DETAILS = 'section-details',
}

export type SchedulerPageState =
| { type: SchedulerPageType.CALENDAR }
| { type: SchedulerPageType.COURSE_DETAILS }
| { type: SchedulerPageType.SECTION_DETAILS; courseId: string };

export type AppNavigationContextValue = {
currentTabIndex: number;
setTabIndex: (next: number) => void;
currentTab: string;
setTab: (next: string) => void;
isDrawerOpen: boolean;
openDrawer: () => void;
closeDrawer: () => void;
currentSchedulerPage: SchedulerPageState;
setCurrentSchedulerPage: (page: SchedulerPageState) => void;
};

export const AppNavigationContext =
React.createContext<AppNavigationContextValue>({
currentTabIndex: 0,
setTabIndex: (): void => {
currentTab: 'Scheduler',
setTab: (): void => {
throw new ErrorWithFields({
message: 'empty AppNavigationContext.setTabIndex value being used',
message: 'empty AppNavigationContext.setTab value being used',
});
},
isDrawerOpen: false,
Expand All @@ -43,6 +56,13 @@ export const AppNavigationContext =
message: 'empty AppNavigationContext.closeDrawer value being used',
});
},
currentSchedulerPage: { type: SchedulerPageType.CALENDAR },
setCurrentSchedulerPage: (): void => {
throw new ErrorWithFields({
message:
'empty AppNavigationContext.setCurrentSchedulerPage value being used',
});
},
});

export type AppNavigationProps = {
Expand All @@ -59,7 +79,10 @@ export function AppNavigation({
const mobile = !useScreenWidth(DESKTOP_BREAKPOINT);

// Allow top-level tab-based navigation
const [currentTabIndex, setTabIndex] = useState(0);
const [currentTab, setTab] = useState<string>('Scheduler');

const [currentSchedulerPage, setCurrentSchedulerPage] =
useState<SchedulerPageState>({ type: SchedulerPageType.CALENDAR });

// Handle the status of the drawer being open on mobile
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
Expand All @@ -75,13 +98,23 @@ export function AppNavigation({
// Memoize the context value
const contextValue = useMemo<AppNavigationContextValue>(
() => ({
currentTabIndex,
setTabIndex,
currentTab,
setTab,
isDrawerOpen,
openDrawer,
closeDrawer,
currentSchedulerPage,
setCurrentSchedulerPage,
}),
[currentTabIndex, setTabIndex, isDrawerOpen, openDrawer, closeDrawer]
[
currentTab,
setTab,
isDrawerOpen,
openDrawer,
closeDrawer,
currentSchedulerPage,
setCurrentSchedulerPage,
]
);

return (
Expand Down Expand Up @@ -135,7 +168,7 @@ export function AppMobileNavDisplay({
}: AppMobileNavDisplayProps): React.ReactElement | null {
const mobile = !useScreenWidth(DESKTOP_BREAKPOINT);
const largeMobile = useScreenWidth(LARGE_MOBILE_BREAKPOINT);
const { currentTabIndex, setTabIndex, isDrawerOpen, closeDrawer } =
const { currentTab, setTab, isDrawerOpen, closeDrawer } =
useContext(AppNavigationContext);

if (!mobile) return null;
Expand All @@ -156,9 +189,12 @@ export function AppMobileNavDisplay({
)}

<NavMenu
items={NAV_TABS}
currentItem={currentTabIndex}
onChangeItem={setTabIndex}
items={MOBILE_NAV_TABS}
currentItem={currentTab}
onChangeItem={(next): void => {
setTab(next);
closeDrawer();
}}
/>
</NavDrawer>
);
Expand Down
16 changes: 8 additions & 8 deletions src/components/App/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
display: flex;
align-items: stretch;

.calendar-container {
.scheduler-container {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
overflow-y: auto;

gap: 20px;
.calendar {
min-height: $calendar-height;
}
Expand Down Expand Up @@ -127,11 +127,11 @@ body.light .App {
line-height: 28px;

span {
color: #C56E5B;
color: #c56e5b;
}

a {
color: #C56E5B;
color: #c56e5b;
}
}
}
Expand All @@ -144,7 +144,7 @@ body.light .App {
.footer {
position: absolute;
bottom: 32px;

img {
width: 200px;
}
Expand Down Expand Up @@ -186,10 +186,10 @@ body.light .App {

.footer {
bottom: 18px;

img {
width: 150px;
}
}
}
}
}
46 changes: 46 additions & 0 deletions src/components/Breadcrumb/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronRight } from '@fortawesome/free-solid-svg-icons';

import './stylesheet.scss';

export type BreadcrumbItem = {
label: string;
onClick?: () => void;
};

export type BreadcrumbProps = {
items: BreadcrumbItem[];
};

export default function Breadcrumb({
items,
}: BreadcrumbProps): React.ReactElement {
return (
<nav className="breadcrumb-container">
<ul className="breadcrumb-list">
{items.map((item, index) => (
<li key={index} className="breadcrumb-item">
{item.onClick ? (
<button
onClick={item.onClick}
className="breadcrumb-clickable"
type="button"
>
{item.label}
</button>
) : (
<span className="breadcrumb-unclickable">{item.label}</span>
)}
{index < items.length - 1 && (
<FontAwesomeIcon
icon={faChevronRight}
className="breadcrumb-separator"
/>
)}
</li>
))}
</ul>
</nav>
);
}
Loading
Loading