diff --git a/src/components/MonthPicker/index.jsx b/src/components/MonthPicker/index.jsx index 0da605f8..9b1f1b85 100644 --- a/src/components/MonthPicker/index.jsx +++ b/src/components/MonthPicker/index.jsx @@ -15,7 +15,7 @@ function getCurrMonthYear() { return new Date(`${year}-${month + 1}`); } -function MonthPicker({ name, value, onChange, onBlur }) { +function MonthPicker({ name, value, onChange, onBlur, onFocus }) { return (
{ + const newVal = +value + step; + if (typeof newVal === "number" && !isNaN(newVal)) { + onChange(newVal); + } + }; + const decrementVal = (step) => { + const newVal = value - step; + if (newVal >= min) { + onChange(value - step); + } + }; + + return ( +
+ + + +
+ ); +} + +NumberInput.propTypes = { + name: PT.string, + value: PT.string, + onChange: PT.func, + onFocus: PT.func, + onBlur: PT.func, + min: PT.string, + error: PT.bool, +}; + +export default NumberInput; diff --git a/src/components/NumberInput/styles.module.scss b/src/components/NumberInput/styles.module.scss new file mode 100644 index 00000000..e5941c56 --- /dev/null +++ b/src/components/NumberInput/styles.module.scss @@ -0,0 +1,43 @@ +@import "styles/include"; + +// remove default buttons and style input as text input +.input { + appearance: textfield; + text-align: center; + + &.error { + border-color: #fe665d; + } +} +.input::-webkit-inner-spin-button, +.input::-webkit-outer-spin-button { + appearance: none; + margin: 0; +} + +.container { + position: relative; + width: fit-content; +} + +.left-button, +.right-button { + @include font-roboto; + font-size: 22px; + color: #137D60; + outline: none; + border: none; + background: none; + position: absolute; + top: 0; + height: 100%; + padding: 0 11px; +} + +.left-button { + left: 0; +} + +.right-button { + right: 0; +} \ No newline at end of file diff --git a/src/constants/index.js b/src/constants/index.js index 45507f02..46a60d98 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -257,7 +257,7 @@ export const ACTION_TYPE = { CLEAR_SEARCHED_ROLES: "CLEAR_SEARCHED_ROLES", ADD_SEARCHED_ROLE: "ADD_SEARCHED_ROLE", ADD_ROLE_SEARCH_ID: "ADD_ROLE_SEARCH_ID", - REPLACE_SEARCHED_ROLES: "REPLACE_SEARCHED_ROLES", + DELETE_SEARCHED_ROLE: "DELETE_SEARCHED_ROLE", }; /** diff --git a/src/root.component.jsx b/src/root.component.jsx index f1e5c3b7..bdd3b79b 100644 --- a/src/root.component.jsx +++ b/src/root.component.jsx @@ -25,7 +25,7 @@ export default function Root() { - + @@ -34,9 +34,9 @@ export default function Root() { - - - + + + {/* Global config for Toastr popups */} diff --git a/src/routes/CreateNewTeam/actions/index.js b/src/routes/CreateNewTeam/actions/index.js index bb78565f..a67e6569 100644 --- a/src/routes/CreateNewTeam/actions/index.js +++ b/src/routes/CreateNewTeam/actions/index.js @@ -22,9 +22,9 @@ const addPreviousSearchId = (id) => ({ payload: id, }); -export const replaceSearchedRoles = (roles) => ({ - type: ACTION_TYPE.REPLACE_SEARCHED_ROLES, - payload: { roles, lastRoleId: roles[roles.length - 1].searchId }, +const deleteRole = (id) => ({ + type: ACTION_TYPE.DELETE_SEARCHED_ROLE, + payload: id, }); export const clearSearchedRoles = () => (dispatch, getState) => { @@ -41,3 +41,8 @@ export const addRoleSearchId = (id) => (dispatch, getState) => { dispatch(addPreviousSearchId(id)); updateLocalStorage(getState().searchedRoles); }; + +export const deleteSearchedRole = (id) => (dispatch, getState) => { + dispatch(deleteRole(id)); + updateLocalStorage(getState().searchedRoles); +}; diff --git a/src/routes/CreateNewTeam/components/AddedRolesAccordion/index.jsx b/src/routes/CreateNewTeam/components/AddedRolesAccordion/index.jsx index 2c1d9a6e..ece5e080 100644 --- a/src/routes/CreateNewTeam/components/AddedRolesAccordion/index.jsx +++ b/src/routes/CreateNewTeam/components/AddedRolesAccordion/index.jsx @@ -19,7 +19,8 @@ function AddedRolesAccordion({ addedRoles }) {

{addedRoles.length}{" "} - {addedRoles.length > 1 ? "roles have" : "role has"} been added. + {addedRoles.length > 1 ? "positions have" : "position has"} been + added.

diff --git a/src/routes/CreateNewTeam/components/ItemList/index.jsx b/src/routes/CreateNewTeam/components/ItemList/index.jsx index 12033b13..56b6496a 100644 --- a/src/routes/CreateNewTeam/components/ItemList/index.jsx +++ b/src/routes/CreateNewTeam/components/ItemList/index.jsx @@ -37,7 +37,7 @@ function ItemList({
header { padding: 16px 24px; @@ -33,9 +33,9 @@ input:not([type="checkbox"]).filter-input { color: #2a2a2a; font-size: 14px; height: 40px; - line-height: 38px; + line-height: normal; outline: none; - padding: 0 15px; + padding: 8px 15px; &:not(:focus) { background-image: url("../../../../assets/images/icon-search.svg"); diff --git a/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx b/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx index 170b9756..4daee929 100644 --- a/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx +++ b/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx @@ -38,7 +38,7 @@ function NoMatchingProfilesResultCard({ role }) {

/Week

)} - + diff --git a/src/routes/CreateNewTeam/components/ResultCard/index.jsx b/src/routes/CreateNewTeam/components/ResultCard/index.jsx index 97e44dbf..07f21c13 100644 --- a/src/routes/CreateNewTeam/components/ResultCard/index.jsx +++ b/src/routes/CreateNewTeam/components/ResultCard/index.jsx @@ -32,6 +32,10 @@ function ResultCard({ role }) { isExternalMember, skillsMatch, rates: [rates], + jobTitle, + name, + timeToCandidate, + timeToInterview, } = role; const [userHandle, setUserHandle] = useState(null); const [showRates, setShowRates] = useState(false); @@ -54,6 +58,9 @@ function ResultCard({ role }) {
+

+ {jobTitle && jobTitle.length ? jobTitle : name} +

Interviews can start within

-
48h
+
{timeToInterview}h
diff --git a/src/routes/CreateNewTeam/components/ResultCard/styles.module.scss b/src/routes/CreateNewTeam/components/ResultCard/styles.module.scss index 95ec69ae..6babd0a1 100644 --- a/src/routes/CreateNewTeam/components/ResultCard/styles.module.scss +++ b/src/routes/CreateNewTeam/components/ResultCard/styles.module.scss @@ -13,7 +13,7 @@ justify-content: flex-start; align-items: center; padding: 30px 0 60px 0; - margin-bottom: 30px; + margin-bottom: 14px; color: #fff; background-image: linear-gradient(225deg, #0ab88a 0%, #137d60 100%); position: relative; @@ -40,6 +40,18 @@ } } +.job-title { + @include font-barlow; + font-size: 22px; + margin-bottom: 18px; + font-weight: 600; + text-align: center; + text-transform: uppercase; + // position text over bottom of header image + position: relative; + z-index: 100; +} + .button-group { display: flex; flex-direction: row; diff --git a/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx b/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx index 206e4ee5..153a8a96 100644 --- a/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx +++ b/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx @@ -90,19 +90,21 @@ function RoleDetailsModal({ roleId, open, onClose }) { Skills - {showSkills ? ( - - ) : ( -
- -
- )} +
+ {showSkills ? ( + + ) : ( +
+ +
+ )} +
); diff --git a/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss index d8ad2bf7..8aa70eac 100644 --- a/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss +++ b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss @@ -58,3 +58,8 @@ margin-bottom: 10px; font-size: 12px; } + +.content { + height: 180px; + overflow-y: auto; +} diff --git a/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx b/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx index b801e2d1..778fd984 100644 --- a/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx +++ b/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx @@ -1,23 +1,71 @@ import { Router } from "@reach/router"; -import React from "react"; -import { useSelector } from "react-redux"; +import _ from "lodash"; +import React, { useCallback, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { searchRoles } from "services/teams"; +import { isCustomRole, setCurrentStage } from "utils/helpers"; +import { addRoleSearchId, addSearchedRole } from "../../actions"; import SearchContainer from "../SearchContainer"; import SubmitContainer from "../SubmitContainer"; function SearchAndSubmit(props) { + const { stages, setStages, searchObject, onClick } = props; + + const [searchState, setSearchState] = useState(null); + const [matchingRole, setMatchingRole] = useState(null); + const { addedRoles, previousSearchId } = useSelector( (state) => state.searchedRoles ); + const dispatch = useDispatch(); + + const search = useCallback(() => { + setCurrentStage(1, stages, setStages); + setSearchState("searching"); + setMatchingRole(null); + const searchObjectCopy = { ...searchObject }; + if (previousSearchId) { + searchObjectCopy.previousRoleSearchRequestId = previousSearchId; + } + searchRoles(searchObjectCopy) + .then((res) => { + const name = _.get(res, "data.name"); + const searchId = _.get(res, "data.roleSearchRequestId"); + if (name && !isCustomRole({ name })) { + dispatch(addSearchedRole({ searchId, name })); + } else if (searchId) { + dispatch(addRoleSearchId(searchId)); + } + setMatchingRole(res.data); + }) + .catch((err) => { + console.error(err); + }) + .finally(() => { + setCurrentStage(2, stages, setStages); + setSearchState("done"); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dispatch, previousSearchId, searchObject]); + return ( + - ); } diff --git a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx index bf32a252..094bd141 100644 --- a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx +++ b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx @@ -5,70 +5,34 @@ * search pages. Contains logic and supporting * components for searching for roles. */ -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import PT from "prop-types"; -import _ from "lodash"; -import { useDispatch } from "react-redux"; import AddedRolesAccordion from "../AddedRolesAccordion"; import Completeness from "../Completeness"; import SearchCard from "../SearchCard"; import ResultCard from "../ResultCard"; import NoMatchingProfilesResultCard from "../NoMatchingProfilesResultCard"; -import { searchRoles } from "services/teams"; -import { isCustomRole, setCurrentStage } from "utils/helpers"; -import { addRoleSearchId, addSearchedRole } from "../../actions"; +import { isCustomRole } from "utils/helpers"; import "./styles.module.scss"; function SearchContainer({ stages, - setStages, isCompletenessDisabled, toRender, - searchObject, + onClick, + search, completenessStyle, navigate, addedRoles, - previousSearchId, + searchState, + matchingRole, }) { - const [searchState, setSearchState] = useState(null); - const [matchingRole, setMatchingRole] = useState(null); - - const dispatch = useDispatch(); - const onSubmit = useCallback(() => { - navigate("result", { state: { matchingRole } }); - }, [navigate, matchingRole]); - - const search = () => { - setCurrentStage(1, stages, setStages); - setSearchState("searching"); - setMatchingRole(null); - const searchObjectCopy = { ...searchObject }; - if (previousSearchId) { - searchObjectCopy.previousRoleSearchRequestId = previousSearchId; - } - searchRoles(searchObjectCopy) - .then((res) => { - const name = _.get(res, "data.name"); - const searchId = _.get(res, "data.roleSearchRequestId"); - if (name && !isCustomRole({ name })) { - dispatch(addSearchedRole({ searchId, name })); - } else if (searchId) { - dispatch(addRoleSearchId(searchId)); - } - setMatchingRole(res.data); - }) - .catch((err) => { - console.error(err); - }) - .finally(() => { - setCurrentStage(2, stages, setStages); - setSearchState("done"); - }); - }; + navigate("result"); + }, [navigate]); const renderLeftSide = () => { - if (!searchState) return toRender; + if (!searchState) return toRender(search); if (searchState === "searching") return ; if (!isCustomRole(matchingRole)) return ; return ; @@ -92,7 +56,7 @@ function SearchContainer({ searchState === "searching" || (searchState === "done" && isCustomRole(matchingRole)) } - onClick={searchState ? onSubmit : search} + onClick={searchState ? onSubmit : onClick ? onClick : search} extraStyleName={completenessStyle} buttonLabel={searchState ? "Submit Request" : "Search"} stages={stages} @@ -105,14 +69,15 @@ function SearchContainer({ SearchContainer.propTypes = { stages: PT.array, - setStages: PT.func, isCompletenessDisabled: PT.bool, - searchObject: PT.object, - toRender: PT.node, + onClick: PT.func, + search: PT.func, + toRender: PT.func, completenessStyle: PT.string, navigate: PT.func, addedRoles: PT.array, - previousSearchId: PT.string, + searchState: PT.string, + matchingRole: PT.object, }; export default SearchContainer; diff --git a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx index e2922708..b6e19b77 100644 --- a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx +++ b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx @@ -32,11 +32,9 @@ function SubmitContainer({ stages, setStages, completenessStyle, - location, + matchingRole, addedRoles, }) { - const matchingRole = location?.state?.matchingRole; - const [addAnotherOpen, setAddAnotherOpen] = useState(true); const [teamDetailsOpen, setTeamDetailsOpen] = useState(false); const [teamObject, setTeamObject] = useState(null); @@ -46,20 +44,16 @@ function SubmitContainer({ useEffect(() => { setCurrentStage(2, stages, setStages); - if (!addedRoles || addedRoles.length === 0) { - navigate("/taas/myteams/createnewteam"); - } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // redirects user if they enter the page URL directly - // without adding any roles. + // without adding any roles or delete all roles. useLayoutEffect(() => { if (!addedRoles || addedRoles.length === 0) { - navigate("/taas/myteams/createnewteam"); + navigate("/taas/createnewteam"); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [addedRoles]); const openTeamDetails = () => { setAddAnotherOpen(false); @@ -67,7 +61,7 @@ function SubmitContainer({ }; const addAnother = () => { - navigate("/taas/myteams/createnewteam"); + navigate("/taas/createnewteam"); }; const assembleTeam = (formData) => { @@ -100,10 +94,9 @@ function SubmitContainer({ const requestTeam = useCallback(() => { setRequestLoading(true); postTeamRequest(teamObject) - .then((res) => { - const projectId = _.get(res, ["data", "projectId"]); + .then(() => { dispatch(clearSearchedRoles()); - navigate(`/taas/myteams/${projectId}`); + navigate("/taas/myteams"); }) .catch((err) => { setRequestLoading(false); @@ -151,8 +144,8 @@ SubmitContainer.propTypes = { stages: PT.array, setStages: PT.func, completenessStyle: PT.string, - location: PT.object, addedRoles: PT.array, + matchingRole: PT.object, }; export default withAuthentication(SubmitContainer); diff --git a/src/routes/CreateNewTeam/components/SuccessCard/index.jsx b/src/routes/CreateNewTeam/components/SuccessCard/index.jsx index 41feb1b4..0c6d06a0 100644 --- a/src/routes/CreateNewTeam/components/SuccessCard/index.jsx +++ b/src/routes/CreateNewTeam/components/SuccessCard/index.jsx @@ -26,7 +26,7 @@ function SuccessCard() { Please use the button to the right to submit your request, or the button below to search for additional roles.

- + diff --git a/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx b/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx index 6c599e67..11802f60 100644 --- a/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx +++ b/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx @@ -6,6 +6,7 @@ import React, { useState } from "react"; import PT from "prop-types"; import { Form, Field, useField } from "react-final-form"; +import { useDispatch } from "react-redux"; import FormField from "components/FormField"; import BaseCreateModal from "../BaseCreateModal"; import { FORM_FIELD_TYPE } from "constants/"; @@ -13,7 +14,10 @@ import { formatPlural } from "utils/format"; import Button from "components/Button"; import MonthPicker from "components/MonthPicker"; import InformationTooltip from "components/InformationTooltip"; +import { deleteSearchedRole } from "../../actions"; +import IconCrossLight from "../../../../assets/images/icon-cross-light.svg"; import "./styles.module.scss"; +import NumberInput from "components/NumberInput"; const Error = ({ name }) => { const { @@ -32,6 +36,8 @@ function TeamDetailsModal({ open, onClose, submitForm, addedRoles }) { return roles; }); + const dispatch = useDispatch(); + const toggleDescription = () => { setShowDescription((prevState) => !prevState); }; @@ -169,31 +175,44 @@ function TeamDetailsModal({ open, onClose, submitForm, addedRoles }) { # of resources Duration (weeks) Start month + {addedRoles.map(({ searchId: id, name }) => ( {name} - + + {({ input, meta }) => ( + + )} + - + + {({ input, meta }) => ( + + )} + - + {startMonthVisible[id] ? ( <> )} @@ -231,6 +251,17 @@ function TeamDetailsModal({ open, onClose, submitForm, addedRoles }) { )} + + + ))} diff --git a/src/routes/CreateNewTeam/components/TeamDetailsModal/styles.module.scss b/src/routes/CreateNewTeam/components/TeamDetailsModal/styles.module.scss index a3f5675a..80ced5a3 100644 --- a/src/routes/CreateNewTeam/components/TeamDetailsModal/styles.module.scss +++ b/src/routes/CreateNewTeam/components/TeamDetailsModal/styles.module.scss @@ -8,6 +8,7 @@ font-size: 12px; font-weight: 500; color: #137D60; + padding: 1px 6px 0 6px; &.toggle-description { margin-top: 12px; @@ -42,14 +43,14 @@ color: #2a2a2a; border-bottom: 1px solid #e9e9e9; - &.start-month { + &:last-child { padding-right: 0; } input { @include font-roboto; font-size: 14px; - line-height: 22px; + line-height: normal; height: 34px; &[type="number"] { width: 98px; @@ -64,6 +65,7 @@ flex-direction: row; align-items: center; justify-content: flex-start; + width: 118px; } .error { @@ -73,14 +75,20 @@ display: block; } +.delete-role { + border: none; + background: none; + + &:hover { + g { + stroke: red; + } + } +} + .modal-body { + overflow-x: auto; textarea { height: 95px; } } - -@media only screen and (max-width: 550px) { - .modal-body { - overflow-x: scroll; - } -} \ No newline at end of file diff --git a/src/routes/CreateNewTeam/index.jsx b/src/routes/CreateNewTeam/index.jsx index efd722e5..3ca8343d 100644 --- a/src/routes/CreateNewTeam/index.jsx +++ b/src/routes/CreateNewTeam/index.jsx @@ -31,21 +31,21 @@ function CreateNewTeam() { description="You know you want a front end developer, or a full stack developer, mobile one or others." icon={} backgroundImage="linear-gradient(101.95deg, #8B41B0 0%, #EF476F 100%)" - onClick={() => goToRoute("/taas/myteams/createnewteam/role")} + onClick={() => goToRoute("/taas/createnewteam/role")} /> } backgroundImage="linear-gradient(221.5deg, #2C95D7 0%, #9D41C9 100%)" - onClick={() => goToRoute("/taas/myteams/createnewteam/skills")} + onClick={() => goToRoute("/taas/createnewteam/skills")} /> } backgroundImage="linear-gradient(135deg, #2984BD 0%, #0AB88A 100%)" - onClick={() => goToRoute("/taas/myteams/createnewteam/jd")} + onClick={() => goToRoute("/taas/createnewteam/jd")} /> ); diff --git a/src/routes/CreateNewTeam/pages/InputJobDescription/components/SkillListPopup/index.jsx b/src/routes/CreateNewTeam/pages/InputJobDescription/components/SkillListPopup/index.jsx index 60317253..6d095ca5 100644 --- a/src/routes/CreateNewTeam/pages/InputJobDescription/components/SkillListPopup/index.jsx +++ b/src/routes/CreateNewTeam/pages/InputJobDescription/components/SkillListPopup/index.jsx @@ -5,67 +5,50 @@ 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"; +import BaseCreateModal from "../../../../components/BaseCreateModal"; -const modalStyle = { - borderRadius: "8px", - padding: "32px 32px 22px 32px", - maxWidth: "460px", - width: "100%", - margin: 0, - "overflow-x": "hidden", -}; - -const containerStyle = { - padding: "10px", -}; +function SkillListPopup({ open, skills, isLoading, onClose, onContinueClick }) { + const Buttons = ( + <> + + + + ); -function SkillListPopup({ open, skills, onClose, isLoading, onContinueClick }) { return ( - + headerIcon={} + title="Skills" + subtitle={ + skills.length + ? "These skills are found in your Job Description" + : "No skills are found in your Job Description" } - styles={{ - modal: modalStyle, - modalContainer: containerStyle, - }} + isLoading={isLoading} + loadingMessage="Loading skills..." + maxWidth="460px" + buttons={Buttons} > -
- {isLoading ? ( - <> - -
loading skills
- - ) : ( - <> - -
skills
- {_.map(skills, (s) => { - return
{s.tag}
; - })} - - )} -
-
- +
+ {_.map(skills, (s) => { + return
{s.tag}
; + })}
- + ); } diff --git a/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx b/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx index 9bc211e1..2ba16303 100644 --- a/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx +++ b/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx @@ -4,11 +4,14 @@ * Allows user to search for roles by * job description */ -import React, { useCallback, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import PageHeader from "components/PageHeader"; import MarkdownEditor from "../../../../components/MarkdownEditor"; import "./styles.module.scss"; import SearchAndSubmit from "../../components/SearchAndSubmit"; +import TextInput from "components/TextInput"; +import { getSkillsByJobDescription } from "services/teams"; +import SkillListPopup from "./components/SkillListPopup"; function InputJobDescription() { const [stages, setStages] = useState([ @@ -17,38 +20,80 @@ function InputJobDescription() { { name: "Overview of the Results" }, ]); const [jdString, setJdString] = useState(""); + const [jobTitle, setJobTitle] = useState(""); + const [skills, setSkills] = useState([]); + const [loadingSkills, setLoadingSkills] = useState(true); + const [popupOpen, setPopupOpen] = useState(false); const onEditChange = useCallback((value) => { setJdString(value); }, []); + const searchObject = useMemo(() => { + if (jobTitle && jobTitle.length) { + return { jobDescription: jdString, jobTitle }; + } + return { jobDescription: jdString }; + }, [jobTitle, jdString]); + + const onClick = useCallback(() => { + setLoadingSkills(true); + setSkills([]); + setPopupOpen(true); + getSkillsByJobDescription(jdString) + .then((res) => { + setSkills(res.data); + }) + .catch((err) => { + console.error(err); + }) + .finally(() => { + setLoadingSkills(false); + }); + }, [jdString]); + return ( 255} completenessStyle="input-job-description" - searchObject={{ jobDescription: jdString }} - toRender={ - <> -
- - 255 - ? "Maximum of 255 characters. Please reduce job description length." - : "" - } + searchObject={searchObject} + onClick={onClick} + toRender={(searchFunc) => ( +
+ +
+
- - } + 255 + ? "Maximum of 255 characters. Please reduce job description length." + : "" + } + /> + setPopupOpen(false)} + skills={skills} + isLoading={loadingSkills} + onContinueClick={searchFunc} + /> +
+ )} /> ); } diff --git a/src/routes/CreateNewTeam/pages/InputJobDescription/styles.module.scss b/src/routes/CreateNewTeam/pages/InputJobDescription/styles.module.scss index 9fe69610..892befbe 100644 --- a/src/routes/CreateNewTeam/pages/InputJobDescription/styles.module.scss +++ b/src/routes/CreateNewTeam/pages/InputJobDescription/styles.module.scss @@ -7,3 +7,12 @@ padding: 0 30px 30px; flex: 1; } + +.job-title { + margin-bottom: 15px; + + input:not([type="checkbox"]) { + line-height: normal; + padding: 8px 15px; + } +} \ No newline at end of file diff --git a/src/routes/CreateNewTeam/pages/InputSkills/index.jsx b/src/routes/CreateNewTeam/pages/InputSkills/index.jsx index a9ace938..ac0a7b2b 100644 --- a/src/routes/CreateNewTeam/pages/InputSkills/index.jsx +++ b/src/routes/CreateNewTeam/pages/InputSkills/index.jsx @@ -51,13 +51,13 @@ function InputSkills() { isCompletenessDisabled={selectedSkills.length < 1} searchObject={{ skills: selectedSkills }} completenessStyle="input-skills" - toRender={ + toRender={() => ( - } + )} /> ); } diff --git a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx index 88c84e07..73dddfa7 100644 --- a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx +++ b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx @@ -49,7 +49,7 @@ function SelectRole() { isCompletenessDisabled={!selectedRoleId} searchObject={{ roleId: selectedRoleId }} completenessStyle="role-selection" - toRender={ + toRender={() => ( <> setRoleDetailsModalOpen(false)} /> - } + )} /> ); } diff --git a/src/routes/CreateNewTeam/reducers/index.js b/src/routes/CreateNewTeam/reducers/index.js index 74c9e6ce..d90316bf 100644 --- a/src/routes/CreateNewTeam/reducers/index.js +++ b/src/routes/CreateNewTeam/reducers/index.js @@ -18,9 +18,18 @@ const loadState = () => { return defaultState; } }; - const initialState = loadState(); +const deleteRoleInState = (state, deleteId) => { + const filteredRoles = state.addedRoles.filter( + (role) => role.searchId !== deleteId + ); + return { + ...state, + addedRoles: filteredRoles, + }; +}; + const reducer = (state = initialState, action) => { switch (action.type) { case ACTION_TYPE.CLEAR_SEARCHED_ROLES: @@ -42,12 +51,8 @@ const reducer = (state = initialState, action) => { previousSearchId: action.payload, }; - case ACTION_TYPE.REPLACE_SEARCHED_ROLES: - return { - ...state, - addedRoles: action.payload.roles, - previousSearchId: action.payload.lastRoleId, - }; + case ACTION_TYPE.DELETE_SEARCHED_ROLE: + return deleteRoleInState(state, action.payload); default: return state; diff --git a/src/services/teams.js b/src/services/teams.js index 7fedd403..b8b4200c 100644 --- a/src/services/teams.js +++ b/src/services/teams.js @@ -215,13 +215,13 @@ export const postProject = () => { * @param {string} searchObject.roleId a role id to search for * @param {string} searchObject.jobDescription job description used for search * @param {string[]} searchObject.skills array of skill ids used for role search + * @param {string} searchObject.jobTitle job title to associate with search * @param {string} searchObject.previousRoleSearchRequestId id of the last search made * * @returns {Promise} the role found */ export const searchRoles = (searchObject) => { const newObject = { ...searchObject }; - delete newObject.previousRoleSearchRequestId; const url = `${config.API.V5}/taas-teams/sendRoleSearchRequest`; return axios.post(url, newObject); }; diff --git a/src/utils/helpers.js b/src/utils/helpers.js index 4a92c84e..c54cbe5f 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -70,4 +70,4 @@ export const setCurrentStage = (currentStepIdx, stages, setStagesCallback) => { * @returns {boolean} whether the role is custom/niche */ export const isCustomRole = (role) => - !role.name || CUSTOM_ROLE_NAMES.includes(role.name.toLowerCase()); + !role || !role.name || CUSTOM_ROLE_NAMES.includes(role.name.toLowerCase());