Compare commits

...

1584 Commits

Author SHA1 Message Date
Hykilpikonna 97e6b9e42b Merge remote-tracking branch 'upstream/master' 2020-08-02 12:45:01 -04:00
Hykilpikonna 1e2da25d58 [O] Allow cookies to determine demo mode 2020-08-02 12:43:43 -04:00
Hykilpikonna 66ba3430fd [U] Release v0.5.6.1761 2020-08-01 20:25:07 -04:00
Hykilpikonna 1abbce4daa [O] Lock submission button when in demo mode 2020-08-01 20:23:14 -04:00
Hykilpikonna d8430a0885 [F] Fix buttons locked when rating submission failed 2020-08-01 20:22:48 -04:00
Hykilpikonna c6054648d3 [S] Style page not available message 2020-08-01 20:22:18 -04:00
Hykilpikonna 74d3183da3 [+] Display page not available for course-selection in demo mode 2020-08-01 20:22:09 -04:00
Hykilpikonna cc9a35355d [S] Fix all unassigned font issues 2020-08-01 20:21:37 -04:00
Hykilpikonna 90e4e334c4 [S] Fix the align of demo text 2020-08-01 20:21:19 -04:00
Hykilpikonna b51ec78ff5 Merge remote-tracking branch 'upstream/master' 2020-08-01 19:47:30 -04:00
Hykilpikonna 8ef9b152f0 [+] Add demo notification 2020-08-01 19:45:47 -04:00
Hykilpikonna 08b8b31e47 [F] Deploy under personal account rather than organization 2020-08-01 19:24:12 -04:00
Hykilpikonna 1bec167be6 [+] Separate demo cname record 2020-08-01 17:57:35 -04:00
Hykilpikonna 641778b169 [O] Optimize code length 2020-08-01 16:19:17 -04:00
Hykilpikonna 73a651f3aa [F] Let bubble chart start from the selected term if a specific term is selected 2020-08-01 16:17:35 -04:00
Hykilpikonna e84911c25d [F] Only display one quarter if a specific quarter is selected 2020-08-01 16:14:57 -04:00
Hykilpikonna 467e036411 [O] Let bubble chart start at when the first quarter starts 2020-08-01 16:14:02 -04:00
Hykilpikonna c643eedbc8 [F] Let bubble chart stop at when the last quarter ends 2020-08-01 16:13:33 -04:00
Hykilpikonna 542ab0a286 [+] Show ratings by default 2020-08-01 16:05:20 -04:00
Hykilpikonna d31173fb9d [F] Fix gradedCourses null 2020-08-01 16:00:22 -04:00
Hykilpikonna a8b49f713b Revert "[O] Make gradedCourses a getter instead of a field"
This reverts commit cc046010ff.
2020-08-01 15:58:49 -04:00
Hykilpikonna c65a6fb7da [+] Load demo 2020-08-01 15:58:40 -04:00
Hykilpikonna 17808a3c1a [+] Create demo loader 2020-08-01 15:58:21 -04:00
Hykilpikonna cc046010ff [O] Make gradedCourses a getter instead of a field 2020-08-01 15:49:27 -04:00
Hykilpikonna 0c5b993f20 [+] Encapsulate method for http get 2020-08-01 15:48:58 -04:00
Hykilpikonna 1c63f795f4 [+] Show login only if not in demo mode 2020-08-01 14:25:31 -04:00
Hykilpikonna ba14fc80a9 [+] Detect demo mode 2020-08-01 14:23:14 -04:00
Hykilpikonna 6015c27e1b [-] Remove windows run script 2020-08-01 14:02:50 -04:00
Hykilpikonna f4ae9f4a8c [-] Remove gitattributes 2020-08-01 14:02:03 -04:00
Hykilpikonna dad1cb0c3c [O] Convert line endings again 2020-08-01 13:59:17 -04:00
Hykilpikonna 608c7f4613 Merge branch 'master' of https://github.com/HyDevelop/VeracrossAnalyzer.Client 2020-08-01 13:48:41 -04:00
Hykilpikonna 991153997b [U] npm update 2020-08-01 13:48:39 -04:00
Hykilpikonna e8bc3e695b [O] Force LF line ending 2020-08-01 13:46:49 -04:00
Hykilpikonna 98fabf382c [+] Add token data to demo-data 2020-08-01 13:42:24 -04:00
Hykilpikonna 833eec4833 [+] Move backup data to demo-data 2020-08-01 13:40:44 -04:00
Hykilpikonna 7aa258bc97 [PR] Merge pull request #6 from HyDevelop/dependabot/npm_and_yarn/elliptic-6.5.3
Bump elliptic from 6.5.2 to 6.5.3
2020-07-31 16:52:33 -04:00
dependabot[bot] a4b6c50c0e Bump elliptic from 6.5.2 to 6.5.3
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-31 20:51:33 +00:00
Vanilla 47deca8859 Merge pull request #5 from HyDevelop/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-18 19:09:02 +08:00
dependabot[bot] ca01ee743b Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-18 08:46:31 +00:00
Vanilla 27ca1d8bfe Merge pull request #4 from HyDevelop/dependabot/npm_and_yarn/websocket-extensions-0.1.4
Bump websocket-extensions from 0.1.3 to 0.1.4
2020-06-07 19:41:42 +08:00
dependabot[bot] 05a6abc1ba Bump websocket-extensions from 0.1.3 to 0.1.4
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-07 07:51:46 +00:00
Hykilpikonna 29ba8509bc [+] Upload backup data 2020-06-06 13:38:28 -04:00
Hykilpikonna a290a3d93e [F] Fix final assignment compatibility 2020-06-06 13:37:30 -04:00
Hykilpikonna 4fe83d732a [F] Fix a login bug 2020-05-26 09:18:25 -04:00
Hykilpikonna 5f7a564b33 [+] Add check for blank usernames 2020-05-25 21:33:15 -04:00
Hykilpikonna 0de22d4f0d [O] Unify show loading 2020-05-25 21:32:05 -04:00
Hykilpikonna 15149d1d07 [O] Fix field name mismatch 2020-05-25 21:28:41 -04:00
Hykilpikonna 5b54fc3b27 [F] Use first name instead of nickname 2020-05-25 21:24:28 -04:00
Hykilpikonna beed3883a8 [-] Remove courses request in app.ts 2020-05-25 21:23:28 -04:00
Hykilpikonna 254c2690e5 [+] Implement new user model 2020-05-25 21:21:58 -04:00
Hykilpikonna 2839304dc5 [F] Fix cookie keep duration 2020-05-25 21:15:40 -04:00
Hykilpikonna 48b4b989b1 [O] Combine onEnter with loginClick 2020-05-25 21:15:17 -04:00
Hykilpikonna 96306afecf [-] Remove maintenance check since it's badly written 2020-05-25 21:11:51 -04:00
Hykilpikonna d267988b55 [O] Combine login into one function 2020-05-25 21:11:27 -04:00
Hykilpikonna 5780a6fc25 [S] Add margin for multiple comments 2020-05-08 20:08:47 -04:00
Hykilpikonna 28eddf4aea [+] Display the rating that the commentor gave 2020-05-08 20:08:35 -04:00
Hykilpikonna d8a7a700c4 [S] Add comments header 2020-05-08 20:07:47 -04:00
Hykilpikonna fc6b3331ac [S] Add a icon for user 2020-05-08 20:07:29 -04:00
Hykilpikonna 2210e6389f [S] Make blolckquote look like a md blockquote 2020-05-08 20:07:13 -04:00
Hykilpikonna ebf692e6a3 [+] Display comment text in blockquote form 2020-05-08 20:04:33 -04:00
Hykilpikonna 5422c1c45f [+] Display comments users 2020-05-08 20:04:12 -04:00
Hykilpikonna f5c63aa958 [O] Obtain comments 2020-05-08 20:00:54 -04:00
Hykilpikonna 4b0bf16916 [+] Create detailsComments field 2020-05-08 20:00:42 -04:00
Hykilpikonna b8a5172d70 [+] Calculate average rating in CourseInfoRating 2020-05-08 20:00:19 -04:00
Hykilpikonna c4735e5603 [+] Split username 2020-05-08 19:59:58 -04:00
Hykilpikonna e601f6b57a [F] Fix rating display rounding issue 2020-05-08 18:20:11 -04:00
Hykilpikonna 272e7e5b98 [+] Add comment to scroll down to find submit button 2020-04-29 11:38:15 -04:00
Hykilpikonna 5304c77548 [O] Don't hide the course-selection tab for seniors 2020-04-29 11:37:43 -04:00
Hykilpikonna 2e57869c5f [F] Fix problem where the ratings are not loading when a course details page is opened after another 2020-04-29 11:37:26 -04:00
Hykilpikonna cde51445a1 [O] Don't block seniors from seeing course ratings 2020-04-29 11:36:48 -04:00
Hykilpikonna 9b144b58bb [O] Enable show all courses by default for seniors 2020-04-29 11:36:00 -04:00
Hykilpikonna 1796bf8fb8 [+] Implement show updates command 2020-04-29 11:35:14 -04:00
Hykilpikonna c587cf7953 [+] Auto detect update notification on load 2020-04-29 11:34:56 -04:00
Hykilpikonna 922e3911d8 [+] Add updates button on avatar menu 2020-04-29 11:34:27 -04:00
Hykilpikonna aadbaf0f75 [+] Create method to show update message 2020-04-29 11:33:55 -04:00
Hykilpikonna 4b95053651 [S] Create comic sans class 2020-04-29 11:33:47 -04:00
Hykilpikonna f66aaa09b0 [F] Forgot to import 2020-04-27 21:57:47 -04:00
Hykilpikonna f7b352f595 [+] Add notification for the last rating 2020-04-27 21:57:25 -04:00
Hykilpikonna 3cfb888a5f [F] Fix error message when closing course details 2020-04-27 21:09:17 -04:00
Hykilpikonna d9d0ea3168 [+] Add todo for comments display 2020-04-27 18:42:14 -04:00
Hykilpikonna 408d62c09d [S] Unify numeric rating looks 2020-04-27 18:25:17 -04:00
Hykilpikonna a4c61f3dd9 [+] Display numeric ratings too 2020-04-27 18:25:05 -04:00
Hykilpikonna f3321ff267 [S] Make criteria title font size larger 2020-04-27 18:18:37 -04:00
Hykilpikonna 2ef242099b [S] Reduce margin from subtitle to ratings 2020-04-27 18:18:22 -04:00
Hykilpikonna 3497c277e3 [S] Specify height for the float boxes 2020-04-27 18:17:57 -04:00
Hykilpikonna 74c47b8dd9 [S] Change "rating details" to "ratings" 2020-04-27 18:17:16 -04:00
Hykilpikonna c860ffd315 [S] Adjust margin under title 2020-04-27 18:16:37 -04:00
Hykilpikonna 1b13f4abb2 [S] Copy style from course-head 2020-04-27 18:16:07 -04:00
Hykilpikonna a8c882e343 [+] Display rating stars 2020-04-27 18:15:22 -04:00
Hykilpikonna 99c51bb205 [+] Open details on click 2020-04-27 18:15:13 -04:00
Hykilpikonna 142e0da7c0 [+] Encapsulate openDetails() 2020-04-27 18:14:58 -04:00
Hykilpikonna 226297c810 [+] Add details/comments popup for course-detail 2020-04-27 18:14:29 -04:00
Hykilpikonna 13167fe050 [O] Separate rating criteria 2020-04-27 18:13:56 -04:00
Hykilpikonna 9665b3a793 [S] Adjust numeric rating margins 2020-04-27 17:24:17 -04:00
Hykilpikonna 95111476f5 [+] Display rating count 2020-04-27 17:23:50 -04:00
Hykilpikonna fcfdd248b6 [+] Display numeric rating out of 5 2020-04-27 17:21:30 -04:00
Hykilpikonna df792a57c8 [+] Display star rating in course-detail 2020-04-27 17:17:21 -04:00
Hykilpikonna 41e68d070d [S] Fix loading bar positioning on full screen 2020-04-27 17:16:53 -04:00
Hykilpikonna 42231c79d9 [+] Calclate ratingAverages and overallRating 2020-04-27 17:16:27 -04:00
Hykilpikonna 41cc66a9f4 [O] Add comments to fields 2020-04-27 17:16:14 -04:00
Hykilpikonna 71dcf9e8c1 [O] Make AnalyzedRating a class 2020-04-27 17:16:01 -04:00
Hykilpikonna 38232c3182 [+] Create star rating component 2020-04-27 16:09:08 -04:00
Hykilpikonna 13288c6620 [+] Import star rating sprite 2020-04-27 16:08:48 -04:00
Hykilpikonna 11b855109a [O] Fix tslint quotation marks 2020-04-27 15:55:00 -04:00
Hykilpikonna 4110b91b45 [M] Move loading-spinner from pages to components 2020-04-27 15:46:43 -04:00
Hykilpikonna c90c50a4b6 [F] Forgot to import component 2020-04-27 05:12:53 -04:00
Hykilpikonna ef5322ebd5 [S] Vertically center loading spinner 2020-04-27 05:12:38 -04:00
Hykilpikonna e82ae7cb88 [+] Show loading spinner when loading ratings 2020-04-27 05:12:17 -04:00
Hykilpikonna 0726783465 [+] Split course-detail items into float-left and float-right 2020-04-27 05:11:28 -04:00
Hykilpikonna 8a7007c7b7 [U] Use LoadingSpinner 2020-04-27 05:10:52 -04:00
Hykilpikonna 606732c987 [+] Add centered property to loading spinner 2020-04-27 05:08:45 -04:00
Hykilpikonna b664674a06 [+] Create a loading spinner component 2020-04-27 05:04:10 -04:00
Hykilpikonna 9b201d8475 [+] Add error message on fail 2020-04-27 04:45:09 -04:00
Hykilpikonna 66d553f6a7 [+] Load rating 2020-04-27 04:43:21 -04:00
Hykilpikonna 94a1a0f108 [+] Use AnalyzedRating for courseInfo 2020-04-27 04:43:03 -04:00
Hykilpikonna e3af901caf [+] Create AnalyzedRating class 2020-04-27 04:42:41 -04:00
Hykilpikonna ad5f5c3e39 [+] Update loading screen when finished loading 2020-04-27 04:26:46 -04:00
Hykilpikonna ddc6aacaf3 [+] Create loading screen for course-selection 2020-04-27 04:26:17 -04:00
Hykilpikonna a88164319b [O] Fix grammar issue 2020-04-27 04:14:51 -04:00
Hykilpikonna 93aeab2c01 [+] Display error message if not all criterias are rated 2020-04-27 04:14:26 -04:00
Hykilpikonna 0be4bc6cb4 [F] Fix issue where rating wouldn't reset 2020-04-27 04:14:09 -04:00
Hykilpikonna d12984cb3a [O] Disable button when rating is posting 2020-04-27 04:13:53 -04:00
Hykilpikonna 2fc8986bd8 [O] Optimize language 2020-04-27 03:45:54 -04:00
Hykilpikonna f8b8588413 [O] Shorten the message 2020-04-27 03:45:09 -04:00
Hykilpikonna 3519ca6018 [F] Fix execution order 2020-04-27 03:44:18 -04:00
Hykilpikonna cffc39dbfd [O] Use filter().length instead of map().reduce() 2020-04-27 03:42:41 -04:00
Hykilpikonna c75dc76526 [U] Add a comment about that ↓ 2020-04-27 03:40:49 -04:00
Hykilpikonna e6d5e35ff0 [F] Updating the first review shouldn't count as first review 2020-04-27 03:40:24 -04:00
Hykilpikonna cb05b8be96 [+] Use showRating in course-head 2020-04-27 03:26:01 -04:00
Hykilpikonna 8735237626 [+] Add default case 2020-04-27 03:25:42 -04:00
Hykilpikonna 67a9dcc37f [+] Implement switch rating 2020-04-27 03:25:06 -04:00
Hykilpikonna 18825670e4 [+] Add showRating field in App 2020-04-27 03:24:51 -04:00
Hykilpikonna 17dc6045b0 [+] Add rating buttons toggler in dropdown 2020-04-27 03:24:27 -04:00
Hykilpikonna c8ec7893e1 [-] Remove unnecessary isDark() 2020-04-27 03:24:08 -04:00
Hykilpikonna 837fda814b [O] Remove unnecessary line of initialization 2020-04-27 03:21:25 -04:00
Hykilpikonna e306b91e37 [S] Add darkmode colors to rating blocks 2020-04-27 03:20:51 -04:00
Hykilpikonna 50377cd9ee [+] Add message for first rating 2020-04-27 03:01:00 -04:00
Hykilpikonna 969336f203 [+] Change "Submit" to "Update" if rated 2020-04-27 02:53:41 -04:00
Hykilpikonna ae14eae711 [S] Specfy rated button color 2020-04-27 02:53:26 -04:00
Hykilpikonna 5603831f5e [+] Allow changing rating 2020-04-27 02:52:45 -04:00
Hykilpikonna 760cfe2463 [S] Make navbar margins look nicer 2020-04-27 02:52:18 -04:00
Hykilpikonna 509243f874 [O] Use CourseInfoRating in course-head 2020-04-27 02:23:55 -04:00
Hykilpikonna 311544b5aa [F] Fix anonymous default open 2020-04-27 02:23:33 -04:00
Hykilpikonna 1cf9ff157a [+] Parse rating when parsing course 2020-04-27 02:19:55 -04:00
Hykilpikonna 8e54749e2e [+] Create alternative constructor for posting 2020-04-27 02:19:33 -04:00
Hykilpikonna 9adc78f287 [+] Create constructor for CourseInfoRating 2020-04-27 02:19:20 -04:00
Hykilpikonna 6309a77b63 [+] Create CourseInfoRating class 2020-04-27 02:19:06 -04:00
Hykilpikonna 1eb8b5c137 [-] Remove annoying width calculations 2020-04-27 02:05:31 -04:00
Hykilpikonna e78c5c8cef [+] Implement submitRating 2020-04-27 02:02:54 -04:00
Hykilpikonna 01662cfa8d [S] Adjust popup top position 2020-04-27 01:59:49 -04:00
Hykilpikonna 1bda3ccd53 [S] Adjsut textarea margins 2020-04-27 01:59:19 -04:00
Hykilpikonna d9896f0b48 [+] Add checkbox for anonymous 2020-04-27 01:59:07 -04:00
Hykilpikonna ac13da1dc6 [+] Add textarea for comment 2020-04-27 01:58:46 -04:00
Hykilpikonna 20988fb35e [S] Fix rated course left padding 2020-04-27 01:58:04 -04:00
Hykilpikonna 5e6c0853c1 [S] Further reduce margins 2020-04-26 20:16:03 -04:00
Hykilpikonna 7a467d6346 [S] Add some margins to subtitle 2020-04-26 20:15:32 -04:00
Hykilpikonna 505953753c [S] Fix header overflow 2020-04-26 20:15:15 -04:00
Hykilpikonna e4ddd12b7b [S] Make subtitle italic 2020-04-26 20:15:01 -04:00
Hykilpikonna e1decbf7c2 [O] Separate popup header to a separate div 2020-04-26 20:14:13 -04:00
Hykilpikonna cdd1712b85 [S] Colorize title too 2020-04-26 20:13:43 -04:00
Hykilpikonna 356259f0ec [S] Give stars a golden color 2020-04-26 20:13:28 -04:00
Hykilpikonna 7928fe6598 [S] Make stars larger 2020-04-26 20:13:09 -04:00
Hykilpikonna bcc8c8492f [S] Set font size for description 2020-04-26 20:12:56 -04:00
Hykilpikonna d26f6618ec [S] Make title larger 2020-04-26 20:12:30 -04:00
Hykilpikonna af919e77e7 [S] Auto wrap text 2020-04-26 20:12:19 -04:00
Hykilpikonna c0aa07f736 [S] Reduce top margin 2020-04-26 20:12:05 -04:00
Hykilpikonna ae3e5c5092 [S] Separate items with margin 2020-04-26 20:03:28 -04:00
Hykilpikonna a2665d12f6 [S] Left-align text 2020-04-26 20:01:45 -04:00
Hykilpikonna 00edf57ebc [O] Give the rating popup an id 2020-04-26 18:57:10 -04:00
Hykilpikonna f1bd6799a7 [O] Change "Confirm" to "Submit" 2020-04-26 18:46:11 -04:00
Hykilpikonna 4b12b44f8b [F] Fix UI upate issue after changing stars 2020-04-26 18:45:58 -04:00
Hykilpikonna f9fc840c3c [+] Implement change stars on click 2020-04-26 18:45:43 -04:00
Hykilpikonna bfe3c62db7 [O] Prevent accidental closing 2020-04-26 18:39:55 -04:00
Hykilpikonna aa7cc12876 [S] Make popup window not clickable 2020-04-26 18:38:28 -04:00
Hykilpikonna 9a2476b095 [+] Display stars 2020-04-26 18:36:57 -04:00
Hykilpikonna 297fa9a4c6 [+] Display rating criteria 2020-04-26 18:36:48 -04:00
Hykilpikonna 6fbe0b2d40 [+] Create rating data 2020-04-26 18:36:33 -04:00
Hykilpikonna cae401ce55 [+] Create rating criteria 2020-04-26 18:36:24 -04:00
Hykilpikonna 8874888846 [S] Optimize padding box 2020-04-26 16:19:03 -04:00
Hykilpikonna 1f5a27a425 [S] Width calculation 2020-04-26 16:18:36 -04:00
Hykilpikonna 81a686b2ec [S] Specify width for rating button 2020-04-26 16:14:00 -04:00
Hykilpikonna 19dd5b8d00 [S] Align content box 2020-04-26 16:13:48 -04:00
Hykilpikonna 351b6da4d1 [+] Separate content with rate button for @click 2020-04-26 16:13:38 -04:00
Hykilpikonna 078b36eea6 [+] Create rating dialog 2020-04-26 16:13:20 -04:00
Hykilpikonna f003f0d48c [O] Don't display rate button on course detail page 2020-04-26 15:55:58 -04:00
Hykilpikonna 616f0a7420 [S] Add left shadow (inset) 2020-04-26 15:52:22 -04:00
Hykilpikonna 208d816c64 [S] Add paddings 2020-04-26 15:52:06 -04:00
Hykilpikonna 43cb9e384f [S] Align block height and relative position to match course-head 2020-04-26 15:51:55 -04:00
Hykilpikonna f28bd1851a [S] Add left margins 2020-04-26 15:51:21 -04:00
Hykilpikonna 4807a6d503 [S] Round corners 2020-04-26 15:50:29 -04:00
Hykilpikonna 2e8e4b330f [S] Add background color to the button 2020-04-26 15:50:22 -04:00
Hykilpikonna ff433f2fec [S] Align rating button to the right 2020-04-26 15:50:02 -04:00
Hykilpikonna 0f92254402 [+] Create rating button 2020-04-26 15:49:16 -04:00
Hykilpikonna 230b69356c [+] Encapsulate displayRate() 2020-04-26 15:45:35 -04:00
Hykilpikonna 30f1600063 [+] Display classes in course-detail 2020-04-26 15:03:57 -04:00
Hykilpikonna f5beddd68e [+] Add rated field to course 2020-04-26 15:03:40 -04:00
Hykilpikonna c66a3b5b11 [+] Move level detection to server side 2020-04-26 14:46:48 -04:00
Hykilpikonna 0fd4d31d6b [+] Encapsulate getLevel() 2020-04-26 14:46:28 -04:00
Hykilpikonna 86f9008804 [+] Add some more level constants 2020-04-26 14:46:18 -04:00
Hykilpikonna 380fe19a20 [-] Remove detectLevel() 2020-04-26 14:46:05 -04:00
Hykilpikonna 9e6eb3c71e [+] Display course enrollments 2020-04-20 18:20:59 -04:00
Hykilpikonna 5ea2fcf592 [+] Implement level filtering 2020-04-20 18:16:08 -04:00
Hykilpikonna 7a5bf96916 [S] Apply margins to the checkboxes 2020-04-20 18:15:55 -04:00
Hykilpikonna cb45759d5e [+] Add level selector checkbox 2020-04-20 18:15:41 -04:00
Hykilpikonna 2ce6cb9d0b [O] Sort by levelID instead of name 2020-04-20 18:02:58 -04:00
Hykilpikonna b6ddfba700 [+] Add levelID field to CourseInfo 2020-04-20 18:02:43 -04:00
Hykilpikonna 22d9e278c5 [O] Sort courses by name 2020-04-20 18:01:41 -04:00
Hykilpikonna ee06f557dc [S] Make course info items look nicer 2020-04-20 18:01:19 -04:00
Hykilpikonna 11b6455c00 [+] Display course info items 2020-04-20 18:01:01 -04:00
Hykilpikonna 6cbbfd9b46 [F] Null cases 2020-04-20 18:00:15 -04:00
Hykilpikonna 1d31bfb5ae [+] Add levelFull field to CourseInfo 2020-04-20 18:00:09 -04:00
Hykilpikonna 1d6db35c5c [+] Encapsulate getLevelFullName() 2020-04-20 17:59:42 -04:00
Hykilpikonna 6412482c06 [+] Encapsulate getLevelID() 2020-04-20 17:59:24 -04:00
Hykilpikonna cc039655ae [+] Encapsulate isNumeric() 2020-04-20 17:59:09 -04:00
Hykilpikonna fef4612122 [F] Fix cannot switch back to course if closed 2020-04-20 17:58:50 -04:00
Hykilpikonna 4e7c458b7f [S] Make course item clickable and unselectable 2020-04-20 17:58:24 -04:00
Hykilpikonna dbb51e50bd [S] Use ellipsis if header is too long 2020-04-20 17:57:41 -04:00
Hykilpikonna ab5caf9701 [+] Show course name 2020-04-20 17:57:16 -04:00
Hykilpikonna 0aeeb2a933 [+] Implement openCourse on click 2020-04-20 17:08:12 -04:00
Hykilpikonna 4c8b7e6ad0 [O] Pass in unique course instead of course info 2020-04-20 17:07:54 -04:00
Hykilpikonna c3c9e2c175 [+] Import course-detail page into course-selection 2020-04-20 16:57:41 -04:00
Hykilpikonna d821be41df [+] Add courseInfo property to course-detail page 2020-04-20 16:57:05 -04:00
Hykilpikonna 103a7a2fa4 [+] Create course detail component 2020-04-20 16:53:32 -04:00
Hykilpikonna f17122d1ca [S] Justify text 2020-04-20 16:51:04 -04:00
Hykilpikonna 131027d1d9 [+] Add notation documentation in welcome screen 2020-04-20 16:50:56 -04:00
Hykilpikonna be0851cdd1 [+] Write better welcome message 2020-04-20 16:50:30 -04:00
Hykilpikonna 8a430dccc4 [S] Make header margin look more aligned with the search bar on the right 2020-04-20 15:31:39 -04:00
Hykilpikonna 79208f811a [+] Display welcome if no page is open 2020-04-20 15:30:59 -04:00
Hykilpikonna 14884d0111 [M] Move implementations too 2020-04-20 15:30:45 -04:00
Hykilpikonna ed727a7f26 [M] Move welcome message to welcome component 2020-04-20 15:25:01 -04:00
Hykilpikonna 10d25ff091 [O] Separate a universal css for course selection pages 2020-04-20 15:21:27 -04:00
Hykilpikonna 587f1d4a93 [+] Create welcome component for course-selection 2020-04-20 15:19:13 -04:00
Hykilpikonna 63612f4474 [S] Reduce radio margins 2020-04-20 15:17:29 -04:00
Hykilpikonna 5e67b1a08f [S] Make radio buttons look nicer 2020-04-20 15:17:18 -04:00
Hykilpikonna 8e4557af18 [+] Implement sort by popularity 2020-04-20 14:19:00 -04:00
Hykilpikonna cc4cbe0b28 [S] Make margins look better 2020-04-20 14:18:35 -04:00
Hykilpikonna f6f009083f [+] Add sort by settings 2020-04-20 14:18:23 -04:00
Hykilpikonna 2744eb97b6 [+] Implement showAllCourses in filtering 2020-04-20 13:23:34 -04:00
Hykilpikonna 3691f16d8c [+] Sync search settings as a param 2020-04-20 13:22:54 -04:00
Hykilpikonna c0d23770b5 [+] Create separate class for SearchSettings 2020-04-20 13:22:21 -04:00
Hykilpikonna 2fb69a5992 [+] Add getter to get setting as object 2020-04-20 13:12:23 -04:00
Hykilpikonna 52e664dd18 [+] Implement openSettings() 2020-04-20 13:12:10 -04:00
Hykilpikonna d923b6ea02 [S] Left align settings 2020-04-20 13:07:38 -04:00
Hykilpikonna f153cb3fff [S] Unify the margins of the divider 2020-04-20 13:07:25 -04:00
Hykilpikonna 2cff73862d [+] Add divider between settingsheader and content 2020-04-20 13:07:08 -04:00
Hykilpikonna 316ea5428e [+] Add showAllCourses option 2020-04-20 13:06:43 -04:00
Hykilpikonna 45e397b6c4 [+] Display teacher count in course data 2020-04-19 19:53:43 -04:00
Hykilpikonna 74148e3782 [+] Import SearchSettings 2020-04-19 19:53:27 -04:00
Hykilpikonna 91f50946b5 [S] Style the header to match the course list header 2020-04-19 19:52:27 -04:00
Hykilpikonna 83fc54fcda [+] Add settings header 2020-04-19 19:52:13 -04:00
Hykilpikonna d1cfc69b5c [+] Create SearchSettings vue 2020-04-19 19:52:01 -04:00
Hykilpikonna 012e2d5aea [F] Fix upper case searching issue 2020-04-19 19:39:47 -04:00
Hykilpikonna 0a5f7d3be2 [+] Encapsulate getter classes() 2020-04-19 19:34:19 -04:00
Hykilpikonna eff37aac03 [O] Make UniqueCourse a class 2020-04-19 19:34:03 -04:00
Hykilpikonna 4e23bfb507 [F] Fix null pointer caused by initialization 2020-04-19 19:29:57 -04:00
Hykilpikonna d1b167c002 [+] Map classinfo to courseinfo 2020-04-19 19:27:55 -04:00
Hykilpikonna 0b51713d95 [+] Parse classInfos 2020-04-19 19:27:38 -04:00
Hykilpikonna 0306585cf8 [+] Create courseInfo class 2020-04-19 19:18:30 -04:00
Hykilpikonna fce32881e3 [M] Separate ts file for course-selection 2020-04-19 18:48:57 -04:00
Hykilpikonna bb79ed6e92 [S] Add space between icon and text 2020-04-19 16:56:18 -04:00
Hykilpikonna 4f44423239 [M] Rename 'Descriptions' to 'Data' 2020-04-19 16:56:01 -04:00
Hykilpikonna d5f01c8ab0 [S] Reduce font size for description 2020-04-19 16:55:19 -04:00
Hykilpikonna 276f9651a1 [S] Switch to left align 2020-04-19 16:55:08 -04:00
Hykilpikonna 39b1fad44e [S] Make items' buttom margin larger 2020-04-19 16:53:19 -04:00
Hykilpikonna 237dd45cde [S] Align the icons by using left align 2020-04-19 16:50:18 -04:00
Hykilpikonna e4b6494046 [S] Align the widths 2020-04-19 16:50:06 -04:00
Hykilpikonna 2300cf6bf0 [+] Add search settings button 2020-04-19 16:49:51 -04:00
Hykilpikonna 6fb2d6a5f5 [+] Display how many class a course opens 2020-04-19 16:48:31 -04:00
Hykilpikonna 0a5cd155e2 [S] Further dim the color 2020-04-19 16:47:52 -04:00
Hykilpikonna 9b3d30959d [F] Fix enrollments not counting correctly 2020-04-19 16:28:37 -04:00
Hykilpikonna b8339a4e4c [O] Wrap enrollement info in a span 2020-04-19 16:25:15 -04:00
Hykilpikonna ebc3dfb75b [O] Right align discriptions 2020-04-19 16:24:11 -04:00
Hykilpikonna 1293967512 [S] Add icon to enrollments 2020-04-19 16:20:05 -04:00
Hykilpikonna f0abfa16ed [+] Display enrollments 2020-04-19 16:19:41 -04:00
Hykilpikonna f1885509d8 [S] Replace definite height with padding 2020-04-19 16:17:07 -04:00
Hykilpikonna cbfad69d22 [O] Fix jslint quotation marks 2020-04-19 16:14:44 -04:00
Hykilpikonna 533d788b6a [M] Move course-selection css to new file 2020-04-19 16:14:20 -04:00
Hykilpikonna 48d1931368 [+] Sum up total enrollments when counting course 2020-04-14 23:19:10 -04:00
Hykilpikonna 808e8a5708 [+] Add enrollments field to UniqueCourse 2020-04-14 23:18:50 -04:00
Hykilpikonna 396edfef41 [+] Count enrollments when parsing data 2020-04-14 23:18:32 -04:00
Hykilpikonna 8cad524217 [+] Add enrollment field to CourseInfo 2020-04-14 23:18:17 -04:00
Hykilpikonna e377f678c8 [-] Remove debug logging 2020-04-12 16:30:05 -04:00
Hykilpikonna bdaca5aeda [+] Sort courses by name 2020-04-12 16:29:54 -04:00
Hykilpikonna 7ca8554d7e [F] Not unescape url but unescape html 2020-04-12 16:24:48 -04:00
Hykilpikonna fda91fbfe3 Revert "[O] Unescape course name"
This reverts commit 2a4a54d60b.
2020-04-12 16:23:33 -04:00
Hykilpikonna 259d4c3474 [O] Replace more in course names 2020-04-12 16:21:50 -04:00
Hykilpikonna 2a4a54d60b [O] Unescape course name 2020-04-12 16:21:29 -04:00
Hykilpikonna 6d55ae8180 [O] Filter out courses that are unavailable for a grade level 2020-04-12 16:21:15 -04:00
Hykilpikonna deda2a194e [+] Map grade levels to course infos 2020-04-12 16:20:58 -04:00
Hykilpikonna 7b1078dad2 [+] Index courseIds 2020-04-12 16:20:20 -04:00
Hykilpikonna 70a46c0782 [O] Parse courseIDs 2020-04-12 16:19:52 -04:00
Hykilpikonna 3f48a97668 [+] Create gradeLevels field in CourseInfo 2020-04-12 15:54:24 -04:00
Hykilpikonna 5391ca7137 [-] Remove debug logging 2020-04-12 15:54:00 -04:00
Hykilpikonna 80d463aba8 [O] Specify data type for directory 2020-04-12 15:53:52 -04:00
Hykilpikonna 3e3ab4fdab [O] Combine course info and directory 2020-04-12 15:53:37 -04:00
Hykilpikonna 97ca5c5443 [O] Provide a more customized welcome message 2020-04-12 15:44:47 -04:00
Hykilpikonna 9cd3bbbd48 [+] Add gradeLevelName field to user 2020-04-12 15:40:20 -04:00
Hykilpikonna d092ef2972 [U] Use uniqueName in course filtering 2020-04-12 15:38:41 -04:00
Hykilpikonna b6182c3466 [+] Parse unique-name by replacing level 2020-04-12 15:38:19 -04:00
Hykilpikonna 902cb66cc4 [+] Add unique name to course-info 2020-04-12 15:38:02 -04:00
Hykilpikonna bf690a941c [+] Create method to get grade level's name 2020-04-12 15:36:58 -04:00
Hykilpikonna bc5a679bb6 [+] Calculate height for cards 2020-04-12 15:26:37 -04:00
Hykilpikonna 2a3109577c [S] Dynamically update height 2020-04-12 15:17:40 -04:00
Hykilpikonna 5631ea2ac3 [O] Filter more levels 2020-04-12 15:05:09 -04:00
Hykilpikonna b84dd14ced [+] Create filter for unique courses 2020-04-12 15:04:59 -04:00
Hykilpikonna 2899f6836b [+] Create UniqueCourse interface 2020-04-12 15:04:31 -04:00
Hykilpikonna 24c89ac381 [O] Trim course names 2020-04-12 15:04:10 -04:00
Hykilpikonna 87a3aed16d [O] Filter out courses not from this year 2020-04-12 14:50:21 -04:00
Hykilpikonna cd14b2a768 [+] Encapsulate getSchoolYear() 2020-04-12 14:49:02 -04:00
Hykilpikonna df79998990 [S] Cut long course names 2020-04-12 14:44:30 -04:00
Hykilpikonna 25d0965696 [S] Remove scrollbar 2020-04-12 14:44:14 -04:00
Hykilpikonna e886f981a0 [O] Remove dynamic width, use fixed height instead 2020-04-12 14:44:00 -04:00
Hykilpikonna 81f66b65de [S] Separate course items to a separate div 2020-04-12 14:01:14 -04:00
Hykilpikonna 61c934c360 [O] Update width on resize 2020-04-12 14:00:31 -04:00
Hykilpikonna ed1a667e09 [S] Fix header and search bar width 2020-04-12 13:55:55 -04:00
Hykilpikonna 3f27db8c77 [S] Remove card body padding 2020-04-12 13:55:31 -04:00
Hykilpikonna b975c0332e [F] Dynamically update width with js 2020-04-12 13:52:31 -04:00
Hykilpikonna a0ae839dd3 [S] Make header fixed from scrolling 2020-04-12 13:52:11 -04:00
Hykilpikonna 43c7918854 [+] Create container for header 2020-04-12 13:17:57 -04:00
Hykilpikonna e16a95837c Revert "[O] Separate course list card from actual course list"
This reverts commit 3d6254f2cc.
2020-04-12 13:16:06 -04:00
Hykilpikonna 3d6254f2cc [O] Separate course list card from actual course list 2020-04-12 13:08:03 -04:00
Hykilpikonna 367dccfe95 [S] Adjust search margin 2020-04-12 12:51:27 -04:00
Hykilpikonna 7c564f9497 [S] Round corners 2020-04-12 12:50:39 -04:00
Hykilpikonna 546ba16bb2 [S] Add left padding 2020-04-12 12:49:57 -04:00
Hykilpikonna a958fc6d9e [S] Add background dim to items 2020-04-12 12:49:45 -04:00
Hykilpikonna 3f7433f4da [S] Add bottom margins 2020-04-12 12:49:29 -04:00
Hykilpikonna 37ff3f5dbf [S] Align names to the left 2020-04-12 12:49:17 -04:00
Hykilpikonna d20479e88d [O] Unify margins for search 2020-04-12 12:45:06 -04:00
Hykilpikonna f9bf5b81c9 [O] Filter out clubs from course selection 2020-04-12 12:43:49 -04:00
Hykilpikonna 43e1e9f0ed [F] Fix undefined case for search text 2020-04-12 12:41:48 -04:00
Hykilpikonna e4357abcfd [+] Implement search 2020-04-12 12:41:27 -04:00
Hykilpikonna 3e26965ad0 [O] Compact search into one line 2020-04-12 12:40:10 -04:00
Hykilpikonna 6035136358 [+] Add search bar component 2020-04-12 12:39:46 -04:00
Hykilpikonna 1472bf4dbe [O] Specify data type when getting course info 2020-04-12 12:36:41 -04:00
Hykilpikonna 2bae41eed1 [+] Create courseinfo class 2020-04-12 12:35:10 -04:00
Hykilpikonna ad4bb875ae [S] Specify item height 2020-04-12 12:28:02 -04:00
Hykilpikonna 0a145ecdb5 [+] Create course info item list 2020-04-12 12:27:47 -04:00
Hykilpikonna 95a7907d72 [S] Specify header margins and font size 2020-04-12 12:27:22 -04:00
Hykilpikonna f019d31f99 [+] Create course selection card header 2020-04-12 12:27:03 -04:00
Hykilpikonna 3d7fa6cdae [S] Add inner scrollbar to card 2020-04-12 12:26:50 -04:00
Hykilpikonna 7e5302c913 [+] Load directory 2020-04-12 12:25:15 -04:00
Hykilpikonna 4cf64a0418 [+] Load course info 2020-04-12 12:25:02 -04:00
Hykilpikonna c8289f5278 [O] Fix typo in comment 2020-04-12 00:14:29 -04:00
Hykilpikonna ea93bc8d1a [S] Only enable bottom padding for overall and course 2020-04-11 20:01:03 -04:00
Hykilpikonna b1df999efb [O] CSS indent 2020-04-11 19:49:37 -04:00
Hykilpikonna 320c7ab8ff [S] Unify left and right margins 2020-04-11 19:49:24 -04:00
Hykilpikonna b706c439c8 [S] Unify top and bottom margins 2020-04-11 19:48:52 -04:00
Hykilpikonna f4e11fcbcc [+] Add cards below info card 2020-04-11 19:47:37 -04:00
Hykilpikonna 3dea971055 [O] Hide course selection tab for seniors 2020-04-11 19:21:05 -04:00
Hykilpikonna 252be18c2f [S] Use red for error notice 2020-04-11 19:20:01 -04:00
Hykilpikonna ba84861628 [+] Add a friendly note to seniors in the course selection page 2020-04-11 19:18:43 -04:00
Hykilpikonna d974fb24a0 [+] Add gradeLevel field to user 2020-04-11 19:16:38 -04:00
Hykilpikonna b05b145911 [+] Create method to getGradeLevel from graduation year 2020-04-11 19:16:23 -04:00
Hykilpikonna 06bffb905e [O] Make user's graduation year a number instead of a string 2020-04-11 19:15:58 -04:00
Hykilpikonna 8ea8a3474f [+] Pass in app as a property to course selection page 2020-04-11 19:02:27 -04:00
Hykilpikonna 7609513a07 [+] Import course selection element in app 2020-04-11 19:00:07 -04:00
Hykilpikonna 8b1ffb412c [+] Create course selection tab on navbar 2020-04-11 18:59:44 -04:00
Hykilpikonna a137466ed1 [+] Create course selection page 2020-04-11 18:59:29 -04:00
Hykilpikonna 852d016203 [O] Turn on deployment warnings by default 2020-04-11 18:59:05 -04:00
Hykilpikonna 49765498e7 [U] Only update safe dependencies 2020-04-03 17:25:14 -04:00
Hykilpikonna 02c2ddd7d8 Revert "[U] Further update packages with ncu"
This reverts commit 522f2f803b.
2020-04-03 17:13:18 -04:00
Hykilpikonna e643b65d98 [O] Remove unnecessary courses prop 2020-04-03 17:05:41 -04:00
Hykilpikonna e3b011003d [F] Remove problematic App.instance usage and pass in app 2020-04-03 17:05:14 -04:00
Hykilpikonna b6b1a9362c [F] Fix newer vue import issues 2020-04-03 17:03:50 -04:00
Hykilpikonna 522f2f803b [U] Further update packages with ncu 2020-04-03 15:16:56 -04:00
Hykilpikonna 4d7109fa6b [U] Update packages 2020-04-03 15:08:26 -04:00
Hykilpikonna c31043a760 [U] Open term 4 2020-03-23 18:22:02 -04:00
Hykilpikonna fed0634a51 [O] Only show graded types on graphs 2020-03-22 18:43:53 -04:00
Hykilpikonna d4f643b3f4 [O] Only display percent average if it's not NaN 2020-03-22 18:43:35 -04:00
Hykilpikonna 18b17cdd67 [+] Separate graded assignments from regular when calculating weighting 2020-03-22 18:43:15 -04:00
Hykilpikonna 74dab07d3f [U] Update Dependencies 2020-03-15 23:39:22 +00:00
Hykilpikonna 91e52d2fc0 [+] Add graded field to AssignmentType 2020-03-14 21:52:51 -04:00
Hykilpikonna 4ba6f4a613 [S] Make the color of late seem less important 2020-03-07 23:57:39 -05:00
Hykilpikonna df68cc5927 [O] Add default case 2020-03-07 23:57:19 -05:00
Hykilpikonna 4201d9aa4e [F] Support "not turned in" as a completion status 2020-03-07 23:56:49 -05:00
Hykilpikonna 7c8bde24b3 [U] Release v0.5.4.1391 2020-03-07 16:55:27 -05:00
Hykilpikonna 158344f24f [F] Only average graded assignments in type average 2020-03-07 16:15:59 -05:00
Hykilpikonna 78159fda3f [S] Reverse alternating shading order 2020-03-07 16:13:03 -05:00
Hykilpikonna 8988e02793 [S] Fix assignment alignment issues on smaller screens 2020-03-07 16:12:24 -05:00
Hykilpikonna 6e7642e126 [S] Make min-width look better 2020-03-07 16:12:02 -05:00
Hykilpikonna 47bea6197a [S] Make bottom margin larger 2020-03-07 16:11:35 -05:00
Hykilpikonna ea17b3e9ea [S] Use alternating shading for gades 2020-03-07 16:11:23 -05:00
Hykilpikonna da719a0a6b [O] Treat close as clearUnread(false) 2020-03-07 16:10:57 -05:00
Hykilpikonna f654527311 [O] Only display grade if graded 2020-03-07 16:10:14 -05:00
Hykilpikonna 880dea1bef [F] Should display un-graded assignments too 2020-03-07 16:09:40 -05:00
Hykilpikonna 021915d9d4 [F] Include "incomplete" in GPA calculation 2020-03-07 16:08:53 -05:00
Hykilpikonna 1fb0102328 [F] NREQ shouldn't be graded 2020-03-07 16:08:19 -05:00
Hykilpikonna 1fc2a2adda [+] Support "incomplete" as a completion status 2020-03-07 16:08:15 -05:00
Hykilpikonna ddc1024611 [O] Support "pending" as a completion status 2020-03-07 16:06:56 -05:00
Hykilpikonna 1de041351c [O] Order completion status by id 2020-03-07 16:06:23 -05:00
Hykilpikonna f64cf0ad02 [F] Fix unread clearing issue 2020-03-05 18:25:42 -05:00
Hykilpikonna 46ef56efbd [M] Move deploy script 2020-01-27 16:49:48 -05:00
Hykilpikonna 7b04d1e006 [F] Enable third quarter 2020-01-27 16:49:38 -05:00
Hykilpikonna 511d4544b6 [U] Release v0.5.3.1373 2020-01-27 16:45:09 -05:00
Hykilpikonna 140893a9b2 [S] Correct margins
#3
2020-01-27 16:38:08 -05:00
Hykilpikonna 427773f4cb [+] Display assignment completion status if it is not complete
#3
2020-01-27 16:37:48 -05:00
Hykilpikonna dfeb5d0272 [+] Create method to get completion status color
#3
2020-01-27 16:37:10 -05:00
Hykilpikonna 304ba63771 [+] Create method to get completion status
#3
2020-01-27 16:36:43 -05:00
Hykilpikonna 1698f1737d [+] Include late and NREQ assignments
#3
2020-01-27 16:03:09 -05:00
Hykilpikonna 9d8a797c54 [-] Remove background for now 2020-01-23 20:35:16 -05:00
Hykilpikonna 4d0c48619d [+] Add title 2020-01-05 18:27:12 -05:00
Hykilpikonna e95d212628 [O] Compress background 2020-01-05 18:25:42 -05:00
Hykilpikonna 936e6ffa41 [+] Create info page background 2020-01-05 18:23:32 -05:00
Hykilpikonna f2a3260b8f [F] Dark mode should not apply to info page 2020-01-05 17:33:25 -05:00
Hykilpikonna 5c8b2b37d4 [O] Mark darkmode as unfinished 2020-01-05 17:31:33 -05:00
Hykilpikonna 44e4b615ba [S] Auto opacity based on darkmode 2020-01-05 17:31:18 -05:00
Hykilpikonna 60a852815b [S] Dark mode for unread number 2020-01-05 17:18:15 -05:00
Hykilpikonna 7c7d7e609a [S] Make course assignment type background look nicer 2020-01-05 17:17:43 -05:00
Hykilpikonna 0da5be9448 [S] Fix darkmode for navbar 2020-01-05 17:13:39 -05:00
Hykilpikonna 1ebb69c89c [S] Fix darkmode for desktop background 2020-01-05 17:13:29 -05:00
Hykilpikonna 99af1c4607 [S] Remove awkward white areas 2020-01-05 17:10:46 -05:00
Hykilpikonna e1caacce34 [+] Implement dark mode switcing 2020-01-05 17:09:13 -05:00
Hykilpikonna e2b6a92743 [O] Change text depending on isDark value 2020-01-05 17:09:03 -05:00
Hykilpikonna 982c8cf872 [+] Create isDark() function 2020-01-05 17:07:58 -05:00
Hykilpikonna 1e928ac1a8 [+] Add darkmode button 2020-01-05 17:07:39 -05:00
Hykilpikonna a17ab1511d [+] Add dark mode class depending on the switch 2020-01-05 17:07:28 -05:00
Hykilpikonna 07c55df766 [+] Initialize dark mode switch to cookie value 2020-01-05 17:07:15 -05:00
Hykilpikonna 06ee7b4de9 [+] Add dark mode switch 2020-01-05 17:07:00 -05:00
Hykilpikonna 0c520d5f50 [+] Use logo more compatible to dark mode 2020-01-05 17:06:48 -05:00
Hykilpikonna 522867a2dc [F] Ignore static page detection for nav-controller 2020-01-05 16:23:17 -05:00
Hykilpikonna d56d985734 [+] Display content according to staticpage 2020-01-05 16:22:56 -05:00
Hykilpikonna 1d404b4f51 [+] Detect static pages 2020-01-05 16:22:25 -05:00
Hykilpikonna c1d3cc88bc [+] Add static page field 2020-01-05 16:22:18 -05:00
Hykilpikonna 1242e2ed58 [+] Import info static page 2020-01-05 16:22:10 -05:00
Hykilpikonna f61dccb90a [+] Add hello world for testing 2020-01-04 21:15:42 -05:00
Hykilpikonna 106da7e7f1 [+] Create info component 2020-01-04 18:57:17 -05:00
Hykilpikonna 4774ad658b [O] Ignore jsons from tslint 2020-01-04 18:51:43 -05:00
Hykilpikonna 6035fe5318 [F] Fix older version url navigation issue 2020-01-04 18:51:26 -05:00
Hykilpikonna 452ac69fb6 [+] Add reminder in deploy script 2020-01-04 18:47:25 -05:00
Hykilpikonna 3ec604f049 [+] Redirect from vera.hydev.org/info 2020-01-04 18:47:13 -05:00
Hykilpikonna f5c093960a [U] Release v0.5.2.1335 2019-12-21 20:47:52 -05:00
Hykilpikonna 984fa394a5 [F] Fix history state null pointer 2019-12-21 20:47:11 -05:00
Hykilpikonna db12a5b9e7 [S] Fix updates style 2019-12-21 20:42:55 -05:00
Hykilpikonna dc57ee16c9 [U] Release v0.5.2.1332 2019-12-21 20:39:15 -05:00
Hykilpikonna 975542dab2 [S] Move the cancel button to the left 2019-12-21 20:38:41 -05:00
Hykilpikonna 5ad2be88c1 [+] Implement mark all as read 2019-12-21 20:27:23 -05:00
Hykilpikonna 76ec5d4476 [S] Make margins line up with the other cards 2019-12-21 20:24:12 -05:00
Hykilpikonna 62237d5f5f [S] Round to one digit 2019-12-21 20:23:52 -05:00
Hykilpikonna eeb2ae56d7 [S] Add margins to progress bar 2019-12-21 20:22:32 -05:00
Hykilpikonna bb1751f442 [S] Change progress bar color to green 2019-12-21 20:21:58 -05:00
Hykilpikonna a4241f9549 [S] Make progress bar visible 2019-12-21 20:21:43 -05:00
Hykilpikonna 693d479b0f [F] Progress percentage * 100 2019-12-21 20:20:35 -05:00
Hykilpikonna cf5c59fb78 [O] Separate started flag 2019-12-21 20:20:06 -05:00
Hykilpikonna 311055a4c9 [O] Create progress getter 2019-12-21 20:19:50 -05:00
Hykilpikonna 02d5e209d9 [U] Update usage in overall-course 2019-12-21 20:14:05 -05:00
Hykilpikonna e4ebaf2935 [+] Call callbacks when unread is updated 2019-12-21 20:13:53 -05:00
Hykilpikonna 97fe8395e6 [+] Encapsulate addCallback() 2019-12-21 20:13:42 -05:00
Hykilpikonna d7b319b6c9 [+] Create updateCallbacks in assignment 2019-12-21 20:13:32 -05:00
Hykilpikonna 1fdf6a8a72 [F] Fix import 2019-12-21 19:52:26 -05:00
Hykilpikonna 3425894c24 [F] Fix vue update problem 2019-12-21 19:45:08 -05:00
Hykilpikonna 3e6caab023 [S] Fix dialog checkbox alignment 2019-12-21 19:39:37 -05:00
Hykilpikonna 7e23919c0d [S] Fix word breaking globally 2019-12-21 19:39:26 -05:00
Hykilpikonna 6b7a5af7ae [O] Inline overall-course 2019-12-21 19:39:03 -05:00
Hykilpikonna 74bfec92f6 [U] Update usage in overall-course 2019-12-21 19:38:46 -05:00
Hykilpikonna 30030a0ca5 [+] Encapsulate markAsRead() 2019-12-21 19:38:28 -05:00
Hykilpikonna 78590f96f1 [O] Change that to -1 2019-12-21 19:24:23 -05:00
Hykilpikonna cc485708c5 [U] Only show progress when progress is not 0 2019-12-21 19:24:02 -05:00
Hykilpikonna daeca0fb0b [O] Use better cookie name 2019-12-21 19:23:13 -05:00
Hykilpikonna 5b5704bd75 [+] Set cookies when don't ask again is checked 2019-12-21 19:20:27 -05:00
Hykilpikonna 762be8bfba [+] Add progress bar 2019-12-21 19:10:02 -05:00
Hykilpikonna b224f07e00 [U] Update unread usage in vue 2019-12-21 18:56:12 -05:00
Hykilpikonna b1a902f92e [O] Optimize mark as unread 2019-12-21 18:55:02 -05:00
Hykilpikonna aeadb6fc8b [O] Optimize count unread for overall-course 2019-12-21 18:54:50 -05:00
Hykilpikonna e8aeecb27c [+] Add don't ask again checkbox 2019-12-21 18:40:56 -05:00
Hykilpikonna 29131227b5 [O] Use better variable names 2019-12-21 18:40:43 -05:00
Hykilpikonna 9b3a61e5cc [O] Cache unread assignments 2019-12-21 18:39:47 -05:00
Hykilpikonna 4bc9113b96 [+] Add image indicating too many unread 2019-12-21 18:32:24 -05:00
Hykilpikonna 45e0ac6066 [S] Fix word newline stuff 2019-12-21 18:26:09 -05:00
Hykilpikonna 4047a3e8f6 [+] Detect notification count 2019-12-21 18:25:43 -05:00
Hykilpikonna d4d8312016 [+] Create too many notifications prompt 2019-12-21 18:25:27 -05:00
Hykilpikonna e60df664c1 [O] Only show term grades if the selected term is "all year" 2019-12-21 17:32:03 -05:00
Hykilpikonna 916c586cbc [O] Encapsulate rawSelectedTerm() 2019-12-21 17:30:45 -05:00
Hykilpikonna a903b2cdfa [S] Largen the gap between term and current grades 2019-12-21 17:24:02 -05:00
Hykilpikonna 79f3a8e497 [S] Adjust term and numeric color to create contrast 2019-12-21 17:20:53 -05:00
Hykilpikonna 5905eb1923 [S] Adjust letter grade font size 2019-12-21 17:20:35 -05:00
Hykilpikonna 6dd3d898aa [S] Set color to gray 2019-12-21 17:20:24 -05:00
Hykilpikonna 7c86ecf3b5 [S] Apply font size to numeric too 2019-12-21 17:20:12 -05:00
Hykilpikonna 45e1376a8f [S] Auto adjust width based on contnet 2019-12-21 17:16:40 -05:00
Hykilpikonna 07f3544ba5 [S] Reduce term font size 2019-12-21 17:16:16 -05:00
Hykilpikonna 4f93539673 [F] Fix: displaying zero based counting 2019-12-21 17:14:09 -05:00
Hykilpikonna 095dfdb54f [+] Display term number 2019-12-21 17:13:48 -05:00
Hykilpikonna eaac2b9332 [S] Vertical align letter and numeric 2019-12-21 17:13:38 -05:00
Hykilpikonna e63547140b [S] Fix reversed array 2019-12-21 17:08:32 -05:00
Hykilpikonna 99aa7b4093 [S] Fix display order 2019-12-21 17:08:02 -05:00
Hykilpikonna b4e6dcdb8c [S] Adjust alignment 2019-12-21 17:07:51 -05:00
Hykilpikonna 2d182c3cf4 [+] Display term grades 2019-12-21 17:02:35 -05:00
Hykilpikonna 05feb8c9f3 [O] Enable caching for numeric grade 2019-12-21 17:02:08 -05:00
Hykilpikonna 3adfdb5aac [+] Encapsulate course.letterGradeTerm() 2019-12-21 17:01:57 -05:00
Hykilpikonna c0ec2e03ff [+] Encapsulate getAllGradingPeriods() 2019-12-21 17:01:37 -05:00
Hykilpikonna e128704552 [S] Optimize other selectors 2019-12-21 15:18:50 -05:00
Hykilpikonna af2aba9a50 [S] Optimize css selectors for block-info and block-grade 2019-12-21 15:16:10 -05:00
Hykilpikonna dbdd33d050 [S] Scope css 2019-12-21 15:13:13 -05:00
Hykilpikonna d230636a0e [O] Remove el-row from course-head 2019-12-21 15:13:04 -05:00
Hykilpikonna e7d639af33 [O] Optimize course-head clickable 2019-12-21 14:50:17 -05:00
Hykilpikonna b97ca4f699 [F] Fix history refresh problem 2019-12-21 14:46:06 -05:00
Hykilpikonna 1657330c57 [-] Remove installed element-ui js library 2019-12-21 14:45:14 -05:00
Hykilpikonna dd8bbf2cbe [U] Update dependencies 2019-12-21 14:44:37 -05:00
Hykilpikonna 53065c9dd3 [O] Serialize index 2019-12-21 14:09:14 -05:00
Hykilpikonna 27bcd6b9b6 [F] Fix navigator selection 2019-12-21 14:08:55 -05:00
Hykilpikonna bc190cbdfb [F] Fix problem where history activates twice 2019-12-21 13:53:02 -05:00
Hykilpikonna 755b384b76 [F] Fix initial index conversion 2019-12-21 13:41:53 -05:00
Hykilpikonna a3f03f5577 [O] Optimize null case with param default 2019-12-21 13:40:46 -05:00
Hykilpikonna 57f29262e3 [O] Separate checkIndex 2019-12-21 13:40:34 -05:00
Hykilpikonna ac5549ccc4 [F] Remove lastTab from history state 2019-12-21 13:40:05 -05:00
Hykilpikonna d3ba0af4f5 [F] Update current index 2019-12-21 13:32:32 -05:00
Hykilpikonna 6312515b7b [U] Update nav usage in navigation vue 2019-12-21 13:31:58 -05:00
Hykilpikonna 41cdbe93b1 [F] Fix error due to auto caching of get methods 2019-12-21 13:31:45 -05:00
Hykilpikonna 702eb4d8f3 [U] Update usage 2019-12-21 13:25:10 -05:00
Hykilpikonna 7581ea016e [O] Specify type for id and info 2019-12-21 13:24:22 -05:00
Hykilpikonna 4938b2a72a [O] Make identifier required 2019-12-21 13:23:21 -05:00
Hykilpikonna 815258e8be [+] Add identifier and info in course.urlIndex 2019-12-21 13:21:37 -05:00
Hykilpikonna adb211c58a [+] Add info to index 2019-12-21 13:20:32 -05:00
Hykilpikonna cdeae1e1d4 [+] Add identifier to index 2019-12-21 13:20:18 -05:00
Hykilpikonna dfbe255191 [M] Shorten var name "activeIndex" to index 2019-12-21 13:20:08 -05:00
Hykilpikonna f8f1c1f8a3 [F] Fix course-head navigator usage 2019-12-21 13:11:35 -05:00
Hykilpikonna 4e5809a1dc [U] Update app component usage 2019-12-21 13:08:41 -05:00
Hykilpikonna aef5fa47fc [U] Update usage in Navigation 2019-12-21 13:07:42 -05:00
Hykilpikonna ca751c27d1 [O] Remove unnecessary getTitle() 2019-12-21 12:59:42 -05:00
Hykilpikonna 95690fe046 [O] Specify type 2019-12-21 12:58:02 -05:00
Hykilpikonna 1fd17706e4 [-] Remove duplicate in course-utils 2019-12-21 12:56:23 -05:00
Hykilpikonna 082400abe8 [+] Encapsulate get urlIndex in course 2019-12-21 12:56:13 -05:00
Hykilpikonna e90741b6bc [+] Encapsulate get urlHash in Course 2019-12-21 12:55:59 -05:00
Hykilpikonna 71352ee39a [O] Make activeIndex accessable 2019-12-21 12:50:02 -05:00
Hykilpikonna caa6b38673 [M] Rename Navigator class to NavController to avoid conflict 2019-12-21 12:47:10 -05:00
Hykilpikonna 49c23c9562 [+] Create navigator field in app 2019-12-21 12:40:56 -05:00
Hykilpikonna 94424ea288 [M] Rename filteredCourses to gradedCourses 2019-12-21 12:40:43 -05:00
Hykilpikonna 956119be2a [O] Optimize assignmentsReady 2019-12-21 12:39:48 -05:00
Hykilpikonna e26decd77d [O] Remove unnecessary public 2019-12-21 12:32:36 -05:00
Hykilpikonna 4d7b41bf2a [+] Create constructor 2019-12-21 11:52:16 -05:00
Hykilpikonna e6cfa30ed4 [O] Optimize encapsulation 2019-12-21 11:51:12 -05:00
Hykilpikonna ea46d16836 [+] Encapsulate updateIndex with only hash 2019-12-21 11:49:06 -05:00
Hykilpikonna 128dbb2ca7 [+] Auto format title if null 2019-12-21 11:44:43 -05:00
Hykilpikonna 097985f087 [O] Optimize nullable format 2019-12-21 11:44:21 -05:00
Hykilpikonna 26fa50ead2 [O] Make title nullable 2019-12-21 11:43:26 -05:00
Hykilpikonna 14a9c5a9b2 [O] Combine index and title 2019-12-21 11:37:25 -05:00
Hykilpikonna 55432e5c33 [+] Create navigator class 2019-12-21 11:34:09 -05:00
Hykilpikonna a2f6a30ad1 [U] Update packages 2019-12-08 13:05:26 -05:00
Hykilpikonna bee2001013 [U] Release v0.5.1.1229 2019-12-07 20:22:36 -05:00
Hykilpikonna facb76c568 [O] Divide nickname with signout 2019-12-07 20:19:51 -05:00
Hykilpikonna aaa36382bc [+] Show nickname on dropdown 2019-12-07 20:19:38 -05:00
Hykilpikonna f66f3551fd [+] Add command to dropdown menu 2019-12-07 17:12:08 -05:00
Hykilpikonna 2671d9a5ba [+] Create avatar menu event function 2019-12-07 17:11:53 -05:00
Hykilpikonna 43174bf294 [-] Remove unnecessary public 2019-12-07 17:08:19 -05:00
Hykilpikonna d69b74571a [+] Add icon to sign-out 2019-12-07 17:06:00 -05:00
Hykilpikonna 1976805f60 [S] Set dropdown font 2019-12-07 16:58:03 -05:00
Hykilpikonna d2af24a574 [S] Optimize font variable 2019-12-07 16:57:56 -05:00
Hykilpikonna a7bb39bc76 [S] Import Nunito font 2019-12-07 16:57:37 -05:00
Hykilpikonna 915fcb94dc [-] Remove signout button 2019-12-07 16:40:40 -05:00
Hykilpikonna eb8ac2b7a5 [O] Trigger on click 2019-12-07 16:38:36 -05:00
Hykilpikonna 282c2aa1b2 [+] Add dropdown to avatar 2019-12-07 16:38:13 -05:00
Hykilpikonna eed72aaa28 [F] Fix potential NaN 2019-12-07 16:03:13 -05:00
Hykilpikonna 0650af48af [F] Use LetterGrade for more accuracy 2019-12-07 15:59:42 -05:00
Hykilpikonna 11ccd9f28a [F] Don't include NaN in GPA calculation 2019-12-07 15:59:27 -05:00
Hykilpikonna ef44e4d149 [F] Account for all year situation 2019-12-07 15:07:47 -05:00
Hykilpikonna 4a220ddc60 [+] Encapsulate getStartDate() 2019-12-07 15:05:46 -05:00
Hykilpikonna 0e60a3d93d [+] Switch terms when generating series data 2019-12-07 15:05:30 -05:00
Hykilpikonna b0a6c5fece [O] Optimize code style 2019-12-07 15:05:13 -05:00
Hykilpikonna b3dfeb2add [M] Rename to shorten getSelectGradingPEriod 2019-12-07 15:04:44 -05:00
Hykilpikonna 844eeefb4c [O] Optimize in-between dates storing 2019-12-07 14:39:12 -05:00
Hykilpikonna 6d3e145558 [O] Use course.getAssignmentsBefore() 2019-12-07 14:29:46 -05:00
Hykilpikonna 25eaf9abe9 [F] Fix unable to find minDate 2019-12-07 14:29:05 -05:00
Hykilpikonna b505365762 [-] Remove duplicate sorting 2019-12-07 14:28:42 -05:00
Hykilpikonna 8402fa7dd9 [F] Fix term ending time calculation 2019-12-07 14:28:00 -05:00
Hykilpikonna 5098b696e3 [F] Sort assignments by time 2019-12-07 14:27:41 -05:00
Hykilpikonna 0487e72c1f [O] Sort by date 2019-12-07 14:16:28 -05:00
Hykilpikonna 40ba71e1d8 [F] Fix date duplicate problem 2019-12-07 14:15:59 -05:00
Hykilpikonna 643430553b [-] Remove unused variable i 2019-12-07 14:15:43 -05:00
Hykilpikonna 940bf3635c [F] Only return assignments of this grading period 2019-12-07 14:12:33 -05:00
Hykilpikonna 2d119ce531 [F] Fix not found problem 2019-12-07 14:05:09 -05:00
Hykilpikonna fe3d96ec9c [F] Fix index problem when finding last index 2019-12-07 14:04:23 -05:00
Hykilpikonna bf4f2f20cf [O] Use timestamp instead of date 2019-12-07 13:56:17 -05:00
Hykilpikonna 6c8e888807 [+] Encapsulate getAssignmentsBefore(date) 2019-12-07 13:51:49 -05:00
Hykilpikonna d71fb87a21 [S] Adjust avatar positioning 2019-12-07 13:51:24 -05:00
Hykilpikonna 6695cad008 [U] Update pWaitFor callback 2019-12-07 13:51:01 -05:00
Hykilpikonna 1e6e21200a [O] Fill new array with null 2019-12-07 13:49:50 -05:00
Hykilpikonna 32313461c6 [U] Remove unnecessary public 2019-12-07 13:48:33 -05:00
Hykilpikonna 34c562c8e9 [F] Force cookie update 2019-12-07 13:48:09 -05:00
Hykilpikonna ec4f66f4f3 [U] Use getTerm 2019-12-07 13:47:56 -05:00
Hykilpikonna 3e37ab15fc [+] Encapsulate getTerm(date) 2019-12-07 13:47:35 -05:00
Hykilpikonna 16e7e408bc [O] Force update cookies 2019-12-07 12:34:11 -05:00
Hykilpikonna 016a8a3960 [U] Update termGrading usage 2019-12-07 12:33:54 -05:00
Hykilpikonna 022c7ec50f [U] Update usage 2019-12-07 12:32:57 -05:00
Hykilpikonna bac9e3524c [O] Use encapsulated graded() method 2019-12-07 12:32:46 -05:00
Hykilpikonna e26d46a5d2 [U] Pass in grading when calculating PT average 2019-12-07 12:32:32 -05:00
Hykilpikonna 314828a089 [+] Encapsulate get numericGrade 2019-12-07 12:26:05 -05:00
Hykilpikonna 4090ec125a [O] Cache grading periods 2019-12-07 12:25:37 -05:00
Hykilpikonna 6f2c5feef6 [O] Only return valid terms 2019-12-07 12:24:33 -05:00
Hykilpikonna 2fcb5348c9 [U] Update usage 2019-12-07 11:59:49 -05:00
Hykilpikonna 964fee639d [-] Remove unused allYearGrade field 2019-12-07 11:58:53 -05:00
Hykilpikonna b21a76e3c6 [O] Put term assignments outside of computed 2019-12-07 11:58:36 -05:00
Hykilpikonna 344f2628e3 [-] Remove one-line encapsulation 2019-12-07 11:57:09 -05:00
Hykilpikonna fdb4752e87 [U] Load raw assignments 2019-12-07 11:55:02 -05:00
Hykilpikonna 9afd71a06c [-] Remove unnecessary JsonUtils 2019-12-07 11:54:45 -05:00
Hykilpikonna 6e25bd6b17 [-] Remove unused variable declaration 2019-12-07 11:53:15 -05:00
Hykilpikonna fd01dda8b3 [+] Encapsulate getGraded() in assignment 2019-12-07 11:53:05 -05:00
Hykilpikonna 24ab0f66f3 [+] Create constructor for assignments 2019-12-07 11:52:34 -05:00
Hykilpikonna 4a51e8ecdb [O] Make Assignment interface a class 2019-12-07 11:52:19 -05:00
Hykilpikonna 32ccac2d15 [O] Find current term dynamically 2019-12-07 11:42:40 -05:00
Hykilpikonna 8ba8489594 [+] Encapsulate findLastIndex() 2019-12-07 11:37:56 -05:00
Hykilpikonna bf4479490f [U] Get numeric grade by term 2019-12-07 11:25:39 -05:00
Hykilpikonna 8846a8be5d [O] Get assignments return all selected terms assignments 2019-12-07 11:25:23 -05:00
Hykilpikonna 99f1a4c58a [+] Encapsulate getGradingPeriods() 2019-12-07 11:21:19 -05:00
Hykilpikonna e57b5a5d69 [+] Encapsulate getGrading(term) 2019-12-07 11:17:30 -05:00
Hykilpikonna e44724a173 [O] Separate grading class 2019-12-07 11:17:17 -05:00
Hykilpikonna 1513a3016c [F] Load grading for each term 2019-12-06 21:22:40 -05:00
Hykilpikonna 81c79d3867 [+] Initialize grading as empty array 2019-12-06 21:22:17 -05:00
Hykilpikonna 8c3f398753 [F] Make weightingMap an array 2019-12-06 21:22:01 -05:00
Hykilpikonna 2a2fae8a97 Revert "[O] Make cache() a function"
This reverts commit bf9d90d80f.
2019-12-06 18:18:41 -05:00
Hykilpikonna 3c632c0488 Revert "[U] Update usage"
This reverts commit dc3365b594.
2019-12-06 18:18:38 -05:00
Hykilpikonna d0519bbab4 Revert "[F] Fix logic typo"
This reverts commit f399fee29c.
2019-12-06 18:18:35 -05:00
Hykilpikonna f399fee29c [F] Fix logic typo 2019-12-06 18:13:20 -05:00
Hykilpikonna dc3365b594 [U] Update usage 2019-12-06 18:11:39 -05:00
Hykilpikonna bf9d90d80f [O] Make cache() a function 2019-12-06 18:10:50 -05:00
Hykilpikonna 2ce8d04cbd [U] Cache assignmentTypes 2019-12-06 18:08:06 -05:00
Hykilpikonna 5d2ef0fadf [U] Cache numericGrade 2019-12-06 18:07:55 -05:00
Hykilpikonna 7307b179f0 [U] Cache letterGrade() 2019-12-06 18:07:46 -05:00
Hykilpikonna 55c6119853 [U] Cache assignments() 2019-12-06 18:07:35 -05:00
Hykilpikonna aba98783db [+] Create cache field in course 2019-12-06 18:07:22 -05:00
Hykilpikonna eb1da15c8f [M] Rename Cache to CacheUtils to avoid naming conflicts 2019-12-05 23:22:43 -05:00
Hykilpikonna 698db97eb1 [+] Create get() method for cache 2019-12-05 23:19:19 -05:00
Hykilpikonna 5a5f2349ea [+] Create a cache map field 2019-12-05 23:19:02 -05:00
Hykilpikonna 86fa51496f [+] Create CacheUtils 2019-12-05 23:18:46 -05:00
Hykilpikonna bf0e1986d4 [S] Add margins to avatar 2019-12-02 22:33:19 -05:00
Hykilpikonna 20d54611b5 [S] Align avatar to the right 2019-12-02 22:33:11 -05:00
Hykilpikonna 68d37f1dc2 [+] Add class to avatar 2019-12-02 22:32:43 -05:00
Hykilpikonna 819610f4f1 [F] Multiple links didn't work 2019-12-02 22:30:50 -05:00
Hykilpikonna 97b1f5c486 [+] Add avatar 2019-12-02 22:30:34 -05:00
Hykilpikonna f39cb9e1cd [F] Only display navigation when user signed in 2019-12-02 22:30:10 -05:00
Hykilpikonna 127ec9df4a [F] Fix not initialized error 2019-12-02 22:29:05 -05:00
Hykilpikonna 4a74df1dea [U] Pass in user in app.vue 2019-12-02 22:09:43 -05:00
Hykilpikonna 27c7d3b192 [+] Add user field in navigation 2019-12-02 22:09:23 -05:00
Hykilpikonna 8a207f7b81 [+] Use all emails 2019-12-02 22:05:40 -05:00
Hykilpikonna 7f42eabbd1 [+] Generate avatar url 2019-12-02 21:59:45 -05:00
Hykilpikonna 3aef7c1223 [O] Trim emails 2019-12-02 21:59:29 -05:00
Hykilpikonna 78faa7430a [+] Add maintenance message 2019-12-02 21:59:17 -05:00
Hykilpikonna c059986a50 [+] Import md5 dependency 2019-12-02 21:50:35 -05:00
Hykilpikonna 03f7b1b56b [F] Fix maintenance page alignment 2019-12-02 17:18:58 -05:00
Hykilpikonna aead3a0021 [+] Show maintenance when it is detected 2019-12-02 17:07:42 -05:00
Hykilpikonna c908e6f157 [+] Add maintenance component 2019-12-02 17:07:01 -05:00
Hykilpikonna 26ae33f807 [+] Add message property in maintenance 2019-12-02 17:06:40 -05:00
Hykilpikonna c4b27a420f [+] Clear cookies when login expires 2019-12-02 16:46:53 -05:00
Hykilpikonna cf28f8617d [O] Remove console logging before clearing cookies 2019-12-02 16:46:40 -05:00
Hykilpikonna ca54abe788 [+] Encapsulate clearCookies() 2019-12-02 16:46:13 -05:00
Hykilpikonna ee7045a120 [+] Create maintenance page 2019-12-02 16:18:14 -05:00
Hykilpikonna d267867381 [O] Optimize imports 2019-12-02 14:51:41 -05:00
Hykilpikonna e4acf55656 [O] Remove empty component tags 2019-12-02 14:49:53 -05:00
Hykilpikonna 2cacc2175a [O] Collapse empty tags 2019-12-02 14:49:17 -05:00
Hykilpikonna 50f9e3aeea [O] Optimize calls with get functions 2019-12-02 14:43:55 -05:00
Hykilpikonna 146323a351 [M] Move loading.vue to /overlays/ 2019-12-02 14:40:40 -05:00
Hykilpikonna b0d95991f1 [+] Disable input when logging in with token 2019-12-02 14:39:15 -05:00
Hykilpikonna 987c9e462a [+] Add switch to disable input 2019-12-02 14:38:59 -05:00
Hykilpikonna c19bb5bfe0 [O] Fix a grammar mistake in constants.ts 2019-12-02 14:22:01 -05:00
Hykilpikonna e10ed6e41b [U] Update user type and usage in Http-utils.js 2019-12-02 14:21:41 -05:00
Hykilpikonna c01817cd97 [U] Update user type in App.ts 2019-12-02 14:21:24 -05:00
Hykilpikonna a3e6c8d635 [U] Update event name in app.vue 2019-12-02 14:20:59 -05:00
Hykilpikonna 6c71bb4ab2 [O] Make login() return LoginUser 2019-12-02 14:20:48 -05:00
Hykilpikonna 991580473d [+] Create constructor for it 2019-12-02 14:17:04 -05:00
Hykilpikonna c6ca171101 [+] Create login-user class 2019-12-02 14:16:54 -05:00
Hykilpikonna 520fbbec5f [O] Fix grammar mistakes in app.ts 2019-12-02 14:07:00 -05:00
Hykilpikonna 4521832a76 [+] Login with token every time 2019-12-02 14:03:35 -05:00
Hykilpikonna 7f07c7d3d6 [O] Show errors properly 2019-12-02 14:01:43 -05:00
Hykilpikonna 63891a8385 [U] Update return data usage 2019-12-02 13:59:22 -05:00
Hykilpikonna 1c52e25e9e [O] Remove unnecessary param after @component 2019-12-02 13:58:48 -05:00
Hykilpikonna af38e4b7d7 [O] Make login.ts code a lot shorter 2019-12-02 13:58:17 -05:00
Hykilpikonna e99e6170b8 [O] Encapsulate login() 2019-12-02 13:55:58 -05:00
Hykilpikonna 7550a99166 [O] Fix grammar mistakes 2019-12-02 13:55:35 -05:00
Hykilpikonna 793c4dcf16 [S] Make version start with v 2019-11-14 22:12:28 -05:00
Hykilpikonna d5bc6b0af8 [S] Correctly align version 2019-11-14 22:12:14 -05:00
Hykilpikonna 80b2980144 [S] Change the font size for version 2019-11-14 22:12:05 -05:00
Hykilpikonna 7ebcb952a9 [S] Lighten the version text 2019-11-14 22:08:42 -05:00
Hykilpikonna 99ec72ce98 [+] Add version number to navbar 2019-11-14 22:07:29 -05:00
Hykilpikonna 3b6bf4a5eb [F] Remove tooltips for pie and radar 2019-11-14 17:37:33 -05:00
Hykilpikonna e11bf75f20 [F] Fix scatter plot tooltip color 2019-11-14 17:29:29 -05:00
Hykilpikonna af56ce497f Revert "[O] Second quarter start at 0"
This reverts commit 2f90f54cb3.
2019-11-14 17:23:14 -05:00
Hykilpikonna 2f90f54cb3 [O] Second quarter start at 0 2019-11-14 17:23:09 -05:00
Hykilpikonna a94701a335 [F] Skip http request if already exists in cookies 2019-11-12 17:29:34 -05:00
Hykilpikonna 67d1525d98 [O] Optimize grading methods by storing them in cookies 2019-11-12 17:28:33 -05:00
Hykilpikonna cdf5475c3b [F] Fix weight errors when the calculated grade equals the supposed grade 2019-11-12 17:23:14 -05:00
Hykilpikonna c97a202bd5 [U] Release v0.4.6.1087 2019-11-11 22:42:42 -05:00
Hykilpikonna b11332953c [F] Fix dark theme logo displaying issue 2019-11-11 22:41:26 -05:00
Hykilpikonna d5f8649b80 [S] Adjust logo font weight 2019-11-11 22:32:01 -05:00
Hykilpikonna fab173afa3 [S] Adjust logo font size 2019-11-11 22:31:48 -05:00
Hykilpikonna 41fbf70428 [S] Create a gradient for logo 2019-11-11 22:30:41 -05:00
Hykilpikonna 1df427b4b4 [S] Add right margin to icon 2019-11-11 22:15:22 -05:00
Hykilpikonna 96a0d3bef6 [S] Remove old logo style 2019-11-11 22:15:13 -05:00
Hykilpikonna 2d917d7858 [S] Limit logo height 2019-11-11 22:15:03 -05:00
Hykilpikonna 2e851e5541 [S] Add logo in nav bar 2019-11-11 22:14:44 -05:00
Hykilpikonna b5ff93bf58 [+] Import Favicon into index.html 2019-11-11 22:09:02 -05:00
Hykilpikonna a10350756f [+] Generate 32px favicon 2019-11-11 22:08:43 -05:00
Hykilpikonna 133765131c [O] Limit logo image width 2019-11-11 21:57:18 -05:00
Hykilpikonna 723a72c1ab [+] Copy logo to assets 2019-11-11 21:53:48 -05:00
Hykilpikonna 6567aeda7d [+] Export logo as png 2019-11-11 21:53:00 -05:00
Hykilpikonna 2182ff8e74 [M] Move vue logo to icon making dir 2019-11-11 21:52:41 -05:00
Hykilpikonna 25865fb372 [+] Remake logo again 2019-11-11 21:52:21 -05:00
Hykilpikonna 81ffeb8d85 [+] Remake logo 2019-11-11 21:51:40 -05:00
Hykilpikonna 19203f3629 [+] Support email login 2019-11-10 17:14:43 -05:00
Hykilpikonna 82ad8f026b [O] Optimize field types 2019-11-10 17:14:33 -05:00
Hykilpikonna 38629a9e34 [O] Specify username format 2019-11-10 17:10:38 -05:00
Hykilpikonna 4499232544 [S] Remove card paddings 2019-11-10 16:39:33 -05:00
Hykilpikonna 960f30295c [S] Specify background color is transparent 2019-11-10 16:39:21 -05:00
Hykilpikonna 415373559c [S] Darken colors 2019-11-10 16:38:17 -05:00
Hykilpikonna a7d22e1620 [S] Add drop shadow to tooltip 2019-11-10 14:27:59 -05:00
Hykilpikonna f88ef7284f [-] Disable dark mode by default 2019-11-10 14:22:18 -05:00
Hykilpikonna 380023668f [S] Apply dark background to course page too 2019-11-10 14:21:41 -05:00
Hykilpikonna fb90900045 [S] Make graph white 2019-11-10 14:15:08 -05:00
Hykilpikonna ab511a706a [S] Compact css entries 2019-11-10 14:14:14 -05:00
Hykilpikonna 407a2889d1 [S] Use css variables 2019-11-10 14:13:38 -05:00
Hykilpikonna 840775314a [S] Fix prev-course and next-course shadow 2019-11-10 14:06:40 -05:00
Hykilpikonna 85c1d93608 [S] Apply darker background to #app-content too 2019-11-10 14:05:23 -05:00
Hykilpikonna 8825886c5c [S] Emphesize course name 2019-11-10 14:04:25 -05:00
Hykilpikonna e924c00f0d [S] Lighten expansion color 2019-11-10 14:00:32 -05:00
Hykilpikonna 03826d108d [S] Add layer effect to course card expansion 2019-11-10 13:59:38 -05:00
Hykilpikonna 1e04b4ad70 [S] Apply light text to buttons too 2019-11-10 13:59:13 -05:00
Hykilpikonna 3ac37d980c [S] Emphesize percent entry box 2019-11-10 13:54:21 -05:00
Hykilpikonna da8cec72b4 [S] Emphesize max entry box 2019-11-10 13:54:10 -05:00
Hykilpikonna 903345b86a [S] Comment overall css 2019-11-10 13:51:24 -05:00
Hykilpikonna 9ed297431d [S] Apply dark background to entry box 2019-11-10 13:50:56 -05:00
Hykilpikonna e763a1ac88 [S] Adjust backtop box shadow 2019-11-10 13:47:50 -05:00
Hykilpikonna 5b3bdc2f1f [S] Apply light text to span too 2019-11-10 13:46:10 -05:00
Hykilpikonna 65b4a68f7e [S] Remove el-card border 2019-11-10 13:44:08 -05:00
Hykilpikonna 7ff885e28b [S] Make overall background darker 2019-11-10 13:44:01 -05:00
Hykilpikonna b936f8a0ca [S] Default use light background for foreground 2019-11-10 13:40:37 -05:00
Hykilpikonna 93a01aeb5d [S] Fix padding under main frame 2019-11-10 13:35:48 -05:00
Hykilpikonna 0326c0bf14 [S] Use gray color with dark background 2019-11-10 13:34:51 -05:00
Hykilpikonna cb91a20844 [S] Apply dark background to all div 2019-11-10 13:34:39 -05:00
Hykilpikonna 9fdb7461ba [S] Create dark css 2019-11-10 13:28:47 -05:00
Hykilpikonna 15b51020fc [O] Make cards clickable 2019-11-10 13:22:26 -05:00
Hykilpikonna 2938621b73 [O] Scroll to top on page change 2019-11-10 13:22:15 -05:00
Hykilpikonna 624158f3d4 [O] Show prev-course and next-course above others 2019-11-10 13:22:02 -05:00
Hykilpikonna 602a8b9c46 [+] Add back-to-top button 2019-11-10 13:21:35 -05:00
Hykilpikonna 62338358d1 [S] Add radial color gradient to the scatter plot points 2019-11-10 13:12:22 -05:00
Hykilpikonna 9bc69a81af [+] Show label on the top 2019-11-10 13:11:51 -05:00
Hykilpikonna c93b1e4eec [+] Resize scatter plot circles according to their weight 2019-11-10 13:09:18 -05:00
Hykilpikonna d30728e2e9 [+] Add assignmentCount to AssignmentType interface 2019-11-10 13:08:22 -05:00
Hykilpikonna 7d86b7a2b9 [+] Import chroma-js instead 2019-11-10 13:02:18 -05:00
Hykilpikonna bb31e18ad5 [+] Add chroma-js dependency 2019-11-10 12:37:52 -05:00
Hykilpikonna 73dc5f6a51 [O] Optimize course-scatter with course.assignmentTypes 2019-11-10 12:05:53 -05:00
Hykilpikonna 6343a10fbc [O] Dynamic radar min value 2019-11-09 23:47:30 -05:00
Hykilpikonna 14beb802b0 [+] Display weight percentage for pie too 2019-11-09 23:29:11 -05:00
Hykilpikonna be71c4ea0b [O] Use the same text style for pie graph 2019-11-09 23:28:46 -05:00
Hykilpikonna 4bd34d46be [O] Separate textStyle to GraphUtils 2019-11-09 23:27:44 -05:00
Hykilpikonna 670ac48516 [O] Use more descriptive title for radar too 2019-11-09 23:23:52 -05:00
Hykilpikonna 4ce7c625ea [O] Use more descriptive title for pie graph 2019-11-09 23:20:22 -05:00
Hykilpikonna 551930f47a [O] Make the center empty 2019-11-09 23:08:05 -05:00
Hykilpikonna 04ca753466 [S] Adjust opacity of the pie areas 2019-11-09 22:58:06 -05:00
Hykilpikonna 4169d5235a [S] Add drop shadow 2019-11-09 22:57:03 -05:00
Hykilpikonna c417698bf2 [S] Adjust y position of pie graph 2019-11-09 22:53:22 -05:00
Hykilpikonna b6bf6373f2 [S] Reduce radius 2019-11-09 22:53:10 -05:00
Hykilpikonna f4326cf9e1 [O] Better label alignment 2019-11-09 22:53:01 -05:00
Hykilpikonna cca9d5a240 [O] Adjust to correct color after sorting 2019-11-09 22:52:52 -05:00
Hykilpikonna 0af3cee18b [O] Sort pie chart data 2019-11-09 22:51:06 -05:00
Hykilpikonna 8d122f0100 [+] Show type name 2019-11-09 22:45:55 -05:00
Hykilpikonna 62373485f5 [O] Use percentage as weight 2019-11-09 22:45:40 -05:00
Hykilpikonna 472d83e9fb [S] Adjust height 2019-11-09 22:44:22 -05:00
Hykilpikonna 34231dc480 [+] Generate pie data 2019-11-09 22:38:36 -05:00
Hykilpikonna 3f6c9c1204 [O] Round weight to 2 digits 2019-11-09 22:38:22 -05:00
Hykilpikonna d0e627bd83 [O] Change title 2019-11-09 22:33:56 -05:00
Hykilpikonna 6e4074b050 [+] Add a type-pie to course-page 2019-11-09 22:30:45 -05:00
Hykilpikonna 963df01b6f [+] Create pie graph component 2019-11-09 22:29:19 -05:00
Hykilpikonna c807d4aecb [-] Remove unused css section 2019-11-09 22:28:40 -05:00
Hykilpikonna e2c9d05a7e [M] Rename type-radar directory too 2019-11-09 22:26:13 -05:00
Hykilpikonna 6204efd453 [U] Release v0.4.3.1006 2019-11-09 22:15:31 -05:00
Hykilpikonna db083732b0 [M] Rename course-type-radar to type-radar 2019-11-09 22:14:41 -05:00
Hykilpikonna 4974049c0b [S] Make background lighter 2019-11-09 22:11:02 -05:00
Hykilpikonna 857192ee6d [S] Add text shadows 2019-11-09 22:10:45 -05:00
Hykilpikonna 90d07b1faa [S] Make font size larger 2019-11-09 22:10:33 -05:00
Hykilpikonna 4abe02da94 [+] Color the indicator texts 2019-11-09 22:10:16 -05:00
Hykilpikonna adca4b41e2 [+] Add percent score after indicator 2019-11-09 22:10:08 -05:00
Hykilpikonna 4d9d8e0be5 [S] Darken line color 2019-11-09 21:58:39 -05:00
Hykilpikonna 546ad81f7c [+] Colorize split area 2019-11-09 21:58:23 -05:00
Hykilpikonna 1eff27ad26 [S] Center color gradient 2019-11-09 21:49:40 -05:00
Hykilpikonna f540e03a56 [S] Adjust the graph down 10% 2019-11-09 21:47:34 -05:00
Hykilpikonna af925741b4 [S] Make graph smaller 2019-11-09 21:47:18 -05:00
Hykilpikonna 08bb24cac4 [O] Use percentage score instead of score 2019-11-09 21:47:06 -05:00
Hykilpikonna 8a9ca83e68 [O] Optimize graph with baseSettings 2019-11-09 21:46:47 -05:00
Hykilpikonna e6b6a73f1f [O] Optimize type adverage with pre-calculated percent 2019-11-09 21:35:18 -05:00
Hykilpikonna ceca351b07 [+] Include percent score in AssignmentType 2019-11-09 21:34:28 -05:00
Hykilpikonna 4e14730db6 [S] Change the graph symbol to circle 2019-11-09 21:24:13 -05:00
Hykilpikonna 3b0e291df4 [S] Make radar only take half the screen 2019-11-09 21:23:54 -05:00
Hykilpikonna 6bcb2577f7 [+] Add area gradient 2019-11-09 21:23:34 -05:00
Hykilpikonna 54e54b89e9 [+] Display tooltip 2019-11-09 21:23:14 -05:00
Hykilpikonna 0085d384fd [+] Display data in radar graph 2019-11-09 21:23:07 -05:00
Hykilpikonna 3b4e40261f [O] Use scoreMax instead 2019-11-09 21:22:31 -05:00
Hykilpikonna eb8715867e [+] Add radar indicator 2019-11-09 21:03:12 -05:00
Hykilpikonna 1bcfdf5648 [+] Add radar component in course page 2019-11-09 20:55:56 -05:00
Hykilpikonna 429de6553b [+] Create course-type-radar 2019-11-09 20:55:39 -05:00
Hykilpikonna fce47648c8 [O] Remove unnecessary getAssignmentTypes() 2019-11-09 20:45:30 -05:00
Hykilpikonna f6d44dd1f2 [O] Remove unnecessary complete verification 2019-11-09 20:45:12 -05:00
Hykilpikonna 4fe0a54277 [O] Remove unnecessary average() method 2019-11-09 20:44:57 -05:00
Hykilpikonna e8bf21e60c [F] Fix type name display 2019-11-09 20:44:37 -05:00
Hykilpikonna 472df39ac8 [O] Pass in AssignmentType object for AssignmentTypeHead component 2019-11-09 20:44:23 -05:00
Hykilpikonna ae94f54a7b [O] Cache assignment types 2019-11-09 20:39:24 -05:00
Hykilpikonna 8c9f0a0e83 [O] Optimize caching 2019-11-09 20:37:56 -05:00
Hykilpikonna cb22baf120 [+] Calculate type score and weight 2019-11-09 20:33:32 -05:00
Hykilpikonna 0525aae98a [+] Create method to get assignment types 2019-11-09 20:25:18 -05:00
Hykilpikonna 4c87cb2947 [F] Fix null pointer 2019-11-09 20:21:57 -05:00
Hykilpikonna 076a1ee52e [O] Return graded assignments by default 2019-11-09 20:21:09 -05:00
Hykilpikonna 7bd9e97396 [S] Remove ugly circle between data points 2019-11-09 20:05:52 -05:00
Hykilpikonna aa014bcdab [+] Create AssignmentType interface 2019-11-09 19:47:56 -05:00
Hykilpikonna ee308d29ff [S] Optimize x axis label 2019-11-09 19:39:53 -05:00
Hykilpikonna 35ef2144b7 [O] Limit minimum zoom 2019-11-09 19:29:45 -05:00
Hykilpikonna 6dc2a21e8f [+] Add back tooltip 2019-11-09 17:42:03 -05:00
Hykilpikonna 343c921eb2 [+] Add y axis label 2019-11-09 17:40:15 -05:00
Hykilpikonna f54dfba058 [F] Fix scatter plot out of bounds issue 2019-11-09 17:39:58 -05:00
Hykilpikonna a7d7ef44a6 [-] Remove debug output 2019-11-09 17:35:29 -05:00
Hykilpikonna 793d7444b2 [O] Add back the term lines and mark areas 2019-11-09 17:35:22 -05:00
Hykilpikonna eaf4d2ce7b [O] Make y max an integer 2019-11-09 17:32:17 -05:00
Hykilpikonna 79e615ee46 [O] Use graded courses only 2019-11-09 17:31:32 -05:00
Hykilpikonna 40353cfd35 [O] Generate settings on created 2019-11-09 17:31:22 -05:00
Hykilpikonna 2be2ce98e6 [F] Fix date conversion 2019-11-09 17:27:45 -05:00
Hykilpikonna 6659f65763 [F] Fix multiple assignment creating multiple dates issue 2019-11-09 17:19:30 -05:00
Hykilpikonna 5b3ba4db07 [+] Create method to convert data points to date points 2019-11-09 17:11:35 -05:00
Hykilpikonna a05281f4e4 [+] Separate method to generate series 2019-11-09 17:10:54 -05:00
Hykilpikonna 2f95548fb3 [+] Create method to get series for course 2019-11-09 17:10:37 -05:00
Hykilpikonna 96ee9e9265 [O] Default to 2 decimal places 2019-11-09 17:05:06 -05:00
Hykilpikonna 9026b9d3a9 [-] Remove deprecated convertChart() 2019-11-09 17:02:53 -05:00
Hykilpikonna 67e38dd554 [F] Fix tooltip date representation 2019-11-09 16:59:52 -05:00
Hykilpikonna 7ffef67e42 [F] Parse time instead of date 2019-11-09 16:57:12 -05:00
Hykilpikonna 0d195cfb7f [F] Fix invalid date 2019-11-09 16:56:22 -05:00
Hykilpikonna 0d3e9c0840 [O] Remove toChartDate, use timestamp instead 2019-11-09 16:53:53 -05:00
Hykilpikonna 6c600f31f8 [O] Change assignment.date to time 2019-11-09 16:50:48 -05:00
Hykilpikonna a05a44aaef [+] Add assignments.length > 0 as a condition 2019-11-09 16:49:30 -05:00
Hykilpikonna 31d3a5a09e [+] Filter graded courses 2019-11-09 16:48:45 -05:00
Hykilpikonna 30293cd261 [O] Encapsulate method to get graded assignments 2019-11-09 16:31:36 -05:00
Hykilpikonna 9a279b3417 [O] Use afterconfig 2019-11-09 16:24:00 -05:00
Hykilpikonna 4a7ff0ea55 [O] Use base settings in overall-line 2019-11-09 16:23:41 -05:00
Hykilpikonna fd341e9d33 [O] Use basesettings in course-scatter 2019-11-09 16:15:21 -05:00
Hykilpikonna bdacc8dd9e [+] Create function to generate base settings 2019-11-09 16:14:58 -05:00
Hykilpikonna ad2c8a1ee8 [M] Move dot to graph utils 2019-11-09 16:12:44 -05:00
Hykilpikonna 1f58818a1a [S] Dim markline brightness 2019-11-09 16:06:28 -05:00
Hykilpikonna 09442cbfba [+] Add mark areas and lines in scatter plot 2019-11-09 16:05:55 -05:00
Hykilpikonna 91e10d1fa8 [+] Add opacity param to markline generation 2019-11-09 16:05:25 -05:00
Hykilpikonna 80267feb54 [O] Separate series creation with the main settings 2019-11-09 16:00:57 -05:00
Hykilpikonna f4ee2dadb6 [M] Move markarea to GraphUtils 2019-11-09 15:51:05 -05:00
Hykilpikonna d698f3d13a [M] Move markline stuff to GraphUtils 2019-11-09 15:47:30 -05:00
Hykilpikonna 82cb845061 [S] Make line animation faster 2019-11-09 15:43:53 -05:00
Hykilpikonna 940738307b [F] Fix term 1 graph displaying dates after term 2 2019-11-09 15:41:54 -05:00
Hykilpikonna df011787e1 [S] Change line color 2019-11-09 15:41:12 -05:00
Hykilpikonna 0af393a1e4 [+] Put in actual term dates 2019-11-09 15:37:52 -05:00
Hykilpikonna 6504cc033b [+] Encapsulate method to get term end date 2019-11-09 15:32:25 -05:00
Hykilpikonna c6ccc5e311 [F] Fix: All year graph begins at term 2 2019-11-09 15:28:48 -05:00
Hykilpikonna 3a8899507f [+] Encapsulate method to get begin date of a term 2019-11-09 15:28:21 -05:00
Hykilpikonna 2b7026c4ce [F] Fix: Make starting time not exceed the beginning of a term 2019-11-09 15:24:41 -05:00
Hykilpikonna a3fd822252 [S] Remove quater line arrow symbol 2019-11-09 15:05:57 -05:00
Hykilpikonna f9d7fa398f [+] Add quater line label 2019-11-09 14:59:38 -05:00
Hykilpikonna 7ffc445bba [+] Show quater lines 2019-11-09 14:55:47 -05:00
Hykilpikonna 8e9f6a4bb7 [O] Optimize date data type 2019-11-09 14:55:37 -05:00
Hykilpikonna 05cb560c8c [-] Disable legend 2019-11-09 14:54:35 -05:00
Hykilpikonna 53a57234a0 [-] Remove unused legend 2019-11-09 14:54:02 -05:00
Hykilpikonna 6af6bb0959 [O] Optimize time display 2019-11-09 14:47:32 -05:00
Hykilpikonna 089aad7398 [O] Optimize date formatting 2019-11-09 14:47:22 -05:00
Hykilpikonna 937e89ce5f [M] Move assignment interface from app.ts to course.ts 2019-11-09 14:38:57 -05:00
Hykilpikonna b0685ffd6b [M] Move util classes to /logic 2019-11-09 14:32:45 -05:00
Hykilpikonna 18dee50b96 [F] Force desktop view on mobile devices 2019-11-09 14:32:10 -05:00
Hykilpikonna 8dbef09ec9 [U] Release v0.4.2.912 2019-11-07 22:29:01 -05:00
Hykilpikonna 73b71f56a5 [S] Disable text selecting 2019-11-07 22:26:43 -05:00
Hykilpikonna ce702405d0 [S] Adjust no-grade font size 2019-11-07 22:26:33 -05:00
Hykilpikonna 21744a1bef [F] Fix gpa -1 when no grade issue 2019-11-07 22:26:13 -05:00
Hykilpikonna 82064f2f02 [O] Optimize graph max value 2019-11-07 22:14:46 -05:00
Hykilpikonna adfebc8c44 [F] Fix term 1 displaying term 2 grades issue 2019-11-07 22:00:08 -05:00
Hykilpikonna 2f30e67671 [F] Fix course grade displayed as 0.00 issue 2019-11-07 21:53:16 -05:00
Hykilpikonna 0a80d534eb [O] Optimize imports 2019-11-07 21:48:40 -05:00
Hykilpikonna a77c495843 [S] Further divide marklines 2019-11-07 21:45:34 -05:00
Hykilpikonna 5503aff6b1 [S] Dim marklines a little bit 2019-11-07 21:40:16 -05:00
Hykilpikonna 7cc4567245 [O] Optimize color representation 2019-11-07 21:39:09 -05:00
Hykilpikonna e7f29ad0bf [+] Add mark area below 70 2019-11-07 21:35:45 -05:00
Hykilpikonna cdbd101428 [+] Add mark area from 70 to 80 2019-11-07 21:33:22 -05:00
Hykilpikonna da650ef16b [+] Add mark area from 100 to 80 2019-11-07 21:31:51 -05:00
Hykilpikonna 8abfdd7f8e [+] Add mark area above 100 2019-11-07 21:31:36 -05:00
Hykilpikonna 3c66f99363 [F] Limit graph max value to 120 2019-11-07 20:57:35 -05:00
Hykilpikonna 251f87a072 [F] Fix assignment type update problem 2019-11-06 23:09:32 -05:00
Hykilpikonna e15c95561c [U] Release v0.4.1.895 2019-11-06 22:34:08 -05:00
Hykilpikonna f4ed39401c [S] Emphesize the title more 2019-11-06 22:29:03 -05:00
Hykilpikonna c3fb998254 [S] Set font size 2019-11-06 22:25:03 -05:00
Hykilpikonna d9e9bcc731 [S] Align the average span to the left 2019-11-06 22:24:56 -05:00
Hykilpikonna 110ff6daec [S] Center the average span 2019-11-06 22:24:46 -05:00
Hykilpikonna 7d83344e73 [F] Calculate percent average instead of ratio 2019-11-06 22:19:29 -05:00
Hykilpikonna 06d93398fb [S] Disable unread in courses page 2019-11-06 22:18:44 -05:00
Hykilpikonna b05328888e [M] Rename unread-entry class to assignment-entry 2019-11-06 22:17:25 -05:00
Hykilpikonna 19598f4a10 [+] Add average span 2019-11-06 22:16:59 -05:00
Hykilpikonna cd7102a5df [+] create method to get type average 2019-11-06 22:16:52 -05:00
Hykilpikonna 9bf1f6b624 [O] Optimize assignments filtering 2019-11-06 21:54:41 -05:00
Hykilpikonna f1681ad405 [F] Fix 'selectedTime undefined' 2019-11-06 21:54:11 -05:00
Hykilpikonna e0a70a23b0 [F] Fix: ' Invalid handler for event "command": got undefined' 2019-11-06 21:53:40 -05:00
Hykilpikonna 677dfb491a [+] Parse grading period 2019-11-06 21:50:28 -05:00
Hykilpikonna 07a9b38c8d [+] Add grading period field to app.ts 2019-11-06 21:50:22 -05:00
Hykilpikonna 53b78c4a94 [M] Rename cookie name too 2019-11-06 21:50:06 -05:00
Hykilpikonna 2057f08e40 [M] Rename time selection to grading period 2019-11-06 21:49:17 -05:00
Hykilpikonna 7bc843aa9a [O] Optimize assignments loading with [].map() 2019-11-06 21:41:49 -05:00
Hykilpikonna 0a8855e020 [F] Fix self-referencing error 2019-11-06 21:37:13 -05:00
Hykilpikonna 445d07c5e4 [+] Encapsulate method to get numeric and letter grades 2019-11-06 21:35:34 -05:00
Hykilpikonna 125e7d14de [O] Change letterGrade and numericGrade to raw fields 2019-11-06 21:32:55 -05:00
Hykilpikonna 4917f5cb0c [O] Optimize getGP 2019-11-06 21:32:38 -05:00
Hykilpikonna 2504b37eb7 [O] Also support numeric grade 2019-11-06 21:30:15 -05:00
Hykilpikonna b0d3bf4bd2 [+] Encapsulate method to find scale 2019-11-06 21:28:27 -05:00
Hykilpikonna e640384fd8 [O] Optimize scale list 2019-11-06 21:27:30 -05:00
Hykilpikonna adf7af6b84 [+] Create interface for scale 2019-11-06 21:27:19 -05:00
Hykilpikonna beb4155aab [+] Compare numeric grade with current term grade 2019-11-06 21:17:31 -05:00
Hykilpikonna 3337766ae6 [+] Add current term constant 2019-11-06 21:17:11 -05:00
Hykilpikonna dc135dc78b [+] Encapsulate getPercentTypeAverage 2019-11-06 21:16:47 -05:00
Hykilpikonna b39c51beea [O] getTotalMeanAverage pass in assignments not course 2019-11-06 21:16:31 -05:00
Hykilpikonna 971339e49c [F] Fix assignments order issue 2019-11-06 20:59:12 -05:00
Hykilpikonna 9db0431e96 [O] Use caching to optimize graphs 2019-11-06 20:57:52 -05:00
Hykilpikonna d667f2ab34 [-] Remove temp string 2019-11-06 20:39:58 -05:00
Hykilpikonna 9b895a8fd7 [+] Reload directly when selected time is changed 2019-11-06 20:39:47 -05:00
Hykilpikonna 66d7e18a71 [F] Fix selectedTime initialization issue 2019-11-06 20:30:05 -05:00
Hykilpikonna 4643155908 [+] Add useless string for updating 2019-11-06 20:29:39 -05:00
Hykilpikonna c6c3303a99 [O] Optimize onclick method call 2019-11-06 20:02:41 -05:00
Hykilpikonna 1aea558c40 [+] Store selected time in cookies 2019-11-06 20:02:29 -05:00
Hykilpikonna 316c7e1f63 [F] Fix 'cannot getTime() of undefined' 2019-11-06 20:01:32 -05:00
Hykilpikonna 8364befc91 [F] Fix more type problems 2019-11-06 19:26:41 -05:00
Hykilpikonna 47c25d0e71 [F] Fix imports 2019-11-06 19:23:39 -05:00
Hykilpikonna 422d574c6c [F] Fix term display number offset issue 2019-11-06 19:14:14 -05:00
Hykilpikonna 3400c07e77 [+] Encapsulate method to get assignments of specific time 2019-11-06 19:13:45 -05:00
Hykilpikonna 79bb10b14e [M] Rename assignments to rawAssignments 2019-11-06 19:12:24 -05:00
Hykilpikonna e7563fcfb5 [+] Encapsulate method to get selected time code 2019-11-06 19:11:55 -05:00
Hykilpikonna 43f0046827 [+] Update selected time dynamically 2019-11-06 19:11:41 -05:00
Hykilpikonna ef424dd9e3 [O] Unify time names 2019-11-06 19:11:27 -05:00
Hykilpikonna 37902b6d1f [+] Display selected time dynamically 2019-11-06 19:11:13 -05:00
Hykilpikonna 92e692f69a [O] Remove getGradedCourses 2019-11-06 18:27:19 -05:00
Hykilpikonna b6e0e12cab [+] Add isGraded method to course 2019-11-06 18:25:48 -05:00
Hykilpikonna 6eb7e421e0 [M] Move level detection to course 2019-11-06 18:22:35 -05:00
Hykilpikonna fbb9352546 [O] Move name parsing to course 2019-11-06 18:15:54 -05:00
Hykilpikonna 6f5c4f3a09 [M] Move loadAssignments to course 2019-11-06 18:13:24 -05:00
Hykilpikonna 1e91cec8d2 [O] Create course objects after parsing json 2019-11-06 18:08:47 -05:00
Hykilpikonna 17262e12af [+] Create constructor 2019-11-06 18:05:53 -05:00
Hykilpikonna 56a954c235 [O] Separate course object 2019-11-06 18:03:27 -05:00
Hykilpikonna da5eced769 [F] Fix pushed data duplicate issue 2019-11-06 17:55:10 -05:00
Hykilpikonna 71f2eccab4 [F] Fix filter assignment order issue 2019-11-06 17:54:57 -05:00
Hykilpikonna a5162c1f5b [O] Optimize date usage 2019-11-06 17:38:53 -05:00
Hykilpikonna 53c82fd477 [F] Fix sorting 2019-11-06 17:38:36 -05:00
Hykilpikonna 2867f8d09c [+] Set computed data 2019-11-06 17:26:52 -05:00
Hykilpikonna 5b902171c8 [+] Filter assignments into terms 2019-11-06 17:26:44 -05:00
Hykilpikonna c40c5b6b94 [+] Create computed model in course 2019-11-06 17:26:29 -05:00
Hykilpikonna b66c313b05 [+] Define terms date list 2019-11-06 17:20:09 -05:00
Hykilpikonna 48287cdc4b [O] Sort by date 2019-11-06 17:17:02 -05:00
Hykilpikonna 750c768848 [O] Use Date for date instead of string 2019-11-06 17:16:49 -05:00
Hykilpikonna 4b512d64d9 [+] Add commands to dropdown options 2019-11-06 16:48:43 -05:00
Hykilpikonna e121210e96 [S] Add proper up and down margins 2019-11-06 16:34:08 -05:00
Hykilpikonna 5a87608fa6 [S] Align dropdown to the right 2019-11-06 16:33:59 -05:00
Hykilpikonna e819abe789 [S] Make dropdown button smaller 2019-11-06 16:33:42 -05:00
Hykilpikonna eb718d14d1 [S] Add id to dropdown 2019-11-06 16:33:35 -05:00
Hykilpikonna 564896e940 [+] Create time selection button 2019-11-06 16:29:02 -05:00
Hykilpikonna d91c3875b0 [F] Fix bar graph color problem 2019-11-06 16:18:39 -05:00
Hykilpikonna 1fe2edb9f4 [F] Fix bar graph -1 problem 2019-11-06 16:17:31 -05:00
Hykilpikonna 91977e1226 [S] Change assignment type head font size 2019-11-06 16:06:33 -05:00
Hykilpikonna 948018c7de [F] Fix grade display when no grade exist 2019-11-06 16:06:03 -05:00
Hykilpikonna f2350680c8 [S] Optimize narrow height 2019-11-05 22:57:19 -05:00
Hykilpikonna 4cc424e079 [S] Make percentage score's width unified 2019-11-05 22:57:09 -05:00
Hykilpikonna 49d26fcf61 [S] Make month's width unified 2019-11-05 22:56:51 -05:00
Hykilpikonna 9fde3b21d4 [S] Fix margins when there are no unread 2019-11-05 22:51:47 -05:00
Hykilpikonna 6952649058 [S] Optimize date formatting 2019-11-05 22:51:15 -05:00
Hykilpikonna b12a717cea [S] Move unread property to css class 2019-11-05 22:41:33 -05:00
Hykilpikonna 8e1e222656 [S] Align the scores the same width 2019-11-05 22:39:57 -05:00
Hykilpikonna 8f7775bb69 [O] Reduce height for narrow layout 2019-11-05 22:33:22 -05:00
Hykilpikonna 0477161af2 [+] Create narrow property for class 2019-11-05 22:29:43 -05:00
Hykilpikonna 3b387db5b5 [S] Fix float left alignment issue 2019-11-05 22:24:45 -05:00
Hykilpikonna d85d0e4e36 [S] Align the text to the left 2019-11-05 22:23:25 -05:00
Hykilpikonna b74b086f98 [S] Vertically center the text 2019-11-05 22:23:14 -05:00
Hykilpikonna e1d20b822f [S] Optimize font size and color 2019-11-05 22:22:53 -05:00
Hykilpikonna e98997f230 [S] Specify background color 2019-11-05 18:25:56 -05:00
Hykilpikonna 82e17030d4 [+] Add property for background style 2019-11-05 18:22:44 -05:00
Hykilpikonna d1905ee2b1 [+] Create info div 2019-11-05 18:09:12 -05:00
Hykilpikonna 310b2bcee1 [S] Remove card body padding 2019-11-05 18:07:49 -05:00
Hykilpikonna d55eebce19 [F] Fix: Next course doesn't show up on mobile devices 2019-11-05 18:00:04 -05:00
Hykilpikonna 03507968ee [+] Add assignment entry components 2019-11-05 17:51:36 -05:00
Hykilpikonna 56769e4518 [F] Fix: Filter assignments based on value of type 2019-11-05 17:51:22 -05:00
Hykilpikonna fba589d6fe [+] Display type name 2019-11-05 17:44:16 -05:00
Hykilpikonna ff5b22b5dc [+] Filter assignment type 2019-11-05 17:42:46 -05:00
Hykilpikonna 14de2e0b23 [+] Create assignments property 2019-11-05 17:40:50 -05:00
Hykilpikonna 880e331c99 [F] Fix distinct key for v-for problem 2019-11-05 17:37:42 -05:00
Hykilpikonna cf794588df [-] Reomve duplicate type names 2019-11-05 17:37:29 -05:00
Hykilpikonna d362598d83 [+] Show an assignment type for each type 2019-11-05 17:29:27 -05:00
Hykilpikonna 536e98642d [+] Encapsulate method to get assignment types 2019-11-05 17:28:28 -05:00
Hykilpikonna baae0d088c [+] Add assignment head element in course page 2019-11-05 17:28:18 -05:00
Hykilpikonna 202feb12d7 [+] Create assignment type head vue comp 2019-11-05 17:22:13 -05:00
Hykilpikonna d2ab7c059f [F] Fix clear cookie issue 2019-11-04 16:23:40 -05:00
Hykilpikonna e1ef117dcd [S] Make logo non-clickable 2019-11-03 11:18:35 -05:00
Hykilpikonna fb3186d575 [S] Add shadow effect to logo 2019-11-03 11:18:26 -05:00
Hykilpikonna b913873951 [S] Adjust margin font size 2019-11-03 11:18:01 -05:00
Hykilpikonna bbdcb42316 [S] Adjust title margin size 2019-11-03 11:17:53 -05:00
Hykilpikonna 5438637224 [S] Add the title 2019-11-03 11:17:33 -05:00
Hykilpikonna 970a058ba3 [U] Pre-release v0.3.6.784 2019-11-03 10:44:57 -05:00
Hykilpikonna 5d295db1b7 [O] Add todo: update token each access 2019-11-03 10:43:50 -05:00
Hykilpikonna b22aac7ca2 [F] Fix cookie expiration issue 2019-11-03 10:26:10 -05:00
Hykilpikonna eef29a4611 [U] Add 'Unknown' to graded courses detection 2019-11-02 23:10:58 -04:00
Hykilpikonna 131952ed37 [O] Trim course names 2019-11-02 23:07:13 -04:00
Hykilpikonna 2e95c2550e [+] Create 404 redirection 2019-11-02 23:04:05 -04:00
Hykilpikonna 0db6e0d693 [S] Add some page end margins 2019-11-02 22:58:37 -04:00
Hykilpikonna 27198ad4e0 [U] Use CourseUtils.postProcess() 2019-11-02 22:57:41 -04:00
Hykilpikonna 3cbb6ebee6 [+] Add "HS" clubs to level detection 2019-11-02 22:56:27 -04:00
Hykilpikonna 2308df65b5 [+] Add post process for courses 2019-11-02 22:54:30 -04:00
Hykilpikonna c8f82cc991 [+] Use unknown course list 2019-11-02 22:54:02 -04:00
Hykilpikonna a6e1b905ed [O] Make unknown course list a map 2019-11-02 22:49:49 -04:00
Hykilpikonna 9432e9a806 [+] Create method to detect course level 2019-11-02 22:46:21 -04:00
Hykilpikonna d90280a10f [+] Create unknown course list 2019-11-02 22:46:04 -04:00
Hykilpikonna db30b7f807 [+] Create club constant 2019-11-02 22:45:52 -04:00
Hykilpikonna 20910b1562 [+] Add level constants 2019-11-02 22:18:58 -04:00
Hykilpikonna 5659a049e5 [O] Parse &amp; in course names 2019-11-02 20:41:11 -04:00
Hykilpikonna 085812d859 [+] Create method to parse html text 2019-11-02 20:37:41 -04:00
Hykilpikonna e60a4669ac [F] Fix execution order problem 2019-11-02 20:21:26 -04:00
Hykilpikonna ac84907a98 [F] Update index only after loading 2019-11-02 20:20:09 -04:00
Hykilpikonna 04ee69e8e2 [F] Fix clickable required issue 2019-11-02 20:12:14 -04:00
Hykilpikonna a2445aca6a [F] Fix path reading issue 2019-11-02 20:11:39 -04:00
Hykilpikonna 336a58b23d [O] Move course head scss to separate file 2019-11-02 20:02:06 -04:00
Hykilpikonna 5a5cf9bd4d [O] Replace more ts-ignores with {required: true} 2019-11-02 20:00:19 -04:00
Hykilpikonna 44d262f457 [O] Inline course-page.ts 2019-11-02 19:58:25 -04:00
Hykilpikonna 27fda43373 [O] Inline overall.ts 2019-11-02 19:56:01 -04:00
Hykilpikonna b3de3b8405 [+] Only show mark as read if it is unread 2019-11-02 19:45:30 -04:00
Hykilpikonna 633918aa40 [U] Pass in unread value 2019-11-02 19:45:11 -04:00
Hykilpikonna 3bc59e87d3 [O] Inline assignment entry ts script 2019-11-02 19:41:55 -04:00
Hykilpikonna af7d9e9dca [+] Add unread prop to assignment entry 2019-11-02 19:40:26 -04:00
Hykilpikonna 3b8884dc84 [O] Optimize imports 2019-11-02 19:39:33 -04:00
Hykilpikonna 92158684c0 [-] Remove unnecessary ts-ignores 2019-11-02 19:38:45 -04:00
Hykilpikonna b37de9cf24 [O] Disable strict property initialization check 2019-11-02 19:37:13 -04:00
Hykilpikonna cd2dff5559 [M] Rename unread-entry to assignment-entry 2019-11-02 19:35:04 -04:00
Hykilpikonna d6a85af15c [O] Use relative date for starting value 2019-11-02 19:24:51 -04:00
Hykilpikonna 0d333879ca [O] Put login in a form 2019-11-02 19:08:02 -04:00
Hykilpikonna 905db3c73a [-] Remove debug logging 2019-11-02 19:04:56 -04:00
Hykilpikonna c5dfad8be8 [F] Remove trapezoid effect for mobile support 2019-11-02 19:03:35 -04:00
Hykilpikonna c9454a3832 [-] Remove todos that are done 2019-11-02 19:02:38 -04:00
Hykilpikonna c732d475f1 [O] Log when cookies doesn't exist 2019-10-23 20:20:54 -04:00
Hykilpikonna a4b7e0fd46 [O] Only clear cookies if cookies exists 2019-10-23 20:20:41 -04:00
Hykilpikonna bcee069b32 [F] Fix url index issue 2019-10-21 19:23:41 -04:00
Hykilpikonna 182208f8c3 [F] Fix Github Pages sub path issue by using # after url 2019-10-21 19:23:31 -04:00
Hykilpikonna 24befed17b [U] Pre-Release v0.3.6.741 2019-10-20 22:00:35 -04:00
Hykilpikonna 07991b2a0e [F] Update title after history 2019-10-20 21:59:11 -04:00
Hykilpikonna 51ea0c7a80 [+] Update title when updating history 2019-10-20 21:56:00 -04:00
Hykilpikonna 8b01428208 [+] Create function to find title 2019-10-20 21:55:39 -04:00
Hykilpikonna f69e2617d4 [+] Encapsulate toTitleCase() 2019-10-20 21:55:13 -04:00
Hykilpikonna ddfdb47b93 [+] Encapsulate findCourse 2019-10-20 21:49:51 -04:00
Hykilpikonna 14849f4211 [O] Move updateIndex logging to a better place 2019-10-20 21:42:44 -04:00
Hykilpikonna 067c599cb1 [F] Fix history pop state override issue 2019-10-20 21:42:18 -04:00
Hykilpikonna 33ceaa38c0 [O] Use Navigation.updateIndex instead 2019-10-20 21:39:08 -04:00
Hykilpikonna 0a0288c2ee [+] Make updateIndex public 2019-10-20 21:38:20 -04:00
Hykilpikonna 90f888bc4b [+] Add instance to navigation 2019-10-20 21:38:11 -04:00
Hykilpikonna 9bb34fb2a4 [O] Make course operations unselectable 2019-10-20 21:34:13 -04:00
Hykilpikonna 22b75a6b30 [+] Add .unselectable to global css 2019-10-20 21:33:43 -04:00
Hykilpikonna 6af8410698 [F] Fix logic mistake 2019-10-20 21:32:30 -04:00
Hykilpikonna f023c724fa [O] Don't update history for initial update 2019-10-20 21:31:22 -04:00
Hykilpikonna 6bbbe9cece [O] Encapsulate update history in updateIndex() 2019-10-20 21:31:05 -04:00
Hykilpikonna e6a4a04bb4 [+] Only show next course when next course isn't null 2019-10-20 21:27:42 -04:00
Hykilpikonna 5c4a391d96 [O] Add jsdocs for findNextCourse 2019-10-20 21:23:53 -04:00
Hykilpikonna a75b15d840 [O] Separate findNextCourse() and nextCourse() 2019-10-20 21:23:29 -04:00
Hykilpikonna 1322bd6326 [O] Adjust opacity 2019-10-20 21:21:47 -04:00
Hykilpikonna e2997c345c [F] Fix null case 2019-10-20 21:20:39 -04:00
Hykilpikonna 923a7e824f [O] Add drop shadows 2019-10-20 21:19:18 -04:00
Hykilpikonna 10ac0b5330 [O] Separate padding from common css 2019-10-20 21:16:10 -04:00
Hykilpikonna bfeba9da40 [O] Put prev-course under navbar 2019-10-20 21:15:56 -04:00
Hykilpikonna 752a865334 [O] Align prev-course upward 2019-10-20 21:14:36 -04:00
Hykilpikonna 5eda771070 [M] Move common css properties to common class 2019-10-20 21:13:51 -04:00
Hykilpikonna 0826080f82 [O] Add css class to both course operations 2019-10-20 21:13:15 -04:00
Hykilpikonna 6fab785a49 [+] Add previous course div 2019-10-20 21:11:03 -04:00
Hykilpikonna ecbcca5f14 [+] Add index offset to nextCourse() 2019-10-20 21:10:53 -04:00
Hykilpikonna 861de56f10 [O] Make cursor a pointer 2019-10-20 21:02:39 -04:00
Hykilpikonna 3ce66e1201 [+] Implement next course 2019-10-20 21:01:53 -04:00
Hykilpikonna 7e8ea73363 [O] Make it a trapezoid with rotateX 2019-10-20 20:56:51 -04:00
Hykilpikonna 9142525d21 [O] Adjust width 2019-10-20 20:56:13 -04:00
Hykilpikonna 62577ff1bb [O] Add padding 2019-10-20 20:56:06 -04:00
Hykilpikonna 953556ccee [O] Reduce font size 2019-10-20 20:51:47 -04:00
Hykilpikonna cc8621f304 [O] Add background 2019-10-20 20:51:41 -04:00
Hykilpikonna baae26d244 [O] Bottom align and center 2019-10-20 20:51:32 -04:00
Hykilpikonna cbf70cbeef [+] Create next course div in navbar 2019-10-20 20:48:18 -04:00
Hykilpikonna 1e28191e67 [U] Pre-Release v0.3.5.703 2019-10-20 20:27:46 -04:00
Hykilpikonna ef4d9d38e7 [O] Add '%' sign 2019-10-20 20:26:57 -04:00
Hykilpikonna 52626406bf [O] Use FormatUtils.limit 2019-10-20 20:26:18 -04:00
Hykilpikonna fec6c77dc2 [+] Create method to format string length 2019-10-20 20:23:47 -04:00
Hykilpikonna 4db8ee7837 [+] Add tooltip formatter 2019-10-20 20:20:58 -04:00
Hykilpikonna 9bfde0e39d [+] Add assignment description to the data 2019-10-20 20:20:45 -04:00
Hykilpikonna cfac8493cd [U] Pre-Release v0.3.5.697 2019-10-20 19:54:57 -04:00
Hykilpikonna 0d003a4f7e [O] Make new update clickable as well 2019-10-20 19:53:56 -04:00
Hykilpikonna 106a4759ae [O] Make clickable text cursor show as pointer 2019-10-20 19:53:42 -04:00
Hykilpikonna 06d09220c5 [O] Move clickable to global css 2019-10-20 19:46:19 -04:00
Hykilpikonna a19960b18f [O] Do nothing if not clickable 2019-10-20 19:44:06 -04:00
Hykilpikonna 656dd7d884 [+] Implement redirect on click in course-head 2019-10-20 19:42:06 -04:00
Hykilpikonna b965859537 [U] Use formatCourseIndex() in navigation 2019-10-20 19:41:50 -04:00
Hykilpikonna 707e96d2e9 [+] Encapsulate method to format course tab index 2019-10-20 19:41:28 -04:00
Hykilpikonna ab795674b2 [+] Add instance in App class 2019-10-20 19:36:38 -04:00
Hykilpikonna eb74feb659 [+] Create onClick function in course-head 2019-10-20 19:33:51 -04:00
Hykilpikonna 4b4c49b5c7 [+] Make courses in overall clickable 2019-10-20 19:29:52 -04:00
Hykilpikonna 1c134e02f9 [+] Add clickable prop to course-head 2019-10-20 19:29:18 -04:00
Hykilpikonna 85305f987f [O] Optimize course-head grid distribution 2019-10-20 19:23:12 -04:00
Hykilpikonna ec6e2b8c7e [F] Fix logical mistake 2019-10-20 19:22:55 -04:00
Hykilpikonna ab34435395 [U] Use VersionUtils.compare() in Login class 2019-10-20 19:17:21 -04:00
Hykilpikonna da96d846eb [+] Create function to compare version numbers 2019-10-20 19:11:22 -04:00
Hykilpikonna 9f6cb2658a [+] Create VersionUtils class 2019-10-20 19:00:47 -04:00
Hykilpikonna 33402012b6 [-] Remove deprecated file 2019-10-20 19:00:04 -04:00
Hykilpikonna 97cf1651f9 [+] Add MIN_SUPPORTED_VERSION 2019-10-20 18:59:26 -04:00
Hykilpikonna 97bfe69986 [O] Add logging before clearing cookies 2019-10-20 18:55:05 -04:00
Hykilpikonna b08fd7f433 [U] Use needToUpdateCookies() to check 2019-10-20 18:54:52 -04:00
Hykilpikonna 83c6a690ec [O] Optimize variable name lengths 2019-10-20 18:53:21 -04:00
Hykilpikonna cb54ae4dee [+] Create function to check version number 2019-10-20 18:53:03 -04:00
Hykilpikonna be2dcbf085 [O] Extend token saving period 2019-10-20 18:44:56 -04:00
Hykilpikonna 4df2726b95 [O] Make the chart full width (for now) 2019-10-20 18:40:35 -04:00
Hykilpikonna aa78e850bb [O] Adjust graph size 2019-10-20 18:39:50 -04:00
Hykilpikonna c05f18c12c [O] Add drop shadow 2019-10-20 18:38:16 -04:00
Hykilpikonna b4041a11a0 [O] Add cross tooltip pointer 2019-10-20 18:31:43 -04:00
Hykilpikonna bcf222a38b [O] Format x axis dates to MMM DD format 2019-10-20 18:28:07 -04:00
Hykilpikonna 7cfe928fcc [O] Adjust y label position 2019-10-20 18:25:12 -04:00
Hykilpikonna b5ad7c12e3 [O] Add '%' signs to y axis labels 2019-10-20 18:24:33 -04:00
Hykilpikonna 6286c5736e [O] Lighten legend label color 2019-10-20 18:20:35 -04:00
Hykilpikonna 0773d3ef0e [O] Make legend smaller 2019-10-20 18:20:21 -04:00
Hykilpikonna 7b912a9325 [O] Make title larger 2019-10-20 18:20:09 -04:00
Hykilpikonna 008155fa61 [O] Adjust legend icon width 2019-10-20 18:16:42 -04:00
Hykilpikonna 117cd9f568 [O] Adjust legend position 2019-10-20 18:16:15 -04:00
Hykilpikonna 3b14727f81 [O] Remove x axis name 2019-10-20 18:15:13 -04:00
Hykilpikonna 444a3733bd [O] Align legend to the bottom 2019-10-20 18:14:09 -04:00
Hykilpikonna de63ff9bb5 [+] Add legend 2019-10-20 18:13:56 -04:00
Hykilpikonna 2b2a4c59a8 [O] Adjust y-axis label position 2019-10-20 18:11:47 -04:00
Hykilpikonna 30f737bd7c [O] Center align y-axis label 2019-10-20 18:10:39 -04:00
Hykilpikonna 1e2c6ca66f [O] Make min x value of course-scatter a whole number 2019-10-20 18:04:43 -04:00
Hykilpikonna 7b13716ce3 [O] Make min x value of overall-line a whole number 2019-10-20 18:04:00 -04:00
Hykilpikonna 7a1b21a2ac [F] Fake course object usage to update computed value when tab switched 2019-10-20 17:36:12 -04:00
Hykilpikonna 2345bb6442 [F] Show only completed assignments 2019-10-20 17:30:00 -04:00
Hykilpikonna 47fd9e1db3 [O] Set max x value as today 2019-10-20 17:28:11 -04:00
Hykilpikonna f8eee081b3 [O] Adjust x axis label position 2019-10-20 17:26:28 -04:00
Hykilpikonna 84e0647c35 [O] Display x axis name 2019-10-20 17:23:22 -04:00
Hykilpikonna 60804dd98c [O] Add tooltip to scatter graph 2019-10-20 17:23:04 -04:00
Hykilpikonna 5789fac985 [-] Remove unnecessary :entend tag 2019-10-20 17:14:03 -04:00
Hykilpikonna 2a89c6316f [O] Override VE chart settings 2019-10-20 17:13:48 -04:00
Hykilpikonna 4c0a26a900 [-] Remove unused notification class 2019-10-20 17:02:22 -04:00
Hykilpikonna 6915617980 [+] Add inner top shadow to course card content 2019-10-20 17:01:58 -04:00
Hykilpikonna 0a09e14021 [-] Remove the todo 2019-10-20 16:58:48 -04:00
Hykilpikonna 34446494a9 [O] Round data 2019-10-20 13:06:30 -04:00
Hykilpikonna 8477c2f63b [O] Use percent score instead of 0 to 1 2019-10-20 13:00:52 -04:00
Hykilpikonna 105d1f7619 [+] Define colors 2019-10-20 12:59:32 -04:00
Hykilpikonna a4be712bd7 [F] Format date so that the chart can read it 2019-10-20 12:58:30 -04:00
Hykilpikonna 3a9a65920e [F] Use Array.from instead of map.forEach 2019-10-20 12:58:03 -04:00
Hykilpikonna ff62847758 [+] Debug with afterConfig() 2019-10-20 12:57:40 -04:00
Hykilpikonna 0207f617c2 [O] Optimize code format 2019-10-20 12:40:00 -04:00
Hykilpikonna 5c530952d3 [O] Add more colors 2019-10-20 12:39:46 -04:00
Hykilpikonna bdcefefd92 [O] Map assignments first 2019-10-20 12:12:25 -04:00
Hykilpikonna 68cebfa68c [O] Show tooltip 2019-10-20 12:12:00 -04:00
Hykilpikonna 94b337e772 [O] Change title of the chart 2019-10-20 12:06:39 -04:00
Hykilpikonna fd1f6223c0 [F] Fix date format 2019-10-20 12:06:29 -04:00
Hykilpikonna 0d86e461cd [+] Create function to format chart date 2019-10-20 12:03:01 -04:00
Hykilpikonna 9f06748b63 [+] Create format-utils 2019-10-20 11:59:41 -04:00
Hykilpikonna 9769fca6af [O] Label x and y axis 2019-10-20 11:57:37 -04:00
Hykilpikonna 416ef0991d [O] Make the x axis type time 2019-10-20 11:57:19 -04:00
Hykilpikonna 2150a563eb [F] Fix null case detection 2019-10-20 11:47:40 -04:00
Hykilpikonna 1ef08c17ec [F] Fix typo: 'course' instead of 'courses' 2019-10-20 11:46:34 -04:00
Hykilpikonna 15e375900c [+] Complete series 2019-10-20 11:45:42 -04:00
Hykilpikonna d70d54d3f7 [+] Create function to convert assignments to series data 2019-10-20 11:45:35 -04:00
Hykilpikonna 0159f639d2 [O] Optimize type with Map<string, Assignment[]> 2019-10-20 11:40:09 -04:00
Hykilpikonna 19d03536b5 [O] Specify return type 2019-10-20 11:36:35 -04:00
Hykilpikonna 214a716f16 [O] Clarify format in jsdocs 2019-10-20 11:35:11 -04:00
Hykilpikonna 1f5ecedf9f [+] Create function to map assignments 2019-10-20 11:34:48 -04:00
Hykilpikonna 3b52dab371 [+] Add course-scatter component to course-page 2019-10-20 09:53:01 -04:00
Hykilpikonna 40340a0abd [F] Fix "This dependency is not found" 2019-10-20 09:52:41 -04:00
Hykilpikonna c2311464f0 [+] Import course-scatter 2019-10-20 09:52:03 -04:00
Hykilpikonna f4f6fa2523 [+] Create course scatter vue component 2019-10-20 09:51:13 -04:00
Hykilpikonna 44d01eaec0 [O] Remove max height limit for course page 2019-10-20 09:48:30 -04:00
Hykilpikonna 300ff04f2e [F] Fix empty pathname detection with '/' 2019-10-14 22:14:46 -04:00
Hykilpikonna 6a34e9f706 [+] Add todo text 2019-10-14 22:13:22 -04:00
Hykilpikonna 97c8953dbd [-] Remove unnecessary overall-line.scss 2019-10-14 22:10:05 -04:00
Hykilpikonna 179d0bc567 [O] Make it scoped 2019-10-14 22:09:04 -04:00
Hykilpikonna 2d1242f3c0 [O] Inline overall-bar scss 2019-10-14 22:08:51 -04:00
Hykilpikonna b7f7e168b9 [O] Make css in unread-entry scoped 2019-10-14 22:07:47 -04:00
Hykilpikonna 83244ec496 [O] Make the css in overall-course and course-page scoped 2019-10-14 22:06:22 -04:00
Hykilpikonna eb3221fa4b [M] Move card padding to global css 2019-10-14 22:06:00 -04:00
Hykilpikonna 4e37ca4c44 [+] Add row on the expansion area 2019-10-14 21:36:57 -04:00
Hykilpikonna ae6172068e [+] Make course-page almost the same with overall-course 2019-10-14 21:35:55 -04:00
Hykilpikonna 65134c02af [+] Import course-head in course-page 2019-10-14 21:34:30 -04:00
Hykilpikonna fa9e1aae7c [O] Fix ' and " issue 2019-10-14 21:31:21 -04:00
Hykilpikonna 3d1401e1c2 [+] Add course-head element in overall-course 2019-10-14 20:33:25 -04:00
Hykilpikonna 8c102f5d5f [M] Move css to course-head 2019-10-14 20:33:05 -04:00
Hykilpikonna c4e1790444 [+] Import course-head in overall-course 2019-10-14 20:27:25 -04:00
Hykilpikonna 68c1fa1216 [M] Separate course-head from overall-course 2019-10-14 20:27:07 -04:00
Hykilpikonna eb094be9af [F] Move global css outside of overall scope 2019-10-14 20:26:13 -04:00
Hykilpikonna 8527e9860d [O] Make overall.scss scoped 2019-10-14 19:35:16 -04:00
Hykilpikonna ceb1ed1404 [O] Surround the course with a card 2019-10-14 19:34:12 -04:00
Hykilpikonna 968fa63f51 [O] Make course name font size 36px 2019-10-14 19:09:55 -04:00
Hykilpikonna 2d530d204e [O] Align text to the left 2019-10-14 19:08:21 -04:00
Hykilpikonna 65efde05ee [O] Add some margins 2019-10-14 19:08:12 -04:00
Hykilpikonna a5d261ac93 [+] Use grid to display basic info 2019-10-14 19:01:17 -04:00
Hykilpikonna b61cd3839a [O] Move v-if assignmentReady detection up an element 2019-10-14 18:45:01 -04:00
Hykilpikonna 665567bf88 [+] Bind the displayed course to the course page 2019-10-14 18:28:37 -04:00
Hykilpikonna a074a9fbed [+] Show course page only if select tab is a course 2019-10-14 18:27:37 -04:00
Hykilpikonna 0e30954f6e [+] Add course page 2019-10-14 18:27:09 -04:00
Hykilpikonna 0e98cffc64 [+] Update initial index 2019-10-14 18:26:26 -04:00
Hykilpikonna e7d5e766e3 [+] Add default path name when there are none 2019-10-14 18:02:02 -04:00
Hykilpikonna 88b0ef752c [+] Dynamically initialize first state based on pathname 2019-10-14 18:01:43 -04:00
Hykilpikonna 1a8fc9eab4 [-] Remove duplicate update 2019-10-14 17:57:56 -04:00
Hykilpikonna 76dd8f73e4 [O] Use updateIndex() instead 2019-10-14 17:57:43 -04:00
Hykilpikonna 4807c4babb [+] Encapsulate method to update index 2019-10-14 17:57:18 -04:00
Hykilpikonna 9b4f5291f0 [O] Use v-bind.sync to sync variable value 2019-10-14 17:57:04 -04:00
Hykilpikonna 5edc4c55f5 [-] Remove testing log 2019-10-14 16:43:21 -04:00
Hykilpikonna 563bf06b8e [-] Remove onNavigate event 2019-10-14 16:42:38 -04:00
Hykilpikonna cdaa2679d1 [M] Move pushState to navigation.ts as well 2019-10-14 16:42:09 -04:00
Hykilpikonna 4efac6023f [O] Bind activeIndex with selectedTab 2019-10-14 16:40:41 -04:00
Hykilpikonna c6e3806024 [M] Move history stuff to navigation.ts 2019-10-14 16:40:27 -04:00
Hykilpikonna e3df5b8e3b [+] Create history state listener 2019-10-14 16:35:00 -04:00
Hykilpikonna 5afc0aebd5 [+] Set state on start 2019-10-14 16:34:39 -04:00
Hykilpikonna d23446b409 [F] Push state after updating tab 2019-10-14 16:33:41 -04:00
Hykilpikonna bc63b457d3 [+] Clarify logging 2019-10-14 16:24:20 -04:00
Hykilpikonna 30a8d62402 [+] Keep last selected tabb 2019-10-14 16:23:16 -04:00
Hykilpikonna 349683de24 [F] Use absolute path for history 2019-10-14 09:40:18 -04:00
Hykilpikonna 06db7f48bd [F] Fix: can't replace all with replace() 2019-10-14 09:38:36 -04:00
Hykilpikonna 986a38d81d [O] Replace spaces in course name with '-' 2019-10-14 09:37:55 -04:00
Hykilpikonna 8b7ee75ca7 [+] Add course id to the navigation index 2019-10-14 09:36:37 -04:00
Hykilpikonna f59bed777b [O] Use all lowercase for course navigation 2019-10-14 09:36:02 -04:00
Hykilpikonna 87634f0df5 [+] Push history state on navigation 2019-10-14 09:32:19 -04:00
Hykilpikonna bb618e74c9 [+] Import course page in app 2019-10-14 09:31:54 -04:00
Hykilpikonna 92d2a7673b [O] Make text lighter 2019-10-13 22:25:48 -04:00
Hykilpikonna 232fe43eb5 [O] Add gradient to loading screen 2019-10-13 22:24:50 -04:00
Hykilpikonna d02cfe0557 [U] Release v0.3.4.561 2019-10-13 21:48:33 -04:00
Hykilpikonna aca0b5635b [+] Show error for assignments and grading too 2019-10-13 21:46:34 -04:00
Hykilpikonna 4e8d3aaeb9 [O] Fix line gap 2019-10-13 21:36:37 -04:00
Hykilpikonna 1c097b639a [O] Reverse dynamic font size 2019-10-13 21:36:28 -04:00
Hykilpikonna ed80b3c82b [O] Separate details and error details 2019-10-13 21:35:52 -04:00
Hykilpikonna 1a59e174ae [O] Make color class red (pink) 2019-10-13 21:31:21 -04:00
Hykilpikonna bbca7c2e14 [F] Should be class instead of style 2019-10-13 21:31:08 -04:00
Hykilpikonna 5c09490d5e [O] Dynamically add error class 2019-10-13 21:28:16 -04:00
Hykilpikonna ba9b24a276 [O] Encapsulate error message function 2019-10-13 21:28:04 -04:00
Hykilpikonna 755b61efe3 [O] Only show spinner if not error 2019-10-13 21:25:17 -04:00
Hykilpikonna 75d6d94757 [+] Switch title to 'Error' dynamically 2019-10-13 21:25:01 -04:00
Hykilpikonna a00285b38a [+] Bind loadingError variable 2019-10-13 21:23:32 -04:00
Hykilpikonna b529aa070a [O] Show error on http error too 2019-10-13 21:21:48 -04:00
Hykilpikonna 38d7b75831 [+] Encapsulate showError function 2019-10-13 21:20:45 -04:00
Hykilpikonna c3b81b5828 [+] Display error after course failed to load 2019-10-13 21:18:57 -04:00
Hykilpikonna 8aae753098 [+] Add loadingError field 2019-10-13 21:18:39 -04:00
Hykilpikonna 382a2aeabc [+] Add error property 2019-10-13 21:15:42 -04:00
Hykilpikonna ec056ef3b3 [+] Remove loading when it's done loading 2019-10-13 21:13:39 -04:00
Hykilpikonna 96d3e6b620 [O] Dynamically size entries based on index 2019-10-13 21:12:32 -04:00
Hykilpikonna 85f59a3983 [+] Add <br> every line 2019-10-13 21:07:50 -04:00
Hykilpikonna 71035ab87b [-] Remove unused pre css 2019-10-13 21:07:29 -04:00
Hykilpikonna bfd91af873 [O] Use span instead of pre 2019-10-13 21:07:17 -04:00
Hykilpikonna de5d406362 [O] Display loading line by line 2019-10-13 21:06:52 -04:00
Hykilpikonna 8c8f405aa5 [+] Add method to split loading messages 2019-10-13 21:03:58 -04:00
Hykilpikonna a59f2e6f7c [+] Log loading before checking grading 2019-10-13 21:02:46 -04:00
Hykilpikonna 5d06ee1c41 [+] Log loading before loading assignments 2019-10-13 21:02:38 -04:00
Hykilpikonna b818420df7 [+] Log loading before loading courses 2019-10-13 21:02:32 -04:00
Hykilpikonna dbe9c69771 [+] Log loading before login 2019-10-13 21:02:17 -04:00
Hykilpikonna 3a58699f62 [O] Fix <pre> tag font 2019-10-13 21:01:53 -04:00
Hykilpikonna f5804c3ce8 [O] Surround text with <pre> tag 2019-10-13 20:59:30 -04:00
Hykilpikonna 5ef7083ee6 [M] Move font-family to theme variable 2019-10-13 20:59:10 -04:00
Hykilpikonna 25370ec412 [+] Create function to log loading 2019-10-13 20:52:12 -04:00
Hykilpikonna b55c25aa7c [O] Hide loading on start because of the login screen 2019-10-13 20:48:17 -04:00
Hykilpikonna 9f68ac8377 [O] Only show loading when loading text is not empty 2019-10-13 20:46:46 -04:00
Hykilpikonna 335cde4d4e [+] Use actual loading text 2019-10-13 20:46:28 -04:00
Hykilpikonna 878b8cf87c [O] Inline loading script 2019-10-13 20:45:03 -04:00
Hykilpikonna 283904d976 [O] Align loading message to bottom 2019-10-13 20:43:52 -04:00
Hykilpikonna 11dea5182b [O] Make details color darker 2019-10-13 20:39:45 -04:00
Hykilpikonna 87f8f49c39 [O] Correct spinner alignments 2019-10-13 20:38:44 -04:00
Hykilpikonna 595033b80f [O] Make the stroke white 2019-10-13 20:37:21 -04:00
Hykilpikonna ccd32ed7e6 [+] Add a loading spinner 2019-10-13 20:35:53 -04:00
Hykilpikonna a40e3b24eb [O] Make details font size smaller 2019-10-13 20:35:41 -04:00
Hykilpikonna 6a4ff9b0a7 [O] Make title font size bigger 2019-10-13 20:35:27 -04:00
Hykilpikonna 2dfb0bf447 [+] Add loading title 2019-10-13 20:35:16 -04:00
Hykilpikonna 21e6352ace Revert "[-] Remove loading"
This reverts commit f1089dbdf5.
2019-10-13 20:29:45 -04:00
Hykilpikonna f1089dbdf5 [-] Remove loading 2019-10-13 20:29:02 -04:00
Hykilpikonna e95efbff59 [O] Center text box vertically 2019-10-13 20:00:10 -04:00
Hykilpikonna 92b46baeed [O] Center text horizontally 2019-10-13 19:59:59 -04:00
Hykilpikonna d45fce6506 [+] Add a loading component in html for testing 2019-10-13 19:43:30 -04:00
Hykilpikonna e4374a6731 [+] Add loading to app 2019-10-13 19:43:11 -04:00
Hykilpikonna cd402c4b86 [O] Make text color white 2019-10-13 19:42:56 -04:00
Hykilpikonna 25bf445582 [O] Darken loading background 2019-10-13 19:42:47 -04:00
Hykilpikonna 74287289e0 [O] Center loading screen 2019-10-13 19:42:33 -04:00
Hykilpikonna cc23f8565a [+] Create loading overlay 2019-10-13 19:42:17 -04:00
Hykilpikonna a537ced0d7 [O] Optimize isAssignmentsReady() 2019-10-13 19:11:38 -04:00
Hykilpikonna 797d962e40 [O] Optimize isGradingReady() with Array.every() 2019-10-13 19:09:55 -04:00
Hykilpikonna 992be72d8d [+] Create course page 2019-10-13 18:56:06 -04:00
Hykilpikonna 375712c0a8 [F] Fix logic error 2019-10-13 18:32:24 -04:00
Hykilpikonna 0b7ab5923c [+] Add version control to cookies 2019-10-13 18:23:36 -04:00
Hykilpikonna d077818508 [F] Make corrections after reverts 2019-10-13 18:23:25 -04:00
Hykilpikonna c991b75384 [-] Revert "[+] Save username to cookies on login"
This reverts commit 5441592d68.
2019-10-13 18:03:18 -04:00
Hykilpikonna 9f59f517b5 [-] Revert "[+] Return username with token"
This reverts commit e28f68aae3.
2019-10-13 18:03:05 -04:00
Hykilpikonna 6654f78486 [-] Revert "[+] Create token interface"
This reverts commit 353a623e5f.
2019-10-13 18:02:45 -04:00
Hykilpikonna 206fef682f [-] Revert "[U] Update http-utils to use token.token"
This reverts commit 543b0ddefe.
2019-10-13 18:02:12 -04:00
Hykilpikonna 3e454423a1 [-] Revert "[U] Also include username when posting request"
This reverts commit 6607afc898.
2019-10-13 18:02:00 -04:00
Hykilpikonna 8326a9e923 [-] Revert "[U] Update variable types"
This reverts commit 6d191f04fb.
2019-10-13 18:01:46 -04:00
Hykilpikonna 5013830815 [-] Revert "[F] Fix http-utils constructor type error"
This reverts commit 0f93a3581f.
2019-10-13 18:00:56 -04:00
Hykilpikonna e4ba53f460 [-] Revert "[O] Optimize token storage"
This reverts commit 846f26db75.
2019-10-13 17:59:07 -04:00
Hykilpikonna fabdc10467 [-] Revert "[U] Use response.data.courses for courses"
This reverts commit 8caab70b25.
2019-10-13 17:57:39 -04:00
Hykilpikonna 91488c6a9f [-] Revert "[+] Save csrf token"
This reverts commit d4df0c3562.
2019-10-13 17:39:25 -04:00
Hykilpikonna f346364633 [O] Make value.min exactly the min value 2019-10-13 17:35:32 -04:00
Hykilpikonna 34e482e8a9 [+] Define value.max for line chart 2019-10-13 17:35:16 -04:00
Hykilpikonna 9aaf662a60 [F] Use scoreId instead of assignmentId when requesting 2019-10-13 15:27:02 -04:00
Hykilpikonna 0b65ebbb00 [+] Parse score_id when parsing 2019-10-13 15:26:32 -04:00
Hykilpikonna 74d1c88f82 [+] Add scoreId to Assignment model 2019-10-13 15:26:22 -04:00
Hykilpikonna 70c8375810 [+] Listen mark as read event 2019-10-13 15:21:00 -04:00
Hykilpikonna b554128337 [+] Implement mark assignment as read 2019-10-13 15:20:49 -04:00
Hykilpikonna 4a8ce2ca18 [O] Use App.http instead of this.http 2019-10-13 15:12:00 -04:00
Hykilpikonna a2df22c1da [O] Make http client static 2019-10-13 15:07:07 -04:00
Hykilpikonna 047ceda252 [-] Remove unnecessary unreadTable() function 2019-10-13 14:53:00 -04:00
Hykilpikonna c94435360f [O] Adjust expansion background clor 2019-10-13 14:51:47 -04:00
Hykilpikonna ed0b7a9740 [O] Use @click instead of onclick 2019-10-13 14:49:44 -04:00
Hykilpikonna b168c4bb82 [+] Call mark as read on click 2019-10-13 14:48:28 -04:00
Hykilpikonna 5078011f40 [+] Add markAsRead() function 2019-10-13 14:47:56 -04:00
Hykilpikonna 1428953cb7 [O] Remove button borders 2019-10-13 14:43:54 -04:00
Hykilpikonna 7f962704d2 [O] Make button paddings smaller 2019-10-13 14:43:44 -04:00
Hykilpikonna 2970263db5 [O] Add left margin 2019-10-13 14:43:31 -04:00
Hykilpikonna 91d9fb90ac [O] Remove button background 2019-10-13 14:43:22 -04:00
Hykilpikonna adb28089b9 [O] Make the button's size mini 2019-10-13 14:42:49 -04:00
Hykilpikonna 6f4a012ac4 [O] Use button instead 2019-10-13 14:42:29 -04:00
Hykilpikonna b807a41496 [O] Make background lighter 2019-10-13 14:08:29 -04:00
Hykilpikonna 02f1fb797f [O] Set color for mark as read 2019-10-13 14:07:54 -04:00
Hykilpikonna caee9117b3 [O] Adjust padding 2019-10-13 14:07:45 -04:00
Hykilpikonna 48cec4c0f0 [+] Add mark-as-read span 2019-10-13 14:07:33 -04:00
Hykilpikonna d4df0c3562 [+] Save csrf token 2019-10-12 20:36:55 -04:00
Hykilpikonna 8caab70b25 [U] Use response.data.courses for courses 2019-10-12 20:36:22 -04:00
Hykilpikonna 846f26db75 [O] Optimize token storage 2019-10-12 20:35:59 -04:00
Hykilpikonna ea2bdb226d [U] Update key names 2019-10-12 20:19:09 -04:00
Hykilpikonna 0f93a3581f [F] Fix http-utils constructor type error 2019-10-12 20:17:00 -04:00
Hykilpikonna 6607afc898 [U] Also include username when posting request 2019-10-12 20:14:57 -04:00
Hykilpikonna 543b0ddefe [U] Update http-utils to use token.token 2019-10-12 20:14:33 -04:00
Hykilpikonna 6d191f04fb [U] Update variable types 2019-10-12 20:14:08 -04:00
Hykilpikonna 353a623e5f [+] Create token interface 2019-10-12 20:11:56 -04:00
Hykilpikonna e28f68aae3 [+] Return username with token 2019-10-12 20:09:22 -04:00
Hykilpikonna 5441592d68 [+] Save username to cookies on login 2019-10-12 20:09:04 -04:00
Hykilpikonna a8e96b142d [+] Add google analytics tag 2019-10-07 21:31:46 -04:00
Hykilpikonna 4527b58084 [O] Optimize alignment for small screens 2019-10-05 20:36:00 -04:00
Hykilpikonna 80d14c1400 [O] Limit max width 2019-10-05 20:30:00 -04:00
Hykilpikonna 86ed26afeb [U] Pre-release v0.3.2.452 2019-10-05 20:15:30 -04:00
Hykilpikonna 35c4147cc1 [O] Lighten drop shadow 2019-10-05 20:13:06 -04:00
Hykilpikonna 711e69ddfb [O] Make font color darker 2019-10-05 20:07:26 -04:00
Hykilpikonna 90d9cac19a [+] Add dynamic assignment type coloring 2019-10-05 20:07:10 -04:00
Hykilpikonna 61593d7d23 [O] Adjust el-col width 2019-10-05 20:02:11 -04:00
Hykilpikonna 7c41e7adcc [O] Add right margins 2019-10-05 20:02:00 -04:00
Hykilpikonna 0215be8681 [O] Make days from now font smaller 2019-10-05 20:01:46 -04:00
Hykilpikonna 1139384ab3 [O] Make assignment type looks like Veracross 2019-10-05 19:57:40 -04:00
Hykilpikonna 45174422e9 [+] Add days from now 2019-10-05 19:57:18 -04:00
Hykilpikonna 2077d784fd [O] Make formatDate return moment instead 2019-10-05 19:55:41 -04:00
Hykilpikonna fa341101a8 [+] Add assignment color variables 2019-10-05 19:47:15 -04:00
Hykilpikonna 1959ac589d [O] show entry box for assignment type 2019-10-05 19:43:46 -04:00
Hykilpikonna 5744493ac3 [+] Add padding to first child 2019-10-05 19:43:06 -04:00
Hykilpikonna 64eb4530af [O] Only show top shadow for first child 2019-10-05 19:22:44 -04:00
Hykilpikonna d38fdfaced [O] Brighten percent score emphesis 2019-10-05 19:20:53 -04:00
Hykilpikonna f76484f824 [O] Adjust el-col width 2019-10-05 19:20:35 -04:00
Hykilpikonna ef6adb0a27 [O] Add entry-box class to span tags 2019-10-05 19:20:22 -04:00
Hykilpikonna ca80df9541 [O] Separate span box class 2019-10-05 19:19:41 -04:00
Hykilpikonna 828907120b [O] Add top shadow 2019-10-05 19:18:43 -04:00
Hykilpikonna 460074b18a [O] Adjust background color 2019-10-05 19:17:00 -04:00
Hykilpikonna 104bd4498e [+] Emphasize percentage score 2019-10-05 17:19:30 -04:00
Hykilpikonna 97082b1e55 [O] Separate percent symbol into new span 2019-10-05 17:18:58 -04:00
Hykilpikonna c9561fba71 [F] Fix "v-for should have explicit keys" 2019-10-05 17:12:31 -04:00
Hykilpikonna 8aa913fe09 [+] Display score in percentage 2019-10-05 17:08:55 -04:00
Hykilpikonna a598521491 [O] Emphasise current score 2019-10-05 17:06:24 -04:00
Hykilpikonna 6461456c16 [O] Style span box to look the same as Veracross 2019-10-05 17:04:35 -04:00
Hykilpikonna b4f697bdea [O] Add css selector classes to spans 2019-10-05 17:01:50 -04:00
Hykilpikonna 721295b9d1 [+] Separate <span>s 2019-10-05 17:00:47 -04:00
Hykilpikonna 70c6e74623 [O] Align grade to the right 2019-10-05 16:59:30 -04:00
Hykilpikonna 1348ca27ab [O] Align text left 2019-10-05 16:58:55 -04:00
Hykilpikonna 116592e436 [+] Add css selector classes to cols 2019-10-05 16:56:31 -04:00
Hykilpikonna 19284a4ddf [O] Combine type and description cols 2019-10-05 16:55:05 -04:00
Hykilpikonna 35e603b850 Revert "[-] Remove el-row and el-col"
This reverts commit 882c7bb35e.
2019-10-05 16:54:19 -04:00
Hykilpikonna 882c7bb35e [-] Remove el-row and el-col 2019-10-05 16:53:51 -04:00
Hykilpikonna 9c8ce3a7f2 [O] Display formatted date 2019-10-05 16:50:49 -04:00
Hykilpikonna 8a6af65786 [+] Create method to format date with moment 2019-10-05 16:50:32 -04:00
Hykilpikonna 4633bd902c [+] Install moment dependency 2019-10-05 16:35:47 -04:00
Hykilpikonna 10fcb8a2f6 [O] Add padding 2019-10-05 16:29:10 -04:00
Hykilpikonna 3ad47eddfd [O] Adjust col width 2019-10-05 16:28:58 -04:00
Hykilpikonna 636f1474bd [O] Vertically center row content 2019-10-05 16:28:48 -04:00
Hykilpikonna ebc9fac4dc [+] Make unread row higher 2019-10-05 16:28:32 -04:00
Hykilpikonna a0e5db6ed9 [+] Parse typeId in jsonUtils 2019-10-05 16:26:19 -04:00
Hykilpikonna f8acd8e222 [+] Add typeId to Assignment model 2019-10-05 16:26:02 -04:00
Hykilpikonna 7b21f82024 [+] Create a table 2019-10-05 16:19:17 -04:00
Hykilpikonna 240cd7ce69 [+] Use unreadEntry components 2019-10-05 16:14:55 -04:00
Hykilpikonna 8a4f9c6f79 [+] Import UnreadEntry component 2019-10-05 16:14:42 -04:00
Hykilpikonna 16f5865c4c [O] Also cache unread assignments 2019-10-05 16:14:31 -04:00
Hykilpikonna 25c3d8e6c1 [+] Create unread-entry component 2019-10-05 16:10:18 -04:00
Hykilpikonna e1584c80a5 [+] Add demo unread entry 2019-10-05 16:05:39 -04:00
Hykilpikonna 89dc493edf [+] Use el-table but comment out 2019-10-05 16:05:14 -04:00
Hykilpikonna aa59075939 [+] Only display expantion when unread messages != 0 2019-10-05 15:50:44 -04:00
Hykilpikonna c55beaf30d [-] Remove debug height declaration 2019-10-05 15:49:27 -04:00
Hykilpikonna 67f1343744 [-] Remove duplicate vertical center code 2019-10-05 15:43:17 -04:00
Hykilpikonna 6b0e0fc8e8 [U] Vertical center main cards 2019-10-05 15:42:38 -04:00
Hykilpikonna af41ad5f53 [O] Separate vertical centering css selector 2019-10-05 15:42:06 -04:00
Hykilpikonna 622cd524e5 [O] Make size larger for debug 2019-10-05 15:41:52 -04:00
Hykilpikonna 7266cf0d80 [+] Make content background darker 2019-10-05 15:39:44 -04:00
Hykilpikonna 47fc11ed96 [+] Add custom padding to content 2019-10-05 15:39:32 -04:00
Hykilpikonna fd927991c7 [F] Remove card padding for styling issues 2019-10-05 15:37:44 -04:00
Hykilpikonna 4b5e6d9856 [+] Add 'main' css class to avoid conflict 2019-10-05 15:32:07 -04:00
Hykilpikonna 3aa5ef9c95 [+] Add notfication div 2019-10-05 15:31:27 -04:00
Hykilpikonna ded76b774c [O] Vertically center content 2019-10-05 15:30:04 -04:00
Hykilpikonna 1bcf2f7410 [O] Make the content hight constant 2019-10-05 15:29:50 -04:00
Hykilpikonna d8cce9ae11 [O] Expand the max hight 2019-10-05 15:29:22 -04:00
Hykilpikonna b4f29559cf [F] Remove global declaration of height 2019-10-05 15:28:08 -04:00
Hykilpikonna a7ea833860 [O] Wrap content in div instead 2019-10-05 15:20:50 -04:00
Hykilpikonna 9c54033343 [+] Wrap course-card around a parent card 2019-10-05 15:11:18 -04:00
Hykilpikonna 7b9dab9d78 [F] Fix rounding issue when detecting necessity of grading api 2019-10-05 14:34:47 -04:00
Hykilpikonna 7f094cbafb [F] Fix typo: should be 'TOTAL_MEAN' instead of 'TOTAL_AVERAGE' 2019-10-05 14:31:08 -04:00
Hykilpikonna c4b8542b5b [F] Skip courses without graded assignments instead of without any assignments 2019-10-05 14:27:18 -04:00
Hykilpikonna 0345d37b2c [U] Pre-release v0.3.1.382 2019-10-05 14:11:32 -04:00
Hykilpikonna 97818c45f5 [-] Remove drop shadow 2019-10-05 14:10:26 -04:00
Hykilpikonna 1a09c7311e [O] Make font size smaller 2019-10-05 14:10:17 -04:00
Hykilpikonna b658f6f707 [O] Make text italic 2019-10-05 14:10:08 -04:00
Hykilpikonna 1d63e4865b [M] Move main color to theme 2019-10-05 14:05:26 -04:00
Hykilpikonna 78fbd342d9 [O] Apply nowrap to all cards 2019-10-05 14:04:06 -04:00
Hykilpikonna 141c192017 [+] Add github link to splash 2019-10-05 14:00:07 -04:00
Hykilpikonna 87e44b83f7 [+] Add github link constant 2019-10-05 13:59:50 -04:00
Hykilpikonna 1064831379 [O] Separate version as a constant 2019-10-05 13:59:37 -04:00
Hykilpikonna 1e42ef7873 [O] Add text shadow 2019-10-05 13:54:56 -04:00
Hykilpikonna c8327f3774 [O] Replace hex with var 2019-10-05 13:51:26 -04:00
Hykilpikonna 69cd4ff050 [+] Use default theme in base div 2019-10-05 13:51:05 -04:00
Hykilpikonna 027f8bfd34 [+] Create theme css class 2019-10-05 13:50:50 -04:00
Hykilpikonna 70ede22c18 [O] Remove space between number and '%' 2019-10-05 13:45:04 -04:00
Hykilpikonna fd74298b0b [+] Add some right margin 2019-10-05 13:44:35 -04:00
Hykilpikonna d47bae00ff [+] Change color of unread text as well 2019-10-05 13:43:32 -04:00
Hykilpikonna 0c91b1b598 [U] Update css implementation 2019-10-05 13:42:13 -04:00
Hykilpikonna 6ba789c7cf [M] Move unread class up a level 2019-10-05 13:41:56 -04:00
Hykilpikonna 54b70f6a1c [F] Fix inversed condition 2019-10-05 13:39:08 -04:00
Hykilpikonna ac32a02ff4 [O] Make 'update' plural only when count >= 2 2019-10-05 13:38:22 -04:00
Hykilpikonna 993578277e [+] Add 'new update' text 2019-10-05 13:38:00 -04:00
Hykilpikonna 48fb8c7d4c [O] Optimize unread count with caching 2019-10-05 13:36:56 -04:00
Hykilpikonna 0f6f27aa15 [O] Add some paddings to make it larger 2019-10-05 13:34:56 -04:00
Hykilpikonna b2947e9ef6 [+] Add shadow 2019-10-05 13:18:17 -04:00
Hykilpikonna c5ef8a297b [F] Fix css syntax: Stacked class vs stacked element 2019-10-05 13:16:31 -04:00
Hykilpikonna 02ca6b8d47 [+] Add dynamic coloring 2019-10-05 13:15:20 -04:00
Hykilpikonna 98b92b4dfb [+] Add dynamic class based on unread count 2019-10-05 13:14:03 -04:00
Hykilpikonna 1c2afdfa52 [O] Add block around the update number 2019-10-05 13:13:45 -04:00
Hykilpikonna 55b4bd9173 [+] Encapsulate method to count unread assignments 2019-10-05 13:10:34 -04:00
Hykilpikonna e422c03ca5 [-] Remove centering 2019-10-05 13:00:02 -04:00
Hykilpikonna 831ef16a2f [+] Display unread 2019-10-05 12:59:45 -04:00
Hykilpikonna 0deb0ed719 [F] Fix key typo: is_unread instead of unread 2019-10-05 12:56:10 -04:00
Hykilpikonna f3d44ceda2 [+] Parse id and unread 2019-10-05 10:24:42 -04:00
Hykilpikonna cb11db6201 [+] Add field id and unread to Assignment type 2019-10-05 10:23:46 -04:00
Hykilpikonna b52f3d2617 [M] Rename type Grade to type Assignment 2019-10-05 10:22:40 -04:00
Hykilpikonna 39cd5bf1a2 [F] Fix grid misplacement problem 2019-10-02 08:13:17 -04:00
Hykilpikonna 19f03717bc [O] Go back to using grid 2019-10-02 08:12:53 -04:00
Hykilpikonna 6d728c25ae [O] Center grade display 2019-10-01 21:45:36 -04:00
Hykilpikonna c8daa2a06e [+] Fix the numeric grade to 2 digits 2019-10-01 21:41:57 -04:00
Hykilpikonna 4d41e679dd [O] Make grade font size match Veracross 2019-10-01 21:29:56 -04:00
Hykilpikonna acfebf9ff3 [+] Show course card for every course 2019-10-01 21:29:35 -04:00
Hykilpikonna 5af1b1e5a1 [O] Add auto margin top and bottoms 2019-10-01 21:19:22 -04:00
Hykilpikonna bc9a4f00c1 [+] Align left and right 2019-10-01 21:19:08 -04:00
Hykilpikonna f13f3a155c [-] Remove the grid 2019-10-01 21:09:50 -04:00
Hykilpikonna a19edb8aa7 [+] Display numeric grade and letter grade 2019-10-01 21:01:15 -04:00
Hykilpikonna 6a0500acb2 [-] Remove unnecessary span 2019-10-01 20:54:29 -04:00
Hykilpikonna 96af69508f [O] Limit course name length 2019-10-01 20:50:25 -04:00
Hykilpikonna 3fbc9764e9 [O] Make teacher name italicised 2019-10-01 20:50:12 -04:00
Hykilpikonna a79dcb76af [O] Make teacher name font size match Veracross 2019-10-01 20:49:54 -04:00
Hykilpikonna 86c2fd5df7 [+] Add underline effect on hover 2019-10-01 20:49:18 -04:00
Hykilpikonna 07eaeef133 [+] Add margin to the beginning of course name 2019-10-01 20:49:03 -04:00
Hykilpikonna d1bd0a5667 [O] Change font size to match Veracross 2019-10-01 20:48:44 -04:00
Hykilpikonna 49dad14c84 [O] Adjust spacing 2019-10-01 20:47:57 -04:00
Hykilpikonna 50e3c345d5 [O] Clarify css selector 2019-10-01 20:40:18 -04:00
Hykilpikonna a444dbb32a [+] Add cols to display course name and teacher name 2019-10-01 20:39:53 -04:00
Hykilpikonna 03e212bd37 [+] Add margins to the navigation bar 2019-10-01 20:24:54 -04:00
Hykilpikonna 0325eb13d5 [F] Fix css priority issue 2019-10-01 20:17:37 -04:00
Hykilpikonna bfcb80aa64 [+] Add a title but comment it out 2019-10-01 20:10:48 -04:00
Hykilpikonna 91a6c0c6e4 [+] Optimize card formatting 2019-10-01 20:01:56 -04:00
Hykilpikonna 845cc94513 [+] Add a card in course element 2019-10-01 20:01:47 -04:00
Hykilpikonna 21ccaceb53 [+] Add a testing course element 2019-10-01 20:01:37 -04:00
Hykilpikonna b9f63171f2 [+] Create overall-course component 2019-10-01 19:44:51 -04:00
Hykilpikonna 636d92d1a0 [M] Rename and correct some misc css class names 2019-10-01 19:44:24 -04:00
Hykilpikonna 199ab9e00c [M] Rename graph-average to overall-bar 2019-10-01 19:37:20 -04:00
Hykilpikonna 77541764d1 [M] Rename graph-overall to overall-line 2019-10-01 19:36:09 -04:00
Hykilpikonna 53ae74f9c4 [O] Use absolute positioning to center what's in the center 2019-10-01 19:33:11 -04:00
Hykilpikonna 5bc1d6ba48 [O] Put sign-out button on the right 2019-10-01 19:30:41 -04:00
Hykilpikonna 831ddcf84e [-] Remove debug output 2019-10-01 19:27:00 -04:00
Hykilpikonna 35a85d8e83 [U] Release v0.2.3.315 2019-10-01 19:19:27 -04:00
Hykilpikonna 71b0a6e4dd [-] Remove debug output 2019-10-01 19:18:51 -04:00
Hykilpikonna d4fbd04466 [F] Fix grading history lower than actual 2019-10-01 19:18:33 -04:00
Hykilpikonna 31b3814b1e [O] Ignore 0 when calculating the score 2019-10-01 19:02:41 -04:00
Hykilpikonna 1aff2b0a68 [-] Remove debug output 2019-10-01 19:02:10 -04:00
Hykilpikonna 2567fcadbd [+] Encapsulate method to calculate total-mean average 2019-10-01 18:41:42 -04:00
Hykilpikonna d9e0e9f84e [F] Fix another null case 2019-10-01 18:41:14 -04:00
Hykilpikonna 59b31ea43f [F] Fix key word typo 2019-10-01 18:41:04 -04:00
Hykilpikonna 2c8b3e0f84 [F] Fix null case 2019-10-01 18:40:54 -04:00
Hykilpikonna 6910a7b5ea [F] Fix null pointer caused by grading not existing 2019-10-01 18:30:20 -04:00
Hykilpikonna cbdcfc4ca1 [+] Check gradings after checking assignments 2019-10-01 18:30:02 -04:00
Hykilpikonna feabc336c1 [+] Create method to check course gradings 2019-10-01 18:29:50 -04:00
Hykilpikonna b5b9f14a49 [U] Pre-release v0.2.2.303 2019-09-30 21:16:53 -04:00
Hykilpikonna fc93cd1248 [+] Skip if not graded 2019-09-30 21:05:39 -04:00
Hykilpikonna 6e58c634a1 [F] Correct course average grade graph calculation 2019-09-30 21:05:29 -04:00
Hykilpikonna 10cca344c7 [M] Copy old course calculation method to deprecated 2019-09-30 21:05:07 -04:00
Hykilpikonna cdf58ea3a0 [O] Specify type for weighting map 2019-09-30 21:04:47 -04:00
Hykilpikonna d97c80afbb [U] Update course model to match the update 2019-09-30 19:25:59 -04:00
Hykilpikonna 8c7d028f5b [R] Update screenshot 2019-09-29 19:51:19 -04:00
Hykilpikonna 19ba8ec7e6 [U] Pre-release v0.2.1.295 2019-09-29 19:45:22 -04:00
Hykilpikonna 6937952f3a [O] Optimize alignment 2019-09-29 19:44:38 -04:00
Hykilpikonna 485717d3ef [+] Dynamic min value 2019-09-29 19:42:26 -04:00
Hykilpikonna 3f3e46bec5 [O] Make graph-overall smoother 2019-09-29 19:42:16 -04:00
Hykilpikonna 1494315e0c [O] Optimize wording 2019-09-29 19:14:39 -04:00
Hykilpikonna 76eb8168ce [O] Align the two graph titles 2019-09-29 19:14:27 -04:00
Hykilpikonna e4a1c4973d [O] Rotate text to 90 degrees 2019-09-29 19:14:12 -04:00
Hykilpikonna b22fc41582 [+] Add title to course gpa graph 2019-09-29 19:14:02 -04:00
Hykilpikonna 0e1264d938 [O] Make the full grade color gray 2019-09-29 18:29:52 -04:00
Hykilpikonna a94a6db4b7 [O] Make the bar color match the line graph color 2019-09-29 18:29:32 -04:00
Hykilpikonna 18b5b7de77 [O] Separate the generation of the gp dataset 2019-09-29 18:28:33 -04:00
Hykilpikonna 28d4e5d871 [F] Fix typo on assignment sign 2019-09-29 18:09:32 -04:00
Hykilpikonna cc5b7b2793 [O] Remove dataset, move data to series 2019-09-29 18:02:40 -04:00
Hykilpikonna 7b4ced4e94 [O] Display larger data on farthest layer 2019-09-29 17:46:00 -04:00
Hykilpikonna 70e6debe82 [+] Stack the bars in graph 2019-09-29 17:44:08 -04:00
Hykilpikonna e0c4426ebb [O] Optimize series generation with [].map 2019-09-29 17:43:01 -04:00
Hykilpikonna 495e776971 [O] Optimize code length 2019-09-29 17:39:21 -04:00
Hykilpikonna fc625c8edb [+] Truncate text if too long 2019-09-29 17:38:53 -04:00
Hykilpikonna 6c1623cec5 [+] Show axis label 2019-09-29 17:31:37 -04:00
Hykilpikonna a9a9cf5f11 [O] Make bar graph vertical 2019-09-29 17:31:29 -04:00
Hykilpikonna d8f276005d [O] Make the two graphs the same width 2019-09-29 17:20:07 -04:00
Hykilpikonna 5c9e67478f [+] Rebuild entire average graph from settings 2019-09-29 17:17:23 -04:00
Hykilpikonna 5e0394f11c [+] Create a theme constant 2019-09-29 16:28:44 -04:00
Hykilpikonna 774e436c9c [F] Fix typo in :data bind method 2019-09-29 16:14:17 -04:00
Hykilpikonna 8b653e3317 [+] GraphAverage: Return graph 2019-09-29 16:13:57 -04:00
Hykilpikonna 9731d4e380 [+] GraphAverage: Map GPA and MaxGPA for each course 2019-09-29 16:13:52 -04:00
Hykilpikonna e3ca21ec29 [+] GraphAverage: Make column list 2019-09-29 16:13:14 -04:00
Hykilpikonna a89c29dc53 [F] Fix class name typo 2019-09-29 16:04:48 -04:00
Hykilpikonna 87a59416ec [O] Optimize minDate calculation with array.map() and Math.min 2019-09-29 16:04:38 -04:00
Hykilpikonna 8243312179 [O] Optimize column generation with array.map() 2019-09-29 15:48:28 -04:00
Hykilpikonna 3dcc1b8319 [+] Add zome bar 2019-09-29 15:34:17 -04:00
Hykilpikonna 899ff22677 [O] Hide legend for now 2019-09-29 15:33:14 -04:00
Hykilpikonna 788f51399a [O] Center title 2019-09-29 15:33:05 -04:00
Hykilpikonna 575dbdf765 [-] Remove duplicate title in html 2019-09-29 15:32:58 -04:00
Hykilpikonna 1659964011 [O] Show title in graph settings 2019-09-29 15:32:46 -04:00
Hykilpikonna 02533f6b07 [+] Add graph-average to overall page 2019-09-29 15:23:51 -04:00
Hykilpikonna 68a91e5eb8 [+] Create average graphs 2019-09-29 15:18:46 -04:00
Hykilpikonna 1eb6128aac [O] Optimize type declaration 2019-09-29 15:17:14 -04:00
Hykilpikonna fbd59f9ec3 [-] Remove unnecessary var declaration in getGPA() 2019-09-29 15:12:47 -04:00
Hykilpikonna 7eb7838f66 [M] Move convertChart() to graph-overall.ts 2019-09-29 15:12:05 -04:00
Hykilpikonna 6459e1c09b [O] Make the legend icon a circle 2019-09-29 15:09:15 -04:00
Hykilpikonna 4461ef835f [U] Pass in filtered courses instead 2019-09-29 15:08:30 -04:00
Hykilpikonna 6ee207d754 [+] Filter courses after assignments are retrieved 2019-09-29 15:07:01 -04:00
Hykilpikonna 3c0c0d5f1b [-] Remove unnecessary jsdoc @param declaration 2019-09-29 15:02:24 -04:00
Hykilpikonna bc8fcc021d [M] Move course filtering to course-utils.ts 2019-09-29 15:01:47 -04:00
Hykilpikonna e9a6cfe5c5 [O] Make legend font size smaller 2019-09-29 14:47:47 -04:00
Hykilpikonna 0e92cedf54 [+] Add title but doesn't show 2019-09-29 14:27:25 -04:00
Hykilpikonna a73d6b0399 Revert "[O] Use vue-echarts instead of v-charts"
This reverts commit d254706a21.
2019-09-29 12:45:06 -04:00
Hykilpikonna 8042765ff5 Revert "[-] Remove v-charts dependency"
This reverts commit 8978b7ca7b.
2019-09-29 12:45:03 -04:00
Hykilpikonna 74a033fb5d Revert "[+] Import vue-echarts"
This reverts commit b78c5b4f5b.
2019-09-29 12:44:57 -04:00
Hykilpikonna cc4378d905 Revert "[+] Add vue-echarts transpile dependencies"
This reverts commit a526946b83.
2019-09-29 12:44:55 -04:00
Hykilpikonna 0fd3696342 Revert "[U] Update overall graph component"
This reverts commit c262584e2f.
2019-09-29 12:44:52 -04:00
Hykilpikonna 3de4b1f6e6 Revert "[+] Add a graph title"
This reverts commit 610d1d190d.
2019-09-29 12:44:50 -04:00
Hykilpikonna 610d1d190d [+] Add a graph title 2019-09-28 17:55:44 -04:00
Hykilpikonna c262584e2f [U] Update overall graph component 2019-09-28 17:55:35 -04:00
Hykilpikonna a526946b83 [+] Add vue-echarts transpile dependencies 2019-09-28 17:52:32 -04:00
Hykilpikonna b78c5b4f5b [+] Import vue-echarts 2019-09-28 17:50:42 -04:00
Hykilpikonna 8978b7ca7b [-] Remove v-charts dependency 2019-09-28 17:47:18 -04:00
Hykilpikonna d254706a21 [O] Use vue-echarts instead of v-charts 2019-09-28 17:47:02 -04:00
Hykilpikonna 8dd7d35abe [U] Pre-release v0.1.2.236 2019-09-28 17:38:33 -04:00
Hykilpikonna 2b989fb137 [-] Remove placeholder button 2019-09-28 17:35:55 -04:00
Hykilpikonna e2a13e90e0 [O] Optimize font size for max gpa 2019-09-28 17:35:46 -04:00
Hykilpikonna 3546a57711 [O] Use class to add style to card 2019-09-28 17:35:17 -04:00
Hykilpikonna 770e26b0cf [F] Fix warning: " should be ' 2019-09-28 16:33:00 -04:00
Hykilpikonna fff60f5754 [F] Fix the newline display for button 2019-09-27 20:12:41 -04:00
Hykilpikonna a46e011c90 [O] Use css to produce new-line effect instead of <br> 2019-09-27 16:47:22 -04:00
Hykilpikonna 48224d9e34 [O] Optimize jsdocs 2019-09-27 16:40:59 -04:00
Hykilpikonna eb311e9f2d [+] Display the maximum GPA 2019-09-27 16:38:52 -04:00
Hykilpikonna 7b53e65a1b [O] Return raw GPA in overall 2019-09-27 16:38:39 -04:00
Hykilpikonna 065d6d31a3 [O] Hit enter to login 2019-09-27 16:38:26 -04:00
Hykilpikonna d8eb160123 [F] Fix max gpa calculation 2019-09-27 16:33:50 -04:00
Hykilpikonna 8e924d8e33 [+] Also calculate max gpa when calculating gpa 2019-09-24 22:22:18 -04:00
Hykilpikonna 1e45b418b8 [O] Encapsulate getGP() with letter grade passed in 2019-09-24 22:20:58 -04:00
Hykilpikonna e42c8be76f [O] Detect letter grade for presence instead of numeric grade 2019-09-24 22:19:48 -04:00
Hykilpikonna b6b3f921a2 [R] Recreate license 2019-09-24 07:37:09 -04:00
Hykilpikonna d3234be6db [-] Remove license 2019-09-24 07:35:37 -04:00
Hykilpikonna 50a5f9dcc5 [O] Remove todo that is already done 2019-09-23 21:11:27 -04:00
Hykilpikonna 62d40dd0a7 [+] Add cname 2019-09-23 20:14:49 -04:00
Hykilpikonna 9e8e44b91f [-] Remove public path 2019-09-23 20:14:41 -04:00
Hykilpikonna df85e1084f [+] Create deploy script
https://cli.vuejs.org/guide/deployment.html#github-pages
2019-09-23 19:58:02 -04:00
Hykilpikonna 0b41f8ac5d [+] Add deploy path 2019-09-23 19:56:27 -04:00
Hykilpikonna 7b11537e0f [R] Make title shorter 2019-09-23 19:52:00 -04:00
Hykilpikonna 830f55441c [R] Create License
[R] Create License
2019-09-23 19:50:57 -04:00
Hykilpikonna 0a49d791ae [R] Create License 2019-09-23 19:50:35 -04:00
Hykilpikonna c675fc5650 [M] Merge Feature > Master: First release
[M] Merge Feature > Master: First release
2019-09-23 19:49:33 -04:00
Hykilpikonna ad8496e661 [R] Add license 2019-09-23 19:47:16 -04:00
Hykilpikonna 72b9e4d214 [R] Write introduction 2019-09-23 19:46:31 -04:00
Hykilpikonna fa3fc44526 [U] Update version number 2019-09-23 19:41:49 -04:00
Hykilpikonna 419cced592 [R] Add a title 2019-09-23 19:37:58 -04:00
Hykilpikonna 352fd58fb5 [O] Show the graph with minimum y axis at 70 2019-09-23 19:33:27 -04:00
Hykilpikonna f043d77e5e [M] Move graph title to the graph component 2019-09-23 19:32:37 -04:00
Hykilpikonna 9e88f3efe1 [U] Ignore 0 grades in calculations 2019-09-23 19:32:21 -04:00
Hykilpikonna cadd328958 [O] Separate settings 2019-09-20 19:27:10 -04:00
Hykilpikonna 8c4759d497 [-] Remove unnecessary sample chart data 2019-09-20 19:26:23 -04:00
Hykilpikonna ac8f488ab4 [O] Refresh page after signing out 2019-09-20 19:21:07 -04:00
Hykilpikonna df639a360c [+] Implement actual sign out function 2019-09-20 19:10:37 -04:00
Hykilpikonna 24328508c0 [+] Bind sign out event 2019-09-20 19:10:23 -04:00
Hykilpikonna ebd4849703 [O] Optimize sign out button 2019-09-20 19:10:12 -04:00
Hykilpikonna 80d72bb5c0 Merge branch 'styling' into feature 2019-09-20 18:52:56 -04:00
Hykilpikonna 204e7dc04a [F] Move signOut() to the right place 2019-09-20 18:50:13 -04:00
Hykilpikonna cef0b31dba [O] Only display score when it is complete 2019-09-19 19:11:54 -04:00
Hykilpikonna 22ba3acab0 [F] Fix key word typo 2019-09-19 19:11:00 -04:00
Hykilpikonna 88bdcd8cf8 [O] Optimize code length 2019-09-19 18:58:59 -04:00
Hykilpikonna 8559a93b9c [+] Filter courses to a variable 2019-09-19 18:58:00 -04:00
Hykilpikonna f8db85dca3 [F] Fix getter signature problem 2019-09-19 18:57:47 -04:00
Hykilpikonna b4bd24d884 [+] Filter courses without assignments 2019-09-19 18:55:55 -04:00
Hykilpikonna f6d30a750a [+] Filter courses without levels 2019-09-19 18:55:44 -04:00
Hykilpikonna 988d6f5463 [+] Create method to filter out courses 2019-09-19 18:55:34 -04:00
Hykilpikonna 608132ad6c [O] Reduce code length 2019-09-19 18:49:00 -04:00
Hykilpikonna 6cffb745a7 [O] Specify type with ts-ignore 2019-09-19 18:48:17 -04:00
Hykilpikonna 82212cf10c [O] Fix " warning 2019-09-19 18:46:40 -04:00
Hykilpikonna 08b665a1fa [+] Call custom event to sign out 2019-09-18 23:25:25 -04:00
Hykilpikonna 500e13ef9d [+] Add onclick to sign-out 2019-09-18 23:25:12 -04:00
Hykilpikonna b95220ba1a [+] Add sign out button 2019-09-18 23:23:24 -04:00
100 changed files with 9848 additions and 3664 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 HyDEV
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+39 -12
View File
@@ -1,6 +1,38 @@
# veracross-analyzer
<h1 align="center"><br><br>
VeracrossAnalyzer UI
</h1>
## Project setup
<h4 align="center">
A Website, A Visual Representation of Students' Grade Data on Veracross
</h4>
<h5 align="center">
<a href="#intro">Introduction</a>&nbsp;&nbsp;
<a href="#setup">Project Setup</a>&nbsp;&nbsp;
<a href="#license">License</a>
</h5><br><br><br>
<a name="intro"></a>
Introduction:
--------
This is a website that generates visual representation of students' grade data on Veracross. Currently there is only one graph and one numerical data representing the GPA. But also it just released yesterday! (Yay!) What do you expect this soon lol?
**Here's how it looks like right now:** *(Now all of you know my grades ;-;)*
![](https://user-images.githubusercontent.com/22280294/65841599-155ead00-e2f2-11e9-9d9f-c2f23c45d9a4.png)
<br>
<a name="setup"></a>
Project Setup:
--------
TODO: Actually write a project setup tutorial that's not generated by Vue on initialization ;-;.
### Install
```
npm install
```
@@ -15,15 +47,10 @@ npm run serve
npm run build
```
### Run your tests
```
npm run test
```
<br>
### Lints and fixes files
```
npm run lint
```
<a name="license"></a>
License: [MIT](https://choosealicense.com/licenses/mit/)
--------
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
The MIT license basically means that this project is open-soucred and you can do whatever you want with it, as long as you include a copy of this license in your distribution. You don't have to ask for permissions to use or anything. However, if you do bad things with it, I'm not responsible.
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
echo "Switch to production database settings"
exit
# abort on errors
set -e
# build
npm run build
# navigate into the build output directory
cd dist
# if you are deploying to a custom domain
echo 'demo.vera.hydev.org' > CNAME
git init
git add -A
git commit -m 'deploy'
# if you are deploying to https://<USERNAME>.github.io/<REPO>
git push -f git@github.com:Hykilpikonna/VeracrossAnalyzerDemo.git master:gh-pages
cd -
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+4307 -3095
View File
File diff suppressed because it is too large Load Diff
+19 -14
View File
@@ -8,24 +8,29 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"echarts": "^4.2.1",
"element-ui": "^2.11.1",
"@types/chroma-js": "^2.0.0",
"@types/md5": "^2.2.0",
"chroma-js": "^2.1.0",
"core-js": "^2.6.10",
"echarts": "^4.8.0",
"element-ui": "^2.13.2",
"md5": "^2.2.1",
"moment": "^2.27.0",
"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"
"vue": "^2.6.11",
"vue-class-component": "^7.2.5",
"vue-cookies": "^1.7.3",
"vue-property-decorator": "^8.5.1"
},
"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"
"@vue/cli-plugin-babel": "^3.12.1",
"@vue/cli-plugin-typescript": "^3.12.1",
"@vue/cli-service": "^4.4.6",
"node-sass": "^4.14.1",
"sass-loader": "^8.0.2",
"typescript": "^3.9.7",
"vue-template-compiler": "^2.6.11"
},
"postcss": {
"plugins": {
+14
View File
@@ -0,0 +1,14 @@
<!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>
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
@@ -0,0 +1 @@
{"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
@@ -0,0 +1 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
@@ -0,0 +1 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
@@ -0,0 +1 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
@@ -0,0 +1 @@
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
+250
View File
@@ -0,0 +1,250 @@
{
"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"
}
]
}
}
+16 -3
View File
@@ -3,9 +3,10 @@
<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">
<!--meta name="viewport" content="width=device-width,initial-scale=1.0"-->
<meta name="viewport" content="width=1024">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="icon" href="<%= BASE_URL %>logo@32px.png">
<title>Veracross Analyzer</title>
</head>
@@ -23,6 +24,18 @@
<!-- 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>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito+Sans&display=swap" rel="stylesheet">
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<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
@@ -0,0 +1,14 @@
<!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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

-2
View File
@@ -1,2 +0,0 @@
cd ../
npm run serve
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 44 KiB

+45
View File
@@ -0,0 +1,45 @@
import LoginUser from '@/logic/login-user';
import App from '@/components/app/app';
import pWaitFor from 'p-wait-for';
export default class AppDemo
{
static loadDemo(app: App)
{
app.logLoading('1. Logging in...')
App.http.get('./demo-data/token.json').then(response =>
{
app.user = new LoginUser(response.data)
app.courses = app.user.courses
app.logLoading('1. Loading assignments...')
app.courses.forEach(course =>
{
App.http.get(`./demo-data/assignments-${course.assignmentsId}.json`).then(response =>
{
course.loadAssignments(response.data);
})
})
pWaitFor(() => app.courses.every(c => c.rawAssignments)).then(() =>
{
app.gradedCourses = app.courses.filter(c => c.isGraded)
app.gradedCourses.forEach(c => [0, 1, 2, 3].forEach(i => c.termGrading[i] = {method: 'TOTAL_MEAN', weightingMap: {}}))
app.logLoading('');
app.assignmentsReady = true
app.showRating = true
app.$alert(
'This demo analyzes an offline snapshot of my data from Jun 6, 2020, ' +
'which displays my academic results from Junior year.<br/>' +
'<br/>' +
'Feel free to click around! 😇<br/>' +
'<br/>' +
'-- The Veracross Analyzer Team (YGui)<br/>' +
'-- Made with 🧡 in SJP',
'🥳 Welcome to VeracrossAnalyzer Demo!',
{dangerouslyUseHTMLString: true, confirmButtonText: 'OK'});
})
})
}
}
+157 -5
View File
@@ -1,8 +1,160 @@
div
{
font-family: -apple-system, Nunito Sans, Avenir, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, Helvetica, Arial, sans-serif;
}
#app
{
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#app-content
{
// Limit max width
max-width: 1300px;
text-align: center;
margin: auto;
}
.theme-default
{
--unread: #ff6c00;
--main: #0c6dad;
--assignment-type-2: #3f991e;
--assignment-type-3: #ff9900;
--assignment-type-4: #b02b02;
}
.dark
{
--dark-layer-1: #383838;
--dark-layer-2: #525252;
--dark-layer-3: #6c6c6c;
--dark-foreground: #e9e9e9;
background: var(--dark-layer-1) !important;
div, ul
{
background: var(--dark-layer-2) !important;
color: var(--dark-foreground) !important;
}
span, button
{
color: var(--dark-foreground) !important;
}
.el-card
{
border: none !important;
}
// Overall
#app-inner, #overall, #overall-course, .overall-span, #app-content
{
background: var(--dark-layer-1) !important;
}
// Course card
.entry-box, .none .unread-number {background: #797979 !important}
.entry-box.max {background-color: #949494 !important}
.entry-box.percent {background-color: #a7a490 !important}
.course-name {color: #cffff6 !important}
#block-grade #updates.none #unread-number {background: #757575 !important}
.course-card-content.expand, .assignment-entry, .unread-row,
.unread-row .el-col, #assignment-type-head, .course-page-graph.el-col
{
background-color: var(--dark-layer-3) !important;
}
// Nav bar
.el-menu--horizontal>.el-menu-item.is-active {color: var(--dark-foreground) !important;}
}
// ##############
// # Global CSS #
// ##############
.el-card
{
margin: 10px;
padding: 0;
}
.el-card.large
{
height: 494px;
}
// Fix padding
.el-card__body
{
padding-top: 0 !important;
padding-bottom: 0 !important;
}
// Vertical centering
.vertical-center
{
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
}
// Remove card padding for styling issues
div.el-card.course-card > div.el-card__body
{
padding-right: 0 !important;
padding-left: 0 !important;
}
// Clickable text
.clickable:hover
{
text-decoration: underline;
cursor: pointer;
}
// Non-selectable text
.unselectable
{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.el-dropdown-menu__item
{
font-family: Nunito Sans, Helvetica Neue, Microsoft YaHei, "微软雅黑", Arial, sans-serif;
}
// Fix word breaking
.el-dialog__body
{
word-break: unset !important;
}
.comic
{
font-family: "Comic Sans MS", Nunito Sans, Helvetica Neue, Microsoft YaHei, "微软雅黑", Arial, sans-serif;
}
#demo-not-available
{
padding-top: 40vh;
font-size: 2em;
color: #bbbbbb;
margin: 0 50px;
}
+201 -115
View File
@@ -1,188 +1,274 @@
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 Login from '@/components/login/login.vue';
import Navigation from '@/components/navigation/navigation.vue';
import Overall from '@/pages/overall/overall.vue';
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[]
}
import {HttpUtils} from '@/logic/utils/http-utils';
import Loading from '@/components/overlays/loading.vue';
import CoursePage from '@/pages/course/course-page.vue';
import Course from '@/logic/course';
import LoginUser from '@/logic/login-user';
import NavController from '@/logic/nav-controller';
import Info from '@/statics/Info.vue';
import CourseSelection from '@/pages/course-selection/course-selection.vue';
import AppDemo from '@/components/app/app-demo';
@Component({
components: {Login, Navigation, Overall},
components: {Login, Navigation, Overall, Loading, CoursePage, Info, CourseSelection},
})
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";
courses: Course[] = [];
gradedCourses: Course[] = [];
// Are the course assignments loaded from the server.
public assignmentsReady: boolean = false;
assignmentsReady: boolean = false;
// Token
public token: string = '';
user: LoginUser = null as any;
// Loading text
loading: string = '';
// Loading error
loadingError: boolean = false;
// Navigation controller
nav: NavController = new NavController();
// Http Client
public http: HttpUtils = new HttpUtils('');
static http: HttpUtils = new HttpUtils();
// Instance
static instance: App;
// Static page
staticPage: string = '';
// Dark mode
darkMode: boolean = this.$cookies.isKey('dark');
// Show rating
showRating: boolean = this.$cookies.get('show-rating') == 'set=yes';
// Demo mode
demoMode: boolean = window.location.hostname == 'demo.vera.hydev.org' || this.$cookies.isKey('demo-mode')
// Is the login panel shown
showLogin: boolean = !this.demoMode
/**
* This is called when the instance is created.
*/
public created()
created()
{
// Show splash
console.log(Constants.SPLASH);
// Update instance
App.instance = this;
// Check location
if (window.location.hash == '#info')
{
this.staticPage = 'info';
}
// Default config
if (!this.$cookies.isKey('show-rating'))
{
this.showRating = Constants.CURRENT_TERM == 3;
}
// Demo
if (this.demoMode)
{
AppDemo.loadDemo(this);
}
}
/**
* This is called when the user logs in.
*
* @param token Authorization token
* @param user Authorization user
*/
public onLogin(token: string)
onLogin(user: LoginUser)
{
// Hide login bar
this.showLogin = false;
// Store token
this.token = token;
// Show loading message
this.logLoading('1. Logging in...');
// Assign token to http client
this.http.token = token;
// Store user
this.user = user;
this.courses = user.courses
// Load data
this.loadCoursesAfterLogin();
}
// Assign user to http client
App.http.user = user;
/**
* 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 assignments
this.loadAssignments();
}
/**
* Load the assignments of the courses
*
* @param courses Courses Json
*/
public loadAssignments()
loadAssignments()
{
// Show loading message
this.logLoading('1. Loading assignments...');
// Get assignments for all the courses
this.courses.forEach(course =>
{
// Send request to get assignments
this.http.post('/assignments', {id: course.assignmentsId}).then(response =>
App.http.post('/assignments', {'assignmentsId': 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);
course.loadAssignments(response.data);
}
else throw new Error(response.data);
})
.catch(alert);
.catch(e => this.showError(`Error: Assignments data failed to load.\n(${e})`));
});
// Wait for assignments to be ready.
pWaitFor(() => this.isAssignmentsReady()).then(() =>
pWaitFor(() => this.courses.every(c => c.rawAssignments != null)).then(() =>
{
// When the assignments are ready
this.assignmentsReady = true;
// Filter courses
this.gradedCourses = this.courses.filter(c => c.isGraded);
// Check grading algorithms
this.checkGradingAlgorithms();
});
}
/**
* Are assignments ready or not
*
* @returns boolean Ready or not
* Check the courses' grading algorithms. (Total-mean or percent-type)
*/
private isAssignmentsReady(): boolean
checkGradingAlgorithms()
{
for (const course of this.courses)
// Show loading message
this.logLoading('2. Checking grading algorithms...');
// Loop through all the courses
for (const course of this.gradedCourses)
{
if (course.assignments == null) return false;
for (const i of [0, 1, 2, 3])
{
const cookieIndex = `va.grading.${i}.${course.assignmentsId}`;
// Check if already exist in cookies
if (this.$cookies.isKey(cookieIndex))
{
course.termGrading[i] = {method: 'TOTAL_MEAN', weightingMap: {}};
continue;
}
// Request grading scheme for this course at this grading period
App.http.post('/grading/term', {assignmentsId: course.assignmentsId, term: i}).then(resp =>
{
// Check success
if (resp.success)
{
// Add it to course
course.termGrading[i] = resp.data;
// If it's total_mean, cache it to cookies
// This is because only percent_type can update over time
if (course.termGrading[i].method == 'TOTAL_MEAN')
{
this.$cookies.set(cookieIndex, 'TOTAL_MEAN', '3d');
}
}
else throw new Error(resp.data);
})
.catch(e => this.showError(`Error: Grading data failed to load.\n(${e})`))
}
}
return true;
// Wait for done
pWaitFor(() => this.gradedCourses.every(c => c.termGrading.every(g => g != null))).then(() =>
{
this.assignmentsReady = true;
// Remove loading
this.logLoading('');
// Check if rating notification should be displayed
if (this.courses.filter(c => c.rated).length == 0 && this.showRating &&
!this.$cookies.isKey('rating-notified'))
{
// Show notification
this.$cookies.set('rating-notified', true);
this.showUpdates()
}
})
}
showUpdates()
{
this.$alert(
'<b>TL;DR:</b><br/>' +
'📅 Added a Course Selection tab to help you schedule for next year!<br/>' +
'🤩 You can now give star ratings to your courses!<br/>' +
'😮 You can also see others\' ratings in the course selection tab!<br/>' +
'<br/>' +
'That\'s it, try things out and have fun! 😇<br/>' +
'<br/>' +
'-- The Veracross Analyzer Team<br/>' +
'-- Made with 🧡 in SJP',
'🥳 Huge updates!',
{dangerouslyUseHTMLString: true, confirmButtonText: 'OK', customClass: 'comic'});
}
/**
* This is called when a navigation tab is clicked
* Log a message to loading screen
*
* @param tab Tab name
* @param message Message
*/
public onNavigate(tab: string)
logLoading(message: string)
{
// Debug output TODO: Remove this
console.log(tab);
if (message == '') this.loading = '';
else this.loading += '\n' + message;
}
// Update selected tab
this.selectedTab = tab;
/**
* Show error message on loading screen
*
* @param message Error message
*/
showError(message: string)
{
this.loadingError = true;
this.loading = message;
}
/**
* Sign out
*/
signOut()
{
// Clear all cookies
this.$cookies.keys().forEach(key => this.$cookies.remove(key));
// Refresh
window.location.reload();
}
/**
* Select time (Eg. Term 1, Term 2, All Year, etc.)
*
* @param code
*/
selectTime(code: number)
{
// TODO: Optimize
window.location.reload();
}
}
+27 -6
View File
@@ -1,13 +1,34 @@
<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" class="theme-default">
<div id="app-inner" v-if="staticPage === ''" :class="{dark: darkMode, padding: nav.id !== 'course-selection'}">
<login v-if="showLogin" v-on:login:user="onLogin"/>
<navigation v-if="user != null"
:app="this" :user="user" :nav="nav"
@sign-out="signOut" @select-time="selectTime">
</navigation>
<div id="app-content">
<overall :courses="courses" v-if="selectedTab === 'overall' && assignmentsReady"></overall>
<div id="app-content" v-if="assignmentsReady && loading === ''">
<overall v-if="nav.id === 'overall'" :courses="gradedCourses"></overall>
<course-page v-if="nav.id === 'course'" :course="gradedCourses.find(c => +c.id === +nav.info.id)"></course-page>
<course-selection v-if="nav.id === 'course-selection' && !demoMode" :app="this"></course-selection>
<div id="demo-not-available" class="unselectable" v-if="nav.id === 'course-selection' && demoMode">
Course selection page is not available in demo mode.
</div>
</div>
<loading v-if="loading !== ''" :text="loading" :error="loadingError"/>
</div>
<Info v-if="staticPage === 'info'"/>
</div>
</template>
<script src="./app.ts" lang="ts"></script>
<style src="./app.scss" lang="scss"></style>
<style src="./app.scss" lang="scss"/>
<style lang="scss" scoped>
.padding
{
padding-bottom: 100px;
}
</style>
+29
View File
@@ -0,0 +1,29 @@
<template>
<div class="el-loading-spinner" :class="{'not-centered': !centered}">
<svg viewBox="25 25 50 50" class="circular" :style="{width: size + 'px', height: size + 'px'}">
<circle cx="50" cy="50" r="20" fill="none" class="path"/>
</svg>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'
@Component
export default class LoadingSpinner extends Vue
{
@Prop({default: '42'}) size: string
@Prop({default: true}) centered: string
}
</script>
<style lang="scss" scoped>
.not-centered
{
top: unset;
margin-top: unset;
width: unset;
text-align: unset;
position: unset;
}
</style>
+7
View File
@@ -5,6 +5,13 @@
}
// Logo image
#login-logo-image
{
width: 80%;
margin-bottom: -15px;
}
// Parent overlay
.login-overlay
{
+88 -31
View File
@@ -1,73 +1,130 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Component, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {HttpUtils} from '@/utils/http-utils';
import App from '@/components/app/app';
import VersionUtils from '@/logic/utils/version-utils';
import LoginUser from '@/logic/login-user';
import Maintenance from '@/components/overlays/maintenance.vue';
/**
* This component handles user login, and obtains data from the server.
*/
@Component({
components: {},
})
@Component({components: {Maintenance}})
export default class Login extends Vue
{
public username: any = '';
public password: any = '';
username = '';
password = '';
public loading: boolean = false;
public error: String = '';
loading = false;
error = '';
@Prop()
public http?: HttpUtils;
disableInput = false;
maintenance = '';
/**
* This is called when the instance is created.
*/
public created()
created()
{
// TODO: Check maintenance
// Check login cookies
if (this.$cookies.isKey('va.token'))
{
// Already contains valid token / TODO: Validate
this.$emit('login:token', this.$cookies.get('va.token'));
// Check cookies version
if (this.needToUpdateCookies()) this.clearCookies();
else
{
// Login with token
this.login('/login/token', {token: this.$cookies.get('va.token')});
}
}
}
/**
* On click, sends username and password to the server.
* Check version number
*
* @returns boolean Need to clear cookies or not
*/
public onLoginClick()
needToUpdateCookies(): boolean
{
// Make login button loading
this.loading = true;
// Version doesn't exist
if (!this.$cookies.isKey('va.version')) return true;
// Bug
if (this.$cookies.get('va.token') == 'undefined') return true
// If the current version is less than the min supported version
return VersionUtils.compare(this.$cookies.get('va.version'), Constants.MIN_SUPPORTED_VERSION) == -1;
}
/**
* When the user clicks, post the login request and process the response
* This is also called when the user hits enter on the input boxes.
*/
loginClick()
{
// Simple checks
if (this.username == '')
{
this.error = 'Username cannot be blank 🤔';
}
// Format it
this.username = this.username.toLowerCase().replace(/ /g, '').replace(/@.*/g, '');
// Actually login
this.login('/login', {username: this.username, password: this.password})
}
/**
* Actually post the request and process the response
*/
login(url: string, data: any)
{
// Show loading
this.disableInput = this.loading = true;
// Fetch request
(<HttpUtils> this.http).post('/login', {username: this.username, password: this.password})
.then(response =>
App.http.post(url, data).then(response =>
{
// Check success
if (response.success)
{
// Save token to cookies
this.$cookies.set('va.token', response.data, '7d');
this.$cookies.set('va.token', response.data.token, '27d');
this.$cookies.set('va.version', Constants.VERSION, '27d');
// Call custom event with token
this.$emit('login:token', response.data);
// Call a custom event with the token
this.$emit('login:user', new LoginUser(response.data));
}
else
{
// Show error message
this.error = response.data;
// Login expired -> clear cookies
if (response.data == 'Error: Login expired')
{
this.clearCookies();
}
// Allow the user to retry
this.loading = false;
// Show error message & allow user to retry
// TODO: Automatic report error
this.error = response.data;
this.disableInput = this.loading = false;
}
})
.catch(err =>
{
alert(err);
// Allow the user to retry
this.loading = false;
// Show error message & allow user to retry
this.error = err;
this.disableInput = this.loading = false;
});
}
/**
* Clear cookies
*/
clearCookies()
{
this.$cookies.keys().forEach(key => this.$cookies.remove(key));
}
}
+21 -14
View File
@@ -2,28 +2,35 @@
<div id="login" class="login-overlay">
<div class="login-vertical-center">
<div class="login-panel">
<img alt="Vue logo" src="../../assets/logo.png">
<img id="login-logo-image" alt="logo" src="../../assets/logo.png">
<h1>Veracross Analyzer</h1>
<form id="login-form">
<el-input v-model="username"
placeholder="SJP Username (Eg. flast21)"
:class="{'input-error': error !== ''}"
v-if="!disableInput"
@keyup.enter.native="loginClick">
</el-input>
<el-input v-model="username"
placeholder="School Username"
:class="{'input-error': error !== ''}">
</el-input>
<el-input v-model="password"
placeholder="SJP Password"
show-password=""
:class="{'input-error': error !== ''}"
v-if="!disableInput"
@keyup.enter.native="loginClick">
</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>
<div class="el-form-item__error custom">{{error}}</div>
<el-button plain type="primary" @click="onLoginClick" :loading="loading">Login</el-button>
<el-button plain type="primary" @click="loginClick" :loading="loading">Login</el-button>
</form>
</div>
</div>
<Maintenance v-if="maintenance" :message="maintenance"/>
</div>
</template>
<script src="./login.ts" lang="ts"></script>
<style src="./login.scss" lang="scss"></style>
<style src="./login.scss" lang="scss"/>
+137
View File
@@ -15,3 +15,140 @@
border-bottom-width: 0;
}
}
#nav-avatar
{
position: absolute;
right: 0;
margin: 10px 20px;
}
#sign-out-button
{
// Float right
position: absolute;
right: 0;
// Set width and height
height: 60px;
width: 110px;
}
#nav-grading-period
{
// Float right
position: absolute;
right: 80px;
// Margins
margin-top: 12px;
margin-bottom: 12px;
}
#nav-title
{
// Float left
position: absolute;
left: 0;
// Set height
height: 60px;
// Center text
display: inline-flex;
align-items: center;
// Margins
margin-left: 20px;
margin-right: 8px;
// Make it non-clickable
pointer-events: none;
#nav-logo
{
height: 70%;
margin-right: 10px;
}
#nav-logo-text
{
// Color
color: #6bbeff !important;
background: linear-gradient(90deg,
rgba(90,177,239,1) 0%,
rgba(25,212,174,1) 100%) !important;
// Font
font-weight: 500;
font-size: 18px;
}
#nav-logo-text.logo-text
{
// Override the background
-webkit-text-fill-color: transparent !important;
-webkit-background-clip: text !important;
}
#nav-logo-version
{
color: #a7a7a7;
margin-left: 5px;
margin-top: 8px;
font-size: 10px;
}
}
#next-course
{
// Down center
width: 50%;
position: absolute;
bottom: 0;
left: 25%;
padding-top: 2px;
box-shadow: 0 -2px 9px 0 #00000029;
}
footer
{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 1000;
}
#prev-course
{
// Up center
width: 50%;
position: absolute;
top: 61px;
left: 25%;
padding-bottom: 2px;
box-shadow: 0 2px 9px 0 #00000029;
z-index: 1001;
}
.nav-course-operations
{
// Background
background-color: rgba(214, 214, 214, 0.67);
opacity: 0.85;
// Font
font-size: 14px;
color: #ab8585;
// Cursor
cursor: pointer;
}
.el-submenu__title
{
padding-right: 5px !important;
}
+145 -10
View File
@@ -1,17 +1,45 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Course from '@/logic/course';
import Constants from '@/constants';
import LoginUser from '@/logic/login-user';
import NavController from '@/logic/nav-controller';
import App from '@/components/app/app.ts';
/**
* This component is the top navigation bar
*/
@Component({
components: {},
})
@Component
export default class Navigation extends Vue
{
public activeIndex: string = 'overall';
@Prop({required: true}) app: App;
@Prop({required: true}) nav: NavController;
@Prop({required: true}) user: LoginUser;
@Prop() courses: any;
private gradingPeriod: string = 'All Year';
// Instance
static instance: Navigation;
/**
* This is called when the instance is created.
*/
created()
{
// Check selected time
if (!this.$cookies.isKey('va.grading-period'))
{
this.$cookies.set('va.grading-period', this.gradingPeriod, '10y');
}
this.gradingPeriod = this.$cookies.get('va.grading-period');
}
/**
* This is called when the instance is loaded.
*/
mounted()
{
Navigation.instance = this;
}
/**
* This function is called when the selection changes.
@@ -19,12 +47,119 @@ export default class Navigation extends Vue
* @param index The index selected
* @param indexPath The path of the index
*/
public onSelect(index: string, indexPath: string)
onSelect(index: string, indexPath: string)
{
// Update active index
this.activeIndex = index;
// Call custom event
this.$emit('navigation:select', this.activeIndex);
try
{
// Is json
this.nav.updateIndex(JSON.parse(index))
}
catch (e)
{
// Not json
this.nav.updateIndex(index);
}
}
/**
* Move to the next course
*
* @param indexOffset Index offset (Eg. 1 for next)
*/
nextCourse(indexOffset: number)
{
// Set tab to the next index
this.nav.updateIndex(this.findNextCourse(indexOffset).urlIndex)
}
/**
* Find the next course
*
* @param indexOffset Index offset (Eg. 1 for next)
*/
findNextCourse(indexOffset: number)
{
return this.findCourse(this.nav.info.id, indexOffset);
}
/**
* Find course
*
* @param courseId Course ID
* @param indexOffset Index offset (Eg. 1 for next)
*/
findCourse(courseId: string, indexOffset: number)
{
// Find current course index
let courseIndex = this.app.gradedCourses.findIndex(c => c.id == +courseId);
// Find next course
return this.app.gradedCourses[courseIndex + indexOffset];
}
/**
* Select grading period
*
* @param command Term 1, Term 2, All Year, etc.
*/
selectGradingPeriod(command: string)
{
this.gradingPeriod = command;
this.$cookies.set('va.grading-period', command, '10y');
// Call event
this.$emit('select-time', this.getSelectedTerm());
}
/**
* Get code for selected time
*/
getSelectedTerm(): number
{
if (this.gradingPeriod == 'All Year') return -1;
else return +this.gradingPeriod.replace('Term ', '') - 1;
}
/**
* Avatar dropdown menu event
*
* @param cmd Command: sign-out
*/
onAvatarMenu(cmd: string)
{
switch (cmd)
{
case 'sign-out':
{
this.$emit('sign-out');
break
}
case 'switch-dark':
{
this.app.darkMode = !this.app.darkMode;
if (this.app.darkMode) this.$cookies.set('dark', true);
else this.$cookies.remove('dark');
break
}
case 'switch-rating':
{
this.app.showRating = !this.app.showRating;
if (this.app.showRating) this.$cookies.set('show-rating', 'set=yes', '30d');
else this.$cookies.set('show-rating', 'set=no', '30d');
break
}
case 'updates':
{
this.app.showUpdates()
break
}
}
}
get version() {return Constants.VERSION}
}
+65 -7
View File
@@ -1,20 +1,78 @@
<template>
<div id="navigation">
<el-menu class="centered" :default-active="activeIndex" mode="horizontal" @select="onSelect">
<el-menu style="margin-bottom: 10px;" class="centered" mode="horizontal"
:default-active="nav.id" @select="onSelect">
<div id="nav-title">
<img id="nav-logo" alt="logo" src="../../assets/logo.png">
<span id="nav-logo-text" class="logo-text">Veracross Analyzer</span>
<span id="nav-logo-version">v{{version}}</span>
</div>
<el-menu-item index="overall">Overall</el-menu-item>
<el-submenu index="courses">
<el-submenu index="">
<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-menu-item v-for="course in app.gradedCourses"
:index="JSON.stringify(course.urlIndex)"
:key="course.id">{{course.name}}</el-menu-item>
</el-submenu>
<el-menu-item index="course-selection">Course Selection</el-menu-item>
<!-- Grading period selection -->
<el-dropdown id="nav-grading-period" @command="selectGradingPeriod">
<el-button type="primary" size="medium">
{{gradingPeriod}}<i class="el-icon-arrow-down el-icon--right"/>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="Term 1">Term 1</el-dropdown-item>
<el-dropdown-item command="Term 2">Term 2</el-dropdown-item>
<el-dropdown-item command="Term 3">Term 3</el-dropdown-item>
<el-dropdown-item command="Term 4">Term 4</el-dropdown-item>
<!-- TODO: Auto enable / disable quarters -->
<el-dropdown-item command="All Year" divided>All Year</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- User avatar -->
<el-dropdown id="nav-avatar" trigger="click" @command="onAvatarMenu">
<el-avatar :src="user.avatarUrl"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item style="text-align: center">{{user.firstName}}</el-dropdown-item>
<el-dropdown-item icon="el-icon-sunrise" command="switch-dark" divided>
{{!app.darkMode ? 'Dark Mode (Unfinished)' : 'Light Mode'}}
</el-dropdown-item>
<el-dropdown-item icon="el-icon-edit-outline" command="switch-rating">
{{app.showRating ? 'Hide rating buttons' : 'Show rating button'}}
</el-dropdown-item>
<el-dropdown-item icon="el-icon-cold-drink" command="updates">
Check out the updates
</el-dropdown-item>
<el-dropdown-item icon="el-icon-switch-button" command="sign-out" divided>Sign Out</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-menu>
<div class="line"></div>
<!-- Previous course / Next course (Only when the page is courses) -->
<div v-if="nav.id === 'course' && findNextCourse(-1) != null"
@click="nextCourse(-1)" id="prev-course" class="nav-course-operations unselectable">
PREVIOUS COURSE
</div>
<footer>
<div v-if="nav.id === 'course' && findNextCourse(1) != null"
@click="nextCourse(1)" id="next-course" class="nav-course-operations unselectable">
NEXT COURSE
</div>
</footer>
<!-- Back to top -->
<el-backtop style="box-shadow: rgba(0, 0, 0, 0.23) 0 3px 11px 0;"/>
</div>
</template>
<script src="./navigation.ts" lang="ts"></script>
<style src="./navigation.scss" lang="scss"></style>
<style src="./navigation.scss" lang="scss"/>
+112
View File
@@ -0,0 +1,112 @@
<template>
<div id="loading">
<div id="text" :class="message">
{{message}}
<div v-if="!error" class="el-loading-spinner">
<svg viewBox="25 25 50 50" class="circular">
<circle cx="50" cy="50" r="20" fill="none" class="path" />
</svg>
</div>
<div v-if="error" id="error-details">
<span v-for="(line, index) in split" :style="`font-size: ${-index === 0 ? 16 : 12}px;`">
{{line}}
<br>
</span>
</div>
</div>
<div v-if="!error" id="details">
<span v-for="(line, index) in split" :style="`font-size: ${16 - split.length + index}px;`">
{{line}}
<br>
</span>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
@Component
export default class Loading extends Vue
{
@Prop({required: true}) text: string;
@Prop({required: true}) error: boolean;
get split()
{
return this.text.split('\n');
}
get message()
{
return this.error ? 'Error' : 'Loading';
}
}
</script>
<style scoped>
#loading
{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
box-shadow: inset 0 0 1px 1px rgba(0,0,0,.1);
background: -webkit-linear-gradient(left, rgba(95, 18, 72, 0.4), rgba(42, 81, 117, 0.4) 100%);
text-align: center;
}
.Error
{
color: #ffdddd !important;
}
#text
{
color: white;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 46px;
}
#details
{
width: 100%;
position: absolute;
bottom: 0;
left: 0;
margin-top: -5px;
font-size: 16px;
color: #f9f9f9;
}
#error-details
{
font-size: 16px;
}
.el-loading-spinner
{
top: unset !important;
margin-top: 0 !important;
width: unset !important;
position: unset !important;
}
.el-loading-spinner .path
{
stroke: white;
}
</style>
+63
View File
@@ -0,0 +1,63 @@
<template>
<div id="maintenance">
<div id="maintenance-content">
<h1>We&rsquo;ll be back soon!</h1>
<div>
<p>Sorry for the inconvenience but we&rsquo;re performing some maintenance at the moment.
We&rsquo;ll be back online shortly!</p>
<p>What went wrong: {{json.reason}}</p>
<p>Estimated fix: {{json.eta}}</p>
<p>&mdash; An Average SJP Junior</p>
</div>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
@Component
export default class Maintenance extends Vue
{
@Prop({required: true}) message: any;
get json()
{
return JSON.parse(this.message);
}
}
</script>
<style lang="scss" scoped>
#maintenance
{
z-index: 1000;
background: white;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
#maintenance-content
{
font: 20px Helvetica, sans-serif;
color: #333;
display: block;
text-align: left;
margin: 150px;
h1
{
font-size: 50px;
}
a {color: #dc8100; text-decoration: none;}
a:hover {color: #333; text-decoration: none;}
}
}
</style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+36
View File
@@ -0,0 +1,36 @@
<template>
<div class="background">
<span :style="{width: (score / 5 * 100).toFixed(2) + '%'}" class="rating"/>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'
@Component
export default class StarRating extends Vue
{
@Prop({required: true}) score: number;
}
</script>
<style lang="scss" scoped>
.background
{
background: url("./star-rating-sprite.png") repeat-x;
font-size: 0;
height: 21px;
line-height: 0;
overflow: hidden;
width: 110px;
margin: 0 auto;
span.rating
{
background: url("./star-rating-sprite.png") repeat-x 0 100%;
float: left;
height: 21px;
display: block;
}
}
</style>
+70 -7
View File
@@ -1,18 +1,81 @@
/**
* This class stores the static constants.
*/
import {findLastIndex} from '@/logic/utils/general-utils';
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';
/** Base url for api access */
static API_URL: string = 'https://va.hydev.org/api';
// static API_URL: string = 'http://localhost:24021/api';
public static SPLASH: string =
/** Current version */
static VERSION: string = '0.5.6.1761';
/** The minimum version that still supports the same cookies */
static MIN_SUPPORTED_VERSION: string = '0.4.6.1087';
static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client';
static SPLASH: string =
'. , ,---. | \n' +
'| |. , |---|,---.,---.| , .,---,,---.,---.\n' +
' \\ / >< | || |,---|| | | .-\' |---\'| \n' +
' `\' \' ` ` \'` \'`---^`---\'`---|\'---\'`---\'` \n' +
' v1.1.0 `---\' '
' `---\' \n' +
` Version v${Constants.VERSION} by Hykilpikonna (YGui21)\n` +
` Github: ${Constants.GITHUB}`;
// Graph Theme
static THEME =
{
// Colors
colors:
[
'#19d4ae',
'#5ab1ef',
'#fa6e86',
'#ffb980',
'#0067a6',
'#c4b4e4',
'#d87a80',
'#9cbbff',
'#d9d0c7',
'#87a997',
'#d49ea2',
'#5b4947',
'#7ba3a8',
'#fc97af',
'#919e8b',
'#d7ab82',
'#6e7074',
'#61a0a8',
'#efa18d',
'#787464',
'#cc7e63',
'#724e58',
'#4b565b'
]
};
// Terms (TODO: Actually get the terms dynamically
static TERMS =
[
new Date('Sep 04 2019'),
new Date('Nov 03 2019'),
new Date('Jan 19 2020'),
new Date('Mar 22 2020'),
new Date('Jun 05 2020'),
];
static CURRENT_TERM = Constants.getTerm(new Date());
/**
* Find out the specified date is in which term
*
* @param date
*/
static getTerm(date: Date)
{
return findLastIndex(Constants.TERMS, d => d <= date);
}
}
+176
View File
@@ -0,0 +1,176 @@
import {CourseUtils} from '@/logic/utils/course-utils';
export default class CourseInfo
{
id_ci: number
year: number
name: string
teacher: string
level: string
courseIds: number[]
uniqueName: string
courseCount: number
gradeLevels: number[]
enrollments: number
classes: ClassInfo[]
levelID: number;
levelFull: string
rating: AnalyzedRating = null as any as AnalyzedRating
/**
* Construct with a json object
*
* @param json
*/
constructor(json: any)
{
this.id_ci = json.id_ci
this.year = json.year
this.name = json.name.trim().replace('&amp;', '&').replace('&quot;', '"')
this.teacher = json.teacher
this.level = json.level
this.courseIds = json.courseIds.split('|').map((id: string) => +id);
this.courseCount = this.courseIds.length;
this.gradeLevels = [];
this.uniqueName = CourseInfo.toUniqueName(this.name);
this.enrollments = 0;
this.classes = []
this.levelID = CourseUtils.getLevelID(this.level);
this.levelFull = CourseUtils.getLevelFullName(this.level);
}
static toUniqueName(name: string)
{
return name
.replace(/( Semester| Full Year|)/g, '')
.replace(/( Accelerated| Honors| College Prep|)/g, '')
.replace(/( A| Acc| CP| H| \(.*\))$/g, '');
}
}
export class UniqueCourse
{
name: string
courses: CourseInfo[]
enrollments: number
constructor(name: string, courses: CourseInfo[], enrollments: number)
{
this.name = name;
this.courses = courses;
this.enrollments = enrollments;
}
get classes()
{
return this.courses.flatMap(c => c.classes);
}
}
export class ClassInfo
{
id: number
name: string
teacher: string
level: string
uniqueName: string
/**
* Construct with a json object
*
* @param json
*/
constructor(json: any)
{
this.id = json.id;
this.name = json.name.trim().replace('&amp;', '&').replace('&quot;', '"')
this.teacher = json.teacher
this.level = json.level;
this.uniqueName = CourseInfo.toUniqueName(this.name);
}
}
export class CourseInfoRating
{
id_ci: number
id_user: number
firstName: string
lastName: string
anonymous: boolean
ratings: number[]
comment: string
averageRating: number = 0
constructor(json: any)
{
this.id_ci = json.id_ci;
this.id_user = json.id_user;
this.anonymous = this.id_user == -1;
this.ratings = json.ratings;
this.comment = json.comment;
if (json.userFullName != null)
{
let nameSplit = json.userFullName.split(']=[');
this.firstName = nameSplit[0];
this.lastName = nameSplit[1];
}
this.ratings.forEach(r => this.averageRating += r);
this.averageRating /= 5;
}
/**
* Create new for posting to the server
* @param id_ci
*/
public static createNew(id_ci: number)
{
return new CourseInfoRating({id_ci: id_ci, id_user: -2, userFullName: null,
anonymous: false, ratings: [0,0,0,0,0], comment: ''})
}
}
export class AnalyzedRating
{
ratingCounts: number[][] // ratingCounts[criteria][stars] = count
ratingSums: number[] // ratingSums[criteria] = total stars
totalCount: number
ratingAverages: number[] = [] // ratingAverages[criteria] = average
overallRating: number = 0
constructor(json: any)
{
this.ratingCounts = json.ratingCounts;
this.ratingSums = json.ratingSums;
this.totalCount = json.totalCount;
// No ratings
if (this.totalCount == 0)
{
this.overallRating = -1;
return;
}
// Calculate overall rating
this.ratingSums.forEach((criteriaScore, i) => this.overallRating += this.ratingAverages[i] = criteriaScore / this.totalCount);
this.overallRating /= this.ratingAverages.length;
}
}
export const RATING_CRITERIA: {title: string, desc: string}[] =
[
{title: 'Enjoyable', desc: 'How enjoyable is the course?'},
{title: 'Knowledge', desc: 'How interesting is the content of the course? ' +
'Is it something you feel worth learning?'},
{title: 'Interactivity', desc: 'How interesting is the teacher? Is the teacher interactive?'},
{title: 'Eloquence', desc: `Are the teacher's lectures easy to understand?`},
{title: 'Fairness', desc: `How fair is the teacher's grading? Is credit given in proportion to effort?`}
];
+436
View File
@@ -0,0 +1,436 @@
import {FormatUtils} from '@/logic/utils/format-utils';
import {CourseUtils} from '@/logic/utils/course-utils';
import Navigation from '@/components/navigation/navigation';
import {GPAUtils} from '@/logic/utils/gpa-utils';
import CacheUtils from '@/logic/utils/cache-utils';
import Constants from '@/constants';
import {Index} from '@/logic/nav-controller';
import App from '@/components/app/app';
import {CourseInfoRating} from '@/logic/course-info';
/**
* Objects of this interface represent assignment grades.
*/
export class Assignment
{
id: number;
scoreId: number;
type: string;
typeId: number;
description: string;
time: number;
complete: string;
include: boolean;
display: boolean;
unread: boolean;
scoreMax: number;
score: number;
gradingPeriod: number;
// Callbacks when this object updates
private updateCallbacks: (() => void)[] = [];
/**
* Construct assignment with json object
*
* @param json Json object
*/
constructor(json: any)
{
this.id = json.assignment_id;
this.scoreId = json.score_id;
this.type = json.assignment_type;
this.typeId = json.assignment_type_id;
this.description = json.assignment_description;
this.time = new Date(json._date).getTime();
this.complete = json.completion_status;
this.include = json.include_in_calculated_grade == 1;
this.display = json.display_grade == 1;
this.unread = json.is_unread == 1;
this.scoreMax = json.maximum_score;
this.score = +json.raw_score;
// 0, 1, 2, 3 contains quarter assignments, 4 contains final assignments
if (json.grading_period.toLowerCase() == 'all') this.gradingPeriod = 4;
else this.gradingPeriod = +json.grading_period.replace('Quarter ', '') - 1;
}
/**
* Graded or not
*/
get graded()
{
// TODO: Add more cases
// Incomplete doesn't mean that the teacher didn't grade it yet, which is "Pending".
// NREQ is not graded.
return this.include && (this.complete == 'Complete' || this.complete == 'Late' || this.complete == 'Incomplete' || this.complete == 'Not Turned In');
}
/**
* What is the problem with this assignment
*
* @return string Empty string if complete, otherwise return problem.
*/
get problem()
{
switch (this.complete)
{
case 'Pending': return 'Pending'; // ID: 0
case 'Not Turned In': return 'Not Turned In'; // ID: 1
case 'Incomplete': return 'Incomplete'; // ID: 2
case 'Complete': return ''; // ID: 3
case 'NREQ': return 'Dropped'; // ID: 4
case 'Late': return 'Late';
default: return this.complete;
}
}
/**
* Get the text color of the problem
*/
get problemColor()
{
switch (this.complete)
{
case 'Pending': return '#b1b1b1';
case 'Not Turned In': return '#ff0036';
case 'Incomplete': return '#ff7a2f';
case 'NREQ': return '#41b141';
case 'Late': return '#ff7a2f';
}
}
/**
* Add callback
*
* @param callback
*/
addCallback(callback: () => void)
{
this.updateCallbacks.push(callback);
}
/**
* Mark as read
*/
markAsRead(): Promise<void>
{
return new Promise((resolve, reject) => {
App.http.post('/mark-as-read', {scoreId: this.scoreId})
.then(response =>
{
// Check success
if (response.success)
{
this.unread = false;
this.updateCallbacks.forEach(callback => callback());
resolve();
}
else reject(response.data);
})
.catch(reject)
})
}
}
export interface AssignmentType
{
id: number
name: string
weight: number
scoreMax: number
score: number
percent: number
assignmentCount: number
graded: boolean
}
export interface Grading
{
method: string
weightingMap: {[index: string]: number}
}
export default class Course
{
id: number
id_ci: number
assignmentsId: number
name: string
teacherName: string
status: string
rawAssignments: Assignment[]
rating: CourseInfoRating
rated: boolean
rawLetterGrade?: string
rawNumericGrade?: number
level: string
scaleUp: number
termGrading: Grading[]
termAssignments: Assignment[][]
cache: CacheUtils = new CacheUtils();
/**
* Construct a course with a course json object
*
* @param courseJson Course json object
*/
constructor(courseJson: any)
{
this.id = courseJson.id;
this.id_ci = courseJson.id_ci;
this.assignmentsId = courseJson.assignmentsId;
this.name = FormatUtils.parseText(courseJson.name).trim();
this.teacherName = courseJson.teacherName;
this.status = courseJson.status;
this.rated = courseJson.rating != null;
this.rating = this.rated ? new CourseInfoRating(courseJson.rating) : CourseInfoRating.createNew(this.id_ci);
this.rawLetterGrade = courseJson.letterGrade;
this.rawNumericGrade = courseJson.numericGrade;
// Other api issue
if (this.rawLetterGrade == '')
{
this.rawNumericGrade = undefined;
this.rawLetterGrade = undefined;
}
// Level and scaleUp TODO: Use server course level
let level = CourseUtils.getLevel(courseJson.level);
this.level = level.level;
this.scaleUp = level.scaleUp;
this.termGrading = new Array(4).fill(null);
}
/**
* Load in assignments data
*
* @param data Assignments data
*/
loadAssignments(data: any)
{
// Load assignments
// Parse json and filter it
this.rawAssignments = data.assignments.map((a: any) => new Assignment(a));
// Sort by date (Latest is at 0)
this.rawAssignments.sort((a, b) => b.time - a.time);
// Filter assignments into terms
this.termAssignments = [[], [], [], [], []];
// Loop through it by time order
this.rawAssignments.forEach(a => this.termAssignments[a.gradingPeriod].push(a));
}
/**
* Is graded or not
*/
get isGraded(): boolean
{
// Skip future or past courses
if (this.status != 'active') return false;
// Skip courses without levels TODO: Ask for user input
if (this.level == 'None' || this.level == 'Unknown' || this.scaleUp == -1) return false;
// Skip courses without graded assignments
if (this.assignments.length == 0) return false;
// Skip if there are no grading scale
// if (course.grading.method == 'NOT_GRADED') return;
// Is graded
return true;
}
/**
* Get currently selected grading periods
*/
get gradingPeriods(): number[]
{
return this.cache.get('GradingPeriods', () =>
{
return (this.rawSelectedTerm == -1 ? [0, 1, 2, 3] : [this.rawSelectedTerm]).filter(term =>
this.termAssignments[term].filter(a => a.graded).length != 0);
})
}
/**
* Get currently selected grading periods
*/
get allGradingPeriods(): number[]
{
return this.cache.get('AllGradingPeriods', () =>
{
return [0, 1, 2, 3].filter(term => this.termAssignments[term].filter(a => a.graded).length != 0);
})
}
/**
* Get assignments of the selected grading periods
*/
get assignments(): Assignment[]
{
return this.gradingPeriods
.flatMap(term => this.termAssignments[term])
.sort((a, b) => b.time - a.time);
}
/**
* Get assignments before a certain date
*
* @param time
*/
getAssignmentsBefore(time: number): {term: number, assignments: Assignment[]}
{
let term = Constants.getTerm(new Date(time));
let assignments = this.assignments.filter(a => a.gradingPeriod == term && a.time <= time);
return {term: term, assignments: assignments}
}
/**
* Get letter grade
*/
get letterGrade(): string
{
return this.cache.get('LetterGrade', () =>
{
// Get scale
let scale = GPAUtils.findScale(this.numericGrade);
// Scale not found
return scale == undefined ? '--' : scale.letter;
})
}
/**
* Get letter grade by term
*
* @param term
*/
letterGradeTerm(term: number): string
{
return this.cache.get('LetterGrade' + term, () =>
{
// Get scale
let scale = GPAUtils.findScale(this.numericGradeTerm(term));
// Scale not found
return scale == undefined ? '--' : scale.letter;
})
}
/**
* Get numeric grade
*/
get numericGrade()
{
return this.cache.get('NumericGrade', () =>
{
return this.gradingPeriods.map(term => this.numericGradeTerm(term))
.reduce((p, v) => p + v) / this.gradingPeriods.length
})
}
/**
* Get numeric grade by term
*
* @param term
*/
numericGradeTerm(term: number): number
{
return this.cache.get('NumericGrade' + term, () =>
{
// Calculate
if (this.termGrading[term].method == 'PERCENT_TYPE')
{
return GPAUtils.getPercentTypeAverage(this.termGrading[term], this.termAssignments[term]);
}
else if (this.termGrading[term].method == 'TOTAL_MEAN')
{
return GPAUtils.getTotalMeanAverage(this.termAssignments[term]);
}
else return -1;
})
}
/**
* Get assignment types
*/
get assignmentTypes(): AssignmentType[]
{
return this.cache.get('AssignmentTypes', () =>
{
// Get all types
let types = this.assignments.map(a => a.type);
// Remove duplicates
types = types.filter((type, i, a) => a.indexOf(type) == i);
// Get total possible score for weight calculation
let totalScoreMax = this.assignments.reduce((sum, a) => sum + a.scoreMax, 0);
// For every type...
return types.map(type =>
{
// Get assignments of the type
let typeAssignments = this.assignments.filter(a => a.type == type);
// Get graded assignments
let gradedAssignments = typeAssignments.filter(a => a.graded);
// Count scores and max scores
let score = gradedAssignments.reduce((sum, a) => sum + a.score, 0);
let scoreMax = gradedAssignments.reduce((sum, a) => sum + a.scoreMax, 0);
// Calculate weight
let weight = this.termGrading[0].method == 'PERCENT_TYPE'
? this.termGrading[0].weightingMap[type] : scoreMax / totalScoreMax;
// Return
return {name: type, id: typeAssignments[0].typeId, weight: +(weight * 100).toFixed(2),
scoreMax: scoreMax, score: score, percent: +(score / scoreMax * 100).toFixed(2),
assignmentCount: typeAssignments.length, graded: gradedAssignments.length > 0}
})
})
}
/**
* Get url hash code
*/
get urlHash(): string
{
return `course/${this.id}`
}
/**
* Get navigation index
*/
get urlIndex(): Index
{
return {hash: this.urlHash, title: this.name, identifier: 'course', info: {id: this.id}}
}
/**
* Selected term
*/
get rawSelectedTerm(): number
{
return Navigation.instance.getSelectedTerm()
}
}
+56
View File
@@ -0,0 +1,56 @@
import {GPAUtils} from '@/logic/utils/gpa-utils';
import Course from '@/logic/course';
const md5 = require('md5');
export default class LoginUser
{
id: number
schoolPersonPk: number
username: string
lastLogin: Date
firstLogin: Date
firstName: string
lastName: string
graduationYear: number
emails: string[]
classes: string[]
avatarUrl: string
token: string
courses: Course[]
gradeLevel: number
gradeLevelName: string
constructor(jsonData: any)
{
let json = jsonData.user
this.id = json.id;
this.schoolPersonPk = json.schoolPersonPk;
this.username = json.username;
this.lastLogin = new Date(json.lastLogin);
this.firstLogin = new Date(json.firstLogin);
this.firstName = json.firstName;
this.lastName = json.lastName;
this.graduationYear = +json.graduationYear;
this.emails = json.emails.split('|').map((e: any) => e.toLowerCase().trim());
this.classes = json.classes.split('|');
this.avatarUrl = json.avatarUrl;
// Extracted in newer versions
this.token = jsonData.token;
this.courses = jsonData.courses.map((courseJson: any) => new Course(courseJson));
// Calculated grade level
this.gradeLevel = GPAUtils.getGradeLevel(this.graduationYear);
this.gradeLevelName = GPAUtils.gradeLevelName(this.gradeLevel);
// Generate default avatar
if (this.avatarUrl == null || this.avatarUrl == '')
{
this.avatarUrl = `https://www.gravatar.com/avatar/${md5(this.emails[0])}?d=404` + encodeURIComponent(
`https://ui-avatars.com/api/${this.firstName.charAt(0)}${this.lastName.charAt(0)}/128`);
}
}
}
+160
View File
@@ -0,0 +1,160 @@
import {FormatUtils} from '@/logic/utils/format-utils';
import pWaitFor from 'p-wait-for';
import App from '@/components/app/app';
export interface Index
{
hash: string
title?: string
identifier: string
info?: any
}
export default class NavController
{
// Current index
index: Index;
// Callback
updateCallback?: () => void;
constructor()
{
// Create history state listener
window.onpopstate = (e: any) =>
{
if (e.state)
{
// Restore previous tab
//console.log(`onPopState: Current: ${this.index.hash}, Previous: ${e.state.hash}`);
this.updateIndex(e.state, false);
}
};
// Initialize
this.init()
}
/**
* Initialize from last location
*/
private init()
{
if (window.location.hash == '#info') return;
// Check history from last session
if (window.history.state != undefined && window.history.state.hash != undefined)
{
// Last history exists
this.index = window.history.state;
return;
}
// Last history doesn't exist but hash url might exist
let hash = window.location.hash.replace('#', '');
// Check hash
if (hash == '')
{
// No location info in url, set page to overall
window.history.replaceState(this.convertIndex('overall'), '', '/#overall');
this.updateIndex('overall', false);
return;
}
// There is hash info in url
let split = hash.split('/');
// Not course -> don't know what to do with this url, so just refresh
if (split[0] != 'course')
{
this.initClear();
return;
}
// Is course -> Update index with placeholder title
this.updateIndex({hash: hash, title: `Loading...`, identifier: 'course', info: {id: +split[1]}}, false);
// Wait for courses to finish loading
pWaitFor(() => App.instance != undefined && App.instance.assignmentsReady).then(() =>
{
// Find course
let course = App.instance.courses.find(c => c.id == +split[1]);
// This person has no such course, refresh to overall
if (course == null)
{
this.initClear();
return;
}
window.history.replaceState(course.urlIndex, '', '/#' + course.urlHash);
this.updateIndex(course.urlIndex, false);
})
}
private initClear()
{
window.location.hash = '';
window.location.reload();
}
/**
* Update index
*
* @param index Hash and title | Hash only
* @param history Record in history or not (Default true)
*/
updateIndex(index: Index | string, history: boolean = true)
{
index = this.convertIndex(index);
// Call custom event
if (this.updateCallback != null) this.updateCallback();
// Record history or not
if (history)
{
//console.log(`history: Current: ${this.index.hash}, New: ${index.hash}`);
// Check url
let url = `/#${index.hash}`;
// Push history state
window.history.pushState(index, '', url);
}
// Update title
document.title = 'Veracross Analyzer - ' + index.title;
// Scroll to top
window.scrollTo(0, 0);
// Update selected index
this.index = index;
}
/**
* Check index conversion
*
* @param index Hash and title | Hash only
* @return Index Hash and title
*/
private convertIndex(index: Index | string): Index
{
// Convert index format if it is hash only
if (typeof index == 'string') index = {hash: index, identifier: index};
if (index.title == null) index.title = FormatUtils.toTitleCase(index.hash);
return index;
}
get id(): string
{
return this.index.identifier
}
get info(): any
{
return this.index.info
}
}
+20
View File
@@ -0,0 +1,20 @@
export default class CacheUtils
{
map: Map<string, any> = new Map();
/**
* Get a cached value, or if not cached, cache it.
*
* @param name Name of the cached value
* @param callback Callback function
*/
public get(name: string, callback: () => any)
{
if (!this.map.has(name))
{
this.map.set(name, callback());
}
return this.map.get(name);
}
}
+96
View File
@@ -0,0 +1,96 @@
import Navigation from '@/components/navigation/navigation';
import Constants from '@/constants';
import {isNumeric} from '@/logic/utils/general-utils';
const LEVEL_AP = {level: 'AP', scaleUp: 1};
const LEVEL_H = {level: 'H', scaleUp: 0.75};
const LEVEL_A = {level: 'A', scaleUp: 0.5};
const LEVEL_CP = {level: 'CP', scaleUp: 0.25};
const LEVEL_CLUB = {level: 'Club', scaleUp: -1};
const LEVEL_SPORT = {level: 'Sport', scaleUp: -1};
const LEVEL_NONE = {level: 'None', scaleUp: -1};
const LEVEL_UNKNOWN = {level: 'Unknown', scaleUp: -1};
export class CourseUtils
{
/**
* Get the begin date of the selected term
*/
static getTermBeginDate()
{
let selected = Navigation.instance.getSelectedTerm();
return selected == -1 ? Constants.TERMS[0] : Constants.TERMS[selected];
}
/**
* Get the end date of the selected term
*/
static getTermEndDate()
{
let selected = Navigation.instance.getSelectedTerm();
return selected == -1 ? Constants.TERMS[4] : Constants.TERMS[selected + 1];
}
static getLevelID(level: string)
{
if (level == undefined) return -1;
level = level.toLowerCase();
if (level == 'ap' || level == 'advanced placement') return 1;
if (level == 'h' || level == 'honors') return 2;
if (level == 'a' || level == 'acc' || level == 'accelerated') return 3;
if (level == 'cp' || level == 'college prep') return 4;
if (level == 'club') return 101;
if (level == 'sport') return 102;
if (level == 'none') return 201;
if (isNumeric(level)) return +level;
return -1;
}
/**
* Get full name of a level from short name
*
* @param level Any level name
*/
static getLevelFullName(level: string)
{
switch (this.getLevelID(level))
{
case 1: return 'AP';
case 2: return 'Honors';
case 3: return 'Accelerated';
case 4: return 'CP';
case 101: return 'Club';
case 102: return 'Sport';
case 201: return 'None';
default: return '--';
}
}
/**
* Get full name of a level from short name
*
* @param level Any level name
*/
static getLevel(level: string)
{
switch (this.getLevelID(level))
{
case 1: return LEVEL_AP;
case 2: return LEVEL_H;
case 3: return LEVEL_A;
case 4: return LEVEL_CP;
case 101: return LEVEL_CLUB;
case 102: return LEVEL_SPORT;
case 201: return LEVEL_NONE;
default: return LEVEL_UNKNOWN;
}
}
}
+34
View File
@@ -0,0 +1,34 @@
export class FormatUtils
{
/**
* Limit string length
*
* @param str String
* @param length Max length
*/
public static limit(str: string, length: number): string
{
return str.length <= length ? str : str.substr(0, length - 2) + '...'
}
/**
* To Title Case
*
* @param str oRigInAL sTrING
* @return string Original String
*/
public static toTitleCase(str: string)
{
return str.replace(/\w\S*/g, s => s.charAt(0).toUpperCase() + s.substr(1).toLowerCase())
}
/**
* Parse html text
*
* @param str
*/
public static parseText(str: string): string
{
return str.replace(/&amp;/g, '&');
}
}
+12
View File
@@ -0,0 +1,12 @@
export function findLastIndex<T>(array: T[], callback: (v: T) => boolean): number
{
let arr2 = array.slice().reverse();
let result = arr2.findIndex(callback);
return result == -1 ? -1 : arr2.length - result - 1;
}
export function isNumeric(str: string)
{
return !isNaN(parseFloat(str)) && isFinite(+str);
}
+232
View File
@@ -0,0 +1,232 @@
import Course, {Assignment, Grading} from '@/logic/course';
export interface Scale
{
min: number
letter: string
gp: number
}
/**
* This is an utility class to calculate GPA.
*/
export class GPAUtils
{
// [[Min score, Letter grade, Base GPA], ...]
public static SCALE: Scale[] =
[
{min: 96.5, letter: 'A+', gp: 4.00},
{min: 92.5, letter: 'A' , gp: 3.75},
{min: 89.5, letter: 'A-', gp: 3.50},
{min: 86.5, letter: 'B+', gp: 3.25},
{min: 82.5, letter: 'B' , gp: 3.00},
{min: 79.5, letter: 'B-', gp: 2.75},
{min: 76.5, letter: 'C+', gp: 2.50},
{min: 72.5, letter: 'C' , gp: 2.25},
{min: 70.5, letter: 'C-', gp: 2.00},
{min: 69.5, letter: 'D' , gp: 1.00},
{min: 0 , letter: 'F' , gp: 0.00}
];
/**
* Calculate GPA for a list of couses
*
* @param coursesOriginal List of courses
*/
public static getGPA(coursesOriginal: Course[]): {gpa: number, accurate: boolean, max: number}
{
// 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.letterGrade == null || course.letterGrade == '')
{
accurate = false;
}
else if (course.level != 'none' && !isNaN(course.numericGrade))
{
courses.push(course);
}
});
// If no course have grade, return -1
if (courses.length == 0)
{
return {gpa: -1, accurate: false, max: -1};
}
// Count total GPA
let totalGPA = 0;
let maxTotal = 0;
courses.forEach(course =>
{
totalGPA += this.getGP(course, course.numericGrade);
maxTotal += this.getGP(course, 'A+');
});
// Get average GPA, round to two decimal places
let gpa = Math.round(totalGPA / courses.length * 100) / 100;
let maxGPA = Math.round(maxTotal / courses.length * 100) / 100;
// Return results
return {gpa: gpa, accurate: accurate, max: maxGPA};
}
/**
* Calculate GPA for a course
*
* @param course Course
* @param letterGrade Letter grade
*/
public static getGP(course: Course, letterGrade: string | number): number
{
// Get scale
let scale = this.findScale(letterGrade);
// No scale
if (scale == undefined) return -1;
// Add scaleUp if not failed.
return scale.gp == 0 ? 0 : scale.gp + course.scaleUp;
}
/**
* Find the scale for a grade
*
* @param grade Letter grade or numeric grade
*/
public static findScale(grade: string | number): Scale | undefined
{
// Letter grade
if (typeof grade == 'string')
{
return this.SCALE.find(scale => scale.letter == grade);
}
// Numeric grade
return this.SCALE.find(scale => grade >= scale.min);
}
/**
* Calculate the total-mean (total/max) average
*
* @param assignments
*/
public static getTotalMeanAverage(assignments: Assignment[])
{
let score = 0;
let max = 0;
// Loop through assignments
assignments.forEach(assignment =>
{
// If assignment should be displayed
if (!assignment.graded) return;
// Record scores
score += assignment.score;
max += assignment.scoreMax;
});
// Return
return +(score / max * 100).toFixed(2);
}
/**
* Calculate the percent type
*
* @param grading
* @param assignments
*/
public static getPercentTypeAverage(grading: Grading, assignments: Assignment[])
{
let typeScores: {[index: string]: any} = {};
let typeCounts: {[index: string]: any} = {};
// Loop through assignments
assignments.forEach(assignment =>
{
// If assignment should be displayed
if (!assignment.graded) return;
// Record scores
if (typeScores[assignment.type] == undefined) typeScores[assignment.type] = 0;
typeScores[assignment.type] += assignment.score / assignment.scoreMax;
if (typeCounts[assignment.type] == undefined) typeCounts[assignment.type] = 0;
typeCounts[assignment.type] ++;
});
// Count total percentage (This is to avoid less than expected cases)
// Eg. If HW = 25% and Quiz = 75%, I have 1 hw and 0 quiz
// Without total percentage, the avg grade I get is 25%.
let totalPercentage = 0;
for (let type in grading.weightingMap)
{
if (typeScores[type] != undefined)
{
totalPercentage += grading.weightingMap[type];
}
}
// Count
let score = 0;
for (let type in typeScores)
{
let typeFactor = grading.weightingMap[type] / totalPercentage;
score += typeScores[type] * typeFactor / typeCounts[type];
}
// Add average to the row
return +(score * 100).toFixed(2);
}
/**
* Get current school year
*/
public static getSchoolYear(): number
{
// Get current year
let currentYear = new Date().getFullYear();
// Convert current year to current school year: +1 if it's after August
if (new Date().getMonth() > 7) currentYear ++;
return currentYear;
}
/**
* Get grade level from graduation year
*
* @param graduationYear
*/
public static getGradeLevel(graduationYear: number): number
{
// Calculate grade level
return 12 - (graduationYear - this.getSchoolYear());
}
/**
* Get grade level name from grade level. (Eg. Freshman, Sophomore, etc.)
*
* @param gradeLevel
*/
public static gradeLevelName(gradeLevel: number): string
{
switch (gradeLevel)
{
case 9: return 'Freshman';
case 10: return 'Sophomore';
case 11: return 'Junior';
case 12: return 'Senior';
default: return 'Grade ' + gradeLevel;
}
}
}
+103
View File
@@ -0,0 +1,103 @@
import Constants from '@/constants';
import App from '@/components/app/app';
export default class GraphUtils
{
static DOT = '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:{color}"></span>';
/**
* Base settings
*
* @param title
* @param subtitle
*/
static getBaseSettings(title?: String, subtitle?: String)
{
return {
// Color
color: Constants.THEME.colors,
backgroundColor: 'transparent',
// Title
title:
{
show: title != null,
textStyle:
{
fontSize: 13
},
text: title,
subtext: subtitle,
x: 'center'
},
}
}
/**
* Get term mark lines
*/
static getTermLines()
{
return {
silent: true,
symbol: 'none',
lineStyle: {color: Constants.THEME.colors[2]},
animationDuration: 500,
data: Constants.TERMS.map((term, index) =>
{
return {xAxis: term.getTime(), label: {formatter: `Term ${index + 1}`}}
})
}
}
/**
* Get mark areas for percentage scores
*/
static getGradeMarkAreas(opacity: number)
{
// TODO: Auto update after switching dark mode (possibly by refreshing)
opacity = App.instance.darkMode ? 0.1 : opacity;
return {
silent: true,
data:
[
// Above 100
[{itemStyle: {color: 'rgba(230,253,255)', opacity: opacity}, yAxis: 120}, {yAxis: 100}],
// 90 to 100
[{itemStyle: {color: 'rgba(241,255,237)', opacity: opacity}, yAxis: 100}, {yAxis: 90}],
// 80 to 90
[{itemStyle: {color: 'rgba(255,250,216)', opacity: opacity}, yAxis: 90}, {yAxis: 80}],
// 70 to 80
[{itemStyle: {color: 'rgba(255,225,199)', opacity: opacity}, yAxis: 80}, {yAxis: 70}],
// Below 70 (Fail)
[{itemStyle: {color: 'rgb(255,190,184)', opacity: opacity}, yAxis: 70}, {yAxis: -100}]
]
}
}
/**
* Text style for pie graphs or radar graphs
*/
static pieTextStyle()
{
return {
fontSize: 14,
textShadowColor: '#cfcfcf',
textShadowBlur: 2,
textShadowOffsetX: 1,
textShadowOffsetY: 1,
backgroundColor: '#f6f6f6',
borderRadius: 3,
padding: [3, 5]
}
}
/**
* CSS shadow string (extraCssText) for tooltip
*/
static tooltipCssShadow()
{
return {extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);'}
}
}
@@ -1,18 +1,14 @@
import Constants from '@/constants';
import LoginUser from '@/logic/login-user';
export class HttpUtils
{
public token: string = '';
constructor (token: string)
{
this.token = token;
}
public user: LoginUser;
public post(node: string, body: any): Promise<any>
{
// Add token
if (this.token != '') body['token'] = this.token;
if (this.user != null) body['token'] = this.user.token;
// Create promise
return new Promise<any>((resolve, reject) =>
@@ -32,4 +28,25 @@ export class HttpUtils
.catch(reject)
});
}
public get(url: string): Promise<any>
{
// Create promise
return new Promise<any>((resolve, reject) =>
{
// Fetch request
fetch(url, {method: 'GET'}).then(res =>
{
// Get response body text
res.text().then(text =>
{
// Parse response
let response = JSON.parse(text);
resolve(response);
})
.catch(reject)
})
.catch(reject)
});
}
}
+41
View File
@@ -0,0 +1,41 @@
export default class VersionUtils
{
/**
* Compare two version numbers
*
* Eg.
* compare('0.1.2', '0.1.3') = -1
* compare('1.0.0', '0.1.3') = 1
* compare('0.0.1', '0.0.1') = 0
*
* @param ver1 Version 1
* @param ver2 Version 2
* @return number (-1 if ver1 < ver2), (1 if ver1 > ver2), (0 if equal)
*/
public static compare(ver1: string, ver2: string): number
{
// Equal case
if (ver1 == ver2) return 0;
// Split
let split1 = ver1.split('.');
let split2 = ver2.split('.');
// Detect each number
for (let i in split1)
{
// Get numbers
let num1 = split1[i];
let num2 = split2[i];
// Current number is equal
if (num1 == num2) continue;
// Current number is different
return +num1 < +num2 ? -1 : 1;
}
// Equal
return 0;
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
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';
const VCharts = require('v-charts');
Vue.config.productionTip = false;
// Use Element UI
@@ -0,0 +1,81 @@
#course-list
{
margin-right: 20px;
height: 70vh;
.padding-fix
{
// Fix width issue
padding-left: 20px;
padding-right: 20px;
border-radius: 4px;
}
.header
{
.text
{
margin-top: 15px;
margin-bottom: 10px;
font-size: 24px;
}
.search
{
margin-bottom: 20px;
}
}
.list
{
overflow: scroll;
overflow-x: hidden;
height: 377px;
}
// Remove scrollbar
.list::-webkit-scrollbar
{
width: 0;
}
.item
{
text-align: left;
margin-bottom: 15px;
background: #fbfbfb;
border-radius: 4px;
padding: 5px 10px;
.name
{
// Text too long
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.data
{
// text-align: right;
color: #a5a5a5;
span
{
display: inline-block;
width: 40px;
// text-align: left;
font-size: 12px;
}
}
}
}
// Cards
.left
{
margin-left: 20px;
}
@@ -0,0 +1,197 @@
import {Component, Prop, Vue} from 'vue-property-decorator'
import App from '@/components/app/app';
import CourseInfo, {ClassInfo, UniqueCourse} from '@/logic/course-info';
import {GPAUtils} from '@/logic/utils/gpa-utils';
// @ts-ignore
import SearchSettingsComponent, {SearchSettings} from '@/pages/course-selection/pages/search-settings.vue';
import Welcome from '@/pages/course-selection/pages/welcome.vue';
import CourseDetail from '@/pages/course-selection/pages/course-detail.vue';
import LoadingSpinner from '@/components/loading-spinner.vue';
@Component({components: {SearchSettings: SearchSettingsComponent, Welcome, CourseDetail, LoadingSpinner}})
export default class CourseSelection extends Vue
{
@Prop({required: true}) app: App
search: string = ''
courseInfo: CourseInfo[] = []
courseIdIndex: any = {} // Map<CourseID, index in courseInfo>
directory: {gradeLevel: number, classes: string}[] = []
classes: ClassInfo[] = []
loading = true
courseListHeight: number = 0;
cardsHeight: number = 0;
openedPage: string = '';
settings: SearchSettings = new SearchSettings();
activeCourse: UniqueCourse = new UniqueCourse('', [], -1);
/**
* Called before rendering
*/
created()
{
// Update width dynamically
window.addEventListener('resize', this.updateHeight);
// Get courses
App.http.post('/course-info', {}).then(result =>
{
if (result.success)
{
// Parse data
this.classes = result.data.classes.map((json: any) => new ClassInfo(json));
this.courseInfo = result.data.courseInfos.map((json: any, index: number) =>
{
let info = new CourseInfo(json);
// Index
info.courseIds.forEach(id =>
{
this.courseIdIndex[id] = index;
// Add class info into course
let classInfo = this.classes.find(c => c.id == id)
if (classInfo == null) return;
info.classes.push(classInfo);
});
return info;
});
this.directory = result.data.studentInfos;
// Use directory data
this.directory.forEach(d =>
{
d.classes.split('|').forEach(classId =>
{
// Get info by class id
let info = this.courseInfo[this.courseIdIndex[+classId]];
if (info as any != null)
{
// Add grade level
if (!info.gradeLevels.includes(d.gradeLevel))
{
info.gradeLevels.push(d.gradeLevel);
}
// Count enrollments
info.enrollments ++;
}
})
})
this.loading = false;
}
});
}
/**
* Called on destroy
*/
destroyed()
{
// Remove width updater
window.removeEventListener('resize', this.updateHeight);
}
/**
* Called on vue update
*/
updated()
{
this.updateHeight()
}
/**
* Update header height. (CSS doesn't work)
*/
updateHeight()
{
// Get element
let cl = this.$refs.cl as Vue;
if (cl as any == null) return;
let el = cl.$el;
// Calculate height
this.cardsHeight = window.innerHeight - el.getBoundingClientRect().top - 20;
this.courseListHeight = this.cardsHeight - 15 - 102;
}
/**
* Open the settings page.
*/
openSettings()
{
this.openedPage = this.openedPage == 'settings' ? '' : 'settings';
}
/**
* Open course page.
*/
openCourse(course: UniqueCourse)
{
if (this.activeCourse == course)
{
this.openedPage = '';
this.activeCourse = null as any as UniqueCourse;
}
else
{
this.activeCourse = course;
this.openedPage = 'course'
}
}
get filteredCourses()
{
let year = GPAUtils.getSchoolYear();
return this.courseInfo.filter(c =>
c.uniqueName.toLowerCase().includes(this.search.toLowerCase()) &&
c.level != null && this.settings.levels.includes(c.level) &&
c.year == year &&
(this.settings.showAllCourses || c.gradeLevels.includes(this.app.user.gradeLevel + 1))
)
}
/**
* Gets unique courses by name, even though many different teachers might teach it.
*/
get uniqueCourses(): UniqueCourse[]
{
let names: string[] = [];
let list: UniqueCourse[] = [];
this.filteredCourses.forEach(c =>
{
// Create the course list if doesn't exist
if (!names.includes(c.uniqueName))
{
names.push(c.uniqueName);
list.push(new UniqueCourse(c.uniqueName, [], 0))
}
// Add the course
list[names.indexOf(c.uniqueName)].courses.push(c);
list[names.indexOf(c.uniqueName)].enrollments += c.enrollments;
})
// Sorting
switch (this.settings.sortBy)
{
case 'Popularity':
{
list.sort((a, b) => b.enrollments - a.enrollments);
break
}
default:
{
list.sort((a, b) => a.name.localeCompare(b.name));
break
}
}
return list;
}
}
@@ -0,0 +1,49 @@
<template>
<div id="course-selection">
<div v-if="loading" class="loading vertical-center" style="height: 100%">
<LoadingSpinner style="left: 0"/>
</div>
<el-row v-else>
<el-col :span="16" class="overall-span">
<el-card class="left" :style="{height: cardsHeight + 'px'}">
<SearchSettings v-if="openedPage === 'settings'" ref="settings" :settings="settings"/>
<Welcome v-if="openedPage === ''" :app="app"/>
<CourseDetail v-if="openedPage === 'course'" :unique-course="activeCourse"/>
</el-card>
</el-col>
<!-- Course list card -->
<el-col :span="8" class="overall-span">
<el-card id="course-list" class="right" ref="cl" body-style="padding: 0" :style="{height: cardsHeight + 'px'}">
<div class="header padding-fix">
<div class="text">Course List</div>
<!-- Search -->
<el-input class="search" placeholder="Search..." prefix-icon="el-icon-search" v-model="search">
<el-button slot="append" icon="el-icon-s-tools" @click="openSettings"/>
</el-input>
</div>
<!-- Actual course list -->
<div class="list padding-fix" :style="{height: courseListHeight + 'px'}">
<!-- Every course -->
<div v-for="(course, index) in uniqueCourses" class="item vertical-center clickable unselectable"
@click="openCourse(course)">
<div class="name">{{course.name}}</div>
<div class="data">
<span class="classes"><i class="el-icon-s-home"/> {{course.classes.length}}</span>
<span class="teachers"><i class="el-icon-user-solid"/> {{course.courses.length}}</span>
<span class="enrollments"><i class="el-icon-user"/> {{course.enrollments}}</span>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script src="./course-selection.ts" lang="ts"/>
<style src="./course-selection.scss" lang="scss" scoped/>
@@ -0,0 +1,269 @@
<template>
<div id="course-detail">
<div class="header">Course: <span style="color: #229fff">{{uniqueCourse.name}}</span></div>
<el-divider class="divider"><i class="el-icon-reading"></i></el-divider>
<!-- All course-infos -->
<div class="item clickable unselectable" v-for="c in sortedCourses" @click="openDetails(c)">
<div class="float-left">
<div>{{c.levelFull}} - <i>{{c.teacher}}</i></div>
<div class="info">
<span class="name">{{c.name}} : </span>
<span class="classes"><i class="el-icon-s-home"/> {{c.classes.length}}</span>
<span class="enrollments"><i class="el-icon-user"/> {{c.enrollments}}</span>
</div>
</div>
<div class="float-right">
<LoadingSpinner v-if="c.rating == null" class="loading" size="30" :centered="false"/>
<div v-else class="rating">
<span v-if="c.rating.totalCount === 0" class="text">No ratings yet...</span>
<span v-else class="stars">
<StarRating :score="c.rating.overallRating"></StarRating>
<span class="info">
<span class="numeric-rating">{{c.rating.overallRating.toFixed(2)}} / 5</span>
<span>({{c.rating.totalCount}} rating{{c.rating.totalCount > 1?'s':''}})</span>
</span>
</span>
</div>
</div>
</div>
<!-- Detail / Comments Popup -->
<el-dialog id="detail-popup" v-if="detailsCourse" :visible="detailsCourse != null" width="50%" top="10vh"
:before-close="closeDetails">
<span slot="title" class="header">
<div class="title">Ratings for {{detailsCourse.name}}</div>
<span class="subtitle">And for {{detailsCourse.teacher}}</span>
</span>
<div class="rating-item" v-for="(criteria, index) of ratingCriteria">
<div class="title float-left">{{criteria.title}}</div>
<div class="stars float-right">
<span class="info numeric-rating">{{rating.ratingAverages[index].toFixed(2)}} / 5</span>
<StarRating :score="rating.ratingAverages[index]" style="display: inline-block"></StarRating>
</div>
</div>
<div class="comments">
<div class="header">
Comments
</div>
<LoadingSpinner v-if="detailsComments == null"/>
<div class="comment" v-else v-for="comment of detailsComments">
<div class="user">
<i class="el-icon-user-solid"/>
{{comment.firstName}} {{comment.lastName}}:
<span class="info numeric-rating" style="margin-left: 5px">{{comment.averageRating.toFixed(2)}} / 5</span>
</div>
<div class="text">
<blockquote>{{comment.comment}}</blockquote>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'
import CourseInfo, {AnalyzedRating, CourseInfoRating, RATING_CRITERIA, UniqueCourse} from '@/logic/course-info';
import App from '@/components/app/app';
import course from '@/logic/course';
import LoadingSpinner from '@/components/loading-spinner.vue';
import loading from '@/components/overlays/loading.vue';
import StarRating from '@/components/star-rating.vue';
@Component({components: {StarRating, LoadingSpinner}})
export default class CourseDetail extends Vue
{
@Prop({required: true}) uniqueCourse: UniqueCourse;
detailsCourse: CourseInfo = null as any as CourseInfo
detailsComments: CourseInfoRating[] = null as any as []
get ratingCriteria() {return RATING_CRITERIA}
get rating() {return this.detailsCourse.rating}
mounted()
{
this.checkRatings()
}
updated()
{
this.checkRatings()
}
checkRatings()
{
// Load ratings
this.sortedCourses.forEach(c =>
{
// Already has rating
if (c.rating as any != null) return;
// Get rating
App.http.post('/course-info/rating/get', {condition: 'course', value: c.id_ci}).then(result =>
{
if (result.success)
{
// Assign rating
c.rating = new AnalyzedRating(result.data);
}
else
{
this.$message.error(`Rating data for ${c.name} / ${c.teacher} failed to load.`)
console.log(result.data);
}
})
})
}
get sortedCourses(): CourseInfo[]
{
return this.uniqueCourse.courses.sort((a, b) => a.levelID - b.levelID);
}
openDetails(course: CourseInfo)
{
let c = this.detailsCourse = this.detailsCourse == course ? null as any as CourseInfo : course;
// Load comments
App.http.post('/course-info/rating/get', {condition: 'course-comments', value: c.id_ci}).then(result =>
{
if (result.success)
{
this.detailsComments = result.data.map((r:any) => new CourseInfoRating(r));
}
else
{
this.$message.error(`Rating data for ${c.name} / ${c.teacher} failed to load.`)
console.log(result.data);
}
})
// TODO: Finish comment section
}
closeDetails()
{
this.detailsCourse = null as any as CourseInfo;
this.detailsComments = null as any as []
}
}
</script>
<style src="./pages.scss" lang="scss" scoped/>
<style lang="scss" scoped>
.item
{
text-align: left;
margin-bottom: 15px;
background: #f8fdff;
border-radius: 4px;
padding: 5px 10px;
height: 40px;
}
.info
{
font-size: 12px;
color: gray;
.classes
{
display: inline-block;
margin-right: 10px;
}
}
.numeric-rating
{
margin-right: 10px;
}
.float-left
{
text-align: left;
float: left;
}
.float-right
{
text-align: right;
float: right;
}
.loading
{
margin-top: 5px !important;
}
.rating
{
.text
{
font-size: 14px;
}
}
#detail-popup
{
text-align: left;
.header
{
.title
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: -10px;
}
.subtitle
{
margin-left: 10px;
font-size: 12px;
font-style: italic;
color: #999999;
}
}
.rating-item
{
height: 30px;
.title
{
font-size: 18px;
}
}
.rating-item:first-child
{
margin-top: -15px;
}
.comments
{
margin-top: 40px;
.comment
{
margin-bottom: 20px;
}
blockquote
{
padding: 0 1em;
/* color: #6a737d; */
border-left: .25em solid #dfe2e5;
margin: 5px 0 0 0;
}
}
}
</style>
@@ -0,0 +1,16 @@
.header
{
margin-top: 20px;
margin-bottom: 10px;
font-size: 24px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.divider
{
margin-top: 20px !important;
}
@@ -0,0 +1,70 @@
<template>
<div id="settings">
<div class="header">Settings</div>
<el-divider class="divider"><i class="el-icon-s-tools"></i></el-divider>
<div class="content">
<el-switch v-model="settings.showAllCourses" class="item"
active-text="Show all courses (including the ones not listed on your grade level)"/>
<div class="item">
<span class="item-label">Sort by:</span>
<el-radio-group v-model="settings.sortBy">
<el-radio label="Name"></el-radio>
<el-radio label="Popularity"></el-radio>
<el-radio label="Classes"></el-radio>
<el-radio label="Level"></el-radio>
<el-radio disabled label="Peer Rating (Coming soon)"></el-radio>
</el-radio-group>
</div>
<div class="item">
<span class="item-label">Levels:</span>
<el-checkbox-group v-model="settings.levels" style="display: inline-block;">
<el-checkbox label="AP">AP</el-checkbox>
<el-checkbox label="H">Honors</el-checkbox>
<el-checkbox label="A">Accelerated</el-checkbox>
<el-checkbox label="CP">CP</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'
import App from '@/components/app/app';
@Component
export default class SearchSettingsComponent extends Vue
{
@Prop({required: true}) settings: SearchSettings;
// TODO: Show all courses option
}
export class SearchSettings
{
showAllCourses: boolean = App.instance.user.gradeLevel == 12;
sortBy: string = 'Name'
levels: string[] = ['AP','H','A','CP']
}
</script>
<style src="./pages.scss" lang="scss" scoped/>
<style lang="scss" scoped>
.content
{
text-align: left;
.item
{
margin-bottom: 20px;
font-size: 14px;
.item-label,.el-radio,.el-checkbox
{
margin-right: 15px;
}
}
}
</style>
@@ -0,0 +1,63 @@
<template>
<div id="welcome">
<div class="header">Welcome</div>
<el-divider class="divider"><i class="el-icon-cold-drink"></i></el-divider>
<div class="content" style="color: #ff3d3d" v-if="app.user.gradeLevel >= 12">
You are a senior, what are you doing over here lol. <br>
Unfortunately I can't help you with college course selection.<br>
(But you can still view course ratings)<br><br>
</div>
<div class="content">
<span style="color:#409EFF">
This new page is designed to help you with your course selection for your {{nextGrade}} year,
providing more information such as how many people are currently enrolled in a course.
</span>
<br><br>
The courses displayed are from the current year,
but since they are unlikely to change,
they can provide a good view for the courses next year.
However, this also means that the new courses
and courses that didn't open this year are not going to be displayed here.
For 2020, the new courses are Financial Algebra and Acc Psychology.
Also, by default, only the courses that current {{nextGrade.toLowerCase()}}s take are displayed,
and you can enable "show all courses" in settings if you want to see all courses.
<br><br>
<b>Notations:</b><br>
<i class="el-icon-s-home"/>: How many classes (blocks) did the course open this year.<br>
<i class="el-icon-user-solid"/>: How many teachers are teaching this course.<br>
<i class="el-icon-user"/> How many students are enrolled.<br>
<br>
<b>Sorting:</b><br>
By default the courses are sorted by name,
but you can change the settings to sort by popularity, by classes, or by level.
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'
import App from '@/components/app/app';
import {GPAUtils} from '@/logic/utils/gpa-utils';
@Component
export default class Welcome extends Vue
{
@Prop({required: true}) app: App
get nextGrade()
{
return GPAUtils.gradeLevelName(this.app.user.gradeLevel + 1)
}
}
</script>
<style src="./pages.scss" lang="scss" scoped/>
<style lang="scss" scoped>
.content
{
text-align: justify;
color: #585858;
}
</style>
@@ -0,0 +1,80 @@
<template>
<div id="assignment-type-head">
<el-card :body-style="{padding: '0px'}">
<div id="type-info-card">
<span id="type-name">{{type.name}}</span>
<span class="type-average" v-if="type.graded">Average: {{type.percent}}%</span>
<span class="type-average" v-if="!type.graded">No grades yet!</span>
</div>
<AssignmentEntry v-for="(assignment, index) of filteredAssignments" :key="assignment.id"
:assignment="assignment" :unread="false"
:backgroundColor="index % 2 === 1 ? '#ffffff' : '#f7f7f7'" narrow="true">
</AssignmentEntry>
</el-card>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import AssignmentEntry from '@/pages/overall/overall-course/assignment-entry/assignment-entry.vue';
import {Assignment, AssignmentType} from '@/logic/course';
@Component({
components: {AssignmentEntry}
})
export default class AssignmentTypeHead extends Vue
{
@Prop({required: true}) type: AssignmentType;
@Prop({required: true}) assignments: Assignment[];
get filteredAssignments()
{
// Filter assignments to only this type
return this.assignments.filter(a => a.typeId == this.type.id);
}
}
</script>
<style lang="scss" scoped>
#assignment-type-head
{
margin-bottom: 20px;
}
#type-info-card
{
height: 60px;
}
#type-name
{
// Font
font-size: 22px;
color: var(--main);
// Center
height: 60px;
line-height: 60px;
// Alignment
padding-left: 20px;
float: left;
}
.type-average
{
// Font
font-size: 14px;
color: #8db3e4;
// Center
height: 60px;
line-height: 64px;
// Alignment
float: left;
margin-left: 15px;
display: inline-block;
}
</style>
+26
View File
@@ -0,0 +1,26 @@
// Card
.el-card.course-card
{
// Margins
margin-right: 20px;
margin-left: 20px;
// Limit name length
white-space: nowrap;
// Expansion color
background: #f4f6f9;
}
.course-card-content.expand
{
// Top shadow
// https://stackoverflow.com/questions/17572619/inset-box-shadow-only-on-one-side
box-shadow: inset 0 7px 9px -7px rgba(0,0,0,0.1);
}
.type-graph
{
padding-top: 23px;
height: 420px !important;
}
+71
View File
@@ -0,0 +1,71 @@
<template>
<el-card id="course-card" class="course-card">
<course-head :clickable="false" :course="course" :unread="countUnread()"/>
<div class="course-card-content expand">
<el-row>
<el-col :span="24" class="course-page-graph">
<el-card class="large overall-line-card vertical-center">
<course-scatter :course="course"/>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col :span="12" class="course-page-graph">
<el-card class="large overall-line-card vertical-center type-graph"
body-style="padding: 0">
<TypeRadar :course="course"/>
</el-card>
</el-col>
<el-col :span="12" class="course-page-graph">
<el-card class="large overall-line-card vertical-center type-graph"
body-style="padding: 0">
<TypePie :course="course"/>
</el-card>
</el-col>
</el-row>
<AssignmentTypeHead v-for="type in course.assignmentTypes" :key="type.id"
:type="type" :assignments="course.assignments">
</AssignmentTypeHead>
</div>
</el-card>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import CourseHead from '@/pages/overall/overall-course/course-head/course-head.vue';
import CourseScatter from '@/pages/course/course-scatter/course-scatter';
import AssignmentEntry from '@/pages/overall/overall-course/assignment-entry/assignment-entry.vue';
import AssignmentTypeHead from '@/pages/course/assignment-type-head/assignment-type-head.vue';
import Course, {Assignment} from '@/logic/course';
import TypeRadar from '@/pages/course/type-radar/type-radar';
import TypePie from '@/pages/course/type-pie/type-pie';
@Component({
components: {TypeRadar, TypePie, AssignmentEntry, CourseHead, CourseScatter, AssignmentTypeHead}
})
export default class CoursePage extends Vue
{
@Prop({required: true}) course: Course;
private unread: number = -1;
private unreadAssignments: Assignment[] = [];
/**
* Count the number of unread assignments with cache
*/
countUnread(): number
{
if (this.unread == -1)
{
this.unreadAssignments = this.course.assignments.filter(a => a.unread);
return this.unread = this.unreadAssignments.length;
}
else return this.unread;
}
}
</script>
<style src="./course-page.scss" lang="scss" scoped/>
@@ -0,0 +1,170 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {FormatUtils} from '@/logic/utils/format-utils';
import moment, {min, Moment} from 'moment';
import Course, {Assignment} from '@/logic/course';
import GraphUtils from '@/logic/utils/graph-utils';
import chroma from 'chroma-js';
import Navigation from '@/components/navigation/navigation';
@Component
export default class CourseScatter extends Vue
{
@Prop({required: true}) course: Course;
/**
* Override options
*
* @param options Original options (Unused)
*/
afterConfig(options: any)
{
return this.chartSettings;
}
/**
* Generate settings
*/
get chartSettings()
{
let term = Navigation.instance.getSelectedTerm()
// Create settings
let settings =
{
// Base settings
...GraphUtils.getBaseSettings('Assignments', 'Assignment scores for ' + this.course.name),
// X axis represents course names
xAxis:
{
type: 'time',
axisLabel:
{
formatter: (name: any) => moment(name).format('MMM DD')
},
min: Constants.TERMS[term == -1 ? 0 : term].getTime(),
max: term == -1 ? moment.min(moment(), moment(Constants.TERMS[4])).toDate().getTime() :
Constants.TERMS[term + 1].getTime()
},
// Y axis represents GPAs and MaxGPAs
yAxis:
{
type: 'value',
name: 'Percentage Score',
nameLocation: 'center',
nameGap: 38,
axisLabel:
{
formatter: (name: any) => name + '%'
},
min: (value: any) => Math.floor(value.min) - 5,
max: (value: any) => Math.min(Math.ceil(value.max), 110)
},
// Tooltip
tooltip:
{
...GraphUtils.tooltipCssShadow(),
trigger: 'axis',
axisPointer:
{
type: 'cross'
},
formatter: (ps: any[]) => moment(ps[0].data[0]).format('MMM DD, YYYY') + '<br>' + ps.map(p =>
`${GraphUtils.DOT.replace('{color}', p.color.colorStops[1].color)}
${FormatUtils.limit(p.data[2].description, 22)}: ${p.data[1]}%<br>`).join('')
},
// Legend
legend:
{
bottom: 24,
itemWidth: 14,
textStyle:
{
color: '#777',
fontSize: 11
}
},
// Data
series: this.series()
};
return settings;
}
/**
* Get series data
*/
private series()
{
// Create scatter plots
let series: any[] = this.course.assignmentTypes.filter(t => t.graded).map((type, i) =>
{
return {
type: 'scatter',
name: type.name,
data: CourseScatter.assignmentsData(this.course.assignments.filter(a => a.typeId == type.id)),
symbolSize: (data: any) => Math.max(Math.sqrt(type.weight * data[2].scoreMax / type.scoreMax) * 12, 12),
label:
{
emphasis:
{
show: true,
formatter: (p: any) => p.data[2].description,
position: 'top'
}
},
itemStyle:
{
normal:
{
opacity: 0.7,
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowColor: 'rgba(0, 0, 0, 0.2)',
color:
{
type: 'radial',
x: 0.4,
y: 0.3,
colorStops:
[
{offset: 0, color: chroma(Constants.THEME.colors[i]).set('hsl.l', 0.9).css()},
{offset: 1, color: Constants.THEME.colors[i]}
]
}
}
}
}
});
// Push other stuff
series.push(
{
type: 'line',
markLine: GraphUtils.getTermLines(),
markArea: GraphUtils.getGradeMarkAreas(0.4)
});
return series;
}
/**
* Convert assignments to series data
*
* @param assignments Assignments
*/
private static assignmentsData(assignments: Assignment[])
{
return assignments.filter(a => a.complete == 'Complete')
.map(a => [a.time, (a.score / a.scoreMax * 100).toFixed(2), a]);
}
}
@@ -0,0 +1,7 @@
<template>
<div id="course-scatter">
<ve-scatter height="450px" class="graph" :extend="{a: this.course.name}" :after-config="afterConfig"/>
</div>
</template>
<script src="./course-scatter.ts" lang="ts"></script>
+56
View File
@@ -0,0 +1,56 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import Course from '@/logic/course';
import GraphUtils from '@/logic/utils/graph-utils';
@Component
export default class TypePie extends Vue
{
@Prop({required: true}) course: Course;
/**
* Override options
*
* @param options Original options (Unused)
*/
afterConfig(options: any)
{
return this.chartSettings;
}
/**
* Generate settings
*/
get chartSettings()
{
// Create settings
let settings =
{
...GraphUtils.getBaseSettings('Assignment Type Weight',
'How much each type of assignment affect your average'),
// Data
series:
{
type: 'pie',
avoidLabelOverlap: false,
radius: ['40%', '60%'],
center: ['50%', '55%'],
label: GraphUtils.pieTextStyle(),
data: this.course.assignmentTypes.filter(t => t.graded).map((t, i) => {return {
value: t.weight,
name: `${t.name}\n${t.weight}%`,
itemStyle:
{
color: Constants.THEME.colors[i],
opacity: 0.8,
shadowColor: 'rgba(0,0,0,0.22)',
shadowBlur: 10
}
}}).sort((a, b) => a.value - b.value)
}
};
return settings;
}
}
+8
View File
@@ -0,0 +1,8 @@
<template>
<div id="type-pie">
<ve-pie height="420px" class="graph" :extend="{a: this.course.name}" :after-config="afterConfig"></ve-pie>
</div>
</template>
<script src="./type-pie.ts" lang="ts"></script>
<style lang="scss" scoped></style>
+102
View File
@@ -0,0 +1,102 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import Course from '@/logic/course';
import GraphUtils from '@/logic/utils/graph-utils';
@Component
export default class TypeRadar extends Vue
{
@Prop({required: true}) course: Course;
/**
* Override options
*
* @param options Original options (Unused)
*/
afterConfig(options: any)
{
return this.chartSettings;
}
/**
* Generate settings
*/
get chartSettings()
{
let min = this.course.assignmentTypes.filter(t => t.graded).reduce((min, t) => Math.min(min, t.percent), 100);
// Create settings
let settings =
{
...GraphUtils.getBaseSettings('Assignment Type Radar',
'How are you doing for different types of assignment'),
// Radar settings
radar:
{
// shape: 'circle',
name:
{
textStyle: GraphUtils.pieTextStyle()
},
splitArea:
{
areaStyle:
{
color:
[
'rgb(255,161,151)',
'rgb(255,190,184)',
'rgba(255,225,199)',
'rgba(255,250,216)',
'rgba(241,255,237)',
],
opacity: 0.4
}
},
indicator: this.course.assignmentTypes.filter(t => t.graded).map((t, i) => {return {
name: `${t.name}\n${t.percent}%`,
max: 100,
min: min - 30,
color: Constants.THEME.colors[i]
}}),
radius: '60%',
center: ['50%', '55%']
},
// Data
series:
{
type: 'radar',
data:
[
{
name: 'Score',
symbol: 'circle',
areaStyle:
{
color:
{
type: 'radial',
x: 0.5, y: 0.55, r: 0.5,
colorStops:
[
{offset: 0, color: '#ffa0a0'},
{offset: 0.5, color: '#fffead'},
{offset: 1, color: '#d1ffde'}
],
global: false // 缺省为 false
},
opacity: 0.2
},
value: this.course.assignmentTypes.filter(t => t.graded).map(t => t.percent)
}
]
},
color: '#6771c1'
};
return settings;
}
}
@@ -0,0 +1,7 @@
<template>
<div id="type-radar">
<ve-radar height="420px" class="graph" :extend="{a: this.course.name}" :after-config="afterConfig"/>
</div>
</template>
<script src="./type-radar.ts" lang="ts"></script>
@@ -1,22 +0,0 @@
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 }
]
};
}
@@ -1,8 +0,0 @@
<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>
@@ -0,0 +1,116 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Course from '@/logic/course';
import {GPAUtils} from '@/logic/utils/gpa-utils';
import Constants from '@/constants';
import {FormatUtils} from '@/logic/utils/format-utils';
@Component
export default class OverallBar extends Vue
{
@Prop({required: true}) courses: Course[];
/**
* Generate settings
*/
get chartSettings()
{
let settings =
{
// Title
title:
{
show: true,
textStyle:
{
fontSize: 12
},
text: 'Course GPA',
subtext: 'Current GPA for every course',
x: 'center'
},
// X axis represents course names
xAxis:
{
type: 'category',
axisLabel: {
interval: 0,
inside: false,
rotate: 90,
// Truncate text length
formatter: (value: string) => FormatUtils.limit(value, 16)
},
},
// Y axis represents GPAs and MaxGPAs
yAxis:
{
type: 'value'
},
// Data
series:
[
// Max GP
{
type: 'bar',
barGap: '-100%',
data: this.courses.map(course =>
{
return {value: [course.name, GPAUtils.getGP(course, 'A+')], itemStyle: {color: '#d8d8d8'}}
}),
},
// Current GP
{
type: 'bar',
barGap: '-100%',
data: this.generateGPData(),
label:
{
show: true,
rotate: 90
}
}
],
// Disable tooltip
tooltip:
{
show: false
}
};
return settings;
}
/**
* Generate GP data for each course
*/
private generateGPData()
{
let data: any = [];
this.courses.forEach((course, index) =>
{
// Get GP
let gp = GPAUtils.getGP(course, course.letterGrade);
// No grade cases
if (gp == -1) return;
// Push data
data.push(
{
value: [course.name, gp],
itemStyle:
{
color: Constants.THEME.colors[index]
}
});
});
return data;
}
}
@@ -0,0 +1,16 @@
<template>
<div id="overall-bar">
<ve-bar height="450px" class="graph" :extend="chartSettings"/>
</div>
</template>
<script src="./overall-bar.ts" lang="ts"></script>
<style lang="scss" scoped>
#overall-bar
{
.graph
{
margin-top: 50px;
}
}
</style>
@@ -0,0 +1,152 @@
// Row
.assignment-entry
{
height: 40px;
padding: 0 10px 0 20px;
background: #f5f7fa;
text-align: left;
// Date
.el-col.date
{
min-width: 150px;
span.month
{
margin-right: 5px;
// Unified width
display: inline-block;
min-width: 50px;
}
span.now
{
font-size: 11px;
color: #888;
}
}
// Description
.el-col.description
{
width: unset;
span.type
{
display: inline-block;
font-size: 13px;
font-weight: 700;
background: #eee;
border-left: 2px solid #000;
height: 22px;
line-height: 22px;
margin-right: 8px;
}
}
// Grade
.el-col.grade
{
text-align: right;
float: right;
// Fix smaller screen display issues.
width: unset;
// Status / Problems
span.status
{
margin-right: 8px;
}
// Percentage score
span.percent
{
font-style: italic;
background: #ffc;
color: #555;
margin-right: 8px;
.symbol
{
padding: 0 1px;
}
}
// Score you got
span.score
{
background: #f2f2f2;
color: #555;
}
// Max score
span.max
{
background: #ddd;
color: #333;
}
// Mark as read
button.mark-as-read
{
margin-left: 8px;
color: #aaa;
padding: 4px;
}
}
.entry-box
{
height: 22px;
padding: 0 5px;
}
// Unified width
.entry-box.score, .entry-box.max
{
min-width: 30px;
display: inline-block;
text-align: center;
}
// Unified width
.entry-box.percent
{
min-width: 60px;
display: inline-block;
text-align: right;
}
}
// Narrow layout
.assignment-entry.narrow
{
height: 34px;
}
// Unread
.no-unread
{
visibility: hidden !important;
width: 0 !important;
margin-left: 0 !important;
padding: 0 0 0 10px !important;
}
.assignment-entry:first-child
{
padding-top: 3px;
// Top shadow
// https://stackoverflow.com/questions/17572619/inset-box-shadow-only-on-one-side
box-shadow: inset 0 7px 9px -7px rgba(0,0,0,0.1);
}
@@ -0,0 +1,74 @@
<template>
<div class="assignment-entry vertical-center"
:class="narrow ? 'narrow' : ''"
:style="`background: ${backgroundColor}`">
<el-row class="unread-row">
<el-col :span="3" class="date">
<span class="month">{{getMoment(assignment.time).format("MMM D")}}</span>
<span class="now">({{getMoment(assignment.time).fromNow()}})</span>
</el-col>
<el-col :span="15" class="description">
<span class="type entry-box"
:style="`border-color: var(--assignment-type-${assignment.typeId})`">
{{assignment.type}}
</span>
<span class="text">{{assignment.description}}</span>
</el-col>
<el-col :span="6" class="grade">
<span v-if="assignment.problem" class="status entry-box" :style="{color: assignment.problemColor}">
{{assignment.problem}}
</span>
<span v-if="assignment.graded" class="percent entry-box">
{{(assignment.score / assignment.scoreMax * 100).toFixed(1)}}
<span class="symbol">%</span>
</span>
<span v-if="assignment.graded" class="score entry-box">{{assignment.score}}</span>
<span v-if="assignment.graded" class="max entry-box">{{assignment.scoreMax}}</span>
<el-button class="mark-as-read" :class="unread ? 'unread' : 'no-unread'"
size="mini" type="text" icon="el-icon-close"
@click="markAsRead">
</el-button>
</el-col>
</el-row>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import moment from 'moment';
import {Assignment} from '@/logic/course';
@Component
export default class AssignmentEntry extends Vue
{
@Prop({required: true}) assignment: Assignment;
@Prop({default: false}) unread: boolean;
@Prop({default: '#f5f7fa'}) backgroundColor: string;
@Prop({default: false}) narrow: boolean;
/**
* Format a date to the displayed format
*
* @param date Date
*/
getMoment(date: number)
{
return moment(new Date(date));
}
/**
* Mark this unread assignment as read
*/
markAsRead()
{
// Call custom event
this.$emit('mark-as-read', this.assignment)
}
}
</script>
<style src="./assignment-entry.scss" lang="scss" scoped/>
@@ -0,0 +1,216 @@
// Main card content
.course-card-content.main
{
// Main color
background: white;
// Alignment
display: block;
padding: 20px;
height: 50px;
}
#block-info
{
// Align left
text-align: left;
float: left;
#name
{
overflow: hidden;
font-size: 22px;
color: var(--main);
}
#teacher
{
font-size: 12px;
color: #999999;
font-style: italic;
}
}
#block-grade
{
// Align right
text-align: right;
float: right;
// Adjust position
margin-top: -2px;
margin-left: 10px;
#grade
{
font-size: 21px;
}
#updates
{
font-size: 14px;
#unread-number
{
display: inline-block;
width: 20px;
text-align: center;
border-radius: 5px;
padding-left: 3px;
padding-right: 3px;
margin-right: 3px;
}
#unread-text
{
font-style: italic;
}
}
#updates.unread
{
#unread-number
{
background: var(--unread);
color: white;
}
#unread-text
{
color: var(--unread);
}
}
#updates.none
{
color: #999999;
#unread-number
{
background: #eeeeee;
}
}
}
#content
{
margin-top: -20px;
padding: 20px 0 20px 20px;
height: 50px;
margin-left: -20px;
}
#block-rate
{
// Align right
width: 55px;
float: right;
margin-left: 20px;
padding: 0 10px;
color: white;
background: #84c0ff;
border-radius: 0 4px 4px 0;
height: 90px;
margin-top: -20px;
margin-right: -20px;
box-shadow: inset 8px 0 11px -4px rgba(0,0,0,.1);
}
#block-rate.rated
{
background: #66eaad;
}
.dark #block-rate > span
{
color: #84c0ff !important;
}
.dark #block-rate.rated > span
{
color: #66eaad !important;
}
#rating-popup
{
text-align: left;
.header
{
.title
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.subtitle
{
margin-left: 10px;
font-size: 12px;
font-style: italic;
color: #999999;
}
}
.item
{
margin-bottom: 10px;
white-space: normal;
.title
{
font-size: 18px;
color: var(--main);
}
.description
{
font-size: 14px;
}
.stars
{
font-size: 20px;
color: #FFB300;
}
.el-textarea
{
margin-top: 5px;
margin-bottom: 5px;
}
}
.item:first-child
{
margin-top: -15px;
}
}
#block-term-grades
{
// Align right
width: auto;
float: right;
margin-right: 10px;
color: gray;
#term, #term-numeric
{
font-size: 11px;
color: #b3b3b3;
}
#term-letter
{
font-size: 14px;
}
}
@@ -0,0 +1,198 @@
<template>
<div id="course-head" class="course-card-content main vertical-center">
<!-- Rating button -->
<div id="block-rate" v-if="displayRate" class="vertical-center clickable"
@click="ratingDialog = true" :class="{rated: course.rated}">
<span v-if="!course.rated">Give a<br>Rating!</span>
<span v-else>Rating<br>Entered</span>
</div>
<!-- Main content -->
<div id="content" @click="redirect" :class="clickable ? 'clickable' : ''">
<!-- Left -->
<div id="block-info">
<div id="name">{{course.name}}</div>
<div id="teacher">{{course.teacherName}}</div>
</div>
<!-- Right -->
<div id="block-grade">
<div id="grade">
<span id="letter">{{course.letterGrade}} </span>
<span id="numeric">{{course.numericGrade === undefined ? '--' : course.numericGrade.toFixed(2)}}</span>
<span id="percent" v-if="course.numericGrade !== undefined">%</span>
</div>
<div id="updates" @click="redirect" :class="unread === 0 ? 'none' : 'unread'">
<span id="unread-number">{{unread}}</span>
<span id="unread-text" :class="clickable ? 'clickable' : ''">new update{{unread >= 2 ? 's' : ''}}</span>
</div>
</div>
<div id="block-term-grades" v-if="course.rawSelectedTerm === -1"
v-for="term in course.allGradingPeriods.slice().reverse()">
<div id="term">Term {{term + 1}}</div>
<div id="term-letter">{{course.letterGradeTerm(term)}}</div>
<div id="term-numeric">{{course.numericGradeTerm(term).toFixed(1)}}%</div>
</div>
</div>
<!-- Rating Popup -->
<el-dialog id="rating-popup" :visible.sync="ratingDialog" width="50%" top="5vh"
:show-close="false" :close-on-click-modal="false" :close-on-press-escape="false">
<span slot="title" class="header">
<div class="title">Give a Rating for {{course.name}}</div>
<span class="subtitle">And for {{course.teacherName}}<br></span>
<span class="subtitle" style="color: #e67b0d;">(might need to scroll down to find the submit button)</span>
</span>
<div class="item" v-for="(criteria, index) of ratingCriteria">
<div class="title">{{criteria.title}}</div>
<div class="description">{{criteria.desc}}</div>
<div class="stars">
<span class="star clickable" v-for="star in [0,1,2,3,4]" @click="changeStars(index, star)">
<i v-if="rating.ratings[index] > star" class="el-icon-star-on"/>
<i v-else class="el-icon-star-off"/>
</span>
</div>
</div>
<div class="item">
<div class="title">Comments</div>
<div class="description">Any additional comments? (this is optional)</div>
<el-input type="textarea" placeholder="Comments... (Optional)"
v-model="rating.comment" maxlength="4500" show-word-limit :autosize="{minRows: 2, maxRows: 4}">
</el-input>
<el-checkbox v-model="rating.anonymous">Anonymous</el-checkbox>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="ratingDialog = false" :disabled="ratingPosting">Cancel</el-button>
<el-button type="primary" @click="submitRating()" :disabled="canSubmit">
{{course.rated ? 'Update' : 'Submit'}}
</el-button>
</span>
</el-dialog>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import Course from '@/logic/course';
import App from '@/components/app/app';
import {GPAUtils} from '@/logic/utils/gpa-utils';
import Constants from '@/constants';
import {RATING_CRITERIA} from '@/logic/course-info';
import Navigation from '@/components/navigation/navigation';
@Component
export default class CourseHead extends Vue
{
@Prop({required: true}) unread: number;
@Prop({required: true}) course: Course;
@Prop({required: true}) clickable: boolean;
ratingDialog = false;
ratingPosting = false;
rating = this.course.rating;
get canSubmit()
{
return this.ratingPosting || App.instance.demoMode
}
/**
* Redirect to the course page
*/
redirect()
{
if (!this.clickable) return;
App.instance.nav.updateIndex(this.course.urlIndex);
}
/**
* Display rate button or not
*/
get displayRate()
{
return this.clickable && App.instance.showRating;
}
get ratingCriteria() {return RATING_CRITERIA}
/**
* Change star rating data
*
* @param index Index of the rating
* @param star Change to how many stars
*/
changeStars(index: number, star: number)
{
this.rating.ratings[index] = star + 1;
this.$forceUpdate();
}
/**
* Submit a rating
*/
submitRating()
{
if (this.rating.ratings.includes(0))
{
this.$message.error('You haven\'t rated all of the criteria yet!');
return;
}
this.ratingPosting = true;
App.http.post('/course-info/rating/set', {rating: this.rating}).then(response =>
{
if (response.success)
{
this.ratingDialog = false;
this.ratingPosting = false;
this.$message.success('Rating successfully posted, thank you!');
// First rating (Updating the first review doesn't count as first review)
if (this.course.rated) return;
this.course.rated = true;
if (App.instance.courses.filter(c => c.rated).length == 1)
{
this.$alert('You can view other courses\'' +
' ratings in the Course Selection tab, or review yours by clicking' +
' the green button that says "Rating Entered." There are also option to turn off the rating buttons ' +
' by clicking on your avatar on the top right corner.',
'Thank you for submitting your fist rating!', {confirmButtonText: 'OK'}
);
}
// Last rating
if (App.instance.courses.filter(c => c.isGraded && !c.rated).length == 0)
{
this.$confirm('You have rated all of your courses! Do you want to turn off the rating buttons?' +
' (there are option to toggle them on again by clicking your avatar on the top right corner.)',
'Thank you for submitting rating!',
{confirmButtonText: 'Sure!', cancelButtonText: 'Nope.'}).then(() =>
{
// Disable rating buttons
Navigation.instance.onAvatarMenu('switch-rating');
this.$message.success('Rating buttons are disabled');
});
}
}
else
{
this.$message.error('Sorry, but rating failed to post, please try again or email me if you continues to have issues. ' +
'But wait! The email system isn\'t created yet... oops!. (Technical error message: ' + response.data + ')');
this.ratingPosting = false;
}
});
}
}
</script>
<style src="./course-head.scss" lang="scss" scoped/>
@@ -0,0 +1,16 @@
// Card
.el-card.course-card
{
// Margins
margin-right: 20px;
margin-left: 20px;
// Height limit
max-height: 250px;
// Limit name length
white-space: nowrap;
// Expansion color
background: #f4f6f9;
}
@@ -0,0 +1,47 @@
<template>
<div id="overall-course">
<el-card class="course-card">
<course-head :clickable="true" :course="course" :unread="unread()"/>
<div class="course-card-content expand"
v-if="unread() !== 0">
<assignment-entry v-for="assignment in unreadAssignments()"
:assignment="assignment"
:key="assignment.id"
unread="true"
v-on:mark-as-read="assignment.markAsRead()">
</assignment-entry>
</div>
</el-card>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import AssignmentEntry from '@/pages/overall/overall-course/assignment-entry/assignment-entry.vue';
import CourseHead from '@/pages/overall/overall-course/course-head/course-head.vue';
import Course, {Assignment} from '@/logic/course';
@Component({
components: {AssignmentEntry, CourseHead}
})
export default class OverallCourse extends Vue
{
@Prop({required: true}) course: Course;
mounted()
{
this.unreadAssignments().forEach(a => a.addCallback(() => this.$forceUpdate()));
}
unreadAssignments(): Assignment[]
{
return this.course.assignments.filter(a => a.unread);
}
unread(): number
{
return this.unreadAssignments().length;
}
}
</script>
<style src="./overall-course.scss" lang="scss" scoped/>
@@ -0,0 +1,180 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import moment from 'moment';
import Course from '@/logic/course';
import {CourseUtils} from '@/logic/utils/course-utils';
import GraphUtils from '@/logic/utils/graph-utils';
import {GPAUtils} from '@/logic/utils/gpa-utils';
import Constants from '@/constants';
import Navigation from '@/components/navigation/navigation';
@Component
export default class OverallLine extends Vue
{
@Prop({required: true}) courses: Course[];
filteredCourses: Course[];
settings: any;
/**
* When this component is created
*/
created()
{
// Filter courses
this.filteredCourses = this.courses.filter(c => c.isGraded && c.assignments.length > 0);
// Generate settings
this.settings =
{
...GraphUtils.getBaseSettings('Average Grade', 'Average score trend for every course'),
// Zoom bar
dataZoom:
[
{
type: 'slider',
startValue: this.getStartDate(),
// Minimum zoom: 1 week
minValueSpan: 7 * 24 * 60 * 60 * 1000
}
],
// Tooltip
tooltip:
{
... GraphUtils.tooltipCssShadow(),
trigger: 'axis'
},
// Axis
xAxis:
{
type: 'time',
axisLabel:
{
formatter: (name: any) => moment(name).format('MMM DD')
},
},
yAxis:
{
axisLabel:
{
formatter: (name: any) => name + '%'
},
min: (value: any) => Math.floor(value.min),
max: (value: any) => Math.min(Math.ceil(value.max), 110)
},
// Series data
series: this.series()
}
}
/**
* Override options
*
* @param options Original options (Unused)
*/
afterConfig(options: any)
{
return this.settings;
}
/**
* Get starting date
*/
private getStartDate()
{
// If it's a past term, use the term's end date, else use today.
let selected = Navigation.instance.getSelectedTerm();
let end = selected == Constants.CURRENT_TERM || selected == -1
? moment() : moment(CourseUtils.getTermEndDate());
return Math.max(end.subtract(30, 'days').toDate().getTime(),
CourseUtils.getTermBeginDate().getTime())
}
/**
* Generate series data
*/
private series()
{
// Each course
let series: any[] = this.filteredCourses.map(course => this.getCourseSeries(course));
// Push other stuff
series.push(
{
type: 'line',
markLine: GraphUtils.getTermLines(),
markArea: GraphUtils.getGradeMarkAreas(0.4)
});
return series
}
/**
* Generate series data for a course
*
* @param course
*/
private getCourseSeries(course: Course)
{
// Graded assignments
let assignments = course.assignments.slice().reverse();
// Create series
return {
name: course.name,
type: 'line',
smooth: true,
symbol: 'circle', // circle, diamond, emptyCircle, none
data: this.toDateRange([...new Set(assignments.map(a => a.time))].map(time =>
{
// Find subset before this assignment
let subset = course.getAssignmentsBefore(time);
// Find grade
if (course.termGrading[subset.term].method == 'PERCENT_TYPE')
return [time, GPAUtils.getPercentTypeAverage(course.termGrading[subset.term], subset.assignments)];
else return [time, GPAUtils.getTotalMeanAverage(subset.assignments)];
}))
}
}
/**
* Convert point data to date range data.
* Eg. [[Mon, 10], [Wed, 5]] to [[Mon, 10], [Tue, 10], [Wed, 5]]
*
* @param data
*/
private toDateRange(data: any[])
{
// Find the min date
let minDate: Date = new Date(data[0][0]);
// Find the dates in between
let now = new Date(Math.min(new Date().getTime(), CourseUtils.getTermEndDate().getTime()));
let times: number[] = [];
for (let date = minDate; date <= now; date.setDate(date.getDate() + 1)) times.push(date.getTime());
// Map the points
let lastValue: any = null;
return times.map(time =>
{
// Data point on this specific date
let thisValue = data.find(a => a[0] == time);
// Switching terms
if (Constants.TERMS.find(t => t.getTime() == time))
lastValue = null;
// Find value
return thisValue == null
? lastValue == null ? null : [time, lastValue[1]]
: [time, (lastValue = thisValue)[1]];
});
}
}
@@ -0,0 +1,10 @@
<template>
<div id="overall-line">
<ve-line :extend="{a: this.courses}" :after-config="afterConfig"/>
</div>
</template>
<script src="./overall-line.ts" lang="ts"></script>
<style lang="scss" scoped>
</style>
+46 -15
View File
@@ -1,29 +1,60 @@
// Add some margins
.el-card
.gpa-card
{
margin: 10px;
height: 494px;
padding: 0;
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
margin-left: 20px;
min-width: 136px;
}
.span-gpa-header
.gpa
{
display: block;
}
.gpa.header
{
font-size: 14px;
}
.span-gpa
.gpa.text
{
font-size: 35px;
font-family: 'Avenir', Helvetica, Arial, sans-serif;
font-family: var(--font);
}
.gpa-time
.gpa.max
{
font-size: 14px;
margin-top: -10px;
margin-bottom: 10px;
font-size: 12px;
color: #409eff;
}
.gpa.time
{
font-size: 11px;
}
.no-grade
{
font-size: 30px;
color: #b1b1b1;
// Disable selecting
display:block;
pointer-events: none;
user-select: none;
}
// Cards
.el-card.overall-bar-card
{
margin-right: 20px;
min-width: 170px;
}
.dialog-checkbox
{
display: block;
margin-top: 20px;
margin-bottom: -20px;
}
-126
View File
@@ -1,126 +0,0 @@
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;
}
}
+128 -17
View File
@@ -1,30 +1,141 @@
<template>
<div id="overall">
<el-row>
<el-col :span="4">
<el-card style="margin-left: 20px">
<el-progress v-if="started" :text-inside="true" :percentage="progress()"
:stroke-width="20" status="success" style="margin: 0 20px"/>
<el-dialog title="Notice" :visible.sync="clearUnreadPrompt" @close="clearUnread(false)"
width="30%" style="word-break: unset;">
<span>You have too many new grade notifications. Clear them now?</span>
<img src="./too-many-unread.png" alt=""/>
<el-checkbox class="dialog-checkbox" v-model="dontAskAgain">Don't Ask Again</el-checkbox>
<span slot="footer" class="dialog-footer">
<el-button @click="clearUnread(false)" style="float: left">Nope</el-button>
<el-button type="primary" @click="clearUnread(true)">Sure!</el-button>
</span>
</el-dialog>
<el-row v-if="getGPA().gpa !== -1">
<el-col :span="4" class="overall-span">
<el-card class="large gpa-card vertical-center" body-style="padding: 0">
<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>
<span class="gpa header">GPA:</span>
<span class="gpa text">{{getGPA().gpa}}</span>
<span class="gpa max">(Out of {{getGPA().max}})</span>
<div class="bottom clearfix gpa time">
<time>{{ new Date().toDateString() }}</time>
</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-col :span="14" class="overall-span">
<el-card class="large overall-line-card vertical-center" body-style="padding: 0 10px">
<overall-line :courses="courses"/>
</el-card>
</el-col>
<el-col :span="6" class="overall-span">
<el-card class="large overall-bar-card vertical-center" body-style="padding: 0 10px">
<overall-bar :courses="courses"/>
</el-card>
</el-col>
</el-row>
<div class=""></div>
<el-row v-if="getGPA().gpa === -1">
<el-card class="large gpa-card vertical-center">
<div class="no-grade">This quarter has no grades yet...</div>
</el-card>
</el-row>
<overall-course v-for="course in courses" :course="course" :key="course.id"/>
</div>
</template>
<script src="./overall.ts" lang="ts"></script>
<style src="./overall.scss" lang="scss"></style>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import OverallLine from '@/pages/overall/overall-line/overall-line';
import OverallBar from '@/pages/overall/overall-bar/overall-bar';
import OverallCourse from '@/pages/overall/overall-course/overall-course.vue';
import Course, {Assignment} from '@/logic/course';
import {GPAUtils} from '@/logic/utils/gpa-utils';
@Component({
components: {OverallLine, OverallBar, OverallCourse}
})
export default class Overall extends Vue
{
@Prop({required: true}) courses: Course[];
/**
* This function is called to get gpa since I can't import another
* class in the Vue file.
*/
getGPA()
{
return GPAUtils.getGPA(this.courses);
}
// For clear unread prompt
unread: Assignment[];
clearUnreadPrompt = false;
dontAskAgain = false;
started = false;
/**
* Mark as read progress
*/
progress()
{
return +(this.unread.filter(a => !a.unread).length / this.unread.length * 100).toFixed(1);
}
/**
* On page load - check if the user has too many notifications
*/
mounted()
{
// Check unread
if (!this.$cookies.isKey('va.ignore-unread'))
{
// Count unread
this.unread = this.courses.flatMap(c => c.assignments.filter(a => a.unread));
// Prompt clear
if (this.unread.length > 15)
{
this.clearUnreadPrompt = true;
}
}
}
/**
* Clear unread
*
* @param confirmed
*/
clearUnread(confirmed: boolean)
{
// Hide prompt
this.clearUnreadPrompt = false;
// Not confirmed, do nothing
if (!confirmed)
{
if (!this.dontAskAgain) return;
// Don't ask again
this.$cookies.set('va.ignore-unread', true);
return;
}
// Clear unread
this.started = true;
this.unread.forEach((a, i) =>
{
// Delay: 100ms per assignment
// I don't want my server to explode lol
setTimeout(() => a.markAsRead().then(() => this.$forceUpdate()), 100 * i);
});
}
}
</script>
<style src="./overall.scss" lang="scss" scoped/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
import Vue, { VNode } from 'vue';
import Vue, {VNode} from 'vue';
declare global {
namespace JSX {
+4 -3
View File
@@ -1,4 +1,5 @@
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
declare module '*.vue'
{
import Vue from 'vue';
export default Vue;
}
+45
View File
@@ -0,0 +1,45 @@
<template>
<div id="info">
<div id="top">
<div id="title">Veracross Analyzer for SJP</div>
<div id="subtitle">Know your grades better.</div>
</div>
</div>
</template>
<script lang="ts">
import {Component, Vue} from 'vue-property-decorator';
@Component
export default class Info extends Vue
{
}
</script>
<style lang="scss" scoped>
#top
{
padding: 40vh 0;
// Center and scale the image nicely
background-position: center;
background-repeat: no-repeat;
background-size: cover;
text-align: right;
#title
{
font-size: 30px;
margin-right: 10vw;
color: white;
}
#subtitle
{
margin-right: 10vw;
color: white;
}
}
</style>
-101
View File
@@ -1,101 +0,0 @@
/**
* 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;
}
}
-33
View File
@@ -1,33 +0,0 @@
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;
}
}
+5 -4
View File
@@ -15,16 +15,17 @@
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
],
// Custom
"strictPropertyInitialization": false
},
"include": [
"src/**/*.ts",
+3 -1
View File
@@ -2,7 +2,9 @@
"defaultSeverity": "warning",
"linterOptions": {
"exclude": [
"node_modules/**"
"node_modules/**",
"*.json",
"**/*.json"
]
},
"rules": {
+5 -3
View File
@@ -1,5 +1,7 @@
module.exports = {
devServer: {
module.exports =
{
devServer:
{
disableHostCheck: true,
}
}
};