diff --git a/src/apps/review/src/lib/components/common/TableColumnRenderers.tsx b/src/apps/review/src/lib/components/common/TableColumnRenderers.tsx index 7b256061d..09a32c7a2 100644 --- a/src/apps/review/src/lib/components/common/TableColumnRenderers.tsx +++ b/src/apps/review/src/lib/components/common/TableColumnRenderers.tsx @@ -242,8 +242,11 @@ export function renderReviewScoreCell( .trim() .toUpperCase() : '' + const hasValidScore = typeof review.finalScore === 'number' + && Number.isFinite(review.finalScore) + if (!normalizedStatus) { - return true + return !hasValidScore } return normalizedStatus !== 'COMPLETED' @@ -540,9 +543,9 @@ export function renderScoreCell( } const reviewInfo = reviewDetail.reviewInfo - const reviewId = reviewInfo?.id || reviewDetail.reviewId + const reviewId = reviewInfo?.id ?? reviewDetail.reviewId - if (!reviewInfo || !reviewId) { + if (!reviewId) { return ( -- diff --git a/src/apps/review/src/lib/hooks/useFetchChallengeRelativeDatas.ts b/src/apps/review/src/lib/hooks/useFetchChallengeRelativeDatas.ts index 310a1e156..739e8ecaa 100644 --- a/src/apps/review/src/lib/hooks/useFetchChallengeRelativeDatas.ts +++ b/src/apps/review/src/lib/hooks/useFetchChallengeRelativeDatas.ts @@ -12,8 +12,52 @@ import { fetchAllResourceRoles, fetchChallengeResouces, } from '../services/resources.service' -import { BackendResourceRole, BackendSubmission, ChallengeRealtiveInfosMapping } from '../models' import { fetchSubmissions } from '../services' +import { BackendResourceRole, BackendSubmission, ChallengeRealtiveInfosMapping } from '../models' + +const FALLBACK_RESOURCE_ROLES: BackendResourceRole[] = [ + { + fullReadAccess: false, + fullWriteAccess: false, + id: 'fd672cca-556e-4d16-b0a2-718218edd412', + isActive: true, + legacyId: 19, + name: 'Checkpoint Screener', + selfObtainable: false, + }, + { + fullReadAccess: true, + fullWriteAccess: false, + id: '3970272b-85b4-48d8-8439-672b4f6031bd', + isActive: true, + legacyId: 20, + name: 'Checkpoint Reviewer', + selfObtainable: false, + }, +] + +const ensureResourceRoleMapping = ( + mapping: { [key: string]: BackendResourceRole } | undefined, +): { [key: string]: BackendResourceRole } => { + const base = { ...(mapping ?? {}) } + + FALLBACK_RESOURCE_ROLES.forEach(role => { + const existing = base[role.id] + if (!existing) { + base[role.id] = role + return + } + + if (!existing.name) { + base[role.id] = { + ...existing, + name: role.name, + } + } + }) + + return base +} export interface useFetchChallengeRelativeDatasProps { challengeRelativeInfosMapping: ChallengeRealtiveInfosMapping // from challenge id to list of my role @@ -57,20 +101,21 @@ export function useFetchChallengeRelativeDatas( setResourceRoleReviewer(find(results.data, { name: 'Reviewer', })) - setResourceRoleMapping( - reduce( - results.data, - (mappingResult, resourceRole: BackendResourceRole) => ({ - ...mappingResult, - [resourceRole.id]: resourceRole, - }), - {}, - ), - ) + const mapping = ensureResourceRoleMapping(reduce( + results.data, + (mappingResult, resourceRole: BackendResourceRole) => ({ + ...mappingResult, + [resourceRole.id]: resourceRole, + }), + {}, + )) + + setResourceRoleMapping(mapping) setIsLoadingResourceRoles(false) }) .catch(e => { handleError(e) + setResourceRoleMapping(current => ensureResourceRoleMapping(current)) setIsLoadingResourceRoles(false) }) }) diff --git a/src/apps/review/src/lib/models/ReviewResult.model.ts b/src/apps/review/src/lib/models/ReviewResult.model.ts index 9d422d17b..dd0e5822c 100644 --- a/src/apps/review/src/lib/models/ReviewResult.model.ts +++ b/src/apps/review/src/lib/models/ReviewResult.model.ts @@ -11,6 +11,7 @@ import { BackendReview } from './BackendReview.model' * Review result info */ export interface ReviewResult { + id?: string appeals: AppealResult[] createdAt: string | Date createdAtString?: string // this field is calculated at frontend @@ -111,6 +112,7 @@ export function convertBackendReviewToReviewResult( appeals: [], createdAt, createdAtString, + id: data.id, phaseName, resourceId: data.resourceId, reviewDate, diff --git a/src/apps/review/src/lib/models/SubmissionInfo.model.ts b/src/apps/review/src/lib/models/SubmissionInfo.model.ts index 284d838d9..73c04946d 100644 --- a/src/apps/review/src/lib/models/SubmissionInfo.model.ts +++ b/src/apps/review/src/lib/models/SubmissionInfo.model.ts @@ -22,6 +22,7 @@ export interface SubmissionInfo { memberId: string userInfo?: BackendResource // this field is calculated at frontend review?: ReviewInfo + reviewInfos?: ReviewInfo[] reviews?: ReviewResult[] /** * Backend review type identifier (e.g. 'Post-Mortem Review'). @@ -109,6 +110,9 @@ export function convertBackendSubmissionToSubmissionInfo( ? isPassingReviewRaw : undefined const reviewEntries = Array.isArray(data.review) ? data.review : [] + const reviewInfos = reviewEntries.map(convertBackendReviewToReviewInfo) + const reviewResults = reviewEntries.map(convertBackendReviewToReviewResult) + const primaryReviewInfo = reviewInfos[0] const primaryReview = reviewEntries[0] return { @@ -117,11 +121,9 @@ export function convertBackendSubmissionToSubmissionInfo( isLatest: data.isLatest, isPassingReview, memberId: data.memberId, - review: - primaryReview - ? convertBackendReviewToReviewInfo(primaryReview) - : undefined, - reviews: reviewEntries.map(convertBackendReviewToReviewResult), + review: primaryReviewInfo, + reviewInfos, + reviews: reviewResults, reviewTypeId: primaryReview?.typeId ?? undefined, submittedDate, submittedDateString, diff --git a/src/apps/review/src/lib/utils/aggregateSubmissionReviews.ts b/src/apps/review/src/lib/utils/aggregateSubmissionReviews.ts index 679295798..a12aeb404 100644 --- a/src/apps/review/src/lib/utils/aggregateSubmissionReviews.ts +++ b/src/apps/review/src/lib/utils/aggregateSubmissionReviews.ts @@ -1,5 +1,5 @@ /* eslint-disable ordered-imports/ordered-imports */ -import { find, forEach, sumBy } from 'lodash' +import { forEach, sumBy } from 'lodash' import moment from 'moment' import { getRatingColor } from '~/libs/core' @@ -9,6 +9,7 @@ import { BackendResource, MappingReviewAppeal, ReviewInfo, + ReviewResult, SubmissionInfo, } from '../models' import { normalizeRatingValue } from './rating' @@ -84,6 +85,31 @@ function resolveHandleColor( : undefined) } +const deriveReviewResultFromReviewInfo = (reviewInfo: ReviewInfo): ReviewResult => { + const reviewerHandle = reviewInfo.reviewerHandle?.trim() || undefined + const reviewerMaxRating = normalizeRatingValue(reviewInfo.reviewerMaxRating) + const reviewerHandleColor = resolveHandleColor( + reviewInfo.reviewerHandleColor, + reviewerHandle, + reviewerMaxRating, + ) ?? '#2a2a2a' + + return { + appeals: [], + createdAt: reviewInfo.createdAt, + createdAtString: reviewInfo.createdAtString, + phaseName: reviewInfo.phaseName ?? undefined, + resourceId: reviewInfo.resourceId, + reviewDate: reviewInfo.reviewDate, + reviewDateString: reviewInfo.reviewDateString ?? reviewInfo.updatedAtString, + reviewerHandle: reviewerHandle ?? '', + reviewerHandleColor, + reviewerMaxRating, + reviewType: reviewInfo.reviewType ?? undefined, + score: normalizeScoreValue(reviewInfo.finalScore ?? reviewInfo.initialScore), + } +} + /* eslint-disable complexity */ /* eslint-disable no-console */ export function aggregateSubmissionReviews({ @@ -135,221 +161,328 @@ export function aggregateSubmissionReviews({ return } - const reviewInfo: ReviewInfo | undefined = submission.review - const reviewId = reviewInfo?.id - const resourceId = reviewInfo?.resourceId - const matchingReviewResult = resourceId - ? find(submission.reviews, reviewResult => reviewResult.resourceId === resourceId) - : undefined - if (!reviewId) { - return + const reviewInfoByResourceId = new Map() + const reviewInfoById = new Map() + + if (submission.review?.resourceId) { + reviewInfoByResourceId.set(submission.review.resourceId, submission.review) } - const seenReviewIds = seenReviewIdsBySubmission.get(submission.id) ?? new Set() - const reviewerInfo = resourceId ? reviewerByResourceId[resourceId] : undefined - if (resourceId) { - discoveredResourceIds.add(resourceId) + if (submission.review?.id) { + reviewInfoById.set(submission.review.id, submission.review) } - const reviewDate = reviewInfo?.reviewDate - ? new Date(reviewInfo.reviewDate) - : reviewInfo?.updatedAt - ? new Date(reviewInfo.updatedAt) - : undefined - const reviewDateString = reviewInfo?.reviewDateString - ?? reviewInfo?.updatedAtString - - const reviewHandle = reviewInfo?.reviewerHandle?.trim() || undefined - const resultHandle = matchingReviewResult?.reviewerHandle?.trim() || undefined - const resourceHandle = reviewerInfo?.memberHandle?.trim() || undefined - const candidateReviewerHandle = reviewHandle - ?? resultHandle - ?? resourceHandle - const fallbackMappedHandle = resourceId ? reviewerHandleByResourceId[resourceId]?.trim() : undefined - const resolvedReviewerHandle = candidateReviewerHandle - ?? fallbackMappedHandle - - if (resourceId && resolvedReviewerHandle) { - reviewerHandleByResourceId[resourceId] = resolvedReviewerHandle + const additionalReviewInfos = Array.isArray(submission.reviewInfos) + ? submission.reviewInfos + : [] + additionalReviewInfos.forEach(info => { + if (info.id) { + reviewInfoById.set(info.id, info) + } + + if (info.resourceId) { + reviewInfoByResourceId.set(info.resourceId, info) + } + }) + + const seenReviewIds = seenReviewIdsBySubmission.get(submission.id) ?? new Set() + const reviewsToProcess: ReviewResult[] = Array.isArray(submission.reviews) + ? submission.reviews.slice() + : [] + + if (!reviewsToProcess.length && submission.review) { + reviewsToProcess.push(deriveReviewResultFromReviewInfo(submission.review)) + } else if (submission.review?.resourceId) { + const hasMatchingReview = reviewsToProcess.some( + review => review.resourceId === submission.review?.resourceId, + ) + if (!hasMatchingReview) { + reviewsToProcess.push(deriveReviewResultFromReviewInfo(submission.review)) + } } - const finalReviewerMaxRating = normalizeRatingValue( - reviewInfo?.reviewerMaxRating - ?? matchingReviewResult?.reviewerMaxRating - ?? reviewerInfo?.rating, - ) - const finalReviewerHandleColor = resolveHandleColor( - reviewInfo?.reviewerHandleColor - ?? matchingReviewResult?.reviewerHandleColor - ?? reviewerInfo?.handleColor, - resolvedReviewerHandle ?? fallbackMappedHandle, - finalReviewerMaxRating, - ) + forEach(reviewsToProcess, reviewResult => { + const resourceId = reviewResult.resourceId + const reviewResultId = reviewResult.id + const reviewInfoFromId = reviewResultId + ? reviewInfoById.get(reviewResultId) + : undefined + const reviewInfo = reviewInfoFromId + ?? (resourceId + ? reviewInfoByResourceId.get(resourceId) + : submission.review && !submission.review.resourceId + ? submission.review + : undefined) + const reviewId = reviewInfo?.id ?? reviewResultId + const reviewKey = reviewId ?? (resourceId ? `resource:${resourceId}` : undefined) + + if (reviewKey && seenReviewIds.has(reviewKey)) { + return + } - if (reviewInfo) { - const trimmedSubmitterHandle = reviewInfo.submitterHandle?.trim() - if (trimmedSubmitterHandle) { - group.submitterHandle = trimmedSubmitterHandle + const reviewerInfo = resourceId ? reviewerByResourceId[resourceId] : undefined + if (resourceId) { + discoveredResourceIds.add(resourceId) } - if (reviewInfo.submitterHandleColor) { - group.submitterHandleColor = reviewInfo.submitterHandleColor + const reviewDate = reviewInfo?.reviewDate + ? new Date(reviewInfo.reviewDate) + : reviewInfo?.updatedAt + ? new Date(reviewInfo.updatedAt) + : reviewResult.reviewDate instanceof Date + ? reviewResult.reviewDate + : reviewResult.reviewDate + ? new Date(reviewResult.reviewDate) + : undefined + const reviewDateString = reviewInfo?.reviewDateString + ?? reviewInfo?.updatedAtString + ?? reviewResult.reviewDateString + + const reviewHandle = reviewInfo?.reviewerHandle?.trim() || undefined + const resultHandle = reviewResult.reviewerHandle?.trim() || undefined + const resourceHandle = reviewerInfo?.memberHandle?.trim() || undefined + const fallbackMappedHandle = resourceId ? reviewerHandleByResourceId[resourceId]?.trim() : undefined + const candidateReviewerHandle = reviewHandle + ?? resultHandle + ?? resourceHandle + const resolvedReviewerHandle = candidateReviewerHandle + ?? fallbackMappedHandle + + if (resourceId && resolvedReviewerHandle) { + reviewerHandleByResourceId[resourceId] = resolvedReviewerHandle } - const normalizedSubmitterMaxRating = normalizeRatingValue(reviewInfo.submitterMaxRating) - if (normalizedSubmitterMaxRating !== undefined) { - group.submitterMaxRating = normalizedSubmitterMaxRating + const finalReviewerMaxRating = normalizeRatingValue( + reviewInfo?.reviewerMaxRating + ?? reviewResult.reviewerMaxRating + ?? reviewerInfo?.rating, + ) + const finalReviewerHandleColor = resolveHandleColor( + reviewInfo?.reviewerHandleColor + ?? reviewResult.reviewerHandleColor + ?? reviewerInfo?.handleColor, + resolvedReviewerHandle ?? fallbackMappedHandle, + finalReviewerMaxRating, + ) + + if (reviewInfo) { + const trimmedSubmitterHandle = reviewInfo.submitterHandle?.trim() + if (trimmedSubmitterHandle) { + group.submitterHandle = trimmedSubmitterHandle + } + + if (reviewInfo.submitterHandleColor) { + group.submitterHandleColor = reviewInfo.submitterHandleColor + } + + const normalizedSubmitterMaxRating = normalizeRatingValue(reviewInfo.submitterMaxRating) + if (normalizedSubmitterMaxRating !== undefined) { + group.submitterMaxRating = normalizedSubmitterMaxRating + } } - } - const finalScore = normalizeScoreValue( - reviewInfo?.finalScore ?? matchingReviewResult?.score, - ) + const finalScore = normalizeScoreValue( + reviewResult.score + ?? reviewInfo?.finalScore + ?? reviewInfo?.initialScore, + ) - let normalizedReviewInfo: ReviewInfo | undefined = reviewInfo - if (reviewInfo) { - const needsHandle = !reviewInfo.reviewerHandle?.trim() && resolvedReviewerHandle - const needsColor = !reviewInfo.reviewerHandleColor && finalReviewerHandleColor - const needsMaxRating = (reviewInfo.reviewerMaxRating === undefined || reviewInfo.reviewerMaxRating === null) - && finalReviewerMaxRating !== undefined - - if (needsHandle || needsColor || needsMaxRating) { - normalizedReviewInfo = { - ...reviewInfo, - reviewerHandle: needsHandle - ? resolvedReviewerHandle ?? reviewInfo.reviewerHandle - : reviewInfo.reviewerHandle, - reviewerHandleColor: needsColor - ? finalReviewerHandleColor ?? reviewInfo.reviewerHandleColor - : reviewInfo.reviewerHandleColor, - reviewerMaxRating: needsMaxRating - ? finalReviewerMaxRating ?? reviewInfo.reviewerMaxRating - : reviewInfo.reviewerMaxRating, + let normalizedReviewInfo: ReviewInfo | undefined = reviewInfo + if (reviewInfo) { + const needsHandle = !reviewInfo.reviewerHandle?.trim() && resolvedReviewerHandle + const needsColor = !reviewInfo.reviewerHandleColor && finalReviewerHandleColor + const needsMaxRating = ( + reviewInfo.reviewerMaxRating === undefined + || reviewInfo.reviewerMaxRating === null + ) + && finalReviewerMaxRating !== undefined + + if (needsHandle || needsColor || needsMaxRating) { + normalizedReviewInfo = { + ...reviewInfo, + reviewerHandle: needsHandle + ? resolvedReviewerHandle ?? reviewInfo.reviewerHandle + : reviewInfo.reviewerHandle, + reviewerHandleColor: needsColor + ? finalReviewerHandleColor ?? reviewInfo.reviewerHandleColor + : reviewInfo.reviewerHandleColor, + reviewerMaxRating: needsMaxRating + ? finalReviewerMaxRating ?? reviewInfo.reviewerMaxRating + : reviewInfo.reviewerMaxRating, + } } } - } - if (process.env.NODE_ENV !== 'production') { - if (resolvedReviewerHandle) { - console.debug('[ReviewAggregation] Resolved reviewer handle', { - resourceHandle: reviewerInfo?.memberHandle, - reviewerHandle: resolvedReviewerHandle, - reviewId, - reviewInfoHandle: reviewInfo?.reviewerHandle, - reviewResultHandle: matchingReviewResult?.reviewerHandle, - source: reviewHandle - ? 'reviewInfo' - : resultHandle - ? 'reviewResult' - : 'resourceMapping', - submissionId: submission.id, - }) - } else { - console.debug('[ReviewAggregation] Missing reviewer handle', { - resourceHandle: reviewerInfo?.memberHandle, + if (process.env.NODE_ENV !== 'production') { + if (resolvedReviewerHandle) { + console.debug('[ReviewAggregation] Resolved reviewer handle', { + resourceHandle: reviewerInfo?.memberHandle, + reviewerHandle: resolvedReviewerHandle, + reviewId, + reviewInfoHandle: reviewInfo?.reviewerHandle, + reviewResultHandle: resultHandle, + source: reviewHandle + ? 'reviewInfo' + : resultHandle + ? 'reviewResult' + : 'resourceMapping', + submissionId: submission.id, + }) + } else { + console.debug('[ReviewAggregation] Missing reviewer handle', { + resourceHandle: reviewerInfo?.memberHandle, + reviewerHandle: resolvedReviewerHandle, + reviewId, + reviewInfoHandle: reviewInfo?.reviewerHandle, + reviewResultHandle: resultHandle, + submissionId: submission.id, + }) + } + + console.debug('[ReviewAggregation] Processing review', { + finalScore, + resourceId, reviewerHandle: resolvedReviewerHandle, reviewId, - reviewInfoHandle: reviewInfo?.reviewerHandle, - reviewResultHandle: matchingReviewResult?.reviewerHandle, submissionId: submission.id, }) + + if (finalScore !== undefined) { + console.debug('[ReviewAggregation] Review score resolved', { + finalScore, + resourceId, + reviewId, + submissionId: submission.id, + }) + } else { + console.debug('[ReviewAggregation] Review score missing', { + resourceId, + reviewId, + submissionId: submission.id, + }) + } } - } - const appealInfo = reviewId ? mappingReviewAppeal[reviewId] : undefined - const finishedAppeals = appealInfo?.finishAppeals ?? 0 - const totalAppeals = appealInfo?.totalAppeals ?? 0 - const unresolvedAppeals = totalAppeals - finishedAppeals + const appealInfo = reviewId ? mappingReviewAppeal[reviewId] : undefined + const finishedAppeals = appealInfo?.finishAppeals ?? 0 + const totalAppeals = appealInfo?.totalAppeals ?? 0 + const unresolvedAppeals = totalAppeals - finishedAppeals - const existingDetail = group.reviews.find(detail => { - const detailReviewId = detail.reviewInfo?.id ?? detail.reviewId - return detailReviewId === reviewId - }) + const existingDetail = group.reviews.find(detail => { + const detailReviewId = detail.reviewInfo?.id ?? detail.reviewId + if (detailReviewId && reviewId) { + return detailReviewId === reviewId + } - const reviewerHandleForDetail = resolvedReviewerHandle ?? fallbackMappedHandle - - const newDetail: AggregatedReviewDetail = { - finalScore, - finishedAppeals: appealInfo?.finishAppeals, - resourceId, - reviewDate, - reviewDateString, - reviewerHandle: reviewerHandleForDetail, - reviewerHandleColor: finalReviewerHandleColor, - reviewerMaxRating: finalReviewerMaxRating, - reviewId, - reviewInfo: normalizedReviewInfo, - reviewProgress: normalizedReviewInfo?.reviewProgress, - status: normalizedReviewInfo?.status, - totalAppeals, - unresolvedAppeals, - } + if (!detailReviewId && !reviewId && resourceId) { + const detailResourceId = detail.resourceId ?? detail.reviewInfo?.resourceId + return detailResourceId === resourceId + } - if (existingDetail) { - if (finalScore !== undefined) { - existingDetail.finalScore = finalScore - } + return false + }) - if (appealInfo?.finishAppeals !== undefined) { - existingDetail.finishedAppeals = appealInfo.finishAppeals + const reviewerHandleForDetail = resolvedReviewerHandle ?? fallbackMappedHandle + const resolvedStatus = normalizedReviewInfo?.status + ?? ((finalScore !== undefined && reviewDate) + ? 'COMPLETED' + : undefined) + + const newDetail: AggregatedReviewDetail = { + finalScore, + finishedAppeals: appealInfo?.finishAppeals, + resourceId, + reviewDate, + reviewDateString, + reviewerHandle: reviewerHandleForDetail, + reviewerHandleColor: finalReviewerHandleColor, + reviewerMaxRating: finalReviewerMaxRating, + reviewId, + reviewInfo: normalizedReviewInfo, + reviewProgress: normalizedReviewInfo?.reviewProgress, + status: resolvedStatus, + totalAppeals, + unresolvedAppeals, } - if (reviewDate) { - existingDetail.reviewDate = reviewDate - } + if (existingDetail) { + if (finalScore !== undefined) { + existingDetail.finalScore = finalScore + } - if (reviewDateString) { - existingDetail.reviewDateString = reviewDateString - } + if (reviewId) { + existingDetail.reviewId = reviewId + } - if (reviewerHandleForDetail) { - existingDetail.reviewerHandle = reviewerHandleForDetail - if (resourceId && !reviewerHandleByResourceId[resourceId]) { - reviewerHandleByResourceId[resourceId] = reviewerHandleForDetail + if (appealInfo?.finishAppeals !== undefined) { + existingDetail.finishedAppeals = appealInfo.finishAppeals } - } - if (finalReviewerHandleColor) { - existingDetail.reviewerHandleColor = finalReviewerHandleColor - } + if (reviewDate) { + existingDetail.reviewDate = reviewDate + } - if (finalReviewerMaxRating !== undefined) { - existingDetail.reviewerMaxRating = finalReviewerMaxRating - } + if (reviewDateString) { + existingDetail.reviewDateString = reviewDateString + } - if (normalizedReviewInfo) { - existingDetail.reviewInfo = existingDetail.reviewInfo - ? { - ...existingDetail.reviewInfo, - ...normalizedReviewInfo, - reviewerHandle: normalizedReviewInfo.reviewerHandle - ?? existingDetail.reviewInfo.reviewerHandle, - reviewerHandleColor: normalizedReviewInfo.reviewerHandleColor - ?? existingDetail.reviewInfo.reviewerHandleColor, - reviewerMaxRating: normalizedReviewInfo.reviewerMaxRating - ?? existingDetail.reviewInfo.reviewerMaxRating, + if (reviewerHandleForDetail) { + existingDetail.reviewerHandle = reviewerHandleForDetail + if (resourceId && !reviewerHandleByResourceId[resourceId]) { + reviewerHandleByResourceId[resourceId] = reviewerHandleForDetail } - : normalizedReviewInfo - } + } + + if (finalReviewerHandleColor) { + existingDetail.reviewerHandleColor = finalReviewerHandleColor + } + + if (finalReviewerMaxRating !== undefined) { + existingDetail.reviewerMaxRating = finalReviewerMaxRating + } + + if (normalizedReviewInfo) { + existingDetail.reviewInfo = existingDetail.reviewInfo + ? { + ...existingDetail.reviewInfo, + ...normalizedReviewInfo, + reviewerHandle: normalizedReviewInfo.reviewerHandle + ?? existingDetail.reviewInfo.reviewerHandle, + reviewerHandleColor: normalizedReviewInfo.reviewerHandleColor + ?? existingDetail.reviewInfo.reviewerHandleColor, + reviewerMaxRating: normalizedReviewInfo.reviewerMaxRating + ?? existingDetail.reviewInfo.reviewerMaxRating, + } + : normalizedReviewInfo + } + + if (normalizedReviewInfo?.reviewProgress !== undefined) { + existingDetail.reviewProgress = normalizedReviewInfo.reviewProgress + } + + if (resolvedStatus !== undefined) { + existingDetail.status = resolvedStatus + } + + existingDetail.totalAppeals = totalAppeals + existingDetail.unresolvedAppeals = unresolvedAppeals - if (normalizedReviewInfo?.reviewProgress !== undefined) { - existingDetail.reviewProgress = normalizedReviewInfo.reviewProgress + if (reviewKey) { + seenReviewIds.add(reviewKey) + } + + seenReviewIdsBySubmission.set(submission.id, seenReviewIds) + return } - if (normalizedReviewInfo?.status !== undefined) { - existingDetail.status = normalizedReviewInfo.status + group.reviews.push(newDetail) + + if (reviewKey) { + seenReviewIds.add(reviewKey) } - existingDetail.totalAppeals = totalAppeals - existingDetail.unresolvedAppeals = unresolvedAppeals - seenReviewIds.add(reviewId) seenReviewIdsBySubmission.set(submission.id, seenReviewIds) - return - } - - group.reviews.push(newDetail) - seenReviewIds.add(reviewId) - seenReviewIdsBySubmission.set(submission.id, seenReviewIds) + }) }) const aggregatedRows: AggregatedSubmissionReviews[] = [] diff --git a/src/apps/review/src/pages/active-review-assignements/ChallengeDetailsPage/ChallengeDetailsPage.tsx b/src/apps/review/src/pages/active-review-assignements/ChallengeDetailsPage/ChallengeDetailsPage.tsx index 5b2d4eee3..25e0bc0b1 100644 --- a/src/apps/review/src/pages/active-review-assignements/ChallengeDetailsPage/ChallengeDetailsPage.tsx +++ b/src/apps/review/src/pages/active-review-assignements/ChallengeDetailsPage/ChallengeDetailsPage.tsx @@ -653,22 +653,17 @@ export const ChallengeDetailsPage: FC = (props: Props) => { useEffect(() => { if (!tabItems.length) return - const assignTab = (value: string | undefined): void => { - if (!value) return - setSelectedTab(value) - sessionStorage.setItem(TAB, value) - } + let nextTab: string | undefined const tab = searchParams.get('tab') if (tab) { const match = tabItems.find(item => kebabCase(item.value) === tab) if (match) { - assignTab(match.value) - return + nextTab = match.value } } - if (!isPastReviewDetail) { + if (!nextTab && !isPastReviewDetail) { const challengePhases = visibleChallengePhases if (challengePhases.length) { let openTabValue: string | undefined @@ -679,19 +674,26 @@ export const ChallengeDetailsPage: FC = (props: Props) => { } }) if (openTabValue) { - assignTab(openTabValue) - return + nextTab = openTabValue } } } - assignTab(tabItems[0]?.value) + if (!nextTab) { + nextTab = tabItems[0]?.value + } + + if (nextTab && nextTab !== selectedTab) { + setSelectedTab(nextTab) + sessionStorage.setItem(TAB, nextTab) + } }, [ searchParams, tabItems, visibleChallengePhases, phaseOrderingOptions, isPastReviewDetail, + selectedTab, ]) // eslint-disable-next-line complexity