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

Commit 47d1319

Browse files
committed
fix: issue #416 #412
1 parent 27c890e commit 47d1319

File tree

9 files changed

+252
-14
lines changed

9 files changed

+252
-14
lines changed

src/routes/CreateNewTeam/components/ResultCard/index.jsx

+34-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
import React, { useState, useEffect } from "react";
88
import PT from "prop-types";
9+
import _ from "lodash";
910
import { getAuthUserProfile } from "@topcoder/micro-frontends-navbar-app";
1011
import "./styles.module.scss";
1112
import IconEarthCheck from "../../../../assets/images/icon-earth-check.svg";
@@ -15,6 +16,7 @@ import IconTeamMeetingChat from "../../../../assets/images/icon-team-meeting-cha
1516
import EditRoleForm from "../EditRoleForm";
1617
import Curve from "../../../../assets/images/curve.svg";
1718
import CircularProgressBar from "../CircularProgressBar";
19+
import SkillTag from "../SkillTag";
1820
import Button from "components/Button";
1921
import { formatMoney } from "utils/format";
2022

@@ -27,7 +29,13 @@ function formatPercent(value) {
2729
return `${Math.round(value * 100)}%`;
2830
}
2931

30-
function ResultCard({ role, currentRole, onSaveEditRole }) {
32+
function ResultCard({
33+
role,
34+
currentRole,
35+
onSaveEditRole,
36+
matchedSkills,
37+
unMatchedSkills,
38+
}) {
3139
const {
3240
numberOfMembersAvailable,
3341
isExternalMember,
@@ -249,17 +257,29 @@ function ResultCard({ role, currentRole, onSaveEditRole }) {
249257
<div styleName="content">
250258
<div styleName="matching-info">
251259
<div>
252-
<CircularProgressBar
253-
size="160"
254-
progress={skillsMatch}
255-
strokeWidth="6"
256-
children={
257-
<div styleName="progressbar-child">
258-
<h4>{formatPercent(skillsMatch)}</h4>
259-
<p>Skills Match</p>
260-
</div>
261-
}
262-
/>
260+
{matchedSkills.length
261+
? _.map(matchedSkills, (s) => (
262+
<SkillTag name={s.name} id={s.id} />
263+
))
264+
: null}
265+
{matchedSkills.length
266+
? _.map(unMatchedSkills, (s) => (
267+
<SkillTag name={s.name} id={s.id} unmatched />
268+
))
269+
: null}
270+
{!matchedSkills.length ? (
271+
<CircularProgressBar
272+
size="160"
273+
progress={skillsMatch}
274+
strokeWidth="6"
275+
children={
276+
<div styleName="progressbar-child">
277+
<h4>{formatPercent(skillsMatch)}</h4>
278+
<p>Skills Match</p>
279+
</div>
280+
}
281+
/>
282+
) : null}
263283
</div>
264284
<div styleName="vertical-line" />
265285
<div>
@@ -279,6 +299,8 @@ function ResultCard({ role, currentRole, onSaveEditRole }) {
279299

280300
ResultCard.propTypes = {
281301
role: PT.object,
302+
matchedSkills: PT.array,
303+
unMatchedSkills: PT.array,
282304
currentRole: PT.object,
283305
onSaveEditRole: PT.func,
284306
};

src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Router, navigate } from "@reach/router";
22
import _ from "lodash";
3-
import React, { useCallback, useState, useEffect } from "react";
3+
import React, { useCallback, useState, useEffect, useMemo } from "react";
44
import { useDispatch, useSelector } from "react-redux";
5+
import { useData } from "hooks/useData";
6+
import { getSkills } from "services/skills";
57
import { searchRoles } from "services/teams";
68
import { isCustomRole, setCurrentStage } from "utils/helpers";
79
import {
@@ -21,9 +23,42 @@ function SearchAndSubmit(props) {
2123

2224
const [searchState, setSearchState] = useState(null);
2325
const [isNewRole, setIsNewRole] = useState(false);
24-
26+
const [skills] = useData(getSkills);
2527
const { matchingRole } = useSelector((state) => state.searchedRoles);
2628

29+
const matchedSkills = useMemo(() => {
30+
if (
31+
skills &&
32+
matchingRole &&
33+
matchingRole.listOfSkills &&
34+
searchObject &&
35+
searchObject.skills &&
36+
searchObject.skills.length
37+
) {
38+
return _.map(searchObject.skills, (s) =>
39+
_.find(skills, (skill) => skill.id === s)
40+
);
41+
} else {
42+
return [];
43+
}
44+
}, [skills, matchingRole, searchObject]);
45+
46+
const unMatchedSkills = useMemo(() => {
47+
if (
48+
skills &&
49+
matchingRole &&
50+
matchingRole.listOfSkills &&
51+
matchedSkills.length
52+
) {
53+
const list = _.filter(
54+
matchingRole.listOfSkills,
55+
(l) => !_.find(matchedSkills, (m) => m.name === l)
56+
);
57+
return _.map(list, (s) => _.find(skills, (skill) => skill.name === s));
58+
} else {
59+
return [];
60+
}
61+
}, [skills, matchingRole, matchedSkills]);
2762
useEffect(() => {
2863
const isFromInputPage =
2964
searchObject.role ||
@@ -99,13 +134,17 @@ function SearchAndSubmit(props) {
99134
path="search"
100135
previousSearchId={previousSearchId}
101136
addedRoles={addedRoles}
137+
matchedSkills={matchedSkills}
138+
unMatchedSkills={unMatchedSkills}
102139
searchState={searchState}
103140
matchingRole={matchingRole}
104141
isNewRole={isNewRole}
105142
{...props}
106143
/>
107144
<SubmitContainer
108145
path="result"
146+
matchedSkills={matchedSkills}
147+
unMatchedSkills={unMatchedSkills}
109148
addedRoles={addedRoles}
110149
previousSearchId={previousSearchId}
111150
matchingRole={matchingRole}

src/routes/CreateNewTeam/components/SearchContainer/index.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import AddAnotherModal from "../AddAnotherModal";
2020
import "./styles.module.scss";
2121

2222
function SearchContainer({
23+
matchedSkills,
24+
unMatchedSkills,
2325
isNewRole,
2426
stages,
2527
progressStyle,
@@ -68,6 +70,8 @@ function SearchContainer({
6870
if (!isCustomRole(matchingRole))
6971
return (
7072
<ResultCard
73+
matchedSkills={matchedSkills}
74+
unMatchedSkills={unMatchedSkills}
7175
role={matchingRole}
7276
onSaveEditRole={onSaveEditRole}
7377
currentRole={currentRole}
@@ -114,6 +118,8 @@ function SearchContainer({
114118
SearchContainer.propTypes = {
115119
isNewRole: PT.bool,
116120
stages: PT.array,
121+
matchedSkills: PT.array,
122+
unMatchedSkills: PT.array,
117123
progressStyle: PT.string,
118124
previousSearchId: PT.string,
119125
navigate: PT.func,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Skill Tag
3+
* An item for the matched skill result page.
4+
* Shows an image and the name of the skill.
5+
*/
6+
import React from "react";
7+
import PT from "prop-types";
8+
import IconSkill from "../../../../assets/images/icon-skill.svg";
9+
import "./styles.module.scss";
10+
import cn from "classnames";
11+
12+
const assets = require.context(
13+
"../../../../assets/images/all-skill-images",
14+
false,
15+
/svg/
16+
);
17+
18+
function SkillTag({ id, name, unmatched }) {
19+
return (
20+
<div styleName={cn("tag", { unmatched })}>
21+
{assets && assets.keys().includes(`./id-${id}.svg`) ? (
22+
<img
23+
src={assets(`./id-${id}.svg`).default}
24+
alt={name}
25+
styleName="image"
26+
/>
27+
) : (
28+
<IconSkill styleName="image" />
29+
)}
30+
<p styleName="item-text">{name}</p>
31+
</div>
32+
);
33+
}
34+
35+
SkillTag.propTypes = {
36+
id: PT.string,
37+
name: PT.string,
38+
unmatched: PT.bool,
39+
};
40+
41+
export default SkillTag;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.tag {
2+
font-family: Roboto;
3+
display: inline-flex;
4+
align-items: center;
5+
height: 32px;
6+
border-radius: 32px;
7+
border: 1px solid #0AB88A;
8+
color: #2A2A2A;
9+
font-size: 10px;
10+
padding: 8px;
11+
line-height: 12px;
12+
margin-right: 6px;
13+
margin-bottom: 6px;
14+
15+
16+
.image {
17+
height: 20px;
18+
}
19+
&.unmatched {
20+
border-color: #EF476F;
21+
background-color: #E9E9E9;
22+
color: #2A2A2A;
23+
24+
}
25+
}
26+
.item-card {
27+
border: 1px solid #d4d4d4;
28+
border-radius: 5px;
29+
width: 117px;
30+
height: 107px;
31+
display: flex;
32+
flex-direction: column;
33+
justify-content: space-evenly;
34+
align-items: center;
35+
margin: 0 0 24px 24px;
36+
cursor: pointer;
37+
color: #555;
38+
font-weight: 500;
39+
40+
&.selected {
41+
border-color: #0ab88a;
42+
background-color: #e0faf3;
43+
font-weight: 500;
44+
color: #2a2a2a;
45+
}
46+
}
47+
48+
.item-text {
49+
text-align: center;
50+
font-size: 14px;
51+
}

src/routes/CreateNewTeam/components/SubmitContainer/index.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { postTeamRequest } from "services/teams";
3030
import NoMatchingProfilesResultCard from "../NoMatchingProfilesResultCard";
3131

3232
function SubmitContainer({
33+
matchedSkills,
34+
unMatchedSkills,
3335
stages,
3436
setStages,
3537
progressStyle,
@@ -131,6 +133,8 @@ function SubmitContainer({
131133
<div styleName="page">
132134
{!isCustomRole(matchingRole) ? (
133135
<ResultCard
136+
matchedSkills={matchedSkills}
137+
unMatchedSkills={unMatchedSkills}
134138
role={matchingRole}
135139
onSaveEditRole={onSaveEditRole}
136140
currentRole={currentRole}
@@ -175,6 +179,8 @@ function SubmitContainer({
175179
}
176180

177181
SubmitContainer.propTypes = {
182+
matchedSkills: PT.array,
183+
unMatchedSkills: PT.array,
178184
stages: PT.array,
179185
setStages: PT.func,
180186
progressStyle: PT.string,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Role Static Item
3+
* An item for the Role List component.
4+
*/
5+
import React from "react";
6+
import { navigate } from "@reach/router";
7+
import PT from "prop-types";
8+
import cn from "classnames";
9+
import FallbackIcon from "../../../../../../assets/images/icon-role-fallback.svg";
10+
import "./styles.module.scss";
11+
12+
function RoleStaticCard() {
13+
const goToJdPage = () => {
14+
navigate("/taas/createnewteam/jd");
15+
};
16+
17+
return (
18+
<div styleName="item-card">
19+
<p styleName="item-text">Don't see what you're looking for?</p>
20+
<button
21+
styleName="button"
22+
onClick={(event) => {
23+
event.preventDefault();
24+
event.stopPropagation();
25+
goToJdPage();
26+
}}
27+
>
28+
Describe your needs
29+
</button>
30+
</div>
31+
);
32+
}
33+
34+
export default RoleStaticCard;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@import "styles/include";
2+
3+
.item-card {
4+
border: 1px solid #d4d4d4;
5+
border-radius: 5px;
6+
padding: 12px 16px;
7+
width: 212px;
8+
height: 136px;
9+
display: flex;
10+
flex-direction: column;
11+
justify-content: space-evenly;
12+
align-items: flex-start;
13+
margin: 0 0 23px 23px;
14+
}
15+
16+
.item-text {
17+
@include font-barlow;
18+
font-size: 16px;
19+
font-weight: 600;
20+
line-height: 20px;
21+
text-transform: uppercase;
22+
}
23+
24+
.button {
25+
font-size: 14px;
26+
line-height: 22px;
27+
padding: 0;
28+
outline: none;
29+
background: none;
30+
color: #0d61bf;
31+
border: none;
32+
text-align: left;
33+
34+
&:hover {
35+
text-decoration: underline;
36+
}
37+
}

src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/index.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import React, { useCallback, useState } from "react";
88
import PT from "prop-types";
99
import RoleItem from "../RoleItem";
10+
import RoleStaticCard from "../RoleStaticCard";
1011
import ItemList from "../../../../components/ItemList";
1112

1213
function RolesList({ roles, selectedRoleId, onDescriptionClick, toggleRole }) {
@@ -43,6 +44,7 @@ function RolesList({ roles, selectedRoleId, onDescriptionClick, toggleRole }) {
4344
isSelected={selectedRoleId === id}
4445
/>
4546
))}
47+
<RoleStaticCard />
4648
</ItemList>
4749
);
4850
}

0 commit comments

Comments
 (0)