@@ -12,7 +12,14 @@ import {
1212 VIRUS_SCAN_FAILED_MESSAGE ,
1313} from '../../utils/constants'
1414import { getReviewRoute } from '../../utils/routes'
15- import { ChallengeDetailContextModel , ChallengeInfo } from '../../models'
15+ import {
16+ ChallengeDetailContextModel ,
17+ ChallengeInfo ,
18+ } from '../../models'
19+ import type {
20+ ReviewInfo ,
21+ ReviewResult ,
22+ } from '../../models'
1623import { isReviewPhaseCurrentlyOpen } from '../../utils'
1724
1825import {
@@ -295,6 +302,116 @@ export function renderReviewScoreCell(
295302 return < span > { rawScoreDisplay } </ span >
296303}
297304
305+ interface ReviewerDisplayData {
306+ color : string
307+ handle ?: string
308+ name : string
309+ profileUrl ?: string
310+ }
311+
312+ function findByResourceId < T extends { resourceId ?: string | null } > (
313+ items : T [ ] ,
314+ resourceId : string | undefined ,
315+ ) : T | undefined {
316+ if ( ! resourceId ) {
317+ return undefined
318+ }
319+
320+ return items . find ( item => item . resourceId === resourceId )
321+ }
322+
323+ function getValueFromMap < T > (
324+ map : Record < string , T | undefined > | undefined ,
325+ resourceId : string | undefined ,
326+ ) : T | undefined {
327+ if ( ! map || ! resourceId ) {
328+ return undefined
329+ }
330+
331+ return map [ resourceId ]
332+ }
333+
334+ function pickFirstNonEmptyString ( values : Array < string | null | undefined > ) : string | undefined {
335+ for ( const value of values ) {
336+ const trimmed = value ?. trim ( )
337+ if ( trimmed ) {
338+ return trimmed
339+ }
340+ }
341+
342+ return undefined
343+ }
344+
345+ function pickFirstNumber ( values : Array < number | null | undefined > ) : number | undefined {
346+ for ( const value of values ) {
347+ if ( typeof value === 'number' ) {
348+ return value
349+ }
350+ }
351+
352+ return undefined
353+ }
354+
355+ function buildReviewerDisplayData (
356+ submission : SubmissionRow ,
357+ reviewDetail : AggregatedReviewDetail ,
358+ ) : ReviewerDisplayData {
359+ const aggregatedSubmission = submission . aggregated ?. submission
360+ const resourceId = reviewDetail . reviewInfo ?. resourceId ?? reviewDetail . resourceId
361+ const candidateReviewInfos : ReviewInfo [ ] = [
362+ reviewDetail . reviewInfo ,
363+ aggregatedSubmission ?. review ,
364+ submission . review ,
365+ ] . filter ( ( info ) : info is ReviewInfo => Boolean ( info ) )
366+ const candidateReviewResults : ReviewResult [ ] = [
367+ ...( submission . reviews ?? [ ] ) ,
368+ ...( aggregatedSubmission ?. reviews ?? [ ] ) ,
369+ ] . filter ( ( result ) : result is ReviewResult => Boolean ( result ) )
370+
371+ const matchingInfo = findByResourceId ( candidateReviewInfos , resourceId )
372+ const matchingResult = findByResourceId ( candidateReviewResults , resourceId )
373+
374+ const reviewerHandle = pickFirstNonEmptyString ( [
375+ reviewDetail . reviewerHandle ,
376+ reviewDetail . reviewInfo ?. reviewerHandle ,
377+ matchingInfo ?. reviewerHandle ,
378+ matchingResult ?. reviewerHandle ,
379+ getValueFromMap ( submission . aggregated ?. reviewerHandles , resourceId ) ,
380+ ] )
381+
382+ const reviewerMaxRating = pickFirstNumber ( [
383+ reviewDetail . reviewerMaxRating ,
384+ reviewDetail . reviewInfo ?. reviewerMaxRating ?? undefined ,
385+ matchingInfo ?. reviewerMaxRating ?? undefined ,
386+ matchingResult ?. reviewerMaxRating ?? undefined ,
387+ getValueFromMap ( submission . aggregated ?. reviewerMaxRatings , resourceId ) ,
388+ ] )
389+
390+ const explicitColor = pickFirstNonEmptyString ( [
391+ reviewDetail . reviewerHandleColor ,
392+ reviewDetail . reviewInfo ?. reviewerHandleColor ,
393+ matchingInfo ?. reviewerHandleColor ,
394+ matchingResult ?. reviewerHandleColor ,
395+ getValueFromMap ( submission . aggregated ?. reviewerHandleColors , resourceId ) ,
396+ ] )
397+
398+ const color = getHandleColor (
399+ explicitColor ,
400+ reviewerHandle ,
401+ reviewerMaxRating ,
402+ ) ?? '#2a2a2a'
403+
404+ const name = reviewerHandle ?? 'Not assigned'
405+ const profileUrl = reviewerHandle ? getProfileUrl ( reviewerHandle ) : undefined
406+
407+ return {
408+ color,
409+ handle : reviewerHandle ,
410+ name,
411+ profileUrl,
412+ }
413+ }
414+
298415/**
299416 * Renders a reviewer cell for the given review index.
300417 */
@@ -312,29 +429,27 @@ export function renderReviewerCell(
312429 )
313430 }
314431
315- const reviewerHandle = reviewDetail . reviewerHandle ?. trim ( )
316- const reviewerColor = getHandleColor (
317- reviewDetail . reviewerHandleColor ,
318- reviewerHandle ,
319- reviewDetail . reviewerMaxRating ,
320- ) ?? '#2a2a2a'
321- const reviewerName = reviewerHandle || 'Not assigned'
322- const reviewerProfileUrl = reviewerHandle ? getProfileUrl ( reviewerHandle ) : undefined
432+ const {
433+ color,
434+ handle,
435+ name,
436+ profileUrl,
437+ } : ReviewerDisplayData = buildReviewerDisplayData ( submission , reviewDetail )
323438
324439 return (
325440 < span className = { styles . reviewer } >
326- { reviewerProfileUrl ? (
441+ { profileUrl ? (
327442 < a
328- href = { reviewerProfileUrl }
329- style = { { color : reviewerColor } }
443+ href = { profileUrl }
444+ style = { { color } }
330445 target = '_blank'
331446 rel = 'noreferrer'
332447 >
333- { reviewerHandle }
448+ { handle }
334449 </ a >
335450 ) : (
336- < span style = { { color : reviewerColor } } >
337- { reviewerName }
451+ < span style = { { color } } >
452+ { name }
338453 </ span >
339454 ) }
340455 </ span >
0 commit comments