settings: Separate "Your account" section in two different sections.

We separate "Your account" section to two different sections -
"Profile" section for user name, custom profile fields, and avatar
and "Account & Security" section for email, password, role, api-key
and deactivating button.

Another important change here is that the modal for changing name
is removed and now the name has a simple input text box and it
behaves similar to inputs for custom-profile-fields.

Fixes #18848.
This commit is contained in:
sahil839 2021-06-17 22:12:31 +05:30 committed by Tim Abbott
parent 5f74e78bee
commit bb816e1998
14 changed files with 102 additions and 142 deletions

View File

@ -22,7 +22,7 @@ function test(label, f) {
}
test("basics", () => {
const hash1 = "#settings/your-account";
const hash1 = "#settings/profile";
const hash2 = "#narrow/is/private";
browser_history.go_to_location(hash1);
assert.equal(location.hash, hash1);

View File

@ -86,26 +86,26 @@ run_test("test_get_hash_category", () => {
assert.deepEqual(hash_util.get_hash_category("#drafts"), "drafts");
assert.deepEqual(hash_util.get_hash_category("invites"), "invites");
location.hash = "#settings/your-account";
location.hash = "#settings/profile";
assert.deepEqual(hash_util.get_current_hash_category(), "settings");
});
run_test("test_get_hash_section", () => {
assert.equal(hash_util.get_hash_section("streams/subscribed"), "subscribed");
assert.equal(hash_util.get_hash_section("#settings/your-account"), "your-account");
assert.equal(hash_util.get_hash_section("#settings/profile"), "profile");
assert.equal(hash_util.get_hash_section("settings/10/general/"), "10");
assert.equal(hash_util.get_hash_section("#drafts"), "");
assert.equal(hash_util.get_hash_section(""), "");
location.hash = "#settings/your-account";
assert.deepEqual(hash_util.get_current_hash_section(), "your-account");
location.hash = "#settings/profile";
assert.deepEqual(hash_util.get_current_hash_section(), "profile");
});
run_test("build_reload_url", () => {
location.hash = "#settings/your-account";
assert.equal(hash_util.build_reload_url(), "+oldhash=settings%2Fyour-account");
location.hash = "#settings/profile";
assert.equal(hash_util.build_reload_url(), "+oldhash=settings%2Fprofile");
location.hash = "#test";
assert.equal(hash_util.build_reload_url(), "+oldhash=test");

View File

@ -27,7 +27,7 @@ async function open_settings(page: Page): Promise<void> {
await page.waitForSelector(settings_selector, {visible: true});
await page.click(settings_selector);
await page.waitForSelector("#settings_content .account-settings-form", {visible: true});
await page.waitForSelector("#settings_content .profile-settings-form", {visible: true});
const page_url = await common.page_url_with_fragment(page);
assert.ok(
page_url.includes("/#settings/"),
@ -36,23 +36,18 @@ async function open_settings(page: Page): Promise<void> {
}
async function test_change_full_name(page: Page): Promise<void> {
await page.click("#change_full_name");
const change_full_name_button_selector = "#change_full_name_button";
await page.waitForSelector(change_full_name_button_selector, {visible: true});
await page.click("#full_name");
const full_name_input_selector = 'input[name="full_name"]';
await page.$eval(full_name_input_selector, (el) => {
(el as HTMLInputElement).value = "";
});
await page.waitForFunction(() => $(":focus").attr("id") === "change_full_name_modal");
await page.type(full_name_input_selector, "New name");
await page.click(change_full_name_button_selector);
await page.waitForFunction(() => $("#change_full_name").text().trim() === "New name");
await common.wait_for_modal_to_close(page);
await common.clear_and_type(page, full_name_input_selector, "New name");
await page.click("#settings_content .profile-settings-form");
await page.waitForSelector(".full-name-change-form .alert-success", {visible: true});
await page.waitForFunction(() => $("#full_name").val() === "New name");
}
async function test_change_password(page: Page): Promise<void> {
await page.click('[data-section="account-and-privacy"]');
await page.click("#change_password");
const change_password_button_selector = "#change_password_button";

View File

@ -95,7 +95,7 @@ export function build_user_avatar_widget(upload_function) {
},
});
}
const modal_parent = $("#account-settings");
const modal_parent = $("#profile-settings");
const html_body = render_confirm_delete_user_avatar();

View File

@ -12,7 +12,7 @@ export function get_hash_category(hash) {
}
export function get_hash_section(hash) {
// given "#settings/your-account", returns "your-account"
// given "#settings/profile", returns "profile"
// given '#streams/5/social", returns "5"
if (!hash) {
return "";

View File

@ -36,15 +36,10 @@ export function update_email(new_email) {
}
export function update_full_name(new_full_name) {
const full_name_field = $("#full_name_value");
if (full_name_field) {
full_name_field.text(new_full_name);
}
// Arguably, this should work more like how the `update_email`
// flow works, where we update the name in the modal on open,
// rather than updating it here, but this works.
const full_name_input = $(".full_name_change_container input[name='full_name']");
const full_name_input = $(".full-name-change-form input[name='full_name']");
if (full_name_input) {
full_name_input.val(new_full_name);
}
@ -279,13 +274,8 @@ export function add_custom_profile_fields_to_settings() {
return;
}
const element_id = "#account-settings .custom-profile-fields-form";
const element_id = "#profile-settings .custom-profile-fields-form";
$(element_id).html("");
if (page_params.custom_profile_fields.length > 0) {
$("#account-settings #custom-field-header").show();
} else {
$("#account-settings #custom-field-header").hide();
}
append_custom_profile_fields(element_id, people.my_current_user_id());
initialize_custom_user_type_fields(element_id, people.my_current_user_id(), true, true);
@ -403,15 +393,6 @@ export function set_up() {
clear_password_change();
$("#change_full_name").on("click", (e) => {
e.preventDefault();
e.stopPropagation();
if (settings_data.user_can_change_name()) {
$("#change_full_name_modal").find("input[name='full_name']").val(page_params.full_name);
overlays.open_modal("#change_full_name_modal");
}
});
$("#change_password").on("click", async (e) => {
e.preventDefault();
e.stopPropagation();
@ -487,28 +468,18 @@ export function set_up() {
password_quality?.(field.val(), $("#pw_strength .bar"), field);
});
$("#change_full_name_button").on("click", (e) => {
$("#full_name").on("change", (e) => {
e.preventDefault();
e.stopPropagation();
const change_full_name_error = $("#change_full_name_modal")
.find(".change_full_name_info")
.expectOne();
const data = {};
data.full_name = $(".full_name_change_container").find("input[name='full_name']").val();
data.full_name = $("#full_name").val();
const opts = {
success_continuation() {
overlays.close_modal("#change_full_name_modal");
},
error_msg_element: change_full_name_error,
};
settings_ui.do_settings_change(
channel.patch,
"/json/settings",
data,
$("#account-settings-status").expectOne(),
opts,
$(".full-name-status").expectOne(),
);
});
@ -556,7 +527,7 @@ export function set_up() {
}
});
$("#account-settings").on("click", ".custom_user_field .remove_date", (e) => {
$("#profile-settings").on("click", ".custom_user_field .remove_date", (e) => {
e.preventDefault();
e.stopPropagation();
const field = $(e.target).closest(".custom_user_field").expectOne();
@ -564,7 +535,7 @@ export function set_up() {
update_user_custom_profile_fields([field_id], channel.del);
});
$("#account-settings").on("change", ".custom_user_field_value", function (e) {
$("#profile-settings").on("change", ".custom_user_field_value", function (e) {
const fields = [];
const value = $(this).val();
const field_id = Number.parseInt(

View File

@ -38,6 +38,10 @@ export function get_group(section) {
case "deactivated-users-admin":
return "org_users";
case "profile":
case "account-and-privacy":
return "your-account";
default:
return section;
}

View File

@ -62,7 +62,8 @@ h3 .fa-question-circle-o {
text-align: left;
}
}
#account-settings {
#account-settings,
#profile-field-settings {
.grid {
label {
min-width: 120px;
@ -108,8 +109,7 @@ h3 .fa-question-circle-o {
}
#change_password_modal,
#change_email_modal,
#change_full_name_modal {
#change_email_modal {
max-width: 480px;
}
@ -587,12 +587,14 @@ input[type="checkbox"] {
}
}
#account-settings {
.custom-profile-fields-form .custom_user_field label {
#profile-settings {
.custom-profile-fields-form .custom_user_field label,
.full-name-change-form label {
min-width: fit-content;
}
.alert-notification.custom-field-status {
.alert-notification.custom-field-status,
.alert-notification.full-name-status {
padding-top: 0;
padding-bottom: 0;
margin-top: 0;
@ -1511,7 +1513,6 @@ input[type="checkbox"] {
width: 245px;
}
#change_full_name_modal .change_full_name_info,
#change_email_modal .change_email_info,
#change_password_modal .change_password_info,
#api_key_modal #api_key_status {
@ -1519,7 +1520,7 @@ input[type="checkbox"] {
}
}
#account-settings,
#profile-settings,
#edit-user-form {
.user-role button {
cursor: default;

View File

@ -1,9 +1,9 @@
<div id="account-settings" class="settings-section show" data-name="your-account">
<div id="account-settings" class="settings-section show" data-name="account-and-privacy">
<div class="alert" id="dev-account-settings-status"></div>
<div class="account-settings-form">
<div class="inline-block">
<div id="user_details_section">
<h3 class="inline-block">{{t "User settings" }}</h3>
<h3 class="inline-block">{{t "Account" }}</h3>
<form class="email-change-form grid">
<div class="alert-notification" id="account-settings-status"></div>
<div class="input-group">
@ -43,41 +43,6 @@
</p>
{{/if}}
<form class="form-horizontal full-name-change-form">
<div class="input-group inline-block grid user-name-parent">
<div class="user-name-section inline-block">
<label for="full_name" class="inline-block title">{{t "Full name" }}</label>
<button type="button" id='change_full_name' class="button btn-link small white rounded inline-block" id="full_name"
{{#unless user_can_change_name}}disabled="disabled"{{/unless}}>
<span id="full_name_value">{{page_params.full_name}}</span>
<i class="fa fa-pencil"></i>
</button>
<i class="fa fa-question-circle change_name_tooltip tippy-zulip-tooltip settings-info-icon"
{{#if user_can_change_name}}style="display:none"{{/if}}
data-tippy-content="{{t 'Name changes are disabled in this organization. Contact an administrator to change your name.' }}">
</i>
</div>
<div id="change_full_name_modal" class="modal modal-bg hide fade" tabindex="-1" role="dialog"
aria-labelledby="change_full_name_modal_label" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="{{t 'Close' }}"><span aria-hidden="true">&times;</span></button>
<h3 class="inline-block" id="change_full_name_modal_label">{{t "Change full name" }}</h3>
<div class="alert-notification change_full_name_info"></div>
</div>
<div class="modal-body">
<div class="input-group full_name_change_container">
<label for="email">{{t "New full name" }}</label>
<input type="text" name="full_name" value="{{ page_params.full_name }}" autocomplete="off" spellcheck="false" autofocus="autofocus"/>
</div>
</div>
<div class="modal-footer">
<button class="button white rounded" type="button" data-dismiss="modal">{{t "Cancel" }}</button>
<button id='change_full_name_button' class="button rounded sea-green" data-dismiss="modal">{{t "Change" }}</button>
</div>
</div>
</div>
</form>
<form class="password-change-form grid">
{{#if page_params.realm_email_auth_enabled}}
<div>
@ -126,44 +91,14 @@
<label for="user_role" class="inline-block title">{{t "Role" }}</label>
<span>{{user_role_text}}</span>
</div>
<form class="deactivate_account grid">
<div class="input-group">
<button type="submit" class="button rounded btn-danger" id="user_deactivate_account_button">
{{t 'Deactivate account' }}
</button>
</div>
</form>
<div class="input-group">
<button type="submit" class="button rounded btn-danger" id="user_deactivate_account_button">
{{t 'Deactivate account' }}
</button>
</div>
</div>
</div>
<div class="inline-block user-avatar-section">
<h3>
{{t "Profile picture" }}
<i class="fa fa-question-circle change_name_tooltip tippy-zulip-tooltip settings-info-icon"
{{#if user_can_change_avatar}}style="display:none"{{/if}}
data-tippy-content="{{t 'Avatar changes are disabled in this organization.' }}">
</i>
</h3>
{{> image_upload_widget
widget = "user-avatar"
upload_text = (t "Upload new profile picture")
delete_text = (t "Delete profile picture")
is_editable_by_current_user = user_can_change_avatar
image = page_params.avatar_url_medium}}
<div id="user-avatar-source">
<a href="https://en.gravatar.com/" target="_blank" rel="noopener noreferrer">{{t "Avatar from Gravatar" }}</a>
</div>
</div>
<div class="clear-float"></div>
<h3 class="inline-block" id="custom-field-header" {{#unless page_params.custom_profile_fields}}style="display: none"{{/unless}}>{{t "Profile" }}</h3>
<form class="form-horizontal custom-profile-fields-form grid"></form>
<button class="button rounded sea-green w-200 block" id="show_my_user_profile_modal">
{{t 'Preview profile' }}
<i class="fa fa-external-link" aria-hidden="true" title="{{t 'Preview profile' }}"></i>
</button>
<hr class="settings_separator" />
<div class="form-horizontal" id="api_key_button_box">

View File

@ -0,0 +1,48 @@
<div id="profile-settings" class="settings-section show" data-name="profile">
<div class="profile-settings-form">
<div class="inline-block">
<h3 class="inline-block hide" id="user-profile-header">{{t "Profile" }}</h3>
<div id="user_details_section">
<form class="form-horizontal full-name-change-form">
<div class="input-group inline-block grid user-name-parent">
<div class="user-name-section inline-block">
<label for="full_name" class="title inline-block">{{t "Full name" }}</label>
<i class="fa fa-question-circle change_name_tooltip tippy-zulip-tooltip settings-info-icon"
{{#if user_can_change_name}}style="display:none"{{/if}}
data-tippy-content="{{t 'Name changes are disabled in this organization. Contact an administrator to change your name.' }}">
</i>
<div class="alert-notification full-name-status"></div>
<div class="name-input">
<input id="full_name" name="full_name" type="text" value="{{ page_params.full_name }}" {{#unless user_can_change_name}}disabled="disabled"{{/unless}} maxlength="60" />
</div>
</div>
</div>
</form>
<form class="form-horizontal custom-profile-fields-form grid"></form>
<button class="button rounded sea-green w-200 block" id="show_my_user_profile_modal">
{{t 'Preview profile' }}
<i class="fa fa-external-link" aria-hidden="true" title="{{t 'Preview profile' }}"></i>
</button>
</div>
</div>
<div class="inline-block user-avatar-section">
<h3>
{{t "Profile picture" }}
<i class="fa fa-question-circle change_name_tooltip tippy-zulip-tooltip settings-info-icon"
{{#if user_can_change_avatar}}style="display:none"{{/if}}
data-tippy-content="{{t 'Avatar changes are disabled in this organization.' }}">
</i>
</h3>
{{> image_upload_widget
widget = "user-avatar"
upload_text = (t "Upload new profile picture")
delete_text = (t "Delete profile picture")
is_editable_by_current_user = user_can_change_avatar
image = page_params.avatar_url_medium}}
<div id="user-avatar-source">
<a href="https://en.gravatar.com/" target="_blank" rel="noopener noreferrer">{{t "Avatar from Gravatar" }}</a>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,6 @@
<div id="settings-change-box" class="new-style">
{{> settings/profile_settings }}
{{> settings/account_settings }}
{{> settings/display_settings }}

View File

@ -129,7 +129,7 @@
{{/unless}}
{{#if is_me}}
<li>
<a href="/#settings/your-account">
<a href="/#settings/profile">
<i class="fa fa-edit" aria-hidden="true"></i> {{#tr}}Edit your profile{{/tr}}
</a>
</li>

View File

@ -7,7 +7,7 @@
<div id="name">
{{full_name}}
{{#if is_me}}
<a href="/#settings/your-account">
<a href="/#settings/profile">
<i class="fa fa-edit" id="edit-button" aria-hidden="true"></i>
</a>
{{/if}}

View File

@ -11,9 +11,13 @@
<div class="sidebar-list dark-grey small-text">
<div class="center tab-container"></div>
<ul class="normal-settings-list">
<li tabindex="0" data-section="your-account">
<li tabindex="0" data-section="profile">
<i class="icon fa fa-user" aria-hidden="true"></i>
<div class="text">{{ _('Your account') }}</div>
<div class="text">{{ _('Profile') }}</div>
</li>
<li tabindex="0" data-section="account-and-privacy">
<i class="icon fa fa-lock" aria-hidden="true"></i>
<div class="text">{{ _('Account & privacy') }}</div>
</li>
<li tabindex="0" data-section="display-settings">
<i class="icon fa fa-clock-o" aria-hidden="true"></i>