Skip to content

Commit ad1642b

Browse files
committed
MP-38 account roles in settings
1 parent 7b11843 commit ad1642b

File tree

10 files changed

+203
-14
lines changed

10 files changed

+203
-14
lines changed

src/apps/accounts/src/settings/tabs/AccountSettingsTabs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const AccountSettingsTabs: FC<AccountSettingsTabsProps> = (props: AccountSetting
2828
/>
2929

3030
{activeTab === AccountSettingsTabViews.account && (
31-
<AccountTab />
31+
<AccountTab profile={props.profile} />
3232
)}
3333
</div>
3434
)

src/apps/accounts/src/settings/tabs/account/AccountTab.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { FC } from 'react'
22

3+
import { UserProfile } from '~/libs/core'
4+
35
import { AccountRole } from './account-role'
46
import styles from './AccountTab.module.scss'
57

6-
const AccountTab: FC<{}> = () => (
8+
interface AccountTabProps {
9+
profile: UserProfile
10+
}
11+
12+
const AccountTab: FC<AccountTabProps> = (props: AccountTabProps) => (
713
<div className={styles.container}>
814
<h3>ACCOUNT INFORMATION & SECURITY</h3>
915

10-
<AccountRole />
16+
<AccountRole profile={props.profile} />
1117
</div>
1218
)
1319

src/apps/accounts/src/settings/tabs/account/account-role/AccountRole.module.scss

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,60 @@
22

33
.container {
44
margin: $sp-8 0;
5+
6+
.content {
7+
display: grid;
8+
grid-template-columns: repeat(2, 1fr);
9+
margin-bottom: 0;
10+
11+
@include ltelg {
12+
grid-template-columns: 1fr;
13+
}
14+
15+
> p {
16+
max-width: 380px;
17+
}
18+
19+
form {
20+
display: flex;
21+
justify-self: flex-end;
22+
23+
@include ltelg {
24+
flex-direction: column;
25+
justify-self: auto;
26+
margin-top: $sp-4;
27+
}
28+
29+
.formControlWrap {
30+
border: 1px solid $black-20;
31+
border-radius: 8px;
32+
padding: $sp-6 $sp-4;
33+
min-width: 286px;
34+
display: flex;
35+
justify-content: space-between;
36+
margin-right: $sp-8;
37+
38+
@include ltelg {
39+
margin-right: 0;
40+
margin-bottom: $sp-4;
41+
}
42+
43+
&:last-child {
44+
margin-right: 0;
45+
}
46+
47+
label {
48+
font-weight: $font-weight-medium;
49+
}
50+
51+
input {
52+
cursor: pointer;
53+
}
54+
}
55+
}
56+
}
557
}
58+
59+
:global(.react-responsive-modal-closeButton) {
60+
display: none;
61+
}
Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,104 @@
1-
import { FC } from 'react'
1+
import { Dispatch, FC, SetStateAction, useState } from 'react'
22

3-
import { Collapsible } from '~/libs/ui'
3+
import { BaseModal, Button, Collapsible } from '~/libs/ui'
4+
import { authUrlLogout, updatePrimaryMemberRoleAsync, UserProfile } from '~/libs/core'
45

56
import styles from './AccountRole.module.scss'
67

7-
const AccountRole: FC<{}> = () => (
8-
<Collapsible
9-
header={<h3>Account Role</h3>}
10-
containerClass={styles.container}
11-
/>
12-
)
8+
interface AccountRoleProps {
9+
profile: UserProfile
10+
}
11+
// TODO: move to libs/core after discussion
12+
// we need to have uniq list of TC roles
13+
enum AccountRoles {
14+
CUSTOMER = 'Topcoder Customer',
15+
TALENT = 'Topcoder Talent'
16+
}
17+
18+
const AccountRole: FC<AccountRoleProps> = (props: AccountRoleProps) => {
19+
const [memberRole, setMemberRole]: [string, Dispatch<SetStateAction<string>>]
20+
= useState<string>(
21+
props.profile.roles.includes(AccountRoles.CUSTOMER) ? AccountRoles.CUSTOMER : AccountRoles.TALENT,
22+
)
23+
24+
const [isUpdating, setIsUpdating]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
25+
26+
const [isRoleChangeConfirmed, setIsRoleChangeConfirmed]: [boolean, Dispatch<SetStateAction<boolean>>]
27+
= useState<boolean>(false)
28+
29+
function handleRoleChange(): void {
30+
const newRole: string = memberRole === AccountRoles.CUSTOMER ? AccountRoles.TALENT : AccountRoles.CUSTOMER
31+
32+
if (!isUpdating) {
33+
setIsUpdating(true)
34+
updatePrimaryMemberRoleAsync(newRole)
35+
.then(() => {
36+
setMemberRole(newRole)
37+
setIsRoleChangeConfirmed(true)
38+
})
39+
.finally(() => {
40+
setIsUpdating(false)
41+
})
42+
}
43+
}
44+
45+
function handleSignOut(): void {
46+
window.location.href = authUrlLogout
47+
}
48+
49+
return (
50+
<Collapsible
51+
header={<h3>Account Role</h3>}
52+
containerClass={styles.container}
53+
contentClass={styles.content}
54+
>
55+
<p>
56+
Access to Topcoder tools and applications are based on your account role.
57+
If you change this setting, you will be required to sign out of your account and login.
58+
</p>
59+
60+
<form>
61+
<div className={styles.formControlWrap}>
62+
<label htmlFor='role-1'>Topcoder Talent</label>
63+
<input
64+
type='radio'
65+
name='role'
66+
id='role-1'
67+
onChange={handleRoleChange}
68+
checked={memberRole === AccountRoles.TALENT}
69+
/>
70+
</div>
71+
<div className={styles.formControlWrap}>
72+
<label htmlFor='role-2'>Topcoder Customer</label>
73+
<input
74+
type='radio'
75+
name='role'
76+
id='role-2'
77+
onChange={handleRoleChange}
78+
checked={memberRole === AccountRoles.CUSTOMER}
79+
/>
80+
</div>
81+
</form>
82+
83+
{
84+
isRoleChangeConfirmed && (
85+
<BaseModal
86+
title='Confirmed'
87+
open
88+
// eslint-disable-next-line react/jsx-no-bind, @typescript-eslint/no-empty-function
89+
onClose={() => { }}
90+
buttons={<Button primary onClick={handleSignOut}>Sign Out</Button>}
91+
>
92+
<p>
93+
You have successfully changed your account role.
94+
Please sign out of your account and login to complete this update.
95+
</p>
96+
</BaseModal>
97+
)
98+
}
99+
100+
</Collapsible>
101+
)
102+
}
13103

14104
export default AccountRole

src/libs/core/lib/profile/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export * from './country-lookup.model'
88
export * from './data-providers'
99
export * from './user-skill.model'
1010
export * from './user-badge.model'
11+
export * from './modify-user-role.model'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export interface ModifyUserRoleRequest {
2+
param: {
3+
primaryRole: string
4+
}
5+
}
6+
7+
export interface ModifyUserRoleResponse {
8+
id: string
9+
result: {
10+
content: string
11+
success: boolean
12+
}
13+
}

src/libs/core/lib/profile/profile-functions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export {
66
getPublicAsync as profileGetPublicAsync,
77
getVerificationStatusAsync,
88
editNameAsync as profileEditNameAsync,
9+
updatePrimaryMemberRoleAsync,
910
} from './profile.functions'
1011
export * from './profile-store'
1112
export * from './rating.functions'

src/libs/core/lib/profile/profile-functions/profile-store/profile-endpoint.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ export function learnBaseURL(): string {
2525
export function memberStatsDistroURL(): string {
2626
return `${EnvironmentConfig.API.V3}/members/stats/distribution`
2727
}
28+
29+
export function memberModifyRoleURL(): string {
30+
return `${EnvironmentConfig.API.V3}/users/updatePrimaryRole`
31+
}

src/libs/core/lib/profile/profile-functions/profile-store/profile-xhr.store.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { xhrGetAsync, xhrPutAsync } from '../../../xhr'
1+
import { xhrGetAsync, xhrPostAsync, xhrPutAsync } from '../../../xhr'
22
import { CountryLookup } from '../../country-lookup.model'
33
import { EditNameRequest } from '../../edit-name-request.model'
4+
import { ModifyUserRoleRequest, ModifyUserRoleResponse } from '../../modify-user-role.model'
45
import { UserProfile } from '../../user-profile.model'
56
import { UserStats } from '../../user-stats.model'
67
import { UserVerify } from '../../user-verify.model'
78

8-
import { countryLookupURL, profile as profileUrl, verify as verifyUrl } from './profile-endpoint.config'
9+
import {
10+
countryLookupURL,
11+
memberModifyRoleURL,
12+
profile as profileUrl,
13+
verify as verifyUrl,
14+
} from './profile-endpoint.config'
915

1016
export function get(handle: string): Promise<UserProfile> {
1117
return xhrGetAsync<UserProfile>(profileUrl(handle))
@@ -31,3 +37,10 @@ export function getCountryLookup(): Promise<CountryLookup[]> {
3137
return xhrGetAsync<CountryLookup[]>(countryLookupURL())
3238
.then((countryLookup: any) => countryLookup.result?.content || [])
3339
}
40+
41+
export async function updatePrimaryMemberRole(primaryRole: string): Promise<ModifyUserRoleResponse> {
42+
return xhrPostAsync<ModifyUserRoleRequest, ModifyUserRoleResponse>(
43+
memberModifyRoleURL(),
44+
{ param: { primaryRole } },
45+
)
46+
}

src/libs/core/lib/profile/profile-functions/profile.functions.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { tokenGetAsync, TokenModel, userGetDiceStatusAsync } from '../../auth'
22
import { CountryLookup } from '../country-lookup.model'
33
import { EditNameRequest } from '../edit-name-request.model'
4+
import { ModifyUserRoleResponse } from '../modify-user-role.model'
45
import { UserProfile } from '../user-profile.model'
56
import { UserStats } from '../user-stats.model'
67
import { UserVerify } from '../user-verify.model'
78

89
import { profileFactoryCreate } from './profile-factory'
910
import { getMemberStats, getVerification, profileStoreGet, profileStorePatchName } from './profile-store'
10-
import { getCountryLookup } from './profile-store/profile-xhr.store'
11+
import { getCountryLookup, updatePrimaryMemberRole } from './profile-store/profile-xhr.store'
1112

1213
export async function getLoggedInAsync(handle?: string): Promise<UserProfile | undefined> {
1314

@@ -63,3 +64,7 @@ export async function getMemberStatsAsync(handle: string): Promise<UserStats | u
6364
export async function getCountryLookupAsync(): Promise<CountryLookup[]> {
6465
return getCountryLookup()
6566
}
67+
68+
export async function updatePrimaryMemberRoleAsync(primaryRole: string): Promise<ModifyUserRoleResponse> {
69+
return updatePrimaryMemberRole(primaryRole)
70+
}

0 commit comments

Comments
 (0)