compose: Replace empty message banner with red outline for compose box.

Previously, we showed an empty message banner if the user tried
to send an empty message. We only showed it for users with
"ctrl+enter to send" because we thought it might be easy for a
user to press just enter accidentally.

However, this missed the case where the user clicks on the Enter
button. We want to show the user something in this case to tell
them that they're missing message content.

To avoid more complicated logic, this PR removes the banner
completely and changes the compose box border to red if the
user tries to send an empty message (for all cases).

The red line goes away as soon as the composebox has non-whitespace
characters.
This commit is contained in:
evykassirer 2023-01-03 00:35:18 -08:00 committed by Tim Abbott
parent 631ca13428
commit 541d3ffa06
7 changed files with 28 additions and 22 deletions

View File

@ -287,6 +287,7 @@ test_ui("send_message", ({override, override_rewire, mock_template}) => {
test_ui("enter_with_preview_open", ({override, override_rewire}) => { test_ui("enter_with_preview_open", ({override, override_rewire}) => {
mock_banners(); mock_banners();
$("#compose-textarea").toggleClass = noop;
override_rewire(compose_banner, "clear_message_sent_banners", () => {}); override_rewire(compose_banner, "clear_message_sent_banners", () => {});
override(reminder, "is_deferred_delivery", () => false); override(reminder, "is_deferred_delivery", () => false);
override(document, "to_$", () => $("document-stub")); override(document, "to_$", () => $("document-stub"));
@ -333,7 +334,7 @@ test_ui("enter_with_preview_open", ({override, override_rewire}) => {
compose.enter_with_preview_open(); compose.enter_with_preview_open();
}); });
test_ui("finish", ({override, override_rewire, mock_template}) => { test_ui("finish", ({override, override_rewire}) => {
mock_banners(); mock_banners();
override_rewire(compose_banner, "clear_message_sent_banners", () => {}); override_rewire(compose_banner, "clear_message_sent_banners", () => {});
override(reminder, "is_deferred_delivery", () => false); override(reminder, "is_deferred_delivery", () => false);
@ -345,10 +346,10 @@ test_ui("finish", ({override, override_rewire, mock_template}) => {
}); });
(function test_when_compose_validation_fails() { (function test_when_compose_validation_fails() {
mock_template("compose_banner/compose_banner.hbs", false, (data) => { $("#compose-textarea").toggleClass = (classname, value) => {
assert.equal(data.classname, "empty_message"); assert.equal(classname, "invalid");
assert.equal(data.banner_text, $t({defaultMessage: "You have nothing to send!"})); assert.equal(value, true);
}); };
$("#compose_invite_users").show(); $("#compose_invite_users").show();
$("#compose-send-button").prop("disabled", false); $("#compose-send-button").prop("disabled", false);
$("#compose-send-button").trigger("focus"); $("#compose-send-button").trigger("focus");

View File

@ -214,7 +214,6 @@ test_ui("validate", ({override, mock_template}) => {
assert.ok(compose_validate.validate()); assert.ok(compose_validate.validate());
let zephyr_error_rendered = false; let zephyr_error_rendered = false;
let empty_message_error_rendered = false;
mock_template("compose_banner/compose_banner.hbs", false, (data) => { mock_template("compose_banner/compose_banner.hbs", false, (data) => {
if (data.classname === compose_banner.CLASSNAMES.zephyr_not_running) { if (data.classname === compose_banner.CLASSNAMES.zephyr_not_running) {
assert.equal( assert.equal(
@ -225,17 +224,17 @@ test_ui("validate", ({override, mock_template}) => {
}), }),
); );
zephyr_error_rendered = true; zephyr_error_rendered = true;
} else if (data.classname === compose_banner.CLASSNAMES.empty_message) {
assert.equal(data.banner_text, $t({defaultMessage: "You have nothing to send!"}));
empty_message_error_rendered = true;
} }
}); });
initialize_pm_pill(); initialize_pm_pill();
compose_state.private_message_recipient("welcome-bot@example.com"); compose_state.private_message_recipient("welcome-bot@example.com");
$("#compose-textarea").toggleClass = (classname, value) => {
assert.equal(classname, "invalid");
assert.equal(value, true);
};
assert.ok(!compose_validate.validate()); assert.ok(!compose_validate.validate());
assert.ok(!$("#compose-send-button .loader").visible()); assert.ok(!$("#compose-send-button .loader").visible());
assert.equal($("#compose-send-button").prop("disabled"), false); assert.equal($("#compose-send-button").prop("disabled"), false);
assert.ok(empty_message_error_rendered);
compose_validate.validate(); compose_validate.validate();
add_content_to_compose_box(); add_content_to_compose_box();

View File

@ -445,6 +445,9 @@ export function initialize() {
$("#compose-textarea").on("input propertychange", () => { $("#compose-textarea").on("input propertychange", () => {
compose_validate.warn_if_topic_resolved(false); compose_validate.warn_if_topic_resolved(false);
const compose_text_length = compose_validate.check_overflow_text(); const compose_text_length = compose_validate.check_overflow_text();
if (compose_text_length !== 0 && $("#compose-textarea").hasClass("invalid")) {
$("#compose-textarea").toggleClass("invalid", false);
}
// Change compose close button tooltip as per condition. // Change compose close button tooltip as per condition.
// We save compose text in draft only if its length is > 2. // We save compose text in draft only if its length is > 2.
if (compose_text_length > 2) { if (compose_text_length > 2) {

View File

@ -25,7 +25,6 @@ export const CLASSNAMES = {
wildcard_warning: "wildcard_warning", wildcard_warning: "wildcard_warning",
private_stream_warning: "private_stream_warning", private_stream_warning: "private_stream_warning",
// errors // errors
empty_message: "empty_message",
wildcards_not_allowed: "wildcards_not_allowed", wildcards_not_allowed: "wildcards_not_allowed",
subscription_error: "subscription_error", subscription_error: "subscription_error",
stream_does_not_exist: "stream_does_not_exist", stream_does_not_exist: "stream_does_not_exist",

View File

@ -18,7 +18,6 @@ import * as people from "./people";
import * as settings_config from "./settings_config"; import * as settings_config from "./settings_config";
import * as settings_data from "./settings_data"; import * as settings_data from "./settings_data";
import * as stream_data from "./stream_data"; import * as stream_data from "./stream_data";
import {user_settings} from "./user_settings";
import * as util from "./util"; import * as util from "./util";
let user_acknowledged_wildcard = false; let user_acknowledged_wildcard = false;
@ -611,18 +610,9 @@ export function warn_for_text_overflow_when_tries_to_send() {
export function validate() { export function validate() {
const message_content = compose_state.message_content(); const message_content = compose_state.message_content();
if (/^\s*$/.test(message_content)) { if (/^\s*$/.test(message_content)) {
// Avoid showing an error message when "enter sends" is enabled, $("#compose-textarea").toggleClass("invalid", true);
// as it is more likely that the user has hit "Enter" accidentally.
if (!user_settings.enter_sends) {
compose_banner.show_error_message(
$t({defaultMessage: "You have nothing to send!"}),
compose_banner.CLASSNAMES.empty_message,
$("#compose-textarea"),
);
}
return false; return false;
} }
$(`#compose_banners .${compose_banner.CLASSNAMES.empty_message}`).remove();
if ($("#zephyr-mirror-error").is(":visible")) { if ($("#zephyr-mirror-error").is(":visible")) {
compose_banner.show_error_message( compose_banner.show_error_message(

View File

@ -487,6 +487,12 @@ textarea.new_message_textarea {
cursor: not-allowed; cursor: not-allowed;
background-color: hsl(0, 0%, 93%); background-color: hsl(0, 0%, 93%);
} }
&.invalid,
&.invalid:focus {
border: 1px solid hsl(3, 57%, 33%);
box-shadow: 0 0 2px hsl(3, 57%, 33%);
}
} }
textarea.new_message_textarea, textarea.new_message_textarea,

View File

@ -288,6 +288,14 @@
} }
} }
textarea.new_message_textarea {
&.invalid,
&.invalid:focus {
border-color: hsl(3, 73%, 74%);
box-shadow: 0 0 2px hsl(3, 73%, 74%);
}
}
.message_embed .data-container::after { .message_embed .data-container::after {
background: linear-gradient(0deg, hsl(212, 28%, 18%), transparent 100%); background: linear-gradient(0deg, hsl(212, 28%, 18%), transparent 100%);
} }