Skip to content

Commit 8d2c316

Browse files
committed
fix: lint
1 parent 9d9153d commit 8d2c316

File tree

5 files changed

+339
-23
lines changed

5 files changed

+339
-23
lines changed

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

Lines changed: 158 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
/* eslint-disable complexity */
2-
import { Dispatch, FC, MutableRefObject, SetStateAction, useRef, useState } from 'react'
2+
import { ChangeEvent, Dispatch, FC, MutableRefObject, SetStateAction, useEffect, useRef, useState } from 'react'
33
import { bind, sortBy, trim } from 'lodash'
44
import { toast } from 'react-toastify'
55
import classNames from 'classnames'
66

7-
import { BaseModal, Button, IconOutline, InputDatePicker, InputSelect, InputText } from '~/libs/ui'
7+
import { BaseModal, Button, IconOutline, InputDatePicker, InputSelect, InputText, InputTextarea } from '~/libs/ui'
88
import {
99
updateDeleteOrCreateMemberTraitAsync,
1010
UserProfile, UserTrait,
1111
UserTraitCategoryNames,
1212
UserTraitIds,
1313
} from '~/libs/core'
14-
import { getIndustryOptionLabel, getIndustryOptionValue, INDUSTRIES_OPTIONS } from '~/libs/shared'
14+
import { getIndustryOptionLabel, getIndustryOptionValue, INDUSTRIES_OPTIONS, InputSkillSelector } from '~/libs/shared'
15+
import { fetchSkillsByIds } from '~/libs/shared/lib/services/standard-skills'
1516

1617
import { WorkExpirenceCard } from '../WorkExpirenceCard'
1718

@@ -32,10 +33,10 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
3233
= useState<boolean>(props.workExpirence?.length === 0 || false)
3334

3435
const [formValues, setFormValues]: [
35-
{ [key: string]: string | boolean | Date | undefined },
36-
Dispatch<SetStateAction<{ [key: string]: string | boolean | Date | undefined }>>
36+
{ [key: string]: string | boolean | Date | any[] | undefined },
37+
Dispatch<SetStateAction<{ [key: string]: string | boolean | Date | any[] | undefined }>>
3738
]
38-
= useState<{ [key: string]: string | boolean | Date | undefined }>({})
39+
= useState<{ [key: string]: string | boolean | Date | any[] | undefined }>({})
3940

4041
const [formErrors, setFormErrors]: [
4142
{ [key: string]: string },
@@ -56,6 +57,86 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
5657
]
5758
= useState<UserTrait[] | undefined>(props.workExpirence)
5859

60+
const [skillNamesMap, setSkillNamesMap] = useState<Record<string, string>>({})
61+
const [loadingSkills, setLoadingSkills] = useState<boolean>(false)
62+
const fetchedSkillIdsRef = useRef<Set<string>>(new Set())
63+
64+
useEffect(() => {
65+
if (!workExpirence) {
66+
setLoadingSkills(false)
67+
return
68+
}
69+
70+
const allSkillIds = new Set<string>()
71+
workExpirence.forEach((work: UserTrait) => {
72+
if (work.associatedSkills && Array.isArray(work.associatedSkills)) {
73+
work.associatedSkills.forEach((skillId: string) => {
74+
if (skillId && typeof skillId === 'string') {
75+
allSkillIds.add(skillId)
76+
}
77+
})
78+
}
79+
})
80+
81+
if (allSkillIds.size > 0) {
82+
const skillIdsToFetch = Array.from(allSkillIds)
83+
.filter(id => !fetchedSkillIdsRef.current.has(id))
84+
85+
if (skillIdsToFetch.length > 0) {
86+
setLoadingSkills(true)
87+
skillIdsToFetch.forEach(id => fetchedSkillIdsRef.current.add(id))
88+
89+
fetchSkillsByIds(skillIdsToFetch)
90+
.then(skills => {
91+
setSkillNamesMap(prevMap => {
92+
const newMap: Record<string, string> = { ...prevMap }
93+
skills.forEach(skill => {
94+
if (skill.id && skill.name) {
95+
newMap[skill.id] = skill.name
96+
}
97+
})
98+
skillIdsToFetch.forEach(skillId => {
99+
if (!newMap[skillId]) {
100+
newMap[skillId] = skillId
101+
}
102+
})
103+
return newMap
104+
})
105+
})
106+
.catch(() => {
107+
setSkillNamesMap(prevMap => {
108+
const fallbackMap: Record<string, string> = { ...prevMap }
109+
skillIdsToFetch.forEach(skillId => {
110+
if (!fallbackMap[skillId]) {
111+
fallbackMap[skillId] = skillId
112+
}
113+
})
114+
return fallbackMap
115+
})
116+
})
117+
.finally(() => {
118+
setLoadingSkills(false)
119+
})
120+
} else {
121+
setLoadingSkills(false)
122+
}
123+
} else {
124+
// No skills to fetch
125+
setLoadingSkills(false)
126+
}
127+
}, [workExpirence])
128+
129+
const areSkillsLoaded = (work: UserTrait): boolean => {
130+
if (!work.associatedSkills || !Array.isArray(work.associatedSkills) || work.associatedSkills.length === 0) {
131+
return true
132+
}
133+
134+
return work.associatedSkills.every((skillId: string) => {
135+
const skillName = skillNamesMap[skillId]
136+
return skillName && skillName !== skillId
137+
})
138+
}
139+
59140
const industryOptions: any = sortBy(INDUSTRIES_OPTIONS)
60141
.map(v => ({
61142
label: getIndustryOptionLabel(v),
@@ -89,13 +170,16 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
89170
})
90171
}
91172

