Skip to content

Commit 2195252

Browse files
authored
Merge pull request #939 from topcoder-platform/TSJR-217_principal-skills
TSJR-217 - add principal skills to user profile
2 parents 3f00a83 + 4b9e2c3 commit 2195252

File tree

22 files changed

+361
-153
lines changed

22 files changed

+361
-153
lines changed

src/apps/profiles/src/config/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ export enum profileEditModes {
2424
}
2525

2626
export const CES_SURVEY_ID = EnvironmentConfig.USERFLOW_SURVEYS.PROFILES
27+
28+
export const MAX_PRINCIPAL_SKILLS_COUNT = 10

src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.module.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,28 @@
2727
.skillsWrap {
2828
padding-bottom: $sp-8;
2929

30+
31+
:global(.large-subtitle) {
32+
margin-bottom: $sp-4;
33+
}
34+
3035
@include ltemd {
3136
padding-bottom: $sp-4;
3237
}
3338
}
3439
}
40+
41+
.principalSkillsWrap {
42+
background: $black-5;
43+
border-radius: $sp-2;
44+
padding: $sp-6;
45+
+ .additionalSkillsWrap {
46+
margin-top: $sp-6;
47+
}
48+
}
49+
50+
.principalSkills {
51+
display: flex;
52+
flex-wrap: wrap;
53+
gap: $sp-2;
54+
}

src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { Dispatch, FC, SetStateAction, useEffect, useMemo, useState } from 'react'
22
import { useSearchParams } from 'react-router-dom'
3-
import { orderBy } from 'lodash'
3+
import { filter, orderBy } from 'lodash'
44

5-
import { UserProfile, UserSkill } from '~/libs/core'
6-
import { GroupedSkillsUI, HowSkillsWorkModal, isSkillVerified } from '~/libs/shared'
5+
import { UserProfile, UserSkill, UserSkillDisplayModes } from '~/libs/core'
6+
import { GroupedSkillsUI, HowSkillsWorkModal, isSkillVerified, SkillPill, useLocalStorage } from '~/libs/shared'
77
import { Button } from '~/libs/ui'
88

99
import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components'
1010
import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config'
1111
import { MemberProfileContextValue, useMemberProfileContext } from '../MemberProfile.context'
1212

1313
import { ModifySkillsModal } from './ModifySkillsModal'
14+
import { PrincipalSkillsModal } from './PrincipalSkillsModal'
1415
import styles from './MemberSkillsInfo.module.scss'
1516

1617
interface MemberSkillsInfoProps {
@@ -24,6 +25,7 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
2425
const editMode: string | null = queryParams.get(EDIT_MODE_QUERY_PARAM)
2526

2627
const canEdit: boolean = props.authProfile?.handle === props.profile.handle
28+
const [hasSeenPrincipalIntro, setHasSeenPrincipalIntro] = useLocalStorage('seen-principal-intro', {} as any)
2729

2830
const { skillsRenderer, isTalentSearch }: MemberProfileContextValue = useMemberProfileContext()
2931

@@ -33,11 +35,19 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
3335
['desc', 'asc'],
3436
) as UserSkill[], [props.profile.skills])
3537

