diff --git a/modules/core/client/less/global-variables.less b/modules/core/client/less/global-variables.less index 7a99dcfebb..6d3c643639 100644 --- a/modules/core/client/less/global-variables.less +++ b/modules/core/client/less/global-variables.less @@ -159,6 +159,15 @@ @text-highlight: lighten(@brand-primary, 40%); @text-highlight-color: @text-color; +// Reference colors +// --------------------------------------- +@reference-recommend-yes-bg: #5cb85c; +@reference-recommend-yes-color: #fff; +@reference-recommend-no-bg: #d9534f; +@reference-recommend-no-color: #fff; +@reference-recommend-unknown-bg: lighten(#000, 98%); +@reference-recommend-unknown-color: @btn-default-color; + // Offer colors // --------------------------------------- @offer-hosting-yes: #5cb85c; diff --git a/modules/references/client/components/ReferencesNew.component.js b/modules/references/client/components/ReferencesNew.component.js new file mode 100644 index 0000000000..53979b1a38 --- /dev/null +++ b/modules/references/client/components/ReferencesNew.component.js @@ -0,0 +1,344 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +function Interaction(props) { + + const { reference: { interactions } } = props; + const isInteraction = [...Object.keys(interactions)].reduce((accumulator, current) => accumulator || interactions[current], false); + return ( +
+
+

How do you know them?

+
+
+
+ +

+ +

