Skip to content

Commit 12cca79

Browse files
authored
Merge pull request #1319 from topcoder-platform/scorecard-review-header
Scorecard review header
2 parents 94d9f86 + 0f87d34 commit 12cca79

File tree

6 files changed

+298
-25
lines changed

6 files changed

+298
-25
lines changed

src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardViewer.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ const ScorecardViewerContent: FC<ScorecardViewerProps> = props => {
9696
const {
9797
form,
9898
totalScore,
99+
reviewProgress,
99100
isTouched,
100101
touchedAllFields,
101102
formErrors,
@@ -162,11 +163,12 @@ const ScorecardViewerContent: FC<ScorecardViewerProps> = props => {
162163
}
163164

164165
props.setReviewStatus({
166+
progress: reviewProgress,
165167
score,
166168
status,
167169
})
168170
}
169-
}, [totalScore, props.scorecard])
171+
}, [totalScore, reviewProgress, props.scorecard])
170172

171173
const actionButtons = useMemo(() => (
172174
<div className={styles.actions}>

src/apps/review/src/lib/models/ReviewsContext.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { BackendSubmission } from './BackendSubmission.model'
99
export interface ReviewCtxStatus {
1010
status: 'passed' | 'pending' | 'failed-score';
1111
score: number;
12+
progress: number;
1213
}
1314

1415
export interface ReviewsContextModel extends ChallengeDetailContextModel {
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.wrap {
4+
width: 100%;
5+
margin-bottom: $sp-6;
6+
}
7+
8+
.title {
9+
font-family: "Figtree", sans-serif;
10+
font-size: 26px;
11+
font-weight: 700;
12+
line-height: 30px;
13+
color: #0A0A0A;
14+
}
15+
16+
.content {
17+
display: flex;
18+
align-items: flex-start;
19+
justify-content: space-between;
20+
gap: $sp-6;
21+
22+
@include ltemd {
23+
flex-direction: column;
24+
gap: $sp-6;
25+
}
26+
}
27+
28+
.leftSection {
29+
display: flex;
30+
align-items: flex-start;
31+
gap: $sp-4;
32+
flex: 1;
33+
}
34+
35+
.iconWrapper {
36+
flex: 0 0 auto;
37+
}
38+
39+
.scorecardIcon {
40+
width: 60px;
41+
height: 60px;
42+
border-radius: 4px;
43+
display: flex;
44+
align-items: center;
45+
justify-content: center;
46+
border: 1px solid #A8A8A8;
47+
}
48+
49+
.aiReviewIcon {
50+
width: 40px;
51+
height: 40px;
52+
}
53+
54+
.infoSection {
55+
display: flex;
56+
flex-direction: column;
57+
gap: $sp-3;
58+
flex: 1;
59+
margin-top: $sp-2;
60+
}
61+
62+
.infoRow {
63+
display: flex;
64+
align-items: center;
65+
gap: $sp-2;
66+
font-family: "Nunito Sans", sans-serif;
67+
font-size: 14px;
68+
line-height: 19px;
69+
font-weight: bold;
70+
color: #0A0A0A;
71+
}
72+
73+
.personIcon {
74+
display: flex;
75+
align-items: center;
76+
flex: 0 0 auto;
77+
width: 20px;
78+
height: 20px;
79+
padding: 2px;
80+
81+
> * {
82+
width: 16px;
83+
height: 16px;
84+
}
85+
}
86+
87+
.whaleIcon {
88+
display: flex;
89+
align-items: center;
90+
flex: 0 0 auto;
91+
width: 16px;
92+
height: 16px;
93+
94+
svg {
95+
width: 16px;
96+
height: 16px;
97+
}
98+
}
99+
100+
.rightSection {
101+
display: flex;
102+
flex-direction: column;
103+
gap: $sp-1;
104+
flex: 0 0 auto;
105+
min-width: 200px;
106+
107+
@include ltemd {
108+
width: 100%;
109+
min-width: auto;
110+
}
111+
}
112+
113+
.scoreInfo {
114+
display: flex;
115+
align-items: center;
116+
gap: $sp-2;
117+
font-family: "Nunito Sans", sans-serif;
118+
font-size: 14px;
119+
line-height: 19px;
120+
font-weight: bold;
121+
color: #0A0A0A;
122+
}
123+
124+
.trophyIcon {
125+
flex: 0 0 auto;
126+
width: 16px;
127+
height: 16px;
128+
129+
path {
130+
fill: #0A0A0A;
131+
}
132+
}
133+
134+
.scoreValue {
135+
font-weight: 400;
136+
}
137+
138+
.progressSection {
139+
display: flex;
140+
align-items: center;
141+
gap: $sp-2;
142+
width: 100%;
143+
144+
:global(.container) {
145+
flex: 1;
146+
}
147+
}
148+
149+
.progressText {
150+
font-family: "Nunito Sans", sans-serif;
151+
font-size: 14px;
152+
font-weight: 400;
153+
color: #0A0A0A;
154+
white-space: nowrap;
155+
flex: 0 0 auto;
156+
}
157+
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { FC, useMemo } from 'react'
2+
3+
import { useChallengeDetailsContext } from '~/apps/review/src/lib'
4+
import { ProgressBar } from '~/apps/review/src/lib/components/ProgressBar'
5+
import { IconDeepseekAi, IconPhaseReview, IconPremium } from '~/apps/review/src/lib/assets/icons'
6+
import { ChallengeDetailContextModel, ReviewInfo, ScorecardInfo } from '~/apps/review/src/lib/models'
7+
import { AiWorkflow } from '~/apps/review/src/lib/hooks'
8+
9+
import styles from './ReviewScorecardHeader.module.scss'
10+
11+
interface Props {
12+
reviewInfo?: ReviewInfo
13+
scorecardInfo?: ScorecardInfo
14+
workflow?: AiWorkflow
15+
reviewProgress?: number
16+
}
17+
18+
export const ReviewScorecardHeader: FC<Props> = (props: Props) => {
19+
const {
20+
resources,
21+
}: ChallengeDetailContextModel = useChallengeDetailsContext()
22+
23+
const reviewer = useMemo(() => {
24+
if (!props.reviewInfo?.resourceId) {
25+
return undefined
26+
}
27+
28+
return resources.find(r => r.id === props.reviewInfo?.resourceId)
29+
}, [props.reviewInfo?.resourceId, resources])
30+
31+
const reviewerHandle = reviewer?.memberHandle
32+
const reviewerColor = reviewer?.handleColor
33+
const llmModelName = props.workflow?.llm?.name || 'N/A'
34+
const minimumPassingScore = props.scorecardInfo?.minimumPassingScore ?? 0
35+
36+
return (
37+
<div className={styles.wrap}>
38+
<div className={styles.content}>
39+
<div className={styles.leftSection}>
40+
<div className={styles.iconWrapper}>
41+
<div className={styles.scorecardIcon}>
42+
<IconPhaseReview className={styles.aiReviewIcon} />
43+
</div>
44+
</div>
45+
<div className={styles.details}>
46+
<h2 className={styles.title}>Edit Review Scorecard</h2>
47+
<div className={styles.infoSection}>
48+
{reviewerHandle && (
49+
<div className={styles.infoRow}>
50+
<div className={styles.personIcon}>
51+
<i className='icon-handle' />
52+
</div>
53+
<span className={styles.infoLabel}>Reviewer:</span>
54+
<span className={styles.infoValue} style={{ color: reviewerColor }}>
55+
{reviewerHandle}
56+
</span>
57+
</div>
58+
)}
59+
{props.workflow?.llm && (
60+
<div className={styles.infoRow}>
61+
<div className={styles.whaleIcon}>
62+
<IconDeepseekAi />
63+
</div>
64+
<span className={styles.infoLabel}>LLM/AI Model:</span>
65+
<span className={styles.infoValue} style={{ color: '#0D61BF' }}>
66+
{llmModelName}
67+
</span>
68+
</div>
69+
)}
70+
</div>
71+
</div>
72+
</div>
73+
<div className={styles.rightSection}>
74+
<div className={styles.scoreInfo}>
75+
<IconPremium className={styles.trophyIcon} />
76+
<span className={styles.scoreLabel}>Minimum passing score:</span>
77+
<span className={styles.scoreValue}>
78+
{minimumPassingScore.toFixed(2)}
79+
</span>
80+
</div>
81+
<div className={styles.progressSection}>
82+
<ProgressBar progress={props.reviewProgress} progressWidth='100%' withoutPercentage />
83+
<span className={styles.progressText}>
84+
{props.reviewProgress}
85+
%
86+
</span>
87+
</div>
88+
</div>
89+
</div>
90+
</div>
91+
)
92+
}
93+
94+
export default ReviewScorecardHeader

src/apps/review/src/pages/reviews/components/ReviewViewer/ReviewViewer.module.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333

3434
.summary {
3535
margin-bottom: $sp-6;
36+
> * {
37+
padding-top: 0;
38+
justify-content: flex-end;
39+
}
3640
}
3741

3842
.lockedNotice {

src/apps/review/src/pages/reviews/components/ReviewViewer/ReviewViewer.tsx

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,18 @@ import { rootRoute } from '~/apps/review/src/config/routes.config'
1818
import { ADMIN, COPILOT, MANAGER } from '../../../../config/index.config'
1919
import { useReviewsContext } from '../../ReviewsContext'
2020

21+
import { ReviewScorecardHeader } from './ReviewScorecardHeader'
2122
import styles from './ReviewViewer.module.scss'
2223

2324
const ReviewViewer: FC = () => {
2425
const navigate = useAppNavigate()
25-
const { reviewId, setReviewStatus, setActionButtons }: ReviewsContextModel = useReviewsContext()
26+
const {
27+
reviewId,
28+
setReviewStatus,
29+
setActionButtons,
30+
workflow,
31+
reviewStatus,
32+
}: ReviewsContextModel = useReviewsContext()
2633

2734
const {
2835
actionChallengeRole,
@@ -234,29 +241,37 @@ const ReviewViewer: FC = () => {
234241
</div>
235242
)}
236243
{!isSubmitterPhaseLocked && (
237-
<ScorecardViewer
238-
actionChallengeRole={actionChallengeRole}
239-
scorecard={scorecardInfo as any}
240-
reviewInfo={reviewInfo}
241-
mappingAppeals={mappingAppeals}
242-
isEdit={isEdit}
243-
onCancelEdit={onCancelEdit}
244-
navigateBack={back}
245-
setIsChanged={setIsChanged}
246-
isLoading={isLoading}
247-
isManagerEdit={isManagerEdit}
248-
isSavingReview={isSavingReview}
249-
isSavingAppeal={isSavingAppeal}
250-
isSavingAppealResponse={isSavingAppealResponse}
251-
isSavingManagerComment={isSavingManagerComment}
252-
saveReviewInfo={saveReviewInfo}
253-
addAppeal={addAppeal}
254-
addAppealResponse={addAppealResponse}
255-
doDeleteAppeal={doDeleteAppeal}
256-
addManagerComment={addManagerComment}
257-
setReviewStatus={setReviewStatus}
258-
setActionButtons={setActionButtons}
259-
/>
244+
<>
245+
<ReviewScorecardHeader
246+
reviewInfo={reviewInfo}
247+
scorecardInfo={scorecardInfo}
248+
workflow={workflow}
249+
reviewProgress={reviewStatus?.progress ?? reviewInfo?.reviewProgress ?? 0}
250+
/>
251+
<ScorecardViewer
252+
actionChallengeRole={actionChallengeRole}
253+
scorecard={scorecardInfo as any}
254+
reviewInfo={reviewInfo}
255+
mappingAppeals={mappingAppeals}
256+
isEdit={isEdit}
257+
onCancelEdit={onCancelEdit}
258+
navigateBack={back}
259+
setIsChanged={setIsChanged}
260+
isLoading={isLoading}
261+
isManagerEdit={isManagerEdit}
262+
isSavingReview={isSavingReview}
263+
isSavingAppeal={isSavingAppeal}
264+
isSavingAppealResponse={isSavingAppealResponse}
265+
isSavingManagerComment={isSavingManagerComment}
266+
saveReviewInfo={saveReviewInfo}
267+
addAppeal={addAppeal}
268+
addAppealResponse={addAppealResponse}
269+
doDeleteAppeal={doDeleteAppeal}
270+
addManagerComment={addManagerComment}
271+
setReviewStatus={setReviewStatus}
272+
setActionButtons={setActionButtons}
273+
/>
274+
</>
260275
)}
261276
</div>
262277
{isEdit && (

0 commit comments

Comments
 (0)