From d0014682d4aeef33353b3f3f952dc2a4178728d6 Mon Sep 17 00:00:00 2001 From: Huan Li Date: Sun, 9 Jun 2019 15:23:01 +0800 Subject: [PATCH 01/18] Topcoder Member Profile UI Fixes and Enhancements - Part 1 https://www.topcoder.com/challenges/30092312 --- src/assets/images/profile/ico-edit.svg | 6 + .../images/tools/device-types/ico-edit.svg | 6 + .../tools/service-provider-types/ico-edit.svg | 6 + .../images/tools/software-types/ico-edit.svg | 6 + .../tools/subscription-types/ico-edit.svg | 6 + .../Profile/Education/List/Item/index.jsx | 102 +++++--- .../Profile/Education/List/Item/styles.scss | 83 +++++-- .../Settings/Profile/Education/List/index.jsx | 9 +- .../Settings/Profile/Education/index.jsx | 217 ++++++++++++---- .../Settings/Profile/Education/styles.scss | 67 +++-- .../Profile/Hobby/List/Item/index.jsx | 63 +++-- .../Profile/Hobby/List/Item/styles.scss | 86 +++++-- .../Settings/Profile/Hobby/List/index.jsx | 9 +- .../Settings/Profile/Hobby/index.jsx | 149 ++++++++--- .../Settings/Profile/Hobby/styles.scss | 49 ++-- .../Profile/Language/List/Item/index.jsx | 99 ++++++-- .../Profile/Language/List/Item/styles.scss | 84 +++++-- .../Settings/Profile/Language/List/index.jsx | 9 +- .../Settings/Profile/Language/dropdowns.json | 2 +- .../Settings/Profile/Language/index.jsx | 197 +++++++++++---- .../Settings/Profile/Language/styles.scss | 58 +++-- .../Settings/Profile/Work/List/Item/index.jsx | 103 ++++++-- .../Profile/Work/List/Item/styles.scss | 84 +++++-- .../Settings/Profile/Work/List/index.jsx | 4 +- .../Settings/Profile/Work/index.jsx | 231 +++++++++++++----- .../Settings/Profile/Work/styles.scss | 57 +++-- .../Tools/Devices/List/Item/index.jsx | 70 ++++-- .../Tools/Devices/List/Item/styles.scss | 86 +++++-- .../Settings/Tools/Devices/List/index.jsx | 9 +- .../Settings/Tools/Devices/index.jsx | 199 ++++++++++----- .../Settings/Tools/Devices/styles.scss | 52 ++-- .../ServiceProviders/List/Item/index.jsx | 40 ++- .../ServiceProviders/List/Item/styles.scss | 73 ++++-- .../Tools/ServiceProviders/List/index.jsx | 9 +- .../Settings/Tools/ServiceProviders/index.jsx | 128 ++++++++-- .../Tools/ServiceProviders/styles.scss | 49 ++-- .../Tools/Software/List/Item/index.jsx | 40 ++- .../Tools/Software/List/Item/styles.scss | 73 ++++-- .../Settings/Tools/Software/List/index.jsx | 9 +- .../Settings/Tools/Software/index.jsx | 126 ++++++++-- .../Settings/Tools/Software/styles.scss | 49 ++-- .../Tools/Subscriptions/List/Item/index.jsx | 40 ++- .../Tools/Subscriptions/List/Item/styles.scss | 77 ++++-- .../Tools/Subscriptions/List/index.jsx | 9 +- .../Settings/Tools/Subscriptions/index.jsx | 125 ++++++++-- .../Settings/Tools/Subscriptions/styles.scss | 45 ++-- src/shared/components/Settings/style.scss | 11 + 47 files changed, 2347 insertions(+), 764 deletions(-) create mode 100644 src/assets/images/profile/ico-edit.svg create mode 100644 src/assets/images/tools/device-types/ico-edit.svg create mode 100644 src/assets/images/tools/service-provider-types/ico-edit.svg create mode 100644 src/assets/images/tools/software-types/ico-edit.svg create mode 100644 src/assets/images/tools/subscription-types/ico-edit.svg diff --git a/src/assets/images/profile/ico-edit.svg b/src/assets/images/profile/ico-edit.svg new file mode 100644 index 0000000000..b3e37a33dc --- /dev/null +++ b/src/assets/images/profile/ico-edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/tools/device-types/ico-edit.svg b/src/assets/images/tools/device-types/ico-edit.svg new file mode 100644 index 0000000000..b3e37a33dc --- /dev/null +++ b/src/assets/images/tools/device-types/ico-edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/tools/service-provider-types/ico-edit.svg b/src/assets/images/tools/service-provider-types/ico-edit.svg new file mode 100644 index 0000000000..b3e37a33dc --- /dev/null +++ b/src/assets/images/tools/service-provider-types/ico-edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/tools/software-types/ico-edit.svg b/src/assets/images/tools/software-types/ico-edit.svg new file mode 100644 index 0000000000..b3e37a33dc --- /dev/null +++ b/src/assets/images/tools/software-types/ico-edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/tools/subscription-types/ico-edit.svg b/src/assets/images/tools/subscription-types/ico-edit.svg new file mode 100644 index 0000000000..b3e37a33dc --- /dev/null +++ b/src/assets/images/tools/subscription-types/ico-edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/shared/components/Settings/Profile/Education/List/Item/index.jsx b/src/shared/components/Settings/Profile/Education/List/Item/index.jsx index 24c15e2e93..7002ffc2d9 100644 --- a/src/shared/components/Settings/Profile/Education/List/Item/index.jsx +++ b/src/shared/components/Settings/Profile/Education/List/Item/index.jsx @@ -1,6 +1,7 @@ /** * render education Item */ +import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; import ReactSVG from 'react-svg'; @@ -19,47 +20,89 @@ export default function Item(props) { education, index, onDeleteItem, + onEditItem, } = props; + const hasSecondLine = () => { + if (_.isEmpty(education.timePeriodFrom) && _.isEmpty(education.timePeriodTo) + && !education.graduated) { + return false; + } + + return true; + }; + return (
-
-
+
+
{ `${education.schoolCollegeName} ${education.type}` }
-
- { `${moment(education.timePeriodFrom).format('YYYY')} - ${moment(education.timePeriodTo).format('YYYY')}${education.graduated ? ' | Graduated' : ''}` } -
-
-

