UX: don't disable "create account" button & display error message for required fields. (#9643)

UX: don’t disable “create account” button & display error message for required fields. (#9643)

diff --git a/app/assets/javascripts/discourse/app/components/user-field.js b/app/assets/javascripts/discourse/app/components/user-field.js
index f8e2554..386b869 100644
--- a/app/assets/javascripts/discourse/app/components/user-field.js
+++ b/app/assets/javascripts/discourse/app/components/user-field.js
@@ -6,6 +6,16 @@ export default Component.extend({
   classNameBindings: [":user-field", "field.field_type", "customFieldClass"],
   layoutName: fmt("field.field_type", "components/user-fields/%@"),
 
+  didInsertElement() {
+    this._super(...arguments);
+
+    let element = this.element.querySelector(
+      ".user-field.dropdown .select-kit-header"
+    );
+    element = element || this.element.querySelector("input");
+    this.field.element = element;
+  },
+
   @discourseComputed
   noneLabel() {
     return "user_fields.none";
diff --git a/app/assets/javascripts/discourse/app/controllers/create-account.js b/app/assets/javascripts/discourse/app/controllers/create-account.js
index 1593ff9..75ec7b2 100644
--- a/app/assets/javascripts/discourse/app/controllers/create-account.js
+++ b/app/assets/javascripts/discourse/app/controllers/create-account.js
@@ -61,27 +61,9 @@ export default Controller.extend(
       this._createUserFields();
     },
 
-    @discourseComputed(
-      "passwordRequired",
-      "nameValidation.failed",
-      "emailValidation.failed",
-      "usernameValidation.failed",
-      "passwordValidation.failed",
-      "userFieldsValidation.failed",
-      "formSubmitted",
-      "inviteCode"
-    )
+    @discourseComputed("formSubmitted")
     submitDisabled() {
       if (this.formSubmitted) return true;
-      if (this.get("nameValidation.failed")) return true;
-      if (this.get("emailValidation.failed")) return true;
-      if (this.get("usernameValidation.failed") && this.usernameRequired)
-        return true;
-      if (this.get("passwordValidation.failed") && this.passwordRequired)
-        return true;
-      if (this.get("userFieldsValidation.failed")) return true;
-
-      if (this.requireInviteCode && !this.inviteCode) return true;
 
       return false;
     },
@@ -114,18 +96,26 @@ export default Controller.extend(
     // Check the email address
     @discourseComputed("accountEmail", "rejectedEmails.[]")
     emailValidation(email, rejectedEmails) {
+      const failedAttrs = {
+        failed: true,
+        element: document.querySelector("#new-account-email")
+      };
+
       // If blank, fail without a reason
       if (isEmpty(email)) {
-        return EmberObject.create({
-          failed: true
-        });
+        return EmberObject.create(
+          Object.assign(failedAttrs, {
+            message: I18n.t("user.email.required")
+          })
+        );
       }
 
       if (rejectedEmails.includes(email)) {
-        return EmberObject.create({
-          failed: true,
-          reason: I18n.t("user.email.invalid")
-        });
+        return EmberObject.create(
+          Object.assign(failedAttrs, {
+            reason: I18n.t("user.email.invalid")
+          })
+        );
       }
 
       if (
@@ -149,10 +139,11 @@ export default Controller.extend(
         });
       }
 
-      return EmberObject.create({
-        failed: true,
-        reason: I18n.t("user.email.invalid")
-      });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          reason: I18n.t("user.email.invalid")
+        })
+      );
     },
 
     @discourseComputed(
@@ -312,6 +303,34 @@ export default Controller.extend(
       },
 
       createAccount() {
+        this.clearFlash();
+
+        const validation = [
+          this.emailValidation,
+          this.usernameValidation,
+          this.nameValidation,
+          this.passwordValidation,
+          this.userFieldsValidation
+        ].find(v => v.failed);
+
+        if (validation) {
+          if (validation.message) {
+            this.flash(validation.message, "error");
+          }
+
+          const element = validation.element;
+          if (element.tagName === "DIV") {
+            if (element.scrollIntoView) {
+              element.scrollIntoView();
+            }
+            element.click();
+          } else {
+            element.focus();
+          }
+
+          return;
+        }
+
         if (new Date() - this._challengeDate > 1000 * this._challengeExpiry) {
           this.fetchConfirmationValue().then(() =>
             this.performAccountCreation()
diff --git a/app/assets/javascripts/discourse/app/mixins/name-validation.js b/app/assets/javascripts/discourse/app/mixins/name-validation.js
index a36ea6a..a2e024b 100644
--- a/app/assets/javascripts/discourse/app/mixins/name-validation.js
+++ b/app/assets/javascripts/discourse/app/mixins/name-validation.js
@@ -18,7 +18,11 @@ export default Mixin.create({
   @discourseComputed("accountName")
   nameValidation() {
     if (this.siteSettings.full_name_required && isEmpty(this.accountName)) {
-      return EmberObject.create({ failed: true });
+      return EmberObject.create({
+        failed: true,
+        message: I18n.t("user.name.required"),
+        element: document.querySelector("#new-account-name")
+      });
     }
 
     return EmberObject.create({ ok: true });
diff --git a/app/assets/javascripts/discourse/app/mixins/password-validation.js b/app/assets/javascripts/discourse/app/mixins/password-validation.js
index 355e9bf..0348362 100644
--- a/app/assets/javascripts/discourse/app/mixins/password-validation.js
+++ b/app/assets/javascripts/discourse/app/mixins/password-validation.js
@@ -43,44 +43,57 @@ export default Mixin.create({
     accountEmail,
     passwordMinLength
   ) {
+    const failedAttrs = {
+      failed: true,
+      element: document.querySelector("#new-account-password")
+    };
+
     if (!passwordRequired) {
       return EmberObject.create({ ok: true });
     }
 
     if (rejectedPasswords.includes(password)) {
-      return EmberObject.create({
-        failed: true,
-        reason:
-          this.rejectedPasswordsMessages.get(password) ||
-          I18n.t("user.password.common")
-      });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          reason:
+            this.rejectedPasswordsMessages.get(password) ||
+            I18n.t("user.password.common")
+        })
+      );
     }
 
     // If blank, fail without a reason
     if (isEmpty(password)) {
-      return EmberObject.create({ failed: true });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          message: I18n.t("user.password.required")
+        })
+      );
     }
 
     // If too short
     if (password.length < passwordMinLength) {
-      return EmberObject.create({
-        failed: true,
-        reason: I18n.t("user.password.too_short")
-      });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          reason: I18n.t("user.password.too_short")
+        })
+      );
     }
 
     if (!isEmpty(accountUsername) && password === accountUsername) {
-      return EmberObject.create({
-        failed: true,
-        reason: I18n.t("user.password.same_as_username")
-      });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          reason: I18n.t("user.password.same_as_username")
+        })
+      );
     }
 
     if (!isEmpty(accountEmail) && password === accountEmail) {
-      return EmberObject.create({
-        failed: true,
-        reason: I18n.t("user.password.same_as_email")
-      });
+      return EmberObject.create(
+        Object.assign(failedAttrs, {
+          reason: I18n.t("user.password.same_as_email")
+        })
+      );
     }
 
     // Looks good!
diff --git a/app/assets/javascripts/discourse/app/mixins/user-fields-validation.js b/app/assets/javascripts/discourse/app/mixins/user-fields-validation.js
index 5a7ff18..520fb8a 100644
--- a/app/assets/javascripts/discourse/app/mixins/user-fields-validation.js

[... diff too long, it was truncated ...]

GitHub sha: c014b938

1 Like

This commit appears in #9643 which was approved by jjaffeux. It was merged by vinothkannans.