mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 03:10:46 -06:00
UX: Use icons as bulleted list in invite modal (#13229)
This commit is contained in:
parent
d2135b23c4
commit
447d8dfc44
@ -1,11 +1,11 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { empty, notEmpty } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import { getNativeContact } from "discourse/lib/pwa-utils";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { getNativeContact } from "discourse/lib/pwa-utils";
|
||||
import Group from "discourse/models/group";
|
||||
import Invite from "discourse/models/invite";
|
||||
import I18n from "I18n";
|
||||
@ -24,7 +24,8 @@ export default Controller.extend(
|
||||
limitToEmail: false,
|
||||
autogenerated: false,
|
||||
|
||||
type: "link",
|
||||
isLink: empty("buffered.email"),
|
||||
isEmail: notEmpty("buffered.email"),
|
||||
|
||||
onShow() {
|
||||
Group.findAll().then((groups) => {
|
||||
@ -52,10 +53,7 @@ export default Controller.extend(
|
||||
},
|
||||
|
||||
setInvite(invite) {
|
||||
this.setProperties({
|
||||
invite,
|
||||
type: invite.email ? "email" : "link",
|
||||
});
|
||||
this.set("invite", invite);
|
||||
},
|
||||
|
||||
setAutogenerated(value) {
|
||||
@ -70,7 +68,7 @@ export default Controller.extend(
|
||||
const data = { ...this.buffered.buffer };
|
||||
|
||||
if (data.groupIds !== undefined) {
|
||||
data.group_ids = data.groupIds;
|
||||
data.group_ids = data.groupIds.length > 0 ? data.groupIds : "";
|
||||
delete data.groupIds;
|
||||
}
|
||||
|
||||
@ -80,13 +78,12 @@ export default Controller.extend(
|
||||
delete data.topicTitle;
|
||||
}
|
||||
|
||||
if (this.type === "link") {
|
||||
if (this.buffered.get("email")) {
|
||||
data.email = "";
|
||||
data.custom_message = "";
|
||||
if (this.isLink) {
|
||||
if (this.invite.email) {
|
||||
data.email = data.custom_message = "";
|
||||
}
|
||||
} else if (this.type === "email") {
|
||||
if (this.buffered.get("max_redemptions_allowed") > 1) {
|
||||
} else if (this.isEmail) {
|
||||
if (this.invite.max_redemptions_allowed > 1) {
|
||||
data.max_redemptions_allowed = 1;
|
||||
}
|
||||
|
||||
@ -106,7 +103,7 @@ export default Controller.extend(
|
||||
this.rollbackBuffer();
|
||||
this.setAutogenerated(opts.autogenerated);
|
||||
if (!this.autogenerated) {
|
||||
if (this.type === "email" && opts.sendEmail) {
|
||||
if (this.isEmail && opts.sendEmail) {
|
||||
this.send("closeModal");
|
||||
} else {
|
||||
this.appEvents.trigger("modal-body:flash", {
|
||||
@ -126,9 +123,6 @@ export default Controller.extend(
|
||||
);
|
||||
},
|
||||
|
||||
isLink: equal("type", "link"),
|
||||
isEmail: equal("type", "email"),
|
||||
|
||||
@discourseComputed(
|
||||
"currentUser.staff",
|
||||
"siteSettings.invite_link_max_redemptions_limit",
|
||||
@ -156,46 +150,16 @@ export default Controller.extend(
|
||||
return staff || groups.any((g) => g.owner);
|
||||
},
|
||||
|
||||
@discourseComputed("type", "buffered.email")
|
||||
disabled(type, email) {
|
||||
if (type === "email") {
|
||||
return !email;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
@discourseComputed("buffered.hasBufferedChanges", "invite.email", "type")
|
||||
changed(hasBufferedChanges, inviteEmail, type) {
|
||||
return hasBufferedChanges || (inviteEmail ? "email" : "link") !== type;
|
||||
},
|
||||
|
||||
@discourseComputed("currentUser.staff", "type")
|
||||
hasAdvanced(staff, type) {
|
||||
return staff || type === "email";
|
||||
@discourseComputed("currentUser.staff", "isEmail", "canInviteToGroup")
|
||||
hasAdvanced(staff, isEmail, canInviteToGroup) {
|
||||
return staff || isEmail || canInviteToGroup;
|
||||
},
|
||||
|
||||
@action
|
||||
copied() {
|
||||
if (this.type === "email" && !this.buffered.get("email")) {
|
||||
return this.appEvents.trigger("modal-body:flash", {
|
||||
text: I18n.t("user.invited.invite.blank_email"),
|
||||
messageClass: "error",
|
||||
});
|
||||
}
|
||||
|
||||
this.save({ sendEmail: false, copy: true });
|
||||
},
|
||||
|
||||
@action
|
||||
toggleLimitToEmail() {
|
||||
const limitToEmail = !this.limitToEmail;
|
||||
this.setProperties({
|
||||
limitToEmail,
|
||||
type: limitToEmail ? "email" : "link",
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
saveInvite(sendEmail) {
|
||||
this.appEvents.trigger("modal-body:clearFlash");
|
||||
|
@ -1,4 +1,6 @@
|
||||
<label for="choose-topic-title">{{i18n labelText}}</label>
|
||||
<label for="choose-topic-title">
|
||||
{{#if labelIcon}}{{d-icon labelIcon}}{{/if}}{{i18n labelText}}
|
||||
</label>
|
||||
|
||||
{{text-field value=topicTitle placeholderKey="choose_topic.title.placeholder" id="choose-topic-title"}}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
<div class="future-date-input">
|
||||
<div class="control-group">
|
||||
<label class={{labelClasses}}>{{displayLabel}}</label>
|
||||
<label class={{labelClasses}}>
|
||||
{{#if displayLabelIcon}}{{d-icon displayLabelIcon}}{{/if}}{{displayLabel}}
|
||||
</label>
|
||||
{{future-date-input-selector
|
||||
minimumResultsForSearch=-1
|
||||
statusType=statusType
|
||||
|
@ -13,33 +13,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{{expiresAtLabel}}</p>
|
||||
<div class="input-group input-expires-at">
|
||||
<label>{{d-icon "far-clock"}}{{expiresAtLabel}}</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group invite-type">
|
||||
{{input type="checkbox" id="invite-type" checked=limitToEmail click=(action "toggleLimitToEmail")}}
|
||||
<label for="invite-type">{{i18n "user.invited.invite.restrict_email"}}</label>
|
||||
|
||||
{{#if isEmail}}
|
||||
<div class="invite-input-with-button">
|
||||
{{input
|
||||
id="invite-email"
|
||||
value=buffered.email
|
||||
placeholderKey="topic.invite_reply.email_placeholder"
|
||||
<div class="input-group input-email">
|
||||
<label for="invite-email">{{d-icon "envelope"}}{{i18n "user.invited.invite.restrict_email"}}</label>
|
||||
<div class="invite-input-with-button">
|
||||
{{input
|
||||
id="invite-email"
|
||||
value=buffered.email
|
||||
placeholderKey="topic.invite_reply.email_placeholder"
|
||||
}}
|
||||
{{#if capabilities.hasContactPicker}}
|
||||
{{d-button
|
||||
icon="address-book"
|
||||
action=(action "searchContact")
|
||||
class="btn-primary open-contact-picker"
|
||||
}}
|
||||
{{#if capabilities.hasContactPicker}}
|
||||
{{d-button
|
||||
icon="address-book"
|
||||
action=(action "searchContact")
|
||||
class="btn-primary open-contact-picker"
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if isLink}}
|
||||
<div class="input-group invite-max-redemptions">
|
||||
<label for="invite-max-redemptions">{{i18n "user.invited.invite.max_redemptions_allowed"}}</label>
|
||||
<label for="invite-max-redemptions">{{d-icon "users"}}{{i18n "user.invited.invite.max_redemptions_allowed"}}</label>
|
||||
{{input
|
||||
id="invite-max-redemptions"
|
||||
type="number"
|
||||
@ -50,10 +48,10 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if isEmail}}
|
||||
{{#if showAdvanced}}
|
||||
{{#if showAdvanced}}
|
||||
{{#if isEmail}}
|
||||
<div class="input-group invite-custom-message">
|
||||
<label for="invite-message">{{i18n "user.invited.invite.custom_message"}}</label>
|
||||
<label for="invite-message">{{d-icon "envelope"}}{{i18n "user.invited.invite.custom_message"}}</label>
|
||||
{{textarea id="invite-message" value=buffered.custom_message}}
|
||||
</div>
|
||||
{{/if}}
|
||||
@ -66,12 +64,13 @@
|
||||
selectedTopicId=buffered.topicId
|
||||
topicTitle=buffered.topicTitle
|
||||
additionalFilters="status:public"
|
||||
labelIcon="hand-point-right"
|
||||
label="user.invited.invite.invite_to_topic"
|
||||
}}
|
||||
</div>
|
||||
{{else if buffered.topicTitle}}
|
||||
<div class="input-group">
|
||||
<label for="invite-topic">{{i18n "user.invited.invite.invite_to_topic"}}</label>
|
||||
<div class="input-group invite-to-topic">
|
||||
<label for="invite-topic">{{d-icon "hand-point-right"}}{{i18n "user.invited.invite.invite_to_topic"}}</label>
|
||||
{{input
|
||||
name="invite-topic"
|
||||
class="invite-topic"
|
||||
@ -85,7 +84,7 @@
|
||||
{{#if showAdvanced}}
|
||||
{{#if canInviteToGroup}}
|
||||
<div class="input-group invite-to-groups">
|
||||
<label>{{i18n "user.invited.invite.add_to_groups"}}</label>
|
||||
<label>{{d-icon "users"}}{{i18n "user.invited.invite.add_to_groups"}}</label>
|
||||
{{group-chooser
|
||||
content=allGroups
|
||||
value=buffered.groupIds
|
||||
@ -100,6 +99,7 @@
|
||||
{{#if currentUser.staff}}
|
||||
<div class="input-group invite-expires-at">
|
||||
{{future-date-input
|
||||
displayLabelIcon="far-clock"
|
||||
displayLabel=(i18n "user.invited.invite.expires_at")
|
||||
includeDateTime=true
|
||||
includeMidFuture=true
|
||||
@ -118,7 +118,6 @@
|
||||
label="user.invited.invite.save_invite"
|
||||
class="btn-primary save-invite"
|
||||
action=(action "saveInvite")
|
||||
disabled=disabled
|
||||
}}
|
||||
|
||||
{{#if isEmail}}
|
||||
@ -127,7 +126,6 @@
|
||||
label=(if invite.emailed "user.invited.reinvite" "user.invited.invite.send_invite_email")
|
||||
class="btn-primary send-invite"
|
||||
action=(action "saveInvite" true)
|
||||
disabled=disabled
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
|
||||
acceptance("Invites - Create & Edit Invite Modal", function (needs) {
|
||||
let deleted;
|
||||
@ -23,7 +22,16 @@ acceptance("Invites - Create & Edit Invite Modal", function (needs) {
|
||||
};
|
||||
|
||||
server.post("/invites", () => helper.response(inviteData));
|
||||
server.put("/invites/1", () => helper.response(inviteData));
|
||||
server.put("/invites/1", (request) => {
|
||||
const data = helper.parsePostData(request.requestBody);
|
||||
if (data.email === "error") {
|
||||
return helper.response(422, {
|
||||
errors: ["error isn't a valid email address."],
|
||||
});
|
||||
} else {
|
||||
return helper.response(inviteData);
|
||||
}
|
||||
});
|
||||
|
||||
server.delete("/invites", () => {
|
||||
deleted = true;
|
||||
@ -95,11 +103,11 @@ acceptance("Invites - Create & Edit Invite Modal", function (needs) {
|
||||
await visit("/u/eviltrout/invited/pending");
|
||||
await click(".invite-controls .btn:first-child");
|
||||
|
||||
await click("#invite-type");
|
||||
await fillIn("#invite-email", "error");
|
||||
await click(".invite-link .btn");
|
||||
assert.equal(
|
||||
find("#modal-alert").text(),
|
||||
I18n.t("user.invited.invite.blank_email")
|
||||
"error isn't a valid email address."
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -172,11 +180,9 @@ acceptance("Invites - Email Invites", function (needs) {
|
||||
await visit("/u/eviltrout/invited/pending");
|
||||
await click(".invite-controls .btn:first-child");
|
||||
|
||||
await click("#invite-type");
|
||||
|
||||
assert.ok(find("#invite-email").length, "shows email field");
|
||||
|
||||
await fillIn("#invite-email", "test@example.com");
|
||||
|
||||
assert.ok(find(".save-invite").length, "shows save without email button");
|
||||
await click(".save-invite");
|
||||
assert.ok(
|
||||
|
@ -832,7 +832,7 @@
|
||||
.create-invite-modal,
|
||||
.share-topic-modal {
|
||||
.input-group {
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@ -841,24 +841,24 @@
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.invite-type {
|
||||
input[type="checkbox"] {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
margin-top: -1px;
|
||||
textarea#invite-message,
|
||||
&.invite-to-topic input[type="text"],
|
||||
.group-chooser,
|
||||
.user-chooser,
|
||||
.future-date-input-selector {
|
||||
margin-left: 25px;
|
||||
width: calc(100% - 25px);
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
&.invite-to-topic input[type="radio"] {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-chooser,
|
||||
.user-chooser,
|
||||
.future-date-input-selector {
|
||||
width: 100%;
|
||||
label .d-icon {
|
||||
color: var(--primary-medium);
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group input[type="text"],
|
||||
@ -868,10 +868,6 @@
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.input-group .btn {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.invite-input-with-button {
|
||||
display: flex;
|
||||
|
||||
@ -880,6 +876,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.input-group.input-expires-at,
|
||||
.input-group.input-email,
|
||||
.input-group.invite-max-redemptions {
|
||||
margin-bottom: 0;
|
||||
|
||||
input[type="text"] {
|
||||
width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.future-date-input {
|
||||
.date-picker-wrapper {
|
||||
input {
|
||||
@ -900,6 +906,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.input-group.input-email {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
|
||||
label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.invite-input-with-button {
|
||||
display: inline-flex;
|
||||
flex: 1;
|
||||
|
||||
input[type="text"] {
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invite-max-redemptions {
|
||||
label {
|
||||
display: inline;
|
||||
@ -910,6 +935,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.invite-to-topic {
|
||||
#choose-topic-title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.show-advanced {
|
||||
margin-left: auto;
|
||||
margin-right: 0;
|
||||
|
@ -1534,7 +1534,7 @@ en:
|
||||
new_title: "Create Invite"
|
||||
edit_title: "Edit Invite"
|
||||
|
||||
instructions: "Share this link to instantly grant access to this site:"
|
||||
instructions: "Share this link to instantly grant access to this site"
|
||||
copy_link: "copy link"
|
||||
expires_in_time: "Expires in %{time}."
|
||||
expired_at_time: "Expired at %{time}."
|
||||
@ -1542,21 +1542,20 @@ en:
|
||||
show_advanced: "Show Advanced Options"
|
||||
hide_advanced: "Hide Advanced Options"
|
||||
|
||||
restrict_email: "Restrict the invite to one email address"
|
||||
restrict_email: "Restrict to one email address"
|
||||
|
||||
max_redemptions_allowed: "Max number of uses:"
|
||||
max_redemptions_allowed: "Max uses"
|
||||
|
||||
add_to_groups: "Add to groups:"
|
||||
invite_to_topic: "Send to topic on first login:"
|
||||
expires_at: "Expire after:"
|
||||
custom_message: "Optional personal message:"
|
||||
add_to_groups: "Add to groups"
|
||||
invite_to_topic: "Arrive at this topic"
|
||||
expires_at: "Expire after"
|
||||
custom_message: "Optional personal message"
|
||||
|
||||
send_invite_email: "Save and Send Email"
|
||||
save_invite: "Save Invite"
|
||||
|
||||
invite_saved: "Invite saved."
|
||||
invite_copied: "Invite link copied."
|
||||
blank_email: "Invite link not copied. Email address is required."
|
||||
|
||||
bulk_invite:
|
||||
none: "No invitations to display on this page."
|
||||
|
Loading…
Reference in New Issue
Block a user