Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 194af0f

Browse files
committedFeb 17, 2021
Merge branch 'dev' into feature/member-management
# Conflicts: # src/utils/format.js
2 parents 886757d + e8e3ec4 commit 194af0f

File tree

18 files changed

+231
-85
lines changed

18 files changed

+231
-85
lines changed
 

‎src/components/Babge/index.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Babge
3+
*
4+
* - type - see BABGE_TYPE values
5+
*
6+
*/
7+
import React from "react";
8+
import PT from "prop-types";
9+
import cn from "classnames";
10+
import { BABGE_TYPE } from "constants";
11+
import "./styles.module.scss";
12+
13+
const Babge = ({ children, type = BABGE_TYPE.PRIMARY }) => {
14+
return <span styleName={cn("babge", `type-${type}`)}>{children}</span>;
15+
};
16+
17+
Babge.propTypes = {
18+
children: PT.node,
19+
type: PT.oneOf(Object.values(BABGE_TYPE)),
20+
};
21+
22+
export default Babge;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@import "styles/include";
2+
3+
.babge {
4+
@include font-roboto;
5+
padding: 0 8px;
6+
line-height: 20px;
7+
border-radius: 5px;
8+
height: 20px;
9+
color: #FFFFFF;
10+
font-size: 12px;
11+
letter-spacing: 0.5px;
12+
text-align: left;
13+
}
14+
15+
.type-primary {
16+
background-color: #0ab88a;
17+
}
18+
19+
.type-danger {
20+
background-color: #ef476f;
21+
}

‎src/components/FormField/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const FormField = ({ field, isGroupField }) => {
4949
<TextInput
5050
placeholder={field.placeholder}
5151
value={input?.value ?? ""}
52+
isRequired={field.isRequired}
5253
type="number"
5354
minValue={field.minValue}
5455
onChange={input.onChange}

‎src/components/SkillsList/index.jsx

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -71,69 +71,69 @@ const SkillsList = ({ requiredSkills, skills, limit = 3 }) => {
7171
}, [isOpen, setIsOpen]);
7272

