Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d089a5f

Browse files
authoredJun 1, 2021
Merge pull request #288 from yoution/feature/role-jd
Role & Skills Intake - Job Description Module
2 parents a372c82 + c46d5ff commit d089a5f

File tree

18 files changed

+359
-33
lines changed

18 files changed

+359
-33
lines changed
 

‎src/routes/InputSkills/components/AddAnotherModal/index.jsx renamed to ‎src/components/AddAnotherModal/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import React from "react";
88
import PT from "prop-types";
99
import Modal from "react-responsive-modal";
1010
import Button from "components/Button";
11-
import IconCrossLight from "../../../../assets/images/icon-cross-light.svg";
12-
import IconSingleManAdd from "../../../../assets/images/icon-single-man-add.svg";
11+
import IconCrossLight from "../../assets/images/icon-cross-light.svg";
12+
import IconSingleManAdd from "../../assets/images/icon-single-man-add.svg";
1313
import "./styles.module.scss";
1414
import CenteredSpinner from "components/CenteredSpinner";
1515

‎src/routes/InputSkills/components/Completeness/index.jsx renamed to ‎src/components/Completeness/index.jsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import cn from "classnames";
1010
import PT from "prop-types";
1111
import CompleteProgress from "../CompleteProgress";
1212
import "./styles.module.scss";
13-
import IconListQuill from "../../../../assets/images/icon-list-quill.svg";
13+
import IconListQuill from "../../assets/images/icon-list-quill.svg";
1414

15-
function Completeness({ isDisabled, onClick, buttonLabel, stage }) {
15+
function Completeness({ title, backgroundIcon, isDisabled, backgroundImage, onClick, buttonLabel, stage }) {
1616
return (
17-
<div styleName="completeness">
17+
<div styleName="completeness"
18+
style={{
19+
backgroundImage,
20+
}}
21+
>
1822
<CompleteProgress
1923
percentDone={stage === 1 ? 26 : stage === 2 ? 52 : 98}
2024
/>
@@ -26,7 +30,7 @@ function Completeness({ isDisabled, onClick, buttonLabel, stage }) {
2630
{ done: stage > 1 }
2731
)}
2832
>
29-
Input Skills
33+
Input {title}
3034
</li>
3135
<li
3236
styleName={cn(
@@ -49,7 +53,7 @@ function Completeness({ isDisabled, onClick, buttonLabel, stage }) {
4953
>
5054
{buttonLabel}
5155
</Button>
52-
<IconListQuill styleName="transparent-icon" />
56+
{backgroundIcon}
5357
</div>
5458
);
5559
}
@@ -59,6 +63,9 @@ Completeness.propTypes = {
5963
onClick: PT.func,
6064
buttonLabel: PT.string,
6165
stage: PT.number,
66+
title: PT.string,
67+
backgroundImage: PT.string,
68+
backgroundIcon: PT.string
6269
};
6370

6471
export default Completeness;

‎src/routes/InputSkills/components/Completeness/styles.module.scss renamed to ‎src/components/Completeness/styles.module.scss

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
@include rounded-card;
55
padding: 12px;
66
position: relative;
7-
background-image: linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%);
87
width: 250px;
98
color: #fff;
9+
10+
> svg {
11+
position: absolute;
12+
right: -50px;
13+
top: 85px;
14+
opacity: 10%;
15+
width: 144px;
16+
height: 144px;
17+
}
1018
}
1119

1220
.list {
@@ -47,12 +55,3 @@
4755
}
4856
}
4957
}
50-
51-
.transparent-icon {
52-
position: absolute;
53-
right: -50px;
54-
top: 85px;
55-
opacity: 10%;
56-
width: 144px;
57-
height: 144px;
58-
}

‎src/routes/InputSkills/components/ResultCard/index.jsx renamed to ‎src/components/ResultCard/index.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
*/
77
import React, { useState } from "react";
88
import "./styles.module.scss";
9-
import IconEarthCheck from "../../../../assets/images/icon-earth-check.svg";
10-
import IconMultipleUsers from "../../../../assets/images/icon-multiple-users.svg";
11-
import IconMultipleActionsCheck from "../../../../assets/images/icon-multiple-actions-check-2.svg";
12-
import IconTeamMeetingChat from "../../../../assets/images/icon-team-meeting-chat.svg";
13-
import Curve from "../../../../assets/images/curve.svg";
9+
import IconEarthCheck from "../../assets/images/icon-earth-check.svg";
10+
import IconMultipleUsers from "../../assets/images/icon-multiple-users.svg";
11+
import IconMultipleActionsCheck from "../../assets/images/icon-multiple-actions-check-2.svg";
12+
import IconTeamMeetingChat from "../../assets/images/icon-team-meeting-chat.svg";
13+
import Curve from "../../assets/images/curve.svg";
1414
import Button from "components/Button";
1515

