Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/shared/containers/challenge-detail/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,14 @@ class ChallengeDetailPageContainer extends React.Component {

componentWillReceiveProps(nextProps) {
const {
auth,
challengeId,
reloadChallengeDetails,
// getAllRecommendedChallenges,
// recommendedChallenges,
// auth,
challenge,
statisticsData,
// loadingRecommendedChallengesUUID,
history,
selectedTab,
Expand Down Expand Up @@ -310,6 +312,25 @@ class ChallengeDetailPageContainer extends React.Component {
reloadChallengeDetails(nextProps.auth, challengeId);
}

const previousToken = _.get(auth, 'tokenV3');
const nextToken = _.get(nextProps, 'auth.tokenV3');
const hasStatisticsData = Array.isArray(statisticsData) && statisticsData.length > 0;
const nextHasStatisticsData = Array.isArray(nextProps.statisticsData)
&& nextProps.statisticsData.length > 0;
const enteringMmDashboard = selectedTab !== DETAIL_TABS.MM_DASHBOARD
&& nextProps.selectedTab === DETAIL_TABS.MM_DASHBOARD;
const tokenBecameAvailable = !previousToken && !!nextToken;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The variable enteringMmDashboard is defined but not used in the subsequent logic. Ensure this condition is necessary or remove it to avoid confusion.


if (
checkIsMM(nextProps.challenge)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 maintainability]
The condition checkIsMM(nextProps.challenge) is used multiple times in this method. Consider extracting it into a variable for better readability and maintainability.

&& nextToken
&& (tokenBecameAvailable || enteringMmDashboard)
&& !hasStatisticsData
&& !nextHasStatisticsData
) {
nextProps.fetchChallengeStatistics(nextProps.auth, nextProps.challenge);
}

const { track } = nextProps.challenge;
if (track !== COMPETITION_TRACKS.DES && thriveArticles.length === 0) {
// filter all tags with value 'Other'
Expand Down
79 changes: 72 additions & 7 deletions src/shared/utils/mm-review-summations.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,33 @@ function getSummationTimestamp(summation) {
return _.find(candidates, value => !!value) || null;
}

function getSummationScoreClassification(summation) {
const metadata = _.isObject(_.get(summation, 'metadata'))
? _.get(summation, 'metadata')
: {};
const type = _.toLower(_.toString(_.get(summation, 'type', '')).trim());
const stage = _.toLower(_.toString(_.get(metadata, 'stage', '')).trim());
const testType = _.toLower(_.toString(_.get(metadata, 'testType', '')).trim());

const isProvisional = Boolean(
_.get(summation, 'isProvisional')
|| _.get(summation, 'is_provisional')
|| type === 'provisional'
|| testType === 'provisional',
);
const isFinal = Boolean(
_.get(summation, 'isFinal')
|| _.get(summation, 'is_final')
|| type === 'final'
|| stage === 'final',
);

return {
isProvisional,
isFinal,
};
}

function toTimestampValue(value) {
if (!value) {
return 0;
Expand Down Expand Up @@ -373,7 +400,10 @@ export function buildMmSubmissionData(reviewSummations = []) {
const normalizedScore = normalizeScoreValue(
_.get(summation, 'aggregateScore'),
);
const isProvisional = Boolean(summation.isProvisional);
const scoreType = getSummationScoreClassification(summation);
// Most MM review summations are provisional updates; if an entry does not
// explicitly identify itself as final, treat it as provisional.
const isProvisional = scoreType.isProvisional || !scoreType.isFinal;
const isLatest = _.isNil(summation.isLatest)
? null
: Boolean(summation.isLatest);
Expand Down Expand Up @@ -415,16 +445,35 @@ export function buildMmSubmissionData(reviewSummations = []) {
- toTimestampValue(a.submissionTime),
);

const hasLatestFlag = submissions.some(s => !_.isNil(s.isLatest));
const latestProvisionalScore = _.chain(submissions)
.map(s => normalizeScoreValue(s.provisionalScore))
.find(score => !_.isNil(score))
.value();

const submissionsWithProvisionalFallback = submissions.map((submission) => {
const hasFinalScore = !_.isNil(normalizeScoreValue(submission.finalScore));
const hasProvisionalScore = !_.isNil(
normalizeScoreValue(submission.provisionalScore),
);
if (!hasFinalScore || hasProvisionalScore || _.isNil(latestProvisionalScore)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 readability]
The condition if (!hasFinalScore || hasProvisionalScore || _.isNil(latestProvisionalScore)) is complex and may lead to confusion. Consider breaking it down into smaller, named boolean variables to improve readability.

return submission;
}
return {
...submission,
provisionalScore: latestProvisionalScore,
};
});

const hasLatestFlag = submissionsWithProvisionalFallback.some(s => !_.isNil(s.isLatest));
const latestSubmissions = hasLatestFlag
? submissions.filter(s => s.isLatest)
: submissions;
? submissionsWithProvisionalFallback.filter(s => s.isLatest)
: submissionsWithProvisionalFallback;
const candidates = latestSubmissions.length
? latestSubmissions
: submissions;
: submissionsWithProvisionalFallback;
const latestSubmissionForRanking = (latestSubmissions.length
? latestSubmissions
: submissions)[0] || null;
: submissionsWithProvisionalFallback)[0] || null;
// Provisional ranks should be based solely on the most recent submission,
// not the best historical one.
const bestProvisionalScore = normalizeScoreValue(
Expand Down Expand Up @@ -463,7 +512,7 @@ export function buildMmSubmissionData(reviewSummations = []) {
rating,
provisionalRank: null,
finalRank: null,
submissions,
submissions: submissionsWithProvisionalFallback,
bestProvisionalScore,
bestProvisionalTimestamp,
bestFinalScore,
Expand Down Expand Up @@ -524,6 +573,13 @@ export function buildStatisticsData(reviewSummations = []) {
return [];
}

const includeOnlyProvisional = reviewSummations.some((summation) => {
if (!summation) {
return false;
}
return getSummationScoreClassification(summation).isProvisional;
});

const grouped = new Map();

reviewSummations.forEach((summation, index) => {
Expand All @@ -550,6 +606,15 @@ export function buildStatisticsData(reviewSummations = []) {
const timestamp = getSummationTimestamp(summation);
const timestampValue = toTimestampValue(timestamp);
const score = normalizeScoreValue(_.get(summation, 'aggregateScore'));
if (_.isNil(score)) {
return;
}
if (includeOnlyProvisional) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The check if (_.isNil(score)) { return; } is repeated in both buildMmSubmissionData and buildStatisticsData. Consider extracting this logic into a helper function to avoid duplication and improve maintainability.

const scoreType = getSummationScoreClassification(summation);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The logic for determining whether to include only provisional scores is duplicated in both buildMmSubmissionData and buildStatisticsData. Consider refactoring this into a shared utility function to reduce redundancy.

if (!scoreType.isProvisional) {
return;
}
}

const rawSubmissionId = _.get(
summation,
Expand Down
Loading