From fa5bb09512ad78e98766135d22cb70f27e424933 Mon Sep 17 00:00:00 2001 From: Huan Li Date: Wed, 15 Aug 2018 06:53:38 +0800 Subject: [PATCH] Profile Settings - Organizations, Hobbies and User Consent --- src/assets/images/profile/ico-hobby.svg | 7 + .../images/profile/ico-organization.svg | 8 + .../Profile/BasicInfo/Track/index.jsx | 2 +- .../Profile/BasicInfo/Track/styles.scss | 22 ++ .../Settings/Profile/BasicInfo/index.jsx | 51 ++- .../Settings/Profile/BasicInfo/styles.scss | 41 ++ .../Settings/Profile/Community/index.jsx | 74 +++- .../Settings/Profile/Education/index.jsx | 55 ++- .../Settings/Profile/Education/styles.scss | 21 + .../Profile/Hobby/List/Item/index.jsx | 59 +++ .../Profile/Hobby/List/Item/styles.scss | 86 ++++ .../Settings/Profile/Hobby/List/index.jsx | 34 ++ .../Settings/Profile/Hobby/List/styles.scss | 29 ++ .../Settings/Profile/Hobby/index.jsx | 290 ++++++++++++++ .../Settings/Profile/Hobby/styles.scss | 175 +++++++++ .../Profile/Language/List/Item/styles.scss | 1 + .../Profile/Language/List/styles.scss | 2 + .../Settings/Profile/Language/index.jsx | 72 +++- .../Settings/Profile/Language/styles.scss | 21 + .../Profile/Organization/List/Item/index.jsx | 67 ++++ .../Organization/List/Item/styles.scss | 102 +++++ .../Profile/Organization/List/index.jsx | 34 ++ .../Profile/Organization/List/styles.scss | 29 ++ .../Settings/Profile/Organization/index.jsx | 369 ++++++++++++++++++ .../Settings/Profile/Organization/styles.scss | 223 +++++++++++ .../Settings/Profile/Skills/index.jsx | 64 ++- .../Settings/Profile/Skills/styles.scss | 46 +++ .../Settings/Profile/Work/index.jsx | 59 ++- .../components/Settings/Profile/index.jsx | 6 + .../Settings/Tools/Devices/index.jsx | 58 ++- .../Settings/Tools/Devices/styles.scss | 21 + .../Settings/Tools/ServiceProviders/index.jsx | 59 ++- .../Settings/Tools/Software/index.jsx | 58 ++- .../Settings/Tools/Software/styles.scss | 21 + .../Settings/Tools/Subscriptions/index.jsx | 59 ++- .../Settings/Tools/Subscriptions/styles.scss | 26 +- .../Settings/UserConsentModal/index.jsx | 44 +++ .../Settings/UserConsentModal/styles.scss | 113 ++++++ src/shared/reducers/page/ui/settings.js | 6 +- 39 files changed, 2415 insertions(+), 99 deletions(-) create mode 100644 src/assets/images/profile/ico-hobby.svg create mode 100644 src/assets/images/profile/ico-organization.svg create mode 100644 src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx create mode 100644 src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss create mode 100644 src/shared/components/Settings/Profile/Hobby/List/index.jsx create mode 100644 src/shared/components/Settings/Profile/Hobby/List/styles.scss create mode 100644 src/shared/components/Settings/Profile/Hobby/index.jsx create mode 100644 src/shared/components/Settings/Profile/Hobby/styles.scss create mode 100644 src/shared/components/Settings/Profile/Organization/List/Item/index.jsx create mode 100644 src/shared/components/Settings/Profile/Organization/List/Item/styles.scss create mode 100644 src/shared/components/Settings/Profile/Organization/List/index.jsx create mode 100644 src/shared/components/Settings/Profile/Organization/List/styles.scss create mode 100644 src/shared/components/Settings/Profile/Organization/index.jsx create mode 100644 src/shared/components/Settings/Profile/Organization/styles.scss create mode 100644 src/shared/components/Settings/UserConsentModal/index.jsx create mode 100644 src/shared/components/Settings/UserConsentModal/styles.scss diff --git a/src/assets/images/profile/ico-hobby.svg b/src/assets/images/profile/ico-hobby.svg new file mode 100644 index 0000000000..d5a6f56238 --- /dev/null +++ b/src/assets/images/profile/ico-hobby.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/images/profile/ico-organization.svg b/src/assets/images/profile/ico-organization.svg new file mode 100644 index 0000000000..9da9b41c64 --- /dev/null +++ b/src/assets/images/profile/ico-organization.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/shared/components/Settings/Profile/BasicInfo/Track/index.jsx b/src/shared/components/Settings/Profile/BasicInfo/Track/index.jsx index 27cfe1c70e..8d1f726736 100644 --- a/src/shared/components/Settings/Profile/BasicInfo/Track/index.jsx +++ b/src/shared/components/Settings/Profile/BasicInfo/Track/index.jsx @@ -37,7 +37,7 @@ export default function Track({ -
+
0) { @@ -117,6 +134,18 @@ export default class BasicInfo extends React.Component { data.push(newBasicInfo); addUserTrait(handle, 'basic_info', data, tokenV3); } + + // save personalization + if (_.isEmpty(personalizationTrait)) { + const personalizationData = { userConsent: answer }; + addUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } else { + const trait = personalizationTrait.traits.data[0]; + if (trait.userConsent !== answer) { + const personalizationData = { userConsent: answer }; + updateUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } + } } onUpdateSelect(option) { @@ -182,6 +211,16 @@ export default class BasicInfo extends React.Component { return _.assign({}, basicInfo); } + /** + * Get personalization trait + * @param userTraits the all user traits + */ + loadPersonalizationTrait = (userTraits) => { + const trait = userTraits.filter(t => t.traitId === 'personalization'); + const personalization = trait.length === 0 ? {} : trait[0]; + return _.assign({}, personalization); + } + /** * Process basic info state */ @@ -322,10 +361,14 @@ export default class BasicInfo extends React.Component { const { savingBasicInfo, newBasicInfo, + showUserConsent, } = this.state; return (
+ { + showUserConsent && () + }
{ diff --git a/src/shared/components/Settings/Profile/BasicInfo/styles.scss b/src/shared/components/Settings/Profile/BasicInfo/styles.scss index 0802b3c9e4..1c803be6db 100644 --- a/src/shared/components/Settings/Profile/BasicInfo/styles.scss +++ b/src/shared/components/Settings/Profile/BasicInfo/styles.scss @@ -252,3 +252,44 @@ margin: 0; } } + +/* + * React Select component styling + */ +.basic-info-container .form-container .row .field :global .Select, +.basic-info-container .form-container .row .field :global .Select-value span, +.basic-info-container .form-container .row .field :global .Select-menu-outer, +.basic-info-container.form-container .row .field :global .Select-placeholder, +.basic-info-container .form-container .row .field :global .Select-input input { + color: $tc-gray-80; + font-size: 15px; + + @include xs-to-sm { + margin-top: 5px; + } +} + +.basic-info-container div[class="Select-control"] { + height: 40px; + + div[class="Select-input"] { + height: 38px; + } + + div[class="Select-placeholder"] { + height: 38px; + line-height: 40px !important; + + @include xs-to-sm { + line-height: 27px !important; + } + } + + div[class="Select-value"] { + line-height: 40px !important; + } +} + +.basic-info-container .form-container .row .field :global .Select-placeholder { + color: $tc-gray-50; +} diff --git a/src/shared/components/Settings/Profile/Community/index.jsx b/src/shared/components/Settings/Profile/Community/index.jsx index c60f90a58b..f8537a9719 100644 --- a/src/shared/components/Settings/Profile/Community/index.jsx +++ b/src/shared/components/Settings/Profile/Community/index.jsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; - +import UserConsentModal from 'components/Settings/UserConsentModal'; import Item from './Item'; import data from './data'; @@ -18,12 +18,18 @@ const SAVE_DELAY = 1000; class Community extends React.Component { constructor(props) { super(props); + this.onShowUserConsent = this.onShowUserConsent.bind(this); this.state = { communityTrait: this.loadCommunityTrait(props.userTraits), + showUserConsent: false, + personalizationTrait: this.loadPersonalizationTrait(props.userTraits), + newCommunity: null, + communityChecked: false, isAdd: false, }; this.loadCommunityTrait = this.loadCommunityTrait.bind(this); + this.loadPersonalizationTrait = this.loadPersonalizationTrait.bind(this); this.onChange = this.onChange.bind(this); } @@ -40,22 +46,40 @@ class Community extends React.Component { const trait = userTraits.filter(t => t.traitId === 'communities'); this.setState({ isAdd: trait.length === 0 ? true : false, + newCommunity: null, + communityChecked: false, }); const communityTrait = this.loadCommunityTrait(nextProps.userTraits); - this.setState({ communityTrait }); + const personalizationTrait = this.loadPersonalizationTrait(nextProps.userTraits); + this.setState({ communityTrait, personalizationTrait }); + } + + /** + * Show User Consent Modal + * @param e event + * @param item the community object + * @param checked the check value + */ + onShowUserConsent(e, item, checked) { + e.preventDefault(); + this.setState({ + showUserConsent: true, + newCommunity: item, + communityChecked: checked, + }); } /** * Add or Update CommunityTrait */ - onProcessCommunities = _.debounce(() => { + onProcessCommunities = _.debounce((answer) => { const { handle, tokenV3, updateUserTrait, addUserTrait, } = this.props; - const { isAdd, communityTrait } = this.state; + const { isAdd, communityTrait, personalizationTrait } = this.state; if (isAdd) { const newCommunities = []; newCommunities.push(communityTrait); @@ -65,22 +89,43 @@ class Community extends React.Component { newCommunities.push(communityTrait); updateUserTrait(handle, 'communities', newCommunities, tokenV3); } + // save personalization + if (_.isEmpty(personalizationTrait)) { + const personalizationData = { userConsent: answer }; + addUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } else { + const trait = personalizationTrait.traits.data[0]; + if (trait.userConsent !== answer) { + const personalizationData = { userConsent: answer }; + updateUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } + } }, SAVE_DELAY); /** * Change toggle button check value - * @param item community object - * @param checked check value + * @param e form submit event + * @param answer user consent answer value */ - onChange(item, checked) { - const { communityTrait } = this.state; - communityTrait[item.id] = checked; + onChange(e, answer) { + this.setState({ showUserConsent: false }); + const { communityTrait, newCommunity, communityChecked } = this.state; + communityTrait[newCommunity.id] = communityChecked; this.setState({ communityTrait, - }, () => this.onProcessCommunities(item.programID)); + }, () => this.onProcessCommunities(answer)); } + /** + * Get personalization trait + * @param userTraits the all user traits + */ + loadPersonalizationTrait = (userTraits) => { + const trait = userTraits.filter(t => t.traitId === 'personalization'); + const personalization = trait.length === 0 ? {} : trait[0]; + return _.assign({}, personalization); + } /** * Get community trait @@ -99,7 +144,7 @@ class Community extends React.Component { render() { const { settingsUI } = this.props; - const { communityTrait } = this.state; + const { communityTrait, showUserConsent } = this.state; const tabs = settingsUI.TABS.PROFILE; const currentTab = settingsUI.currentProfileTab; const containerStyle = currentTab === tabs.COMMUNITY ? '' : 'hide'; @@ -107,6 +152,11 @@ class Community extends React.Component { return (
+ { + showUserConsent && ( + + ) + }

Community @@ -125,7 +175,7 @@ class Community extends React.Component { title={item.name} programID={item.programID} description={item.description} - onToggle={event => this.onChange(item, event.target.checked)} + onToggle={event => this.onShowUserConsent(event, item, event.target.checked)} /> ); }) diff --git a/src/shared/components/Settings/Profile/Education/index.jsx b/src/shared/components/Settings/Profile/Education/index.jsx index 5a6b131eaa..3d061051a4 100644 --- a/src/shared/components/Settings/Profile/Education/index.jsx +++ b/src/shared/components/Settings/Profile/Education/index.jsx @@ -8,7 +8,7 @@ import React from 'react'; import PT from 'prop-types'; import _ from 'lodash'; - +import UserConsentModal from 'components/Settings/UserConsentModal'; import Select from 'components/Select'; import { PrimaryButton } from 'topcoder-react-ui-kit'; import dropdowns from './dropdowns.json'; @@ -25,11 +25,15 @@ export default class Education extends React.Component { this.loadEducationTrait = this.loadEducationTrait.bind(this); this.onUpdateInput = this.onUpdateInput.bind(this); this.onAddEducation = this.onAddEducation.bind(this); + this.onShowUserConsent = this.onShowUserConsent.bind(this); + this.loadPersonalizationTrait = this.loadPersonalizationTrait.bind(this); this.state = { formInvalid: false, + showUserConsent: false, errorMessage: '', educationTrait: this.loadEducationTrait(props.userTraits), + personalizationTrait: this.loadPersonalizationTrait(props.userTraits), newEducation: { type: '', schoolCollegeName: '', @@ -43,8 +47,10 @@ export default class Education extends React.Component { componentWillReceiveProps(nextProps) { const educationTrait = this.loadEducationTrait(nextProps.userTraits); + const personalizationTrait = this.loadPersonalizationTrait(nextProps.userTraits); this.setState({ educationTrait, + personalizationTrait, formInvalid: false, errorMessage: '', newEducation: { @@ -157,11 +163,12 @@ export default class Education extends React.Component { /** * Add new education * @param e form submit event + * @param answer user consent answer value */ - onAddEducation(e) { + onAddEducation(e, answer) { e.preventDefault(); - - const { newEducation } = this.state; + this.setState({ showUserConsent: false }); + const { newEducation, personalizationTrait } = this.state; if (this.onCheckFormValue(newEducation)) { return; @@ -202,6 +209,17 @@ export default class Education extends React.Component { graduated: false, }; this.setState({ newEducation: empty }); + // save personalization + if (_.isEmpty(personalizationTrait)) { + const personalizationData = { userConsent: answer }; + addUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } else { + const trait = personalizationTrait.traits.data[0]; + if (trait.userConsent !== answer) { + const personalizationData = { userConsent: answer }; + updateUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } + } } /** @@ -228,6 +246,19 @@ export default class Education extends React.Component { } } + /** + * Show User Consent Modal + * @param e event + */ + onShowUserConsent(e) { + e.preventDefault(); + const { newEducation } = this.state; + if (this.onCheckFormValue(newEducation)) { + return; + } + this.setState({ showUserConsent: true }); + } + /** * Get education trait * @param userTraits the all user traits @@ -238,12 +269,23 @@ export default class Education extends React.Component { return _.assign({}, educations); } + /** + * Get personalization trait + * @param userTraits the all user traits + */ + loadPersonalizationTrait = (userTraits) => { + const trait = userTraits.filter(t => t.traitId === 'personalization'); + const personalization = trait.length === 0 ? {} : trait[0]; + return _.assign({}, personalization); + } + render() { const { settingsUI, } = this.props; const { educationTrait, + showUserConsent, } = this.state; const tabs = settingsUI.TABS.PROFILE; const currentTab = settingsUI.currentProfileTab; @@ -255,6 +297,9 @@ export default class Education extends React.Component { return (
+ { + showUserConsent && () + }
{ errorMessage } @@ -332,7 +377,7 @@ export default class Education extends React.Component {
Add Education diff --git a/src/shared/components/Settings/Profile/Education/styles.scss b/src/shared/components/Settings/Profile/Education/styles.scss index 17d41f7729..baf540c8a4 100644 --- a/src/shared/components/Settings/Profile/Education/styles.scss +++ b/src/shared/components/Settings/Profile/Education/styles.scss @@ -284,6 +284,27 @@ $checkbox-bg-selected: $tc-dark-blue; } } +.education-container div[class="Select-control"] { + height: 40px; + + div[class="Select-input"] { + height: 38px; + } + + div[class="Select-placeholder"] { + height: 38px; + line-height: 40px !important; + + @include xs-to-sm { + line-height: 27px !important; + } + } + + div[class="Select-value"] { + line-height: 40px !important; + } +} + .education-container .form-container .row .field :global .Select-placeholder { color: $tc-gray-50; } diff --git a/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx b/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx new file mode 100644 index 0000000000..22a2cb5b64 --- /dev/null +++ b/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx @@ -0,0 +1,59 @@ +/** + * render hobby Item + */ +import React from 'react'; +import PT from 'prop-types'; +import ReactSVG from 'react-svg'; +import { isomorphy } from 'topcoder-react-utils'; + + +import './styles.scss'; + +let assets; +if (isomorphy.isClientSide()) { + assets = require.context('assets/images/profile', false, /svg/); +} + +export default function Item(props) { + const { + hobby, + index, + onDeleteItem, + } = props; + + return ( + + ); +} + +Item.propTypes = { + hobby: PT.shape().isRequired, + index: PT.number.isRequired, + onDeleteItem: PT.func.isRequired, +}; diff --git a/src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss b/src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss new file mode 100644 index 0000000000..3e1a14f888 --- /dev/null +++ b/src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss @@ -0,0 +1,86 @@ +@import "../../../../style"; + +.container { + display: flex; + flex-direction: row; + justify-items: center; + justify-content: space-between; + height: 100%; + width: 100%; + padding: 20px; + border: 1px solid $tc-gray-10; + border-bottom: none; + background-color: $tc-white; +} + +.hobby-info { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.hobby-icon { + height: 49px; + width: 49px; + margin-right: 18px; +} + +.hobby-parameters { + @include roboto-medium; + + display: flex; + flex-direction: column; + justify-items: center; + justify-content: center; + font-size: 15px; + line-height: 20px; + text-transform: capitalize; + word-break: break-word; + margin-right: 20px; +} + +.parameter-first-line { + font-weight: 500; + color: $tc-black; + margin-bottom: 10px; + + @include xs-to-sm { + margin-bottom: 0; + } +} + +.parameter-second-line { + color: $tc-gray-50; + font-weight: 400; +} + +.delete { + display: flex; + flex-direction: column; + justify-items: center; + justify-content: center; + cursor: pointer; + outline-style: none; + margin-left: 10px; + + img { + margin-bottom: 10px; + + @include xs-to-sm { + margin-bottom: 0; + } + } + + p { + @include roboto-regular; + + font-size: 11px; + line-height: 15px; + font-weight: 400; + color: $tc-gray-50; + + @include xs-to-sm { + display: none; + } + } +} diff --git a/src/shared/components/Settings/Profile/Hobby/List/index.jsx b/src/shared/components/Settings/Profile/Hobby/List/index.jsx new file mode 100644 index 0000000000..a9428e232a --- /dev/null +++ b/src/shared/components/Settings/Profile/Hobby/List/index.jsx @@ -0,0 +1,34 @@ +/** + * render Hobby list + */ +import React from 'react'; +import PT from 'prop-types'; +import Item from './Item'; + +import './styles.scss'; + +export default function HobbyList(props) { + const { + hobbyList, + onDeleteItem, + } = props; + + return ( +
0 ? 'active' : ''}`}> +
    + { + hobbyList.items.map((hobby, index) => ( +
  • + +
  • + )) + } +
+
+ ); +} + +HobbyList.propTypes = { + hobbyList: PT.shape().isRequired, + onDeleteItem: PT.func.isRequired, +}; diff --git a/src/shared/components/Settings/Profile/Hobby/List/styles.scss b/src/shared/components/Settings/Profile/Hobby/List/styles.scss new file mode 100644 index 0000000000..1063b42b48 --- /dev/null +++ b/src/shared/components/Settings/Profile/Hobby/List/styles.scss @@ -0,0 +1,29 @@ +@import "../../../style"; + +.container { + width: 100%; + background-color: $tc-white; + padding: 0; + + &.active { + margin-top: 20px; + + @include xs-to-sm { + margin-top: 0; + } + } + + ul { + display: flex; + flex-direction: column; + justify-items: center; + + li { + min-height: 90px; + } + + li:last-child { + border-bottom: 1px solid $tc-gray-10; + } + } +} diff --git a/src/shared/components/Settings/Profile/Hobby/index.jsx b/src/shared/components/Settings/Profile/Hobby/index.jsx new file mode 100644 index 0000000000..361df10726 --- /dev/null +++ b/src/shared/components/Settings/Profile/Hobby/index.jsx @@ -0,0 +1,290 @@ +/** + * Child component of Settings/Profile/ renders the + * 'Hobby' page. + */ +/* eslint-disable react/forbid-prop-types */ +/* eslint-disable no-nested-ternary */ +/* eslint-disable jsx-a11y/label-has-for */ +import React from 'react'; +import PT from 'prop-types'; +import _ from 'lodash'; + +import { PrimaryButton } from 'topcoder-react-ui-kit'; +import UserConsentModal from 'components/Settings/UserConsentModal'; +import HobbyList from './List'; + +import './styles.scss'; + + +export default class Hobby extends React.Component { + constructor(props) { + super(props); + this.onDeleteHobby = this.onDeleteHobby.bind(this); + this.loadHobbyTrait = this.loadHobbyTrait.bind(this); + this.loadPersonalizationTrait = this.loadPersonalizationTrait.bind(this); + this.onUpdateInput = this.onUpdateInput.bind(this); + this.onAddHobby = this.onAddHobby.bind(this); + this.onShowUserConsent = this.onShowUserConsent.bind(this); + + this.state = { + showUserConsent: false, + formInvalid: false, + errorMessage: '', + hobbyTrait: this.loadHobbyTrait(props.userTraits), + personalizationTrait: this.loadPersonalizationTrait(props.userTraits), + newHobby: { + hobby: '', + description: '', + }, + }; + } + + componentWillReceiveProps(nextProps) { + const hobbyTrait = this.loadHobbyTrait(nextProps.userTraits); + const personalizationTrait = this.loadPersonalizationTrait(nextProps.userTraits); + this.setState({ + hobbyTrait, + personalizationTrait, + formInvalid: false, + errorMessage: '', + newHobby: { + hobby: '', + description: '', + }, + }); + } + + /** + * Show User Consent Modal + * @param e event + */ + onShowUserConsent(e) { + e.preventDefault(); + const { newHobby } = this.state; + if (this.onCheckFormValue(newHobby)) { + return; + } + this.setState({ showUserConsent: true }); + } + + /** + * Check form fields value, + * Invalid value, can not save + * @param newHobby object + */ + onCheckFormValue(newHobby) { + let invalid = false; + + let errorMessage = ''; + if (!_.trim(newHobby.hobby).length) { + errorMessage += 'Hobby, '; + invalid = true; + } + + if (!_.trim(newHobby.description).length) { + errorMessage += 'Description, '; + invalid = true; + } + + if (errorMessage.length > 0) { + errorMessage += ' cannot be empty'; + } + + this.setState({ errorMessage, formInvalid: invalid }); + return invalid; + } + + /** + * Delete hobby by index + * @param indexNo the hobby index no + */ + onDeleteHobby(indexNo) { + const { hobbyTrait } = this.state; + const newHobbyTrait = { ...hobbyTrait }; + newHobbyTrait.traits.data.splice(indexNo, 1); + this.setState({ + hobbyTrait: newHobbyTrait, + }); + + const { + handle, + tokenV3, + updateUserTrait, + deleteUserTrait, + } = this.props; + + if (newHobbyTrait.traits.data.length > 0) { + updateUserTrait(handle, 'hobby', newHobbyTrait.traits.data, tokenV3); + } else { + deleteUserTrait(handle, 'hobby', tokenV3); + } + } + + /** + * Add new hobby + * @param e form submit event + * @param answer user consent answer value + */ + onAddHobby(e, answer) { + e.preventDefault(); + this.setState({ showUserConsent: false }); + const { newHobby, personalizationTrait, hobbyTrait } = this.state; + + const { + handle, + tokenV3, + updateUserTrait, + addUserTrait, + } = this.props; + + // save hobby + if (hobbyTrait.traits && hobbyTrait.traits.data.length > 0) { + const newHobbyTrait = { ...hobbyTrait }; + newHobbyTrait.traits.data.push(newHobby); + this.setState({ hobbyTrait: newHobbyTrait }); + updateUserTrait(handle, 'hobby', newHobbyTrait.traits.data, tokenV3); + } else { + const newHobbies = []; + newHobbies.push(newHobby); + const traits = { + data: newHobbies, + }; + this.setState({ hobbyTrait: { traits } }); + addUserTrait(handle, 'hobby', newHobbies, tokenV3); + } + const empty = { + hobby: '', + description: '', + }; + this.setState({ newHobby: empty }); + + // save personalization + if (_.isEmpty(personalizationTrait)) { + const personalizationData = { userConsent: answer }; + addUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } else { + const trait = personalizationTrait.traits.data[0]; + if (trait.userConsent !== answer) { + const personalizationData = { userConsent: answer }; + updateUserTrait(handle, 'personalization', [personalizationData], tokenV3); + } + } + } + + /** + * Update input value + * @param e event + */ + onUpdateInput(e) { + const { newHobby: oldHobby } = this.state; + const newHobby = { ...oldHobby }; + newHobby[e.target.name] = e.target.value; + this.setState({ newHobby }); + } + + /** + * Get hobby trait + * @param userTraits the all user traits + */ + loadHobbyTrait = (userTraits) => { + const trait = userTraits.filter(t => t.traitId === 'hobby'); + const hobbys = trait.length === 0 ? {} : trait[0]; + return _.assign({}, hobbys); + } + + /** + * Get personalization trait + * @param userTraits the all user traits + */ + loadPersonalizationTrait = (userTraits) => { + const trait = userTraits.filter(t => t.traitId === 'personalization'); + const personalization = trait.length === 0 ? {} : trait[0]; + return _.assign({}, personalization); + } + + render() { + const { + settingsUI, + } = this.props; + const { + hobbyTrait, + showUserConsent, + } = this.state; + const tabs = settingsUI.TABS.PROFILE; + const currentTab = settingsUI.currentProfileTab; + const containerStyle = currentTab === tabs.HOBBY ? '' : 'hide'; + const hobbyItems = hobbyTrait.traits + ? hobbyTrait.traits.data.slice() : []; + const { newHobby, formInvalid, errorMessage } = this.state; + + return ( +
+ { + showUserConsent && () + } +
+
+ { errorMessage } +
+

+ Hobby +

+
+
+
+

+ Add Hobby +

+
+
+
+ + +
+
+
+
+ +