Skip to content

Commit c89607d

Browse files
committed
Progressive Registration Feedback for loading/role/field problem
Progressive Registration Feedback for loading/role/field problem
1 parent b10c94f commit c89607d

File tree

11 files changed

+199
-27
lines changed

11 files changed

+199
-27
lines changed

src/components/Select/FormsySelect.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const FormsySelect = props => {
1414
const selectedOption = props.getValue()
1515
const getOnlyValues = (selected) => props.isMulti ? (selected || []).map(o => o.value) : selected.value
1616

17+
const hasError = !props.isPristine() && !props.isValid()
18+
const errorMessage = props.getErrorMessage() || props.validationError
1719
const onSelectionChange = selectedOption => {
1820
props.setValue(setValueOnly ? getOnlyValues(selectedOption) : selectedOption)
1921
onChange && onChange(selectedOption)
@@ -22,7 +24,12 @@ const FormsySelect = props => {
2224
? _.find(options, o => o.value === selectedOption)
2325
: selectedOption
2426

25-
return <Select {...props} value={value} onChange={onSelectionChange} />
27+
return (
28+
<div>
29+
<Select {...props} value={value} onChange={onSelectionChange} />
30+
{(hasError && errorMessage) ? (<p className="error-message">{errorMessage}</p>) : null}
31+
</div>
32+
)
2633
}
2734

2835
FormsySelect.PropTypes = {

src/components/Wizard/Wizard.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
position: absolute;
2828
right: 12px;
2929
top: 12px;
30-
z-index: 1;
30+
z-index: 2;
3131
}
3232
}
3333
}

src/config/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const SAVE_NOTIFICATION_SETTINGS_FAILURE = 'SAVE_NOTIFICATION_SETTINGS_FA
5454

5555
export const GET_PROFILE_SETTINGS_PENDING = 'GET_PROFILE_SETTINGS_PENDING'
5656
export const GET_PROFILE_SETTINGS_SUCCESS = 'GET_PROFILE_SETTINGS_SUCCESS'
57+
export const GET_PROFILE_SETTINGS_RESET = 'GET_PROFILE_SETTINGS_RESET'
5758
export const GET_PROFILE_SETTINGS_FAILURE = 'GET_PROFILE_SETTINGS_FAILURE'
5859
export const SAVE_PROFILE_SETTINGS_PENDING = 'SAVE_PROFILE_SETTINGS_PENDING'
5960
export const SAVE_PROFILE_SETTINGS_SUCCESS = 'SAVE_PROFILE_SETTINGS_SUCCESS'