92-
function handleFormValueChange(key: string, event: React.ChangeEvent<HTMLInputElement>): void {
173+
function handleFormValueChange(
174+
key: string,
175+
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
176+
): void {
93177
let value: string | boolean | Date | undefined
94178
const oldFormValues = { ...formValues }
95179

96180
switch (key) {
97181
case 'currentlyWorking':
98-
value = event.target.checked
182+
value = (event.target as HTMLInputElement).checked
99183
if (value) {
100184
oldFormValues.endDate = undefined
101185
}
@@ -116,6 +200,17 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
116200
})
117201
}
118202

203+
function handleSkillsChange(event: ChangeEvent<HTMLInputElement>): void {
204+
const selectedSkills = (event.target as any).value || []
205+
setFormValues({
206+
...formValues,
207+
associatedSkills: selectedSkills.map((skill: any) => ({
208+
id: skill.value || skill.id,
209+
name: skill.label || skill.name,
210+
})),
211+
})
212+
}
213+
119214
function resetForm(): void {
120215
setFormValues({})
121216
setFormErrors({})
@@ -173,9 +268,10 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
173268
: undefined
174269

175270
const updatedWorkExpirence: UserTrait = {
176-
cityTown: formValues.city,
271+
associatedSkills: (formValues.associatedSkills as any[])?.map((s: any) => s.id || s) || [],
177272
company: companyName,
178273
companyName,
274+
description: (formValues.description as string) || undefined,
179275
endDate: endDateIso,
180276
industry: formValues.industry,
181277
position: formValues.position,
@@ -200,20 +296,41 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
200296
resetForm()
201297
}
202298

203-
function handleWorkExpirenceEdit(indx: number): void {
299+
async function handleWorkExpirenceEdit(indx: number): Promise<void> {
204300
const work: UserTrait = workExpirence ? workExpirence[indx] : {}
205301

206302
setEditedItemIndex(indx)
207303

304+
let associatedSkills: any[] = []
305+
if (work.associatedSkills && Array.isArray(work.associatedSkills) && work.associatedSkills.length > 0) {
306+
try {
307+
const skills = await fetchSkillsByIds(
308+
work.associatedSkills.filter((id): id is string => typeof id === 'string'),
309+
)
310+
const skillsMap = new Map(skills.map(s => [s.id, s.name]))
311+
312+
associatedSkills = work.associatedSkills.map((skillId: string) => ({
313+
id: skillId,
314+
name: skillsMap.get(skillId) || '',
315+
}))
316+
} catch {
317+
associatedSkills = work.associatedSkills.map((skillId: string) => ({
318+
id: skillId,
319+
name: skillNamesMap[skillId] || '',
320+
}))
321+
}
322+
}
323+
208324
setFormValues({
209-
city: work.cityTown || work.city,
210-
company: work.company || work.companyName,
211-
currentlyWorking: work.working,
325+
associatedSkills,
326+
company: (work.company || work.companyName || '') as string,
327+
currentlyWorking: work.working || false,
328+
description: work.description || '',
212329
endDate: work.timePeriodTo
213330
? new Date(work.timePeriodTo)
214331
: (work.endDate ? new Date(work.endDate) : undefined),
215-
industry: work.industry,
216-
position: work.position,
332+
industry: work.industry || '',
333+
position: (work.position || '') as string,
217334
startDate: work.timePeriodFrom
218335
? new Date(work.timePeriodFrom)
219336
: (work.startDate ? new Date(work.startDate) : undefined),
@@ -241,6 +358,7 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
241358
}
242359
}
243360

361+
console.log(formValues, 'formValues')
244362
return (
245363
<BaseModal
246364
onClose={props.onClose}
@@ -286,7 +404,12 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
286404
className={styles.workExpirenceCardWrap}
287405
key={uniqueKey || `${work.position}-${indx}`}
288406
>
289-
<WorkExpirenceCard work={work} isModalView />
407+
<WorkExpirenceCard
408+
work={work}
409+
isModalView
410+
skillNamesMap={skillNamesMap}
411+
showSkills={!loadingSkills && areSkillsLoaded(work)}
412+
/>
290413
<div className={styles.actionElements}>
291414
<Button
292415
className={styles.ctaBtn}
@@ -320,6 +443,7 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
320443
placeholder='Enter a company'
321444
dirty
322445
tabIndex={0}
446+
forceUpdateValue
323447
type='text'
324448
onChange={bind(handleFormValueChange, this, 'company')}
325449
value={formValues.company as string}
@@ -332,6 +456,7 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
332456
dirty
333457
tabIndex={0}
334458
type='text'
459+
forceUpdateValue
335460
onChange={bind(handleFormValueChange, this, 'position')}
336461
value={formValues.position as string}
337462
/>
@@ -376,6 +501,23 @@ const ModifyWorkExpirenceModal: FC<ModifyWorkExpirenceModalProps> = (props: Modi
376501
onChange={bind(handleFormValueChange, this, 'currentlyWorking')}
377502
checked={formValues.currentlyWorking as boolean}
378503
/>
504+
<InputTextarea
505+
name='description'
506+
label='Description'
507+
placeholder='Describe your role and achievements at this company'
508+
dirty
509+
tabIndex={0}
510+
onChange={bind(handleFormValueChange, this, 'description')}
511+
value={formValues.description as string}
512+
rows={4}
513+
/>
514+
<InputSkillSelector
515+
label='Associated Skills'
516+
placeholder='Type to search and add skills...'
517+
value={formValues.associatedSkills as any[]}
518+
onChange={handleSkillsChange}
519+
loading={false}
520+
/>
379521
</form>
380522
) : (
381523
<Button

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Dispatch, FC, SetStateAction, useEffect, useMemo, useState } from 'react'
1+
import { Dispatch, FC, SetStateAction, useEffect, useMemo, useRef, 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'
56

67
import { EDIT_MODE_QUERY_PARAM, profileEditModes } from '../../config'
78
import { AddButton, EditMemberPropertyBtn, EmptySection } from '../../components'
@@ -31,6 +32,85 @@ const WorkExpirence: FC<WorkExpirenceProps> = (props: WorkExpirenceProps) => {
3132
const workExpirence: UserTrait[] | undefined
3233
= useMemo(() => memberWorkExpirenceTraits?.[0]?.traits?.data, [memberWorkExpirenceTraits])
3334

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(() => {
40+
if (!workExpirence) {
41+
setLoadingSkills(false)
42+
return
43+
}
44+
45+
const allSkillIds = new Set<string>()
46+
workExpirence.forEach((work: UserTrait) => {
47+
if (work.associatedSkills && Array.isArray(work.associatedSkills)) {
48+
work.associatedSkills.forEach((skillId: string) => {
49+
if (skillId && typeof skillId === 'string') {
50+
allSkillIds.add(skillId)
51+
}
52+
})
53+
}
54+
})
55+
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+
}
101+
}, [workExpirence])
102+
103+
const areSkillsLoaded = (work: UserTrait): boolean => {
104+
if (!work.associatedSkills || !Array.isArray(work.associatedSkills) || work.associatedSkills.length === 0) {
105+
return true
106+
}
107+
108+
return work.associatedSkills.every((skillId: string) => {
109+
const skillName = skillNamesMap[skillId]
110+
return skillName && skillName !== skillId
111+
})
112+
}
113+
34114
useEffect(() => {
35115
if (props.authProfile && editMode === profileEditModes.workExperience) {
36116
setIsEditMode(true)
@@ -83,6 +163,8 @@ const WorkExpirence: FC<WorkExpirenceProps> = (props: WorkExpirenceProps) => {
83163
<WorkExpirenceCard
84164
key={uniqueKey || `${work.position || 'experience'}-${index}`}
85165
work={work}
166+
skillNamesMap={skillNamesMap}
167+
showSkills={!loadingSkills && areSkillsLoaded(work)}
86168
/>
87169
)
88170
})

0 commit comments

Comments
 (0)