Compare commits

..

182 Commits

Author SHA1 Message Date
Hykilpikonna 9656b3184b [O] Optimize nav bar shadow 2019-09-18 23:25:50 -04:00
Hykilpikonna b8dfb8f732 [F] Fix negative index problem 2019-09-18 23:07:43 -04:00
Hykilpikonna 002aa84444 [O] Ignore non-active scores 2019-09-18 21:52:10 -04:00
Hykilpikonna e7c513695d [O] Disable host check 2019-09-18 21:51:27 -04:00
Hykilpikonna e51dbd2c5b [O] Make GPA time font size smaller 2019-09-18 21:50:44 -04:00
Hykilpikonna 9157232d45 [O] Make GPA font size larger 2019-09-18 21:50:32 -04:00
Hykilpikonna 17ef8f4380 [O] Vertically center 2019-09-18 21:50:19 -04:00
Hykilpikonna c31dbf0e50 [O] Make GPA header font smaller 2019-09-18 21:50:05 -04:00
Hykilpikonna 9c2c1c3195 [O] Optimize card margins 2019-09-18 08:27:59 -04:00
Hykilpikonna 820c3c1148 [O] Optimize layout 2019-09-18 08:27:27 -04:00
Hykilpikonna 6efb832212 Merge branch 'feature' into styling 2019-09-18 08:26:07 -04:00
Hykilpikonna c885137ed7 [O] Fix floating point precision errors 2019-09-16 22:47:13 -04:00
Hykilpikonna bb4b34722f [+] Display GPA string 2019-09-16 22:24:56 -04:00
Hykilpikonna 2beca45e38 [+] Encapsulate method to get GPA string 2019-09-16 22:24:47 -04:00
Hykilpikonna cbec0add3b Revert "[T] Test GPA calculations"
This reverts commit 0ebce968b9.
2019-09-16 22:24:10 -04:00
Hykilpikonna 0ebce968b9 [T] Test GPA calculations 2019-09-16 22:24:06 -04:00
Hykilpikonna 4095041925 [+] Add status field in course model 2019-09-16 22:23:52 -04:00
Hykilpikonna 0e618ceb13 [+] Create cards in overall 2019-09-07 17:04:04 -04:00
Hykilpikonna 042e72abb6 [O] Reduce redundant code 2019-09-07 16:48:57 -04:00
Hykilpikonna 517235982b [F] Fix return type void 2019-09-07 16:48:46 -04:00
Hykilpikonna 6e7041edcd [+] Create method to calculate GP for a course 2019-09-07 16:46:46 -04:00
Hykilpikonna 67cf33b48c [F] Remove scaleUp if score is 0 2019-09-07 16:44:34 -04:00
Hykilpikonna 4c822fd207 [+] Add borders to navigation 2019-09-07 16:32:05 -04:00
Hykilpikonna 68afbb8c76 [O] Optimize accuracy detection 2019-09-07 16:14:42 -04:00
Hykilpikonna 5da0e89e08 [+] Return boolean indicating accurate or not when calculating gpa 2019-09-07 16:12:32 -04:00
Hykilpikonna b2db05d5e2 [O] Remove course that does not have level 2019-09-07 16:04:50 -04:00
Hykilpikonna 3cb74083a7 [+] Create method to calculate GPA 2019-09-07 16:03:57 -04:00
Hykilpikonna d3072ccaf6 [+] Create keyword constants in GPAUtils 2019-09-07 16:03:34 -04:00
Hykilpikonna d566b53c22 [+] Create letterGrade and numericGrade fields 2019-09-07 15:49:11 -04:00
Hykilpikonna 7bad961f70 [+] Add field level and scaleUp 2019-09-07 14:57:37 -04:00
Hykilpikonna 13e307f8d2 [+] Create GPA scale 2019-09-07 14:52:54 -04:00
Hykilpikonna 448e699cd3 [O] Optimize login http fetch 2019-09-07 14:42:22 -04:00
Hykilpikonna 1ca32b5ebd [O] Optimize loadAssignments() 2019-09-07 14:07:49 -04:00
Hykilpikonna 5ac3183ec1 [F] Fix body isn't in json format problem 2019-09-07 14:04:59 -04:00
Hykilpikonna a7384753c8 [O] Optimize loadCourses request 2019-09-07 14:04:38 -04:00
Hykilpikonna 393fc1cc71 [+] Create http field in App.ts 2019-09-07 14:04:23 -04:00
Hykilpikonna 06c265159b [F] Fix constructor 2019-09-07 13:59:05 -04:00
Hykilpikonna 53a0884d0b [+] Create http-utils class 2019-09-07 13:56:43 -04:00
Hykilpikonna 7b0f11a1f4 [F] Fix assignments null 2019-09-07 13:01:05 -04:00
Hykilpikonna 4dc5966e51 [+] Load assignments 2019-09-07 12:30:27 -04:00
Hykilpikonna be0a657ba3 [+] Load courses 2019-09-07 12:30:19 -04:00
Hykilpikonna 3287c14fa3 [+] Store token in a field 2019-09-07 12:15:13 -04:00
Hykilpikonna 7af20f806b [O] Move cookies detection to login class 2019-09-07 12:14:57 -04:00
Hykilpikonna bd8d7fd113 [U] Update keywords (from "token" to "data") 2019-09-07 11:48:28 -04:00
Hykilpikonna 76cf8c4c53 [+] Check cookies on initt 2019-09-07 10:11:31 -04:00
Hykilpikonna eaa1609b77 [+] Load data after login 2019-09-07 10:11:18 -04:00
Hykilpikonna 1324afe978 [+] Create method to load data after login 2019-09-07 10:11:08 -04:00
Hykilpikonna e86d2fd4f5 [O] Create a better ascii art 2019-09-07 10:08:49 -04:00
Hykilpikonna cf34db2c61 [+] Show splash on create 2019-09-07 10:07:04 -04:00
Hykilpikonna 9038a73678 [+] Save cookies on login 2019-09-07 10:06:19 -04:00
Hykilpikonna 446ed686bd [+] Create splash ascii art 2019-09-07 10:05:53 -04:00
Hykilpikonna 4782870d94 [+] Add vue-cookies to Vue.use() 2019-09-07 09:21:57 -04:00
Hykilpikonna 3ce21623d8 [+] Import vue-cookies 2019-09-07 09:21:29 -04:00
Hykilpikonna 2338e4f6af [+] Show error message on error 2019-09-07 09:14:13 -04:00
Hykilpikonna 38089c74b5 [F] Fix duplicate "/api/" in path 2019-09-07 09:13:11 -04:00
Hykilpikonna 8860c88b1a [F] Fix HTTP GET can't have body 2019-09-07 09:09:50 -04:00
Hykilpikonna 75f9dc9849 [U] Remove testing error text 2019-09-07 08:31:32 -04:00
Hykilpikonna 805ffaa50e [+] Check the success flag in response 2019-09-07 08:28:54 -04:00
Hykilpikonna c7d16a00e6 [+] Send username and password to api in body 2019-09-07 08:28:24 -04:00
Hykilpikonna 67ec2b85b2 [+] Create error message div 2019-09-07 08:24:16 -04:00
Hykilpikonna 9a752305e3 [O] Fix error message styling 2019-09-07 08:23:34 -04:00
Hykilpikonna c95a5b343e Merge branch 'feature' into styling 2019-09-07 08:10:10 -04:00
Hykilpikonna 5029555c21 [U] Update api url 2019-09-07 08:02:50 -04:00
Hykilpikonna 8eb2080f14 [+] Add error class on error 2019-09-07 08:02:22 -04:00
Hykilpikonna 0296b2151a [+] Create error message field 2019-09-07 08:01:49 -04:00
Hykilpikonna 3575db8182 [+] Create css class for input error 2019-09-07 08:01:36 -04:00
Hykilpikonna 0025ec9213 [O] Optimize graph creation 2019-09-06 19:43:36 -04:00
Hykilpikonna 489328c624 [+] Use the chart data to show chart 2019-08-27 20:55:33 +08:00
Hykilpikonna 36a211e186 [+] Create method to convert chart data 2019-08-27 20:55:06 +08:00
Hykilpikonna d7c4c87959 [+] Create courses prop. and pass it from overall.vue 2019-08-25 01:57:11 +08:00
Hykilpikonna 3cd9db65ec [+] Create courses prop. and pass it from app.vue 2019-08-25 01:56:52 +08:00
Hykilpikonna e03798af13 Merge branch 'optimization' into feature 2019-08-24 21:21:38 +08:00
Hykilpikonna 1fd4e89f84 [+] Add proper documentation to the fields 2019-08-24 21:21:04 +08:00
Hykilpikonna c05b799334 [O] Show overall only when assignments are ready. 2019-08-24 21:18:51 +08:00
Hykilpikonna b9f0316f76 [+] Wait for isAssignmentReady() 2019-08-24 21:16:42 +08:00
Hykilpikonna 2b3cbb4061 [+] Create method to check if the courses are ready 2019-08-24 21:16:13 +08:00
Hykilpikonna 0653deba64 [+] Import pWaitFor dependency 2019-08-24 21:08:06 +08:00
Hykilpikonna 67a9417f2b [+] Create assignmentsReady field 2019-08-24 21:05:41 +08:00
Hykilpikonna ca49223432 [+] Get assignments for all the courses 2019-08-24 21:05:23 +08:00
Hykilpikonna 6d0d23d0dd [O] Specify type for the onLogin method 2019-08-24 20:39:43 +08:00
Hykilpikonna 6c9061d4d9 [O] Specify type for the courses field 2019-08-24 20:39:29 +08:00
Hykilpikonna 56b9be01ba [+] Create course interface 2019-08-24 20:39:14 +08:00
Hykilpikonna c8935c41cb [M] Move Grade interface to App.ts 2019-08-24 20:39:00 +08:00
Hykilpikonna 1d96dcc0a8 [+] Create method to filter assignments 2019-08-22 21:58:16 +08:00
Hykilpikonna 811de8f5e2 [+] Create a grade interfacce 2019-08-22 21:58:01 +08:00
Hykilpikonna ec4196088a [+] Create json utils class 2019-08-22 21:57:48 +08:00
Hykilpikonna 863fdcb50e Merge branch 'bug-fixes' into feature 2019-08-22 21:05:51 +08:00
Hykilpikonna 2e27fcceb9 [F] Fix selected tab default value 2019-08-22 21:03:19 +08:00
Hykilpikonna 84f202ac9e [O] Disable graph smoothing 2019-08-22 20:59:39 +08:00
Hykilpikonna fba56b3eca [+] Add a ve-line graph in graph comp. 2019-08-22 17:02:42 +08:00
Hykilpikonna a3c2bf6139 [+] Add a graph in overall 2019-08-22 17:02:26 +08:00
Hykilpikonna 9997080c63 [+] Update the selected tab on event 2019-08-22 17:01:42 +08:00
Hykilpikonna 497875d56a [+] Add an overall component 2019-08-22 17:01:12 +08:00
Hykilpikonna 79b50cc59c [+] Import VCharts with Vue.use() 2019-08-22 17:00:41 +08:00
Hykilpikonna 9c474d4ecd Merge branch 'styling' into feature 2019-08-22 16:27:09 +08:00
Hykilpikonna 32e616b65d Merge branch 'optimization' into feature 2019-08-22 16:24:49 +08:00
Hykilpikonna c19581e602 [O] Optimize error handling in login.ts 2019-08-22 16:24:32 +08:00
Hykilpikonna 91929df865 [-] Remove unnecessary event call 2019-08-22 16:24:07 +08:00
Hykilpikonna fdeab0f2c9 [+] Create overall page element 2019-08-22 16:21:05 +08:00
Hykilpikonna 3a7c447058 [+] Import v-chars cdn 2019-08-22 16:20:38 +08:00
Hykilpikonna 9bc1618dc5 [+] Import v-charts 2019-08-22 16:20:18 +08:00
Hykilpikonna 08e98c140f [+] Create a graph component 2019-08-22 15:48:14 +08:00
Hykilpikonna 70346aeece [O] Center the navigation items 2019-08-22 15:36:12 +08:00
Hykilpikonna 2a69d9a1de Merge branch 'styling' 2019-08-21 23:29:42 +08:00
Hykilpikonna ecb418cc61 [+] Add a selectedTab field 2019-08-21 23:29:37 +08:00
Hykilpikonna 21850bca5d [+] Add app content div 2019-08-21 23:29:20 +08:00
Hykilpikonna a574dcd64a [F] Fix body user agent margins 2019-08-21 23:27:14 +08:00
Hykilpikonna 06707403b7 Merge branch 'bug-fixes' 2019-08-21 23:17:51 +08:00
Hykilpikonna c0d4eab637 [F] Fix the identifier for courses displaying as "course-[Object]" 2019-08-21 23:17:33 +08:00
Hykilpikonna f1955b61ab Merge branch 'feature' 2019-08-21 23:04:20 +08:00
Hykilpikonna 1a50ada15a Merge branch 'styling' 2019-08-21 23:02:51 +08:00
Hykilpikonna 0043a16666 Merge branch 'bug-fixes' 2019-08-21 23:01:39 +08:00
Hykilpikonna 7562a0144c [F] Fix active index not updating 2019-08-21 23:00:50 +08:00
Hykilpikonna c22e38033e [-] Remove glowing effect 2019-08-21 22:56:06 +08:00
Hykilpikonna 294480418c [F] Fix login screen size on iPhone 5/SE 2019-08-21 22:55:55 +08:00
Hykilpikonna fac4c86b2d [F] Fix vertical center on mobile devices 2019-08-21 22:55:09 +08:00
Hykilpikonna 7aebde42b1 [+] Add some debug output 2019-08-21 16:29:22 +08:00
Hykilpikonna 10c994d6c2 [+] Call method in app.ts on navigate 2019-08-21 16:27:55 +08:00
Hykilpikonna f82d1081f9 [+] Call custom event when a navigation item is selected 2019-08-21 16:24:43 +08:00
Hykilpikonna d33e189934 Merge branch 'optimization' 2019-08-21 15:58:38 +08:00
Hykilpikonna 54f862ff13 [F] Fix "component lists rendered with v-for should have explicit keys" 2019-08-21 15:58:17 +08:00
Hykilpikonna 8cca38b55a [O] Fix TSLint: " should be ' 2019-08-21 15:56:56 +08:00
Hykilpikonna 22f3e208d8 Merge branch 'bug-fixes' 2019-08-21 15:49:27 +08:00
Hykilpikonna 615e4fa2cb [F] Fix course name displaying as json 2019-08-21 15:48:39 +08:00
Hykilpikonna c8b6292cb1 Merge branch 'feature' 2019-08-21 15:42:42 +08:00
Hykilpikonna ebf9b0efc6 Merge branch 'styling' 2019-08-21 15:42:25 +08:00
Hykilpikonna db0915ca0e [F] Remove excessive margin-top in app.scss 2019-08-21 15:42:00 +08:00
Hykilpikonna 36b8857191 [+] Add navigation comp. to app.vue 2019-08-21 15:41:05 +08:00
Hykilpikonna 1dcb26cd25 [+] Import navigation in app.ts 2019-08-21 15:40:24 +08:00
Hykilpikonna 822a1fecc2 [+] Show courses with v-for 2019-08-21 15:40:06 +08:00
Hykilpikonna 7e73d6581b [+] Add "courses" property to navigation comp. 2019-08-21 15:39:54 +08:00
Hykilpikonna 69b93d4356 [+] Create navigation bar component 2019-08-21 15:39:33 +08:00
Hykilpikonna 06f3c9614a [+] Assign courses when user logged in 2019-08-21 15:06:01 +08:00
Hykilpikonna 8ef5993f56 [+] Add a courses field 2019-08-21 15:05:30 +08:00
Hykilpikonna 70d0ee6c29 [+] Hide login panel on login 2019-08-21 15:03:36 +08:00
Hykilpikonna 5bc3964649 Merge branch 'UI' 2019-08-21 14:58:20 +08:00
Hykilpikonna aa64b2b4cd [-] Remove disable loading because it is useless 2019-08-21 14:57:38 +08:00
Hykilpikonna e7daac738d [+] Enable and disable loading at appropriate time 2019-08-21 14:56:50 +08:00
Hykilpikonna 6b15b617cf [F] Fix "Interpolation inside attributes has been removed" 2019-08-21 14:55:59 +08:00
Hykilpikonna 96f73cf31d [+] Add login button loading switch 2019-08-21 14:52:39 +08:00
Hykilpikonna ff82c3811f [O] Add a glowing effect to the panel 2019-08-21 14:30:24 +08:00
Hykilpikonna c4561d11a1 [O] Make the panel's background white 2019-08-21 14:26:26 +08:00
Hykilpikonna 7216cdb5c8 [O] Vertically center the login panel 2019-08-21 14:24:53 +08:00
Hykilpikonna 2e697904c9 [+] Add an overlay to the login panel 2019-08-21 14:19:39 +08:00
Hykilpikonna 4be24d59fd [+] Create a field controling if login is shown 2019-08-21 14:06:15 +08:00
Hykilpikonna 53668f3cc2 [O] Move the logo into the login panel 2019-08-21 14:05:26 +08:00
Hykilpikonna 6d20b42447 [O] Add some borders to the login panel 2019-08-21 14:04:47 +08:00
Hykilpikonna 011db90677 [O] Center the login panel 2019-08-21 14:04:26 +08:00
Hykilpikonna f7a43b3d86 [O] Make the login panel smaller 2019-08-21 14:04:13 +08:00
Hykilpikonna d9dfef59a2 [O] Style the button to have the same width 2019-08-21 14:02:23 +08:00
Hykilpikonna cea3c2724f [O] Clarify comments 2019-08-21 14:01:25 +08:00
Hykilpikonna 19dfbd04b9 [+] Call back when the response text is ready 2019-08-19 20:22:13 +08:00
Hykilpikonna e4bd1f7d50 [+] Fetch request 2019-08-19 20:22:00 +08:00
Hykilpikonna ec467dc5e8 [U] Update base url 2019-08-19 20:21:11 +08:00
Hykilpikonna 2a723a5b06 [+] Create base url constant 2019-08-19 13:25:32 +08:00
Hykilpikonna 4a89b3c24c [+] Create constants class 2019-08-19 13:25:20 +08:00
Hykilpikonna 2fa6f46869 [+] Add proper javadocs 2019-08-19 13:22:21 +08:00
Hykilpikonna 1cd30558ff [+] Add onclick method to the login button 2019-08-19 13:22:11 +08:00
Hykilpikonna b36336e024 [+] Add a login button 2019-08-19 13:21:33 +08:00
Hykilpikonna 80409bd753 [O] Add some margins to the input bars 2019-08-17 13:49:02 +08:00
Hykilpikonna 851503edc6 [F] Fix "Property is not defined on the instance but referenced during render." 2019-08-17 13:37:14 +08:00
Hykilpikonna 6da21fbced [O] Change v-model names 2019-08-17 13:23:10 +08:00
Hykilpikonna b0d6d78a7e [+] Add proper comments for ElementUI imports 2019-08-17 12:51:55 +08:00
Hykilpikonna ad7bd06b13 [+] Import style sheets for Element 2019-08-17 12:51:02 +08:00
Hykilpikonna 0d194dea06 [F] Add id to fix component import problem 2019-08-17 12:50:37 +08:00
Hykilpikonna b0d35b5551 [-] Remove "tslint:recommended" 2019-08-17 12:32:14 +08:00
Hykilpikonna a257675a36 [F] Fix invalid path 2019-08-17 12:31:57 +08:00
Hykilpikonna 189984d900 [+] Add a login element 2019-08-17 12:31:40 +08:00
Hykilpikonna e51c0ac115 [+] Import login comp. in app.ts 2019-08-17 12:31:28 +08:00
Hykilpikonna f0dff3c3f9 [+] Add el-inputs to login comp. 2019-08-17 12:31:14 +08:00
Hykilpikonna 162b915911 [+] Create login component 2019-08-17 12:30:49 +08:00
Hykilpikonna ed1b843597 [+] Create run script 2019-08-17 12:30:26 +08:00
Hykilpikonna c3419b9764 [U] Change language to english 2019-08-16 16:56:11 +08:00
Hykilpikonna b687c50cfb [+] Import ElementUI 2019-08-16 16:56:00 +08:00
Hykilpikonna 9cd0ba01f8 [O] Disable tslint check for curly braces 2019-08-16 16:42:19 +08:00
Hykilpikonna 634db4c906 [M] Move app into components dir 2019-08-16 16:42:03 +08:00
Hykilpikonna 1524303486 [O] Change the tslint indent to 4 spaces 2019-08-15 11:45:00 +08:00
Hykilpikonna 7133ac7f15 [U] Reimport app in main 2019-08-15 11:44:44 +08:00
Hykilpikonna 0e60153cc8 [M] Move app to app directory and separate the files 2019-08-15 11:44:32 +08:00
Hykilpikonna 9941dc95fe [-] Remove hello world 2019-08-15 11:44:08 +08:00
Hykilpikonna 2e6b573d38 [U] Reformat index.html 2019-08-15 11:43:43 +08:00
Hykilpikonna 11573cb673 init 2019-08-15 10:35:19 +08:00
60 changed files with 12703 additions and 675 deletions
+21
View File
@@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
-14
View File
@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404: Redirecting...</title>
<meta http-equiv = "refresh" content = "0; url = https://vera.hydev.org/" />
</head>
<body>
404 Not Found! Redirecting to (<a href="https://vera.hydev.org">https://vera.hydev.org</a>)...
<script>
window.location.href = 'https://vera.hydev.org';
</script>
</body>
</html>
-1
View File
@@ -1 +0,0 @@
demo.vera.hydev.org
+29
View File
@@ -0,0 +1,29 @@
# veracross-analyzer
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[{"score_id":5593330,"id":322150,"assignment_id":322150,"assignment_type_id":3,"assignment_type":"Quiz","assignment_type_sort_key":3,"assignment_description":"2.3 Open Notes","grading_period":"Quarter 1","assignment_date_long":"Wed, Sep 11","due_date_long":"Wed, Sep 11","due_date":"Sep 11","due_day":"Wed","_date":"09/11/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":16,"points_possible":16,"raw_score":"14","percent_grade":"8750%","completion_status_id":3,"completion_status":"Complete","is_unread":1.0,"is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0},{"score_id":5584935,"id":321649,"assignment_id":321649,"assignment_type_id":3,"assignment_type":"Quiz","assignment_type_sort_key":3,"assignment_description":"2.2 Open Notes","grading_period":"Quarter 1","assignment_date_long":"Mon, Sep 09","due_date_long":"Mon, Sep 09","due_date":"Sep 09","due_day":"Mon","_date":"09/09/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":10,"points_possible":10,"raw_score":"6","percent_grade":"6000%","completion_status_id":3,"completion_status":"Complete","is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0},{"score_id":5602940,"id":322723,"assignment_id":322723,"assignment_type_id":2,"assignment_type":"Homework","assignment_type_sort_key":2,"assignment_description":"Autobiography","grading_period":"Quarter 1","assignment_date_long":"Wed, Sep 04","due_date_long":"Thu, Sep 05","due_date":"Sep 05","due_day":"Thu","_date":"09/05/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":10,"points_possible":10,"raw_score":"","percent_grade":"0%","completion_status_id":0,"completion_status":"Pending","is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0}],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
-1
View File
@@ -1 +0,0 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
-250
View File
@@ -1,250 +0,0 @@
{
"success": true,
"data": {
"user": {
"id": 1,
"schoolPersonPk": 109467,
"username": "ygui21",
"lastLogin": "Jun 5, 2020 1:28:51 PM",
"firstLogin": "Dec 2, 2019 7:31:15 PM",
"firstName": "Yijie",
"lastName": "Gui",
"graduationYear": 2021,
"emails": "ygui21@stjohnsprep.org",
"classes": "32451|32453|32458|32856|32872|32874|32878|32880|32882|32890|33070|33093|33121|33173|33337|33464|34174|34197|34199|34209"
},
"token": "Removed",
"courses": [
{
"level": "H",
"id_ci": 196,
"rating": {
"id_ci": 196,
"id_user": 1,
"userFullName": "Yijie]\u003d[Gui",
"ratings": [
5,
5,
3,
5,
4
],
"comment": "Mr. Crowell\u0027s selected books for this course are very interesting, and the essay topics are generally unique too, allowing us to express our creativity. His lectures are also very in-depth, strengthening our understanding of the ideas that the authors wanted to express. However, the style of the classroom might be boring for some people. For grading fairness, I think it is very fair, but his standards are a little bit too high because achieving a perfect score for an essay is very much impossible."
},
"name": "English 3 H",
"teacherName": "Mr. Crowell",
"id": 33337,
"assignmentsId": 10934147,
"letterGrade": "A+",
"numericGrade": 97.14,
"status": "active"
},
{
"level": "AP",
"id_ci": 19,
"rating": {
"id_ci": 19,
"id_user": -1,
"userFullName": "Anonymous]\u003d[Student",
"ratings": [
5,
5,
5,
5,
5
],
"comment": "Calculus made so much easier"
},
"name": "AP Calculus AB (Juniors)",
"teacherName": "Ms. Dobrowolski",
"id": 32453,
"assignmentsId": 10934142,
"letterGrade": "A+",
"numericGrade": 100.0,
"status": "active"
},
{
"level": "AP",
"id_ci": 251,
"rating": {
"id_ci": 251,
"id_user": 1,
"userFullName": "Yijie]\u003d[Gui",
"ratings": [
5,
5,
5,
5,
5
],
"comment": "Cations go meow"
},
"name": "AP Chemistry",
"teacherName": "Ms. Stone",
"id": 33464,
"assignmentsId": 10934148,
"letterGrade": "A+",
"numericGrade": 100.0,
"status": "active"
},
{
"level": "AP",
"id_ci": 22,
"rating": {
"id_ci": 22,
"id_user": 1,
"userFullName": "Yijie]\u003d[Gui",
"ratings": [
5,
5,
5,
3,
4
],
"comment": "Mr. Dankert can\u0027t really systematically teach, often he forgets to tell us something very important and then forgets that he forgot. The labs explained a lot of them very well."
},
"name": "AP Physics 1",
"teacherName": "Mr. Dankert",
"id": 32458,
"assignmentsId": 10934143,
"letterGrade": "A",
"numericGrade": 95.67,
"status": "active"
},
{
"level": "AP",
"id_ci": 18,
"rating": {
"id_ci": 18,
"id_user": 1,
"userFullName": "Yijie]\u003d[Gui",
"ratings": [
5,
5,
5,
5,
5
],
"comment": "Psychology is the best, and most valuable class I\u0027ve ever taken! Everything is just so relatable to my life!"
},
"name": "AP Psychology",
"teacherName": "Mr. Emerson",
"id": 32451,
"assignmentsId": 10934141,
"letterGrade": "A+",
"numericGrade": 100.0,
"status": "active"
},
{
"level": "A",
"id_ci": 98,
"rating": {
"id_ci": 98,
"id_user": 1,
"userFullName": "Yijie]\u003d[Gui",
"ratings": [
5,
5,
5,
5,
5
],
"comment": "Mr. Pynchon is very nice and encouraging."
},
"name": "US History A",
"teacherName": "Mr. Pynchon",
"id": 33093,
"assignmentsId": 10941280,
"letterGrade": "A+",
"numericGrade": 99.39,
"status": "active"
},
{
"level": "H",
"id_ci": 100,
"name": "US History H",
"teacherName": "Ms. Heath",
"id": 33096,
"assignmentsId": 10934144,
"status": "past"
},
{
"level": "A",
"id_ci": 134,
"name": "Relational Dynamics A",
"teacherName": "Mr. Reinbold",
"id": 33173,
"assignmentsId": 10934146,
"status": "past"
},
{
"level": "A",
"id_ci": 77,
"rating": {
"id_ci": 77,
"id_user": -1,
"userFullName": "Anonymous]\u003d[Student",
"ratings": [
5,
4,
5,
5,
3
],
"comment": "Honestly, everything is great except that the grading is way too harsh for an Accelerated course."
},
"name": "Social Justice A",
"teacherName": "Mr. Reinbold",
"id": 33121,
"assignmentsId": 10934145,
"letterGrade": "A+",
"numericGrade": 97.0,
"status": "active"
},
{
"level": "Sport",
"name": "Yoga AS",
"teacherName": "Ms. Fanikos",
"id": 33070,
"assignmentsId": 10935189,
"status": "past"
},
{
"level": "Club",
"id_ci": 316,
"name": "HS Magic Trick Club 2019",
"teacherName": "Mr. Reinbold",
"id": 34174,
"assignmentsId": 10949139,
"status": "active"
},
{
"level": "Club",
"id_ci": 331,
"name": "HS Science \u0026amp; Technology 2019",
"teacherName": "Ms. Erwin",
"id": 34197,
"assignmentsId": 10952100,
"status": "active"
},
{
"level": "Club",
"id_ci": 333,
"name": "HS Computer Club 2019",
"teacherName": "Mr. Gilmore",
"id": 34199,
"assignmentsId": 10951448,
"status": "active"
},
{
"level": "Club",
"id_ci": 336,
"name": "HS Chinese Ambassadors Club 2019",
"teacherName": "Mrs. Mills",
"id": 34209,
"assignmentsId": 10953979,
"status": "active"
}
]
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

-5
View File
@@ -1,5 +0,0 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=1024"><link rel=icon href=/logo@32px.png><title>Veracross Analyzer</title><link href=/css/app.72ceade9.css rel=preload as=style><link href=/js/app.c7702e9a.js rel=preload as=script><link href=/js/chunk-vendors.4383782d.js rel=preload as=script><link href=/css/app.72ceade9.css rel=stylesheet></head><body style="margin: 0"><noscript><strong>We're sorry but veracross-analyzer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js></script><script src=https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js></script><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css><link rel=stylesheet href=https://unpkg.com/element-ui/lib/theme-chalk/index.css><link href="https://fonts.googleapis.com/css?family=Nunito+Sans&display=swap" rel=stylesheet><script src=/js/chunk-vendors.4383782d.js></script><script src=/js/app.c7702e9a.js></script></body><script async src="https://www.googletagmanager.com/gtag/js?id=G-Q615K1KFLC"></script><script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Q615K1KFLC');</script></html>
-14
View File
@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirecting...</title>
<meta http-equiv = "refresh" content = "0; url = https://vera.hydev.org/#info" />
</head>
<body>
Redirecting to (<a href="https://vera.hydev.org/#info">https://vera.hydev.org/#info</a>)...
<script>
window.location.href = 'https://vera.hydev.org/#info';
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

+11600
View File
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
{
"name": "veracross-analyzer",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"echarts": "^4.2.1",
"element-ui": "^2.11.1",
"p-wait-for": "^3.1.0",
"v-charts": "^1.19.0",
"vue": "^2.6.10",
"vue-class-component": "^7.0.2",
"vue-cookies": "^1.5.13",
"vue-property-decorator": "^8.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.10.0",
"@vue/cli-plugin-typescript": "^3.10.0",
"@vue/cli-service": "^3.10.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.1.0",
"typescript": "^3.4.3",
"vue-template-compiler": "^2.6.10"
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Veracross Analyzer</title>
</head>
<body style="margin: 0">
<noscript>
<strong>We're sorry but veracross-analyzer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- V-Charts -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css">
<!-- ElementUI -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</body>
</html>
+2
View File
@@ -0,0 +1,2 @@
cd ../
npm run serve
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+8
View File
@@ -0,0 +1,8 @@
#app
{
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
+188
View File
@@ -0,0 +1,188 @@
import {Component, Vue} from 'vue-property-decorator';
import Login from '@/components/login/login';
import Navigation from '@/components/navigation/navigation';
import Overall from '@/pages/overall/overall';
import Constants from '@/constants';
import JsonUtils from '@/utils/json-utils';
import pWaitFor from 'p-wait-for';
import {HttpUtils} from '@/utils/http-utils';
/**
* Objects of this interface represent assignment grades.
*/
export interface Grade
{
type: string,
description: string,
date: string,
complete: string,
include: boolean,
display: boolean,
scoreMax: number,
score: number
}
/**
* A course
*/
export interface Course
{
assignmentsId: number,
id: number,
name: string,
teacherName: string,
status: string,
letterGrade?: string,
numericGrade?: number,
level: string,
scaleUp: number,
assignments: Grade[]
}
@Component({
components: {Login, Navigation, Overall},
})
export default class App extends Vue
{
// Is the login panel shown
public showLogin: boolean = true;
// List of course that the student takes
public courses: Course[] = [];
// Currently selected tab
public selectedTab: string = "overall";
// Are the course assignments loaded from the server.
public assignmentsReady: boolean = false;
// Token
public token: string = '';
// Http Client
public http: HttpUtils = new HttpUtils('');
/**
* This is called when the instance is created.
*/
public created()
{
// Show splash
console.log(Constants.SPLASH);
}
/**
* This is called when the user logs in.
*
* @param token Authorization token
*/
public onLogin(token: string)
{
// Hide login bar
this.showLogin = false;
// Store token
this.token = token;
// Assign token to http client
this.http.token = token;
// Load data
this.loadCoursesAfterLogin();
}
/**
* Load courses data after login.
*/
public loadCoursesAfterLogin()
{
this.http.post('/courses', {}).then(response =>
{
// Check success
if (response.success)
{
// Save courses
this.courses = response.data;
// Load assignments
this.loadAssignments();
}
else
{
// Show error message TODO: Show it properly
alert(response.data);
}
})
.catch(alert);
}
/**
* Load the assignments of the courses
*
* @param courses Courses Json
*/
public loadAssignments()
{
// Get assignments for all the courses
this.courses.forEach(course =>
{
// Send request to get assignments
this.http.post('/assignments', {id: course.assignmentsId}).then(response =>
{
// Check success
if (response.success)
{
// Load assignments
// Parse json and filter it
course.assignments = JsonUtils.filterAssignments(response.data);
}
else
{
// Show error message TODO: Show it properly
alert(response.data);
}
})
.catch(alert);
});
// Wait for assignments to be ready.
pWaitFor(() => this.isAssignmentsReady()).then(() =>
{
// When the assignments are ready
this.assignmentsReady = true;
});
}
/**
* Are assignments ready or not
*
* @returns boolean Ready or not
*/
private isAssignmentsReady(): boolean
{
for (const course of this.courses)
{
if (course.assignments == null) return false;
}
return true;
}
/**
* This is called when a navigation tab is clicked
*
* @param tab Tab name
*/
public onNavigate(tab: string)
{
// Debug output TODO: Remove this
console.log(tab);
// Update selected tab
this.selectedTab = tab;
}
}
+13
View File
@@ -0,0 +1,13 @@
<template>
<div id="app">
<login v-if="showLogin" v-on:login:token="onLogin" :http="http"></login>
<navigation :courses="courses" v-on:navigation:select="onNavigate"></navigation>
<div id="app-content">
<overall :courses="courses" v-if="selectedTab === 'overall' && assignmentsReady"></overall>
</div>
</div>
</template>
<script src="./app.ts" lang="ts"></script>
<style src="./app.scss" lang="scss"></style>
+99
View File
@@ -0,0 +1,99 @@
// Parent div for login
#login
{
}
// Parent overlay
.login-overlay
{
// Credit to w3schools.com:
// https://www.w3schools.com/howto/howto_js_fullscreen_overlay.asp
// Fill entire screen
height: 100%;
width: 100%;
left: 0;
top: 0;
// Stay in place
position: fixed;
// Sit on top layer
z-index: 1;
// Overlay color
background-color: rgba(0,0,0, 0.65);
// Disable horizontal scroll
overflow-x: hidden;
// Make it a table for vertical centering
display: table;
}
.login-vertical-center
{
// Vertically center
display: table-cell;
vertical-align: middle;
}
// The user interacting panel
.login-panel
{
// Make it smaller
width: 256px;
// Center
margin-left: auto;
margin-right: auto;
// Borders
padding: 15px;
border-radius: 10px;
// box-shadow: 0 0 20px 0 white;
border: 1px solid #DCDFE6;
// Make it white
background-color: white;
// Input bars
.el-input
{
margin: 5px 0;
}
// Button
.el-button
{
margin: 5px 0;
width: 100%;
}
}
// Error
.input-error
{
.el-input__inner
{
color: #ff3a3a6b !important;
border-color: #ff3a3a6b !important;
background-color: #ffdddd3b !important;
}
.el-input__inner:focus
{
background-color: white !important;
}
}
// Fix error message
.el-form-item__error.custom
{
padding-top: 0;
position: relative;
top: auto;
float: left;
}
+73
View File
@@ -0,0 +1,73 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {HttpUtils} from '@/utils/http-utils';
/**
* This component handles user login, and obtains data from the server.
*/
@Component({
components: {},
})
export default class Login extends Vue
{
public username: any = '';
public password: any = '';
public loading: boolean = false;
public error: String = '';
@Prop()
public http?: HttpUtils;
/**
* This is called when the instance is created.
*/
public created()
{
// Check login cookies
if (this.$cookies.isKey('va.token'))
{
// Already contains valid token / TODO: Validate
this.$emit('login:token', this.$cookies.get('va.token'));
}
}
/**
* On click, sends username and password to the server.
*/
public onLoginClick()
{
// Make login button loading
this.loading = true;
// Fetch request
(<HttpUtils> this.http).post('/login', {username: this.username, password: this.password})
.then(response =>
{
// Check success
if (response.success)
{
// Save token to cookies
this.$cookies.set('va.token', response.data, '7d');
// Call custom event with token
this.$emit('login:token', response.data);
}
else
{
// Show error message
this.error = response.data;
// Allow the user to retry
this.loading = false;
}
})
.catch(err =>
{
alert(err);
// Allow the user to retry
this.loading = false;
});
}
}
+29
View File
@@ -0,0 +1,29 @@
<template>
<div id="login" class="login-overlay">
<div class="login-vertical-center">
<div class="login-panel">
<img alt="Vue logo" src="../../assets/logo.png">
<h1>Veracross Analyzer</h1>
<el-input v-model="username"
placeholder="School Username"
:class="{'input-error': error !== ''}">
</el-input>
<el-input v-model="password"
placeholder="Veracross Password"
show-password=""
:class="{'input-error': error !== ''}">
</el-input>
<div class="el-form-item__error custom">{{error}}</div>
<el-button plain type="primary" @click="onLoginClick" :loading="loading">Login</el-button>
</div>
</div>
</div>
</template>
<script src="./login.ts" lang="ts"></script>
<style src="./login.scss" lang="scss"></style>
+17
View File
@@ -0,0 +1,17 @@
.el-menu.centered li
{
display: inline-block !important;
float: none !important;
}
// Borders
#navigation
{
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
ul
{
border-bottom-width: 0;
}
}
+30
View File
@@ -0,0 +1,30 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
/**
* This component is the top navigation bar
*/
@Component({
components: {},
})
export default class Navigation extends Vue
{
public activeIndex: string = 'overall';
@Prop() courses: any;
/**
* This function is called when the selection changes.
*
* @param index The index selected
* @param indexPath The path of the index
*/
public onSelect(index: string, indexPath: string)
{
// Update active index
this.activeIndex = index;
// Call custom event
this.$emit('navigation:select', this.activeIndex);
}
}
+20
View File
@@ -0,0 +1,20 @@
<template>
<div id="navigation">
<el-menu class="centered" :default-active="activeIndex" mode="horizontal" @select="onSelect">
<el-menu-item index="overall">Overall</el-menu-item>
<el-submenu index="courses">
<template slot="title">Courses</template>
<el-menu-item v-for="course in courses"
:index="`course-${course.name}`"
:key="course.name">{{course.name}}</el-menu-item>
</el-submenu>
</el-menu>
<div class="line"></div>
</div>
</template>
<script src="./navigation.ts" lang="ts"></script>
<style src="./navigation.scss" lang="scss"></style>
+18
View File
@@ -0,0 +1,18 @@
/**
* This class stores the static constants.
*/
export default class Constants
{
/**
* Base url for api access
* TODO: Use https for actual usage
*/
public static API_URL: string = 'https://va.hydev.org/api';
public static SPLASH: string =
'. , ,---. | \n' +
'| |. , |---|,---.,---.| , .,---,,---.,---.\n' +
' \\ / >< | || |,---|| | | .-\' |---\'| \n' +
' `\' \' ` ` \'` \'`---^`---\'`---|\'---\'`---\'` \n' +
' v1.1.0 `---\' '
}
+22
View File
@@ -0,0 +1,22 @@
import Vue from 'vue';
import ElementUI from 'element-ui';
const VCharts = require('v-charts');
import App from './components/app/app.vue';
import VueCookies from 'vue-cookies';
Vue.config.productionTip = false;
// Use Element UI
Vue.use(ElementUI, {locale: 'en-us'});
// Use VCharts
Vue.use(VCharts);
// Use Cookies
Vue.use(VueCookies);
// Init app
new Vue({
render: (h) => h(App),
}).$mount('#app');
@@ -0,0 +1,22 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
@Component({
})
export default class GraphOverall extends Vue
{
@Prop({required: true}) chart: any;
public chartData =
{
columns: ['日期', '访问用户', '下单用户', '下单率'],
rows: [
{ '日期': '1/1', '访问用户': 1393, '下单用户': 1093, '下单率': 0.32 },
{ '日期': '1/2', '访问用户': 3530, '下单用户': 3230, '下单率': 0.26 },
{ '日期': '1/3', '访问用户': 2923, '下单用户': 2623, '下单率': 0.76 },
{ '日期': '1/4', '访问用户': 1723, '下单用户': 1423, '下单率': 0.49 },
{ '日期': '1/5', '访问用户': 3792, '下单用户': 3492, '下单率': 0.323 },
{ '日期': '1/6', '访问用户': 4593, '下单用户': 4293, '下单率': 0.78 }
]
};
}
@@ -0,0 +1,8 @@
<template>
<div id="graph-overall">
<ve-line :data="chart" :extend="{series: {smooth: false}}"></ve-line>
</div>
</template>
<script src="./graph-overall.ts" lang="ts"></script>
<style src="./graph-overall.scss" lang="scss"></style>
+29
View File
@@ -0,0 +1,29 @@
// Add some margins
.el-card
{
margin: 10px;
height: 494px;
padding: 0;
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
}
.span-gpa-header
{
font-size: 14px;
}
.span-gpa
{
font-size: 35px;
font-family: 'Avenir', Helvetica, Arial, sans-serif;
}
.gpa-time
{
font-size: 14px;
}
+126
View File
@@ -0,0 +1,126 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import GraphOverall from '@/pages/overall/graph-overall/graph-overall';
import {Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils';
@Component({
components: {GraphOverall}
})
export default class Overall extends Vue
{
@Prop({required: true}) courses: any;
get convertCharts()
{
// Null case
if (this.courses == null) return [];
// Compute the column names
let columns = ['date'];
this.courses.forEach((course: Course) =>
{
// Ignore non-important courses
if (course.status != 'active') return;
columns.push(course.name);
});
// Find the min date
let minDate: Date = new Date();
this.courses.forEach((course: Course) =>
{
// Ignore non-important courses
if (course.status != 'active') return;
if (course.assignments.length == 0) return;
let date = new Date(course.assignments[course.assignments.length - 1].date);
if (date < minDate) minDate = date;
});
// Find the dates in between
let now = new Date();
let dates = [];
for (let date = minDate; date <= now; date.setDate(date.getDate() + 1))
{
dates.push(new Date(date));
}
// Initialize course specific variables
let courseScores: {[index: string]: any} = {};
let courseMaxScores: {[index: string]: any} = {};
let courseIndexes: {[index: string]: any} = {};
this.courses.forEach((course: Course) =>
{
// Ignore non-important courses
if (course.status != 'active') return;
courseScores[course.name] = 0;
courseMaxScores[course.name] = 0;
courseIndexes[course.name] = course.assignments.length - 1;
});
// Compute the rows data
let rows: {[index: string]: any}[] = [];
dates.forEach(date =>
{
// Define row object
let row: {[index: string]:any} = {'date': date.toLocaleDateString('en-US')};
// Loop through courses
this.courses.forEach((course: Course) =>
{
// Ignore non-important courses
if (course.status != 'active') return;
// Reversed loop through the assignments
for (let r = courseIndexes[course.name]; r >= 0; r--)
{
let assignment = course.assignments[r];
let assignmentDate = new Date(assignment.date);
// Date is being looked at
if (assignmentDate.getTime() == date.getTime())
{
// Record scores
courseScores[course.name] += assignment.score;
courseMaxScores[course.name] += assignment.scoreMax;
}
// Not now
else if (assignmentDate > date)
{
courseIndexes[course.name] = r;
break;
}
}
// Add average to the row
row[course.name] = courseScores[course.name] / courseMaxScores[course.name] * 100;
});
// Add it to the array
rows.push(row);
});
console.log(rows);
return {
columns: columns,
rows: rows
}
}
public getGPA()
{
let gpa = GPAUtils.getGPA(this.courses);
let result = '' + gpa.gpa;
/* Not accurate
if (!gpa.accurate)
{
result = `(${result})`;
}*/
return result;
}
}
+30
View File
@@ -0,0 +1,30 @@
<template>
<div id="overall">
<el-row>
<el-col :span="4">
<el-card style="margin-left: 20px">
<div style="padding: 14px;">
<span class="span-gpa-header">GPA:</span>
<br>
<span class="span-gpa">{{getGPA()}}</span>
<div class="bottom clearfix gpa-time">
<time class="time">{{ new Date().toDateString() }}</time>
<br>
<el-button type="text" class="button">Button</el-button>
</div>
</div>
</el-card>
</el-col>
<el-col :span="20">
<el-card style="margin-right: 20px">
<p>Your average score graph all time:</p>
<graph-overall :chart="convertCharts"></graph-overall>
</el-card>
</el-col>
</el-row>
<div class=""></div>
</div>
</template>
<script src="./overall.ts" lang="ts"></script>
<style src="./overall.scss" lang="scss"></style>
+13
View File
@@ -0,0 +1,13 @@
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
+4
View File
@@ -0,0 +1,4 @@
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
+101
View File
@@ -0,0 +1,101 @@
/**
* This is an utility class to calculate GPA.
*/
import {Course} from '@/components/app/app';
export class GPAUtils
{
// [[Min score, Letter grade, Base GPA], ...]
public static SCALE =
[
[96.5, 'A+', 4.00],
[92.5, 'A' , 3.75],
[89.5, 'A-', 3.50],
[86.5, 'B+', 3.25],
[82.5, 'B' , 3.00],
[79.5, 'B-', 2.75],
[76.5, 'C+', 2.50],
[72.5, 'C' , 2.25],
[70.5, 'C-', 2.00],
[69.5, 'D' , 1.00],
[0 , 'F' , 0.00]
];
// Keywords
public static MIN = 0;
public static LETTER = 1;
public static GPA = 2;
/**
* Calculate GPA for a list of couses
*
* @param coursesOriginal List of courses
*/
public static getGPA(coursesOriginal: Course[]): {gpa: number, accurate: boolean}
{
// Clone array
let courses: Course[] = [];
// Accurate or not
let accurate: boolean = true;
// Remove all courses that does not have a grade
coursesOriginal.forEach(course =>
{
if (course.numericGrade == null)
{
accurate = false;
}
else if (course.level != 'none')
{
courses.push(course);
}
});
// If no course have grade, return -1
if (courses.length == 0)
{
return {gpa: -1, accurate: false};
}
// Count total GPA
let totalGPA = 0;
courses.forEach(course =>
{
totalGPA += this.getGP(course);
});
// Get average GPA, round to two decimal places
let gpa = Math.round(totalGPA / courses.length * 100) / 100;
// Return results
return {gpa: gpa, accurate: accurate};
}
/**
* Calculate GPA for a course
*
* @param course Course
*/
public static getGP(course: Course): number
{
// Find the GPA for this course.
for (let scale of this.SCALE)
{
// Letter grades are the same
if (scale[this.LETTER] == course.letterGrade)
{
// Get grade and add it
let grade = <number> scale[this.GPA];
// Add scaleUp if not failed.
if (grade != 0) grade += course.scaleUp;
// That's it
return grade;
}
}
return -1;
}
}
+35
View File
@@ -0,0 +1,35 @@
import Constants from '@/constants';
export class HttpUtils
{
public token: string = '';
constructor (token: string)
{
this.token = token;
}
public post(node: string, body: any): Promise<any>
{
// Add token
if (this.token != '') body['token'] = this.token;
// Create promise
return new Promise<any>((resolve, reject) =>
{
// Fetch request
fetch(`${Constants.API_URL}${node}`, {method: 'POST', body: JSON.stringify(body)}).then(res =>
{
// Get response body text
res.text().then(text =>
{
// Parse response
let response = JSON.parse(text);
resolve(response);
})
.catch(reject)
})
.catch(reject)
});
}
}
+33
View File
@@ -0,0 +1,33 @@
import {Grade} from '@/components/app/app';
export default class JsonUtils
{
/**
* This method filters the information provided in an assignments json.
*
* @param assignments Assignments object
* @returns Grade[] Filtered assignment grade object list
*/
public static filterAssignments(assignments: any): Grade[]
{
let result: Grade[] = [];
assignments.assignments.forEach((assignment: any) =>
{
result.push(
{
type: assignment.assignment_type,
description: assignment.assignment_description,
date: assignment._date,
complete: assignment.complete_status,
include: assignment.include_in_calculated_grade == 1,
display: assignment.display_grade == 1,
scoreMax: assignment.maximum_score,
score: +assignment.raw_score
});
});
return result;
}
}
+39
View File
@@ -0,0 +1,39 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
+17
View File
@@ -0,0 +1,17 @@
{
"defaultSeverity": "warning",
"linterOptions": {
"exclude": [
"node_modules/**"
]
},
"rules": {
"indent": [true, "spaces", 4],
"curly": false,
"interface-name": false,
"no-consecutive-blank-lines": false,
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [true, "single"]
}
}
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
devServer: {
disableHostCheck: true,
}
}