@@ -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+
58155export 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 }
0 commit comments