finished grade distribution ui
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user