Skip to content

Commit 6c928c5

Browse files
committed
Challenge review details page integration part 1
1 parent 0dfa6b0 commit 6c928c5

File tree

62 files changed

+29431
-20598
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+29431
-20598
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
node_modules
55
/.pnp
66
.pnp.js
7+
.yarn
78

89
# testing
910
/coverage

src/apps/admin/src/lib/hooks/useTableFilterLocal.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ export interface useTableFilterLocalProps<T> {
2222
* @param allDatas all table datas
2323
* @param defaultSort default sort
2424
* @param mappingSortField mapping from property field to sort field
25+
* @param disablePagination should disable pagination
2526
*/
2627
export function useTableFilterLocal<T>(
2728
allDatas: T[],
2829
defaultSort?: Sort,
2930
mappingSortField?: { [key: string]: string },
31+
disablePagination?: boolean,
3032
): useTableFilterLocalProps<T> {
3133
const [page, setPage] = useState(1)
3234
const [sort, setSort] = useState<Sort | undefined>(defaultSort)
@@ -66,6 +68,8 @@ export function useTableFilterLocal<T>(
6668
let datas = sortedDatas
6769
if (!datas.length) {
6870
setResults([])
71+
} else if (disablePagination) {
72+
setResults(datas)
6973
} else {
7074
const pageFrom0 = (page || 1) - 1
7175
const itemOffset

src/apps/review/src/config/routes.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export const rootRoute: string
1111
export const activeReviewAssigmentsRouteId = 'active-review-assigments'
1212
export const openOpportunitiesRouteId = 'open-opportunities'
1313
export const pastReviewAssignmentsRouteId = 'past-review-assignments'
14+
export const challengeDetailRouteId = ':challengeId'

src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
import { FC } from 'react'
55

6+
import { TableLoading } from '~/apps/admin/src/lib'
7+
68
import {
79
ProjectResult,
810
RegistrationInfo,
@@ -14,14 +16,15 @@ import { TableNoRecord } from '../TableNoRecord'
1416
import { TableSubmissionScreening } from '../TableSubmissionScreening'
1517
import { TableReviewAppeals } from '../TableReviewAppeals'
1618
import { TableWinners } from '../TableWinners'
17-
import { useRole } from '../../hooks'
19+
import { useRole, useRoleProps } from '../../hooks'
1820
import { APPROVAL, MOCKHANDLE, REVIEWER, SUBMITTER } from '../../../config/index.config'
1921
import { TableReviewAppealsForSubmitter } from '../TableReviewAppealsForSubmitter'
2022

2123
interface Props {
2224
selectedTab: string
2325
type?: string
2426
registrations: RegistrationInfo[]
27+
isLoadingRegistrants: boolean
2528
submissions: SubmissionInfo[]
2629
projectResults: ProjectResult[]
2730
screening: Screening[]
@@ -35,15 +38,30 @@ export const ChallengeDetailsContent: FC<Props> = (props: Props) => {
3538
const submissions = props.submissions
3639
const firstSubmissions = props.firstSubmissions
3740
const projectResults = props.projectResults
38-
const { role }: { role: string } = useRole()
41+
const { actionChallengeRole }: useRoleProps = useRole()
3942
const screening
40-
= role === REVIEWER
43+
= actionChallengeRole === REVIEWER
4144
? props.screening
4245
: props.screening.filter(s => s.handle === MOCKHANDLE)
4346

47+
// show ui for Registration tab
48+
if (selectedTab === 'Registration') {
49+
// show loading ui when fetching registrants
50+
if (props.isLoadingRegistrants) {
51+
return <TableLoading />
52+
}
53+
54+
// show no record message
55+
if (!registrations.length) {
56+
return <TableNoRecord />
57+
}
58+
59+
// show registrants table
60+
return <TableRegistration datas={registrations} />
61+
}
62+
4463
if (
45-
!registrations.length
46-
|| !submissions.length
64+
!submissions.length
4765
|| !projectResults.length
4866
|| !screening.length
4967
) {
@@ -52,13 +70,11 @@ export const ChallengeDetailsContent: FC<Props> = (props: Props) => {
5270

5371
return (
5472
<>
55-
{selectedTab === 'Registration' ? (
56-
<TableRegistration datas={registrations} />
57-
) : selectedTab === 'Submission / Screening' ? (
73+
{selectedTab === 'Submission / Screening' ? (
5874
<TableSubmissionScreening datas={screening} />
5975
) : selectedTab === 'Winners' ? (
6076
<TableWinners datas={projectResults} />
61-
) : (role !== SUBMITTER || selectedTab === APPROVAL) ? (
77+
) : (actionChallengeRole !== SUBMITTER || selectedTab === APPROVAL) ? (
6278
<TableReviewAppeals
6379
datas={submissions}
6480
tab={selectedTab}

src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.tsx

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
/**
22
* Challenge Links.
33
*/
4-
import { FC } from 'react'
5-
import { includes } from 'lodash'
4+
import { FC, useContext, useMemo, useState } from 'react'
65
import classNames from 'classnames'
76

8-
import { ADMIN, COPILOT } from '../../../config/index.config'
9-
import { useRole } from '../../hooks'
7+
import {
8+
REVIEWER,
9+
SUBMITTER,
10+
} from '../../../config/index.config'
11+
import { DialogContactManager } from '../DialogContactManager'
12+
import { ChallengeDetailContextModel } from '../../models'
13+
import { ChallengeDetailContext } from '../../contexts'
14+
import { filterResources } from '../../utils'
1015

1116
import styles from './ChallengeLinks.module.scss'
1217

@@ -15,15 +20,49 @@ interface Props {
1520
}
1621

1722
export const ChallengeLinks: FC<Props> = (props: Props) => {
18-
const { role }: {role: string} = useRole()
23+
const { challengeInfo, myResources }: ChallengeDetailContextModel
24+
= useContext(ChallengeDetailContext)
25+
// Show/hide contact manager dialog
26+
const [showContactManager, setShowContactManager] = useState(false)
27+
28+
// Show/hide contact manager button
29+
const canShowContactManagerButton = useMemo(
30+
() => filterResources([SUBMITTER, REVIEWER], myResources).length > 0,
31+
[myResources],
32+
)
33+
1934
return (
2035
<div className={classNames(styles.container, props.className)}>
21-
{!includes([ADMIN, COPILOT], role) && (
22-
<button type='button' className='borderButton'>
36+
{canShowContactManagerButton && (
37+
<button
38+
type='button'
39+
className='borderButton'
40+
onClick={function onClick() {
41+
setShowContactManager(true)
42+
}}
43+
>
2344
Contact Manager
2445
</button>
2546
)}
26-
<button type='button' className='borderButton'>Forum</button>
47+
{challengeInfo && challengeInfo.discussionsUrl && (
48+
<a
49+
href={challengeInfo?.discussionsUrl}
50+
className='borderButton'
51+
target='_blank'
52+
rel='noreferrer'
53+
>
54+
Forum
55+
</a>
56+
)}
57+
58+
{showContactManager && (
59+
<DialogContactManager
60+
open
61+
setOpen={function setOpen(open: boolean) {
62+
setShowContactManager(open)
63+
}}
64+
/>
65+
)}
2766
</div>
2867
)
2968
}

src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.module.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,20 @@
6363
padding-top: 7px;
6464
}
6565
}
66+
67+
.blockMyRoles {
68+
display: flex;
69+
flex-direction: column;
70+
gap: 0;
71+
}
72+
73+
.textInfo {
74+
span {
75+
align-items: center;
76+
color: var(--FontColor);
77+
font-family: "Nunito Sans", sans-serif;
78+
display: flex;
79+
font-weight: 700;
80+
line-height: 20px;
81+
}
82+
}

src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import classNames from 'classnames'
66

77
import { ChallengeInfo } from '../../models'
88
import { ProgressBar } from '../ProgressBar'
9+
import { useRole, useRoleProps } from '../../hooks'
910

1011
import styles from './ChallengePhaseInfo.module.scss'
1112

@@ -15,24 +16,31 @@ interface Props {
1516
}
1617

1718
export const ChallengePhaseInfo: FC<Props> = (props: Props) => {
19+
const { myChallengeRoles }: useRoleProps = useRole()
1820
const PROGRESS_TYPE = 'progress'
1921
const uiItems = useMemo(() => {
2022
const data = props.challengeInfo
2123
return [
2224
{
2325
icon: 'icon-review',
2426
title: 'Phase',
25-
value: data.currentPhase,
27+
value: data.currentPhase || 'N/A',
2628
},
2729
{
2830
icon: 'icon-handle',
2931
title: 'My Role',
30-
value: data.role,
32+
value: (
33+
<div className={styles.blockMyRoles}>
34+
{myChallengeRoles.map(item => (
35+
<span key={item}>{item}</span>
36+
))}
37+
</div>
38+
),
3139
},
3240
{
3341
icon: 'icon-event',
3442
title: 'Phase End Date',
35-
value: data.currentPhaseEndDateString,
43+
value: data.currentPhaseEndDateString || 'N/A',
3644
},
3745
{
3846
icon: 'icon-timer',
@@ -41,15 +49,15 @@ export const ChallengePhaseInfo: FC<Props> = (props: Props) => {
4149
color: data.timeLeftColor,
4250
},
4351
title: 'Time Left',
44-
value: data.timeLeft,
52+
value: data.timeLeft || 'N/A',
4553
},
4654
{
4755
title: 'Review Progress',
4856
type: PROGRESS_TYPE,
4957
value: data.reviewProgress,
5058
},
5159
]
52-
}, [props.challengeInfo])
60+
}, [props.challengeInfo, myChallengeRoles])
5361
return (
5462
<div className={classNames(styles.container, props.className)}>
5563
{uiItems.map(item => {
@@ -85,8 +93,13 @@ export const ChallengePhaseInfo: FC<Props> = (props: Props) => {
8593
</span>
8694
<div>
8795
<span>{item.title}</span>
88-
<strong style={item.style}>
89-
{item.status && <i className={`icon-${item.status}`} />}
96+
<strong
97+
style={item.style}
98+
className={styles.textInfo}
99+
>
100+
{item.status && (
101+
<i className={`icon-${item.status}`} />
102+
)}
90103
{item.value}
91104
</strong>
92105
</div>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.modal {
2+
max-width: 800px !important;
3+
}
4+
5+
.container {
6+
display: flex;
7+
flex-direction: column;
8+
gap: 20px;
9+
position: relative;
10+
11+
textarea {
12+
resize: none !important;
13+
}
14+
}
15+
16+
.actionButtons {
17+
display: flex;
18+
justify-content: flex-end;
19+
gap: 6px;
20+
}
21+
22+
.dialogLoadingSpinnerContainer {
23+
position: absolute;
24+
width: 64px;
25+
display: flex;
26+
align-items: center;
27+
justify-content: center;
28+
bottom: 0;
29+
height: 64px;
30+
left: 0;
31+
32+
.spinner {
33+
background: none;
34+
}
35+
}

0 commit comments

Comments
 (0)