From ae8738dbfa11504326dd9d1d581757e8ee0aad06 Mon Sep 17 00:00:00 2001
From: Michael Baghel
Date: Wed, 16 Jun 2021 11:48:58 +0400
Subject: [PATCH 1/6] New icon-role-fallback for RoleItem Change SkillItem to
use IconSkill Use localStorage to persist searched roles
---
src/assets/images/icon-role-fallback-old.svg | 17 +++++++
src/assets/images/icon-role-fallback.svg | 38 ++++++++------
src/routes/CreateNewTeam/actions/index.js | 29 +++++++++--
.../NoMatchingProfilesResultCard/index.jsx | 2 +-
.../components/SearchAndSubmit/index.jsx | 14 +++++-
.../components/SearchContainer/index.jsx | 34 ++-----------
.../components/SubmitContainer/index.jsx | 50 ++++---------------
.../components/SuccessCard/index.jsx | 2 +-
src/routes/CreateNewTeam/index.jsx | 20 +-------
.../components/SkillItem/index.jsx | 4 +-
.../CreateNewTeam/pages/SelectRole/index.jsx | 7 ---
src/routes/CreateNewTeam/reducers/index.js | 19 +++++--
12 files changed, 112 insertions(+), 124 deletions(-)
create mode 100644 src/assets/images/icon-role-fallback-old.svg
diff --git a/src/assets/images/icon-role-fallback-old.svg b/src/assets/images/icon-role-fallback-old.svg
new file mode 100644
index 00000000..9e0f1123
--- /dev/null
+++ b/src/assets/images/icon-role-fallback-old.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/images/icon-role-fallback.svg b/src/assets/images/icon-role-fallback.svg
index 9e0f1123..d285b7e6 100644
--- a/src/assets/images/icon-role-fallback.svg
+++ b/src/assets/images/icon-role-fallback.svg
@@ -1,17 +1,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Layer 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
diff --git a/src/routes/CreateNewTeam/actions/index.js b/src/routes/CreateNewTeam/actions/index.js
index 99106fc4..bb78565f 100644
--- a/src/routes/CreateNewTeam/actions/index.js
+++ b/src/routes/CreateNewTeam/actions/index.js
@@ -1,15 +1,23 @@
import { ACTION_TYPE } from "constants";
-export const clearSearchedRoles = () => ({
+const updateLocalStorage = (state) => {
+ try {
+ localStorage.setItem("rolesState", JSON.stringify(state));
+ } catch {
+ console.error("Unable to set localStorage");
+ }
+};
+
+const clearRoles = () => ({
type: ACTION_TYPE.CLEAR_SEARCHED_ROLES,
});
-export const addSearchedRole = (searchedRole) => ({
+const addRole = (searchedRole) => ({
type: ACTION_TYPE.ADD_SEARCHED_ROLE,
payload: searchedRole,
});
-export const addRoleSearchId = (id) => ({
+const addPreviousSearchId = (id) => ({
type: ACTION_TYPE.ADD_ROLE_SEARCH_ID,
payload: id,
});
@@ -18,3 +26,18 @@ export const replaceSearchedRoles = (roles) => ({
type: ACTION_TYPE.REPLACE_SEARCHED_ROLES,
payload: { roles, lastRoleId: roles[roles.length - 1].searchId },
});
+
+export const clearSearchedRoles = () => (dispatch, getState) => {
+ dispatch(clearRoles());
+ updateLocalStorage(getState().searchedRoles);
+};
+
+export const addSearchedRole = (searchedRole) => (dispatch, getState) => {
+ dispatch(addRole(searchedRole));
+ updateLocalStorage(getState().searchedRoles);
+};
+
+export const addRoleSearchId = (id) => (dispatch, getState) => {
+ dispatch(addPreviousSearchId(id));
+ updateLocalStorage(getState().searchedRoles);
+};
diff --git a/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx b/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx
index 18940725..2b1fd779 100644
--- a/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx
+++ b/src/routes/CreateNewTeam/components/NoMatchingProfilesResultCard/index.jsx
@@ -28,7 +28,7 @@ function NoMatchingProfilesResultCard() {
$1,200
/Week
-
+
Modify Search Criteria
diff --git a/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx b/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx
index 9f27e3ba..b801e2d1 100644
--- a/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx
+++ b/src/routes/CreateNewTeam/components/SearchAndSubmit/index.jsx
@@ -1,13 +1,23 @@
import { Router } from "@reach/router";
import React from "react";
+import { useSelector } from "react-redux";
import SearchContainer from "../SearchContainer";
import SubmitContainer from "../SubmitContainer";
function SearchAndSubmit(props) {
+ const { addedRoles, previousSearchId } = useSelector(
+ (state) => state.searchedRoles
+ );
+
return (
-
-
+
+
);
}
diff --git a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
index 4cf96c6f..7b85e495 100644
--- a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
@@ -19,25 +19,6 @@ import { setCurrentStage } from "utils/helpers";
import { addRoleSearchId, addSearchedRole } from "../../actions";
import "./styles.module.scss";
-/**
- * Converts an array of role search objects to two data
- * lists which can be set as sessionStorage items
- *
- * @param {object[]} arrayOfObjects array of role objects
- */
-const storeStrings = (arrayOfObjects) => {
- const objectOfArrays = arrayOfObjects.reduce(
- (acc, curr) => ({
- searchId: [...acc.searchId, curr.searchId],
- name: [...acc.name, curr.name],
- }),
- { searchId: [], name: [] }
- );
-
- sessionStorage.setItem("searchIds", objectOfArrays.searchId.join(","));
- sessionStorage.setItem("roleNames", objectOfArrays.name.join(","));
-};
-
function SearchContainer({
stages,
setStages,
@@ -45,24 +26,18 @@ function SearchContainer({
toRender,
searchObject,
completenessStyle,
- reloadRolesPage,
navigate,
+ addedRoles,
+ previousSearchId,
}) {
- const { addedRoles, previousSearchId } = useSelector(
- (state) => state.searchedRoles
- );
-
const [searchState, setSearchState] = useState(null);
const [matchingRole, setMatchingRole] = useState(null);
- const [addAnotherModalOpen, setAddAnotherModalOpen] = useState(false);
- const [submitDone, setSubmitDone] = useState(true);
const dispatch = useDispatch();
const onSubmit = useCallback(() => {
- storeStrings(addedRoles);
navigate("result", { state: { matchingRole } });
- }, [addedRoles, navigate, matchingRole]);
+ }, [navigate, matchingRole]);
const search = () => {
setCurrentStage(1, stages, setStages);
@@ -135,8 +110,9 @@ SearchContainer.propTypes = {
searchObject: PT.object,
toRender: PT.node,
completenessStyle: PT.string,
- reloadRolesPage: PT.func,
navigate: PT.func,
+ addedRoles: PT.array,
+ previousSearchId: PT.string,
};
export default SearchContainer;
diff --git a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
index a8223a29..aa1bbf78 100644
--- a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
@@ -19,46 +19,19 @@ import ConfirmationModal from "../ConfirmationModal";
import withAuthentication from "../../../../hoc/withAuthentication";
import "./styles.module.scss";
import { setCurrentStage } from "utils/helpers";
-import { clearSearchedRoles, replaceSearchedRoles } from "../../actions";
+import { clearSearchedRoles } from "../../actions";
import { postTeamRequest } from "services/teams";
import SuccessCard from "../SuccessCard";
-const retrieveRoles = () => {
- const searchIdString = sessionStorage.getItem("searchIds");
- const nameString = sessionStorage.getItem("roleNames");
-
- if (!searchIdString || !nameString) return [];
- const searchIds = searchIdString.split(",");
- const names = nameString.split(",");
- if (searchIds.length !== names.length) return [];
-
- const roles = [];
- for (let i = 0; i < searchIds.length; i++) {
- roles.push({
- searchId: searchIds[i],
- name: names[i],
- });
- }
-
- return roles;
-};
-
-const clearSessionKeys = () => {
- sessionStorage.removeItem("searchIds");
- sessionStorage.removeItem("roleNames");
-};
-
function SubmitContainer({
stages,
setStages,
completenessStyle,
- reloadRolesPage,
location,
+ addedRoles,
}) {
const matchingRole = location?.state?.matchingRole;
- const { addedRoles } = useSelector((state) => state.searchedRoles);
-
const [addAnotherOpen, setAddAnotherOpen] = useState(true);
const [teamDetailsOpen, setTeamDetailsOpen] = useState(false);
const [teamObject, setTeamObject] = useState(null);
@@ -66,14 +39,14 @@ function SubmitContainer({
const dispatch = useDispatch();
+ // Set correct state for Completeness tab, and redirect
+ // to main page if path loaded without any selected roles.
useEffect(() => {
setCurrentStage(2, stages, setStages);
- const storedRoles = retrieveRoles();
- if (storedRoles) {
- if (!addedRoles || storedRoles.length > addedRoles.length) {
- dispatch(replaceSearchedRoles(storedRoles));
- }
+ if (!addedRoles || addedRoles.length === 0) {
+ navigate("/taas/myteams/createnewteam");
}
+ // only needed on initial load, avoids too many re-renders
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -83,11 +56,7 @@ function SubmitContainer({
};
const addAnother = () => {
- if (reloadRolesPage) {
- setCurrentStage(0, stages, setStages);
- reloadRolesPage();
- }
- navigate("/taas/myteams/createnewteam/role");
+ navigate("/taas/myteams/createnewteam");
};
const assembleTeam = (formData) => {
@@ -121,7 +90,6 @@ function SubmitContainer({
postTeamRequest(teamObject)
.then((res) => {
const projectId = _.get(res, ["data", "projectId"]);
- clearSessionKeys();
dispatch(clearSearchedRoles());
navigate(`/taas/myteams/${projectId}`);
})
@@ -171,8 +139,8 @@ SubmitContainer.propTypes = {
stages: PT.array,
setStages: PT.func,
completenessStyle: PT.string,
- reloadRolesPage: PT.bool,
location: PT.object,
+ addedRoles: PT.array,
};
export default withAuthentication(SubmitContainer);
diff --git a/src/routes/CreateNewTeam/components/SuccessCard/index.jsx b/src/routes/CreateNewTeam/components/SuccessCard/index.jsx
index 1aa05fa8..ff2ee0da 100644
--- a/src/routes/CreateNewTeam/components/SuccessCard/index.jsx
+++ b/src/routes/CreateNewTeam/components/SuccessCard/index.jsx
@@ -30,7 +30,7 @@ function SuccessCard() {
Please use the button to the right to submit your request, or the
button below to search for additional roles.
-
+
Continue Search
diff --git a/src/routes/CreateNewTeam/index.jsx b/src/routes/CreateNewTeam/index.jsx
index 4158b2f8..efd722e5 100644
--- a/src/routes/CreateNewTeam/index.jsx
+++ b/src/routes/CreateNewTeam/index.jsx
@@ -1,9 +1,6 @@
/**
* Create New Team
*
- * Gets location state from router to pass
- * along to search pages
- *
* Landing page for creating new teams
* by selecting a role, inputting skills,
* or inputting a job description
@@ -11,25 +8,14 @@
import React, { useEffect } from "react";
import { navigate } from "@reach/router";
import _ from "lodash";
-import PT from "prop-types";
-import { useDispatch } from "react-redux";
import Page from "components/Page";
import PageHeader from "components/PageHeader";
import LandingBox from "./components/LandingBox";
import IconMultipleActionsCheck from "../../assets/images/icon-multiple-actions-check-2.svg";
import IconListQuill from "../../assets/images/icon-list-quill.svg";
import IconOfficeFileText from "../../assets/images/icon-office-file-text.svg";
-import { clearSearchedRoles } from "./actions";
-
-function CreateNewTeam({ location: { state: locationState } }) {
- const dispatch = useDispatch();
-
- useEffect(() => {
- if (!locationState || !locationState.keepAddedRoles) {
- dispatch(clearSearchedRoles());
- }
- });
+function CreateNewTeam() {
const goToRoute = (path) => {
navigate(path);
};
@@ -65,8 +51,4 @@ function CreateNewTeam({ location: { state: locationState } }) {
);
}
-CreateNewTeam.propTypes = {
- locationState: PT.object,
-};
-
export default CreateNewTeam;
diff --git a/src/routes/CreateNewTeam/pages/InputSkills/components/SkillItem/index.jsx b/src/routes/CreateNewTeam/pages/InputSkills/components/SkillItem/index.jsx
index ec94cea5..66a819e7 100644
--- a/src/routes/CreateNewTeam/pages/InputSkills/components/SkillItem/index.jsx
+++ b/src/routes/CreateNewTeam/pages/InputSkills/components/SkillItem/index.jsx
@@ -5,7 +5,7 @@
*/
import React from "react";
import PT from "prop-types";
-import IconQuestionCircle from "../../../../../../assets/images/icon-question-circle.svg";
+import IconSkill from "../../../../../../assets/images/icon-skill.svg";
import "./styles.module.scss";
import cn from "classnames";
@@ -28,7 +28,7 @@ function SkillItem({ id, name, onClick, isSelected }) {
styleName="image"
/>
) : (
-
+
)}
{name}
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
index 5488b60b..7486b59e 100644
--- a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
+++ b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
@@ -33,12 +33,6 @@ function SelectRole() {
setRoleDetailsModalOpen(true);
}, []);
- const resetState = () => {
- setSelectedRoleId(null);
- setRoleDetailsModalOpen(false);
- setRoleDetailsModalId(null);
- };
-
if (!roles) {
return ;
}
@@ -50,7 +44,6 @@ function SelectRole() {
isCompletenessDisabled={!selectedRoleId}
searchObject={{ roleId: selectedRoleId }}
completenessStyle="role-selection"
- reloadRolesPage={resetState}
toRender={
<>
{
+ const defaultState = {
+ previousSearchId: undefined,
+ addedRoles: [],
+ };
+ try {
+ const state = localStorage.getItem("rolesState");
+ if (state === null) {
+ return defaultState;
+ }
+ return JSON.parse(state);
+ } catch {
+ return defaultState;
+ }
};
+const initialState = loadState();
+
const reducer = (state = initialState, action) => {
switch (action.type) {
case ACTION_TYPE.CLEAR_SEARCHED_ROLES:
From 0d8961e760a028cf4db3dd0fca46e6b4f4d1988d Mon Sep 17 00:00:00 2001
From: Michael Baghel
Date: Wed, 16 Jun 2021 12:00:25 +0400
Subject: [PATCH 2/6] Remove unneccesary imports. Redirect user from results
page if no added roles before first paint.
---
.../components/SearchContainer/index.jsx | 2 +-
.../components/SubmitContainer/index.jsx | 21 ++++++++++++++-----
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
index 7b85e495..8e91bc3b 100644
--- a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
@@ -8,7 +8,7 @@
import React, { useCallback, useState } from "react";
import PT from "prop-types";
import _ from "lodash";
-import { useDispatch, useSelector } from "react-redux";
+import { useDispatch } from "react-redux";
import AddedRolesAccordion from "../AddedRolesAccordion";
import Completeness from "../Completeness";
import SearchCard from "../SearchCard";
diff --git a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
index aa1bbf78..55c493bb 100644
--- a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
@@ -4,9 +4,14 @@
* Requires authentication to complete submission process
* and contains a series of popups to lead user through the flow.
*/
-import React, { useCallback, useEffect, useState } from "react";
+import React, {
+ useCallback,
+ useEffect,
+ useLayoutEffect,
+ useState,
+} from "react";
import PT from "prop-types";
-import { useDispatch, useSelector } from "react-redux";
+import { useDispatch } from "react-redux";
import _ from "lodash";
import { toastr } from "react-redux-toastr";
import { navigate } from "@reach/router";
@@ -39,14 +44,20 @@ function SubmitContainer({
const dispatch = useDispatch();
- // Set correct state for Completeness tab, and redirect
- // to main page if path loaded without any selected roles.
useEffect(() => {
setCurrentStage(2, stages, setStages);
if (!addedRoles || addedRoles.length === 0) {
navigate("/taas/myteams/createnewteam");
}
- // only needed on initial load, avoids too many re-renders
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ // redirects user if they enter the page URL directly
+ // without adding any roles.
+ useLayoutEffect(() => {
+ if (!addedRoles || addedRoles.length === 0) {
+ navigate("/taas/myteams/createnewteam");
+ }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
From 4b8ede8ffc15aef66114ea684801a73d4804085c Mon Sep 17 00:00:00 2001
From: Michael Baghel
Date: Thu, 17 Jun 2021 14:39:53 +0400
Subject: [PATCH 3/6] Update styling of RoleDetailsModal. Client-side
validation for InputJobDescription. Ensure custom/niche role does not appear
in SelectRole page. Update ResultCard to read matching rate from search
result.
---
src/components/MarkdownEditor/index.jsx | 3 ++
.../MarkdownEditor/styles.module.scss | 31 ++++++++++---------
src/constants/index.js | 5 +++
.../components/CircularProgressBar/index.jsx | 2 +-
.../components/ResultCard/index.jsx | 15 ++++++---
.../components/RoleDetailsModal/index.jsx | 2 +-
.../RoleDetailsModal/styles.module.scss | 23 ++++++++++----
.../components/SearchContainer/index.jsx | 3 +-
.../pages/InputJobDescription/index.jsx | 7 ++++-
.../CreateNewTeam/pages/SelectRole/index.jsx | 7 ++++-
10 files changed, 67 insertions(+), 31 deletions(-)
diff --git a/src/components/MarkdownEditor/index.jsx b/src/components/MarkdownEditor/index.jsx
index 6c38b851..83939222 100644
--- a/src/components/MarkdownEditor/index.jsx
+++ b/src/components/MarkdownEditor/index.jsx
@@ -53,6 +53,9 @@ const MarkdownEditor = (props) => {
]}
plugins={[]}
/>
+ {props.errorMessage && (
+ {props.errorMessage}
+ )}
);
};
diff --git a/src/components/MarkdownEditor/styles.module.scss b/src/components/MarkdownEditor/styles.module.scss
index d444b248..13c0aa00 100644
--- a/src/components/MarkdownEditor/styles.module.scss
+++ b/src/components/MarkdownEditor/styles.module.scss
@@ -12,21 +12,6 @@
overflow-y: auto;
background: #fafafb;
}
- .message {
- @include font-roboto;
-
- width: 100%;
- text-align: center;
- min-height: 40px;
- line-height: 20px;
- padding: 9px 10px;
- margin: 10px 0 5px;
- font-size: 14px;
- color: #ff5b52;
- border: 1px solid #ffd5d1;
- cursor: auto;
- outline: none;
- }
}
.editor-container {
:global {
@@ -72,3 +57,19 @@
}
}
}
+
+.message {
+ @include font-roboto;
+
+ width: 100%;
+ text-align: center;
+ min-height: 40px;
+ line-height: 20px;
+ padding: 9px 10px;
+ margin: 10px 0 5px;
+ font-size: 14px;
+ color: #ff5b52;
+ border: 1px solid #ffd5d1;
+ cursor: auto;
+ outline: none;
+}
\ No newline at end of file
diff --git a/src/constants/index.js b/src/constants/index.js
index 5bc6228f..c0c822de 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -360,3 +360,8 @@ export const MAX_ALLOWED_INTERVIEWS = 3;
* Matching rate to show in CreateNewTeam ResultCard
*/
export const MATCHING_RATE = "80";
+
+/**
+ * Custom role names to remove from RoleList component
+ */
+export const CUSTOM_ROLE_NAMES = ["custom", "niche"];
diff --git a/src/routes/CreateNewTeam/components/CircularProgressBar/index.jsx b/src/routes/CreateNewTeam/components/CircularProgressBar/index.jsx
index 7a19f03e..06ea736c 100644
--- a/src/routes/CreateNewTeam/components/CircularProgressBar/index.jsx
+++ b/src/routes/CreateNewTeam/components/CircularProgressBar/index.jsx
@@ -14,7 +14,7 @@ const CircularProgressBar = ({ size, progress, children, strokeWidth }) => {
const radius = size / 2 - strokeWidth / 2;
const circumference = 2 * Math.PI * radius;
useEffect(() => {
- const progressOffset = ((100 - progress) / 100) * circumference;
+ const progressOffset = (1 - progress) * circumference;
setOffset(progressOffset);
circleRef.current.style = "transition: stroke-dashoffset 850ms ease-in-out";
}, [setOffset, progress, circumference, offset]);
diff --git a/src/routes/CreateNewTeam/components/ResultCard/index.jsx b/src/routes/CreateNewTeam/components/ResultCard/index.jsx
index c6920c22..09569ac7 100644
--- a/src/routes/CreateNewTeam/components/ResultCard/index.jsx
+++ b/src/routes/CreateNewTeam/components/ResultCard/index.jsx
@@ -23,10 +23,15 @@ function formatRate(value) {
return formatMoney(value);
}
+function formatPercent(value) {
+ return `${Math.round(value * 100)}%`;
+}
+
function ResultCard({ role }) {
const {
numberOfMembersAvailable,
isExternalMember,
+ matchingRate,
rates: [rates],
} = role;
const [userHandle, setUserHandle] = useState(null);
@@ -34,7 +39,7 @@ function ResultCard({ role }) {
useEffect(() => {
getAuthUserProfile().then((res) => {
- setUserHandle(res.handle || null);
+ setUserHandle(res?.handle || null);
});
}, []);
@@ -44,8 +49,8 @@ function ResultCard({ role }) {
We have matching profiles
- We have qualified candidates who match {MATCHING_RATE}% or more of
- your job requirements.
+ We have qualified candidates who match {formatPercent(matchingRate)}
+ {matchingRate < 1 ? " or more " : " "} of your job requirements.
@@ -217,11 +222,11 @@ function ResultCard({ role }) {
- {MATCHING_RATE}%
+ {formatPercent(matchingRate)}
Matching rate
}
diff --git a/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx b/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx
index a10f2de7..206e4ee5 100644
--- a/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx
+++ b/src/routes/CreateNewTeam/components/RoleDetailsModal/index.jsx
@@ -48,7 +48,7 @@ function RoleDetailsModal({ roleId, open, onClose }) {
[role, imgError]
);
- const skills = role ? role.listOfSkills : [];
+ const skills = role && role.listOfSkills ? role.listOfSkills : [];
const hideSkills = () => {
onClose();
diff --git a/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss
index e7470ce5..d8ad2bf7 100644
--- a/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss
+++ b/src/routes/CreateNewTeam/components/RoleDetailsModal/styles.module.scss
@@ -14,12 +14,23 @@
}
.markdown-container {
- // not adds specificity to override style
- p:not(table) {
- @include font-roboto;
- color: #2a2a2a;
- font-size: 16px;
- line-height: 26px;
+ :global {
+ // resets styles in markdown-viewer
+ .tui-editor-contents {
+ @include font-roboto;
+ color: #2a2a2a;
+ font-size: 16px;
+ line-height: 26px;
+ ul {
+ list-style: initial;
+ >li {
+ margin-bottom: 10px;
+ &::before {
+ background: none;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
index 8e91bc3b..8001cda5 100644
--- a/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SearchContainer/index.jsx
@@ -17,6 +17,7 @@ import NoMatchingProfilesResultCard from "../NoMatchingProfilesResultCard";
import { searchRoles } from "services/teams";
import { setCurrentStage } from "utils/helpers";
import { addRoleSearchId, addSearchedRole } from "../../actions";
+import { CUSTOM_ROLE_NAMES } from "constants";
import "./styles.module.scss";
function SearchContainer({
@@ -51,7 +52,7 @@ function SearchContainer({
.then((res) => {
const name = _.get(res, "data.name");
const searchId = _.get(res, "data.roleSearchRequestId");
- if (name && !name.toLowerCase().includes("niche")) {
+ if (name && !CUSTOM_ROLE_NAMES.includes(name.toLowerCase())) {
setMatchingRole(res.data);
dispatch(addSearchedRole({ searchId, name }));
} else if (searchId) {
diff --git a/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx b/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx
index 776267b3..9bc211e1 100644
--- a/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx
+++ b/src/routes/CreateNewTeam/pages/InputJobDescription/index.jsx
@@ -26,7 +26,7 @@ function InputJobDescription() {
255}
completenessStyle="input-job-description"
searchObject={{ jobDescription: jdString }}
toRender={
@@ -40,6 +40,11 @@ function InputJobDescription() {
height="482px"
placeholder="input job description"
onChange={onEditChange}
+ errorMessage={
+ jdString.length > 255
+ ? "Maximum of 255 characters. Please reduce job description length."
+ : ""
+ }
/>
>
diff --git a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
index 7486b59e..79522873 100644
--- a/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
+++ b/src/routes/CreateNewTeam/pages/SelectRole/index.jsx
@@ -8,10 +8,15 @@ import React, { useCallback, useState } from "react";
import { useData } from "hooks/useData";
import RolesList from "./components/RolesList";
import { getRoles } from "services/roles";
+import { CUSTOM_ROLE_NAMES } from "constants";
import LoadingIndicator from "components/LoadingIndicator";
import RoleDetailsModal from "../../components/RoleDetailsModal";
import SearchAndSubmit from "../../components/SearchAndSubmit";
+// Remove custom roles from role list
+const removeCustomRoles = (roles) =>
+ roles.filter(({ name }) => !CUSTOM_ROLE_NAMES.includes(name.toLowerCase()));
+
function SelectRole() {
const [stages, setStages] = useState([
{ name: "Select a Role", isCurrent: true },
@@ -47,7 +52,7 @@ function SelectRole() {
toRender={
<>
Date: Thu, 17 Jun 2021 18:41:32 +0400
Subject: [PATCH 4/6] Updates to behaviour of team description popup: Set min=1
on number inputs. Set maxlengths as per
https://github.com/topcoder-platform/taas-app/issues/313. Add cross-browser
month input component. Change durationWeek and numberOfResources to number
for request. Remove description value from form data when toggled off of
form.
---
package-lock.json | 43 ++++++++++++-----
package.json | 2 +-
src/components/FormField/index.jsx | 1 +
src/components/TextArea/index.jsx | 1 +
.../components/SubmitContainer/index.jsx | 7 +--
.../components/TeamDetailsModal/index.jsx | 48 +++++++++++++++----
src/styles/main.vendor.scss | 1 +
7 files changed, 75 insertions(+), 28 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index c5832bbb..da18caae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1249,6 +1249,25 @@
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
+ "@hypnosphi/create-react-context": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz",
+ "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==",
+ "requires": {
+ "gud": "^1.0.0",
+ "warning": "^4.0.3"
+ },
+ "dependencies": {
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ }
+ }
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -14434,24 +14453,24 @@
}
},
"react-datepicker": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.4.1.tgz",
- "integrity": "sha512-ASyVb7UmVx1vzeITidD7Cr/EXRXhKyjjbSkBndPc1MipYq4rqQ3eMFgvRQzpsXc3JmIMFgICm7nmN6Otc1GE/Q==",
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.8.0.tgz",
+ "integrity": "sha512-iFVNEp8DJoX5yEvEiciM7sJKmLGrvE70U38KhpG13XrulNSijeHw1RZkhd/0UmuXR71dcZB/kdfjiidifstZjw==",
"requires": {
"classnames": "^2.2.6",
"date-fns": "^2.0.1",
"prop-types": "^15.7.2",
- "react-onclickoutside": "^6.9.0",
- "react-popper": "^1.3.4"
+ "react-onclickoutside": "^6.10.0",
+ "react-popper": "^1.3.8"
},
"dependencies": {
"react-popper": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz",
- "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==",
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz",
+ "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==",
"requires": {
"@babel/runtime": "^7.1.2",
- "create-react-context": "^0.3.0",
+ "@hypnosphi/create-react-context": "^0.3.1",
"deep-equal": "^1.1.1",
"popper.js": "^1.14.4",
"prop-types": "^15.6.1",
@@ -14548,9 +14567,9 @@
}
},
"react-onclickoutside": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz",
- "integrity": "sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ=="
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.11.2.tgz",
+ "integrity": "sha512-640486eSwU/t5iD6yeTlefma8dI3bxPXD93hM9JGKyYITAd0P1JFkkcDeyHZRqNpY/fv1YW0Fad9BXr44OY8wQ=="
},
"react-outside-click-handler": {
"version": "1.3.0",
diff --git a/package.json b/package.json
index 4215d91d..61cd6967 100644
--- a/package.json
+++ b/package.json
@@ -71,7 +71,7 @@
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-avatar": "^3.9.7",
- "react-datepicker": "^3.4.1",
+ "react-datepicker": "^3.8.0",
"react-dom": "^16.12.0",
"react-final-form": "^6.5.2",
"react-final-form-arrays": "^3.1.3",
diff --git a/src/components/FormField/index.jsx b/src/components/FormField/index.jsx
index f43d48fc..c7de9520 100644
--- a/src/components/FormField/index.jsx
+++ b/src/components/FormField/index.jsx
@@ -82,6 +82,7 @@ const FormField = ({ field }) => {
onBlur={input.onBlur}
onFocus={input.onFocus}
className={meta.error && meta.touched ? "error" : ""}
+ maxLength={field.maxLength}
/>
)}
{field.type === FORM_FIELD_TYPE.DATE && (
diff --git a/src/components/TextArea/index.jsx b/src/components/TextArea/index.jsx
index 8ec9e7e5..fc247056 100644
--- a/src/components/TextArea/index.jsx
+++ b/src/components/TextArea/index.jsx
@@ -18,6 +18,7 @@ function TextArea(props) {
autoFocus={props.autoFocus}
onBlur={props.onBlur}
onFocus={props.onFocus}
+ maxLength={props.maxLength}
/>
);
}
diff --git a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
index 55c493bb..384ce6bc 100644
--- a/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
+++ b/src/routes/CreateNewTeam/components/SubmitContainer/index.jsx
@@ -78,11 +78,8 @@ function SubmitContainer({
if (key === "teamName" || key === "teamDescription") {
continue;
}
- const position = _.pick(
- formData[key],
- "numberOfResources",
- "durationWeeks",
- "startMonth"
+ const position = _.mapValues(formData[key], (val, key) =>
+ key === "startMonth" ? val : parseInt(val, 10)
);
position.roleSearchRequestId = key;
diff --git a/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx b/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx
index 716d375d..bb9c10f1 100644
--- a/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx
+++ b/src/routes/CreateNewTeam/components/TeamDetailsModal/index.jsx
@@ -12,12 +12,13 @@ import { FORM_FIELD_TYPE } from "constants/";
import { formatPlural } from "utils/format";
import Button from "components/Button";
import "./styles.module.scss";
+import DatePicker from "react-datepicker";
const Error = ({ name }) => {
const {
- meta: { touched, error },
- } = useField(name, { subscription: { touched: true, error: true } });
- return touched && error ? {error} : null;
+ meta: { dirty, error },
+ } = useField(name, { subscription: { dirty: true, error: true } });
+ return dirty && error ? {error} : null;
};
function TeamDetailsModal({ open, onClose, submitForm, addedRoles }) {
@@ -95,10 +96,21 @@ function TeamDetailsModal({ open, onClose, submitForm, addedRoles }) {
return (