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

Commit 58c12e9

Browse files
committed
Role & Skills Intake - Job Description Module
1 parent 011fc84 commit 58c12e9

File tree

9 files changed

+329
-6
lines changed

9 files changed

+329
-6
lines changed

src/root.component.jsx

+2
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/CreateNewTeam/pages/InputSkills";
14+
import InputJobDescription from "./routes/CreateNewTeam/pages/InputJobDescription";
1415
import SelectRole from "./routes/CreateNewTeam/pages/SelectRole";
1516
import ReduxToastr from "react-redux-toastr";
1617
import store from "./store";
@@ -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/components/Completeness/index.jsx

+12-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import CompleteProgress from "../CompleteProgress";
1212
import "./styles.module.scss";
1313
import IconMultipleActionsCheck from "../../../../assets/images/icon-multiple-actions-check-2.svg";
1414
import IconListQuill from "../../../../assets/images/icon-list-quill.svg";
15+
import IconOfficeFileText from "../../../../assets/images/icon-office-file-text.svg";
1516

1617
function Completeness({
1718
extraStyleName,
@@ -21,6 +22,16 @@ function Completeness({
2122
stages,
2223
percentage,
2324
}) {
25+
26+
let backgroundIcon
27+
if (extraStyleName === "input-skills") {
28+
backgroundIcon= <IconListQuill styleName="transparent-icon" />
29+
} else if (extraStyleName === "input-job-description") {
30+
backgroundIcon= <IconOfficeFileText styleName="transparent-icon" />
31+
} else {
32+
backgroundIcon= <IconMultipleActionsCheck styleName="transparent-icon" />
33+
}
34+
2435
return (
2536
<div styleName={cn("completeness", extraStyleName)}>
2637
<CompleteProgress percentDone={percentage} />
@@ -44,11 +55,7 @@ function Completeness({
4455
>
4556
{buttonLabel}
4657
</Button>
47-
{extraStyleName === "input-skills" ? (
48-
<IconListQuill styleName="transparent-icon" />
49-
) : (
50-
<IconMultipleActionsCheck styleName="transparent-icon" />
51-
)}
58+
{backgroundIcon}
5259
</div>
5360
);
5461
}

src/routes/CreateNewTeam/components/Completeness/styles.module.scss

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
}
1212
}
1313

14+
.input-job-description {
15+
background-image: linear-gradient(135deg, #2984BD 0%, #0AB88A 100%);
16+
}
17+
1418
.input-skills {
1519
background-image: linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%);
1620
}

src/routes/CreateNewTeam/index.jsx

+5-1
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
);
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 SkillListPopup({ 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+
SkillListPopup.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 SkillListPopup;
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
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 { setCurrentStage } from "utils/helpers";
10+
import Page from "components/Page";
11+
import PT from "prop-types";
12+
import PageHeader from "components/PageHeader";
13+
import LoadingIndicator from "components/LoadingIndicator";
14+
import MarkdownEditor from "../../../../components/MarkdownEditor";
15+
import { getSkillsByJobDescription } from "../../../../services/teams";
16+
import Completeness from "../../components/Completeness";
17+
import { getSkills } from "services/skills";
18+
import SearchCard from "../../components/SearchCard";
19+
import ResultCard from "../../components/ResultCard";
20+
import AddAnotherModal from "../../components/AddAnotherModal";
21+
import SkillListPopup from "./components/SkillListPopup";
22+
import "./styles.module.scss";
23+
import withAuthentication from "../../../../hoc/withAuthentication";
24+
import IconOfficeFileText from "../../../../assets/images/icon-office-file-text.svg";
25+
26+
function InputJobDescription() {
27+
const [stages, setStages] = useState([
28+
{ name: "Input Job Desccription", isCurrent: true },
29+
{ name: "Search Member" },
30+
{ name: "Overview of the Results" },
31+
]);
32+
const [jdString, setJdString] = useState("");
33+
const [searchState, setSearchState] = useState(null);
34+
const [modalOpen, setModalOpen] = useState(false);
35+
const [skillModalOpen, setSkillModalOpen] = useState(false);
36+
const [submitDone, setSubmitDone] = useState(false);
37+
const [skills, setSkills] = useState([]);
38+
const [isLoadingSkills, setIsLoadingSkills] = useState(false);
39+
40+
const onSearch = useCallback(
41+
(value) => {
42+
setSkillModalOpen(true);
43+
setIsLoadingSkills(true);
44+
getSkillsByJobDescription(jdString)
45+
.then((response) => {
46+
setSkills(response.data);
47+
setIsLoadingSkills(false);
48+
setSkillModalOpen(true);
49+
})
50+
.catch(() => {
51+
setIsLoadingSkills(false);
52+
});
53+
},
54+
[jdString]
55+
);
56+
57+
const onConfirationClick = useCallback(() => {
58+
setSearchState("searching");
59+
setCurrentStage(1, stages, setStages);
60+
setTimeout(() => {
61+
setCurrentStage(2, stages, setStages);
62+
setSearchState("done");
63+
}, 3000);
64+
}, []);
65+
66+
const addAnother = useCallback(() => {
67+
// navigate(`/taas/myteams/createnewteam/${projectId}/role`);
68+
}, []);
69+
70+
const submitJob = () => {
71+
setSubmitDone(false);
72+
setModalOpen(true);
73+
setTimeout(() => {
74+
setSubmitDone(true);
75+
}, 3000);
76+
};
77+
78+
const onEditChange = useCallback((value) => {
79+
setJdString(value);
80+
}, []);
81+
82+
return (
83+
<div>
84+
{!searchState ? (
85+
<div styleName="page">
86+
<div styleName="edit-container">
87+
<PageHeader
88+
title="Input Job Description"
89+
backTo="/taas/myteams/createnewteam"
90+
/>
91+
<MarkdownEditor
92+
height="482px"
93+
placeholder="input job description"
94+
onChange={onEditChange}
95+
/>
96+
</div>
97+
<Completeness
98+
extraStyleName="input-job-description"
99+
isDisabled={jdString.length < 10}
100+
stages={stages}
101+
onClick={onSearch}
102+
buttonLabel="Search"
103+
percentage="26"
104+
/>
105+
<SkillListPopup
106+
open={skillModalOpen}
107+
skills={skills}
108+
onClose={() => setSkillModalOpen(false)}
109+
isLoading={isLoadingSkills}
110+
onContinueClick={onConfirationClick}
111+
/>
112+
</div>
113+
) : searchState === "searching" ? (
114+
<div styleName="page">
115+
<SearchCard />
116+
<Completeness
117+
extraStyleName="input-job-description"
118+
isDisabled
119+
stages={stages}
120+
buttonLabel="Submit Request"
121+
percentage="52"
122+
/>
123+
</div>
124+
) : (
125+
<div styleName="page">
126+
<ResultCard />
127+
<Completeness
128+
extraStyleName="input-job-description"
129+
stages={stages}
130+
buttonLabel="Submit Request"
131+
percentage="92"
132+
onClick={submitJob}
133+
/>
134+
<AddAnotherModal
135+
open={modalOpen}
136+
onClose={() => setModalOpen(false)}
137+
submitDone={submitDone}
138+
addAnother={addAnother}
139+
/>
140+
</div>
141+
)}
142+
</div>
143+
);
144+
}
145+
146+
InputJobDescription.propTypes = {
147+
projectId: PT.string,
148+
};
149+
150+
export default withAuthentication(InputJobDescription);
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+
}

0 commit comments

Comments
 (0)