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

Feature/member management Add Members Directly #107

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"redux": "^4.0.5",
"redux-logger": "^3.0.6",
"redux-promise-middleware": "^6.1.2",
"redux-thunk": "^2.3.0"
"redux-thunk": "^2.3.0",
"tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.4"
},
"browserslist": [
"last 1 version",
Expand Down
13 changes: 11 additions & 2 deletions src/components/BaseModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,22 @@ const containerStyle = {
padding: "10px",
};

function BaseModal({ open, onClose, children, title, button, disabled }) {
function BaseModal({
open,
onClose,
children,
title,
button,
disabled,
extraModalStyle,
}) {
return (
<Modal
open={open}
onClose={onClose}
closeIcon={<IconCross width="15px" height="15px" />}
styles={{
modal: modalStyle,
modal: { ...modalStyle, ...extraModalStyle },
modalContainer: containerStyle,
}}
center={true}
Expand Down Expand Up @@ -63,6 +71,7 @@ BaseModal.propTypes = {
title: PT.string,
button: PT.element,
disabled: PT.bool,
extraModalStyle: PT.object,
};

export default BaseModal;
2 changes: 1 addition & 1 deletion src/components/DateInput/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ DateInput.propTypes = {
placeholder: PT.string,
onBlur: PT.func,
onFocus: PT.func,
className: PT.string
className: PT.string,
};

export default DateInput;
3 changes: 1 addition & 2 deletions src/components/DateInput/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
width: 100%;
}
&.error {
input{
input {
border-color: #fe665d;
}

}
}

Expand Down
8 changes: 4 additions & 4 deletions src/components/FormField/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const FormField = ({ field }) => {
<Field name={field.name}>
{({ input, meta }) => (
<div>
{ !field.readonly && (
{!field.readonly && (
<label
styleName={
(input.value != "undefined" &&
Expand Down Expand Up @@ -89,9 +89,9 @@ const FormField = ({ field }) => {
onFocus={input.onFocus}
/>
)}
{(field.isRequired || field.customValidator) && meta.error && meta.touched && (
<div styleName="field-error">{meta.error}</div>
)}
{(field.isRequired || field.customValidator) &&
meta.error &&
meta.touched && <div styleName="field-error">{meta.error}</div>}
</div>
)}
</Field>
Expand Down
45 changes: 33 additions & 12 deletions src/components/ReactSelect/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import React from "react";
import PT from "prop-types";
import Select from "react-select";
import CreatableSelect from "react-select/creatable";
import "./styles.module.scss";

const ReactSelect = (props) => {
Expand Down Expand Up @@ -69,18 +70,36 @@ const ReactSelect = (props) => {

return (
<div styleName="select-wrapper">
<Select
value={props.value}
styles={customStyles}
onChange={props.onChange}
options={props.options}
styleName={props.error ? "error" : ""}
isMulti={props.isMulti}
onBlur={props.onBlur}
onFocus={props.onFocus}
placeholder={props.placeholder}
onInputChange={props.onInputChange}
/>
{props.isCreatable ? (
<CreatableSelect
value={props.value}
styles={customStyles}
onChange={props.onChange}
options={props.options}
styleName={props.error ? "error" : ""}
isMulti={props.isMulti}
onBlur={props.onBlur}
onFocus={props.onFocus}
placeholder={props.placeholder}
onInputChange={props.onInputChange}
noOptionsMessage={() => props.noOptionsText}
createOptionPosition="first"
/>
) : (
<Select
value={props.value}
styles={customStyles}
onChange={props.onChange}
options={props.options}
styleName={props.error ? "error" : ""}
isMulti={props.isMulti}
onBlur={props.onBlur}
onFocus={props.onFocus}
placeholder={props.placeholder}
onInputChange={props.onInputChange}
noOptionsMessage={() => props.noOptionsText}
/>
)}
</div>
);
};
Expand All @@ -100,6 +119,8 @@ ReactSelect.propTypes = {
label: PT.string.isRequired,
}).isRequired
),
isCreatable: PT.bool,
noOptionsText: PT.string,
};

export default ReactSelect;
4 changes: 1 addition & 3 deletions src/components/TCForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ const TCForm = ({
<div styleName="field-group">
{row.fields.map((field) => (
<div styleName="field-group-field" key={field.name}>
<FormField
field={fields[field]}
/>
<FormField field={fields[field]} />
</div>
))}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/TCForm/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}
}

.job-form-fields-wrapper{
.job-form-fields-wrapper {
width: 100%;
max-width: 640px;
margin: 0 auto;
Expand Down
2 changes: 1 addition & 1 deletion src/components/TextInput/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "./styles.module.scss";
function TextInput(props) {
return (
<input
styleName={cn("TextInput", props.className, {"readonly": props.readonly})}
styleName={cn("TextInput", props.className, { readonly: props.readonly })}
maxLength={props.maxLength}
min={props.minValue}
onChange={(event) => {
Expand Down
27 changes: 27 additions & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,30 @@ export const STATUS_OPTIONS = [
{ value: "closed", label: "closed" },
{ value: "cancelled", label: "cancelled" },
];

/*
* TopCoder user roles
*/
export const ROLE_TOPCODER_USER = "Topcoder User";
export const ROLE_CONNECT_COPILOT = "Connect Copilot";
export const ROLE_CONNECT_MANAGER = "Connect Manager";
export const ROLE_CONNECT_ACCOUNT_MANAGER = "Connect Account Manager";
export const ROLE_CONNECT_ADMIN = "Connect Admin";
export const ROLE_ADMINISTRATOR = "administrator";
export const ROLE_CONNECT_COPILOT_MANAGER = "Connect Copilot Manager";
export const ROLE_BUSINESS_DEVELOPMENT_REPRESENTATIVE =
"Business Development Representative";
export const ROLE_PRESALES = "Presales";
export const ROLE_ACCOUNT_EXECUTIVE = "Account Executive";
export const ROLE_PROGRAM_MANAGER = "Program Manager";
export const ROLE_SOLUTION_ARCHITECT = "Solution Architect";
export const ROLE_PROJECT_MANAGER = "Project Manager";

// User roles that can see suggestions when adding new members to project
export const SEE_SUGGESTION_ROLES = [
ROLE_ADMINISTRATOR,
ROLE_CONNECT_ADMIN,
ROLE_CONNECT_MANAGER,
ROLE_CONNECT_ACCOUNT_MANAGER,
ROLE_CONNECT_COPILOT_MANAGER,
];
11 changes: 8 additions & 3 deletions src/routes/JobDetails/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ const JobDetails = ({ teamId, jobId }) => {
const skill = _.find(skills, { id: skillId });

if (!skill) {
console.warn(`Couldn't find name for skill id "${skillId}" of the job "${job.id}".`)
return null
console.warn(
`Couldn't find name for skill id "${skillId}" of the job "${job.id}".`
);
return null;
}

return skill.name;
Expand Down Expand Up @@ -79,7 +81,10 @@ const JobDetails = ({ teamId, jobId }) => {
<DataItem title="Resource Type" icon={<IconDescription />}>
{job.resourceType}
</DataItem>
<DataItem title="Resource Rate Frequency" icon={<IconDescription />}>
<DataItem
title="Resource Rate Frequency"
icon={<IconDescription />}
>
{job.rateType}
</DataItem>
<DataItem title="Workload" icon={<IconDescription />}>
Expand Down
29 changes: 15 additions & 14 deletions src/routes/JobForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,21 @@ const JobForm = ({ teamId, jobId }) => {

// as we are using `PUT` method (not `PATCH`) we have send ALL the fields
// fields which we don't send would become `null` otherwise
const getRequestData = (values) => _.pick(values, [
'projectId',
'externalId',
'description',
'title',
'startDate',
'duration',
'numPositions',
'resourceType',
'rateType',
'workload',
'skills',
'status',
]);
const getRequestData = (values) =>
_.pick(values, [
"projectId",
"externalId",
"description",
"title",
"startDate",
"duration",
"numPositions",
"resourceType",
"rateType",
"workload",
"skills",
"status",
]);

useEffect(() => {
if (skills && job && !options) {
Expand Down
14 changes: 10 additions & 4 deletions src/routes/PositionDetails/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import "./styles.module.scss";

const PositionDetails = ({ teamId, positionId }) => {
// be dafault show "Interested" tab
const [candidateStatus, setCandidateStatus] = useState(CANDIDATE_STATUS.SHORTLIST);
const [candidateStatus, setCandidateStatus] = useState(
CANDIDATE_STATUS.SHORTLIST
);
const {
state: { position, error },
updateCandidate,
Expand All @@ -32,10 +34,14 @@ const PositionDetails = ({ teamId, positionId }) => {

// if there are some candidates to review, then show "To Review" tab by default
useEffect(() => {
if (position && _.filter(position.candidates, { status: CANDIDATE_STATUS.OPEN }).length > 0) {
setCandidateStatus(CANDIDATE_STATUS.OPEN)
if (
position &&
_.filter(position.candidates, { status: CANDIDATE_STATUS.OPEN }).length >
0
) {
setCandidateStatus(CANDIDATE_STATUS.OPEN);
}
}, [position])
}, [position]);

return (
<Page title="Job Details">
Expand Down
56 changes: 30 additions & 26 deletions src/routes/ResourceBookingDetails/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,30 @@ import ResourceDetails from "./ResourceDetails";
import "./styles.module.scss";

const ResourceBookingDetails = ({ teamId, resourceBookingId }) => {
const [resource, loadingError] = useData(getReourceBookingById, resourceBookingId);
const [resource, loadingError] = useData(
getReourceBookingById,
resourceBookingId
);
const [team, loadingTeamError] = useData(getTeamById, teamId);
const [jobTitle, setJobTitle] = useState("")
const [member, setMember] = useState("")
const [jobTitle, setJobTitle] = useState("");
const [member, setMember] = useState("");

useEffect(() => {
if (team) {
const resourceWithMemberDetails = _.find(
team.resources,
{ id: resourceBookingId }
);
const resourceWithMemberDetails = _.find(team.resources, {
id: resourceBookingId,
});

// resource inside Team object has all the member details we need
setMember(resourceWithMemberDetails);

if (resourceWithMemberDetails.jobId) {
const job = _.find(team.jobs, { id: resourceWithMemberDetails.jobId });
setJobTitle(_.get(job, "title", `<Not Found> ${resourceWithMemberDetails.jobId}`));
setJobTitle(
_.get(job, "title", `<Not Found> ${resourceWithMemberDetails.jobId}`)
);
} else {
setJobTitle("<Not Assigned>")
setJobTitle("<Not Assigned>");
}
}
}, [team, resourceBookingId]);
Expand All @@ -49,25 +53,25 @@ const ResourceBookingDetails = ({ teamId, resourceBookingId }) => {
{!(member && resource) ? (
<LoadingIndicator error={loadingError || loadingTeamError} />
) : (
<>
<PageHeader
title="Member Details"
backTo={`/taas/myteams/${teamId}`}
/>
<div styleName="content-wrapper">
<ResourceSummary member={member} />
<ResourceDetails resource={resource} jobTitle={jobTitle} />
<div styleName="actions">
<Button
size="medium"
routeTo={`/taas/myteams/${teamId}/rb/${resource.id}/edit`}
>
Edit Member Details
<>
<PageHeader
title="Member Details"
backTo={`/taas/myteams/${teamId}`}
/>
<div styleName="content-wrapper">
<ResourceSummary member={member} />
<ResourceDetails resource={resource} jobTitle={jobTitle} />
<div styleName="actions">
<Button
size="medium"
routeTo={`/taas/myteams/${teamId}/rb/${resource.id}/edit`}
>
Edit Member Details
</Button>
</div>
</div>
</>
)}
</div>
</>
)}
</Page>
);
};
Expand Down
Loading