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 && (