displaying bar graph, fetching distributions message
This commit is contained in:
27
package-lock.json
generated
27
package-lock.json
generated
@@ -11,6 +11,8 @@
|
||||
"chrome-extension-toolkit": "^0.0.23",
|
||||
"classnames": "^2.3.2",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"highcharts": "^10.3.3",
|
||||
"highcharts-react-official": "^3.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.57.1",
|
||||
@@ -8213,6 +8215,20 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/highcharts": {
|
||||
"version": "10.3.3",
|
||||
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-10.3.3.tgz",
|
||||
"integrity": "sha512-r7wgUPQI9tr3jFDn3XT36qsNwEIZYcfgz4mkKEA6E4nn5p86y+u1EZjazIG4TRkl5/gmGRtkBUiZW81g029RIw=="
|
||||
},
|
||||
"node_modules/highcharts-react-official": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highcharts-react-official/-/highcharts-react-official-3.2.0.tgz",
|
||||
"integrity": "sha512-71IJZsLmEboYFjONpwC3NRsg6JKvtKYtS5Si3e6s6MLRSOFNOY8KILTkzvO36kjpeR/A0X3/kvvewE+GMPpkjw==",
|
||||
"peerDependencies": {
|
||||
"highcharts": ">=6.0.0",
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hook-std": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
|
||||
@@ -23388,6 +23404,17 @@
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"highcharts": {
|
||||
"version": "10.3.3",
|
||||
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-10.3.3.tgz",
|
||||
"integrity": "sha512-r7wgUPQI9tr3jFDn3XT36qsNwEIZYcfgz4mkKEA6E4nn5p86y+u1EZjazIG4TRkl5/gmGRtkBUiZW81g029RIw=="
|
||||
},
|
||||
"highcharts-react-official": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highcharts-react-official/-/highcharts-react-official-3.2.0.tgz",
|
||||
"integrity": "sha512-71IJZsLmEboYFjONpwC3NRsg6JKvtKYtS5Si3e6s6MLRSOFNOY8KILTkzvO36kjpeR/A0X3/kvvewE+GMPpkjw==",
|
||||
"requires": {}
|
||||
},
|
||||
"hook-std": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
"chrome-extension-toolkit": "^0.0.23",
|
||||
"classnames": "^2.3.2",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"highcharts": "^10.3.3",
|
||||
"highcharts-react-official": "^3.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.57.1",
|
||||
|
||||
@@ -9,6 +9,7 @@ import { SessionStore } from './storage/SessionStore';
|
||||
import browserActionHandler from './handler/browserActionHandler';
|
||||
import hotReloadingHandler from './handler/hotReloadingHandler';
|
||||
import tabManagementHandler from './handler/tabManagementHandler';
|
||||
import courseDataHandler from './handler/courseDataHandler';
|
||||
|
||||
onServiceWorkerAlive();
|
||||
|
||||
@@ -34,6 +35,7 @@ const messageListener = new MessageListener<BACKGROUND_MESSAGES>({
|
||||
...browserActionHandler,
|
||||
...hotReloadingHandler,
|
||||
...tabManagementHandler,
|
||||
...courseDataHandler,
|
||||
});
|
||||
|
||||
messageListener.listen();
|
||||
|
||||
14
src/background/handler/courseDataHandler.ts
Normal file
14
src/background/handler/courseDataHandler.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { MessageHandler } from 'chrome-extension-toolkit';
|
||||
import CourseDataMessages from 'src/shared/messages/CourseDataMessages';
|
||||
|
||||
const courseDataHandler: MessageHandler<CourseDataMessages> = {
|
||||
getDistribution({ data, sendResponse }) {
|
||||
const { course } = data;
|
||||
|
||||
const dummyData = Array.from({ length: 18 }, () => Math.floor(Math.random() * 100));
|
||||
|
||||
sendResponse(dummyData);
|
||||
},
|
||||
};
|
||||
|
||||
export default courseDataHandler;
|
||||
9
src/shared/messages/CourseDataMessages.ts
Normal file
9
src/shared/messages/CourseDataMessages.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Course } from '../types/Course';
|
||||
|
||||
export default interface CourseDataMessages {
|
||||
/**
|
||||
* Gets the distribution of grades for the given course
|
||||
* @returns an array of the number of students in each grade range from A+ to F, with the index of the array corresponding to the grade range
|
||||
*/
|
||||
getDistribution: (data: { course: Course }) => number[] | undefined;
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
/**
|
||||
* This is a type with all the message definitions that can be sent TO specific tabs
|
||||
*/
|
||||
export default interface TAB_MESSAGES {
|
||||
reAnalyzePage: (data: { url: string }) => void;
|
||||
}
|
||||
export default interface TAB_MESSAGES {}
|
||||
|
||||
@@ -3,18 +3,21 @@ import TAB_MESSAGES from './TabMessages';
|
||||
import BrowserActionMessages from './BrowserActionMessages';
|
||||
import HotReloadingMessages from './HotReloadingMessages';
|
||||
import TabManagementMessages from './TabManagementMessages';
|
||||
import CourseDataMessages from './CourseDataMessages';
|
||||
|
||||
/**
|
||||
* This is a type with all the message definitions that can be sent TO the background script
|
||||
*/
|
||||
export type BACKGROUND_MESSAGES = BrowserActionMessages & TabManagementMessages & HotReloadingMessages;
|
||||
export type BACKGROUND_MESSAGES = BrowserActionMessages &
|
||||
TabManagementMessages &
|
||||
HotReloadingMessages &
|
||||
CourseDataMessages;
|
||||
|
||||
/**
|
||||
* A utility object that can be used to send type-safe messages to the background script
|
||||
*/
|
||||
export const bMessenger = createMessenger<BACKGROUND_MESSAGES>('background');
|
||||
|
||||
|
||||
/**
|
||||
* A utility object that can be used to send type-safe messages to specific tabs
|
||||
*/
|
||||
|
||||
@@ -33,7 +33,6 @@ export type Semester = {
|
||||
/**
|
||||
* The internal representation of a course for the extension
|
||||
*/
|
||||
|
||||
export class Course {
|
||||
/** Every course has a uniqueId within UT's registrar system corresponding to each course section */
|
||||
uniqueId: number;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Course } from 'src/shared/types/Course';
|
||||
import Card from '../../common/Card/Card';
|
||||
import Popup from '../../common/Popup/Popup';
|
||||
import CourseDescription from './CourseDescription/CourseDescription';
|
||||
import CourseHeader from './CourseHeader/CourseHeader';
|
||||
import styles from './CoursePopup.module.scss';
|
||||
import GradeDistribution from './GradeDistribution/GradeDistribution';
|
||||
|
||||
interface Props {
|
||||
course: Course;
|
||||
@@ -19,6 +21,7 @@ export default function CoursePopup({ course, onClose }: Props) {
|
||||
<Popup className={styles.popup} overlay onClose={onClose}>
|
||||
<CourseHeader course={course} onClose={onClose} />
|
||||
<CourseDescription course={course} />
|
||||
<GradeDistribution course={course} />
|
||||
</Popup>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
.container {
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
margin: 20px;
|
||||
padding: 12px;
|
||||
|
||||
> div {
|
||||
overflow: hidden;
|
||||
min-width: auto;
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import HighchartsReact from 'highcharts-react-official';
|
||||
import Highcharts from 'highcharts';
|
||||
import Card from 'src/views/components/common/Card/Card';
|
||||
import { bMessenger } from 'src/shared/messages';
|
||||
import { Course } from 'src/shared/types/Course';
|
||||
import styles from './GradeDistribution.module.scss';
|
||||
import colors from 'src/views/styles/colors.module.scss';
|
||||
|
||||
enum DataStatus {
|
||||
LOADING = 'LOADING',
|
||||
DONE = 'DONE',
|
||||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
course: Course;
|
||||
}
|
||||
|
||||
export default function GradeDistribution({ course }: Props) {
|
||||
const [chartOptions, setChartOptions] = useState<Highcharts.Options>({
|
||||
title: {
|
||||
text: undefined,
|
||||
},
|
||||
subtitle: {
|
||||
text: undefined,
|
||||
},
|
||||
legend: {
|
||||
enabled: false,
|
||||
},
|
||||
xAxis: {
|
||||
title: {
|
||||
text: 'Grades',
|
||||
},
|
||||
categories: ['A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'F'],
|
||||
crosshair: true,
|
||||
},
|
||||
yAxis: {
|
||||
min: 0,
|
||||
title: {
|
||||
text: 'Students',
|
||||
},
|
||||
},
|
||||
chart: {
|
||||
style: {
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: '600',
|
||||
},
|
||||
},
|
||||
credits: {
|
||||
enabled: false,
|
||||
},
|
||||
tooltip: {
|
||||
headerFormat: '<span style="font-size:small; font-weight:bold">{point.key}</span><table>',
|
||||
pointFormat:
|
||||
'<td style="color:{black};padding:0;font-size:small; font-weight:bold;"><b>{point.y:.0f} Students</b></td>',
|
||||
footerFormat: '</table>',
|
||||
shared: true,
|
||||
useHTML: true,
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
pointPadding: 0.2,
|
||||
borderWidth: 0,
|
||||
},
|
||||
series: {
|
||||
animation: {
|
||||
duration: 700,
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'column',
|
||||
name: 'Grades',
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
const [status, setStatus] = useState<DataStatus>(DataStatus.LOADING);
|
||||
|
||||
useEffect(() => {
|
||||
bMessenger.getDistribution({ course }).then(distribution => {
|
||||
if (!distribution) {
|
||||
return setStatus(DataStatus.ERROR);
|
||||
}
|
||||
|
||||
setChartOptions(options => ({
|
||||
...options,
|
||||
series: [
|
||||
{
|
||||
type: 'column',
|
||||
name: 'Grades',
|
||||
data: distribution.map((y, i) => ({
|
||||
y,
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
// color: i < 8 ? '#2ECC71' : i < 10 ? '#F1C40F' : '#E74C3C',
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
color: i < 8 ? colors.cactus : i < 10 ? colors.sunshine : colors.speedway_brick,
|
||||
})),
|
||||
},
|
||||
],
|
||||
}));
|
||||
});
|
||||
}, [course]);
|
||||
|
||||
if (!chartOptions.series?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<HighchartsReact highcharts={Highcharts} options={chartOptions} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user