@@ -14,13 +14,19 @@ import { Link } from 'react-router-dom'
1414import _ from 'lodash'
1515import classNames from 'classnames'
1616
17+ import { UserRole } from '~/libs/core'
1718import { TableMobile } from '~/apps/admin/src/lib/components/common/TableMobile'
1819import { IsRemovingType } from '~/apps/admin/src/lib/models'
1920import { MobileTableColumn } from '~/apps/admin/src/lib/models/MobileTableColumn.model'
2021import { copyTextToClipboard , useWindowSize , WindowSize } from '~/libs/shared'
2122import { IconOutline , Table , TableColumn , Tooltip } from '~/libs/ui'
2223
23- import { ChallengeDetailContextModel , Screening , SubmissionInfo } from '../../models'
24+ import {
25+ ChallengeDetailContextModel ,
26+ ReviewAppContextModel ,
27+ Screening ,
28+ SubmissionInfo ,
29+ } from '../../models'
2430import { TableWrapper } from '../TableWrapper'
2531import { SubmissionHistoryModal } from '../SubmissionHistoryModal'
2632import {
@@ -30,12 +36,14 @@ import {
3036 partitionSubmissionHistory ,
3137 SubmissionHistoryPartition ,
3238} from '../../utils'
33- import { ChallengeDetailContext } from '../../contexts'
39+ import { ChallengeDetailContext , ReviewAppContext } from '../../contexts'
3440import { useSubmissionDownloadAccess } from '../../hooks'
3541import type { UseSubmissionDownloadAccessResult } from '../../hooks/useSubmissionDownloadAccess'
3642
3743import styles from './TableSubmissionScreening.module.scss'
3844
45+ const VIEW_OWN_SCORECARD_TOOLTIP = 'You can only view scorecards for your own submissions.'
46+
3947interface Props {
4048 className ?: string
4149 screenings : Screening [ ]
@@ -60,6 +68,11 @@ interface BaseColumnsConfig {
6068 virusScanColumn : TableColumn < Screening >
6169}
6270
71+ interface ScreeningColumnConfig {
72+ canViewAllScorecards : boolean
73+ currentMemberId ?: string
74+ }
75+
6376interface ActionRenderer {
6477 key : string
6578 render : ( isLast : boolean ) => JSX . Element
@@ -216,11 +229,14 @@ const createBaseColumns = ({
216229 virusScanColumn ,
217230]
218231
219- const createScreeningColumns = ( ) : TableColumn < Screening > [ ] => [
232+ const createScreeningColumns = ( {
233+ canViewAllScorecards,
234+ currentMemberId,
235+ } : ScreeningColumnConfig ) : TableColumn < Screening > [ ] => [
220236 {
221237 label : 'Screener' ,
222238 propertyName : 'screenerHandle' ,
223- renderer : ( data : Screening ) => ( data . screener ?. id ? (
239+ renderer : ( data : Screening ) => ( data . screener ?. memberHandle ? (
224240 < a
225241 href = { getHandleUrl ( data . screener ) }
226242 target = '_blank'
@@ -251,7 +267,36 @@ const createScreeningColumns = (): TableColumn<Screening>[] => [
251267 {
252268 label : 'Screening Score' ,
253269 propertyName : 'score' ,
254- type : 'text' ,
270+ renderer : ( data : Screening ) => {
271+ const scoreValue = data . score ?? '-'
272+
273+ if ( ! data . reviewId ) {
274+ return < span > { scoreValue } </ span >
275+ }
276+
277+ const canViewScorecard = canViewAllScorecards
278+ || Boolean ( data . memberId && data . memberId === currentMemberId )
279+
280+ if ( ! canViewScorecard ) {
281+ return (
282+ < Tooltip content = { VIEW_OWN_SCORECARD_TOOLTIP } triggerOn = 'click-hover' >
283+ < span className = { styles . tooltipTrigger } >
284+ < span className = { styles . textBlue } > { scoreValue } </ span >
285+ </ span >
286+ </ Tooltip >
287+ )
288+ }
289+
290+ return (
291+ < Link
292+ to = { `./../review/${ data . reviewId } ` }
293+ className = { styles . textBlue }
294+ >
295+ { scoreValue }
296+ </ Link >
297+ )
298+ } ,
299+ type : 'element' ,
255300 } ,
256301 {
257302 label : 'Screening Result' ,
@@ -397,14 +442,39 @@ const normalizeCreatedAt = (
397442export const TableSubmissionScreening : FC < Props > = ( props : Props ) => {
398443 const { width : screenWidth } : WindowSize = useWindowSize ( )
399444 const isTablet = useMemo ( ( ) => screenWidth <= 984 , [ screenWidth ] )
400- const { challengeInfo } : ChallengeDetailContextModel = useContext (
445+ const { challengeInfo, myRoles } : ChallengeDetailContextModel = useContext (
401446 ChallengeDetailContext ,
402447 )
448+ const { loginUserInfo } : ReviewAppContextModel = useContext ( ReviewAppContext )
403449 const {
404450 restrictionMessage,
405451 isSubmissionDownloadRestrictedForMember,
406452 getRestrictionMessageForMember,
453+ currentMemberId,
407454 } : UseSubmissionDownloadAccessResult = useSubmissionDownloadAccess ( )
455+
456+ const normalisedRoles = useMemo (
457+ ( ) => ( myRoles ?? [ ] ) . map ( role => role . toLowerCase ( ) ) ,
458+ [ myRoles ] ,
459+ )
460+
461+ const hasCopilotRole = useMemo (
462+ ( ) => normalisedRoles . some ( role => role . includes ( 'copilot' ) ) ,
463+ [ normalisedRoles ] ,
464+ )
465+
466+ const isAdminUser = useMemo (
467+ ( ) => loginUserInfo ?. roles ?. some (
468+ role => typeof role === 'string'
469+ && role . toLowerCase ( ) === UserRole . administrator ,
470+ ) ?? false ,
471+ [ loginUserInfo ?. roles ] ,
472+ )
473+
474+ const canViewAllScorecards = useMemo (
475+ ( ) => isAdminUser || hasCopilotRole ,
476+ [ isAdminUser , hasCopilotRole ] ,
477+ )
408478 const showScreeningColumns = props . showScreeningColumns ?? true
409479 const submissionTypes = useMemo (
410480 ( ) => new Set (
@@ -608,7 +678,13 @@ export const TableSubmissionScreening: FC<Props> = (props: Props) => {
608678 [ handleColumn , submissionColumn , submissionDateColumn , virusScanColumn ] ,
609679 )
610680
611- const screeningColumns = useMemo < TableColumn < Screening > [ ] > ( createScreeningColumns , [ ] )
681+ const screeningColumns = useMemo < TableColumn < Screening > [ ] > (
682+ ( ) => createScreeningColumns ( {
683+ canViewAllScorecards,
684+ currentMemberId,
685+ } ) ,
686+ [ canViewAllScorecards , currentMemberId ] ,
687+ )
612688
613689 const actionColumn = useMemo (
614690 ( ) => createActionColumn ( {
0 commit comments