From e54ec23afd943882cdf41dd5186091836082efef Mon Sep 17 00:00:00 2001 From: Joven Soh <34702990+JovenSoh@users.noreply.github.com> Date: Mon, 18 Mar 2024 00:31:09 +0800 Subject: [PATCH 01/13] updated for mobile --- .../achievement/AchievementManualEditor.tsx | 128 +++---- .../utils/AchievementInferencer.ts | 3 +- .../subcomponents/AchievementDashboard.tsx | 6 +- src/styles/_achievementdashboard.scss | 327 +++++++++++++++++- 4 files changed, 395 insertions(+), 69 deletions(-) diff --git a/src/commons/achievement/AchievementManualEditor.tsx b/src/commons/achievement/AchievementManualEditor.tsx index 859eee93bb..316d1d0df2 100644 --- a/src/commons/achievement/AchievementManualEditor.tsx +++ b/src/commons/achievement/AchievementManualEditor.tsx @@ -45,24 +45,24 @@ const AchievementManualEditor: React.FC = props => const users = studio === 'Staff' ? // The name can be null for users who have yet to log in. We push these to the back of the array. - [...props.users].sort( + [...props.users].sort( + (user1, user2) => + user1.name != null && user2.name != null + ? user1.name.localeCompare(user2.name) + : user1.name == null + ? 1 // user1.name is null, user1 > user2 + : -1 // user2.name is null, user1 < user2 + ) + : props.users + .filter(user => user.group === studio) + .sort( (user1, user2) => user1.name != null && user2.name != null ? user1.name.localeCompare(user2.name) : user1.name == null - ? 1 // user1.name is null, user1 > user2 - : -1 // user2.name is null, user1 < user2 - ) - : props.users - .filter(user => user.group === studio) - .sort( - (user1, user2) => - user1.name != null && user2.name != null - ? user1.name.localeCompare(user2.name) - : user1.name == null ? 1 // user1.name is null, user1 > user2 : -1 // user2.name is null, user1 < user2 - ); + ); useEffect(() => { getUsers(); @@ -95,53 +95,63 @@ const AchievementManualEditor: React.FC = props => return (
-

User:

- } - > -
+ +
+

Goal:

+ } + > +
+ +
+

Count:

