Skip to content

Commit 638cb68

Browse files
committed
TSJR-314 - add suggestions drodpdown
1 parent 0d8e64f commit 638cb68

File tree

5 files changed

+121
-17
lines changed

5 files changed

+121
-17
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.wrap {
4+
position: relative;
5+
6+
&.isDirty> :global(.input-wrapper):focus-within + .dropdown {
7+
display: block;
8+
}
9+
}
10+
11+
.dropdown {
12+
position: absolute;
13+
top: $sp-12;
14+
left: 0;
15+
right: 0;
16+
17+
background: $tc-white;
18+
19+
border: 1px solid $black-20;
20+
border-radius: $sp-1;
21+
padding: $sp-2;
22+
23+
z-index: 9;
24+
25+
max-height: 160px;
26+
overflow: auto;
27+
28+
display: none;
29+
}
30+
31+
.categoryList {
32+
> li + li {
33+
margin-top: $sp-4;
34+
}
35+
}
36+
37+
.skillList {
38+
margin-top: $sp-2;
39+
margin-left: $sp-4;
40+
41+
> li + li {
42+
margin-top: $sp-2;
43+
}
44+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { FC, PropsWithChildren, useMemo } from 'react'
2+
import classNames from 'classnames'
3+
4+
import { StandardizedSkill, StandardizedSkillCategory } from '../../../services'
5+
import { findSkillsMatches, groupSkillsByCategory } from '../../../lib'
6+
7+
import styles from './SimilarSkillsDropdown.module.scss'
8+
9+
interface SimilarSkillsDropdownProps extends PropsWithChildren {
10+
categories: StandardizedSkillCategory[]
11+
skillName?: string
12+
skills: StandardizedSkill[]
13+
isInputDirty?: boolean
14+
}
15+
16+
const SimilarSkillsDropdown: FC<SimilarSkillsDropdownProps> = props => {
17+
const skillsList = useMemo(() => (
18+
(props.skillName ? findSkillsMatches(props.skills ?? [], props.skillName) : [])
19+
), [props.skillName, props.skills])
20+
21+
const groupedSkills = useMemo(() => groupSkillsByCategory(skillsList), [skillsList])
22+
23+
const categories = useMemo(() => (
24+
props.categories.filter(c => !!groupedSkills[c.id])
25+
), [props.categories, groupedSkills])
26+
27+
return (
28+
<div className={classNames(styles.wrap, props.isInputDirty && styles.isDirty)}>
29+
{props.children}
30+
{props.skillName && skillsList.length > 0 && (
31+
<div className={styles.dropdown}>
32+
<ul className={styles.categoryList}>
33+
{categories.map(category => (
34+
<li key={category.id}>
35+
<div className='body-small-bold'>{category.name}</div>
36+
<ul className={styles.skillList}>
37+
{groupedSkills[category.id].map(skill => (
38+
<li key={skill.id} className='body-small'>{skill.name}</li>
39+
))}
40+
</ul>
41+
</li>
42+
))}
43+
</ul>
44+
</div>
45+
)}
46+
</div>
47+
)
48+
}
49+
50+
export default SimilarSkillsDropdown
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as SimilarSkillsDropdown } from './SimilarSkillsDropdown'

src/apps/admin/src/skills-manager/components/skill-modals/skill-form/SkillForm.tsx

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ChangeEvent, FC, ReactNode, useCallback, useEffect, useMemo, useState }
22
import { find, pick } from 'lodash'
33
import { toast } from 'react-toastify'
44

5-
import { Button, InputSelectReact, InputText, InputTextarea } from '~/libs/ui'
5+
import { Button, FormInputAutocompleteOption, InputSelectReact, InputText, InputTextarea } from '~/libs/ui'
66

77
import { SkillsManagerContextValue, useSkillsManagerContext } from '../../../context'
88
import { mapCategoryToSelectOption } from '../../../lib'
@@ -11,6 +11,7 @@ import {
1111
StandardizedSkill,
1212
StandardizedSkillCategory,
1313
} from '../../../services'
14+
import { SimilarSkillsDropdown } from '../similar-skills-dropdown'
1415

1516
import styles from './SkillForm.module.scss'
1617

@@ -158,21 +159,29 @@ const SkillForm: FC<SkillFormProps> = props => {
158159

159160
return (
160161
<form className={styles.form} onSubmit={handleFormSubmit}>
161-
<InputText
162-
dirty={formState.name.dirty}
163-
label='Skill Name'
164-
name='name'
165-
placeholder='Enter skill name'
166-
type='text'
167-
value={formValue.name}
168-
onChange={handleFormChanges}
169-
autoFocus
170-
onBlur={validateName}
171-
error={formState.name.error}
172-
tabIndex={0}
173-
disabled={props.isDisabled}
174-
forceUpdateValue={forceUpdate}
175-
/>
162+
<SimilarSkillsDropdown
163+
categories={categories}
164+
skillName={formValue.name}
165+
skills={skillsList}
166+
isInputDirty={formState.name.dirty}
167+
>
168+
<InputText
169+
dirty={formState.name.dirty}
170+
label='Skill Name'
171+
name='name'
172+
placeholder='Enter skill name'
173+
type='text'
174+
value={formValue.name}
175+
onChange={handleFormChanges}
176+
autoFocus
177+
onBlur={validateName}
178+
error={formState.name.error}
179+
tabIndex={0}
180+
disabled={props.isDisabled}
181+
forceUpdateValue={forceUpdate}
182+
autocomplete={FormInputAutocompleteOption.off}
183+
/>
184+
</SimilarSkillsDropdown>
176185
<InputTextarea
177186
dirty={formState.description.dirty}
178187
label='Skill Description'

src/apps/admin/src/skills-manager/lib/skills.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const groupSkillsByCategory = (skills: StandardizedSkill[]): GroupedSkill
3232
export const findSkillsMatches = (skills: StandardizedSkill[], skillsFilter: string): StandardizedSkill[] => {
3333
const filterRegex = new RegExp(escapeRegExp(skillsFilter), 'i')
3434
return skills.filter(skill => (
35-
filterRegex.test(skill.name) || filterRegex.test(skill.category.name)
35+
filterRegex.test(skill.name) || filterRegex.test(skill.category?.name ?? '')
3636
))
3737
}
3838

0 commit comments

Comments
 (0)