- {`${moment(education.timePeriodFrom).format('YYYY')} - ${moment(education.timePeriodTo).format('YYYY')}`} -

- { - education.graduated && ( -

- Graduated -

- ) - } -
+ { + hasSecondLine() && ( + +
+ { + `${!_.isEmpty(education.timePeriodFrom) && !_.isEmpty(education.timePeriodTo) && !education.graduated ? `${moment(education.timePeriodFrom).format('YYYY')} - ${moment(education.timePeriodTo).format('YYYY')}` : ''}` + } + { + _.isEmpty(education.timePeriodFrom) && _.isEmpty(education.timePeriodTo) && `${education.graduated ? 'Graduated' : ''}` + } + { + !_.isEmpty(education.timePeriodFrom) && !_.isEmpty(education.timePeriodTo) && education.graduated && `${moment(education.timePeriodFrom).format('YYYY')} - ${moment(education.timePeriodTo).format('YYYY')} | Graduated` + } +
+
+ { + !_.isEmpty(education.timePeriodFrom) && !_.isEmpty(education.timePeriodTo) && ( +

+ {`${moment(education.timePeriodFrom).format('YYYY')} - ${moment(education.timePeriodTo).format('YYYY')}`} +

+ ) + } + { + education.graduated && ( +

+ Graduated +

+ ) + } +
+
+ ) + }
- onDeleteItem(index)} - tabIndex={0} - role="button" - onClick={() => onDeleteItem(index)} - > - delete-icon -

- Delete -

-
+
+ onEditItem(index)} + tabIndex={0} + role="button" + onClick={() => onEditItem(index)} + > + edit-icon +

+ Edit +

+
+ onDeleteItem(index)} + tabIndex={0} + role="button" + onClick={() => onDeleteItem(index)} + > + delete-icon +

+ Delete +

