Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5439ea7
Revert "Revert "Merge pull request #916 from topcoder-platform/TAL-84…
vas3a Oct 5, 2023
079bce4
TSJR-111 implement skills category UI
kkartunov Oct 11, 2023
8e5b918
ci: on dev
kkartunov Oct 11, 2023
138f279
TSJR-111 responsive skills UI
kkartunov Oct 12, 2023
f587205
TSJR-111 clean up talent-search view
kkartunov Oct 12, 2023
5ed2ac6
Merge branch 'TSJR-14_update-skill-selector-standardized-skills' into…
vas3a Oct 12, 2023
bba03bc
update circleci
vas3a Oct 12, 2023
3ed5bf2
Merge branch 'dev' into TSJR-111
kkartunov Oct 16, 2023
2e23333
TSJR-111 add new skills model & clean uplegacy
kkartunov Oct 16, 2023
71d7676
TSJR-111 clen up EMSIskill definitions
kkartunov Oct 16, 2023
c887e34
TSJR-111 move skill components to shared
kkartunov Oct 16, 2023
3c21eb5
Merge branch 'feature/standardized-skills' into TSJR-111
kkartunov Oct 16, 2023
040ce2b
Resolve merge conflicts 2
kkartunov Oct 16, 2023
a617ee8
Update search handler types for talent-serach app
vas3a Oct 16, 2023
9d3106e
Merge pull request #927 from topcoder-platform/TSJR-111
kkartunov Oct 17, 2023
1410318
TSJR-14 - update api endpoints for skills
vas3a Oct 17, 2023
3baa835
Fix popular skill IDs for new database
jmgasper Oct 17, 2023
82e4c11
Merge pull request #929 from topcoder-platform/fix_popular_skill_ids
vas3a Oct 17, 2023
1a8cb24
TSJR-14 - update calls to standardized skills api to send correct pay…
vas3a Oct 17, 2023
84a2d1b
Merge pull request #928 from topcoder-platform/TSJR-14_standardized-s…
vas3a Oct 17, 2023
519ed3f
Update to use non-deleted IDs
jmgasper Oct 17, 2023
36b790f
Fix names
jmgasper Oct 17, 2023
7e1250c
Merge pull request #930 from topcoder-platform/fix_popular_skill_ids
jmgasper Oct 17, 2023
bc11f31
TSJR-159rbetter mobile responsive
kkartunov Oct 18, 2023
126d369
TSJR-158 better collapse skills UI
kkartunov Oct 18, 2023
4b72b46
TSJR-111 updates
kkartunov Oct 19, 2023
43010b9
TSJR-169 columns layout
kkartunov Oct 20, 2023
c9a8d4a
remove react-responsive-masonry lib as not used
kkartunov Oct 20, 2023
bac25fc
Merge pull request #931 from topcoder-platform/TSJR-111-skills-UI-upd…
kkartunov Oct 20, 2023
7ffe3bc
Removing parantheses from skill names (TSJR-192)
jmgasper Oct 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,13 @@ workflows:
ignore:
- master
- qa
- profiles-app

- build-qa:
context: org-global
filters:
branches:
only:
- qa
- profiles-app

- build-prod:
context: org-global
Expand All @@ -261,7 +259,7 @@ workflows:
- dev
- justin_fixes
- talent_search_fixes
- PROD-4398_integrate-userflow-remove-sprig
- feature/standardized-skills

- deployQa:
context: org-global
Expand Down
8 changes: 4 additions & 4 deletions src/apps/learn/src/lib/components/skill-tags/SkillTags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Tooltip } from '~/libs/ui'
import { EnvironmentConfig } from '~/config'

import { SkillLabel } from '..'
import { TCAEMSISkillType } from '../../data-providers'
import { TCASkillType } from '../../data-providers'

import styles from './SkillTags.module.scss'

Expand All @@ -15,7 +15,7 @@ interface SkillTagsProps {
label?: string
theme?: 'white' | 'gray' | undefined
skills?: Array<string> | null | undefined
emsiSkills?: TCAEMSISkillType[]
emsiSkills?: TCASkillType[]
}

