Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 3aa1bf4

Browse files
committed
fix: skillMatched
don't use skillMatched from the server and calculate it client-side correctly
1 parent 0a9cda2 commit 3aa1bf4

File tree

6 files changed

+46
-33
lines changed

6 files changed

+46
-33
lines changed

src/components/SkillsList/index.jsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* SkillsList
33
*
44
* Shows list of skills with "N more" link which is showing tooltip with a full list of skills.
5-
* If `showMatches = true` it marks matched and not matched required skills.
65
*/
76
import React, { useCallback, useState } from "react";
87
import PT from "prop-types";
@@ -13,11 +12,7 @@ import IconCross from "../../assets/images/icon-cross.svg";
1312
import { usePopper } from "react-popper";
1413
import OutsideClickHandler from "react-outside-click-handler";
1514

16-
const SkillsList = ({
17-
skills,
18-
limit = 3,
19-
showMatches = false,
20-
}) => {
15+
const SkillsList = ({ skills, limit = 3 }) => {
2116
const skillsToShow = skills.slice(0, limit);
2217
const skillsToHide = skills.slice(limit);
2318

@@ -124,7 +119,6 @@ export const skillShape = PT.shape({
124119
SkillsList.propTypes = {
125120
skills: PT.arrayOf(skillShape),
126121
limit: PT.number,
127-
showMatches: PT.bool,
128122
};
129123

130124
export default SkillsList;

src/components/SkillsSummary/index.jsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ import PercentageBar from "components/PercentageBar";
1010
import SkillsList from "components/SkillsList";
1111
import "./styles.module.scss";
1212

13-
const SkillsSummary = ({ skills, skillMatched, limit }) => {
13+
const SkillsSummary = ({ skills, requiredSkills = [], limit }) => {
14+
const skillsMatched = _.intersectionBy(skills, requiredSkills, "id");
15+
const skillsMatchedRatio =
16+
requiredSkills.length > 0
17+
? skillsMatched.length / requiredSkills.length
18+
: 1;
19+
1420
return (
1521
<div>
1622
<div styleName="percentage">
17-
<PercentageBar ratio={skillMatched / 100} styleName="percentage-bar" />
18-
{Math.round(skillMatched)}% skill matched
23+
<PercentageBar ratio={skillsMatchedRatio} styleName="percentage-bar" />
24+
{Math.round(skillsMatchedRatio * 100)}% skill matched
1925
</div>
20-
<SkillsList
21-
skills={skills}
22-
limit={limit}
23-
showMatches
24-
/>
26+
<SkillsList skills={skills} limit={limit} />
2527
</div>
2628
);
2729
};
@@ -33,8 +35,8 @@ const skillShape = PT.shape({
3335

3436
SkillsSummary.propTypes = {
3537
skills: PT.arrayOf(skillShape),
38+
requiredSkills: PT.arrayOf(skillShape),
3639
limit: PT.number,
37-
skillMatched: PT.number,
3840
};
3941

4042
export default SkillsSummary;

src/constants/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export const CANDIDATE_STATUS_FILTERS = [
110110
* Candidates "sort by" values
111111
*/
112112
export const CANDIDATES_SORT_BY = {
113-
SKILL_MATCHED: "skillMatched",
113+
SKILL_MATCHED: "skillsMatched",
114114
HANDLE: "handle",
115115
};
116116

src/routes/MyTeamsDetails/components/TeamMembers/index.jsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ import ActionsMenu from "components/ActionsMenu";
1616
import Button from "components/Button";
1717
import Pagination from "components/Pagination";
1818
import { DAY_FORMAT, TEAM_MEMBERS_PER_PAGE } from "constants";
19-
import { formatMoney, formatReportIssueUrl, formatRequestExtensionUrl } from "utils/format";
19+
import {
20+
formatMoney,
21+
formatReportIssueUrl,
22+
formatRequestExtensionUrl,
23+
} from "utils/format";
2024
import Input from "components/Input";
2125
import { skillShape } from "components/SkillsList";
2226

@@ -132,7 +136,7 @@ const TeamMembers = ({ team }) => {
132136
<div styleName="table-cell cell-skills">
133137
<SkillsSummary
134138
skills={member.skills}
135-
skillMatched={member.skillMatched}
139+
requiredSkills={member.job.skills}
136140
/>
137141
</div>
138142
<div styleName="table-group-second-inner">
@@ -206,7 +210,7 @@ TeamMembers.propTypes = {
206210
firstName: PT.string,
207211
lastName: PT.string,
208212
skills: PT.arrayOf(skillShape),
209-
skillMatched: PT.number,
213+
skillsMatched: PT.number,
210214
})
211215
),
212216
}),

src/routes/PositionDetails/components/PositionCandidates/index.jsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { toastr } from "react-redux-toastr";
3333
const createSortCandidatesMethod = (sortBy) => (candidate1, candidate2) => {
3434
switch (sortBy) {
3535
case CANDIDATES_SORT_BY.SKILL_MATCHED:
36-
return candidate2.skillMatched - candidate1.skillMatched;
36+
return candidate2.skillsMatched - candidate1.skillsMatched;
3737
case CANDIDATES_SORT_BY.HANDLE:
3838
return new Intl.Collator().compare(
3939
candidate1.handle.toLowerCase(),
@@ -42,18 +42,31 @@ const createSortCandidatesMethod = (sortBy) => (candidate1, candidate2) => {
4242
}
4343
};
4444

45-
const PositionCandidates = ({
46-
candidates,
47-
candidateStatus,
48-
updateCandidate,
49-
}) => {
45+
/**
46+
* Populates candidate objects with `skillsMatched` property
47+
* which define the number of candidate skills that match position skills
48+
*
49+
* @param {object} position position
50+
* @param {object} candidate candidate for position
51+
*/
52+
const populateSkillsMatched = (position, candidate) => ({
53+
...candidate,
54+
skillsMatched: _.intersectionBy(position.skills, candidate.skills, "id"),
55+
});
56+
57+
const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {
58+
const { candidates } = position;
5059
const [sortBy, setSortBy] = useState(CANDIDATES_SORT_BY.SKILL_MATCHED);
5160
const filteredCandidates = useMemo(
5261
() =>
53-
_.filter(candidates, { status: candidateStatus }).sort(
54-
createSortCandidatesMethod(sortBy)
55-
),
56-
[candidates, candidateStatus, sortBy]
62+
_.chain(candidates)
63+
.map((candidate) => populateSkillsMatched(position, candidate))
64+
.filter({
65+
status: candidateStatus,
66+
})
67+
.value()
68+
.sort(createSortCandidatesMethod(sortBy)),
69+
[candidates, candidateStatus, sortBy, position]
5770
);
5871

5972
const onSortByChange = useCallback(
@@ -158,7 +171,7 @@ const PositionCandidates = ({
158171
<div styleName="table-cell cell-skills">
159172
<SkillsSummary
160173
skills={candidate.skills}
161-
skillMatched={candidate.skillMatched}
174+
requiredSkills={position.skills}
162175
limit={7}
163176
/>
164177
{candidate.resumeLink && (
@@ -221,7 +234,7 @@ const PositionCandidates = ({
221234
};
222235

223236
PositionCandidates.propType = {
224-
candidates: PT.array,
237+
position: PT.object,
225238
candidateStatus: PT.oneOf(Object.values(CANDIDATE_STATUS)),
226239
};
227240

src/routes/PositionDetails/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const PositionDetails = ({ teamId, positionId }) => {
4646
}
4747
/>
4848
<PositionCandidates
49-
candidates={position.candidates}
49+
position={position}
5050
candidateStatus={candidateStatus}
5151
updateCandidate={updateCandidate}
5252
/>

0 commit comments

Comments
 (0)