From 73e687e475e4cb8850f0d3ec6a639ecb6eafab90 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 23 Feb 2024 14:15:03 +1100 Subject: [PATCH 1/6] Add Unilectives widget to course attributes bar --- backend/server/server.py | 10 +- .../CourseAttributes/CourseAttributes.tsx | 101 +++++++++++++++++- .../CourseAttributes/styles.ts | 15 ++- 3 files changed, 119 insertions(+), 7 deletions(-) diff --git a/backend/server/server.py b/backend/server/server.py index 62f6965f6..7981c9c91 100644 --- a/backend/server/server.py +++ b/backend/server/server.py @@ -25,10 +25,9 @@ "http://frontend:8000", "http://frontend:3000", "http://frontend:3001", - "https://circles.csesoc.unsw.edu.au", "https://circles.devsoc.app", - "https://cselectives.staging.csesoc.unsw.edu.au", - "https://cselectives.csesoc.unsw.edu.au", + "https://unilectives.devsoc.app", + "https://unilectives.staging.devsoc.app", ] app.add_middleware( @@ -52,10 +51,11 @@ @app.get("/") async def index() -> str: - """ sanity test that this file is loaded """ + """sanity test that this file is loaded""" return "At index inside server.py" + @app.get("/live_year") def live_year() -> int: - """ sanity check for the live year """ + """sanity check for the live year""" return LIVE_YEAR diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx index f30a9a70e..0c05071cd 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; -import { Typography } from 'antd'; +import { Progress, Rate, Typography } from 'antd'; import { Course } from 'types/api'; import { EnrolmentCapacityData } from 'types/courseCapacity'; import ProgressBar from 'components/ProgressBar'; @@ -15,10 +15,52 @@ type CourseAttributesProps = { courseCapacity?: EnrolmentCapacityData; }; +interface UnilectivesCourse { + courseCode: string; + archived: boolean; + // attributes: any[]; + calendar: string; + campus: string; + description: string; + enrolmentRules: string; + equivalents: string[]; + exclusions: string[]; + faculty: string; + fieldOfEducation: string; + genEd: boolean; + level: number; + school: string; + studyLevel: string; + terms: number[]; + title: string; + uoc: number; + overallRating: number; + manageability: number; + usefulness: number; + enjoyability: number; + reviewCount: number; +} + +const getCourseRating = async (code: string) => { + const res = await fetch(`https://unilectives.devsoc.app/api/v1/course/${code}`); + if (res.status !== 200) return undefined; + return ((await res.json()) as { course: UnilectivesCourse }).course; +}; + const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => { const { pathname } = useLocation(); const sidebar = pathname === '/course-selector'; + const [rating, setRating] = React.useState(undefined); + + React.useEffect(() => { + const fetchRating = async () => { + const r = await getCourseRating(course.code); + if (r) setRating(r); + }; + fetchRating(); + }, [course.code]); + const { study_level: studyLevel, terms, campus, code, school, UOC } = course; const termTags = terms?.length @@ -109,6 +151,63 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => { title: 'Units of Credit', content: UOC + }, + { + title: 'Unilectives Rating', + content: rating ? ( + <> + +
+ + `${rating.enjoyability ? rating.enjoyability.toFixed(1) : '?'} / 5` + } + width={65} + /> +

Enjoyability

+
+
+ `${rating.usefulness ? rating.usefulness.toFixed(1) : '?'} / 5`} + width={65} + /> +

Usefulness

+
+
+ + `${rating.manageability ? rating.manageability.toFixed(1) : '?'} / 5` + } + width={65} + /> +

Manageability

+
+
+
+ +

Overall Rating

