diff --git a/src/assets/images/icon-earth-x.svg b/src/assets/images/icon-earth-x.svg
new file mode 100644
index 00000000..40037611
--- /dev/null
+++ b/src/assets/images/icon-earth-x.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/src/assets/images/icon-role-fallback.svg b/src/assets/images/icon-role-fallback.svg
new file mode 100644
index 00000000..9e0f1123
--- /dev/null
+++ b/src/assets/images/icon-role-fallback.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/src/assets/images/icon-search.svg b/src/assets/images/icon-search.svg
new file mode 100644
index 00000000..f6941732
--- /dev/null
+++ b/src/assets/images/icon-search.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/src/root.component.jsx b/src/root.component.jsx
index a50a3023..578361c0 100644
--- a/src/root.component.jsx
+++ b/src/root.component.jsx
@@ -10,12 +10,12 @@ import JobDetails from "./routes/JobDetails";
import JobForm from "./routes/JobForm";
import TeamAccess from "./routes/TeamAccess";
import CreateNewTeam from "./routes/CreateNewTeam";
-import InputSkills from "./routes/InputSkills";
+import InputSkills from "./routes/CreateNewTeam/pages/InputSkills";
+import SelectRole from "./routes/CreateNewTeam/pages/SelectRole";
import ReduxToastr from "react-redux-toastr";
import store from "./store";
import "./styles/main.vendor.scss";
import styles from "./styles/main.module.scss";
-import SelectRole from "./routes/SelectRole";
export default function Root() {
return (
diff --git a/src/routes/InputSkills/components/AddAnotherModal/index.jsx b/src/routes/CreateNewTeam/components/AddAnotherModal/index.jsx
similarity index 88%
rename from src/routes/InputSkills/components/AddAnotherModal/index.jsx
rename to src/routes/CreateNewTeam/components/AddAnotherModal/index.jsx
index e031669a..c99efcb9 100644
--- a/src/routes/InputSkills/components/AddAnotherModal/index.jsx
+++ b/src/routes/CreateNewTeam/components/AddAnotherModal/index.jsx
@@ -26,7 +26,13 @@ const containerStyle = {
padding: "10px",
};
-function AddAnotherModal({ open, onClose, submitDone, addAnother }) {
+function AddAnotherModal({
+ open,
+ onClose,
+ onContinueClick,
+ submitDone,
+ addAnother,
+}) {
return (
Add Another Position
-
+ );
+}
+
+RoleDetailsModal.propTypes = {
+ roleId: PT.string,
+ open: PT.bool,
+ onClose: PT.func,
+};
+
+export default RoleDetailsModal;
diff --git a/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss
new file mode 100644
index 00000000..81daa623
--- /dev/null
+++ b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss
@@ -0,0 +1,55 @@
+@import "styles/include";
+
+.button-group {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: flex-end;
+ :first-child {
+ margin-right: 8px;
+ }
+}
+
+.tab-button-group {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 42px;
+}
+
+.modal-body {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ text-align: center;
+ margin-bottom: 80px;
+
+ .role-icon {
+ width: 42px;
+ height: 42px;
+ }
+
+ 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/InputSkills/components/SearchCard/index.jsx b/src/routes/CreateNewTeam/components/SearchCard/index.jsx
similarity index 98%
rename from src/routes/InputSkills/components/SearchCard/index.jsx
rename to src/routes/CreateNewTeam/components/SearchCard/index.jsx
index dbdebd5a..487f9ceb 100644
--- a/src/routes/InputSkills/components/SearchCard/index.jsx
+++ b/src/routes/CreateNewTeam/components/SearchCard/index.jsx
@@ -32,7 +32,7 @@ function SearchCard() {
-
Search..
+
Search...
Matching the criteria with 1.5 million members around the world..
diff --git a/src/routes/InputSkills/components/SearchCard/styles.module.scss b/src/routes/CreateNewTeam/components/SearchCard/styles.module.scss
similarity index 100%
rename from src/routes/InputSkills/components/SearchCard/styles.module.scss
rename to src/routes/CreateNewTeam/components/SearchCard/styles.module.scss
diff --git a/src/routes/CreateNewTeam/index.jsx b/src/routes/CreateNewTeam/index.jsx
index 08701d91..2ff109dc 100644
--- a/src/routes/CreateNewTeam/index.jsx
+++ b/src/routes/CreateNewTeam/index.jsx
@@ -18,11 +18,11 @@ import { postProject } from "services/teams";
import withAuthentication from "../../hoc/withAuthentication";
function CreateNewTeam() {
- const createProject = async () => {
+ const createProjectAndNavigate = async (navigateTo) => {
postProject()
.then((res) => {
const id = _.get(res, "data.id");
- navigate(`/taas/myteams/createnewteam/${id}/skills`);
+ navigate(`/taas/myteams/createnewteam/${id}/${navigateTo}`);
})
.catch((err) => {
toastr.warning("Error", "Failed to create a new team.");
@@ -41,14 +41,14 @@ 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%)"
- isDisabled
+ onClick={() => createProjectAndNavigate("role")}
/>
}
backgroundImage="linear-gradient(221.5deg, #2C95D7 0%, #9D41C9 100%)"
- onClick={createProject}
+ onClick={() => createProjectAndNavigate("skills")}
/>
{
- navigate(`/taas/myteams/createnewteam/${projectId}/role`);
+ navigate(`/taas/myteams/createnewteam/${projectId}/roles`);
}, [projectId]);
const toggleSkill = useCallback(
@@ -74,8 +80,10 @@ function InputSkills({ projectId }) {
// mocked search for users with given skills
const search = () => {
setSearchState("searching");
+ setCurrentStage(1, stages, setStages);
searchTimer = setTimeout(() => {
setSearchState("done");
+ setCurrentStage(2, stages, setStages);
}, 3000);
};
@@ -92,22 +100,32 @@ function InputSkills({ projectId }) {
/>
) : searchState === "searching" ? (
-
+
) : (
+ setIsOpen(!isOpen)} styleName="button">
+
+
+ {addedRoles.length}{" "}
+ {addedRoles.length > 1 ? "roles have" : "role has"} been added.
+
+
+
+
+ {isOpen && (
+
+ {addedRoles.map(({ name }) => (
+
{name}
+ ))}
+
+ )}
+
+ );
+}
+
+AddedRolesAccordion.propTypes = {
+ addedRoles: PT.arrayOf(PT.string),
+};
+
+export default AddedRolesAccordion;
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/components/AddedRolesAccordion/styles.module.scss b/src/routes/CreateNewTeam/pages/SelectRole/components/AddedRolesAccordion/styles.module.scss
new file mode 100644
index 00000000..6478f1f0
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/components/AddedRolesAccordion/styles.module.scss
@@ -0,0 +1,72 @@
+@import "styles/include";
+
+.accordion {
+ border-radius: 8px;
+ box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.02);
+ background-color: #FFFFFF;
+ width: 250px;
+}
+
+.button {
+ cursor: pointer;
+ width: 100%;
+ border: none;
+ outline: none;
+ border-radius: 8px;
+ background-color: #fff;
+ color: #2a2a2a;
+ display: flex;
+ text-align: left;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+ padding: 15px 14px 10px 16px;
+}
+
+.arrow {
+ display: inline-block;
+ height: 10px;
+ width: 10px;
+ border-bottom: 3px solid #2A2A2A;
+ border-right: 3px solid #2A2A2A;
+ margin-bottom: 4px;
+ &.down {
+ transform: rotate(45deg);
+ }
+ &.up {
+ transform: rotate(-135deg);
+ }
+}
+
+.heading {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+}
+
+.title {
+ @include font-roboto;
+ font-size: 14px;
+ line-height: 22px;
+}
+
+.panel {
+ padding: 12px 18px 14px 10px;
+ .role-name {
+ height: 40px;
+ width: 100%;
+ background-color: #F4F4F4;
+ border-radius: 6px;
+ padding: 10px;
+ @include font-barlow;
+ font-size: 16px;
+ line-height: 20px;
+ font-weight: 600;
+ text-transform: uppercase;
+ &:not(:first-child) {
+ margin-top: 5px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/index.jsx
new file mode 100644
index 00000000..f1a47f05
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/index.jsx
@@ -0,0 +1,63 @@
+/**
+ * Role Item
+ * An item for the Role List component.
+ * Shows an image and the name of the role.
+ */
+import React, { useState, useCallback } from "react";
+import PT from "prop-types";
+import cn from "classnames";
+import FallbackIcon from "../../../../../../assets/images/icon-role-fallback.svg";
+import "./styles.module.scss";
+
+function RoleItem({
+ id,
+ name,
+ imageUrl,
+ onClick,
+ onDescriptionClick,
+ isSelected,
+}) {
+ const [error, setError] = useState(false);
+ const onImgError = useCallback(() => setError(true), []);
+
+ return (
+
onClick(id)}
+ >
+ {imageUrl && !error ? (
+

+ ) : (
+
+ )}
+
{name}
+
{
+ event.preventDefault();
+ event.stopPropagation();
+ onDescriptionClick(id);
+ }}
+ >
+ Description
+
+
+ );
+}
+
+RoleItem.propTypes = {
+ id: PT.string,
+ name: PT.string,
+ onClick: PT.func,
+ onDescriptionClick: PT.func,
+ isSelected: PT.bool,
+};
+
+export default RoleItem;
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/styles.module.scss b/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/styles.module.scss
new file mode 100644
index 00000000..3f5b7652
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/components/RoleItem/styles.module.scss
@@ -0,0 +1,48 @@
+@import "styles/include";
+
+.item-card {
+ border: 1px solid #d4d4d4;
+ border-radius: 5px;
+ padding: 12px 16px;
+ width: 213px;
+ height: 136px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-evenly;
+ margin: 0 0 24px 24px;
+ cursor: pointer;
+
+ &.selected {
+ border-color: #0ab88a;
+ background-color: #e0faf3;
+ }
+}
+
+.role-icon {
+ width: 42px;
+ height: 42px;
+ margin-left: 8px;
+}
+
+.item-text {
+ @include font-barlow;
+ font-size: 16px;
+ font-weight: 600;
+ line-height: 20px;
+ text-transform: uppercase;
+}
+
+.button {
+ font-size: 14px;
+ line-height: 22px;
+ padding: 0;
+ outline: none;
+ background: none;
+ color: #0D61BF;
+ border: none;
+ text-align: left;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/index.jsx
new file mode 100644
index 00000000..88bd66f7
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/index.jsx
@@ -0,0 +1,94 @@
+/**
+ * Roles List
+ * Lists all roles available to apply to a job
+ * and search for. Allows selecting roles and filtering
+ * by name.
+ */
+import React, { useEffect, useState } from "react";
+import { useDebounce } from "react-use";
+import PT from "prop-types";
+import Input from "components/Input";
+import PageHeader from "components/PageHeader";
+import "./styles.module.scss";
+import RoleItem from "../RoleItem";
+import { INPUT_DEBOUNCE_DELAY } from "constants/";
+
+function RolesList({ roles, selectedRoleId, onDescriptionClick, toggleRole }) {
+ const [filteredRoles, setFilteredRoles] = useState(roles);
+ const [filter, setFilter] = useState("");
+ const [debouncedFilter, setDebouncedFilter] = useState("");
+
+ const onFilterChange = (e) => {
+ setFilter(e.target.value);
+ };
+
+ useDebounce(
+ () => {
+ setDebouncedFilter(filter);
+ },
+ INPUT_DEBOUNCE_DELAY,
+ [filter]
+ );
+
+ useEffect(() => {
+ if (debouncedFilter.length > 0) {
+ const filterText = debouncedFilter.toLowerCase();
+ setFilteredRoles(
+ roles.filter((role) => role.name.toLowerCase().includes(filterText))
+ );
+ } else {
+ setFilteredRoles(roles);
+ }
+ }, [debouncedFilter, roles]);
+
+ return (
+
+ );
+}
+
+RolesList.propTypes = {
+ roles: PT.array,
+ selectedRoleId: PT.string,
+ toggleRole: PT.func,
+};
+
+export default RolesList;
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/styles.module.scss b/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/styles.module.scss
new file mode 100644
index 00000000..bc9e544e
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/components/RolesList/styles.module.scss
@@ -0,0 +1,67 @@
+@import "styles/include";
+
+.roles-list {
+ @include rounded-card;
+ max-width: 746px;
+ margin-right: 20px;
+ position: relative;
+
+ > header {
+ padding: 16px 24px;
+ }
+}
+
+.role-count {
+ position: absolute;
+ font-size: 12px;
+ top: 72px;
+ left: 73px;
+}
+
+// adding "input:not([type="checkbox"])" to make sure that we override reset styles
+input:not([type="checkbox"]).filter-input {
+ display: inline-block;
+ position: relative;
+ width: 300px;
+ background-color: #ffffff;
+ border: 1px solid #aaaaaa;
+ border-radius: 6px;
+ box-sizing: border-box;
+ color: #2a2a2a;
+ font-size: 14px;
+ height: 40px;
+ line-height: 38px;
+ outline: none;
+ padding: 0 15px;
+
+ &:not(:focus) {
+ background-image: url("../../../../../../assets/images/icon-search.svg");
+ background-repeat: no-repeat;
+ background-position: 10px center;
+ text-indent: 20px;
+ }
+
+ &::placeholder {
+ color: #aaaaaa;
+ }
+}
+
+.clear-input-button {
+ position: absolute;
+ right: 35px;
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 38px;
+ cursor: pointer;
+ &:hover {
+ color: rgb(216, 24, 24);
+ }
+}
+
+.role-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ flex-wrap: wrap;
+ margin-right: 24px;
+}
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
new file mode 100644
index 00000000..a8137e94
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
@@ -0,0 +1,191 @@
+/**
+ * Select Role Page
+ *
+ * Gets project id from the router.
+ *
+ * Allows selecting a role, searching for users
+ * with that role, and submitting a job requiring the roles.
+ */
+import React, { useCallback, useEffect, useState } from "react";
+import { useData } from "hooks/useData";
+import { navigate } from "@reach/router";
+import { toastr } from "react-redux-toastr";
+import PT from "prop-types";
+import RolesList from "./components/RolesList";
+import Completeness from "../../components/Completeness";
+import "./styles.module.scss";
+import { getRoles } from "services/roles";
+import { setCurrentStage } from "utils/helpers";
+import LoadingIndicator from "components/LoadingIndicator";
+import SearchCard from "../../components/SearchCard";
+import ResultCard from "../../components/ResultCard";
+import NoMatchingProfilesResultCard from "../../components/NoMatchingProfilesResultCard";
+import { createJob } from "services/jobs";
+import AddAnotherModal from "../../components/AddAnotherModal";
+import RoleDetailsModal from "../../components/RoleDetailsModal";
+import withAuthentication from "../../../../hoc/withAuthentication";
+import AddedRolesAccordion from "./components/AddedRolesAccordion";
+
+function SelectRole({ projectId }) {
+ const [stages, setStages] = useState([
+ { name: "Select a Role", isCurrent: true },
+ { name: "Search Member" },
+ { name: "Overview of the Results" },
+ ]);
+ const [addedRoles, setAddedRoles] = useState([]);
+ const [selectedRoleId, setSelectedRoleId] = useState(null);
+ const [searchState, setSearchState] = useState(null);
+ const [matchingProfiles, setMatchingProfiles] = useState(null);
+ const [addAnotherModalOpen, setAddAnotherModalOpen] = useState(false);
+ const [roleDetailsModalOpen, setRoleDetailsModalOpen] = useState(false);
+ const [roleDetailsModalId, setRoleDetailsModalId] = useState(null);
+ const [submitDone, setSubmitDone] = useState(true);
+
+ const [roles, loadingError] = useData(getRoles);
+
+ let searchTimer;
+
+ const submitJob = () => {
+ setSubmitDone(false);
+ createJob({
+ projectId,
+ title: `job-${Date()}`,
+ skills: [],
+ roleIds: addedRoles.map((r) => r.id),
+ numPositions: 1,
+ })
+ .then(() => {
+ toastr.success("Job Submitted");
+ })
+ .catch((err) => {
+ console.error(err);
+ toastr.warning("Error Submitting Job");
+ })
+ .finally(() => {
+ setSubmitDone(true);
+ navigate("/taas/myteams");
+ });
+ };
+
+ const addAnother = useCallback(() => {
+ setSelectedRoleId(null);
+ setCurrentStage(0, stages, setStages);
+ setAddAnotherModalOpen(false);
+ setSearchState(null);
+ }, [stages]);
+
+ const toggleRole = useCallback(
+ (id) => {
+ setSelectedRoleId((selectedRoleId) =>
+ id === selectedRoleId ? null : id
+ );
+ },
+ [setSelectedRoleId]
+ );
+
+ const onDescriptionClick = useCallback((roleId) => {
+ setRoleDetailsModalId(roleId);
+ setRoleDetailsModalOpen(true);
+ }, []);
+
+ // mocked search for users with given roles
+ const search = () => {
+ setCurrentStage(1, stages, setStages);
+ setSearchState("searching");
+ searchTimer = setTimeout(() => {
+ setCurrentStage(2, stages, setStages);
+ setMatchingProfiles(null); // display no matching profiles screen for a while
+ setSearchState("done");
+ setTimeout(() => setMatchingProfiles(true), 2000);
+ // add selected role
+ const { id, name } = roles.find((r) => r.id === selectedRoleId);
+ setAddedRoles((addedRoles) => [...addedRoles, { id, name }]);
+ }, 3000);
+ };
+
+ useEffect(() => clearTimeout(searchTimer));
+
+ if (!roles) {
+ return
;
+ }
+
+ if (roles && !searchState) {
+ return (
+
+
+
+ {addedRoles.length > 0 && (
+
+ )}
+
+
setRoleDetailsModalOpen(false)}
+ />
+
+
+ );
+ }
+
+ if (searchState === "searching") {
+ return (
+
+
+
+
+ );
+ }
+
+ if (searchState === "done") {
+ return (
+
+ {matchingProfiles ?
:
}
+
+ {matchingProfiles &&
}
+
setAddAnotherModalOpen(true)}
+ />
+
+ {matchingProfiles && (
+
setAddAnotherModalOpen(false)}
+ submitDone={submitDone}
+ onContinueClick={submitJob}
+ addAnother={addAnother}
+ />
+ )}
+
+ );
+ }
+}
+
+SelectRole.propTypes = {
+ projectId: PT.string,
+};
+
+export default withAuthentication(SelectRole);
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/styles.module.scss b/src/routes/CreateNewTeam/pages/SelectRole/styles.module.scss
new file mode 100644
index 00000000..7bacc294
--- /dev/null
+++ b/src/routes/CreateNewTeam/pages/SelectRole/styles.module.scss
@@ -0,0 +1,14 @@
+.page {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: flex-start;
+ margin: 42px 35px;
+ .right-side {
+ display: flex;
+ flex-direction: column;
+ & > div:not(:first-child) {
+ margin-top: 16px;
+ }
+ }
+}
diff --git a/src/routes/InputSkills/components/Completeness/index.jsx b/src/routes/InputSkills/components/Completeness/index.jsx
deleted file mode 100644
index 4bc91ac9..00000000
--- a/src/routes/InputSkills/components/Completeness/index.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Completeness Sidebar
- * Shows level of completeness through skill
- * input process and contains a button for
- * searching for users or submitting the job.
- */
-import Button from "components/Button";
-import React from "react";
-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";
-
-function Completeness({ isDisabled, onClick, buttonLabel, stage }) {
- return (
-
-
-
- - 1 }
- )}
- >
- Input Skills
-
- -
- Search Member
-
- -
- Overview of the Results
-
-
-
- {buttonLabel}
-
-
-
- );
-}
-
-Completeness.propTypes = {
- isDisabled: PT.bool,
- onClick: PT.func,
- buttonLabel: PT.string,
- stage: PT.number,
-};
-
-export default Completeness;
diff --git a/src/routes/InputSkills/components/ResultCard/index.jsx b/src/routes/InputSkills/components/ResultCard/index.jsx
deleted file mode 100644
index 01a98935..00000000
--- a/src/routes/InputSkills/components/ResultCard/index.jsx
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Result Card
- * Card that appears after searching for
- * users matching given skills. Gives information
- * about costs and number of matching candidates.
- */
-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 Button from "components/Button";
-
-function ResultCard() {
- const [showRates, setShowRates] = useState(false);
-
- return (
-
-
-
-
We have matching profiles
-
- We have qualified candidates who match 80% or more of your job
- requirements.
-
-
-
-
-
- setShowRates(false)}
- >
- Overview
-
- setShowRates(true)}
- >
- Rate Details
-
-
- {showRates ? (
-
-
-
-
-
Full-Time
-
(40h / week)
-
-
-
-
-
-
Part-Time
-
(30h / week)
-
-
-
-
-
-
Part-Time
-
(20h / week)
-
-
-
-
-
-
-
-
-
-
Qualified candidates within
-
24h
-
-
-
-
-
-
Interviews can start within
-
48h
-
-
-
-
- ) : (
- <>
-
-
-
-
-
-
300+
-
Members matched
-
-
-
-
- 60% of members are available 20 hours / week (part
- time)
-
-
- 20% of members are available 30 hours / week (part
- time)
-
-
- 10% of members are available 40 hours / week (full
- time)
-
-
- >
- )}
-
- );
-}
-
-export default ResultCard;
diff --git a/src/routes/SelectRole/index.jsx b/src/routes/SelectRole/index.jsx
deleted file mode 100644
index 5f6fa502..00000000
--- a/src/routes/SelectRole/index.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Select Role
- * Page for selecting a role to add to your team
- */
-
-import React from "react";
-
-function SelectRole() {
- return
Select A Role
;
-}
-
-export default SelectRole;
diff --git a/src/services/roles.js b/src/services/roles.js
new file mode 100644
index 00000000..f3d154ae
--- /dev/null
+++ b/src/services/roles.js
@@ -0,0 +1,94 @@
+/**
+ * Topcoder TaaS Service for Roles
+ */
+
+const mockRoles = [
+ {
+ id: "78c1d981-f235-4a75-97fb-693a26d2a56d",
+ name: "Python Engineer",
+ description: "Python Engineer Description",
+ listOfSkills: [],
+ imageUrl: "https://svgur.com/i/XdC.svg",
+ },
+ {
+ id: "bf1011c1-336a-4ec4-aa07-a916d648dbb4",
+ name: "Android Developer",
+ description: "Android Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/Xe_.svg",
+ },
+ {
+ id: "532433a6-505d-41fe-beb2-815e9b999077",
+ name: "SQL Engineer",
+ description: "SQL Engineer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/Xe2.svg",
+ },
+ {
+ id: "3f5ee777-7221-4fe8-ba3a-11cf09077d3f",
+ name: ".NET Developer",
+ description: ".NET Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/XeW.svg",
+ },
+ {
+ id: "94653ab7-9e48-4ef2-b5c3-cbd720f134ad",
+ name: "C# Developer",
+ description: "C# Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/XeV.svg",
+ },
+ {
+ id: "b663d69b-fd56-4ab6-8ef6-3560c4ad0be3",
+ name: "Angular Developer",
+ description: "Angular Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/XeX.svg",
+ },
+ {
+ id: "e1f25908-664f-4956-a069-08017064b4be",
+ name: "Ajax Developer",
+ description: "Ajax Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/Xeu.svg",
+ },
+ {
+ id: "8d7f43da-d126-4f53-8146-7d874fb44bff",
+ name: "API Developer",
+ description: "API Developer Description",
+ listOfSkills: [],
+ imageUrl: "http://svgur.com/i/Xcr.svg",
+ },
+ {
+ id: "98895ea0-f9f8-4abb-ae6b-b00567eafa93",
+ name: "Python Engineer",
+ description: "Python Engineer Description",
+ listOfSkills: [],
+ imageUrl: "https://svgur.com/i/XdC.svg",
+ },
+ {
+ id: "212de943-944f-40a1-871a-af384f462644",
+ name: "Role FallbackIcon",
+ description: "Role for FallbackIcon Description",
+ listOfSkills: [],
+ imageUrl: "https://svgur.com/i/XdC-nonexisting.svg",
+ },
+];
+
+/**
+ * Mock API request. Returns a list of mock roles.
+ */
+export function getRoles() {
+ return new Promise((resolve) =>
+ setTimeout(resolve, 1500, { data: mockRoles })
+ );
+}
+
+/**
+ * Mock API request. Returns a single role.
+ */
+export function getRoleById(id) {
+ return new Promise((resolve) =>
+ setTimeout(resolve, 1500, { data: mockRoles.find((r) => r.id === id) })
+ );
+}
diff --git a/src/utils/helpers.js b/src/utils/helpers.js
index 53f24cd2..5de1d653 100644
--- a/src/utils/helpers.js
+++ b/src/utils/helpers.js
@@ -38,3 +38,27 @@ export const getSelectOptionByValue = (value, selectOptions) => {
return option;
};
+
+/**
+ * Activates the current step in the Completion Box.
+ *
+ * * Set `isCurrent: true` of the current step.
+ * * Set `isCurrent: false` for all other steps.
+ * * Set `complete: true` for steps prior to the current.
+ * * Set `complete: false` for the steps after the current.
+ *
+ * @param {Number} currentStepIdx 0-based index of the current step
+ * @param {Array} stages stages array
+ * @param {Function} setStagesCallback `setStages` callback to update state
+ */
+export const setCurrentStage = (currentStepIdx, stages, setStagesCallback) => {
+ setStagesCallback([
+ ...stages
+ .slice(0, currentStepIdx)
+ .map((s) => ({ ...s, completed: true, isCurrent: false })),
+ { ...stages[currentStepIdx], isCurrent: true, completed: false },
+ ...stages
+ .slice(currentStepIdx + 1)
+ .map((s) => ({ ...s, completed: false, isCurrent: false })),
+ ]);
+};