From b9c94aa234fb6198a163ca2e990a3e0b209fbf90 Mon Sep 17 00:00:00 2001
From: Arpit Jalan
Date: Fri, 9 Jun 2017 00:40:43 +0530
Subject: [PATCH] FEATURE: add required user fields to invite accept form UX:
make "accept invitation" page consistent with sign up modal
---
.../controllers/create-account.js.es6 | 34 +++-----------
.../discourse/controllers/invites-show.js.es6 | 27 +++++++-----
.../discourse/mixins/name-validation.js.es6 | 5 +++
.../mixins/user-fields-validation.js.es6 | 35 +++++++++++++++
.../components/user-fields/confirm.hbs | 2 +-
.../discourse/templates/invites/show.hbs | 22 +++++++---
app/assets/stylesheets/common/base/login.scss | 7 +++
app/assets/stylesheets/desktop/login.scss | 9 +++-
app/controllers/invites_controller.rb | 4 +-
app/models/invite.rb | 4 +-
app/models/invite_redeemer.rb | 18 ++++++--
config/locales/client.en.yml | 1 -
spec/models/invite_redeemer_spec.rb | 14 ++++++
.../invite-show-user-fields-test.js.es6 | 44 +++++++++++++++++++
14 files changed, 171 insertions(+), 55 deletions(-)
create mode 100644 app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6
create mode 100644 test/javascripts/acceptance/invite-show-user-fields-test.js.es6
diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6
index 956b9bf35b7..9b3528f32b4 100644
--- a/app/assets/javascripts/discourse/controllers/create-account.js.es6
+++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6
@@ -7,9 +7,10 @@ import InputValidation from 'discourse/models/input-validation';
import PasswordValidation from "discourse/mixins/password-validation";
import UsernameValidation from "discourse/mixins/username-validation";
import NameValidation from "discourse/mixins/name-validation";
+import UserFieldsValidation from "discourse/mixins/user-fields-validation";
import { userPath } from 'discourse/lib/url';
-export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, UsernameValidation, NameValidation, {
+export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, {
login: Ember.inject.controller(),
complete: false,
@@ -50,19 +51,10 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
if (this.get('emailValidation.failed')) return true;
if (this.get('usernameValidation.failed')) return true;
if (this.get('passwordValidation.failed')) return true;
+ if (this.get('userFieldsValidation.failed')) return true;
- // Validate required fields
- let userFields = this.get('userFields');
- if (userFields) { userFields = userFields.filterBy('field.required'); }
- if (!Ember.isEmpty(userFields)) {
- const anyEmpty = userFields.any(function(uf) {
- const val = uf.get('value');
- return !val || Ember.isEmpty(val);
- });
- if (anyEmpty) { return true; }
- }
return false;
- }.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted', 'userFields.@each.value'),
+ }.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'userFieldsValidation.failed', 'formSubmitted'),
usernameRequired: Ember.computed.not('authOptions.omit_username'),
@@ -82,10 +74,6 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
});
}.property(),
- nameInstructions: function() {
- return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
- }.property(),
-
// Check the email address
emailValidation: function() {
// If blank, fail without a reason
@@ -212,18 +200,6 @@ export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, U
return self.flash(I18n.t('create_account.failed'), 'error');
});
}
- },
-
- _createUserFields: function() {
- if (!this.site) { return; }
-
- let userFields = this.site.get('user_fields');
- if (userFields) {
- userFields = _.sortBy(userFields, 'position').map(function(f) {
- return Ember.Object.create({ value: null, field: f });
- });
- }
- this.set('userFields', userFields);
- }.on('init')
+ }
});
diff --git a/app/assets/javascripts/discourse/controllers/invites-show.js.es6 b/app/assets/javascripts/discourse/controllers/invites-show.js.es6
index d032c769852..20e533ec0c5 100644
--- a/app/assets/javascripts/discourse/controllers/invites-show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/invites-show.js.es6
@@ -5,15 +5,17 @@ import { ajax } from 'discourse/lib/ajax';
import PasswordValidation from "discourse/mixins/password-validation";
import UsernameValidation from "discourse/mixins/username-validation";
import NameValidation from "discourse/mixins/name-validation";
+import UserFieldsValidation from "discourse/mixins/user-fields-validation";
import { findAll as findLoginMethods } from 'discourse/models/login-method';
-export default Ember.Controller.extend(PasswordValidation, UsernameValidation, NameValidation, {
+export default Ember.Controller.extend(PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, {
invitedBy: Ember.computed.alias('model.invited_by'),
email: Ember.computed.alias('model.email'),
accountUsername: Ember.computed.alias('model.username'),
passwordRequired: Ember.computed.notEmpty('accountPassword'),
successMessage: null,
errorMessage: null,
+ userFields: null,
inviteImageUrl: getUrl('/images/envelope.svg'),
@computed
@@ -21,11 +23,6 @@ export default Ember.Controller.extend(PasswordValidation, UsernameValidation, N
return I18n.t('invites.welcome_to', {site_name: this.siteSettings.title});
},
- @computed
- nameLabel() {
- return I18n.t(this.siteSettings.full_name_required ? 'invites.name_label' : 'invites.name_label_optional');
- },
-
@computed('email')
yourEmailMessage(email) {
return I18n.t('invites.your_email', {email: email});
@@ -36,20 +33,30 @@ export default Ember.Controller.extend(PasswordValidation, UsernameValidation, N
return findLoginMethods(this.siteSettings, this.capabilities, this.site.isMobileDevice).length > 0;
},
- @computed('usernameValidation.failed', 'passwordValidation.failed', 'nameValidation.failed')
- submitDisabled(usernameFailed, passwordFailed, nameFailed) {
- return usernameFailed || passwordFailed || nameFailed;
+ @computed('usernameValidation.failed', 'passwordValidation.failed', 'nameValidation.failed', 'userFieldsValidation.failed')
+ submitDisabled(usernameFailed, passwordFailed, nameFailed, userFieldsFailed) {
+ return usernameFailed || passwordFailed || nameFailed || userFieldsFailed;
},
actions: {
submit() {
+
+ const userFields = this.get('userFields');
+ let userCustomFields = {};
+ if (!Ember.isEmpty(userFields)) {
+ userFields.forEach(function(f) {
+ userCustomFields[f.get('field.id')] = f.get('value');
+ });
+ }
+
ajax({
url: `/invites/show/${this.get('model.token')}.json`,
type: 'PUT',
data: {
username: this.get('accountUsername'),
name: this.get('accountName'),
- password: this.get('accountPassword')
+ password: this.get('accountPassword'),
+ userCustomFields
}
}).then(result => {
if (result.success) {
diff --git a/app/assets/javascripts/discourse/mixins/name-validation.js.es6 b/app/assets/javascripts/discourse/mixins/name-validation.js.es6
index 8a286522dff..b225533c36d 100644
--- a/app/assets/javascripts/discourse/mixins/name-validation.js.es6
+++ b/app/assets/javascripts/discourse/mixins/name-validation.js.es6
@@ -3,6 +3,11 @@ import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Mixin.create({
+ @computed()
+ nameInstructions() {
+ return I18n.t(this.siteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
+ },
+
// Validate the name.
@computed('accountName')
nameValidation() {
diff --git a/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6 b/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6
new file mode 100644
index 00000000000..6c3f8ca3c69
--- /dev/null
+++ b/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6
@@ -0,0 +1,35 @@
+import InputValidation from 'discourse/models/input-validation';
+import { on, default as computed } from 'ember-addons/ember-computed-decorators';
+
+export default Ember.Mixin.create({
+
+ @on('init')
+ _createUserFields() {
+ if (!this.site) { return; }
+
+ let userFields = this.site.get('user_fields');
+ if (userFields) {
+ userFields = _.sortBy(userFields, 'position').map(function(f) {
+ return Ember.Object.create({ value: null, field: f });
+ });
+ }
+ this.set('userFields', userFields);
+ },
+
+ // Validate required fields
+ @computed('userFields.@each.value')
+ userFieldsValidation() {
+ let userFields = this.get('userFields');
+ if (userFields) { userFields = userFields.filterBy('field.required'); }
+ if (!Ember.isEmpty(userFields)) {
+ const anyEmpty = userFields.any(uf => {
+ const val = uf.get('value');
+ return !val || Ember.isEmpty(val);
+ });
+ if (anyEmpty) {
+ return InputValidation.create({ failed: true });
+ }
+ }
+ return InputValidation.create({ ok: true });
+ }
+});
diff --git a/app/assets/javascripts/discourse/templates/components/user-fields/confirm.hbs b/app/assets/javascripts/discourse/templates/components/user-fields/confirm.hbs
index 5db0b43bb53..ad7f851e2c7 100644
--- a/app/assets/javascripts/discourse/templates/components/user-fields/confirm.hbs
+++ b/app/assets/javascripts/discourse/templates/components/user-fields/confirm.hbs
@@ -1,3 +1,3 @@
-
+
diff --git a/app/assets/javascripts/discourse/templates/invites/show.hbs b/app/assets/javascripts/discourse/templates/invites/show.hbs
index 5822156abd8..80eb832a63a 100644
--- a/app/assets/javascripts/discourse/templates/invites/show.hbs
+++ b/app/assets/javascripts/discourse/templates/invites/show.hbs
@@ -23,26 +23,36 @@