+
+ + View full reviews on Unilectives + + + ) : ( +

N/A

+ ) } ] : []; diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts index 22b322779..1811e60eb 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts @@ -36,11 +36,24 @@ const Link = styled.a` } `; +const RatingWrapper = styled.div` + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +`; + +const RatingDial = styled.div` + text-align: center; +`; + export default { AttributeWrapper, AttributeText, TermWrapper, AttributesWrapperConcise, AttributeConcise, - Link + Link, + RatingWrapper, + RatingDial }; From d1bca8c6703a88d428aaad09fc04a2c5d457f2cf Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 23 Feb 2024 15:27:04 +1100 Subject: [PATCH 2/6] Update style for Unilectives widget --- .../CourseAttributes/CourseAttributes.tsx | 8 ++++---- .../CourseDescriptionPanel/CourseAttributes/styles.ts | 7 +------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx index 0c05071cd..d049d45a4 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx @@ -157,7 +157,7 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => content: rating ? ( <> -
+
/>

Enjoyability

-
+
/>

Usefulness

-
+
defaultValue={rating.overallRating ? rating.overallRating : 0} allowHalf /> -

Overall Rating

+

Overall

Date: Thu, 4 Apr 2024 13:22:14 +1100 Subject: [PATCH 3/6] Move Unilectives API to React Query and Axios --- frontend/package-lock.json | 190 +++++++++--------- .../CourseAttributes/CourseAttributes.tsx | 45 +---- frontend/src/types/unilectives.ts | 25 +++ frontend/src/utils/api/unilectivesApi.ts | 14 ++ 4 files changed, 138 insertions(+), 136 deletions(-) create mode 100644 frontend/src/types/unilectives.ts create mode 100644 frontend/src/utils/api/unilectivesApi.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 21976c00e..489e03419 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -214,9 +214,9 @@ } }, "node_modules/@antv/component": { - "version": "1.0.1-beta.0", - "resolved": "https://registry.npmjs.org/@antv/component/-/component-1.0.1-beta.0.tgz", - "integrity": "sha512-syonGLy7bcpe+4qqKjtwBZMUUfZU8TKJRQAeYOB4pEiz2kr1Ky/qZLteT12QDQRugeMz9KnrUXMF+nAvUErKww==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-1.0.3.tgz", + "integrity": "sha512-eIs4JoBUfvHZvC8Cb9pA1vX2OWICl48mFXhnvLfUvl3AXloh0KNzBfAblznGaavUuhxbAdrs8kpjtwa940p2WA==", "dependencies": { "@antv/g": "^5.18.6", "@antv/scale": "^0.4.3", @@ -258,14 +258,14 @@ "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==" }, "node_modules/@antv/g": { - "version": "5.18.24", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-5.18.24.tgz", - "integrity": "sha512-qUIjxNPd60VpA6bjDALkRWEWA0CKm2G+vRPkP729eiZ0JnqlRuSqVNibo6QbrlZGEZQfqKiNjiVDODbJjHxNIw==", + "version": "5.18.27", + "resolved": "https://registry.npmjs.org/@antv/g/-/g-5.18.27.tgz", + "integrity": "sha512-SgJ3l7kNfJp0df7g8UItuNk5K7ctzik4z4ZmrXvz9f4cD/s7zfpvRWcIIyBaJQtJCaXtKVqP4wapeqhL7c95zQ==", "dependencies": { - "@antv/g-camera-api": "1.2.22", - "@antv/g-dom-mutation-observer-api": "1.2.21", - "@antv/g-lite": "1.2.21", - "@antv/g-web-animations-api": "1.2.22" + "@antv/g-camera-api": "1.2.25", + "@antv/g-dom-mutation-observer-api": "1.2.24", + "@antv/g-lite": "1.2.24", + "@antv/g-web-animations-api": "1.2.25" } }, "node_modules/@antv/g-base": { @@ -316,20 +316,20 @@ } }, "node_modules/@antv/g-camera-api": { - "version": "1.2.22", - "resolved": "https://registry.npmjs.org/@antv/g-camera-api/-/g-camera-api-1.2.22.tgz", - "integrity": "sha512-+sWDUMTeOACfb6HUJbuMS3ab79xCtFgCHhD+drlNbOjRCJDlkFHPsplyM7vA1a2Rs0zoyV+K68duClsP7Ei3OA==", + "version": "1.2.25", + "resolved": "https://registry.npmjs.org/@antv/g-camera-api/-/g-camera-api-1.2.25.tgz", + "integrity": "sha512-h0ckza5y9YpMgj58VdMhKry0iEBTHVQtapM0XraLQr/XSr3GiP9WTSusjWaVLqN7WxtA94O1dd/AKOOqjDIrPA==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/util": "^3.3.4", "gl-matrix": "^3.4.3", "tslib": "^2.5.3" } }, "node_modules/@antv/g-camera-api/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -337,17 +337,17 @@ } }, "node_modules/@antv/g-canvas": { - "version": "1.11.26", - "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-1.11.26.tgz", - "integrity": "sha512-7THxFINBbh5MHaapzuUs1mcgXLh4imGZP6xovg8W1riroWGg9q/Mkyt9oXVxK9TtrBNTYQkGR6yVQw7pz3dm6g==", - "dependencies": { - "@antv/g-lite": "1.2.21", - "@antv/g-plugin-canvas-path-generator": "1.3.21", - "@antv/g-plugin-canvas-picker": "1.10.23", - "@antv/g-plugin-canvas-renderer": "1.9.23", - "@antv/g-plugin-dom-interaction": "1.9.21", - "@antv/g-plugin-html-renderer": "1.9.24", - "@antv/g-plugin-image-loader": "1.3.21", + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-1.11.29.tgz", + "integrity": "sha512-CEAAqMgGlqOY2pCXpD+peOfhcpdSCKt9HQpmxPN2crsoDHk7wD1yiYVSpc0+iX1S8SNCa9TrnjZX+oQyMkFY0A==", + "dependencies": { + "@antv/g-lite": "1.2.24", + "@antv/g-plugin-canvas-path-generator": "1.3.24", + "@antv/g-plugin-canvas-picker": "1.10.26", + "@antv/g-plugin-canvas-renderer": "1.9.26", + "@antv/g-plugin-dom-interaction": "1.9.24", + "@antv/g-plugin-html-renderer": "1.9.27", + "@antv/g-plugin-image-loader": "1.3.24", "@antv/util": "^3.3.4", "tslib": "^2.5.3" } @@ -363,17 +363,17 @@ } }, "node_modules/@antv/g-dom-mutation-observer-api": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/@antv/g-dom-mutation-observer-api/-/g-dom-mutation-observer-api-1.2.21.tgz", - "integrity": "sha512-/gE0hYFAKyrh0bDad4HH6pI9s9VRG3h9RWA5pU4MzFo/9nTQtjp+DvWr9TR/oahg0u9gtyrBO5HE4eI5kziMRA==", + "version": "1.2.24", + "resolved": "https://registry.npmjs.org/@antv/g-dom-mutation-observer-api/-/g-dom-mutation-observer-api-1.2.24.tgz", + "integrity": "sha512-TRfg6sI5ThdtxNBH/YXuNaO3bgV9tTbO4fcFZ3ZOWyEwH/PFFC2SIkxH/dk13sAj4ZC1ZIAmVktHnYbTvEeXsg==", "dependencies": { - "@antv/g-lite": "1.2.21" + "@antv/g-lite": "1.2.24" } }, "node_modules/@antv/g-lite": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/@antv/g-lite/-/g-lite-1.2.21.tgz", - "integrity": "sha512-VGo78eaJE93cRPLaWZcXyi0TjfymHrAbweAVI01t3A3wgduqn1CpTXKBICqaNgi/T73rL0zcVO0Nn9th3Lincg==", + "version": "1.2.24", + "resolved": "https://registry.npmjs.org/@antv/g-lite/-/g-lite-1.2.24.tgz", + "integrity": "sha512-7FfySdANOtn2zKq41gbRj30KJ0TpnWDfyvAENVQ6Hbfqmst3/LP14rKwBmFTavjl3POdruf/dh4w6JX2gR/rUA==", "dependencies": { "@antv/g-math": "2.0.2", "@antv/util": "^3.3.4", @@ -385,9 +385,9 @@ } }, "node_modules/@antv/g-lite/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -420,20 +420,20 @@ } }, "node_modules/@antv/g-plugin-canvas-path-generator": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-path-generator/-/g-plugin-canvas-path-generator-1.3.21.tgz", - "integrity": "sha512-pz+2mCHIFGQ9w3ED4awGCrpUQbxdxkGtw1VqjAu178+uimDQJYaTXkpT2rdqsobVcm4LwQCNlugczAJfoJp9fQ==", + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-path-generator/-/g-plugin-canvas-path-generator-1.3.24.tgz", + "integrity": "sha512-+85VyXQCdR/8uo3TEk95GyxT2tiyEmnPHtPETVTCVgzuSeN/NQzLgByse65VQSejJG7a5SXygOaTHOBLmqbWCA==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/g-math": "2.0.2", "@antv/util": "^3.3.4", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-canvas-path-generator/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -441,23 +441,23 @@ } }, "node_modules/@antv/g-plugin-canvas-picker": { - "version": "1.10.23", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-picker/-/g-plugin-canvas-picker-1.10.23.tgz", - "integrity": "sha512-rdgSrLQMXIzPAnHf+vJ0unSKGkq1gC90iQVisyWKbH761sfNfVa6I+4lFWrpcBnwU09E3AfGroD1vfiHcpvQ1A==", + "version": "1.10.26", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-picker/-/g-plugin-canvas-picker-1.10.26.tgz", + "integrity": "sha512-xP71wHNuGknzI20B6Tk2qCsNsEb/DtpQTtIkBqsRiG+hT+IVBFp5yQ1KE+4dkZQ4/6UqQlKDLb1eIVm7I8fyWg==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/g-math": "2.0.2", - "@antv/g-plugin-canvas-path-generator": "1.3.21", - "@antv/g-plugin-canvas-renderer": "1.9.23", + "@antv/g-plugin-canvas-path-generator": "1.3.24", + "@antv/g-plugin-canvas-renderer": "1.9.26", "@antv/util": "^3.3.4", "gl-matrix": "^3.4.3", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-canvas-picker/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -465,23 +465,23 @@ } }, "node_modules/@antv/g-plugin-canvas-renderer": { - "version": "1.9.23", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-renderer/-/g-plugin-canvas-renderer-1.9.23.tgz", - "integrity": "sha512-uT2IsUJnwQ0m6n3S86eJYYDMMqF3yUMYcfj6sBchwym2NB3tAC/x0BVFGHZtEyqUkfmBr2wKcYjjBOfPl1tbhw==", + "version": "1.9.26", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-canvas-renderer/-/g-plugin-canvas-renderer-1.9.26.tgz", + "integrity": "sha512-0rz1+7746MhQSJ/NJ7bbuxURv0A5/OvbM1SPXFh6w5geFJoU89uPK2dVG4IFz6x4kgcCkcjFdhXg7Oti3LOjNg==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/g-math": "2.0.2", - "@antv/g-plugin-canvas-path-generator": "1.3.21", - "@antv/g-plugin-image-loader": "1.3.21", + "@antv/g-plugin-canvas-path-generator": "1.3.24", + "@antv/g-plugin-image-loader": "1.3.24", "@antv/util": "^3.3.4", "gl-matrix": "^3.4.3", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-canvas-renderer/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -489,20 +489,20 @@ } }, "node_modules/@antv/g-plugin-dom-interaction": { - "version": "1.9.21", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-dom-interaction/-/g-plugin-dom-interaction-1.9.21.tgz", - "integrity": "sha512-aO4yWve2yquZQYqZDU03pM2vgkOjFKk24zTRk+V4cAmdgjtUjCa7EcMWODI8eX2UB6zT31aySzyhOjXHQVC78A==", + "version": "1.9.24", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-dom-interaction/-/g-plugin-dom-interaction-1.9.24.tgz", + "integrity": "sha512-pBftZLmLCHvelUHCxZqYl1q2LGgVdwSI58Eek/XWjaZ4NV10TiJAJVBW83Iu4rKIlzMNLjF1QpY16WM01JbHJw==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-dragndrop": { - "version": "1.8.21", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-1.8.21.tgz", - "integrity": "sha512-iyhZJsToY3vmVqwuiZIpeWOqGcpK/9Nk13rPR2Qjk+U/9DncNF2b5fEXh3GHMFmQYysiCdPfMbFAwMuRUvoRKQ==", + "version": "1.8.24", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-1.8.24.tgz", + "integrity": "sha512-muk2juDPnafWS6xYDVjQRnI+bOlG4k4jWOb8Fk6hKjDRxmXXiP1fz4lo8kn5QvsCKra9Gu08JlU7UNONFFBspQ==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/util": "^3.3.4", "tslib": "^2.5.3" } @@ -518,20 +518,20 @@ } }, "node_modules/@antv/g-plugin-html-renderer": { - "version": "1.9.24", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-html-renderer/-/g-plugin-html-renderer-1.9.24.tgz", - "integrity": "sha512-8tM2LaHXpgoyT27tryu/lVDX+YEvKv+KaPCtMTfQf04vL0XfbQ/ATcEXAEksIsNdZ+brQvi3LKh6UPiWCRAs3A==", + "version": "1.9.27", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-html-renderer/-/g-plugin-html-renderer-1.9.27.tgz", + "integrity": "sha512-sXdHH4qFlilAKmrdI5bIkP24uht7+d9Tej6GVuokFBu6KkGT89SROExHhssoybhcYY2KxTShEsaXF+yO6pBbeQ==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/util": "^3.3.4", "gl-matrix": "^3.4.3", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-html-renderer/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -539,20 +539,20 @@ } }, "node_modules/@antv/g-plugin-image-loader": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/@antv/g-plugin-image-loader/-/g-plugin-image-loader-1.3.21.tgz", - "integrity": "sha512-PCFRYscSapA4pMkm9TcUQcxV9hnHKe0AIJaR35kV2F1hhuWLMyCPEuxVyWaCMYDFMfrDtVj7dXzL81L4fja8HQ==", + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/@antv/g-plugin-image-loader/-/g-plugin-image-loader-1.3.24.tgz", + "integrity": "sha512-M0grJ/GiYxUsBexakQCL7Wr1Uyg8BTdzmjgjDNKPzcF7tb5DrSVisZAy5jE+eRIE4ZqWylg0IUdJq/RFeds9jQ==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/util": "^3.3.4", "gl-matrix": "^3.4.3", "tslib": "^2.5.3" } }, "node_modules/@antv/g-plugin-image-loader/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -581,19 +581,19 @@ } }, "node_modules/@antv/g-web-animations-api": { - "version": "1.2.22", - "resolved": "https://registry.npmjs.org/@antv/g-web-animations-api/-/g-web-animations-api-1.2.22.tgz", - "integrity": "sha512-/bh/jUF/hVaDOnNtXRoB5ZsDnPK9IIrduLr4o5sFP+tOuCCBpalWgxeP11yBJoMpl2Y14GmipZTAD8QUoZyyNw==", + "version": "1.2.25", + "resolved": "https://registry.npmjs.org/@antv/g-web-animations-api/-/g-web-animations-api-1.2.25.tgz", + "integrity": "sha512-N6PA59OwjMxxL5axoOZeYdWNxmqErBvnjEiOWKq7xUqjaoyzz7/jRBBg5CtJ+IA+NNIRHOnMMEPPl4p8YCljRg==", "dependencies": { - "@antv/g-lite": "1.2.21", + "@antv/g-lite": "1.2.24", "@antv/util": "^3.3.4", "tslib": "^2.5.3" } }, "node_modules/@antv/g-web-animations-api/node_modules/@antv/util": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.6.tgz", - "integrity": "sha512-Oj2uAwBWEpEKbYcYgSJ/B6zv7t515L+JZzSpnkZeez/qwvDbS6s80lQRuzWzVhWCTHKSPLkgImxhkV9nzLmv4Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.7.tgz", + "integrity": "sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==", "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", @@ -640,9 +640,9 @@ } }, "node_modules/@antv/g2": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-5.1.15.tgz", - "integrity": "sha512-WiISs4GUOzHlA4vrkt+eQfr1+LVIAuv4AkfFCRzTprayMO72pLAdgTcwUg9YlvafwM220r9FQD1nXIlYNXOOhA==", + "version": "5.1.17", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-5.1.17.tgz", + "integrity": "sha512-KsPHfGUfgu3yTSR7yrDDqV9gWXMONynYAVRnPBt8xzXAvXCoYG8MU5O1iUu90IwOQi+4u9BxkC8r3bvd23EsDA==", "dependencies": { "@antv/component": "^1.0.1-beta.0", "@antv/coord": "^0.4.6", diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx index d049d45a4..c4bebaa30 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { useQuery } from 'react-query'; import { useLocation } from 'react-router-dom'; import { Progress, Rate, Typography } from 'antd'; import { Course } from 'types/api'; import { EnrolmentCapacityData } from 'types/courseCapacity'; +import { getCourseRating } from 'utils/api/unilectivesApi'; import ProgressBar from 'components/ProgressBar'; import TermTag from 'components/TermTag'; import { TERM } from 'config/constants'; @@ -15,51 +17,12 @@ type CourseAttributesProps = { courseCapacity?: EnrolmentCapacityData; }; -interface UnilectivesCourse { - courseCode: string; - archived: boolean; - // attributes: any[]; - calendar: string; - campus: string; - description: string; - enrolmentRules: string; - equivalents: string[]; - exclusions: string[]; - faculty: string; - fieldOfEducation: string; - genEd: boolean; - level: number; - school: string; - studyLevel: string; - terms: number[]; - title: string; - uoc: number; - overallRating: number; - manageability: number; - usefulness: number; - enjoyability: number; - reviewCount: number; -} - -const getCourseRating = async (code: string) => { - const res = await fetch(`https://unilectives.devsoc.app/api/v1/course/${code}`); - if (res.status !== 200) return undefined; - return ((await res.json()) as { course: UnilectivesCourse }).course; -}; - const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => { const { pathname } = useLocation(); const sidebar = pathname === '/course-selector'; - const [rating, setRating] = React.useState(undefined); - - React.useEffect(() => { - const fetchRating = async () => { - const r = await getCourseRating(course.code); - if (r) setRating(r); - }; - fetchRating(); - }, [course.code]); + const ratingQuery = useQuery(['courseRating', course.code], () => getCourseRating(course.code)); + const rating = ratingQuery.data; const { study_level: studyLevel, terms, campus, code, school, UOC } = course; diff --git a/frontend/src/types/unilectives.ts b/frontend/src/types/unilectives.ts new file mode 100644 index 000000000..e047aa110 --- /dev/null +++ b/frontend/src/types/unilectives.ts @@ -0,0 +1,25 @@ +export type UnilectivesCourse = { + courseCode: string; + archived: boolean; + // attributes: any[]; + calendar: string; + campus: string; + description: string; + enrolmentRules: string; + equivalents: string[]; + exclusions: string[]; + faculty: string; + fieldOfEducation: string; + genEd: boolean; + level: number; + school: string; + studyLevel: string; + terms: number[]; + title: string; + uoc: number; + overallRating: number; + manageability: number; + usefulness: number; + enjoyability: number; + reviewCount: number; +}; diff --git a/frontend/src/utils/api/unilectivesApi.ts b/frontend/src/utils/api/unilectivesApi.ts new file mode 100644 index 000000000..3cc7617dc --- /dev/null +++ b/frontend/src/utils/api/unilectivesApi.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; +import { UnilectivesCourse } from 'types/unilectives'; + +// eslint-disable-next-line import/prefer-default-export +export const getCourseRating = async (code: string) => { + try { + const res = await axios.get(`https://unilectives.devsoc.app/api/v1/course/${code}`); + return (res.data as { course: UnilectivesCourse }).course; + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error at getCourseRating: ', err); + return undefined; + } +}; From 7e32d7b0904e908e9d15df2719d7677d875ca829 Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 4 Apr 2024 16:05:59 +1100 Subject: [PATCH 4/6] Change Unilective rating dials to Circles colors --- .../CourseAttributes/CourseAttributes.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx index c4bebaa30..3c3ce7440 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useQuery } from 'react-query'; import { useLocation } from 'react-router-dom'; import { Progress, Rate, Typography } from 'antd'; +import { useTheme } from 'styled-components'; import { Course } from 'types/api'; import { EnrolmentCapacityData } from 'types/courseCapacity'; import { getCourseRating } from 'utils/api/unilectivesApi'; @@ -20,6 +21,7 @@ type CourseAttributesProps = { const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => { const { pathname } = useLocation(); const sidebar = pathname === '/course-selector'; + const theme = useTheme(); const ratingQuery = useQuery(['courseRating', course.code], () => getCourseRating(course.code)); const rating = ratingQuery.data; @@ -127,7 +129,8 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => format={() => `${rating.enjoyability ? rating.enjoyability.toFixed(1) : '?'} / 5` } - width={65} + strokeColor={theme.purplePrimary} + size={65} />

Enjoyability

@@ -136,7 +139,8 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => type="dashboard" percent={rating.usefulness ? (rating.usefulness / 5) * 100 : 0} format={() => `${rating.usefulness ? rating.usefulness.toFixed(1) : '?'} / 5`} - width={65} + strokeColor={theme.purplePrimary} + size={65} />

Usefulness

@@ -147,17 +151,14 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => format={() => `${rating.manageability ? rating.manageability.toFixed(1) : '?'} / 5` } - width={65} + strokeColor={theme.purplePrimary} + size={65} />

Manageability

- +

Overall

Date: Sat, 6 Apr 2024 21:56:33 +1100 Subject: [PATCH 5/6] Refactor Unilectives widget CSS --- .../CourseAttributes/CourseAttributes.tsx | 18 +++++++++--------- .../CourseAttributes/styles.ts | 13 ++++++++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx index 3c3ce7440..d9c0acac1 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/CourseAttributes.tsx @@ -122,7 +122,7 @@ const CourseAttributes = ({ course, courseCapacity }: CourseAttributesProps) => content: rating ? ( <> -
+ strokeColor={theme.purplePrimary} size={65} /> -

Enjoyability

-
-
+ Enjoyability + + strokeColor={theme.purplePrimary} size={65} /> -

Usefulness

-
-
+ Usefulness + + strokeColor={theme.purplePrimary} size={65} /> -

Manageability

-
+ Manageability +
diff --git a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts index d4f836b2b..0a004f4e6 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts +++ b/frontend/src/components/CourseDescriptionPanel/CourseAttributes/styles.ts @@ -43,6 +43,15 @@ const RatingWrapper = styled.div` justify-content: space-between; `; +const DialWrapper = styled.div` + text-align: center; + width: 85px; +`; + +const DialLabel = styled.p` + font-size: small; +`; + export default { AttributeWrapper, AttributeText, @@ -50,5 +59,7 @@ export default { AttributesWrapperConcise, AttributeConcise, Link, - RatingWrapper + RatingWrapper, + DialWrapper, + DialLabel }; From a80308462e1b2d41d3b8124196f46583d4494f88 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 7 Apr 2024 14:03:00 +1000 Subject: [PATCH 6/6] Refactor Unilectives API helper --- frontend/src/utils/api/unilectivesApi.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/utils/api/unilectivesApi.ts b/frontend/src/utils/api/unilectivesApi.ts index 3cc7617dc..c466357b3 100644 --- a/frontend/src/utils/api/unilectivesApi.ts +++ b/frontend/src/utils/api/unilectivesApi.ts @@ -4,8 +4,10 @@ import { UnilectivesCourse } from 'types/unilectives'; // eslint-disable-next-line import/prefer-default-export export const getCourseRating = async (code: string) => { try { - const res = await axios.get(`https://unilectives.devsoc.app/api/v1/course/${code}`); - return (res.data as { course: UnilectivesCourse }).course; + const res = await axios.get<{ course: UnilectivesCourse }>( + `https://unilectives.devsoc.app/api/v1/course/${code}` + ); + return res.data.course; } catch (err) { // eslint-disable-next-line no-console console.error('Error at getCourseRating: ', err);