Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 12 additions & 13 deletions src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
import { DESKTOP_BREAKPOINT } from '../../constants';
import useScreenWidth from '../../hooks/useScreenWidth';
import InformationModal from '../InformationModal';
// TODO: Remove Before merging #380
import CourseInfoSandbox from '../Sandbox/CourseInfo';

import 'react-virtualized/styles.css';
import './stylesheet.scss';

Check warning on line 21 in src/components/App/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups

Check warning on line 21 in src/components/App/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups
import CourseDetailsSandbox from '../Sandbox/CourseDetails';

Check warning on line 22 in src/components/App/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../Sandbox/CourseDetails` import should occur before import of `react-virtualized/styles.css`

Check warning on line 22 in src/components/App/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../Sandbox/CourseDetails` import should occur before import of `react-virtualized/styles.css`

export default function App(): React.ReactElement {
// Grab the current theme (light/dark) from local storage.
Expand Down Expand Up @@ -59,23 +58,23 @@
</AppSkeleton>
)}
>
{/* TODO: Remove this conditional Before merging #380 */}
{window.location.pathname.startsWith('/sandbox') ? (
// Sandbox-only route
<CourseInfoSandbox />
) : (
<AppNavigation>
{/* AppDataLoader is in charge of ensuring that there are valid values
<AppNavigation>
{/* AppDataLoader is in charge of ensuring that there are valid values
for the Terms and Term contexts before rendering its children.
If any data is still loading,
then it displays an "app skeleton" with a spinner.
If there was an error while loading
then it displays an error screen. */}
<AppDataLoader>
<AppDataLoader>
{window.location.pathname.startsWith('/sandbox') ? (
// Sandbox-only route
// TODO: remove before merge
<CourseDetailsSandbox />
) : (
<AppContent />
</AppDataLoader>
</AppNavigation>
)}
)}
</AppDataLoader>
</AppNavigation>
<Feedback />

{/* Display a popup when first visiting the site */}
Expand Down
30 changes: 29 additions & 1 deletion src/components/App/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,23 @@ import { AccountContextValue } from '../../contexts/account';
import useScreenWidth from '../../hooks/useScreenWidth';
import { ErrorWithFields } from '../../log';
import HeaderActionBar from '../HeaderActionBar';
import { Course } from '../../data/beans';

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

export type SchedulerPageState =
| { type: 'calendar' }
| { type: 'course-details' }
| { type: 'section-details'; course: Course };

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

export const AppNavigationContext =
Expand All @@ -43,6 +51,13 @@ export const AppNavigationContext =
message: 'empty AppNavigationContext.closeDrawer value being used',
});
},
currentSchedulerPage: { type: 'calendar' },
setCurrentSchedulerPage: (): void => {
throw new ErrorWithFields({
message:
'empty AppNavigationContext.setCurrentSchedulerPage value being used',
});
},
});

export type AppNavigationProps = {
Expand All @@ -61,6 +76,9 @@ export function AppNavigation({
// Allow top-level tab-based navigation
const [currentTabIndex, setTabIndex] = useState(0);

const [currentSchedulerPage, setCurrentSchedulerPage] =
useState<SchedulerPageState>({ type: 'calendar' });

// Handle the status of the drawer being open on mobile
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const openDrawer = useCallback(() => setIsDrawerOpen(true), []);
Expand All @@ -80,8 +98,18 @@ export function AppNavigation({
isDrawerOpen,
openDrawer,
closeDrawer,
currentSchedulerPage,
setCurrentSchedulerPage,
}),
[currentTabIndex, setTabIndex, isDrawerOpen, openDrawer, closeDrawer]
[
currentTabIndex,
setTabIndex,
isDrawerOpen,
openDrawer,
closeDrawer,
currentSchedulerPage,
setCurrentSchedulerPage,
]
);

return (
Expand Down
33 changes: 26 additions & 7 deletions src/components/App/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,32 @@
display: flex;
align-items: stretch;

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

.view-mode-section {
display: flex;
align-items: center;
font-size: 1em;
gap: 16px;
margin-left: 16px;
margin-top: 16px;

.view-mode-tab-bar {
@include dark(background, $view-mode-tab-bar-background-dark);
@include light(background, $view-mode-tab-bar-background-light);
padding: 0.25em;

.tab {
width: 128px;
}
}
}

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

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

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

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

.footer {
bottom: 18px;

img {
width: 150px;
}
}
}
}
}
8 changes: 4 additions & 4 deletions src/components/Breadcrumb/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './stylesheet.scss';

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