1616
function ResultCard() {

‎src/routes/InputSkills/components/SearchCard/index.jsx renamed to ‎src/components/SearchCard/index.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
*/
66
import React, { useEffect, useState } from "react";
77
import "./styles.module.scss";
8-
import IconEarthSearch from "../../../../assets/images/icon-earth-search.svg";
9-
import WorldMapDotted from "../../../../assets/images/world-map-dotted.svg";
10-
import WorldMapSearch1 from "../../../../assets/images/world-map-search1.svg";
11-
import WorldMapSearch2 from "../../../../assets/images/world-map-search2.svg";
8+
import IconEarthSearch from "../../assets/images/icon-earth-search.svg";
9+
import WorldMapDotted from "../../assets/images/world-map-dotted.svg";
10+
import WorldMapSearch1 from "../../assets/images/world-map-search1.svg";
11+
import WorldMapSearch2 from "../../assets/images/world-map-search2.svg";
1212

1313
function SearchCard() {
1414
const [searchState, setSearchState] = useState(null);

‎src/root.component.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import JobForm from "./routes/JobForm";
1111
import TeamAccess from "./routes/TeamAccess";
1212
import CreateNewTeam from "./routes/CreateNewTeam";
1313
import InputSkills from "./routes/InputSkills";
14+
import InputJobDescription from "./routes/InputJobDescription";
1415
import ReduxToastr from "react-redux-toastr";
1516
import store from "./store";
1617
import "./styles/main.vendor.scss";
@@ -33,6 +34,7 @@ export default function Root() {
3334
<ResourceBookingForm path="/taas/myteams/:teamId/rb/:resourceBookingId/edit" />
3435
<PositionDetails path="/taas/myteams/:teamId/positions/:positionId/candidates" />
3536
<TeamAccess path="/taas/myteams/:teamId/access" />
37+
<InputJobDescription path="/taas/myteams/createnewteam/jd" />
3638
<InputSkills path="/taas/myteams/createnewteam/:projectId/skills" />
3739
<SelectRole path="/taas/myteams/createnewteam/:projectId/role" />
3840
</Router>

‎src/routes/CreateNewTeam/index.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ function CreateNewTeam() {
3030
});
3131
};
3232

33+
const goToJobDescription = ()=> {
34+
navigate(`/taas/myteams/createnewteam/jd`);
35+
}
36+
3337
return (
3438
<Page title="Create New Team">
3539
<PageHeader title="Create New Team" />
@@ -55,7 +59,7 @@ function CreateNewTeam() {
5559
description="You would like to use a description to explain what you need."
5660
icon={<IconOfficeFileText />}
5761
backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)"
58-
isDisabled
62+
onClick={goToJobDescription}
5963
/>
6064
</Page>
6165
);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Temporary Popup for skill list
3+
* show skill list
4+
*/
5+
import React from "react";
6+
import _ from "lodash";
7+
import PT from "prop-types";
8+
import Modal from "react-responsive-modal";
9+
import Button from "components/Button";
10+
import IconCrossLight from "../../../../assets/images/icon-cross-light.svg";
11+
import IconSingleManAdd from "../../../../assets/images/icon-single-man-add.svg";
12+
import "./styles.module.scss";
13+
import CenteredSpinner from "components/CenteredSpinner";
14+
15+
const modalStyle = {
16+
borderRadius: "8px",
17+
padding: "32px 32px 22px 32px",
18+
maxWidth: "460px",
19+
width: "100%",
20+
margin: 0,
21+
"overflow-x": "hidden",
22+
};
23+
24+
const containerStyle = {
25+
padding: "10px",
26+
};
27+
28+
function Popup({ open, skills, onClose, isLoading, onContinueClick }) {
29+
return (
30+
<Modal
31+
open={open}
32+
center
33+
onClose={onClose}
34+
closeIcon={
35+
<IconCrossLight height="18px" width="18px" styleName="cross" />
36+
}
37+
styles={{
38+
modal: modalStyle,
39+
modalContainer: containerStyle,
40+
}}
41+
>
42+
<div styleName="modal-body">
43+
{isLoading ? (
44+
<>
45+
<CenteredSpinner />
46+
<h5>loading skills</h5>
47+
</>
48+
) : (
49+
<>
50+
<IconSingleManAdd />
51+
<h5>skills</h5>
52+
{_.map(skills, (s) => {
53+
return <div>{s.tag}</div>;
54+
})}
55+
</>
56+
)}
57+
</div>
58+
<div styleName="button-group">
59+
<Button
60+
type="primary"
61+
size="medium"
62+
disabled={isLoading}
63+
onClick={onContinueClick}
64+
>
65+
Continue
66+
</Button>
67+
</div>
68+
</Modal>
69+
);
70+
}
71+
72+
Popup.propTypes = {
73+
open: PT.bool,
74+
onClose: PT.func,
75+
isLoading: PT.bool,
76+
onContinueClick: PT.func,
77+
skills: PT.arrayOf(PT.shape()),
78+
};
79+
80+
export default Popup;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
@import "styles/include";
2+
3+
.button-group {
4+
display: flex;
5+
flex-direction: row;
6+
justify-content: center;
7+
align-items: flex-end;
8+
:first-child {
9+
margin-right: 8px;
10+
}
11+
}
12+
13+
.modal-body {
14+
display: flex;
15+
flex-direction: column;
16+
justify-content: flex-start;
17+
align-items: center;
18+
text-align: center;
19+
margin-bottom: 80px;
20+
21+
svg {
22+
width: 48px;
23+
height: 48px;
24+
margin-bottom: 16px;
25+
}
26+
27+
h5 {
28+
@include font-barlow-condensed;
29+
font-size: 34px;
30+
color: #1e94a3;
31+
text-transform: uppercase;
32+
font-weight: 500;
33+
margin-bottom: 10px;
34+
}
35+
36+
p {
37+
@include font-roboto;
38+
font-size: 16px;
39+
color: #555555;
40+
line-height: 26px;
41+
}
42+
}
43+
44+
.cross {
45+
g {
46+
stroke: #000;
47+
}
48+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Input Job Description page
3+
*
4+
*/
5+
import React, { useCallback, useEffect, useState } from "react";
6+
import { useData } from "hooks/useData";
7+
import { navigate } from "@reach/router";
8+
import { toastr } from "react-redux-toastr";
9+
import MarkdownEditor from "../../components/MarkdownEditor";
10+
import { getSkillsByJobDescription } from "../../services/teams";
11+
import Page from "components/Page";
12+
import PageHeader from "components/PageHeader";
13+
import PT from "prop-types";
14+
import Completeness from "components/Completeness";
15+
import { getSkills } from "services/skills";
16+
import LoadingIndicator from "components/LoadingIndicator";
17+
import SearchCard from "components/SearchCard";
18+
import ResultCard from "components/ResultCard";
19+
import AddAnotherModal from "components/AddAnotherModal";
20+
import SkillListPopup from "./components/Popup";
21+
import "./styles.module.scss";
22+
import withAuthentication from "../../hoc/withAuthentication";
23+
import IconOfficeFileText from "../../assets/images/icon-office-file-text.svg";
24+
25+
function InputJobDescription() {
26+
const [jdString, setJdString] = useState("");
27+
const [searchState, setSearchState] = useState(null);
28+
const [modalOpen, setModalOpen] = useState(false);
29+
const [skillModalOpen, setSkillModalOpen] = useState(false);
30+
const [submitDone, setSubmitDone] = useState(false);
31+
const [skills, setSkills] = useState([]);
32+
const [isLoadingSkills, setIsLoadingSkills] = useState(false);
33+
34+
const onSearch = useCallback(
35+
(value) => {
36+
setSkillModalOpen(true);
37+
setIsLoadingSkills(true);
38+
getSkillsByJobDescription(jdString)
39+
.then((response) => {
40+
setSkills(response.data);
41+
setIsLoadingSkills(false);
42+
setSkillModalOpen(true);
43+
})
44+
.catch(() => {
45+
setIsLoadingSkills(false);
46+
});
47+
},
48+
[jdString]
49+
);
50+
51+
const onConfirationClick = useCallback(() => {
52+
setSearchState("searching");
53+
setTimeout(() => {
54+
setSearchState("done");
55+
}, 3000);
56+
}, []);
57+
58+
const addAnother = useCallback(() => {
59+
// navigate(`/taas/myteams/createnewteam/${projectId}/role`);
60+
}, []);
61+
62+
const submitJob = () => {
63+
setSubmitDone(false);
64+
setModalOpen(true);
65+
setTimeout(() => {
66+
setSubmitDone(true);
67+
}, 3000);
68+
};
69+
70+
const onEditChange = useCallback((value) => {
71+
setJdString(value);
72+
}, []);
73+
74+
return (
75+
<div>
76+
{!searchState ? (
77+
<div styleName="page">
78+
<div styleName='edit-container'>
79+
<PageHeader
80+
title="Input Job Description"
81+
backTo="/taas/myteams/createnewteam"
82+
/>
83+
<MarkdownEditor
84+
height='482px'
85+
placeholder="input job description"
86+
onChange={onEditChange}
87+
/>
88+
</div>
89+
<Completeness
90+
title="Job Desccription"
91+
isDisabled={jdString.length < 10}
92+
backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)"
93+
backgroundIcon={<IconOfficeFileText />}
94+
onClick={onSearch}
95+
buttonLabel="Search"
96+
stage={1}
97+
/>
98+
<SkillListPopup
99+
open={skillModalOpen}
100+
skills={skills}
101+
onClose={() => setSkillModalOpen(false)}
102+
isLoading={isLoadingSkills}
103+
onContinueClick={onConfirationClick}
104+
/>
105+
</div>
106+
) : searchState === "searching" ? (
107+
<div styleName="page">
108+
<SearchCard />
109+
<Completeness
110+
title="Job Desccription"
111+
backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)"
112+
backgroundIcon={<IconOfficeFileText />}
113+
isDisabled
114+
buttonLabel="Submit Request"
115+
stage={2}
116+
/>
117+
</div>
118+
) : (
119+
<div styleName="page">
120+
<ResultCard />
121+
<Completeness
122+
title="Job Desccription"
123+
backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)"
124+
backgroundIcon={<IconOfficeFileText />}
125+
buttonLabel="Submit Request"
126+
stage={3}
127+
onClick={submitJob}
128+
/>
129+
<AddAnotherModal
130+
open={modalOpen}
131+
onClose={() => setModalOpen(false)}
132+
submitDone={submitDone}
133+
addAnother={addAnother}
134+
/>
135+
</div>
136+
)}
137+
</div>
138+
);
139+
}
140+
141+
InputJobDescription.propTypes = {
142+
projectId: PT.string,
143+
};
144+
145+
export default withAuthentication(InputJobDescription);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.page {
2+
display: flex;
3+
flex-direction: row;
4+
justify-content: center;
5+
align-items: flex-start;
6+
margin: 42px 35px;
7+
8+
.edit-container {
9+
background-color: #ffffff;
10+
border-radius: 8px;
11+
max-width: 746px;
12+
position: relative;
13+
margin-right: 30px;
14+
padding: 0 30px 30px;
15+
flex: 1;
16+
}
17+
}

