DEV: Add a callback to the validation of user custom fields in the signup form (#27369)
# Description Add `addCustomUserFieldValidationCallback` to the user fields validation mixin. This allows you to add a custom validation when checking the validity of custom user field values in the signup form on submit. ```js addCustomUserFieldValidationCallback((userField) => { if (userField.field.name === "my custom user field" && userField.value === "foo") { return EmberObject.create({ failed: true, reason: I18n.t("value_can_not_be_foo"), element: userField.field.element, }); } }); ``` In the case your custom validation deems an input value `failed`, you return an EmberObject with the fields `failed: true`, `reason`, and `element`. ```js return EmberObject.create({ failed: true, reason: I18n.t("value_can_not_be_foo"), element: userField.field.element, }); ``` which will then display your custom `reason` to the user attached to the given user custom field input and will not submit the signup form. <img width="288" alt="Screenshot 2024-06-06 at 11 08 40 AM" src="https://github.com/discourse/discourse/assets/50783505/11168fb8-8806-43f0-9417-73991bbd1178"> # Other - Add `addCustomUserFieldValidationCallback` to the plugin api - Bump plugin api version - Update plugin api changelog - Add tests
This commit is contained in:
parent
dbd16776fa
commit
69193c4bd5
|
@ -96,6 +96,7 @@ import { includeAttributes } from "discourse/lib/transform-post";
|
|||
import { registerUserMenuTab } from "discourse/lib/user-menu/tab";
|
||||
import { replaceFormatter } from "discourse/lib/utilities";
|
||||
import { addCardClickListenerSelector } from "discourse/mixins/card-contents-base";
|
||||
import { addCustomUserFieldValidationCallback } from "discourse/mixins/user-fields-validation";
|
||||
import Composer, {
|
||||
registerCustomizationCallback,
|
||||
} from "discourse/models/composer";
|
||||
|
@ -152,7 +153,7 @@ import { modifySelectKit } from "select-kit/mixins/plugin-api";
|
|||
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
||||
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
||||
|
||||
export const PLUGIN_API_VERSION = "1.32.0";
|
||||
export const PLUGIN_API_VERSION = "1.33.0";
|
||||
|
||||
const DEPRECATED_HEADER_WIDGETS = [
|
||||
"header",
|
||||
|
@ -1288,6 +1289,33 @@ class PluginApi {
|
|||
addTopicParticipantClassesCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback when validating the value of a custom user field in the signup form.
|
||||
*
|
||||
* If the validation is intended to fail, the callback should return an Ember Object with the
|
||||
* following properties: `failed`, `reason`, and `element`.
|
||||
*
|
||||
* In the case of a failed validation, the `reason` will be displayed to the user
|
||||
* and the form will not be submitted.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* addCustomUserFieldValidationCallback((userField) => {
|
||||
* if (userField.field.name === "my custom user field" && userField.value === "foo") {
|
||||
* return EmberObject.create({
|
||||
* failed: true,
|
||||
* reason: I18n.t("value_can_not_be_foo"),
|
||||
* element: userField.field.element,
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
**/
|
||||
|
||||
addCustomUserFieldValidationCallback(callback) {
|
||||
addCustomUserFieldValidationCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Adds a callback to be executed on the "transformed" post that is passed to the post
|
||||
|
|
|
@ -4,6 +4,11 @@ import { isEmpty } from "@ember/utils";
|
|||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const addCustomUserFieldValidationCallbacks = [];
|
||||
export function addCustomUserFieldValidationCallback(callback) {
|
||||
addCustomUserFieldValidationCallbacks.push(callback);
|
||||
}
|
||||
|
||||
export default Mixin.create({
|
||||
@on("init")
|
||||
_createUserFields() {
|
||||
|
@ -55,6 +60,13 @@ export default Mixin.create({
|
|||
});
|
||||
}
|
||||
|
||||
addCustomUserFieldValidationCallbacks.map((callback) => {
|
||||
const customUserFieldValidationObject = callback(userField);
|
||||
if (customUserFieldValidationObject) {
|
||||
validation = customUserFieldValidationObject;
|
||||
}
|
||||
});
|
||||
|
||||
userField.set("validation", validation);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,9 +1,27 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const CUSTOM_VALIDATION_REASON = "bad choice";
|
||||
|
||||
acceptance("Create Account - User Fields", function (needs) {
|
||||
needs.hooks.beforeEach(function () {
|
||||
withPluginApi("1.33.0", (api) => {
|
||||
api.addCustomUserFieldValidationCallback((userField) => {
|
||||
if (userField.field.id === 37 && userField.value !== "red") {
|
||||
return EmberObject.create({
|
||||
failed: true,
|
||||
reason: CUSTOM_VALIDATION_REASON,
|
||||
element: userField.field.element,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
needs.site({
|
||||
user_fields: [
|
||||
{
|
||||
|
@ -24,6 +42,12 @@ acceptance("Create Account - User Fields", function (needs) {
|
|||
field_type: "text",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
id: 37,
|
||||
name: "What is your favorite color?",
|
||||
field_type: "text",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -84,4 +108,46 @@ acceptance("Create Account - User Fields", function (needs) {
|
|||
.dom(".user-field-whats-your-dad-like .tip.bad")
|
||||
.exists("shows same as password error");
|
||||
});
|
||||
|
||||
test("allows for custom validations of user fields", async function (assert) {
|
||||
await visit("/");
|
||||
await click("header .sign-up-button");
|
||||
|
||||
await fillIn(".user-field-what-is-your-favorite-color input", "blue");
|
||||
|
||||
assert
|
||||
.dom(".user-field-what-is-your-favorite-color .tip.bad")
|
||||
.doesNotExist(
|
||||
"it does not show error message until the form is submitted"
|
||||
);
|
||||
|
||||
await click(".d-modal__footer .btn-primary");
|
||||
|
||||
assert
|
||||
.dom(".user-field-what-is-your-favorite-color .tip.bad")
|
||||
.hasText(CUSTOM_VALIDATION_REASON, "shows custom error message");
|
||||
});
|
||||
|
||||
test("it does not submit the form when custom validation fails", async function (assert) {
|
||||
await visit("/");
|
||||
await click("header .sign-up-button");
|
||||
|
||||
// incorrect value for custom validation
|
||||
await fillIn(".user-field-what-is-your-favorite-color input", "blue");
|
||||
|
||||
await fillIn("#new-account-name", "Dr. Good Tuna");
|
||||
await fillIn("#new-account-password", "cool password bro");
|
||||
await fillIn("#new-account-email", "good.tuna@test.com");
|
||||
await fillIn("#new-account-username", "goodtuna");
|
||||
await fillIn(".user-field input[type=text]:nth-of-type(1)", "Barky");
|
||||
await click(".user-field input[type=checkbox]");
|
||||
|
||||
await click(".d-modal__footer .btn-primary");
|
||||
assert
|
||||
.dom(".user-field-what-is-your-favorite-color .tip.bad")
|
||||
.hasText(
|
||||
CUSTOM_VALIDATION_REASON,
|
||||
"shows custom error message, and the form is not submitted"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,10 @@ in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.33.0] - 2024-06-06
|
||||
|
||||
- Added `addCustomUserFieldValidationCallback` which allows to set a callback to change the validation and user facing message when attempting to save the signup form.
|
||||
|
||||
## [1.32.0] - 2024-05-16
|
||||
|
||||
- Added `registerHomeLogoHrefCallback` which allows to set a callback to change the home logo URL.
|
||||
|
|
Loading…
Reference in New Issue