@@ -100,20 +100,27 @@ function isCancelledChallengeStatus(status) {
100100/**
101101 * Loads submission counters for challenge responses from the review submission table.
102102 *
103- * Community app badges show the number of members with submissions, not the
104- * number of attempts, so repeated uploads by the same member are counted once.
103+ * Community app badges normally show the number of members with submissions,
104+ * so repeated uploads by the same member are counted once. Design challenges
105+ * count every submission because each upload can be a unique concept.
105106 *
106107 * @param {Array<String> } challengeIds challenge identifiers to count submissions for
108+ * @param {Array<String> } designChallengeIds Design challenge identifiers that count every upload
107109 * @returns {Promise<Map<String, { numOfSubmissions: Number, numOfCheckpointSubmissions: Number }>> }
108110 * counts keyed by challenge id
109111 * @throws {Error } when the review database query fails
110112 */
111- async function getLatestSubmissionCountsByChallenge ( challengeIds ) {
113+ async function getLatestSubmissionCountsByChallenge ( challengeIds , designChallengeIds = [ ] ) {
112114 const ids = _ . uniq (
113115 ( challengeIds || [ ] )
114116 . map ( ( challengeId ) => _ . toString ( challengeId ) . trim ( ) )
115117 . filter ( ( challengeId ) => ! ! challengeId ) ,
116118 ) ;
119+ const designIds = _ . uniq (
120+ ( designChallengeIds || [ ] )
121+ . map ( ( challengeId ) => _ . toString ( challengeId ) . trim ( ) )
122+ . filter ( ( challengeId ) => ! ! challengeId ) ,
123+ ) ;
117124 const countsByChallenge = new Map ( ) ;
118125
119126 if ( ! ids . length || ! config . REVIEW_DB_URL ) {
@@ -124,16 +131,22 @@ async function getLatestSubmissionCountsByChallenge(challengeIds) {
124131 const submissionTable = reviewSchema
125132 ? Prisma . raw ( `"${ reviewSchema . replace ( / " / g, '""' ) } "."submission"` )
126133 : Prisma . raw ( '"submission"' ) ;
134+ const submissionIdentity = designIds . length
135+ ? Prisma . sql `CASE
136+ WHEN "challengeId" IN (${ Prisma . join ( designIds ) } ) THEN "id"
137+ ELSE "memberId"
138+ END`
139+ : Prisma . sql `"memberId"` ;
127140 const reviewClient = getReviewClient ( ) ;
128141
129142 const rows = await reviewClient . $queryRaw `
130143 SELECT
131144 "challengeId",
132145 COUNT(DISTINCT CASE
133- WHEN "type"::text = ${ CHECKPOINT_SUBMISSION_TYPE } THEN "memberId"
146+ WHEN "type"::text = ${ CHECKPOINT_SUBMISSION_TYPE } THEN ${ submissionIdentity }
134147 END)::int AS "numOfCheckpointSubmissions",
135148 COUNT(DISTINCT CASE
136- WHEN "type"::text <> ${ CHECKPOINT_SUBMISSION_TYPE } THEN "memberId"
149+ WHEN "type"::text <> ${ CHECKPOINT_SUBMISSION_TYPE } THEN ${ submissionIdentity }
137150 END)::int AS "numOfSubmissions"
138151 FROM ${ submissionTable }
139152 WHERE "challengeId" IN (${ Prisma . join ( ids ) } )
@@ -152,7 +165,11 @@ async function getLatestSubmissionCountsByChallenge(challengeIds) {
152165}
153166
154167/**
155- * Applies latest-member submission counts to challenge records before response conversion.
168+ * Applies submission counts to challenge records before response conversion.
169+ *
170+ * Design challenges count every submission as a separate concept. Other tracks
171+ * count distinct submitting members so replacement attempts do not inflate the
172+ * displayed total.
156173 *
157174 * If the review query succeeds, challenges without submission rows are reset to
158175 * zero so stale stored counters are not shown. If the query cannot run, callers
@@ -169,8 +186,12 @@ async function applyLatestSubmissionCounts(challenges) {
169186
170187 let countsByChallenge ;
171188 try {
189+ const designChallengeIds = records
190+ . filter ( ( challenge ) => phaseHelper . isDesignTrack ( challenge . track ) )
191+ . map ( ( challenge ) => challenge . id ) ;
172192 countsByChallenge = await getLatestSubmissionCountsByChallenge (
173193 records . map ( ( challenge ) => challenge . id ) ,
194+ designChallengeIds ,
174195 ) ;
175196 } catch ( err ) {
176197 logger . warn ( `Failed to load latest submission counts: ${ err . message } ` ) ;
0 commit comments