Skip to content

Commit 44f5417

Browse files
authored
Merge pull request #1302 from topcoder-platform/feat/v6
Show reopen button for registration phase, if submission or TG submission phase is open
2 parents bd29900 + 0e678d5 commit 44f5417

File tree

2 files changed

+153
-11
lines changed

2 files changed

+153
-11
lines changed

src/apps/review/src/lib/components/ChallengeDetailsContent/TabContentReview.tsx

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,115 @@ interface Props {
5555
isActiveChallenge: boolean
5656
}
5757

58+
const normalizeTabLabel = (value?: string): string => (
59+
value
60+
? value
61+
.toLowerCase()
62+
.replace(/[^a-z]/g, '')
63+
: ''
64+
)
65+
66+
const parseScoreValue = (value: unknown): number | undefined => {
67+
if (typeof value === 'number') {
68+
return Number.isFinite(value) ? value : undefined
69+
}
70+
71+
if (typeof value === 'string') {
72+
const trimmed = value.trim()
73+
if (!trimmed.length) {
74+
return undefined
75+
}
76+
77+
const parsed = Number.parseFloat(trimmed)
78+
return Number.isFinite(parsed) ? parsed : undefined
79+
}
80+
81+
return undefined
82+
}
83+
84+
const resolveSubmissionReviewScore = (submission: SubmissionInfo): number | undefined => {
85+
const reviewResultScores = Array.isArray(submission.reviews)
86+
? submission.reviews
87+
.map(review => parseScoreValue(review?.score))
88+
.filter((score): score is number => typeof score === 'number')
89+
: []
90+
91+
if (reviewResultScores.length) {
92+
const total = reviewResultScores.reduce((sum, score) => sum + score, 0)
93+
return total / reviewResultScores.length
94+
}
95+
96+
const aggregateScore = parseScoreValue(submission.aggregateScore)
97+
if (aggregateScore !== undefined) {
98+
return aggregateScore
99+
}
100+
101+
const finalScore = parseScoreValue(submission.review?.finalScore)
102+
if (finalScore !== undefined) {
103+
return finalScore
104+
}
105+
106+
const initialScore = parseScoreValue(submission.review?.initialScore)
107+
if (initialScore !== undefined) {
108+
return initialScore
109+
}
110+
111+
return undefined
112+
}
113+
114+
type SubmissionScoreEntry = {
115+
index: number
116+
score?: number
117+
submission: SubmissionInfo
118+
}
119+
120+
const sortSubmissionsByReviewScoreDesc = (rows: SubmissionInfo[]): SubmissionInfo[] => {
121+
const entries: SubmissionScoreEntry[] = rows.map((submission, index) => ({
122+
index,
123+
score: resolveSubmissionReviewScore(submission),
124+
submission,
125+
}))
126+
127+
entries.sort((a: SubmissionScoreEntry, b: SubmissionScoreEntry) => {
128+
const scoreA: number | undefined = a.score
129+
const scoreB: number | undefined = b.score
130+
const indexA: number = a.index
131+
const indexB: number = b.index
132+
133+
if (scoreA === undefined && scoreB === undefined) {
134+
return indexA - indexB
135+
}
136+
137+
if (scoreA === undefined) {
138+
return 1
139+
}
140+
141+
if (scoreB === undefined) {
142+
return -1
143+
}
144+
145+
if (scoreB !== scoreA) {
146+
return scoreB - scoreA
147+
}
148+
149+
return indexA - indexB
150+
})
151+
152+
return entries.map(entry => entry.submission)
153+
}
154+
58155
export const TabContentReview: FC<Props> = (props: Props) => {
59156
const selectedTab = props.selectedTab
60157
const providedReviews = props.reviews
61158
const providedSubmitterReviews = props.submitterReviews
159+
const normalizedSelectedTab = useMemo(
160+
() => normalizeTabLabel(selectedTab),
161+
[selectedTab],
162+
)
163+
const shouldSortReviewTabByScore = useMemo(
164+
() => !props.isActiveChallenge && normalizedSelectedTab === 'review',
165+
[normalizedSelectedTab, props.isActiveChallenge],
166+
)
62167
const {
63168
challengeInfo,
64169
challengeSubmissions: backendChallengeSubmissions,
@@ -546,13 +651,27 @@ export const TabContentReview: FC<Props> = (props: Props) => {
546651
},
547652
[resolvedSubmitterReviews],
548653
)
654+
const reviewerRowsForReviewTab = useMemo(
655+
() => (shouldSortReviewTabByScore
656+
? sortSubmissionsByReviewScoreDesc(filteredReviews)
657+
: filteredReviews),
658+
[filteredReviews, shouldSortReviewTabByScore],
659+
)
660+
const submitterRowsForReviewTab = useMemo(
661+
() => (shouldSortReviewTabByScore
662+
? sortSubmissionsByReviewScoreDesc(filteredSubmitterReviews)
663+
: filteredSubmitterReviews),
664+
[filteredSubmitterReviews, shouldSortReviewTabByScore],
665+
)
549666
const hideHandleColumn = props.isActiveChallenge
550667
&& actionChallengeRole === REVIEWER
551668

552669
// show loading ui when fetching data
553670
const isSubmitterView = actionChallengeRole === SUBMITTER
554671
&& selectedTab !== APPROVAL
555-
const reviewRows = isSubmitterView ? filteredSubmitterReviews : filteredReviews
672+
const reviewRows = isSubmitterView
673+
? (shouldSortReviewTabByScore ? submitterRowsForReviewTab : filteredSubmitterReviews)
674+
: (shouldSortReviewTabByScore ? reviewerRowsForReviewTab : filteredReviews)
556675

557676
if (props.isLoadingReview) {
558677
return <TableLoading />
@@ -596,14 +715,14 @@ export const TabContentReview: FC<Props> = (props: Props) => {
596715

597716
return isSubmitterView ? (
598717
<TableReviewForSubmitter
599-
datas={filteredSubmitterReviews}
718+
datas={reviewRows}
600719
isDownloading={props.isDownloading}
601720
downloadSubmission={props.downloadSubmission}
602721
mappingReviewAppeal={props.mappingReviewAppeal}
603722
/>
604723
) : (
605724
<TableReview
606-
datas={filteredReviews}
725+
datas={reviewRows}
607726
isDownloading={props.isDownloading}
608727
downloadSubmission={props.downloadSubmission}
609728
mappingReviewAppeal={props.mappingReviewAppeal}

src/apps/review/src/pages/active-review-assignements/ChallengeDetailsPage/ChallengeDetailsPage.tsx

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ interface Props {
6666
className?: string
6767
}
6868

69+
const normalizePhaseName = (name?: string): string => (name ? name.trim()
70+
.toLowerCase() : '')
71+
const SUBMISSION_PHASE_NAMES = new Set(['submission', 'topgear submission'])
72+
const REGISTRATION_PHASE_NAME = 'registration'
73+
6974
// Helpers to keep UI hooks simple and under complexity limits
7075

7176
// Compute a Set of this member's reviewer resource IDs (excluding iterative roles)
@@ -1089,23 +1094,41 @@ export const ChallengeDetailsPage: FC<Props> = (props: Props) => {
10891094
return allowed
10901095
}
10911096

1092-
challengePhases.forEach(phase => {
1093-
if (!phase?.isOpen || !phase.predecessor) {
1097+
const addPhaseIdentifiers = (phase?: BackendPhase): void => {
1098+
if (!phase) {
10941099
return
10951100
}
10961101

1097-
allowed.add(phase.predecessor)
1102+
if (phase.id) {
1103+
allowed.add(phase.id)
1104+
}
10981105

1099-
const predecessorPhase = phaseLookup.get(phase.predecessor)
1100-
if (predecessorPhase?.id) {
1101-
allowed.add(predecessorPhase.id)
1106+
if (phase.phaseId) {
1107+
allowed.add(phase.phaseId)
11021108
}
1109+
}
11031110

1104-
if (predecessorPhase?.phaseId) {
1105-
allowed.add(predecessorPhase.phaseId)
1111+
challengePhases.forEach(phase => {
1112+
if (!phase?.isOpen || !phase.predecessor) {
1113+
return
11061114
}
1115+
1116+
allowed.add(phase.predecessor)
1117+
addPhaseIdentifiers(phaseLookup.get(phase.predecessor))
11071118
})
11081119

1120+
const hasSubmissionVariantOpen = challengePhases.some(phase => (
1121+
phase?.isOpen && SUBMISSION_PHASE_NAMES.has(normalizePhaseName(phase.name))
1122+
))
1123+
1124+
if (hasSubmissionVariantOpen) {
1125+
challengePhases.forEach(phase => {
1126+
if (normalizePhaseName(phase?.name) === REGISTRATION_PHASE_NAME) {
1127+
addPhaseIdentifiers(phase)
1128+
}
1129+
})
1130+
}
1131+
11091132
return allowed
11101133
}, [challengePhases, phaseLookup])
11111134

0 commit comments

Comments
 (0)