‎src/routes/InputSkills/index.jsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ import { useData } from "hooks/useData";
1212
import { navigate } from "@reach/router";
1313
import { toastr } from "react-redux-toastr";
1414
import PT from "prop-types";
15-
import SkillsList from "./components/SkillsList";
16-
import Completeness from "./components/Completeness";
15+
import Completeness from "components/Completeness";
1716
import "./styles.module.scss";
1817
import { getSkills } from "services/skills";
1918
import LoadingIndicator from "components/LoadingIndicator";
20-
import SearchCard from "./components/SearchCard";
21-
import ResultCard from "./components/ResultCard";
19+
import SearchCard from "components/SearchCard";
20+
import ResultCard from "components/ResultCard";
2221
import { createJob } from "services/jobs";
23-
import AddAnotherModal from "./components/AddAnotherModal";
22+
import AddAnotherModal from "components/AddAnotherModal";
23+
import SkillsList from "./components/SkillsList";
2424
import withAuthentication from "../../hoc/withAuthentication";
25+
import IconListQuill from "../../assets/images/icon-list-quill.svg";
2526

2627
function InputSkills({ projectId }) {
2728
const [selectedSkills, setSelectedSkills] = useState([]);
@@ -91,6 +92,9 @@ function InputSkills({ projectId }) {
9192
toggleSkill={toggleSkill}
9293
/>
9394
<Completeness
95+
title='Skills'
96+
backgroundImage='linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%)'
97+
backgroundIcon={<IconListQuill/>}
9498
isDisabled={selectedSkills.length < 1}
9599
onClick={search}
96100
buttonLabel="Search"
@@ -100,12 +104,21 @@ function InputSkills({ projectId }) {
100104
) : searchState === "searching" ? (
101105
<div styleName="page">
102106
<SearchCard />
103-
<Completeness isDisabled buttonLabel="Submit Request" stage={2} />
107+
<Completeness
108+
title='Skills'
109+
backgroundImage='linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%)'
110+
backgroundIcon={<IconListQuill/>}
111+
isDisabled
112+
buttonLabel="Submit Request"
113+
stage={2} />
104114
</div>
105115
) : (
106116
<div styleName="page">
107117
<ResultCard />
108118
<Completeness
119+
title='Skills'
120+
backgroundImage='linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%)'
121+
backgroundIcon={<IconListQuill/>}
109122
buttonLabel="Submit Request"
110123
stage={3}
111124
onClick={submitJob}

‎src/services/teams.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ export const getV5UserProfile = () => {
3131
return axios.get(`${config.API.V5}/taas-teams/me`);
3232
};
3333

34+
/**
35+
* Get skills by job description
36+
* @param {string} description
37+
* @returns {Promise<{}>} skills list
38+
*/
39+
export const getSkillsByJobDescription = (description) => {
40+
return axios.post(`${config.API.V5}/taas-teams/getSkillsByJobDescription`, {
41+
description,
42+
});
43+
};
44+
3445
/**
3546
* Get team by id.
3647
*

0 commit comments

Comments
 (0)
This repository has been archived.