38+
const principalSkills = useMemo(() => (
39+
filter(memberSkills, s => s.displayMode?.name === UserSkillDisplayModes.principal)
40+
), [memberSkills])
41+
42+
const additionalSkills = useMemo(() => (
43+
filter(memberSkills, s => s.displayMode?.name !== UserSkillDisplayModes.principal)
44+
), [memberSkills])
45+
3646
const groupedSkillsByCategory: { [key: string]: UserSkill[] } = useMemo(() => {
3747
const grouped: { [key: string]: UserSkill[] } = {}
3848
const sortedGroupedSkillsByCategory: { [key: string]: UserSkill[] } = {}
3949

40-
memberSkills.forEach((skill: UserSkill) => {
50+
additionalSkills.forEach((skill: UserSkill) => {
4151
const categoryName = skill.category?.name ?? ''
4252
if (grouped[categoryName]) {
4353
grouped[categoryName].push(skill)
@@ -53,14 +63,17 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
5363
})
5464

5565
return sortedGroupedSkillsByCategory
56-
}, [memberSkills])
66+
}, [additionalSkills])
5767

5868
const [isEditMode, setIsEditMode]: [boolean, Dispatch<SetStateAction<boolean>>]
5969
= useState<boolean>(false)
6070

6171
const [howSkillsWorkVisible, setHowSkillsWorkVisible]: [boolean, Dispatch<SetStateAction<boolean>>]
6272
= useState<boolean>(false)
6373

74+
const [principalIntroModalVisible, setPrincipalIntroModalVisible]: [boolean, Dispatch<SetStateAction<boolean>>]
75+
= useState<boolean>(false)
76+
6477
useEffect(() => {
6578
if (props.authProfile && editMode === profileEditModes.skills) {
6679
setIsEditMode(true)
@@ -69,6 +82,19 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
6982
// eslint-disable-next-line react-hooks/exhaustive-deps
7083
}, [props.authProfile])
7184

85+
useEffect(() => {
86+
if (
87+
!canEdit
88+
|| !props.authProfile
89+
|| hasSeenPrincipalIntro[props.authProfile.handle]
90+
|| isTalentSearch
91+
) {
92+
return
93+
}
94+
95+
setPrincipalIntroModalVisible(true)
96+
}, [hasSeenPrincipalIntro, canEdit, isTalentSearch, props.authProfile, setHasSeenPrincipalIntro])
97+
7298
function handleEditSkillsClick(): void {
7399
setIsEditMode(true)
74100
}
@@ -92,16 +118,21 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
92118
setHowSkillsWorkVisible(false)
93119
}
94120

121+
function handlePrincipalIntroShow(): void {
122+
setPrincipalIntroModalVisible(true)
123+
}
124+
125+
function handlePrincipalIntroClose(): void {
126+
setHasSeenPrincipalIntro((prevValue: any) => ({
127+
...prevValue,
128+
[props.authProfile?.handle ?? '']: true,
129+
}))
130+
131+
setPrincipalIntroModalVisible(false)
132+
}
133+
95134
return (
96135
<div className={styles.container}>
97-
{
98-
skillsRenderer && memberSkills.length > 0 && (
99-
<div className={styles.skillsWrap}>
100-
{skillsRenderer(memberSkills)}
101-
</div>
102-
)
103-
}
104-
105136
<div className={styles.titleWrap}>
106137
<div className={styles.headerWrap}>
107138
<h3>Skills</h3>
@@ -123,11 +154,42 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
123154
</div>
124155
</div>
125156

157+
{
158+
skillsRenderer && memberSkills.length > 0 && (
159+
<div className={styles.skillsWrap}>
160+
{skillsRenderer(memberSkills)}
161+
</div>
162+
)
163+
}
164+
126165
<div className={styles.skillsWrap}>
127-
{memberSkills.length > 0 && (
128-
<GroupedSkillsUI
129-
groupedSkillsByCategory={groupedSkillsByCategory}
130-
/>
166+
{principalSkills.length > 0 && (
167+
<div className={styles.principalSkillsWrap}>
168+
<div className='large-subtitle'>
169+
Principal Skills
170+
</div>
171+
<div className={styles.principalSkills}>
172+
{principalSkills.map((skill: UserSkill) => (
173+
<SkillPill
174+
skill={skill}
175+
key={skill.id}
176+
theme={isSkillVerified(skill) ? 'verified' : 'dark'}
177+
/>
178+
))}
179+
</div>
180+
</div>
181+
)}
182+
{additionalSkills.length > 0 && (
183+
<div className={styles.additionalSkillsWrap}>
184+
{principalSkills.length > 0 && (
185+
<div className='large-subtitle'>
186+
Additional Skills
187+
</div>
188+
)}
189+
<GroupedSkillsUI
190+
groupedSkillsByCategory={groupedSkillsByCategory}
191+
/>
192+
</div>
131193
)}
132194
{!memberSkills.length && (
133195
<EmptySection
@@ -155,6 +217,7 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
155217
<ModifySkillsModal
156218
onClose={handleModyfSkillsModalClose}
157219
onSave={handleModyfSkillsSave}
220+
showPrincipalIntroModal={handlePrincipalIntroShow}
158221
/>
159222
)
160223
}
@@ -168,6 +231,14 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
168231
/>
169232
)
170233
}
234+
235+
{
236+
principalIntroModalVisible && (
237+
<PrincipalSkillsModal
238+
onClose={handlePrincipalIntroClose}
239+
/>
240+
)
241+
}
171242
</div>
172243
)
173244
}

src/apps/profiles/src/member-profile/skills/ModifySkillsModal/ModifySkillsModal.module.scss

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
@import '@libs/ui/styles/includes';
22