+
+
); } @@ -68,4 +111,5 @@ Item.propTypes = { education: PT.shape().isRequired, index: PT.number.isRequired, onDeleteItem: PT.func.isRequired, + onEditItem: PT.func.isRequired, }; diff --git a/src/shared/components/Settings/Profile/Education/List/Item/styles.scss b/src/shared/components/Settings/Profile/Education/List/Item/styles.scss index 1f9610afa3..2f9a2117a3 100644 --- a/src/shared/components/Settings/Profile/Education/List/Item/styles.scss +++ b/src/shared/components/Settings/Profile/Education/List/Item/styles.scss @@ -36,6 +36,11 @@ line-height: 20px; text-transform: capitalize; padding-right: 20px; + + &.single-line { + flex-direction: row; + align-items: center; + } } .parameter-first-line { @@ -44,6 +49,10 @@ margin-bottom: 10px; word-break: break-all; + &.single-line { + margin-bottom: 0; + } + @include upto-sm { margin-bottom: 0; } @@ -74,32 +83,70 @@ } } -.delete { +.operation-container { display: flex; - flex-direction: column; - justify-items: center; - justify-content: center; - cursor: pointer; - outline-style: none; + flex-direction: row; + justify-content: space-between; - img { - margin-bottom: 10px; + .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 upto-sm { + margin-bottom: 0; + } + } + + p { + @include roboto-regular; - @include upto-sm { - margin-bottom: 0; + font-size: 11px; + line-height: 15px; + font-weight: 400; + color: $tc-gray-50; + + @include upto-sm { + display: none; + } } } - p { - @include roboto-regular; + .edit { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + outline-style: none; + margin-left: 10px; + + img { + margin-bottom: 10px; + + @include upto-sm { + margin-bottom: 0; + } + } - font-size: 11px; - line-height: 15px; - font-weight: 400; - color: $tc-gray-50; + p { + @include roboto-regular; + + font-size: 11px; + line-height: 15px; + font-weight: 400; + color: $tc-gray-50; - @include upto-sm { - display: none; + @include upto-sm { + display: none; + } } } } diff --git a/src/shared/components/Settings/Profile/Education/List/index.jsx b/src/shared/components/Settings/Profile/Education/List/index.jsx index b8eaf68c7c..624afdc5f3 100644 --- a/src/shared/components/Settings/Profile/Education/List/index.jsx +++ b/src/shared/components/Settings/Profile/Education/List/index.jsx @@ -11,6 +11,7 @@ export default function EducationList(props) { const { educationList, onDeleteItem, + onEditItem, } = props; return ( @@ -19,7 +20,12 @@ export default function EducationList(props) { { educationList.items.map((education, index) => (
  • - +
  • )) } @@ -31,4 +37,5 @@ export default function EducationList(props) { EducationList.propTypes = { educationList: PT.shape().isRequired, onDeleteItem: PT.func.isRequired, + onEditItem: PT.func.isRequired, }; diff --git a/src/shared/components/Settings/Profile/Education/index.jsx b/src/shared/components/Settings/Profile/Education/index.jsx index 326ce05fc5..35d94b44ef 100644 --- a/src/shared/components/Settings/Profile/Education/index.jsx +++ b/src/shared/components/Settings/Profile/Education/index.jsx @@ -15,6 +15,7 @@ import ConsentComponent from 'components/Settings/ConsentComponent'; import { PrimaryButton } from 'topcoder-react-ui-kit'; import DatePicker from 'components/challenge-listing/Filters/DatePicker'; import dropdowns from './dropdowns.json'; +import ConfirmationModal from '../../CofirmationModal'; import EducationList from './List'; import './styles.scss'; @@ -25,6 +26,7 @@ export default class Education extends ConsentComponent { super(props); this.onHandleDeleteEducation = this.onHandleDeleteEducation.bind(this); this.onDeleteEducation = this.onDeleteEducation.bind(this); + this.onEditEducation = this.onEditEducation.bind(this); this.onUpdateSelect = this.onUpdateSelect.bind(this); this.loadEducationTrait = this.loadEducationTrait.bind(this); this.onUpdateInput = this.onUpdateInput.bind(this); @@ -33,6 +35,7 @@ export default class Education extends ConsentComponent { this.loadPersonalizationTrait = this.loadPersonalizationTrait.bind(this); this.updatePredicate = this.updatePredicate.bind(this); this.onUpdateDate = this.onUpdateDate.bind(this); + this.onCancelEditStatus = this.onCancelEditStatus.bind(this); const { userTraits } = props; this.state = { @@ -50,6 +53,9 @@ export default class Education extends ConsentComponent { }, isMobileView: false, screenSM: 767, + isEdit: false, + indexNo: null, + showConfirmation: false, }; } @@ -100,12 +106,7 @@ export default class Education extends ConsentComponent { } if (!_.trim(newEducation.schoolCollegeName).length) { - errorMessage += 'Name, '; - invalid = true; - } - - if (!_.trim(newEducation.major).length) { - errorMessage += 'Major, '; + errorMessage += 'Name of College or University, '; invalid = true; } @@ -113,16 +114,19 @@ export default class Education extends ConsentComponent { errorMessage += ' cannot be empty'; } - const fromDate = new Date(newEducation.timePeriodFrom).getTime(); - const toDate = new Date(newEducation.timePeriodTo).getTime(); + if (!_.isEmpty(newEducation.timePeriodFrom) && !_.isEmpty(newEducation.timePeriodTo)) { + const fromDate = new Date(newEducation.timePeriodFrom).getTime(); + const toDate = new Date(newEducation.timePeriodTo).getTime(); - if (fromDate > toDate) { - dateError += 'From Date value should be smaller than To Date value. '; - dateInvalid = true; - haveDate = true; + if (fromDate > toDate) { + dateError += 'From Date value should be smaller than To Date value. '; + dateInvalid = true; + haveDate = true; + } } - if (!haveDate) { + if (!haveDate + && !(_.isEmpty(newEducation.timePeriodFrom) && _.isEmpty(newEducation.timePeriodTo))) { if (!_.trim(newEducation.timePeriodFrom).length) { dateError += 'From Date, '; dateInvalid = true; @@ -139,7 +143,6 @@ export default class Education extends ConsentComponent { } } - if (errorMessage.length > 0) { errorMessage = `${errorMessage}. \n${dateError}`; } else if (dateError.length > 0) { @@ -152,7 +155,10 @@ export default class Education extends ConsentComponent { } onHandleDeleteEducation(indexNo) { - this.showConsent(this.onDeleteEducation.bind(this, indexNo)); + this.setState({ + showConfirmation: true, + indexNo, + }); } onUpdateDate(date, timePeriod) { @@ -188,6 +194,31 @@ export default class Education extends ConsentComponent { } else { deleteUserTrait(handle, 'education', tokenV3); } + + this.setState({ + showConfirmation: false, + indexNo: null, + }); + } + + /** + * Edit Education by index + * @param indexNo the education index no + */ + onEditEducation(indexNo) { + const { educationTrait } = this.state; + this.setState({ + newEducation: { + type: educationTrait.traits.data[indexNo].type, + schoolCollegeName: educationTrait.traits.data[indexNo].schoolCollegeName, + major: _.isEmpty(educationTrait.traits.data[indexNo].major) ? '' : educationTrait.traits.data[indexNo].major, + timePeriodFrom: _.isEmpty(educationTrait.traits.data[indexNo].timePeriodFrom) ? '' : educationTrait.traits.data[indexNo].timePeriodFrom, + timePeriodTo: _.isEmpty(educationTrait.traits.data[indexNo].timePeriodTo) ? '' : educationTrait.traits.data[indexNo].timePeriodTo, + graduated: educationTrait.traits.data[indexNo].graduated, + }, + isEdit: true, + indexNo, + }); } /** @@ -195,7 +226,9 @@ export default class Education extends ConsentComponent { * @param answer user consent answer value */ onAddEducation(answer) { - const { newEducation, personalizationTrait } = this.state; + const { + newEducation, personalizationTrait, isEdit, indexNo, + } = this.state; if (this.onCheckFormValue(newEducation)) { return; @@ -210,17 +243,32 @@ export default class Education extends ConsentComponent { const { educationTrait } = this.state; - newEducation.timePeriodFrom = new Date(newEducation.timePeriodFrom).getTime(); - newEducation.timePeriodTo = new Date(newEducation.timePeriodTo).getTime(); + const education = _.clone(newEducation); + if (_.isEmpty(education.major)) { + delete education.major; + } + if (_.isEmpty(education.timePeriodFrom)) { + delete education.timePeriodFrom; + } else { + education.timePeriodFrom = new Date(newEducation.timePeriodFrom).getTime(); + } + if (_.isEmpty(education.timePeriodTo)) { + delete education.timePeriodTo; + } else { + education.timePeriodTo = new Date(newEducation.timePeriodTo).getTime(); + } if (educationTrait.traits && educationTrait.traits.data.length > 0) { const newEducationTrait = { ...educationTrait }; - newEducationTrait.traits.data.push(newEducation); + if (isEdit) { + newEducationTrait.traits.data.splice(indexNo, 1); + } + newEducationTrait.traits.data.push(education); this.setState({ educationTrait: newEducationTrait }); updateUserTrait(handle, 'education', newEducationTrait.traits.data, tokenV3); } else { const newEducations = []; - newEducations.push(newEducation); + newEducations.push(education); const traits = { data: newEducations, }; @@ -235,7 +283,11 @@ export default class Education extends ConsentComponent { timePeriodTo: '', graduated: false, }; - this.setState({ newEducation: empty }); + this.setState({ + newEducation: empty, + isEdit: false, + indexNo: null, + }); // save personalization if (_.isEmpty(personalizationTrait)) { const personalizationData = { userConsent: answer }; @@ -311,6 +363,24 @@ export default class Education extends ConsentComponent { this.setState({ isMobileView: window.innerWidth <= screenSM }); } + onCancelEditStatus() { + const { isEdit } = this.state; + if (isEdit) { + this.setState({ + isEdit: false, + indexNo: null, + newEducation: { + type: '', + schoolCollegeName: '', + major: '', + timePeriodFrom: '', + timePeriodTo: '', + graduated: false, + }, + }); + } + } + render() { const { settingsUI, @@ -318,6 +388,9 @@ export default class Education extends ConsentComponent { const { educationTrait, isMobileView, + isEdit, + showConfirmation, + indexNo, } = this.state; const tabs = settingsUI.TABS.PROFILE; const currentTab = settingsUI.currentProfileTab; @@ -332,6 +405,17 @@ export default class Education extends ConsentComponent { { this.shouldRenderConsent() && this.renderConsent() } + { + showConfirmation && ( + this.showConsent(this.onDeleteEducation.bind(this, indexNo))} + onCancel={() => this.setState({ + showConfirmation: false, + indexNo: null, + })} + /> + ) + }
    { errorMessage } @@ -347,12 +431,16 @@ export default class Education extends ConsentComponent { && ( ) }
    0 ? 'second' : 'first'}`}> - Add a new education + { + isEdit ? (Edit education) + : (Add a new education) + }
    @@ -380,7 +468,7 @@ export default class Education extends ConsentComponent {
    @@ -390,26 +478,24 @@ export default class Education extends ConsentComponent {
    -
    +
    - * Required
    -
    +
    - * Required
    -
    +
    - * Required
    -
    - - Add education to your list - +
    +
    + + { + isEdit ? (Edit education to your list) + : (Add education to your list) + } + +
    + { + isEdit && ( +
    + + Cancel + +
    + ) + }

    - Add Education + { + isEdit ? (Edit Education) + : (Add Education) + }

    @@ -565,13 +672,30 @@ export default class Education extends ConsentComponent {
    -
    - - Add Education - +
    +
    + + { + isEdit ? (Edit Education) + : (Add Education) + } + +
    + { + isEdit && ( +
    + + Cancel + +
    + ) + }
    { @@ -580,6 +704,7 @@ export default class Education extends ConsentComponent { ) } diff --git a/src/shared/components/Settings/Profile/Education/styles.scss b/src/shared/components/Settings/Profile/Education/styles.scss index 46d598c983..b025f03c02 100644 --- a/src/shared/components/Settings/Profile/Education/styles.scss +++ b/src/shared/components/Settings/Profile/Education/styles.scss @@ -80,11 +80,18 @@ $checkbox-bg-selected: $tc-dark-blue; label { @include roboto-medium; + display: block; font-size: 12px; line-height: 15px; font-weight: 500; color: $tc-gray-80; margin-bottom: 5px; + + .text-required { + font-size: 10px; + color: $tc-red-110; + margin-left: 5px; + } } .tc-checkbox { @@ -184,6 +191,16 @@ label { user-select: none; cursor: pointer; } + + .row { + .field { + &.col-1, + &.col-1-no-padding { + max-width: 200px; + min-width: 200px; + } + } + } } .form-container-mobile { @@ -255,7 +272,8 @@ label { align-items: center; } - &.col-1 { + &.col-1, + &.col-1-no-padding { width: 23%; @include upto-sm { @@ -315,31 +333,42 @@ label { } } -.button-save { - align-self: center; +.button-container { + display: flex; + justify-content: center; + align-items: center; - @include upto-sm { - margin-top: 30px; - } + .button-save, + .button-cancel { + align-self: center; - button, - a { - @include roboto-medium; + @include upto-sm { + margin-top: 30px; + } - height: 40px; - font-size: 15px; - font-weight: 500; - margin: 0; - padding: 0; - width: 250px; + button, + a { + @include roboto-medium; - @include upto-sm { - width: 156px; + height: 40px; + font-size: 15px; + font-weight: 500; + margin: 0; + padding: 0; + width: 250px; + + @include upto-sm { + width: 156px; + } + } + + .complete { + color: $tc-white; } } - .complete { - color: $tc-white; + .button-cancel { + margin-left: 10px; } } diff --git a/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx b/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx index 22a2cb5b64..199f87e8bc 100644 --- a/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx +++ b/src/shared/components/Settings/Profile/Hobby/List/Item/index.jsx @@ -1,6 +1,7 @@ /** * render hobby Item */ +import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; import ReactSVG from 'react-svg'; @@ -19,35 +20,62 @@ export default function Item(props) { hobby, index, onDeleteItem, + onEditItem, } = props; + const hasSecondLine = () => { + if (_.isEmpty(hobby.description)) { + return false; + } + + return true; + }; + return (
    - ); } @@ -56,4 +84,5 @@ Item.propTypes = { hobby: PT.shape().isRequired, index: PT.number.isRequired, onDeleteItem: PT.func.isRequired, + onEditItem: 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 index 99e35dde9c..547acc2b0f 100644 --- a/src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss +++ b/src/shared/components/Settings/Profile/Hobby/List/Item/styles.scss @@ -37,6 +37,11 @@ text-transform: capitalize; word-break: break-word; margin-right: 20px; + + &.single-line { + flex-direction: row; + align-items: center; + } } .parameter-first-line { @@ -44,6 +49,12 @@ color: $tc-black; margin-bottom: 10px; + &.single-line { + flex-direction: row; + align-items: center; + margin-bottom: 0; + } + @include upto-sm { margin-bottom: 0; } @@ -54,33 +65,70 @@ font-weight: 400; } -.delete { +.operation-container { display: flex; - flex-direction: column; - justify-items: center; - justify-content: center; - cursor: pointer; - outline-style: none; - margin-left: 10px; + flex-direction: row; + justify-content: space-between; - img { - margin-bottom: 10px; + .delete { + display: flex; + flex-direction: column; + justify-items: center; + justify-content: center; + cursor: pointer; + outline-style: none; + margin-left: 10px; - @include upto-sm { - margin-bottom: 0; + img { + margin-bottom: 10px; + + @include upto-sm { + margin-bottom: 0; + } + } + + p { + @include roboto-regular; + + font-size: 11px; + line-height: 15px; + font-weight: 400; + color: $tc-gray-50; + + @include upto-sm { + display: none; + } } } - p { - @include roboto-regular; + .edit { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + outline-style: none; + margin-left: 10px; + + img { + margin-bottom: 10px; + + @include upto-sm { + margin-bottom: 0; + } + } + + p { + @include roboto-regular; - font-size: 11px; - line-height: 15px; - font-weight: 400; - color: $tc-gray-50; + font-size: 11px; + line-height: 15px; + font-weight: 400; + color: $tc-gray-50; - @include upto-sm { - display: none; + @include upto-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 index a9428e232a..34767a332a 100644 --- a/src/shared/components/Settings/Profile/Hobby/List/index.jsx +++ b/src/shared/components/Settings/Profile/Hobby/List/index.jsx @@ -11,6 +11,7 @@ export default function HobbyList(props) { const { hobbyList, onDeleteItem, + onEditItem, } = props; return ( @@ -19,7 +20,12 @@ export default function HobbyList(props) { { hobbyList.items.map((hobby, index) => (
  • - +
  • )) } @@ -31,4 +37,5 @@ export default function HobbyList(props) { HobbyList.propTypes = { hobbyList: PT.shape().isRequired, onDeleteItem: PT.func.isRequired, + onEditItem: PT.func.isRequired, }; diff --git a/src/shared/components/Settings/Profile/Hobby/index.jsx b/src/shared/components/Settings/Profile/Hobby/index.jsx index 6fc926ea26..20a9014a60 100644 --- a/src/shared/components/Settings/Profile/Hobby/index.jsx +++ b/src/shared/components/Settings/Profile/Hobby/index.jsx @@ -23,12 +23,14 @@ export default class Hobby extends ConsentComponent { super(props); this.onHandleDeleteHobby = this.onHandleDeleteHobby.bind(this); this.onDeleteHobby = this.onDeleteHobby.bind(this); + this.onEditHobby = this.onEditHobby.bind(this); this.loadHobbyTrait = this.loadHobbyTrait.bind(this); this.loadPersonalizationTrait = this.loadPersonalizationTrait.bind(this); this.onUpdateInput = this.onUpdateInput.bind(this); this.onHandleAddHobby = this.onHandleAddHobby.bind(this); this.onAddHobby = this.onAddHobby.bind(this); this.updatePredicate = this.updatePredicate.bind(this); + this.onCancelEditStatus = this.onCancelEditStatus.bind(this); const { userTraits } = props; this.state = { @@ -44,6 +46,7 @@ export default class Hobby extends ConsentComponent { screenSM: 767, showConfirmation: false, indexNo: null, + isEdit: false, }; } @@ -99,11 +102,6 @@ export default class Hobby extends ConsentComponent { invalid = true; } - if (!_.trim(newHobby.description).length) { - invalidFields.push('Description'); - invalid = true; - } - if (invalidFields.length > 0) { errorMessage += invalidFields.join(', '); errorMessage += ' cannot be empty'; @@ -155,7 +153,9 @@ export default class Hobby extends ConsentComponent { * @param answer user consent answer value */ onAddHobby(answer) { - const { newHobby, personalizationTrait, hobbyTrait } = this.state; + const { + newHobby, personalizationTrait, hobbyTrait, isEdit, indexNo, + } = this.state; const { handle, @@ -163,16 +163,23 @@ export default class Hobby extends ConsentComponent { updateUserTrait, addUserTrait, } = this.props; + const hobby = _.clone(newHobby); + if (_.isEmpty(hobby.description)) { + delete hobby.description; + } // save hobby if (hobbyTrait.traits && hobbyTrait.traits.data.length > 0) { const newHobbyTrait = { ...hobbyTrait }; - newHobbyTrait.traits.data.push(newHobby); + if (isEdit) { + newHobbyTrait.traits.data.splice(indexNo, 1); + } + newHobbyTrait.traits.data.push(hobby); this.setState({ hobbyTrait: newHobbyTrait }); updateUserTrait(handle, 'hobby', newHobbyTrait.traits.data, tokenV3); } else { const newHobbies = []; - newHobbies.push(newHobby); + newHobbies.push(hobby); const traits = { data: newHobbies, }; @@ -183,7 +190,11 @@ export default class Hobby extends ConsentComponent { hobby: '', description: '', }; - this.setState({ newHobby: empty }); + this.setState({ + newHobby: empty, + isEdit: false, + indexNo: null, + }); // save personalization if (_.isEmpty(personalizationTrait)) { @@ -234,6 +245,36 @@ export default class Hobby extends ConsentComponent { this.setState({ isMobileView: window.innerWidth <= screenSM }); } + /** + * Edit hobby by index + * @param indexNo the hobby index no + */ + onEditHobby(indexNo) { + const { hobbyTrait } = this.state; + this.setState({ + newHobby: { + hobby: hobbyTrait.traits.data[indexNo].hobby, + description: _.isEmpty(hobbyTrait.traits.data[indexNo].description) ? '' : hobbyTrait.traits.data[indexNo].description, + }, + isEdit: true, + indexNo, + }); + } + + onCancelEditStatus() { + const { isEdit } = this.state; + if (isEdit) { + this.setState({ + isEdit: false, + indexNo: null, + newHobby: { + hobby: '', + description: '', + }, + }); + } + } + render() { const { settingsUI, @@ -241,7 +282,7 @@ export default class Hobby extends ConsentComponent { const { hobbyTrait, isMobileView, - showConfirmation, indexNo, + showConfirmation, indexNo, isEdit, } = this.state; const canModifyTrait = !this.props.traitRequestCount; const tabs = settingsUI.TABS.PROFILE; @@ -264,6 +305,9 @@ export default class Hobby extends ConsentComponent { /> )}
    +
    + {errorMessage} +

    Hobby

    @@ -276,11 +320,15 @@ export default class Hobby extends ConsentComponent { ) }
    0 ? 'second' : 'first'}`}> - Add a new hobby + { + isEdit ? (Edit hobby) + : (Add a new hobby) + }
    @@ -297,7 +345,7 @@ export default class Hobby extends ConsentComponent {
    -
    +