Skip to content

Commit 8ed9e48

Browse files
committed
New component for talent-picker
1 parent 1334039 commit 8ed9e48

File tree

7 files changed

+1176
-341
lines changed

7 files changed

+1176
-341
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ workflows:
128128
- build-dev
129129
filters:
130130
branches:
131-
only: ['dev']
131+
only: ['dev', 'feature/talent_picker_v2']
132132

133133
- deployTest01:
134134
context : org-global

package-lock.json

Lines changed: 560 additions & 340 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/projects/detail/components/SpecQuestionList/SpecQuestionList.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@
172172
border-color: $tc-gray-20;
173173
max-width: 300px;
174174
margin-left: 0px;
175+
176+
&.error {
177+
border: 1px solid #ff5b52 !important;
178+
}
175179

176180
&:after {
177181
border-bottom-color: $tc-gray-70;
@@ -190,6 +194,10 @@
190194
line-height: 24px;
191195
}
192196

197+
textarea.job-textarea {
198+
min-height: 100px;
199+
}
200+
193201
.radio-group-input,
194202
.checkbox-group-item {
195203
width: 100%;

src/projects/detail/components/SpecQuestions.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import SpecQuestionList from './SpecQuestionList/SpecQuestionList'
1111
import SpecQuestionIcons from './SpecQuestionList/SpecQuestionIcons'
1212
import SkillsQuestion from './SkillsQuestion/SkillsQuestion'
1313
import TalentPickerQuestion from './TalentPickerQuestion/TalentPickerQuestion'
14+
import TalentPickerQuestionV2 from './TalentPickerQuestion/TalentPickerQuestionV2'
1415
import SpecFeatureQuestion from './SpecFeatureQuestion'
1516
import ColorSelector from './../../../components/ColorSelector/ColorSelector'
1617
import SelectDropdown from './../../../components/SelectDropdown/SelectDropdown'
@@ -382,6 +383,12 @@ class SpecQuestions extends React.Component {
382383
options: q.options,
383384
})
384385
break
386+
case 'talent-picker-v2':
387+
ChildElem = TalentPickerQuestionV2
388+
_.assign(elemProps, {
389+
options: q.options,
390+
})
391+
break
385392
default:
386393
ChildElem = () => (
387394
<div style={{ borderWidth: 1, borderStyle: 'dashed', borderColor: '#f00' }}>
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import React, { Component, PropTypes } from 'react'
2+
import _ from 'lodash'
3+
import { HOC as hoc } from 'formsy-react'
4+
import cn from 'classnames'
5+
6+
import TalentPickerRowV2 from '../TalentPickerRow/TalentPickerRowV2'
7+
import './TalentPickerQuestion.scss'
8+
9+
class TalentPickerQuestionV2 extends Component {
10+
11+
constructor(props) {
12+
super(props)
13+
14+
this.state = {
15+
options: []
16+
}
17+
18+
this.getDefaultValue = this.getDefaultValue.bind(this)
19+
this.handleValueChange = this.handleValueChange.bind(this)
20+
21+
this.insertRole = this.insertRole.bind(this)
22+
this.removeRole = this.removeRole.bind(this)
23+
this.canDeleteRole = this.canDeleteRole.bind(this)
24+
this.setValidator(props)
25+
}
26+
27+
componentWillReceiveProps(nextProps) {
28+
this.setValidator(nextProps)
29+
30+
31+
if (!_.isEqual(this.props.options, nextProps.options)) {
32+
this.updateOptions(nextProps)
33+
}
34+
}
35+
36+
componentDidMount() {
37+
this.updateOptions(this.props)
38+
}
39+
40+
setValidator(props) {
41+
const { setValidations, required } = props
42+
const validations = {
43+
oneRowHaveValidValue: (formValues, value) => {
44+
if (!required) {
45+
return true
46+
}
47+
return _.some(value, (v) => {
48+
return v.people !== '0' && v.duration !== '0' && v.skills.length > 0 && v.workLoad.value !== null && v.jobDescription.length
49+
}) // validation body
50+
},
51+
noPartialFillsExist: (formValues, value) => {
52+
return _.every(value, v => {
53+
54+
const isOneValueFilled = v.people > 0 || v.duration > 0 || (v.skills && v.skills.length) || (v.jobDescription && v.jobDescription.length) || (v.workLoad && v.workLoad.value !== null)
55+
const isAllValuesFilled = v.people > 0 && v.duration > 0 && v.skills && v.skills.length && v.jobDescription.length && v.workLoad.value !== null
56+
// If one value is filled, all values should be filled to make this row valid. Partial fill is not valid
57+
const isRowValid = !isOneValueFilled || isAllValuesFilled
58+
return isRowValid
59+
})
60+
}
61+
}
62+
setValidations(validations)
63+
}
64+
65+
updateOptions(props) {
66+
const options = props.options.map(o => ({...o, skillsCategories: o.skillsCategory ? [ o.skillsCategory ] : null}))
67+
this.setState({ options })
68+
}
69+
70+
getDefaultValue() {
71+
const { options } = this.props
72+
return options.map((o) => ({
73+
role: o.role,
74+
people: '0',
75+
duration: '0',
76+
skills: [],
77+
additionalSkills: [],
78+
workLoad: { value: null, title: 'Select Workload'},
79+
jobDescription: ''
80+
}))
81+
}
82+
83+
onChange(value) {
84+
const {setValue, name} = this.props
85+
86+
setValue(value)
87+
this.props.onChange(name, value)
88+
}
89+
90+
handleValueChange(index, field, value) {
91+
const { getValue } = this.props
92+
let values = getValue() || this.getDefaultValue()
93+
values = [...values.slice(0, index), { ...values[index], [field]: value }, ...values.slice(index + 1)]
94+
95+
this.onChange(values)
96+
}
97+
98+
insertRole(index, role) {
99+
const { getValue } = this.props
100+
let values = getValue() || this.getDefaultValue()
101+
102+
values = [
103+
...values.slice(0, index),
104+
{
105+
role,
106+
people: '0',
107+
duration: '0',
108+
skills: [],
109+
additionalSkills: [],
110+
workLoad: { value: null, title: 'Select Workload'},
111+
jobDescription: '',
112+
},
113+
...values.slice(index)
114+
]
115+
this.onChange(values)
116+
}
117+
118+
removeRole(index) {
119+
const { getValue } = this.props
120+
let values = getValue() || this.getDefaultValue()
121+
values = [...values.slice(0, index), ...values.slice(index + 1)]
122+
this.onChange(values)
123+
}
124+
125+
canDeleteRole(role, index) {
126+
const { getValue } = this.props
127+
const values = getValue() || this.getDefaultValue()
128+
return _.findIndex(values, { role }) !== index
129+
}
130+
131+
render() {
132+
const { wrapperClass, getValue } = this.props
133+
const { options } = this.state
134+
135+
const errorMessage =
136+
this.props.getErrorMessage() || this.props.validationError
137+
const hasError = !this.props.isPristine() && !this.props.isValid()
138+
139+
const values = getValue() || this.getDefaultValue()
140+
141+
return (
142+
<div className={cn(wrapperClass)}>
143+
<div styleName="container">
144+
{options.length > 0 ? values.map((v, roleIndex) => {
145+
const roleSetting = _.find(options, { role: v.role })
146+
return (
147+
<TalentPickerRowV2
148+
key={roleIndex}
149+
rowIndex={roleIndex}
150+
value={v}
151+
canBeDeleted={this.canDeleteRole}
152+
roleSetting={roleSetting}
153+
onChange={this.handleValueChange}
154+
onDeleteRow={this.removeRole}
155+
onAddRow={this.insertRole}
156+
/>
157+
)
158+
}) : null}
159+
</div>
160+
{hasError ? <p className="error-message">{errorMessage}</p> : null}
161+
</div>
162+
)
163+
}
164+
}
165+
166+
TalentPickerQuestionV2.PropTypes = {
167+
options: PropTypes.arrayOf(
168+
PropTypes.shape({
169+
role: PropTypes.string.isRequired,
170+
skillsCategory: PropTypes.string.isRequired,
171+
roleTitle: PropTypes.string.isRequired,
172+
disabled: PropTypes.bool,
173+
})
174+
).isRequired,
175+
onChange: PropTypes.func,
176+
}
177+
178+
TalentPickerQuestionV2.defaultProps = {
179+
onChange: _.noop
180+
}
181+
182+
export default hoc(TalentPickerQuestionV2)

0 commit comments

Comments
 (0)