+ +
+ +
+
+ +
+ changeViewHidden(!viewHidden)} + /> +
+ ); }; diff --git a/src/commons/achievement/utils/AchievementInferencer.ts b/src/commons/achievement/utils/AchievementInferencer.ts index f83478ac7d..5693df6a0e 100644 --- a/src/commons/achievement/utils/AchievementInferencer.ts +++ b/src/commons/achievement/utils/AchievementInferencer.ts @@ -288,7 +288,6 @@ class AchievementInferencer { // finally, process the nodeList this.processNodes(); this.normalizePositions(achievement.uuid, achievement.position); - return newUuid; } @@ -743,6 +742,8 @@ class AchievementInferencer { this.generateProgressFrac(node); this.generateStatus(node); }); + + } private processGoals() { diff --git a/src/pages/achievement/subcomponents/AchievementDashboard.tsx b/src/pages/achievement/subcomponents/AchievementDashboard.tsx index 688ad717ae..dd6eaee69d 100644 --- a/src/pages/achievement/subcomponents/AchievementDashboard.tsx +++ b/src/pages/achievement/subcomponents/AchievementDashboard.tsx @@ -2,7 +2,7 @@ import { IconNames } from '@blueprintjs/icons'; import React, { useEffect, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import { Role } from 'src/commons/application/ApplicationTypes'; -import { useSession, useTypedSelector } from 'src/commons/utils/Hooks'; +import { useResponsive, useSession, useTypedSelector } from 'src/commons/utils/Hooks'; import AchievementFilter from '../../../commons/achievement/AchievementFilter'; import AchievementManualEditor from '../../../commons/achievement/AchievementManualEditor'; @@ -52,6 +52,7 @@ const AchievementDashboard: React.FC = () => { // default nothing selected const userIdState = useState(undefined); const [selectedUser] = userIdState; + const { isMobileBreakpoint } = useResponsive(); const { group, @@ -156,8 +157,7 @@ const AchievementDashboard: React.FC = () => { updateGoalProgress={handleUpdateGoalProgress} /> )} - -
+
* { + >* { margin: 0 auto; } } @@ -112,9 +114,12 @@ .achievement-manual-editor { $default-spacing: 0.5em; + $vertical-spacing: 10px; align-items: center; display: flex; + gap: $default-spacing $vertical-spacing; + flex-wrap: wrap; padding: $default-spacing; color: white; @@ -133,6 +138,11 @@ margin: 0 $default-spacing; display: inline-flex; } + + .editor-section { + display: flex; + align-items: center; + } } .achievement-main { @@ -199,7 +209,7 @@ padding: $default-spacing; - > * + * { + >*+* { margin-top: $default-spacing; } @@ -227,7 +237,7 @@ align-items: center; display: flex; - > * { + >* { margin: 0; } } @@ -274,8 +284,7 @@ .dropdown-lines { height: $top-spacing + $card-height + $remaining-width + $line-extension; - margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 - $line-width; + margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 $line-width; min-width: $line-width; } @@ -441,4 +450,310 @@ border-radius: 1.5px; } } -} + + .achievement-main-mobile { + // Cover aspect ratio 2:1 + $cover-height: 16em; + $cover-width: 18em; + // Card aspect ratio 2:1 + $card-height: 5em; + $card-width: 25em; + // Default spacing should be at least 10px to prevent border glow bleeding + $default-spacing: 1em; + // View aspect ratio 18:25 + $view-height: 50em; + $view-width: $cover-width; + + align-items: center; + display: flex; + flex-direction: column; + height: 100%; + + %container { + display: flex; + flex-direction: row; + margin: 90 auto; + max-height: $view-height + $default-spacing * 2; + min-width: max-content; + } + + .filter-container { + @extend %container; + height: 15%; + + .filter { + align-items: center; + cursor: pointer; + display: flex; + flex-direction: row; + margin: auto $default-spacing; + + p { + font-size: 0.8em; + margin: 0; + padding: 1em 0 0 0; + white-space: nowrap; + } + } + + @media only screen and (max-height: 600px) { + height: 80%; + + p { + display: none; + } + } + } + + .task-container { + display: flex; + flex-direction: column; + gap: $default-spacing; + list-style-type: none; + overflow-y: auto; + padding: $default-spacing; + scrollbar-color: white #444; + scrollbar-width: thin; + + >*+* { + margin-top: $default-spacing; + } + + .task { + .achievement-card { + border-radius: 0.3rem; + cursor: pointer; + display: flex; + align-items: center; + height: $card-height; + transition: box-shadow 0.2s ease-in-out; + width: $card-width; + + padding: 0.5em; + column-gap: 0.5em; + + .content { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + width: 100%; + + .heading { + align-items: center; + display: flex; + + >* { + margin: 0; + } + } + + .details { + display: flex; + flex-direction: row; + font-size: 0.8em; + + p { + margin: 0; + } + + .deadline, + .xp { + align-items: center; + display: flex; + column-gap: 0.3em; + width: 100%; + } + } + } + } + + .achievement-card:hover { + box-shadow: 0 0 10px black; + } + + .prerequisite-container { + $shrink-factor: 0.9; + $line-width: 1em; + // remaining-width is the empty space between line and card + $remaining-width: math.div((1 - $shrink-factor) * $card-width - 2 * $line-width, 2); + $top-spacing: 0.2em; + $line-extension: 0.1em; + + display: flex; + flex-direction: column; + + .prerequisite { + display: flex; + flex-direction: row; + max-width: $card-width; + + .dropdown-lines { + height: $top-spacing + $card-height + $remaining-width + $line-extension; + margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 $line-width; + min-width: $line-width; + } + + .achievement-card { + margin: $top-spacing 0 0 0; + transform: scale($shrink-factor); + } + } + + .prerequisite:first-child { + .dropdown-lines { + height: $top-spacing + math.div($card-height, 2) + $remaining-width; + margin-top: 0; + } + } + } + } + } + + .view-container { + $cover-spacing: 0.3em; + $content-spacing: 0.5em; + + @extend %container; + min-width: $view-width + $default-spacing * 2; + overflow-y: auto; + scrollbar-color: white #444; + scrollbar-width: thin; + + .no-view { + align-items: center; + background: rgba(0, 0, 0, 0.5); + text-shadow: black 1px 1px; + color: white; + display: flex; + flex-direction: column; + height: $view-height / 3; + justify-content: center; + margin: 1em auto; + width: $view-width; + border-radius: 1rem; + } + + .view { + border-radius: 1rem; + text-shadow: black 1px 1px; + color: white; + display: flex; + flex-direction: column; + margin: $default-spacing; + width: $view-width; + padding-bottom: 1rem; + + .cover { + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; + display: flex; + flex-direction: column; + text-align: center; + min-height: $cover-height; + min-width: $cover-width; + + h1 { + margin: 0.5em auto 0; + padding: $cover-spacing; + } + + p { + margin: 0 auto; + padding: $cover-spacing; + } + + .description { + color: yellow; + font-size: 0.85em; + margin: auto auto 1em; + width: 80%; + } + } + + .progress-header { + margin-left: 2rem; + } + + .goal { + align-items: center; + display: flex; + flex-direction: row; + padding: $content-spacing; + + .goal-badge { + align-items: center; + display: flex; + flex-direction: column; + min-width: 6em; + padding: 0 $content-spacing; + + .goal-icon { + background: url(#{$achievement-assets}/xp-icon.png) center/contain; + height: 2em; + width: 2em; + } + + p { + text-align: center; + font-size: 0.7em; + padding: 0.2em 0 0 0; + } + } + + .goal-progress { + width: 100%; + padding-right: 2.5em; + + .progress { + margin-top: 5px; + } + } + + p { + margin: 0; + padding: 0; + } + } + + hr { + background: lightgrey; + border: none; + height: 1px; + margin: $content-spacing auto; + width: 90%; + } + + .completion { + padding: $content-spacing; + text-align: center; + + h1 { + color: #fc0; + margin: 0 auto $content-spacing; + } + + p { + margin: 0; + padding: 0; + } + } + } + } + + // Scroll Bar + ::-webkit-scrollbar { + width: 3px; + } + + ::-webkit-scrollbar-track { + border-radius: 1.5px; + box-shadow: inset 0 0 3px black; + } + + ::-webkit-scrollbar-thumb { + background: white; + border-radius: 1.5px; + } + } +} \ No newline at end of file From 7661a4d2af90546ea2578bf5ead2edfafb6656e4 Mon Sep 17 00:00:00 2001 From: Joven Soh <34702990+JovenSoh@users.noreply.github.com> Date: Mon, 18 Mar 2024 00:33:45 +0800 Subject: [PATCH 02/13] fixed formatting --- .../achievement/AchievementManualEditor.tsx | 24 +++++++++---------- .../utils/AchievementInferencer.ts | 2 -- src/styles/_achievementdashboard.scss | 22 +++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/commons/achievement/AchievementManualEditor.tsx b/src/commons/achievement/AchievementManualEditor.tsx index 316d1d0df2..3de4b83817 100644 --- a/src/commons/achievement/AchievementManualEditor.tsx +++ b/src/commons/achievement/AchievementManualEditor.tsx @@ -45,24 +45,24 @@ const AchievementManualEditor: React.FC = props => const users = studio === 'Staff' ? // The name can be null for users who have yet to log in. We push these to the back of the array. - [...props.users].sort( - (user1, user2) => - user1.name != null && user2.name != null - ? user1.name.localeCompare(user2.name) - : user1.name == null - ? 1 // user1.name is null, user1 > user2 - : -1 // user2.name is null, user1 < user2 - ) - : props.users - .filter(user => user.group === studio) - .sort( + [...props.users].sort( (user1, user2) => user1.name != null && user2.name != null ? user1.name.localeCompare(user2.name) : user1.name == null + ? 1 // user1.name is null, user1 > user2 + : -1 // user2.name is null, user1 < user2 + ) + : props.users + .filter(user => user.group === studio) + .sort( + (user1, user2) => + user1.name != null && user2.name != null + ? user1.name.localeCompare(user2.name) + : user1.name == null ? 1 // user1.name is null, user1 > user2 : -1 // user2.name is null, user1 < user2 - ); + ); useEffect(() => { getUsers(); diff --git a/src/commons/achievement/utils/AchievementInferencer.ts b/src/commons/achievement/utils/AchievementInferencer.ts index 5693df6a0e..5597e58c82 100644 --- a/src/commons/achievement/utils/AchievementInferencer.ts +++ b/src/commons/achievement/utils/AchievementInferencer.ts @@ -742,8 +742,6 @@ class AchievementInferencer { this.generateProgressFrac(node); this.generateStatus(node); }); - - } private processGoals() { diff --git a/src/styles/_achievementdashboard.scss b/src/styles/_achievementdashboard.scss index 069d533da0..c517a33f99 100644 --- a/src/styles/_achievementdashboard.scss +++ b/src/styles/_achievementdashboard.scss @@ -32,7 +32,7 @@ width: 2.5em; } - >* { + > * { margin: 0 auto; } } @@ -209,7 +209,7 @@ padding: $default-spacing; - >*+* { + > * + * { margin-top: $default-spacing; } @@ -237,7 +237,7 @@ align-items: center; display: flex; - >* { + > * { margin: 0; } } @@ -284,7 +284,8 @@ .dropdown-lines { height: $top-spacing + $card-height + $remaining-width + $line-extension; - margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 $line-width; + margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 + $line-width; min-width: $line-width; } @@ -507,15 +508,15 @@ .task-container { display: flex; - flex-direction: column; - gap: $default-spacing; + flex-direction: column; + gap: $default-spacing; list-style-type: none; overflow-y: auto; padding: $default-spacing; scrollbar-color: white #444; scrollbar-width: thin; - >*+* { + > * + * { margin-top: $default-spacing; } @@ -543,7 +544,7 @@ align-items: center; display: flex; - >* { + > * { margin: 0; } } @@ -590,7 +591,8 @@ .dropdown-lines { height: $top-spacing + $card-height + $remaining-width + $line-extension; - margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 $line-width; + margin: -#{math.div($card-height, 1.6)} -#{$line-width + $remaining-width} 0 + $line-width; min-width: $line-width; } @@ -756,4 +758,4 @@ border-radius: 1.5px; } } -} \ No newline at end of file +} From 53e3ef1532c8a76125a2e1748ad1467f8fea3fc1 Mon Sep 17 00:00:00 2001 From: Joven Soh <34702990+JovenSoh@users.noreply.github.com> Date: Mon, 18 Mar 2024 00:44:28 +0800 Subject: [PATCH 03/13] ran test suites --- .coverage-fix.tmp | 2 + lcov.info | 31 ++++++++++++++ .../{sharedb-ace.d.ts => sharedb-ace.ts} | 0 .../__snapshots__/CseMachine.tsx.snap | 40 +++++++++---------- src/{react-app-env.d.ts => react-app-env.ts} | 0 5 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 .coverage-fix.tmp create mode 100644 lcov.info rename src/commons/workspace/{sharedb-ace.d.ts => sharedb-ace.ts} (100%) rename src/{react-app-env.d.ts => react-app-env.ts} (100%) diff --git a/.coverage-fix.tmp b/.coverage-fix.tmp new file mode 100644 index 0000000000..0a0d143317 --- /dev/null +++ b/.coverage-fix.tmp @@ -0,0 +1,2 @@ +./src/commons/workspace/sharedb-ace.ts +./src/react-app-env.ts diff --git a/lcov.info b/lcov.info new file mode 100644 index 0000000000..bb217223a4 --- /dev/null +++ b/lcov.info @@ -0,0 +1,31 @@ +TN: +SF:src/react-app-env.ts +FNF:0 +FNH:0 +LF:0 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/commons/workspace/sharedb-ace.ts +FNF:0 +FNH:0 +LF:0 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/features/cseMachine/__tests__/__snapshots__/CseMachine.tsx.snap +FNF:0 +FNH:0 +DA:1,0 +LF:1 +LH:0 +BRF:0 +BRH:0 +end_of_record + + + \ No newline at end of file diff --git a/src/commons/workspace/sharedb-ace.d.ts b/src/commons/workspace/sharedb-ace.ts similarity index 100% rename from src/commons/workspace/sharedb-ace.d.ts rename to src/commons/workspace/sharedb-ace.ts diff --git a/src/features/cseMachine/__tests__/__snapshots__/CseMachine.tsx.snap b/src/features/cseMachine/__tests__/__snapshots__/CseMachine.tsx.snap index 77124e66ba..e2b0392f37 100644 --- a/src/features/cseMachine/__tests__/__snapshots__/CseMachine.tsx.snap +++ b/src/features/cseMachine/__tests__/__snapshots__/CseMachine.tsx.snap @@ -181,7 +181,7 @@ exports[`CSE Machine Control Stash correctly renders: Control is truncated prope onMouseLeave={[Function]} >