Skip to content

Commit babe900

Browse files
Merge pull request #454 from topcoder-platform/TCA-853_dice-modal
TCA-852 DICE Setup Required Modal -> TCA-851_wipro-mfa
2 parents c0f4b7b + d08943d commit babe900

File tree

11 files changed

+112
-21
lines changed

11 files changed

+112
-21
lines changed

src-ts/.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ module.exports = {
251251
2,
252252
4,
253253
],
254+
'react/jsx-no-bind': [
255+
'error',
256+
{
257+
allowFunctions: true,
258+
}
259+
],
254260
'react/jsx-no-useless-fragment': [
255261
0
256262
],

src-ts/config/environments/environment.default.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export const EnvironmentConfigDefault: EnvironmentConfigModel = {
3636
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzMiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.jl6Lp_friVNwEP8nfsfmL-vrQFzOFp2IfM_HC7AwGcg',
3737
},
3838
TOPCODER_URLS: {
39+
ACCOUNT_SETTINGS: `${COMMUNITY_WEBSITE}/settings/account`,
3940
API_BASE: `${COMMUNITY_WEBSITE}/api`,
4041
BLOG_PAGE: `${COMMUNITY_WEBSITE}/blog`,
4142
CHALLENGES_PAGE: `${COMMUNITY_WEBSITE}/challenges`,

src-ts/config/environments/environment.prod.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const EnvironmentConfigProd: EnvironmentConfigModel = {
3434
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJ0ZXN0MSIsImV4cCI6MjU2MzA3NjY4OSwidXNlcklkIjoiNDAwNTEzMzMiLCJpYXQiOjE0NjMwNzYwODksImVtYWlsIjoidGVzdEB0b3Bjb2Rlci5jb20iLCJqdGkiOiJiMzNiNzdjZC1iNTJlLTQwZmUtODM3ZS1iZWI4ZTBhZTZhNGEifQ.jl6Lp_friVNwEP8nfsfmL-vrQFzOFp2IfM_HC7AwGcg',
3535
},
3636
TOPCODER_URLS: {
37+
ACCOUNT_SETTINGS: `${COMMUNITY_WEBSITE}/settings/account`,
3738
API_BASE: `${COMMUNITY_WEBSITE}/api`,
3839
BLOG_PAGE: `${COMMUNITY_WEBSITE}/blog`,
3940
CHALLENGES_PAGE: `${COMMUNITY_WEBSITE}/challenges`,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export {
2-
getDiceStatusAsync as userStoreGetDiceStatusAsync,
2+
getMfaStatusAsync as userStoreGetMfaStatusAsync,
33
patchAsync as userStorePatchAsync,
44
} from './user-xhr.store'
55
export { type UserPatchRequest } from './user-xhr.store'

src-ts/lib/functions/user-functions/user-store/user-xhr.store.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ import { xhrGetAsync, xhrPatchAsync } from '../../xhr-functions'
33

44
import { user as userEndpoint } from './user-endpoint.config'
55

6+
export interface MfaStatusResult {
7+
result: {
8+
content: {
9+
diceEnabled: boolean
10+
mfaEnabled: boolean
11+
}
12+
}
13+
}
14+
615
export interface UserPatchRequest {
716
param: {
817
credential: {
@@ -12,19 +21,8 @@ export interface UserPatchRequest {
1221
}
1322
}
1423

15-
export async function getDiceStatusAsync(userId: number): Promise<boolean> {
16-
17-
interface DiceStatusResult {
18-
result: {
19-
content: {
20-
diceEnabled: boolean
21-
}
22-
}
23-
}
24-
const result: DiceStatusResult
25-
= await xhrGetAsync<DiceStatusResult>(`${userEndpoint(userId)}/2fa`)
26-
27-
return !!result.result.content.diceEnabled
24+
export async function getMfaStatusAsync(userId: number): Promise<MfaStatusResult> {
25+
return xhrGetAsync<MfaStatusResult>(`${userEndpoint(userId)}/2fa`)
2826
}
2927

3028
export async function patchAsync(userId: number, request: UserPatchRequest): Promise<User> {

src-ts/lib/functions/user-functions/user.functions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { UserPatchRequest, userStoreGetDiceStatusAsync, userStorePatchAsync } from './user-store'
1+
import { UserPatchRequest, userStoreGetMfaStatusAsync, userStorePatchAsync } from './user-store'
2+
import { MfaStatusResult } from './user-store/user-xhr.store'
23

34
export async function getDiceStatusAsync(userId: number): Promise<boolean> {
4-
return userStoreGetDiceStatusAsync(userId)
5+
const result: MfaStatusResult = await userStoreGetMfaStatusAsync(userId)
6+
return !!result.result.content.mfaEnabled && !!result.result.content.diceEnabled
57
}
68

79
export async function updatePasswordAsync(userId: number, currentPassword: string, password: string): Promise<void> {

src-ts/lib/global-config.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface GlobalConfig {
2929
CUSTOMER_TOKEN: string
3030
}
3131
TOPCODER_URLS: {
32+
ACCOUNT_SETTINGS: string
3233
API_BASE: string
3334
BLOG_PAGE: string
3435
CHALLENGES_PAGE: string

src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424

2525
import { CurriculumSummary } from './curriculum-summary'
2626
import { TcAcademyPolicyModal } from './tc-academy-policy-modal'
27+
import { DiceModal } from './dice-modal'
2728
import styles from './CourseCurriculum.module.scss'
2829

2930
interface CourseCurriculumProps {
@@ -43,6 +44,8 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
4344

4445
const [isTcAcademyPolicyModal, setIsTcAcademyPolicyModal]: [boolean, Dispatch<SetStateAction<boolean>>]
4546
= useState<boolean>(false)
47+
const [isDiceModalOpen, setIsDiceModalOpen]: [boolean, Dispatch<SetStateAction<boolean>>]
48+
= useState<boolean>(false)
4649

4750
const status: string = props.progress?.status ?? UserCertificationProgressStatus.inititialized
4851
const completedPercentage: number = (props.progress?.courseProgressPercentage ?? 0) / 100
@@ -89,8 +92,7 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
8992
// if the user is wipro and s/he hasn't set up DICE,
9093
// let the user know
9194
if (props.profile?.isWipro && !props.profile.diceEnabled) {
92-
// TODO
93-
console.debug('TODO: user needs dice')
95+
setIsDiceModalOpen(true)
9496
return
9597
}
9698

@@ -102,7 +104,7 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
102104

103105
// show the academic policy modal before starting a new course
104106
setIsTcAcademyPolicyModal(true)
105-
// eslint-disable-next-line react-hooks/exhaustive-deps
107+
// eslint-disable-next-line react-hooks/exhaustive-deps
106108
}, [
107109
handleStartCourse,
108110
isLoggedIn,
@@ -141,7 +143,7 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
141143
}
142144

143145
handleStartCourse()
144-
// eslint-disable-next-line react-hooks/exhaustive-deps
146+
// eslint-disable-next-line react-hooks/exhaustive-deps
145147
}, [
146148
handleStartCourse,
147149
props.course.certificationId,
@@ -167,6 +169,14 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
167169
}
168170
}, [handleStartCourseClick, isLoggedIn, props.progressReady, searchParams])
169171

172+
function onAcademicHonestyModalClose(): void {
173+
setIsTcAcademyPolicyModal(false)
174+
}
175+
176+
function onDiceModalClose(): void {
177+
setIsDiceModalOpen(false)
178+
}
179+
170180
return (
171181
<>
172182
<div className={styles.wrap}>
@@ -211,9 +221,14 @@ const CourseCurriculum: FC<CourseCurriculumProps> = (props: CourseCurriculumProp
211221

212222
<TcAcademyPolicyModal
213223
isOpen={isTcAcademyPolicyModal}
214-
onClose={() => setIsTcAcademyPolicyModal(false)}
224+
onClose={onAcademicHonestyModalClose}
215225
onConfirm={handlePolicyAccept}
216226
/>
227+
228+
<DiceModal
229+
isOpen={isDiceModalOpen}
230+
onClose={onDiceModalClose}
231+
/>
217232
</>
218233
)
219234
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@import '../../../../../lib/styles/includes';
2+
3+
.diceModal {
4+
5+
p {
6+
margin-bottom: $space-lg;
7+
8+
&.buttonContainer {
9+
display: flex;
10+
justify-content: center;
11+
}
12+
}
13+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react'
2+
3+
import { EnvironmentConfig } from '../../../../../config'
4+
import { BaseModal, Button } from '../../../../../lib'
5+
6+
import styles from './DiceModal.module.scss'
7+
8+
interface DiceModalProps {
9+
isOpen: boolean
10+
onClose: () => void
11+
}
12+
13+
const DiceModal: FC<DiceModalProps> = (props: DiceModalProps) => {
14+
15+
const [isOpen, setIsOpen]: [boolean, Dispatch<SetStateAction<boolean>>]
16+
= useState<boolean>(false)
17+
18+
useEffect(() => {
19+
setIsOpen(props.isOpen)
20+
}, [props.isOpen])
21+
22+
return (
23+
<BaseModal
24+
onClose={props.onClose}
25+
open={isOpen}
26+
size='md'
27+
title='DICE ID Multifactor Authentication Required'
28+
>
29+
<div className={styles.diceModal}>
30+
31+
<p>
32+
Wipro requires employees to enable Multifactor Authentication
33+
with DICE ID in order to take Topcoder Academy courses.
34+
</p>
35+
<p>
36+
Please go to Account Settings to configure your account.
37+
</p>
38+
<p className={styles.buttonContainer}>
39+
<Button
40+
buttonStyle='primary'
41+
label='Account Settings'
42+
onClick={props.onClose}
43+
target='_blank'
44+
url={EnvironmentConfig.TOPCODER_URLS.ACCOUNT_SETTINGS}
45+
/>
46+
</p>
47+
</div>
48+
49+
</BaseModal>
50+
)
51+
}
52+
53+
export default DiceModal
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as DiceModal } from './DiceModal'

0 commit comments

Comments
 (0)