diff --git a/src/routes/InputSkills/components/AddAnotherModal/index.jsx b/src/components/AddAnotherModal/index.jsx similarity index 92% rename from src/routes/InputSkills/components/AddAnotherModal/index.jsx rename to src/components/AddAnotherModal/index.jsx index e031669a..14d2bdb1 100644 --- a/src/routes/InputSkills/components/AddAnotherModal/index.jsx +++ b/src/components/AddAnotherModal/index.jsx @@ -8,8 +8,8 @@ import React from "react"; import PT from "prop-types"; import Modal from "react-responsive-modal"; import Button from "components/Button"; -import IconCrossLight from "../../../../assets/images/icon-cross-light.svg"; -import IconSingleManAdd from "../../../../assets/images/icon-single-man-add.svg"; +import IconCrossLight from "../../assets/images/icon-cross-light.svg"; +import IconSingleManAdd from "../../assets/images/icon-single-man-add.svg"; import "./styles.module.scss"; import CenteredSpinner from "components/CenteredSpinner"; diff --git a/src/routes/InputSkills/components/AddAnotherModal/styles.module.scss b/src/components/AddAnotherModal/styles.module.scss similarity index 100% rename from src/routes/InputSkills/components/AddAnotherModal/styles.module.scss rename to src/components/AddAnotherModal/styles.module.scss diff --git a/src/routes/InputSkills/components/CompleteProgress/index.jsx b/src/components/CompleteProgress/index.jsx similarity index 100% rename from src/routes/InputSkills/components/CompleteProgress/index.jsx rename to src/components/CompleteProgress/index.jsx diff --git a/src/routes/InputSkills/components/CompleteProgress/styles.module.scss b/src/components/CompleteProgress/styles.module.scss similarity index 100% rename from src/routes/InputSkills/components/CompleteProgress/styles.module.scss rename to src/components/CompleteProgress/styles.module.scss diff --git a/src/routes/InputSkills/components/Completeness/index.jsx b/src/components/Completeness/index.jsx similarity index 77% rename from src/routes/InputSkills/components/Completeness/index.jsx rename to src/components/Completeness/index.jsx index 4bc91ac9..bf6a9cfa 100644 --- a/src/routes/InputSkills/components/Completeness/index.jsx +++ b/src/components/Completeness/index.jsx @@ -10,11 +10,15 @@ import cn from "classnames"; import PT from "prop-types"; import CompleteProgress from "../CompleteProgress"; import "./styles.module.scss"; -import IconListQuill from "../../../../assets/images/icon-list-quill.svg"; +import IconListQuill from "../../assets/images/icon-list-quill.svg"; -function Completeness({ isDisabled, onClick, buttonLabel, stage }) { +function Completeness({ title, backgroundIcon, isDisabled, backgroundImage, onClick, buttonLabel, stage }) { return ( -
+
@@ -26,7 +30,7 @@ function Completeness({ isDisabled, onClick, buttonLabel, stage }) { { done: stage > 1 } )} > - Input Skills + Input {title}
  • {buttonLabel} - + {backgroundIcon}
  • ); } @@ -59,6 +63,9 @@ Completeness.propTypes = { onClick: PT.func, buttonLabel: PT.string, stage: PT.number, + title: PT.string, + backgroundImage: PT.string, + backgroundIcon: PT.string }; export default Completeness; diff --git a/src/routes/InputSkills/components/Completeness/styles.module.scss b/src/components/Completeness/styles.module.scss similarity index 78% rename from src/routes/InputSkills/components/Completeness/styles.module.scss rename to src/components/Completeness/styles.module.scss index 5c44deb9..3320d5ef 100644 --- a/src/routes/InputSkills/components/Completeness/styles.module.scss +++ b/src/components/Completeness/styles.module.scss @@ -4,9 +4,17 @@ @include rounded-card; padding: 12px; position: relative; - background-image: linear-gradient(221.5deg, #2c95d7 0%, #9d41c9 100%); width: 250px; color: #fff; + + > svg { + position: absolute; + right: -50px; + top: 85px; + opacity: 10%; + width: 144px; + height: 144px; + } } .list { @@ -47,12 +55,3 @@ } } } - -.transparent-icon { - position: absolute; - right: -50px; - top: 85px; - opacity: 10%; - width: 144px; - height: 144px; -} diff --git a/src/routes/InputSkills/components/ResultCard/index.jsx b/src/components/ResultCard/index.jsx similarity index 90% rename from src/routes/InputSkills/components/ResultCard/index.jsx rename to src/components/ResultCard/index.jsx index 01a98935..a99446ad 100644 --- a/src/routes/InputSkills/components/ResultCard/index.jsx +++ b/src/components/ResultCard/index.jsx @@ -6,11 +6,11 @@ */ import React, { useState } from "react"; import "./styles.module.scss"; -import IconEarthCheck from "../../../../assets/images/icon-earth-check.svg"; -import IconMultipleUsers from "../../../../assets/images/icon-multiple-users.svg"; -import IconMultipleActionsCheck from "../../../../assets/images/icon-multiple-actions-check-2.svg"; -import IconTeamMeetingChat from "../../../../assets/images/icon-team-meeting-chat.svg"; -import Curve from "../../../../assets/images/curve.svg"; +import IconEarthCheck from "../../assets/images/icon-earth-check.svg"; +import IconMultipleUsers from "../../assets/images/icon-multiple-users.svg"; +import IconMultipleActionsCheck from "../../assets/images/icon-multiple-actions-check-2.svg"; +import IconTeamMeetingChat from "../../assets/images/icon-team-meeting-chat.svg"; +import Curve from "../../assets/images/curve.svg"; import Button from "components/Button"; function ResultCard() { diff --git a/src/routes/InputSkills/components/ResultCard/styles.module.scss b/src/components/ResultCard/styles.module.scss similarity index 100% rename from src/routes/InputSkills/components/ResultCard/styles.module.scss rename to src/components/ResultCard/styles.module.scss diff --git a/src/routes/InputSkills/components/SearchCard/index.jsx b/src/components/SearchCard/index.jsx similarity index 77% rename from src/routes/InputSkills/components/SearchCard/index.jsx rename to src/components/SearchCard/index.jsx index dbdebd5a..0edb34f5 100644 --- a/src/routes/InputSkills/components/SearchCard/index.jsx +++ b/src/components/SearchCard/index.jsx @@ -5,10 +5,10 @@ */ import React, { useEffect, useState } from "react"; import "./styles.module.scss"; -import IconEarthSearch from "../../../../assets/images/icon-earth-search.svg"; -import WorldMapDotted from "../../../../assets/images/world-map-dotted.svg"; -import WorldMapSearch1 from "../../../../assets/images/world-map-search1.svg"; -import WorldMapSearch2 from "../../../../assets/images/world-map-search2.svg"; +import IconEarthSearch from "../../assets/images/icon-earth-search.svg"; +import WorldMapDotted from "../../assets/images/world-map-dotted.svg"; +import WorldMapSearch1 from "../../assets/images/world-map-search1.svg"; +import WorldMapSearch2 from "../../assets/images/world-map-search2.svg"; function SearchCard() { const [searchState, setSearchState] = useState(null); diff --git a/src/routes/InputSkills/components/SearchCard/styles.module.scss b/src/components/SearchCard/styles.module.scss similarity index 100% rename from src/routes/InputSkills/components/SearchCard/styles.module.scss rename to src/components/SearchCard/styles.module.scss diff --git a/src/root.component.jsx b/src/root.component.jsx index a50a3023..268ae29a 100644 --- a/src/root.component.jsx +++ b/src/root.component.jsx @@ -11,6 +11,7 @@ import JobForm from "./routes/JobForm"; import TeamAccess from "./routes/TeamAccess"; import CreateNewTeam from "./routes/CreateNewTeam"; import InputSkills from "./routes/InputSkills"; +import InputJobDescription from "./routes/InputJobDescription"; import ReduxToastr from "react-redux-toastr"; import store from "./store"; import "./styles/main.vendor.scss"; @@ -33,6 +34,7 @@ export default function Root() { + diff --git a/src/routes/CreateNewTeam/index.jsx b/src/routes/CreateNewTeam/index.jsx index 08701d91..3f4a5d91 100644 --- a/src/routes/CreateNewTeam/index.jsx +++ b/src/routes/CreateNewTeam/index.jsx @@ -30,6 +30,10 @@ function CreateNewTeam() { }); }; + const goToJobDescription = ()=> { + navigate(`/taas/myteams/createnewteam/jd`); + } + return ( @@ -55,7 +59,7 @@ function CreateNewTeam() { description="You would like to use a description to explain what you need." icon={} backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)" - isDisabled + onClick={goToJobDescription} /> ); diff --git a/src/routes/InputJobDescription/components/Popup/index.jsx b/src/routes/InputJobDescription/components/Popup/index.jsx new file mode 100644 index 00000000..38aaae61 --- /dev/null +++ b/src/routes/InputJobDescription/components/Popup/index.jsx @@ -0,0 +1,80 @@ +/** + * Temporary Popup for skill list + * show skill list + */ +import React from "react"; +import _ from "lodash"; +import PT from "prop-types"; +import Modal from "react-responsive-modal"; +import Button from "components/Button"; +import IconCrossLight from "../../../../assets/images/icon-cross-light.svg"; +import IconSingleManAdd from "../../../../assets/images/icon-single-man-add.svg"; +import "./styles.module.scss"; +import CenteredSpinner from "components/CenteredSpinner"; + +const modalStyle = { + borderRadius: "8px", + padding: "32px 32px 22px 32px", + maxWidth: "460px", + width: "100%", + margin: 0, + "overflow-x": "hidden", +}; + +const containerStyle = { + padding: "10px", +}; + +function Popup({ open, skills, onClose, isLoading, onContinueClick }) { + return ( + + } + styles={{ + modal: modalStyle, + modalContainer: containerStyle, + }} + > +
    + {isLoading ? ( + <> + +
    loading skills
    + + ) : ( + <> + +
    skills
    + {_.map(skills, (s) => { + return
    {s.tag}
    ; + })} + + )} +
    +
    + +
    +
    + ); +} + +Popup.propTypes = { + open: PT.bool, + onClose: PT.func, + isLoading: PT.bool, + onContinueClick: PT.func, + skills: PT.arrayOf(PT.shape()), +}; + +export default Popup; diff --git a/src/routes/InputJobDescription/components/Popup/styles.module.scss b/src/routes/InputJobDescription/components/Popup/styles.module.scss new file mode 100644 index 00000000..b0270326 --- /dev/null +++ b/src/routes/InputJobDescription/components/Popup/styles.module.scss @@ -0,0 +1,48 @@ +@import "styles/include"; + +.button-group { + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-end; + :first-child { + margin-right: 8px; + } +} + +.modal-body { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + text-align: center; + margin-bottom: 80px; + + svg { + width: 48px; + height: 48px; + margin-bottom: 16px; + } + + h5 { + @include font-barlow-condensed; + font-size: 34px; + color: #1e94a3; + text-transform: uppercase; + font-weight: 500; + margin-bottom: 10px; + } + + p { + @include font-roboto; + font-size: 16px; + color: #555555; + line-height: 26px; + } +} + +.cross { + g { + stroke: #000; + } +} diff --git a/src/routes/InputJobDescription/index.jsx b/src/routes/InputJobDescription/index.jsx new file mode 100644 index 00000000..15581565 --- /dev/null +++ b/src/routes/InputJobDescription/index.jsx @@ -0,0 +1,145 @@ +/** + * Input Job Description page + * + */ +import React, { useCallback, useEffect, useState } from "react"; +import { useData } from "hooks/useData"; +import { navigate } from "@reach/router"; +import { toastr } from "react-redux-toastr"; +import MarkdownEditor from "../../components/MarkdownEditor"; +import { getSkillsByJobDescription } from "../../services/teams"; +import Page from "components/Page"; +import PageHeader from "components/PageHeader"; +import PT from "prop-types"; +import Completeness from "components/Completeness"; +import { getSkills } from "services/skills"; +import LoadingIndicator from "components/LoadingIndicator"; +import SearchCard from "components/SearchCard"; +import ResultCard from "components/ResultCard"; +import AddAnotherModal from "components/AddAnotherModal"; +import SkillListPopup from "./components/Popup"; +import "./styles.module.scss"; +import withAuthentication from "../../hoc/withAuthentication"; +import IconOfficeFileText from "../../assets/images/icon-office-file-text.svg"; + +function InputJobDescription() { + const [jdString, setJdString] = useState(""); + const [searchState, setSearchState] = useState(null); + const [modalOpen, setModalOpen] = useState(false); + const [skillModalOpen, setSkillModalOpen] = useState(false); + const [submitDone, setSubmitDone] = useState(false); + const [skills, setSkills] = useState([]); + const [isLoadingSkills, setIsLoadingSkills] = useState(false); + + const onSearch = useCallback( + (value) => { + setSkillModalOpen(true); + setIsLoadingSkills(true); + getSkillsByJobDescription(jdString) + .then((response) => { + setSkills(response.data); + setIsLoadingSkills(false); + setSkillModalOpen(true); + }) + .catch(() => { + setIsLoadingSkills(false); + }); + }, + [jdString] + ); + + const onConfirationClick = useCallback(() => { + setSearchState("searching"); + setTimeout(() => { + setSearchState("done"); + }, 3000); + }, []); + + const addAnother = useCallback(() => { + // navigate(`/taas/myteams/createnewteam/${projectId}/role`); + }, []); + + const submitJob = () => { + setSubmitDone(false); + setModalOpen(true); + setTimeout(() => { + setSubmitDone(true); + }, 3000); + }; + + const onEditChange = useCallback((value) => { + setJdString(value); + }, []); + + return ( +
    + {!searchState ? ( +
    +
    + + +
    + } + onClick={onSearch} + buttonLabel="Search" + stage={1} + /> + setSkillModalOpen(false)} + isLoading={isLoadingSkills} + onContinueClick={onConfirationClick} + /> +
    + ) : searchState === "searching" ? ( +
    + + } + isDisabled + buttonLabel="Submit Request" + stage={2} + /> +
    + ) : ( +
    + + } + buttonLabel="Submit Request" + stage={3} + onClick={submitJob} + /> + setModalOpen(false)} + submitDone={submitDone} + addAnother={addAnother} + /> +
    + )} +
    + ); +} + +InputJobDescription.propTypes = { + projectId: PT.string, +}; + +export default withAuthentication(InputJobDescription); diff --git a/src/routes/InputJobDescription/styles.module.scss b/src/routes/InputJobDescription/styles.module.scss new file mode 100644 index 00000000..31e3ca4b --- /dev/null +++ b/src/routes/InputJobDescription/styles.module.scss @@ -0,0 +1,17 @@ +.page { + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; + margin: 42px 35px; + + .edit-container { + background-color: #ffffff; + border-radius: 8px; + max-width: 746px; + position: relative; + margin-right: 30px; + padding: 0 30px 30px; + flex: 1; + } +} diff --git a/src/routes/InputSkills/index.jsx b/src/routes/InputSkills/index.jsx index a69d6e95..be4d89d9 100644 --- a/src/routes/InputSkills/index.jsx +++ b/src/routes/InputSkills/index.jsx @@ -12,16 +12,17 @@ import { useData } from "hooks/useData"; import { navigate } from "@reach/router"; import { toastr } from "react-redux-toastr"; import PT from "prop-types"; -import SkillsList from "./components/SkillsList"; -import Completeness from "./components/Completeness"; +import Completeness from "components/Completeness"; import "./styles.module.scss"; import { getSkills } from "services/skills"; import LoadingIndicator from "components/LoadingIndicator"; -import SearchCard from "./components/SearchCard"; -import ResultCard from "./components/ResultCard"; +import SearchCard from "components/SearchCard"; +import ResultCard from "components/ResultCard"; import { createJob } from "services/jobs"; -import AddAnotherModal from "./components/AddAnotherModal"; +import AddAnotherModal from "components/AddAnotherModal"; +import SkillsList from "./components/SkillsList"; import withAuthentication from "../../hoc/withAuthentication"; +import IconListQuill from "../../assets/images/icon-list-quill.svg"; function InputSkills({ projectId }) { const [selectedSkills, setSelectedSkills] = useState([]); @@ -91,6 +92,9 @@ function InputSkills({ projectId }) { toggleSkill={toggleSkill} /> } isDisabled={selectedSkills.length < 1} onClick={search} buttonLabel="Search" @@ -100,12 +104,21 @@ function InputSkills({ projectId }) { ) : searchState === "searching" ? (
    - + } + isDisabled + buttonLabel="Submit Request" + stage={2} />
    ) : (
    } buttonLabel="Submit Request" stage={3} onClick={submitJob} diff --git a/src/services/teams.js b/src/services/teams.js index 0d4aa79f..f220a1d6 100644 --- a/src/services/teams.js +++ b/src/services/teams.js @@ -31,6 +31,17 @@ export const getV5UserProfile = () => { return axios.get(`${config.API.V5}/taas-teams/me`); }; +/** + * Get skills by job description + * @param {string} description + * @returns {Promise<{}>} skills list + */ +export const getSkillsByJobDescription = (description) => { + return axios.post(`${config.API.V5}/taas-teams/getSkillsByJobDescription`, { + description, + }); +}; + /** * Get team by id. *