7373
return (
74-
<div styleName="skills-list">
75-
{_.map(skillsToShow, "name").join(", ")}
76-
{skillsToHide.length > 0 && (
74+
<OutsideClickHandler onOutsideClick={close} display="inline">
75+
<div
76+
styleName="skills-list"
77+
onClick={toggle}
78+
onMouseEnter={open}
79+
onMouseLeave={close}
80+
role="button"
81+
tabIndex={0}
82+
ref={setReferenceElement}
83+
>
84+
{_.map(skillsToShow, "name").join(", ")}
85+
86+
{skillsToHide.length > 0 && (
87+
<>
88+
{" and "}
89+
<span styleName="more">{skillsToHide.length > 0} more</span>
90+
</>
91+
)}
7792
<>
78-
{" and "}
79-
<OutsideClickHandler onOutsideClick={close} display="inline">
80-
<span
81-
styleName="more"
82-
onClick={toggle}
83-
onMouseEnter={open}
84-
onMouseLeave={close}
85-
role="button"
86-
tabIndex={0}
87-
ref={setReferenceElement}
93+
{isOpen && (
94+
<div
95+
styleName="popover"
96+
ref={setPopperElement}
97+
style={styles.popper}
98+
{...attributes.popper}
8899
>
89-
{skillsToHide.length > 0} more
90-
</span>
91-
92-
{isOpen && (
93-
<div
94-
styleName="popover"
95-
ref={setPopperElement}
96-
style={styles.popper}
97-
{...attributes.popper}
98-
>
99-
<div styleName="popover-content">
100-
{requiredSkills && (
101-
<div styleName="skills-section">
102-
<div styleName="skills-title">Required Job Skills</div>
103-
<ul styleName="skills-list">
104-
{!requiredSkills.length && <li>None</li>}
105-
{requiredSkills.map((skill) => (
106-
<li key={skill.id}>
107-
{_.find(skills, { id: skill.id }) ? (
108-
<IconCheck />
109-
) : (
110-
<IconCross />
111-
)}{" "}
112-
{skill.name}
113-
</li>
114-
))}
115-
</ul>
116-
</div>
117-
)}
118-
{otherSkills && (
119-
<div styleName="skills-section">
120-
<div styleName="skills-title">
121-
{showMatches ? "Other User Skills" : "Required Skills"}
122-
</div>
123-
<ul styleName="skills-list">
124-
{otherSkills.map((skill) => (
125-
<li key={skill.id}>{skill.name}</li>
126-
))}
127-
</ul>
100+
<div styleName="popover-content">
101+
{requiredSkills && (
102+
<div styleName="skills-section">
103+
<div styleName="skills-title">Required Job Skills</div>
104+
<ul styleName="skills-list">
105+
{!requiredSkills.length && <li>None</li>}
106+
{requiredSkills.map((skill) => (
107+
<li key={skill.id}>
108+
{_.find(skills, { id: skill.id }) ? (
109+
<IconCheck />
110+
) : (
111+
<IconCross />
112+
)}{" "}
113+
{skill.name}
114+
</li>
115+
))}
116+
</ul>
117+
</div>
118+
)}
119+
{otherSkills && (
120+
<div styleName="skills-section">
121+
<div styleName="skills-title">
122+
{showMatches ? "Other User Skills" : "Required Skills"}
128123
</div>
129-
)}
130-
</div>
124+
<ul styleName="skills-list">
125+
{otherSkills.map((skill) => (
126+
<li key={skill.id}>{skill.name}</li>
127+
))}
128+
</ul>
129+
</div>
130+
)}
131131
</div>
132-
)}
133-
</OutsideClickHandler>
132+
</div>
133+
)}
134134
</>
135-
)}
136-
</div>
135+
</div>
136+
</OutsideClickHandler>
137137
);
138138
};
139139