+ +
+ {(!isInteraction) ? ( +
+ Sorry, you cannot leave them a reference if you didn't have any previous interraction. +
+ ) : null} +
+
+ ); +} + +Interaction.propTypes = { + onChange: PropTypes.func, + reference: PropTypes.object +}; + +function Recommend(props) { + + const { hostedMe, hostedThem } = props.reference.interactions; + const maxInteraction = (hostedMe) ? 'hostedMe' : (hostedThem) ? 'hostedThem' : 'met'; + const recommendQuestions = { + hostedMe: 'Would you recommend others to stay with them?', + hostedThem: 'Would you recommend others to host them?', + met: 'Would you recommend others to meet them?' + }; + + return ( +
+
+

{recommendQuestions[maxInteraction]}

+
+
+
+ + + +
+ {(!props.reference.recommend) ? +
+ Please choose if you can recommend them. +
: null} + {(props.reference.recommend === 'no') ? + : null} +
+
+ ); +} + +Recommend.propTypes = { + reference: PropTypes.object, + onChange: PropTypes.func, + onChangeReportMessage: PropTypes.func, + onChangeReport: PropTypes.func, + onChangeReportMessage: PropTypes.func, + report: PropTypes.bool, + reportMessage: PropTypes.string +}; + +function Report(props) { + return ( +
+

+

+ We're sad to hear you didn't have great experience using Trustroots! 😞 +

+ +

+ {(props.report) ? +
+ + + + Please write in English if possible.
+
+
: null + } +
+ ); +} + +Report.propTypes = { + report: PropTypes.bool, + reportMessage: PropTypes.string, + onChangeReport: PropTypes.func, + onChangeReportMessage: PropTypes.func +}; + +function Navigation(props) { + const back = ( + + ); + + const next = ( + + ); + + const submit = ( + + ); + + return ( +
+ {(props.tab > 0) ? back : null} + {(props.tab < props.tabs - 1) ? next : null} + {/* */} + {(props.tab === props.tabs - 1) ? submit : null} +
+ + ); +} + +Navigation.propTypes = { + onBack: PropTypes.func, + onNext: PropTypes.func, + onSubmit: PropTypes.func, + tab: PropTypes.number, // current tab index - indexed from 0 + tabs: PropTypes.number, // amount of tabs to display + tabDone: PropTypes.number // which tab is already filled +}; + +export default class ReferencesNew extends React.Component { + + constructor(props) { + super(props); + this.state = { + tab: 0, + reference: { + interactions: { + met: false, + hostedThem: false, + hostedMe: false + }, + recommend: null + }, + report: false, + reportMessage: '' + }; + } + + handleTabSwitch(move) { + this.setState({ + ...this.state, + tab: this.state.tab + move + }); + } + + handleChange(field, ...data) { + if (field === 'interactions') { + const interaction = { }; + interaction[data[0]] = !this.state.reference.interactions[data[0]]; + this.setState({ + ...this.state, + reference: { + ...this.state.reference, + interactions: { + ...this.state.reference.interactions, + ...interaction + } + } + }); + } + + if (field === 'recommend') { + this.setState({ + ...this.state, + reference: { + ...this.state.reference, + recommend: data[0] + } + }); + } + } + + handleChangeReport() { + this.setState({ + ...this.state, + report: !this.state.report + }); + } + + handleChangeReportMessage(reportMessage) { + this.setState({ + ...this.state, + reportMessage + }); + } + + handleSubmit() { + /* do something with the provided data + { + reference: this.state.reference, + report: this.state.report, + reportMessage: this.state.reportMessage + }; + */ + } + + render() { + const tabs = [ + this.handleChange(...data)} />, + this.handleChange(...data)} + report={this.state.report} + reportMessage={this.state.reportMessage} + onChangeReport={() => this.handleChangeReport()} + onChangeReportMessage={(reportMessage) => this.handleChangeReportMessage(reportMessage)} + /> + ]; + + const { interactions: { hostedMe, hostedThem, met }, recommend } = this.state.reference; + + const tabDone = (recommend) ? 1 : + (hostedMe || hostedThem || met) ? 0 : -1; + + return ( +
+ + {tabs[this.state.tab]} + {/* */} + this.handleTabSwitch(-1)} + onNext={() => this.handleTabSwitch(+1)} + onSubmit={() => this.handleSubmit()} + /> +
+ ); + } +} + +ReferencesNew.propTypes = {}; diff --git a/modules/references/client/less/reference-new.less b/modules/references/client/less/reference-new.less new file mode 100644 index 0000000000..0e1b6031fb --- /dev/null +++ b/modules/references/client/less/reference-new.less @@ -0,0 +1,116 @@ +.reference-new-tabs { + .nav-pills { + margin-bottom: @padding-base-horizontal; + margin-right: 1px; + > li { + clear: both; + width: 100%; + opacity: 0.5; + &.active, + &.reference-new-tabs-tab-processed { + opacity: 1; + } + + li { + margin-left: 0; + } + // This is here just so that we can apply `text-decoration:none` to it later + > a:before { + display: none; + } + &.active > a { + color: @brand-primary; + background: transparent; + } + &.disabled > a { + text-decoration: line-through; + color: @gray-light; + &:before { + text-decoration: none; + } + } + > a { + color: @gray; + background: transparent; + font-style: italic; + padding: 3px 6px; + cursor: default; + &:hover { + background: none; + } + } + &.reference-new-tabs-tab-processed > a { + cursor: pointer; + } + } + @media (min-width: @screen-xs-min) { + > li { + clear: none; + width: auto; + margin: 0; + > a { + padding: 0; + &:before { + display: inline-block; + content: '›'; + margin: 0 10px; + color: @gray-light; + } + } + &:first-child a:before { + display: none; + } + } + } + } +} + +.btn-group { + > .btn-reference-recommend { + &, &:hover { + border-color: transparent; + } + span { + border-bottom: 2px solid transparent; + padding: 1px 2px; + margin: 0 5px; + } + } + > .btn-reference-recommend-unknown { + .button-variant(@reference-recommend-unknown-color; @reference-recommend-unknown-bg; @reference-recommend-unknown-bg); + &.active { + span { + border-color: @reference-recommend-unknown-color; + } + } + } + > .btn-reference-recommend-no { + .button-variant(@reference-recommend-no-color; @reference-recommend-no-bg; @reference-recommend-no-bg); + &.active { + span { + border-color: @reference-recommend-no-color; + } + } + } + > .btn-reference-recommend-yes { + .button-variant(@reference-recommend-yes-color; @reference-recommend-yes-bg; @reference-recommend-yes-bg); + &.active { + span { + border-color: @reference-recommend-yes-color; + } + } + } +} + +.reference-new-tabs-alert { + margin-top: @padding-base-horizontal; +} + +.reference-new-endorsement-selector { + button.list-group-item { + width: 50%; + float: left; + &[disabled] { + color: @gray-light; + } + } +} diff --git a/modules/users/client/config/users.client.routes.js b/modules/users/client/config/users.client.routes.js index b88213305b..cdd59089ec 100644 --- a/modules/users/client/config/users.client.routes.js +++ b/modules/users/client/config/users.client.routes.js @@ -235,6 +235,34 @@ pageTitle: 'Profile contacts' } }). + state('profile.references', { + url: '/references', + templateUrl: '/modules/users/views/profile/profile-view-references.client.view.html', + requiresAuth: true, + noScrollingTop: true, + abstract: true, + data: { + pageTitle: 'Profile references' + } + }). + state('profile.references.list', { + url: '', + templateUrl: '/modules/users/views/profile/profile-view-references-list.client.view.html', + requiresAuth: true, + noScrollingTop: true, + data: { + pageTitle: 'Profile references' + } + }). + state('profile.references.new', { + url: '/new', + template: '', + requiresAuth: true, + noScrollingTop: true, + data: { + pageTitle: 'Leave a reference' + } + }). state('profile.tribes', { url: '/tribes', templateUrl: '/modules/users/views/profile/profile-view-tribes.client.view.html', diff --git a/modules/users/client/views/profile/profile-view-references.client.view.html b/modules/users/client/views/profile/profile-view-references.client.view.html new file mode 100644 index 0000000000..740d8f27b3 --- /dev/null +++ b/modules/users/client/views/profile/profile-view-references.client.view.html @@ -0,0 +1,8 @@ +
+
+ +
+ +
+ +
diff --git a/modules/users/client/views/profile/profile-view.client.view.html b/modules/users/client/views/profile/profile-view.client.view.html index 573c10610f..8e8ebe7654 100644 --- a/modules/users/client/views/profile/profile-view.client.view.html +++ b/modules/users/client/views/profile/profile-view.client.view.html @@ -20,6 +20,11 @@ Send a message +
  • + + Write a reference + +
  • @@ -129,13 +134,7 @@

    Don't panic!

  • +
  • + + + Write a reference + +
  • Don't panic!
  • +
  • + + + + + {{profileCtrl.referencesCount || 0}} References + + +