Skip to content

Commit 079cd93

Browse files
authored
Merge pull request #4189 from appirio-tech/feature/accept-reject-terms-in-profile
[DEV] Feature/accept reject terms in profile
2 parents ca74afe + 1412853 commit 079cd93

File tree

11 files changed

+404
-8677
lines changed

11 files changed

+404
-8677
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ workflows:
138138
- build-dev
139139
filters:
140140
branches:
141-
only: ['feature/unified-permissions']
141+
only: ['feature/unified-permissions', 'feature/accept-reject-terms-in-profile']
142142

143143
- deployProd:
144144
context : org-global

package-lock.json

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

src/components/BtnGroup/BtnGroup.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class BtnGroup extends React.Component {
4545

4646
BtnGroup.propTypes = {
4747
items: PropTypes.arrayOf(PropTypes.shape({
48-
value: PropTypes.string.isRequired,
48+
value: PropTypes.oneOfType(PropTypes.string, PropTypes.number, PropTypes.bool).isRequired,
4949
text: PropTypes.string.isRequired
5050
})).isRequired,
5151
onChange: PropTypes.func

src/components/BtnGroup/BtnGroup.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
> .tc-btn.active,
2222
> .tc-btn.active:hover,
23-
> .tc-btn.active:active {
23+
> .tc-btn.active:active,
24+
> .tc-btn.active:focus {
2425
background: $tc-gray-20;
2526
box-shadow: inset 0 1px 3px 0 rgba($tc-gray-80, 0.38);
2627
cursor: default;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, { Component } from 'react'
2+
import PropTypes from 'prop-types'
3+
import { HOC as hoc } from 'formsy-react'
4+
import BtnGroup from './BtnGroup'
5+
6+
/**
7+
* This component is a formsy wrapper for the BtnGroup component
8+
* @param {Object} props Component props
9+
*/
10+
class FormsyBtnGroup extends Component {
11+
constructor(props) {
12+
super(props)
13+
this.changeValue = this.changeValue.bind(this)
14+
}
15+
16+
changeValue(value) {
17+
this.props.setValue(value)
18+
this.props.onChange && this.props.onChange(this.props.name, value)
19+
}
20+
21+
render() {
22+
const { items } = this.props
23+
const hasError = !this.props.isPristine() && !this.props.isValid()
24+
const errorMessage = this.props.getErrorMessage() || this.props.validationError
25+
26+
return (
27+
<div>
28+
<BtnGroup items={items} value={this.props.getValue()} onChange={this.changeValue} />
29+
{(hasError && errorMessage) ? (<p className="error-message">{errorMessage}</p>) : null}
30+
</div>
31+
)
32+
}
33+
}
34+
35+
FormsyBtnGroup.PropTypes = {
36+
items: PropTypes.arrayOf(PropTypes.shape({
37+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]).isRequired,
38+
text: PropTypes.string.isRequired
39+
})).isRequired
40+
}
41+
42+
export default hoc(FormsyBtnGroup)

src/components/IncompleteUserProfile/IncompleteUserProfile.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const IncompleteUserProfile = ({
2020
delete fieldsConfig.avatar
2121
// config the form to only show required fields which doesn't have the value yet
2222
const missingFieldsConfig = _.reduce(fieldsConfig, (acc, isFieldRequired, fieldKey) => {
23-
if (isFieldRequired && !_.get(profileSettings, `settings.${fieldKey}`)) {
23+
if (isFieldRequired && _.isNil(_.get(profileSettings, `settings.${fieldKey}`))) {
2424
acc[fieldKey] = isFieldRequired
2525
}
2626
return acc

src/config/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ export const TC_CDN_URL = process.env.TC_CDN_URL || `https://community-app.${DOM
739739

740740
export const RESET_PASSWORD_URL = `https://accounts.${DOMAIN}/member/reset-password`
741741
export const VERIFY_EMAIL_URL = `http://www.${DOMAIN}/settings/account/changeEmail`
742+
export const TOPCODER_CONNECT_TERMS_URL = `https://connect.${DOMAIN}/terms`
742743

743744
export const PROJECT_NAME_MAX_LENGTH = 255
744745
export const PROJECT_REF_CODE_MAX_LENGTH = 32
@@ -1048,6 +1049,7 @@ export const PROFILE_FIELDS_CONFIG = {
10481049
timeZone: true,
10491050
workingHourStart: true,
10501051
workingHourEnd: true,
1052+
// termsAccepted: true,
10511053

10521054
// optional fields
10531055
avatar: false,
@@ -1065,6 +1067,7 @@ export const PROFILE_FIELDS_CONFIG = {
10651067
companyURL: true,
10661068
businessPhone: true,
10671069
businessEmail: true,
1070+
termsAccepted: true,
10681071

10691072
// optional fields
10701073
avatar: false,
@@ -1080,6 +1083,7 @@ export const PROFILE_FIELDS_CONFIG = {
10801083
timeZone: true,
10811084
workingHourStart: true,
10821085
workingHourEnd: true,
1086+
// termsAccepted: true,
10831087

10841088
// optional fields
10851089
avatar: false,

src/helpers/tcHelpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export const isUserProfileComplete = (user, profileSettings) => {
6565
_.forEach(_.keys(fieldsConfig), (fieldKey) => {
6666
const isFieldRequired = fieldsConfig[fieldKey]
6767

68-
if (isFieldRequired && !profileSettings[fieldKey]) {
68+
if (isFieldRequired && _.isNil(profileSettings[fieldKey])) {
6969
isMissingUserInfo = true
7070
return false
7171
}

src/routes/settings/routes/profile/components/ProfileSettingsForm.jsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ const TCFormFields = FormsyForm.Fields
1111
const Formsy = FormsyForm.Formsy
1212
import ProfileSettingsAvatar from './ProfileSettingsAvatar'
1313
import FormsySelect from '../../../../../components/Select/FormsySelect'
14+
import FormsyBtnGroup from '../../../../../components/BtnGroup/FormsyBtnGroup'
1415
import ISOCountries from '../../../../../helpers/ISOCountries'
1516
import { formatPhone } from '../../../../../helpers/utils'
1617
import { hasPermission } from '../../../../../helpers/permissions'
1718
import { PERMISSIONS } from '../../../../../config/permissions'
19+
import { TOPCODER_CONNECT_TERMS_URL } from '../../../../../config/constants'
1820
import './ProfileSettingsForm.scss'
1921

2022
const countries = _.orderBy(ISOCountries, ['name'], ['asc']).map((country) => ({
@@ -382,8 +384,36 @@ class ProfileSettingsForm extends Component {
382384
</div>
383385
</div>
384386
)}
387+
{!_.isUndefined(fieldsConfig.termsAccepted) && (
388+
<div className="field">
389+
<div className="label">
390+
<a styleName="fieldLabelText" href={TOPCODER_CONNECT_TERMS_URL} target="_blank">Topcoder Terms</a>&nbsp;
391+
{fieldsConfig.termsAccepted && <sup styleName="requiredMarker">*</sup>}
392+
</div>
393+
<div className="input-field">
394+
<div styleName="terms-field">
395+
{_.isNil(this.props.values.settings.termsAccepted) ? (
396+
<FormsyBtnGroup
397+
name="termsAccepted"
398+
items={[
399+
{ value: true, text: 'Accept' },
400+
{ value: false, text: 'Reject' }
401+
]}
402+
validations={{
403+
isRequired: fieldsConfig.timeZone
404+
}}
405+
validationErrors={{
406+
isRequired: 'Please accept or decline Topcoder Terms'
407+
}}
408+
/>
409+
) : (
410+
<span>{this.props.values.settings.termsAccepted ? 'Accepted' : 'Rejected'}</span>
411+
)}
412+
</div>
413+
</div>
414+
</div>
415+
)}
385416
<div className="controls">
386-
387417
{showBackButton && (
388418
<button
389419
className={`tc-btn tc-btn-default btn-back ${buttonExtraClassName}`}

src/routes/settings/routes/profile/components/ProfileSettingsForm.scss

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,25 @@
191191
vertical-align: top;
192192
}
193193

194+
a.fieldLabelText {
195+
color: $tc-dark-blue-110;
196+
}
197+
198+
.terms-field {
199+
align-items: center;
200+
display: flex;
201+
padding: 7px 0;
202+
203+
> span {
204+
display: inline-block;
205+
color: $tc-gray-60;
206+
font-size: 13px;
207+
font-weight: bold;
208+
line-height: 20px;
209+
padding: 5px 0;
210+
}
211+
}
212+
194213
.warningText {
195214
margin: 5px auto;
196215
@include roboto;
@@ -203,4 +222,4 @@
203222
color: $tc-orange-70;
204223
padding:10px;
205224
border-radius: 2px;
206-
}
225+
}

0 commit comments

Comments
 (0)