3+
.skillsModalHeader {
4+
:global(.body-main-normal) {
5+
margin-top: $sp-2;
6+
}
7+
}
8+
39
.container {
410
display: flex;
511
flex-direction: column;
612

7-
:global(.body-main-bold) {
8-
font-size: 20px;
9-
margin-bottom: $sp-2;
10-
}
11-
12-
.skillPicker {
13-
margin-top: $sp-4;
13+
:global(.input-wrapper) {
14+
margin-top: $sp-2;
1415
}
1516
}
1617

@@ -29,3 +30,15 @@
2930
.skillsModalBody {
3031
overflow: visible !important;
3132
}
33+
34+
.principalIntroLink {
35+
display: flex;
36+
justify-content: flex-end;
37+
> span {
38+
color: $link-blue-dark;
39+
cursor: pointer;
40+
&:hover {
41+
color: darken($link-blue-dark, 5);
42+
}
43+
}
44+
}

src/apps/profiles/src/member-profile/skills/ModifySkillsModal/ModifySkillsModal.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import styles from './ModifySkillsModal.module.scss'
99
interface ModifySkillsModalProps {
1010
onClose: () => void
1111
onSave: () => void
12+
showPrincipalIntroModal: () => void
1213
}
1314

1415
const ModifySkillsModal: FC<ModifySkillsModalProps> = (props: ModifySkillsModalProps) => {
@@ -40,7 +41,14 @@ const ModifySkillsModal: FC<ModifySkillsModalProps> = (props: ModifySkillsModalP
4041
onClose={props.onClose}
4142
open
4243
size='lg'
43-
title='My Skills'
44+
title={(
45+
<div className={styles.skillsModalHeader}>
46+
<h3>Your skills</h3>
47+
<p className='body-main-normal'>
48+
We use your skills to connect you to the best opportunities.
49+
</p>
50+
</div>
51+
)}
4452
buttons={(
4553
<div className={styles.modalButtons}>
4654
<Button
@@ -58,13 +66,17 @@ const ModifySkillsModal: FC<ModifySkillsModalProps> = (props: ModifySkillsModalP
5866
)}
5967
>
6068
<div className={styles.container}>
61-
<p className='body-main-bold'>What are your skills?</p>
62-
<p>
63-
Understanding your skills will allow us to connect you to the right opportunities.
64-
</p>
6569
<div className={styles.skillPicker}>
6670
{editor.formInput}
6771
</div>
72+
<div
73+
className={styles.principalIntroLink}
74+
onClick={props.showPrincipalIntroModal}
75+
>
76+
<span className='body-main-link'>
77+
See what Principal skills are
78+
</span>
79+
</div>
6880
</div>
6981
</BaseModal>
7082
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.verified {
4+
display: inline-flex;
5+
6+
svg {
7+
margin: 0 $sp-2;
8+
color: $turq-120;
9+
}
10+
}
11+
12+
.container {
13+
strong {
14+
font-weight: bold;
15+
}
16+
}
17+
18+
.mb1 {
19+
margin-bottom: $sp-2;
20+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { FC } from 'react'
2+
3+
import { BaseModal } from '~/libs/ui'
4+
5+
import { MAX_PRINCIPAL_SKILLS_COUNT } from '../../../config'
6+
7+
import principalInputImg from './principal-input.png'
8+
import principalSectionImg from './principal-section.png'
9+
import styles from './PrincipalSkillsModal.module.scss'
10+
11+
interface PrincipalSkillsModalProps {
12+
onClose: () => void
13+
}
14+
15+
const PrincipalSkillsModal: FC<PrincipalSkillsModalProps> = (props: PrincipalSkillsModalProps) => (
16+
<BaseModal
17+
onClose={props.onClose}
18+
open
19+
title='Highlight your Principal Skills'
20+
size='lg'
21+
>
22+
<div className={styles.container}>
23+
<p>
24+
<div className={styles.mb1}>
25+
Now you can highlight your most important skills using the&nbsp;
26+
<strong>Principal Skills</strong>
27+
&nbsp;section!
28+
</div>
29+
<img src={principalSectionImg} alt='' />
30+
</p>
31+
<br />
32+
<p>
33+
<div className={styles.mb1}>
34+
Just move the skills you want to highlight by typing them in the&nbsp;
35+
<strong>Principal Skills input</strong>
36+
&nbsp;when you edit your skills.
37+
</div>
38+
<img src={principalInputImg} alt='' />
39+
</p>
40+
<br />
41+
<p>
42+
<strong>NOTE:</strong>
43+
&nbsp;You can add up to
44+
{' '}
45+
{MAX_PRINCIPAL_SKILLS_COUNT}
46+
{' '}
47+
skills to your Principal Skills section.
48+
</p>
49+
<br />
50+
<p>
51+
To move a skill back to the
52+
{' '}
53+
<strong>Additional Skills section</strong>
54+
, just type it in the
55+
{' '}
56+
<strong>Additional Skills input</strong>
57+
.
58+
</p>
59+
</div>
60+
</BaseModal>
61+
)
62+
63+
export default PrincipalSkillsModal
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as PrincipalSkillsModal } from './PrincipalSkillsModal'
6.19 KB
Loading
22 KB
Loading

0 commit comments

Comments
 (0)