finished grade distribution ui

This commit is contained in:
Sriram Hariharan
2023-03-08 20:44:34 -06:00
parent 2562e65d66
commit c1910bacb0
5 changed files with 74 additions and 25 deletions

View File

@@ -7,7 +7,7 @@ import styles from './Text.module.scss';
export type TextProps = { export type TextProps = {
color?: Color; color?: Color;
weight?: Weight; weight?: Weight;
size: Size; size?: Size;
span?: boolean; span?: boolean;
className?: string; className?: string;
onClick?: () => void; onClick?: () => void;
@@ -31,11 +31,10 @@ export default function Text(props: PropsWithChildren<TextProps>) {
const className = classNames( const className = classNames(
styles.text, styles.text,
props.className,
styles[weightClass], styles[weightClass],
styles[fontSizeClass], styles[fontSizeClass],
styles[lineHightClass] styles[lineHightClass],
props.className
); );
if (props.span) { if (props.span) {

View File

@@ -3,7 +3,7 @@
position: relative; position: relative;
max-width: 50%; max-width: 50%;
overflow-y: auto; overflow-y: auto;
max-height: 80%; max-height: 90%;
// fade in animation // fade in animation
animation: fadeIn 0.2s ease-out; animation: fadeIn 0.2s ease-out;

View File

@@ -16,7 +16,6 @@ interface Props {
* The popup that appears when the user clicks on a course for more details. * The popup that appears when the user clicks on a course for more details.
*/ */
export default function CoursePopup({ course, onClose }: Props) { export default function CoursePopup({ course, onClose }: Props) {
console.log(course);
return ( return (
<Popup className={styles.popup} overlay onClose={onClose}> <Popup className={styles.popup} overlay onClose={onClose}>
<CourseHeader course={course} onClose={onClose} /> <CourseHeader course={course} onClose={onClose} />

View File

@@ -1,14 +1,31 @@
.container { @import 'src/views/styles/base.module.scss';
max-width: 100%;
.chartContainer {
height: 250px; height: 250px;
margin: 20px; margin: 20px;
padding: 12px; padding: 12px;
> div { :global(.highcharts-background) {
overflow: hidden; fill: transparent;
min-width: auto; }
max-width: 100%; }
height: 250px;
margin: 0 auto; .textContainer {
height: 250px;
margin: 20px;
padding: 12px;
display: flex;
align-items: center;
justify-content: center;
.text {
padding: 12px;
box-shadow: none;
text-align: center;
// add some vertical padding to each element
> * {
margin: 0.2em 0;
}
} }
} }

View File

@@ -1,16 +1,20 @@
/* eslint-disable no-nested-ternary */ /* eslint-disable no-nested-ternary */
import React, { useEffect, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import HighchartsReact from 'highcharts-react-official'; import HighchartsReact from 'highcharts-react-official';
import Highcharts from 'highcharts'; import Highcharts from 'highcharts';
import Card from 'src/views/components/common/Card/Card'; import Card from 'src/views/components/common/Card/Card';
import { bMessenger } from 'src/shared/messages'; import { bMessenger } from 'src/shared/messages';
import { Course } from 'src/shared/types/Course'; import { Course } from 'src/shared/types/Course';
import styles from './GradeDistribution.module.scss';
import colors from 'src/views/styles/colors.module.scss'; import colors from 'src/views/styles/colors.module.scss';
import Spinner from 'src/views/components/common/Spinner/Spinner';
import Text from 'src/views/components/common/Text/Text';
import Icon from 'src/views/components/common/Icon/Icon';
import styles from './GradeDistribution.module.scss';
enum DataStatus { enum DataStatus {
LOADING = 'LOADING', LOADING = 'LOADING',
DONE = 'DONE', FOUND = 'FOUND',
NOT_FOUND = 'NOT_FOUND',
ERROR = 'ERROR', ERROR = 'ERROR',
} }
@@ -18,7 +22,12 @@ interface Props {
course: Course; course: Course;
} }
/**
* A chart to fetch and display the grade distribution for a course
* @returns
*/
export default function GradeDistribution({ course }: Props) { export default function GradeDistribution({ course }: Props) {
const ref = useRef<HighchartsReact.RefObject>(null);
const [chartOptions, setChartOptions] = useState<Highcharts.Options>({ const [chartOptions, setChartOptions] = useState<Highcharts.Options>({
title: { title: {
text: undefined, text: undefined,
@@ -47,6 +56,8 @@ export default function GradeDistribution({ course }: Props) {
fontFamily: 'Inter', fontFamily: 'Inter',
fontWeight: '600', fontWeight: '600',
}, },
spacingBottom: 25,
height: 250,
}, },
credits: { credits: {
enabled: false, enabled: false,
@@ -85,7 +96,9 @@ export default function GradeDistribution({ course }: Props) {
if (!distribution) { if (!distribution) {
return setStatus(DataStatus.ERROR); return setStatus(DataStatus.ERROR);
} }
if (!distribution.length) {
return setStatus(DataStatus.NOT_FOUND);
}
setChartOptions(options => ({ setChartOptions(options => ({
...options, ...options,
series: [ series: [
@@ -94,9 +107,6 @@ export default function GradeDistribution({ course }: Props) {
name: 'Grades', name: 'Grades',
data: distribution.map((y, i) => ({ data: distribution.map((y, i) => ({
y, y,
// eslint-disable-next-line no-nested-ternary
// color: i < 8 ? '#2ECC71' : i < 10 ? '#F1C40F' : '#E74C3C',
// eslint-disable-next-line no-nested-ternary
color: color:
i < 3 i < 3
? colors.turtle_pond ? colors.turtle_pond
@@ -111,16 +121,40 @@ export default function GradeDistribution({ course }: Props) {
}, },
], ],
})); }));
setStatus(DataStatus.FOUND);
// the highcharts library kinda sucks and doesn't resize the chart when the window resizes,
// so we have to manually trigger a resize event when the chart is rendered 🙃
window.dispatchEvent(new Event('resize'));
}); });
}, [course]); }, [course]);
if (!chartOptions.series?.length) { if (status === DataStatus.FOUND) {
return null; return (
<Card className={styles.chartContainer}>
<HighchartsReact ref={ref} highcharts={Highcharts} options={chartOptions} />
</Card>
);
} }
return ( return (
<Card className={styles.container}> <Card className={styles.textContainer}>
<HighchartsReact highcharts={Highcharts} options={chartOptions} /> {status === DataStatus.LOADING && <Spinner />}
{status === DataStatus.ERROR && (
<Card className={styles.text}>
<Text color='speedway_brick' size='medium' weight='semi_bold'>
There was an error fetching the grade distribution data
</Text>
<Icon color='speedway_brick' size='large' name='sentiment_dissatisfied' />
</Card>
)}
{status === DataStatus.NOT_FOUND && (
<Card className={styles.text}>
<Text color='charcoal' size='medium' weight='semi_bold'>
No grade distribution data was found for this course
</Text>
<Icon color='charcoal' size='x_large' name='search_off' />
</Card>
)}
</Card> </Card>
); );
} }