Skip to content

Commit b90b66f

Browse files
committed
fix: review comments
1 parent 17c4257 commit b90b66f

File tree

2 files changed

+80
-62
lines changed

2 files changed

+80
-62
lines changed

src/apps/profiles/src/member-profile/work-expirence/WorkExpirence.tsx

Lines changed: 40 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Dispatch, FC, SetStateAction, useEffect, useMemo, useRef, useState } from 'react'
1+
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react'
22
import { useSearchParams } from 'react-router-dom'
33

44
import { MemberTraitsAPI, useMemberTraits, UserProfile, UserTrait, UserTraitIds } from '~/libs/core'
5-
import { fetchSkillsByIds } from '~/libs/shared/lib/services/standard-skills'
5+
import { useSkillsByIds } from '~/libs/shared/lib/services/standard-skills'
66

77
import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config'
88
import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components'
@@ -32,75 +32,57 @@ const WorkExpirence: FC<WorkExpirenceProps> = (props: WorkExpirenceProps) => {
3232
const workExpirence: UserTrait[] | undefined
3333
= useMemo(() => memberWorkExpirenceTraits?.[0]?.traits?.data, [memberWorkExpirenceTraits])
3434

35-
const [skillNamesMap, setSkillNamesMap] = useState<Record<string, string>>({})
36-
const [loadingSkills, setLoadingSkills] = useState<boolean>(false)
37-
const fetchedSkillIdsRef = useRef<Set<string>>(new Set())
38-
39-
useEffect(() => {
35+
// Collect all unique skill IDs from work experience entries
36+
const allSkillIds = useMemo(() => {
4037
if (!workExpirence) {
41-
setLoadingSkills(false)
42-
return
38+
return []
4339
}
4440

45-
const allSkillIds = new Set<string>()
41+
const skillIdsSet = new Set<string>()
4642
workExpirence.forEach((work: UserTrait) => {
4743
if (work.associatedSkills && Array.isArray(work.associatedSkills)) {
4844
work.associatedSkills.forEach((skillId: string) => {
4945
if (skillId && typeof skillId === 'string') {
50-
allSkillIds.add(skillId)
46+
skillIdsSet.add(skillId)
5147
}
5248
})
5349
}
5450
})
5551

56-
if (allSkillIds.size > 0) {
57-
const skillIdsToFetch = Array.from(allSkillIds)
58-
.filter(id => !fetchedSkillIdsRef.current.has(id))
59-
60-
if (skillIdsToFetch.length > 0) {
61-
setLoadingSkills(true)
62-
skillIdsToFetch.forEach(id => fetchedSkillIdsRef.current.add(id))
63-
64-
fetchSkillsByIds(skillIdsToFetch)
65-
.then(skills => {
66-
setSkillNamesMap(prevMap => {
67-
const newMap: Record<string, string> = { ...prevMap }
68-
skills.forEach(skill => {
69-
if (skill.id && skill.name) {
70-
newMap[skill.id] = skill.name
71-
}
72-
})
73-
skillIdsToFetch.forEach(skillId => {
74-
if (!newMap[skillId]) {
75-
newMap[skillId] = skillId
76-
}
77-
})
78-
return newMap
79-
})
80-
})
81-
.catch(() => {
82-
setSkillNamesMap(prevMap => {
83-
const fallbackMap: Record<string, string> = { ...prevMap }
84-
skillIdsToFetch.forEach(skillId => {
85-
if (!fallbackMap[skillId]) {
86-
fallbackMap[skillId] = skillId
87-
}
88-
})
89-
return fallbackMap
90-
})
91-
})
92-
.finally(() => {
93-
setLoadingSkills(false)
94-
})
95-
} else {
96-
setLoadingSkills(false)
97-
}
98-
} else {
99-
setLoadingSkills(false)
100-
}
52+
return Array.from(skillIdsSet)
10153
}, [workExpirence])
10254

103-
const areSkillsLoaded = (work: UserTrait): boolean => {
55+
// Fetch skills using SWR hook
56+
const { data: fetchedSkills, error: skillsError } = useSkillsByIds(
57+
allSkillIds.length > 0 ? allSkillIds : undefined,
58+
)
59+
60+
// Determine loading state: data is undefined and no error yet
61+
const loadingSkills = fetchedSkills === undefined && !skillsError
62+
63+
// Build skill names map from fetched skills
64+
const skillNamesMap = useMemo(() => {
65+
const map: Record<string, string> = {}
66+
67+
if (fetchedSkills) {
68+
fetchedSkills.forEach(skill => {
69+
if (skill.id && skill.name) {
70+
map[skill.id] = skill.name
71+
}
72+
})
73+
}
74+
75+
// For skills that weren't found, use ID as fallback
76+
allSkillIds.forEach(skillId => {
77+
if (!map[skillId]) {
78+
map[skillId] = skillId
79+
}
80+
})
81+
82+
return map
83+
}, [fetchedSkills, allSkillIds])
84+
85+
const areSkillsLoaded = useCallback((work: UserTrait): boolean => {
10486
if (!work.associatedSkills || !Array.isArray(work.associatedSkills) || work.associatedSkills.length === 0) {
10587
return true
10688
}
@@ -109,7 +91,7 @@ const WorkExpirence: FC<WorkExpirenceProps> = (props: WorkExpirenceProps) => {
10991
const skillName = skillNamesMap[skillId]
11092
return skillName && skillName !== skillId
11193
})
112-
}
94+
}, [skillNamesMap])
11395

11496
useEffect(() => {
11597
if (props.authProfile && editMode === profileEditModes.workExperience) {

src/libs/shared/lib/services/standard-skills/standard-skills.service.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { useMemo } from 'react'
2+
import { SWRResponse } from 'swr'
3+
import useSWR from 'swr'
4+
15
import { EnvironmentConfig } from '~/config'
26
import { UserSkill, xhrGetAsync, xhrPostAsync, xhrPutAsync } from '~/libs/core'
37

@@ -45,21 +49,53 @@ export async function updateMemberSkills(
4549
}
4650

4751
/**
48-
* Fetch skills by their IDs
52+
* Fetcher function for useSWR to fetch skills by their IDs
4953
* @param skillIds Array of skill UUIDs
5054
* @returns Promise with array of UserSkill objects
5155
*/
52-
export async function fetchSkillsByIds(skillIds: string[]): Promise<UserSkill[]> {
56+
async function fetchSkillsByIdsFetcher(skillIds: string[]): Promise<UserSkill[]> {
5357
if (!skillIds || skillIds.length === 0) {
54-
return Promise.resolve([])
58+
return []
5559
}
5660

5761
try {
5862
const skillPromises = skillIds.map(skillId => xhrGetAsync<UserSkill>(`${baseUrl}/skills/${skillId}`)
5963
.catch(() => undefined))
6064
const results = await Promise.all(skillPromises)
61-
return results.filter((skill): skill is UserSkill => (skill !== null || skill !== undefined))
65+
return results.filter((skill): skill is UserSkill => skill !== null && skill !== undefined)
6266
} catch {
6367
return []
6468
}
6569
}
70+
71+
/**
72+
* Hook to fetch skills by their IDs using SWR
73+
* @param skillIds Array of skill UUIDs
74+
* @returns SWRResponse with array of UserSkill objects
75+
*/
76+
export function useSkillsByIds(skillIds: string[] | undefined): SWRResponse<UserSkill[], Error> {
77+
const swrKey = useMemo(() => {
78+
if (!skillIds || skillIds.length === 0) {
79+
return null
80+
}
81+
return ['skills-by-ids', [...skillIds].sort().join(',')]
82+
}, [skillIds])
83+
84+
return useSWR<UserSkill[], Error>(
85+
swrKey,
86+
() => fetchSkillsByIdsFetcher(skillIds!),
87+
{
88+
revalidateOnFocus: false,
89+
revalidateOnReconnect: false,
90+
},
91+
)
92+
}
93+
94+
/**
95+
* Fetch skills by their IDs (legacy async function for backward compatibility)
96+
* @param skillIds Array of skill UUIDs
97+
* @returns Promise with array of UserSkill objects
98+
*/
99+
export async function fetchSkillsByIds(skillIds: string[]): Promise<UserSkill[]> {
100+
return fetchSkillsByIdsFetcher(skillIds)
101+
}

0 commit comments

Comments
 (0)