diff --git a/__tests__/shared/components/challenge-detail/Header/index.jsx b/__tests__/shared/components/challenge-detail/Header/index.jsx
index 8ffdb6648..9a51b14d5 100644
--- a/__tests__/shared/components/challenge-detail/Header/index.jsx
+++ b/__tests__/shared/components/challenge-detail/Header/index.jsx
@@ -2,9 +2,14 @@ import React from 'react';
import Renderer from 'react-test-renderer/shallow';
import Header from 'components/challenge-detail/Header';
+import TabSelector from 'components/challenge-detail/Header/TabSelector';
+
+jest.mock('react-responsive', () => ({
+ useMediaQuery: () => true,
+}));
function collectText(node) {
- if (typeof node === 'string') {
+ if (typeof node === 'string' || typeof node === 'number') {
return [node];
}
@@ -125,3 +130,40 @@ describe('Challenge detail header actions', () => {
expect(collectText(output)).toContain('Submit a solution');
});
});
+
+describe('Challenge detail tab counts', () => {
+ test('renders the MM submission total independently of loaded attempts', () => {
+ const renderer = new Renderer();
+ renderer.render(
+ ,
+ );
+
+ const text = collectText(renderer.getRenderOutput());
+ const mySubmissionsLabelIndex = text.indexOf('My Submissions');
+
+ expect(text[mySubmissionsLabelIndex + 1]).toBe(3);
+ });
+});
diff --git a/__tests__/shared/containers/challenge-detail/index.jsx b/__tests__/shared/containers/challenge-detail/index.jsx
index 5fef65aa9..59b7497c4 100644
--- a/__tests__/shared/containers/challenge-detail/index.jsx
+++ b/__tests__/shared/containers/challenge-detail/index.jsx
@@ -4,6 +4,7 @@ import {
isGroupedChallenge,
isGroupedChallengeAccessError,
isWiproRegistrationBlocked,
+ mapStateToProps,
shouldLoginForGroupedChallenge,
shouldLoginForGroupedChallengeError,
} from 'containers/challenge-detail';
@@ -76,6 +77,64 @@ describe('Challenge detail winners filter', () => {
});
});
+describe('Challenge detail My Submissions count', () => {
+ test('uses the total attempt count when only the latest MM submission is loaded', () => {
+ const state = {
+ auth: {
+ user: {
+ handle: 'member',
+ userId: '123',
+ },
+ },
+ challenge: {
+ checkpoints: {},
+ details: {
+ id: 'challenge-id',
+ registrants: [{ memberHandle: 'member', memberId: '123' }],
+ submissions: [],
+ },
+ mmSubmissions: {
+ challengeId: 'challenge-id',
+ data: [{
+ member: 'member',
+ memberId: '123',
+ submissionCount: 3,
+ submissions: [{ submissionId: 'latest-submission' }],
+ }],
+ },
+ reviewSummations: [],
+ statisticsData: [],
+ },
+ challengeListing: {},
+ domain: {},
+ lookup: {
+ allCountries: [],
+ reviewTypes: [],
+ },
+ page: {
+ challengeDetails: {
+ feedbackOpen: {},
+ },
+ },
+ tcCommunities: {
+ list: {},
+ },
+ terms: {},
+ topcoderHeader: {},
+ };
+
+ const props = mapStateToProps(state, {
+ challengesUrl: '/challenges',
+ match: {
+ params: { challengeId: 'challenge-id' },
+ },
+ });
+
+ expect(props.mySubmissions).toHaveLength(1);
+ expect(props.mySubmissionsCount).toBe(3);
+ });
+});
+
describe('Challenge detail grouped challenge login guard', () => {
beforeEach(() => {
document.cookie = 'tc_utm=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
diff --git a/src/shared/components/challenge-detail/Header/TabSelector/index.jsx b/src/shared/components/challenge-detail/Header/TabSelector/index.jsx
index a02f2177b..6916a4ac9 100644
--- a/src/shared/components/challenge-detail/Header/TabSelector/index.jsx
+++ b/src/shared/components/challenge-detail/Header/TabSelector/index.jsx
@@ -39,6 +39,7 @@ export default function ChallengeViewSelector(props) {
trackLower,
hasRegistered,
mySubmissions,
+ mySubmissionsCount,
onSort,
viewAsTable,
} = props;
@@ -133,6 +134,9 @@ export default function ChallengeViewSelector(props) {
}
const numOfSub = numOfSubmissions + (numOfCheckpointSubmissions || 0);
+ const mySubmissionsBadgeCount = _.isFinite(mySubmissionsCount)
+ ? mySubmissionsCount
+ : mySubmissions.length;
const forumId = _.get(challenge, 'legacy.forumId') || 0;
const discuss = _.get(challenge, 'discussions', []).filter(d => (
_.toLower(d.type) === 'challenge' && !_.isEmpty(d.url)
@@ -247,7 +251,7 @@ export default function ChallengeViewSelector(props) {
styleName={getSelectorStyle(selectedView, DETAIL_TABS.MY_SUBMISSIONS)}
>
My Submissions
- {mySubmissions.length}
+ {mySubmissionsBadgeCount}
) : null
}
@@ -358,7 +362,7 @@ export default function ChallengeViewSelector(props) {
{
currentSelected === DETAIL_TABS.MY_SUBMISSIONS && hasRegistered
&& isMM && mySubmissions && (
- {mySubmissions.length}
+ {mySubmissionsBadgeCount}
)
}
{
@@ -447,6 +451,7 @@ ChallengeViewSelector.defaultProps = {
numOfRegistrants: 0,
numOfCheckpointSubmissions: 0,
numOfSubmissions: 0,
+ mySubmissionsCount: null,
};
ChallengeViewSelector.propTypes = {
@@ -477,6 +482,7 @@ ChallengeViewSelector.propTypes = {
trackLower: PT.string.isRequired,
hasRegistered: PT.bool.isRequired,
mySubmissions: PT.arrayOf(PT.shape()).isRequired,
+ mySubmissionsCount: PT.number,
onSort: PT.func.isRequired,
viewAsTable: PT.bool.isRequired,
};
diff --git a/src/shared/components/challenge-detail/Header/index.jsx b/src/shared/components/challenge-detail/Header/index.jsx
index 77c945f40..345ed44c1 100644
--- a/src/shared/components/challenge-detail/Header/index.jsx
+++ b/src/shared/components/challenge-detail/Header/index.jsx
@@ -63,6 +63,7 @@ export default function ChallengeHeader(props) {
isMenuOpened,
submissionEnded,
mySubmissions,
+ mySubmissionsCount,
openForRegistrationChallenges,
onSort,
viewAsTable,
@@ -571,6 +572,7 @@ export default function ChallengeHeader(props) {
hasRegistered={hasRegistered}
checkpointCount={checkpointCount}
mySubmissions={mySubmissions}
+ mySubmissionsCount={mySubmissionsCount}
onSort={onSort}
viewAsTable={viewAsTable}
/>
@@ -585,6 +587,7 @@ ChallengeHeader.defaultProps = {
isMenuOpened: false,
hasThriveArticles: false,
hasRecommendedChallenges: false,
+ mySubmissionsCount: null,
};
ChallengeHeader.propTypes = {
@@ -639,6 +642,7 @@ ChallengeHeader.propTypes = {
hasFirstPlacement: PT.bool.isRequired,
isMenuOpened: PT.bool,
mySubmissions: PT.arrayOf(PT.shape()).isRequired,
+ mySubmissionsCount: PT.number,
openForRegistrationChallenges: PT.shape().isRequired,
onSort: PT.func.isRequired,
viewAsTable: PT.bool.isRequired,
diff --git a/src/shared/containers/challenge-detail/index.jsx b/src/shared/containers/challenge-detail/index.jsx
index dce96908b..8cc7594ed 100644
--- a/src/shared/containers/challenge-detail/index.jsx
+++ b/src/shared/containers/challenge-detail/index.jsx
@@ -564,6 +564,7 @@ class ChallengeDetailPageContainer extends React.Component {
// expandedTags,
// expandTag,
mySubmissions,
+ mySubmissionsCount,
reviewTypes,
openForRegistrationChallenges,
statisticsData,
@@ -710,6 +711,7 @@ class ChallengeDetailPageContainer extends React.Component {
isMenuOpened={isMenuOpened}
submissionEnded={submissionEnded}
mySubmissions={challenge.isRegistered ? mySubmissions : []}
+ mySubmissionsCount={challenge.isRegistered ? mySubmissionsCount : 0}
openForRegistrationChallenges={openForRegistrationChallenges}
viewAsTable={viewAsTable && isMM}
onSort={(currenctSelected, sort) => {
@@ -941,6 +943,7 @@ ChallengeDetailPageContainer.defaultProps = {
loadingMMSubmissionsForChallengeId: null,
mmSubmissions: [],
mySubmissions: [],
+ mySubmissionsCount: 0,
isLoadingSubmissionInformation: false,
submissionInformation: null,
// prizeMode: 'money-usd',
@@ -993,6 +996,7 @@ ChallengeDetailPageContainer.propTypes = {
reviewTypes: PT.arrayOf(PT.shape()),
reviewSummations: PT.arrayOf(PT.shape()).isRequired,
mySubmissions: PT.arrayOf(PT.shape()),
+ mySubmissionsCount: PT.number,
toggleCheckpointFeedback: PT.func.isRequired,
unregisterFromChallenge: PT.func.isRequired,
unregistering: PT.bool.isRequired,
@@ -1269,6 +1273,7 @@ export function mapStateToProps(state, props) {
? buildReviewSummationLookup(reviewSummations)
: null;
let mySubmissions = [];
+ let mySubmissionsCount = 0;
if (challenge.registrants) {
challenge.registrants = challenge.registrants.map(registrant => ({
...registrant,
@@ -1516,6 +1521,12 @@ export function mapStateToProps(state, props) {
...attempt,
id: normalizedAttempts.length - index,
}));
+ const submissionCount = _.isNil(submission.submissionCount)
+ ? null
+ : Number(submission.submissionCount);
+ mySubmissionsCount = Number.isFinite(submissionCount)
+ ? submissionCount
+ : mySubmissions.length;
}
return ({
@@ -1528,6 +1539,7 @@ export function mapStateToProps(state, props) {
});
} else if (loggedInUserId) {
mySubmissions = _.filter(challenge.submissions, s => (`${s.memberId}` === `${loggedInUserId}`));
+ mySubmissionsCount = mySubmissions.length;
}
}
const { page: { challengeDetails: { feedbackOpen } } } = state;
@@ -1582,6 +1594,7 @@ export function mapStateToProps(state, props) {
reviewSummations,
allCountries: state.lookup.allCountries,
mySubmissions,
+ mySubmissionsCount,
reviewTypes,
openForRegistrationChallenges: state.challengeListing.openForRegistrationChallenges,
statisticsData,