From 80c11cc8e50bf710fc0f63d24468e79822bb48bc Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:13:24 +0800 Subject: [PATCH 1/7] feat: Implement tool tip to show bonus xp end date --- src/commons/XMLParser/XMLParserHelper.ts | 3 ++- src/commons/assessment/Assessment.tsx | 9 ++++++- src/commons/assessment/AssessmentTypes.ts | 4 ++- src/commons/mocks/AssessmentMocks.ts | 30 +++++++++++++++-------- src/commons/utils/DateHelper.ts | 6 +++++ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/commons/XMLParser/XMLParserHelper.ts b/src/commons/XMLParser/XMLParserHelper.ts index 6f1d6e5c61..7b57f9bdae 100644 --- a/src/commons/XMLParser/XMLParserHelper.ts +++ b/src/commons/XMLParser/XMLParserHelper.ts @@ -87,7 +87,8 @@ const makeAssessmentOverview = (result: any, maxXpVal: number): AssessmentOvervi isGradingPublished: false, xp: 0, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }; }; diff --git a/src/commons/assessment/Assessment.tsx b/src/commons/assessment/Assessment.tsx index 634e49f486..eb6ef10ac4 100644 --- a/src/commons/assessment/Assessment.tsx +++ b/src/commons/assessment/Assessment.tsx @@ -38,7 +38,7 @@ import Markdown from '../Markdown'; import NotificationBadge from '../notificationBadge/NotificationBadge'; import { filterNotificationsByAssessment } from '../notificationBadge/NotificationBadgeHelper'; import Constants from '../utils/Constants'; -import { beforeNow, getPrettyDate } from '../utils/DateHelper'; +import { beforeNow, getPrettyDate, getPrettyDateAfterHours } from '../utils/DateHelper'; import { useResponsive, useSession } from '../utils/Hooks'; import { assessmentTypeLink, convertParamToInt } from '../utils/ParamParseHelper'; import AssessmentNotFound from './AssessmentNotFound'; @@ -179,6 +179,13 @@ const Assessment: React.FC = () => { ? `XP: ${overview.xp} / ${overview.maxXp}` : `Max XP: ${overview.maxXp}`} + {hasBonusXp && ( + + + + )}
diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index 09bf818ed4..c3d5cecbf4 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -81,6 +81,7 @@ export type AssessmentOverview = { title: string; xp: number; maxTeamSize: number; // For team assessment + hoursBeforeEarlyXpDecay: number; }; /* @@ -259,7 +260,8 @@ export const overviewTemplate = (): AssessmentOverview => { isGradingPublished: false, xp: 0, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }; }; diff --git a/src/commons/mocks/AssessmentMocks.ts b/src/commons/mocks/AssessmentMocks.ts index 4a3c8ad5dd..deda0f8cba 100644 --- a/src/commons/mocks/AssessmentMocks.ts +++ b/src/commons/mocks/AssessmentMocks.ts @@ -127,7 +127,8 @@ const mockUnopenedAssessmentsOverviews: AssessmentOverview[] = [ xp: 0, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; @@ -162,7 +163,8 @@ const mockOpenedAssessmentsOverviews: AssessmentOverview[] = [ xp: 1, isGradingPublished: false, maxTeamSize: 4, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Missions', @@ -182,7 +184,8 @@ const mockOpenedAssessmentsOverviews: AssessmentOverview[] = [ xp: 2, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Quests', @@ -202,7 +205,8 @@ const mockOpenedAssessmentsOverviews: AssessmentOverview[] = [ xp: 3, isGradingPublished: false, maxTeamSize: 2, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Paths', @@ -222,7 +226,8 @@ const mockOpenedAssessmentsOverviews: AssessmentOverview[] = [ xp: 0, isGradingPublished: false, maxTeamSize: 2, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Others', @@ -243,7 +248,8 @@ const mockOpenedAssessmentsOverviews: AssessmentOverview[] = [ private: true, maxTeamSize: 1, isGradingPublished: false, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; @@ -266,7 +272,8 @@ const mockClosedAssessmentOverviews: AssessmentOverview[] = [ xp: 800, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Quests', @@ -286,7 +293,8 @@ const mockClosedAssessmentOverviews: AssessmentOverview[] = [ xp: 500, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Quests', @@ -306,7 +314,8 @@ const mockClosedAssessmentOverviews: AssessmentOverview[] = [ xp: 150, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 }, { type: 'Paths', @@ -326,7 +335,8 @@ const mockClosedAssessmentOverviews: AssessmentOverview[] = [ xp: 100, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; diff --git a/src/commons/utils/DateHelper.ts b/src/commons/utils/DateHelper.ts index b33667cff0..e826b7378e 100644 --- a/src/commons/utils/DateHelper.ts +++ b/src/commons/utils/DateHelper.ts @@ -41,3 +41,9 @@ export const getStandardDate = (dateString: string): string => { const prettyDate = date.format('MMMM Do YYYY'); return prettyDate; }; + +export const getPrettyDateAfterHours = (dateString: string, hours: number): string => { + const date = moment(dateString).add(hours, 'hours'); + const prettyDate = date.format('Do MMMM, HH:mm'); + return prettyDate; +}; From 7380b631ccf90373773253158b17db215677b35c Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:33:26 +0800 Subject: [PATCH 2/7] fix: Fix formatting --- src/styles/_academy.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/styles/_academy.scss b/src/styles/_academy.scss index aaaa964289..8dd6a76247 100644 --- a/src/styles/_academy.scss +++ b/src/styles/_academy.scss @@ -189,6 +189,11 @@ flex-direction: column; } + .listing-xp { + display: flex; + gap: 0.5rem; + } + .listing-header { margin-bottom: 0.8rem; display: flex; From 392e428492e0914689f178d9f0e656b3c2e4a943 Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:33:44 +0800 Subject: [PATCH 3/7] fix: Change to use overview's info instead --- src/commons/assessment/Assessment.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commons/assessment/Assessment.tsx b/src/commons/assessment/Assessment.tsx index eb6ef10ac4..655c7cc208 100644 --- a/src/commons/assessment/Assessment.tsx +++ b/src/commons/assessment/Assessment.tsx @@ -179,7 +179,7 @@ const Assessment: React.FC = () => { ? `XP: ${overview.xp} / ${overview.maxXp}` : `Max XP: ${overview.maxXp}`} - {hasBonusXp && ( + {overview.earlySubmissionXp > 0 && ( From 3a3fe1bc7b74689be8e595fe32d90be738b49ce2 Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:09:56 +0800 Subject: [PATCH 4/7] fix: Add missing fields for test --- src/commons/application/actions/__tests__/SessionActions.ts | 3 ++- .../application/reducers/__tests__/SessionReducer.ts | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/commons/application/actions/__tests__/SessionActions.ts b/src/commons/application/actions/__tests__/SessionActions.ts index 199cd32b56..cf65144525 100644 --- a/src/commons/application/actions/__tests__/SessionActions.ts +++ b/src/commons/application/actions/__tests__/SessionActions.ts @@ -484,7 +484,8 @@ test('updateAssessmentOverviews generates correct action object', () => { xp: 0, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; const action = SessionActions.updateAssessmentOverviews(overviews); diff --git a/src/commons/application/reducers/__tests__/SessionReducer.ts b/src/commons/application/reducers/__tests__/SessionReducer.ts index 5a4e3261ef..8a589c4aad 100644 --- a/src/commons/application/reducers/__tests__/SessionReducer.ts +++ b/src/commons/application/reducers/__tests__/SessionReducer.ts @@ -335,7 +335,8 @@ const assessmentOverviewsTest1: AssessmentOverview[] = [ xp: 0, isGradingPublished: false, maxTeamSize: 5, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; @@ -358,7 +359,8 @@ const assessmentOverviewsTest2: AssessmentOverview[] = [ xp: 1, isGradingPublished: false, maxTeamSize: 1, - hasVotingFeatures: false + hasVotingFeatures: false, + hoursBeforeEarlyXpDecay: 0 } ]; From 2148314c02d63a7e262f83786ec4ecc1f35807cf Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:30:17 +0800 Subject: [PATCH 5/7] refactor: Use CSS Module instead of global scoped stylesheet --- src/commons/assessment/Assessment.tsx | 3 ++- src/styles/Academy.module.scss | 5 +++++ src/styles/_academy.scss | 5 ----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/commons/assessment/Assessment.tsx b/src/commons/assessment/Assessment.tsx index 655c7cc208..3482c15066 100644 --- a/src/commons/assessment/Assessment.tsx +++ b/src/commons/assessment/Assessment.tsx @@ -25,6 +25,7 @@ import { useDispatch } from 'react-redux'; import { Navigate, useLoaderData, useParams } from 'react-router'; import { NavLink } from 'react-router-dom'; import { numberRegExp } from 'src/features/academy/AcademyTypes'; +import classes from 'src/styles/Academy.module.scss'; import defaultCoverImage from '../../assets/default_cover_image.jpg'; import SessionActions from '../application/actions/SessionActions'; @@ -173,7 +174,7 @@ const Assessment: React.FC = () => {
{makeOverviewCardTitle(overview, index, renderGradingTooltip)} -
+
{overview.isGradingPublished ? `XP: ${overview.xp} / ${overview.maxXp}` diff --git a/src/styles/Academy.module.scss b/src/styles/Academy.module.scss index 88adf782b2..c261c29ff2 100644 --- a/src/styles/Academy.module.scss +++ b/src/styles/Academy.module.scss @@ -15,3 +15,8 @@ align-items: center; justify-content: center; } + +.listing-xp { + display: flex; + gap: 0.5rem; +} diff --git a/src/styles/_academy.scss b/src/styles/_academy.scss index ff76aebeca..6cdbcb3557 100644 --- a/src/styles/_academy.scss +++ b/src/styles/_academy.scss @@ -189,11 +189,6 @@ flex-direction: column; } - .listing-xp { - display: flex; - gap: 0.5rem; - } - .listing-header { margin-bottom: 0.8rem; display: flex; From be8551988af67d540352255f7d4fdaf1468298ce Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:39:49 +0800 Subject: [PATCH 6/7] feat: Add relative deadline to helper function --- src/commons/utils/DateHelper.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commons/utils/DateHelper.ts b/src/commons/utils/DateHelper.ts index e826b7378e..79454affba 100644 --- a/src/commons/utils/DateHelper.ts +++ b/src/commons/utils/DateHelper.ts @@ -44,6 +44,7 @@ export const getStandardDate = (dateString: string): string => { export const getPrettyDateAfterHours = (dateString: string, hours: number): string => { const date = moment(dateString).add(hours, 'hours'); - const prettyDate = date.format('Do MMMM, HH:mm'); - return prettyDate; + const absolutePrettyDate = date.format('Do MMMM, HH:mm'); + const relativePrettyDate = date.fromNow(); + return `${absolutePrettyDate} (${relativePrettyDate})`; }; From 42533638b34d6ce453eb56a1e8d7f1d40ea9c0e0 Mon Sep 17 00:00:00 2001 From: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:39:56 +0800 Subject: [PATCH 7/7] chore: Correct wording --- src/commons/assessment/Assessment.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commons/assessment/Assessment.tsx b/src/commons/assessment/Assessment.tsx index 3482c15066..d0f4f5ea05 100644 --- a/src/commons/assessment/Assessment.tsx +++ b/src/commons/assessment/Assessment.tsx @@ -182,7 +182,7 @@ const Assessment: React.FC = () => {
{overview.earlySubmissionXp > 0 && (