src/projects/create/components/FillProjectDetails.js

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import ProjectBasicDetailsForm from '../components/ProjectBasicDetailsForm'
99
import HeaderWithProgress from './HeaderWithProgress'
1010
import UpdateUserInfo from './UpdateUserInfo'
1111
import { formatProfileSettings } from '../../../routes/settings/helpers/settings'
12+
import LoadingIndicator from '../../../components/LoadingIndicator/LoadingIndicator'
1213
import {
1314
getProfileSettings,
1415
saveProfileSettings,
1516
uploadProfilePhoto,
17+
resetProfileSetting,
1618
} from '../../../routes/settings/actions/index'
1719
import {
18-
ROLE_TOPCODER_USER,
1920
ROLE_CONNECT_COPILOT,
2021
ROLE_CONNECT_MANAGER,
2122
ROLE_CONNECT_ACCOUNT_MANAGER,
@@ -37,7 +38,17 @@ class FillProjectDetails extends Component {
3738
this.handleStepChange = this.handleStepChange.bind(this)
3839
this.openUserSettings = this.openUserSettings.bind(this)
3940
this.closeUserSettings = this.closeUserSettings.bind(this)
40-
this.state = { project: {}, currentWizardStep: null, showUpdateUser: false }
41+
this.onCreateProject = this.onCreateProject.bind(this)
42+
this.onRequireCheckUserSetting = this.onRequireCheckUserSetting.bind(this)
43+
this.state = {
44+
project: {},
45+
currentWizardStep: null,
46+
showUpdateUser: false,
47+
isSavingProject: false,
48+
requireCheckUserSetting: false,
49+
}
50+
props.resetProfileSetting()
51+
4152
}
4253

4354
componentWillMount() {
@@ -65,6 +76,14 @@ class FillProjectDetails extends Component {
6576
_.isEqual(
6677
nextProps.isLoadedProfileSetting,
6778
this.props.isLoadedProfileSetting
79+
) &&
80+
_.isEqual(
81+
nextProps.profileSettings.isLoading,
82+
this.props.profileSettings.isLoading
83+
) &&
84+
_.isEqual(
85+
nextProps.profileSettings.pending,
86+
this.props.profileSettings.pending
6887
)
6988
)
7089
}
@@ -87,6 +106,16 @@ class FillProjectDetails extends Component {
87106
this.setState({ showUpdateUser: false })
88107
}
89108

109+
onRequireCheckUserSetting(isRequire, cb) {
110+
this.setState({ requireCheckUserSetting: isRequire }, cb)
111+
}
112+
113+
onCreateProject(newProject) {
114+
this.setState({ requireCheckUserSetting: false }, () => {
115+
this.props.onCreateProject(newProject)
116+
})
117+
}
118+
90119
render() {
91120
const {
92121
project,
@@ -102,7 +131,7 @@ class FillProjectDetails extends Component {
102131
isMissingUserInfo,
103132
isLoadedProfileSetting,
104133
} = this.props
105-
const { currentWizardStep, showUpdateUser } = this.state
134+
const { currentWizardStep, showUpdateUser, isSavingProject, requireCheckUserSetting } = this.state
106135
const projectTemplateId = _.get(project, 'templateId')
107136
const projectTemplate = _.find(projectTemplates, { id: projectTemplateId })
108137
const formDisclaimer = _.get(projectTemplate, 'scope.formDisclaimer')
@@ -135,6 +164,19 @@ class FillProjectDetails extends Component {
135164
)
136165
}
137166
}
167+
if (
168+
isSavingProject
169+
) {
170+
return (
171+
<div
172+
className={cn('FillProjectDetailsWrapper', {
173+
[`form-theme-${template.theme}`]: template.theme,
174+
})}
175+
>
176+
<LoadingIndicator />
177+
</div>
178+
)
179+
}
138180

139181
return (
140182
<div
@@ -149,7 +191,9 @@ class FillProjectDetails extends Component {
149191
/>
150192
) : (
151193
<div className="FillProjectDetails">
152-
<div className="header">{header}</div>
194+
{!profileSettings.isLoading && !profileSettings.pending && (
195+
<div className="header">{header}</div>
196+
)}
153197
<section className="two-col-content content">
154198
<div className="container">
155199
<div className="left-area">
@@ -161,7 +205,7 @@ class FillProjectDetails extends Component {
161205
dirtyProject={dirtyProject}
162206
template={template}
163207
isEditable
164-
submitHandler={this.props.onCreateProject}
208+
submitHandler={this.onCreateProject}
165209
addAttachment={this.props.addAttachment}
166210
updateAttachment={this.props.updateAttachment}
167211
removeAttachment={this.props.removeAttachment}
@@ -177,6 +221,8 @@ class FillProjectDetails extends Component {
177221
isMissingUserInfo={isMissingUserInfo}
178222
isLoadedProfileSetting={isLoadedProfileSetting}
179223
openUserSettings={this.openUserSettings}
224+
onRequireCheckUserSetting={this.onRequireCheckUserSetting}
225+
requireCheckUserSetting={requireCheckUserSetting}
180226
/>
181227
</div>
182228
{formDisclaimer && (
@@ -188,7 +234,8 @@ class FillProjectDetails extends Component {
188234
</div>
189235
</section>
190236
</div>
191-
)}
237+
)
238+
}
192239
</div>
193240
)
194241
}
@@ -233,7 +280,6 @@ const mapStateToProps = ({ settings, loadUser }) => {
233280
ROLE_CONNECT_MANAGER,
234281
]
235282
const topCoderRoles = [
236-
ROLE_TOPCODER_USER,
237283
ROLE_CONNECT_COPILOT,
238284
ROLE_CONNECT_MANAGER,
239285
ROLE_CONNECT_ACCOUNT_MANAGER,
@@ -247,8 +293,7 @@ const mapStateToProps = ({ settings, loadUser }) => {
247293
ROLE_SOLUTION_ARCHITECT,
248294
ROLE_PROJECT_MANAGER,
249295
]
250-
const isTopcoderUser =
251-
_.intersection(loadUser.user.roles, topCoderRoles).length > 0
296+
const isTopcoderUser = _.intersection(loadUser.user.roles, topCoderRoles).length > 0
252297
let isMissingUserInfo = true
253298
const profileSettings = formatProfileSettings(settings.profile.traits)
254299
if (isTopcoderUser) {
@@ -292,6 +337,7 @@ const mapDispatchToProps = {
292337
getProfileSettings,
293338
saveProfileSettings,
294339
uploadProfilePhoto,
340+
resetProfileSetting,
295341
}
296342

297343
export default connect(mapStateToProps, mapDispatchToProps)(FillProjectDetails)

src/projects/create/components/ProjectBasicDetailsForm.js

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
STEP_VISIBILITY,
1717
geStepState,
1818
} from '../../../helpers/wizardHelper'
19+
import LoadingIndicator from '../../../components/LoadingIndicator/LoadingIndicator'
1920
import {
2021
LS_INCOMPLETE_WIZARD,
2122
LS_INCOMPLETE_PROJECT,
@@ -77,14 +78,16 @@ class ProjectBasicDetailsForm extends Component {
7778
&& _.isEqual(nextProps.dirtyProject, this.props.dirtyProject)
7879
&& _.isEqual(nextProps.isMissingUserInfo, this.props.isMissingUserInfo)
7980
&& _.isEqual(nextProps.isLoadedProfileSetting, this.props.isLoadedProfileSetting)
81+
&& _.isEqual(nextProps.profileSettings.isLoading, this.props.profileSettings.isLoading)
82+
&& _.isEqual(nextProps.profileSettings.pending, this.props.profileSettings.pending)
83+
&& _.isEqual(nextProps.requireCheckUserSetting, this.props.requireCheckUserSetting)
8084
&& _.isEqual(nextState.project, this.state.project)
8185
&& _.isEqual(nextState.canSubmit, this.state.canSubmit)
8286
&& _.isEqual(nextState.template, this.state.template)
8387
&& _.isEqual(nextState.currentWizardStep, this.state.currentWizardStep)
8488
&& _.isEqual(nextState.isSaving, this.state.isSaving)
8589
&& _.isEqual(nextState.nextWizardStep, this.state.nextWizardStep)
8690
&& _.isEqual(nextState.prevWizardStep, this.state.prevWizardStep)
87-
&& _.isEqual(nextState.checkUserSetting, this.state.checkUserSetting)
8891
)
8992
}
9093

@@ -140,18 +143,17 @@ class ProjectBasicDetailsForm extends Component {
140143
}
141144
})
142145
})
143-
const { checkUserSetting } = this.state
146+
const { isSaving } = this.state
144147
const {
145148
isMissingUserInfo,
146149
isLoadedProfileSetting,
147150
openUserSettings,
151+
requireCheckUserSetting
148152
} = this.props
149-
if (isLoadedProfileSetting && checkUserSetting && isMissingUserInfo) {
150-
this.setState({checkUserSetting: false }, () => {
151-
openUserSettings()
152-
})
153+
if (isLoadedProfileSetting && requireCheckUserSetting && isMissingUserInfo) {
154+
openUserSettings()
153155
}
154-
if (isLoadedProfileSetting && checkUserSetting && !isMissingUserInfo) {
156+
if (!isSaving && isLoadedProfileSetting && requireCheckUserSetting && !isMissingUserInfo) {
155157
this.submit()
156158
}
157159
}
@@ -165,7 +167,8 @@ class ProjectBasicDetailsForm extends Component {
165167
}
166168

167169
fetchUserSettings() {
168-
this.setState({checkUserSetting: true }, () => {
170+
const { onRequireCheckUserSetting } = this.props
171+
onRequireCheckUserSetting(true, () => {
169172
this.props.getProfileSettings()
170173
})
171174
}
@@ -174,9 +177,10 @@ class ProjectBasicDetailsForm extends Component {
174177
// we cannot use `model` provided by Formzy because in the `previousStepVisibility==none` mode
175178
// some parts of the form are hidden, so Formzy thinks we don't have them
176179
// instead we use this.props.dirtyProject which contains the current project data
177-
this.setState({isSaving: true })
178-
const modelWithoutHiddenValues = removeValuesOfHiddenNodes(this.state.template, this.props.dirtyProject)
179-
this.props.submitHandler(modelWithoutHiddenValues)
180+
this.setState({isSaving: true }, () => {
181+
const modelWithoutHiddenValues = removeValuesOfHiddenNodes(this.state.template, this.props.dirtyProject)
182+
this.props.submitHandler(modelWithoutHiddenValues)
183+
})
180184
}
181185

182186
/**
@@ -239,7 +243,6 @@ class ProjectBasicDetailsForm extends Component {
239243
prevWizardStep,
240244
isWizardMode,
241245
currentWizardStep,
242-
checkUserSetting,
243246
} = this.state
244247

245248
const currentSection = currentWizardStep && template.sections[currentWizardStep.sectionIndex]
@@ -288,6 +291,14 @@ class ProjectBasicDetailsForm extends Component {
288291
)
289292
}
290293

294+
if (
295+
this.state.isSaving ||
296+
profileSettings.isLoading ||
297+
profileSettings.pending
298+
) {
299+
return <LoadingIndicator />
300+
}
301+
291302
return (
292303
<div>
293304
<Formsy.Form
@@ -330,7 +341,7 @@ class ProjectBasicDetailsForm extends Component {
330341
className="tc-btn tc-btn-primary tc-btn-md"
331342
type="submit"
332343
disabled={
333-
(checkUserSetting && profileSettings.isLoading) ||
344+
profileSettings.isLoading ||
334345
(this.state.isSaving) ||
335346
!canSubmit
336347
}
@@ -349,7 +360,9 @@ class ProjectBasicDetailsForm extends Component {
349360

350361
ProjectBasicDetailsForm.defaultProps = {
351362
shouldUpdateTemplate: false,
352-
openUserSettings: () => {}
363+
requireCheckUserSetting: false,
364+
openUserSettings: () => {},
365+
onRequireCheckUserSetting: () => {},
353366
}
354367

355368
ProjectBasicDetailsForm.propTypes = {
@@ -366,6 +379,8 @@ ProjectBasicDetailsForm.propTypes = {
366379
isMissingUserInfo: PropTypes.bool.isRequired,
367380
isLoadedProfileSetting: PropTypes.bool.isRequired,
368381
openUserSettings: PropTypes.func,
382+
onRequireCheckUserSetting: PropTypes.func,
383+
requireCheckUserSetting: PropTypes.bool,
369384
}
370385

371386
export default ProjectBasicDetailsForm

src/projects/create/components/UpdateUserInfo.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ModalControl from '../../../components/ModalControl'
44
import TailLeft from '../../../assets/icons/arrows-16px-1_tail-left.svg'
55

66
import ProfileSettingsForm from '../../../routes/settings/routes/profile/components/ProfileSettingsForm'
7+
import LoadingIndicator from '../../../components/LoadingIndicator/LoadingIndicator'
78

89
import './UpdateUserInfo.scss'
910

@@ -32,6 +33,15 @@ class UpdateUserInfo extends Component {
3233
closeUserSettings,
3334
} = this.props
3435

36+
if (
37+
profileSettings.isLoading ||
38+
profileSettings.pending
39+
) {
40+
return (
41+
<LoadingIndicator />
42+
)
43+
}
44+
3545
return (
3646
<div styleName="container">
3747
<ModalControl
@@ -42,6 +52,9 @@ class UpdateUserInfo extends Component {
4252
/>
4353

4454
<div styleName="user-container">
55+
<span styleName="title-1">Profile Information</span>
56+
<span styleName="title-2">You have incomplete required profile information.</span>
57+
<span styleName="title-3">Please complete your profile information below to able to submit your project request.</span>
4558
<ProfileSettingsForm
4659
values={profileSettings}
4760
saveSettings={saveProfileSettings}
@@ -57,6 +70,12 @@ class UpdateUserInfo extends Component {
5770
isRequiredTimeZone={isTopcoderUser}
5871
isRequiredCountry={isTopcoderUser}
5972
isRequiredWorkingHours={isTopcoderUser}
73+
isRequiredBusinessEmail={!isTopcoderUser}
74+
submitButton="Send my Request"
75+
showBackButton
76+
onBack={closeUserSettings}
77+
shouldDoValidateOnStart
78+
shouldShowTitle={false}
6079
/>
6180
</div>
6281
</div>

0 commit comments

Comments
 (0)