export type BreadcrumbProps = {
Expand All @@ -23,10 +23,10 @@ export default function Breadcrumb({
<ul className="list">
{items.map((item, index) => (
<li key={index} className="item">
{item.link ? (
<a href={item.link} className="link">
{item.onClick ? (
<button onClick={item.onClick} className="button" type="button">
{item.label}
</a>
</button>
) : (
<span className="label">{item.label}</span>
)}
Expand Down
6 changes: 5 additions & 1 deletion src/components/Breadcrumb/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
display: flex;
align-items: center;

.link {
.button {
color: $course-page-link-color;
text-decoration: none;
font-weight: 500;
cursor: pointer;
background: none;
border: none;
padding: 0;
}

.label {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Calendar/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
}

.Calendar {
@include calendar-margin(24px, 16px);
@include calendar-margin(12px, 16px);
flex: 1;
position: relative;
height: $calendar-height;
Expand Down
24 changes: 24 additions & 0 deletions src/components/Course/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
faPalette,
faPlus,
faTrash,
faCircleInfo,
} from '@fortawesome/free-solid-svg-icons';

import { classes, getContentClassName } from '../../utils/misc';
Expand All @@ -16,7 +17,8 @@
import { CourseGpa, CrawlerPrerequisites } from '../../types';
import { ErrorWithFields, softError } from '../../log';

import './stylesheet.scss';

Check warning on line 20 in src/components/Course/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups

Check warning on line 20 in src/components/Course/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups
import CourseInfoModal from '../CourseInfoModal';

Check warning on line 21 in src/components/Course/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../CourseInfoModal` import should occur before import of `./stylesheet.scss`

Check warning on line 21 in src/components/Course/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../CourseInfoModal` import should occur before import of `./stylesheet.scss`

export type CourseProps = {
className?: string;
Expand All @@ -32,6 +34,7 @@
const [expanded, setExpanded] = useState<boolean>(false);
const [prereqOpen, setPrereqOpen] = useState<boolean>(false);
const [paletteShown, setPaletteShown] = useState<boolean>(false);
const [courseModalOpen, setCourseModalOpen] = useState<boolean>(false);
const [gpaMap, setGpaMap] = useState<CourseGpa | null>(null);
const isSearching = Boolean(onAddCourse);
const [
Expand Down Expand Up @@ -156,6 +159,14 @@
0
);

const handleOpenCourseModal = (): void => {
setCourseModalOpen(true);
};

const handleCloseCourseModal = (): void => {
setCourseModalOpen(false);
};

return (
<div
className={classes('Course', contentClassName, 'default', className)}
Expand All @@ -176,6 +187,12 @@
onClick: (): void => prereqControl(false, !expanded),
},
prereqAction,
{
icon: faCircleInfo,
onClick: handleOpenCourseModal,
tooltip: 'View Section Details',
id: `${course.id}-details`,
},
{
icon: faPalette,
onClick: (): void => {
Expand Down Expand Up @@ -271,6 +288,13 @@
{expanded && prereqOpen && prereqs !== null && (
<Prerequisite course={course} prereqs={prereqs} />
)}
{courseModalOpen && (
<CourseInfoModal
courseId={course.id}
show={courseModalOpen}
onHide={handleCloseCourseModal}
/>
)}
</div>
);
}
29 changes: 29 additions & 0 deletions src/components/CourseDetailsContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useContext } from 'react';

import { ScheduleContext } from '../../contexts';

import 'react-virtualized/styles.css';
import './stylesheet.scss';

Check warning on line 6 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups

Check warning on line 6 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups
import CourseInfoCard from '../CourseInfoCard';

Check warning on line 7 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../CourseInfoCard` import should occur before import of `react-virtualized/styles.css`

Check warning on line 7 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

`../CourseInfoCard` import should occur before import of `react-virtualized/styles.css`

export default function CourseDetailsContainer(): React.ReactElement {
const [{ oscar, desiredCourses }] = useContext(ScheduleContext);

Check warning on line 10 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

'oscar' is assigned a value but never used

Check warning on line 10 in src/components/CourseDetailsContainer/index.tsx

View workflow job for this annotation

GitHub Actions / Lint

'oscar' is assigned a value but never used

if (desiredCourses.length === 0) {
return (
<div className="empty-container">
{/* TODO: insert image here */}
<span className="empty-title">Course Details</span>
<span className="empty-description">Add courses to view details</span>
</div>
);
}

return (
<div className="cards-container">
{desiredCourses.map((course) => {
return <CourseInfoCard courseId={course} />;
})}
</div>
);
}
26 changes: 26 additions & 0 deletions src/components/CourseDetailsContainer/stylesheet.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import '../../variables';

.empty-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: $color-neutral;
flex: 1;

.empty-title {
font-size: 1.125em;
font-weight: bold;
text-align: center;
}

.empty-description {
width: 170px;
font-size: 0.875em;
text-align: center;
}
}

.cards-container {
margin: 20px 16px 16px 16px;
}
19 changes: 9 additions & 10 deletions src/components/DaySelection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,17 @@ export default function DaySelection({
{course.type === ScheduleBlockEventType.CustomEvent
? course.title
: course.id}
{course.type === ScheduleBlockEventType.Course
? ` - ${course.title}`
: ''}
</div>
{course.type === ScheduleBlockEventType.Course && (
<span className="course-row">{course.title}</span>
)}
{course.type === ScheduleBlockEventType.CustomEvent &&
course.where && (
<span className="course-row">
{/* avoid showing full address
{course.where && (
<span className="course-row">
{/* avoid showing full address
is there a better way to format this? */}
{course.where.split(',')[0]}
</span>
)}
{course.where.split(',')[0]}
</span>
)}
<span className="course-row">
{course.daysOfWeek} {timeLabel}
</span>
Expand Down
1 change: 1 addition & 0 deletions src/components/Map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default function Map(): React.ReactElement {
section: section.id,
type: ScheduleBlockEventType.Course,
coords: firstMeeting.location,
where: firstMeeting.where ?? null,
});
courseDateMap[day] = scheduleBlocks;
});
Expand Down
Loading
Loading