const SkillTags: FC<SkillTagsProps> = (props: SkillTagsProps) => {
Expand All @@ -24,15 +24,15 @@ const SkillTags: FC<SkillTagsProps> = (props: SkillTagsProps) => {
const label: string = props.label ?? 'skills taught'
const tcaEMSIEnabled: boolean = EnvironmentConfig.ENABLE_EMSI_SKILLS || false

const skills: string[] | TCAEMSISkillType[] = tcaEMSIEnabled ? (props.emsiSkills || []) : (props.skills || [])
const skills: string[] | TCASkillType[] = tcaEMSIEnabled ? (props.emsiSkills || []) : (props.skills || [])

return (
<div className={styles.skills}>
{label && (
<span className={classNames('body-small', styles.infoText)}>{label}</span>
)}
{skills?.slice(0, expandCount)
.map((skill: string | TCAEMSISkillType) => (
.map((skill: string | TCASkillType) => (
<SkillLabel
skill={skill}
theme={theme}
Expand Down
4 changes: 2 additions & 2 deletions src/apps/learn/src/lib/components/skill/SkillLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { FC } from 'react'

import { TCAEMSISkillType } from '../../data-providers'
import { TCASkillType } from '../../data-providers'

import styles from './SkillLabel.module.scss'

interface SkillLabelProps {
skill: string | TCAEMSISkillType
skill: string | TCASkillType
theme: 'white' | 'gray' | undefined
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { LearnModelBase } from '../../functions'
import { CertificationLearnLevel, LearnCertification } from '../all-certifications-provider'
import { LearnModule } from '../lesson-provider'
import { ResourceProvider } from '../resource-provider-provider'
import { TCAEMSISkillType } from '../tca-certifications-provider/tca-emsi-skill-type'
import { TCASkillType } from '../tca-certifications-provider/tca-skill-type'

export interface LearnCourse extends LearnModelBase {
certificationId: string
completionSuggestions: Array<string>
emsiSkills: Array<TCAEMSISkillType>
emsiSkills: Array<TCASkillType>
estimatedCompletionTimeValue: number
estimatedCompletionTimeUnits: string
fccCourseUuid: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ export * from './tca-certification-progress'
export * from './tca-certification-enrollment-base.model'
export * from './tca-certification-validation'
export * from './tca-certification-enrollment'
export * from './tca-emsi-skill-type'
export * from './tca-skill-type'
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TCACertificationCompletionTimeRange } from './tca-certification-complet
import { TCACertificationProvider } from './tca-certification-provider.model'
import { TCACertificationProviderBase } from './tca-certification-provider.model-base'
import { TCACertificationResource } from './tca-certification-resource.model'
import { TCAEMSISkillType } from './tca-emsi-skill-type'
import { TCASkillType } from './tca-skill-type'

export interface TCACertification {
certificationCategory: TCACertificationCategory
Expand All @@ -16,7 +16,7 @@ export interface TCACertification {
createdAt: Date
dashedName: string
description: string
emsiSkills: Array<TCAEMSISkillType>
emsiSkills: Array<TCASkillType>
id: number
introText: string
learnerLevel: TCACertificationLearnLevel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type TCAEMSISkillType = {
export type TCASkillType = {
assessed: boolean
confidence: number
emsiId: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
TCACertification,
TCACertificationProgress,
TCACertificationProviderBase,
TCAEMSISkillType,
TCASkillType,
} from '../../../lib'

import styles from './TCCertCard.module.scss'
Expand All @@ -43,7 +43,7 @@ const TCCertCard: FC<TCCertCardProps> = (props: TCCertCardProps) => {
skills: string[],
providers: Array<TCACertificationProviderBase>,
dashedName: string
emsiSkills: TCAEMSISkillType[]
emsiSkills: TCASkillType[]
} = props.certification

const isEnrolled: boolean = props.progress?.status === 'enrolled'
Expand Down
6 changes: 3 additions & 3 deletions src/apps/onboarding/src/models/MemberInfo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MemberEmsiSkill, MemberMaxRating } from '~/apps/talent-search/src/lib/models'
import { MemberStats } from '~/libs/core'
import { MemberMaxRating } from '~/apps/talent-search/src/lib/models'
import { MemberStats, UserSkill } from '~/libs/core'

import MemberAddress from './MemberAddress'

Expand All @@ -13,7 +13,7 @@ export default interface MemberInfo {
email: string
accountAge: number
maxRating: MemberMaxRating
emsiSkills: Array<MemberEmsiSkill>
skills: Array<UserSkill>
stats: Array<MemberStats>
addresses?: MemberAddress[]
country: string
Expand Down
6 changes: 3 additions & 3 deletions src/apps/onboarding/src/pages/skills/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export const PageSkillsContent: FC<{
}> = props => {
const navigate: any = useNavigate()
const [loading, setLoading] = useState(false)
const { formInput: emsiFormInput, saveSkills: saveEmsiSkills }: MemberSkillEditor = useMemberSkillEditor()
const editor: MemberSkillEditor = useMemberSkillEditor()

async function saveSkills(): Promise<void> {
setLoading(true)
try {
await saveEmsiSkills()
await editor.saveSkills()
} catch (error) {
}

Expand All @@ -46,7 +46,7 @@ export const PageSkillsContent: FC<{
Understanding your skills will allow us to connect you to the right opportunities.
</span>
<div className='mt-16 full-width color-black-80'>
{emsiFormInput}
{editor.formInput}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createContext, FC, ReactNode, useContext, useMemo } from 'react'

import { UserEMSISkill } from '~/libs/core'
import { UserSkill } from '~/libs/core'

export interface MemberProfileContextValue {
isTalentSearch?: boolean
skillsRenderer?: (
skills: Pick<UserEMSISkill, 'name'|'skillId'|'skillSources'>[]
skills: Pick<UserSkill, 'name'|'id'|'levels'>[]
) => ReactNode
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
.container {
display: flex;
flex-direction: column;
margin-bottom: $sp-6;

.headerWrap {
display: flex;
Expand All @@ -22,35 +21,14 @@
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $sp-4;
margin-bottom: $sp-6;
}

.skillsWrap {
display: flex;
flex-wrap: wrap;
column-gap: $sp-1;
row-gap: $sp-2;

.skillItem {
border: 1px solid $black-20;
font-size: 14px;
line-height: 16px;
white-space: nowrap;
padding: $sp-2 $sp-3;
border-radius: 24px;
display: flex;
align-items: center;

&.verifiedSkillItem {
border: 2px solid $turq-120;
padding-bottom: $sp-8;

svg {
margin-left: $sp-1;
width: 16px;
height: 16px;
color: $turq-120;
}
}
@include ltemd {
padding-bottom: $sp-4;
}
}
}
89 changes: 56 additions & 33 deletions src/apps/profiles/src/member-profile/skills/MemberSkillsInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Dispatch, FC, SetStateAction, useEffect, useMemo, useState } from 'reac
import { useSearchParams } from 'react-router-dom'
import { orderBy } from 'lodash'

import { UserEMSISkill, UserProfile } from '~/libs/core'
import { ExpandableList, HowSkillsWorkModal, isSkillVerified, Skill, SkillPill } from '~/libs/shared'
import { UserProfile, UserSkill } from '~/libs/core'
import { GroupedSkillsUI, HowSkillsWorkModal, isSkillVerified } from '~/libs/shared'
import { Button } from '~/libs/ui'

import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components'
Expand All @@ -27,11 +27,32 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp

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

const memberEMSISkills: UserEMSISkill[] = useMemo(() => orderBy(
props.profile.emsiSkills ?? [],
const memberSkills: UserSkill[] = useMemo(() => orderBy(
props.profile.skills ?? [],
[isSkillVerified, 'name'],
['desc', 'asc'],
) as UserEMSISkill[], [props.profile.emsiSkills])
) as UserSkill[], [props.profile.skills])

const groupedSkillsByCategory: { [key: string]: UserSkill[] } = useMemo(() => {
const grouped: { [key: string]: UserSkill[] } = {}
const sortedGroupedSkillsByCategory: { [key: string]: UserSkill[] } = {}

memberSkills.forEach((skill: UserSkill) => {
if (grouped[skill.category.name]) {
grouped[skill.category.name].push(skill)
} else {
grouped[skill.category.name] = [skill]
}
})

Object.keys(grouped)
.sort()
.forEach(key => {
sortedGroupedSkillsByCategory[key] = grouped[key]
})

return sortedGroupedSkillsByCategory
}, [memberSkills])

const [isEditMode, setIsEditMode]: [boolean, Dispatch<SetStateAction<boolean>>]
= useState<boolean>(false)
Expand Down Expand Up @@ -72,42 +93,42 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp

return (
<div className={styles.container}>
{
skillsRenderer && memberSkills.length > 0 && (
<div className={styles.skillsWrap}>
{skillsRenderer(memberSkills)}
</div>
)
}

<div className={styles.titleWrap}>
<div className={styles.headerWrap}>
<h3>Skills</h3>
{
canEdit && memberEMSISkills.length > 0 && (
canEdit && memberSkills.length > 0 && (
<EditMemberPropertyBtn
onClick={handleEditSkillsClick}
/>
)
}
</div>
<Button
link
label='How skills work'
onClick={handleHowSkillsWorkClick}
variant='linkblue'
/>
<div className={styles.skillActions}>
<Button
link
label='How skills work'
onClick={handleHowSkillsWorkClick}
variant='linkblue'
/>
</div>
</div>

<div className={styles.skillsWrap}>
{skillsRenderer && memberEMSISkills.length > 0 && skillsRenderer(memberEMSISkills)}
{!skillsRenderer && memberEMSISkills.length > 0 && (
<ExpandableList visible={10} itemLabel='skill'>
{
memberEMSISkills
.map(memberEMSISkill => (
<SkillPill
skill={memberEMSISkill as unknown as Skill}
key={memberEMSISkill.id}
theme='dark'
/>
))
}
</ExpandableList>
{memberSkills.length > 0 && (
<GroupedSkillsUI
groupedSkillsByCategory={groupedSkillsByCategory}
/>
)}
{!memberEMSISkills.length && (
{!memberSkills.length && (
<EmptySection
title='Topcoder verifies and tracks skills as our members complete projects and challenges.'
wide
Expand All @@ -119,12 +140,14 @@ const MemberSkillsInfo: FC<MemberSkillsInfoProps> = (props: MemberSkillsInfoProp
</EmptySection>
)}
</div>
{canEdit && !memberEMSISkills.length && (
<AddButton
label='Add skills'
onClick={handleEditSkillsClick}
/>
)}
{
canEdit && !memberSkills.length && (
<AddButton
label='Add skills'
onClick={handleEditSkillsClick}
/>
)
}

{
isEditMode && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ const ModifySkillsModal: FC<ModifySkillsModalProps> = (props: ModifySkillsModalP
const [isSaving, setIsSaving]: [boolean, Dispatch<SetStateAction<boolean>>]
= useState<boolean>(false)

const { formInput: emsiFormInput, saveSkills: saveEmsiSkills }: MemberSkillEditor = useMemberSkillEditor()
const editor: MemberSkillEditor = useMemberSkillEditor()

function handleModifySkillsSave(): void {
setIsSaving(true)

saveEmsiSkills()
editor.saveSkills()
.then(() => {
toast.success('Skills updated successfully.', { position: toast.POSITION.BOTTOM_RIGHT })
props.onSave()
Expand Down Expand Up @@ -63,7 +63,7 @@ const ModifySkillsModal: FC<ModifySkillsModalProps> = (props: ModifySkillsModalP
Understanding your skills will allow us to connect you to the right opportunities.
</p>
<div className={styles.skillPicker}>
{emsiFormInput}
{editor.formInput}
</div>
</div>
</BaseModal>
Expand Down
Loading