Skip to content

Profile Settings - Organizations, Hobbies and User Consent #1181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/assets/images/profile/ico-hobby.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/assets/images/profile/ico-organization.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default function Track({
</div>
</div>
</div>
<div className="onoffswitch" styleName="onoffswitch-no-padding-right">
<div styleName="onoffswitch-no-padding-right">
<input
type="checkbox"
name="eprf-onoffswitch"
Expand Down
22 changes: 22 additions & 0 deletions src/shared/components/Settings/Profile/BasicInfo/Track/styles.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
@import "~styles/mixins";

@mixin switch-transition {
transition: all 0.15s ease-in-out;
}

$switch-active-color: $tc-dark-blue-110;
$switch-inactive-color: $tc-gray-20;
$switch-width: 34px;
$switch-height: 20px;

.track-container {
display: flex;
flex-direction: row;
Expand Down Expand Up @@ -57,4 +66,17 @@
.onoffswitch-no-padding-right {
margin-right: 10px;
margin-left: 30px;

@include switch-transition;

align-self: center;
background-color: $switch-inactive-color;
border-radius: $switch-height;
box-sizing: border-box;
height: $switch-height;
width: $switch-width;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
51 changes: 47 additions & 4 deletions src/shared/components/Settings/Profile/BasicInfo/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import moment from 'moment';

import { PrimaryButton } from 'topcoder-react-ui-kit';
import { getAllCountryObjects } from 'utils/countries';

import UserConsentModal from 'components/Settings/UserConsentModal';
import Select from 'components/Select';
import ImageInput from '../ImageInput';
import Track from './Track';
Expand All @@ -34,11 +34,14 @@ export default class BasicInfo extends React.Component {
this.onUpdateInput = this.onUpdateInput.bind(this);
this.onSaveBasicInfo = this.onSaveBasicInfo.bind(this);
this.onChange = this.onChange.bind(this);
this.onShowUserConsent = this.onShowUserConsent.bind(this);

this.state = {
showUserConsent: false,
savingBasicInfo: false,
inputChanged: false,
basicInfoTrait: this.loadBasicInfoTraits(props.userTraits),
personalizationTrait: this.loadPersonalizationTrait(props.userTraits),
newBasicInfo: {
handle: '',
firstName: '',
Expand Down Expand Up @@ -81,21 +84,35 @@ export default class BasicInfo extends React.Component {
componentWillReceiveProps(nextProps) {
const basicInfoTrait = this.loadBasicInfoTraits(nextProps.userTraits);
const basicInfo = basicInfoTrait.traits ? basicInfoTrait.traits.data[0] : {};
const personalizationTrait = this.loadPersonalizationTrait(nextProps.userTraits);
this.processBasicInfo(basicInfo);
this.setState({
basicInfoTrait,
personalizationTrait,
savingBasicInfo: false,
inputChanged: false,
});
}

/**
* Show User Consent Modal
* @param {*} e event
*/
onShowUserConsent(e) {
e.preventDefault();
this.setState({ showUserConsent: true });
}

/**
* Save Basic Info
* @param e form submit event
* @param answer user consent answer value
*/
onSaveBasicInfo(e) {
onSaveBasicInfo(e, answer) {
e.preventDefault();
this.setState({
savingBasicInfo: true,
showUserConsent: false,
});

const {
Expand All @@ -104,7 +121,7 @@ export default class BasicInfo extends React.Component {
addUserTrait,
updateUserTrait,
} = this.props;
const { newBasicInfo, basicInfoTrait } = this.state;
const { newBasicInfo, basicInfoTrait, personalizationTrait } = this.state;
newBasicInfo.birthDate = new Date(newBasicInfo.birthDate).toISOString();

if (basicInfoTrait.traits && basicInfoTrait.traits.data.length > 0) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -322,10 +361,14 @@ export default class BasicInfo extends React.Component {
const {
savingBasicInfo,
newBasicInfo,
showUserConsent,
} = this.state;

return (
<div styleName="basic-info-container">
{
showUserConsent && (<UserConsentModal onSaveTrait={this.onSaveBasicInfo} />)
}
<div styleName="about-me-container">
<div styleName="user-icon">
<ImageInput
Expand Down Expand Up @@ -522,7 +565,7 @@ export default class BasicInfo extends React.Component {
<div styleName="button-save">
<PrimaryButton
styleName="white-label"
onClick={this.onSaveBasicInfo}
onClick={this.onShowUserConsent}
disabled={this.shouldDisableSave() || savingBasicInfo}
>
{
Expand Down
41 changes: 41 additions & 0 deletions src/shared/components/Settings/Profile/BasicInfo/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
74 changes: 62 additions & 12 deletions src/shared/components/Settings/Profile/Community/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -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
Expand All @@ -99,14 +144,19 @@ 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';
const communityItems = communityTrait;

return (
<div styleName={containerStyle}>
{
showUserConsent && (
<UserConsentModal onSaveTrait={this.onChange} />
)
}
<div styleName="community-container">
<h1>
Community
Expand All @@ -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)}
/>
);
})
Expand Down
Loading