‎src/components/TextInput/index.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ function TextInput(props) {
2020
if (event.target.value >= props.minValue) {
2121
props.onChange(event.target.value);
2222
} else {
23-
props.onChange(props.minValue);
23+
if (props.isRequired) {
24+
props.onChange(props.minValue);
25+
} else {
26+
// can delete the number
27+
props.onChange("");
28+
}
2429
}
2530
} else {
2631
props.onChange(event.target.value);

‎src/constants/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ export const BUTTON_TYPE = {
7373
SEGMENT_SELECTED: "segment-selected",
7474
};
7575

76+
/**
77+
* Supported Babge Types
78+
*/
79+
export const BABGE_TYPE = {
80+
PRIMARY: "primary",
81+
DANGER: "danger",
82+
};
83+
7684
/**
7785
* Type of rate
7886
*/

‎src/routes/JobDetails/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ const JobDetails = ({ teamId, jobId }) => {
6464
<DataItem title="Start Date" icon={<IconDescription />}>
6565
{formatDate(job.startDate)}
6666
</DataItem>
67-
<DataItem title="End Date" icon={<IconDescription />}>
68-
{formatDate(job.endDate)}
67+
<DataItem title="Duration" icon={<IconDescription />}>
68+
{job.duration || "TBD"}
6969
</DataItem>
7070
<DataItem title="Resource Type" icon={<IconDescription />}>
7171
{job.resourceType}

‎src/routes/JobForm/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const JobForm = ({ teamId, jobId }) => {
6666
description: values.description,
6767
title: values.title,
6868
startDate: values.startDate,
69-
endDate: values.endDate,
69+
duration: values.duration,
7070
numPositions: values.numPositions,
7171
resourceType: values.resourceType,
7272
rateType: values.rateType,

‎src/routes/JobForm/utils.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const CREATE_JOB_ROWS = [
1414
{ type: FORM_ROW_TYPE.SINGLE, fields: ["description"] },
1515
{ type: FORM_ROW_TYPE.SINGLE, fields: ["numPositions"] },
1616
{ type: FORM_ROW_TYPE.SINGLE, fields: ["skills"] },
17-
{ type: FORM_ROW_TYPE.GROUP, fields: ["startDate", "endDate"] },
17+
{ type: FORM_ROW_TYPE.GROUP, fields: ["startDate", "duration"] },
1818
{ type: FORM_ROW_TYPE.SINGLE, fields: ["resourceType"] },
1919
{ type: FORM_ROW_TYPE.SINGLE, fields: ["rateType"] },
2020
{ type: FORM_ROW_TYPE.SINGLE, fields: ["workload"] },
@@ -26,7 +26,7 @@ const EDIT_JOB_ROWS = [
2626
{ type: FORM_ROW_TYPE.SINGLE, fields: ["description"] },
2727
{ type: FORM_ROW_TYPE.SINGLE, fields: ["numPositions"] },
2828
{ type: FORM_ROW_TYPE.SINGLE, fields: ["skills"] },
29-
{ type: FORM_ROW_TYPE.GROUP, fields: ["startDate", "endDate"] },
29+
{ type: FORM_ROW_TYPE.GROUP, fields: ["startDate", "duration"] },
3030
{ type: FORM_ROW_TYPE.SINGLE, fields: ["resourceType"] },
3131
{ type: FORM_ROW_TYPE.SINGLE, fields: ["rateType"] },
3232
{ type: FORM_ROW_TYPE.SINGLE, fields: ["workload"] },
@@ -79,10 +79,11 @@ export const getEditJobConfig = (skillOptions, onSubmit) => {
7979
placeholder: "Start Date",
8080
},
8181
{
82-
label: "End Date",
83-
type: FORM_FIELD_TYPE.DATE,
84-
name: "endDate",
85-
placeholder: "End Date",
82+
label: "Duration",
83+
type: FORM_FIELD_TYPE.NUMBER,
84+
name: "duration",
85+
minValue: 1,
86+
placeholder: "Duration",
8687
},
8788
{
8889
label: "Resource Type",
@@ -163,10 +164,11 @@ export const getCreateJobConfig = (skillOptions, onSubmit) => {
163164
placeholder: "Start Date",
164165
},
165166
{
166-
label: "End Date",
167-
type: FORM_FIELD_TYPE.DATE,
168-
name: "endDate",
169-
placeholder: "End Date",
167+
label: "Duration",
168+
type: FORM_FIELD_TYPE.NUMBER,
169+
name: "duration",
170+
minValue: 1,
171+
placeholder: "Duration",
170172
},
171173
{
172174
label: "Resource Type",

‎src/routes/MyTeamsDetails/components/TeamMembers/index.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import React, { useState, useCallback, useMemo } from "react";
77
import PT from "prop-types";
88
import "./styles.module.scss";
99
import _ from "lodash";
10+
import { navigate } from "@reach/router";
1011
import User from "components/User";
1112
import CardHeader from "components/CardHeader";
1213
// import Rating from "components/Rating";
@@ -146,6 +147,17 @@ const TeamMembers = ({ team }) => {
146147
<div styleName="table-cell cell-action">
147148
<ActionsMenu
148149
options={[
150+
{
151+
label: "Edit Member Details",
152+
action: () => {
153+
navigate(
154+
`/taas/myteams/${team.id}/rb/${member.id}/edit`
155+
);
156+
},
157+
},
158+
{
159+
separator: true,
160+
},
149161
{
150162
label: "Report an Issue",
151163
action: () => {

‎src/routes/MyTeamsDetails/components/TeamMembers/styles.module.scss

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
padding: 0 24px 24px;
77
}
88

9-
.filter-input {
9+
// adding "input:not([type="checkbox"])" to make sure that we override reset styles
10+
input:not([type="checkbox"]).filter-input {
1011
width: 380px;
1112
}
1213

@@ -223,10 +224,9 @@
223224
width: 100%;
224225
}
225226
}
226-
}
227227

228-
@media (max-width: 374px) {
229-
.filter-input {
228+
// adding "input:not([type="checkbox"])" to make sure that we override reset styles
229+
input:not([type="checkbox"]).filter-input {
230230
width: 100%;
231231
}
232232
}

‎src/routes/MyTeamsDetails/components/TeamPositions/index.jsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import SkillsList, { skillShape } from "components/SkillsList";
1010
import Button from "components/Button";
1111
import { POSITION_STATUS, POSITION_STATUS_TO_TEXT, RATE_TYPE } from "constants";
1212
import "./styles.module.scss";
13-
import { formatDateRange } from "utils/format";
13+
import { formatJobDate, formatOpenPositions } from "utils/format";
1414
import { Link } from "@reach/router";
1515

16-
const TeamPositions = ({ teamId, positions }) => {
16+
const TeamPositions = ({ teamId, positions, resources }) => {
1717
return (
1818
<div styleName="team-positions">
1919
<div styleName="team-position-header">
@@ -41,10 +41,11 @@ const TeamPositions = ({ teamId, positions }) => {
4141
<strong>{position.title}</strong>
4242
</Link>
4343
<SkillsList skills={position.skills} limit={5} />
44+
<div>{formatOpenPositions(position, resources)}</div>
4445
</div>
4546
<div styleName="table-group-first-inner">
4647
<div styleName="table-cell cell-date">
47-
{formatDateRange(position.startDate, position.endDate)}
48+
{formatJobDate(position.startDate, position.duration)}
4849
</div>
4950
<div styleName="table-cell cell-money">
5051
{/* Hide rate as we don't have data for it */}
@@ -61,7 +62,7 @@ const TeamPositions = ({ teamId, positions }) => {
6162
<Button
6263
routeTo={`/taas/myteams/${teamId}/positions/${position.id}/candidates`}
6364
>
64-
select candidates
65+
Review candidates
6566
</Button>
6667
)}
6768
</div>
@@ -89,6 +90,16 @@ TeamPositions.propTypes = {
8990
status: PT.oneOf(Object.values(POSITION_STATUS)),
9091
})
9192
),
93+
resources: PT.arrayOf(
94+
PT.shape({
95+
id: PT.string,
96+
handle: PT.string,
97+
firstName: PT.string,
98+
lastName: PT.string,
99+
skills: PT.arrayOf(skillShape),
100+
skillsMatched: PT.number,
101+
})
102+
),
92103
};
93104

94105
export default TeamPositions;

‎src/routes/MyTeamsDetails/index.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ const MyTeamsDetails = ({ teamId }) => {
2828
<PageHeader title={team.name} backTo="/taas/myteams" />
2929
<TeamSummary team={team} />
3030
<TeamMembers team={team} />
31-
<TeamPositions positions={team.jobs || []} teamId={teamId} />
31+
<TeamPositions
32+
positions={team.jobs || []}
33+
teamId={teamId}
34+
resources={team.resources}
35+
/>
3236
</>
3337
)}
3438
</Page>

‎src/routes/MyTeamsList/styles.module.scss

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@import "styles/include";
22

3-
.filter-input {
3+
// adding "input:not([type="checkbox"])" to make sure that we override reset styles
4+
input:not([type="checkbox"]).filter-input {
45
width: 380px;
56
background-color: #ffffff;
67
border: 1px solid #aaaaaa;
@@ -30,7 +31,8 @@
3031
}
3132

3233
@media (max-width: 650px) {
33-
.filter-input {
34+
// adding "input:not([type="checkbox"])" to make sure that we override reset styles
35+
input:not([type="checkbox"]).filter-input {
3436
width: 100%;
3537
}
3638
}

‎src/routes/PositionDetails/components/CandidatesStatusFilter/index.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import PT from "prop-types";
66
import "./styles.module.scss";
77
import _ from "lodash";
88
import Button from "components/Button";
9+
import Babge from "components/Babge";
910
import {
1011
CANDIDATE_STATUS,
1112
CANDIDATE_STATUS_FILTERS,
@@ -15,14 +16,17 @@ import {
1516
const CandidatesStatusFilter = ({ currentStatus, onChange, candidates }) => {
1617
return (
1718
<div styleName="candidates-status-filter">
18-
{CANDIDATE_STATUS_FILTERS.map((status) => (
19+
{CANDIDATE_STATUS_FILTERS.map((status, index) => (
1920
<Button
2021
key={status}
2122
type={currentStatus === status ? "segment-selected" : "segment"}
2223
onClick={() => onChange(status)}
2324
>
2425
{CANDIDATE_STATUS_TO_TEXT[status]} (
2526
{_.filter(candidates, { status }).length})
27+
{index === 0 && _.filter(candidates, { status }).length ? (
28+
<Babge type="danger">Pending</Babge>
29+
) : null}
2630
</Button>
2731
))}
2832
</div>

‎src/routes/PositionDetails/components/CandidatesStatusFilter/styles.module.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@
88
> *:not(:last-child) {
99
margin-right: 10px;
1010
}
11+
button {
12+
span {
13+
margin-left: 5px;
14+
}
15+
}
1116
}

‎src/routes/PositionDetails/components/PositionCandidates/index.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Show a list of position candidates with sort select and pagination.
55
*/
6-
import React, { useMemo, useState, useCallback } from "react";
6+
import React, { useMemo, useState, useCallback, useEffect } from "react";
77
import PT from "prop-types";
88
import _ from "lodash";
99
import CardHeader from "components/CardHeader";
@@ -58,6 +58,11 @@ const populateSkillsMatched = (position, candidate) => ({
5858
const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {
5959
const { candidates } = position;
6060
const [sortBy, setSortBy] = useState(CANDIDATES_SORT_BY.SKILL_MATCHED);
61+
62+
useEffect(() => {
63+
setPage(1);
64+
}, [candidateStatus])
65+
6166
const filteredCandidates = useMemo(
6267
() =>
6368
_.chain(candidates)

‎src/utils/format.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,50 @@ export const formatPageTitle = (pageTitle) => {
201201
return formattedPageTitle;
202202
};
203203

204+
/**
205+
* Format open positions.
206+
*
207+
* @param {Object} job job object
208+
* @param {Array} resources resource list
209+
*
210+
* @returns {string} open positions string
211+
*/
212+
export const formatOpenPositions = (job, resources) => {
213+
const jobResources = _.filter(resources, { jobId: job.id });
214+
if (jobResources.length === 0) {
215+
return `${formatPlural(job.numPositions, "open position")}`;
216+
} else {
217+
return `${jobResources.length} / ${formatPlural(
218+
job.numPositions,
219+
"open position"
220+
)}`;
221+
}
222+
};
223+
224+
/**
225+
* Format job date
226+
*
227+
* @param {string} startDate job startDate
228+
* @param {number} duration job duration
229+
*
230+
* @returns {string} formatted string
231+
*/
232+
export const formatJobDate = (startDate, duration) => {
233+
const dateStr = startDate ? moment(startDate).format(DAY_FORMAT) : "";
234+
235+
if (startDate && duration) {
236+
return `Requested starting ${dateStr} for ${formatPlural(
237+
duration,
238+
"week"
239+
)}`;
240+
} else if (startDate) {
241+
return `Requested starting ${dateStr}`;
242+
} else if (duration) {
243+
return formatPlural(duration, "week");
244+
}
245+
return "TBD";
246+
};
247+
204248
/**
205249
* Format localTime
206250
*

0 commit comments

Comments
 (0)
This repository has been archived.