2024-01-25 15:45:10 +01:00
|
|
|
import ClipboardJS from "clipboard";
|
2021-06-23 20:48:49 +02:00
|
|
|
import {parseISO} from "date-fns";
|
|
|
|
import $ from "jquery";
|
|
|
|
|
2024-01-05 16:00:57 +01:00
|
|
|
import render_profile_access_error_model from "../templates/profile_access_error_modal.hbs";
|
2023-09-25 12:15:17 +02:00
|
|
|
import render_admin_human_form from "../templates/settings/admin_human_form.hbs";
|
2023-09-25 11:29:07 +02:00
|
|
|
import render_edit_bot_form from "../templates/settings/edit_bot_form.hbs";
|
|
|
|
import render_settings_edit_embedded_bot_service from "../templates/settings/edit_embedded_bot_service.hbs";
|
|
|
|
import render_settings_edit_outgoing_webhook_service from "../templates/settings/edit_outgoing_webhook_service.hbs";
|
2021-06-23 20:48:49 +02:00
|
|
|
import render_user_group_list_item from "../templates/user_group_list_item.hbs";
|
|
|
|
import render_user_profile_modal from "../templates/user_profile_modal.hbs";
|
|
|
|
import render_user_stream_list_item from "../templates/user_stream_list_item.hbs";
|
|
|
|
|
2023-09-25 11:29:07 +02:00
|
|
|
import * as avatar from "./avatar";
|
|
|
|
import * as bot_data from "./bot_data";
|
2021-06-30 23:07:02 +02:00
|
|
|
import * as browser_history from "./browser_history";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as buddy_data from "./buddy_data";
|
2021-06-30 23:07:02 +02:00
|
|
|
import * as channel from "./channel";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as components from "./components";
|
2024-01-25 15:45:10 +01:00
|
|
|
import {show_copied_confirmation} from "./copied_tooltip";
|
2023-09-25 11:29:07 +02:00
|
|
|
import {csrf_token} from "./csrf";
|
2023-09-25 13:16:40 +02:00
|
|
|
import * as custom_profile_fields_ui from "./custom_profile_fields_ui";
|
2023-09-25 11:29:07 +02:00
|
|
|
import * as dialog_widget from "./dialog_widget";
|
2023-09-08 19:37:58 +02:00
|
|
|
import * as dropdown_widget from "./dropdown_widget";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as hash_util from "./hash_util";
|
2021-06-30 23:07:02 +02:00
|
|
|
import {$t, $t_html} from "./i18n";
|
2023-09-25 19:13:40 +02:00
|
|
|
import * as integration_url_modal from "./integration_url_modal";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as ListWidget from "./list_widget";
|
2023-09-27 19:09:10 +02:00
|
|
|
import * as loading from "./loading";
|
2023-10-10 14:25:18 +02:00
|
|
|
import * as modals from "./modals";
|
2023-01-15 13:13:19 +01:00
|
|
|
import * as peer_data from "./peer_data";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as people from "./people";
|
2024-04-03 16:14:34 +02:00
|
|
|
import * as settings_components from "./settings_components";
|
2023-09-25 11:29:07 +02:00
|
|
|
import * as settings_config from "./settings_config";
|
2023-09-25 10:15:19 +02:00
|
|
|
import * as settings_data from "./settings_data";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as settings_profile_fields from "./settings_profile_fields";
|
2024-02-13 02:08:24 +01:00
|
|
|
import {current_user, realm} from "./state_data";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as stream_data from "./stream_data";
|
2021-06-30 23:07:02 +02:00
|
|
|
import * as sub_store from "./sub_store";
|
2022-02-21 15:28:56 +01:00
|
|
|
import * as subscriber_api from "./subscriber_api";
|
2023-01-08 18:08:49 +01:00
|
|
|
import * as timerender from "./timerender";
|
2021-06-30 23:07:02 +02:00
|
|
|
import * as ui_report from "./ui_report";
|
2023-09-25 19:19:40 +02:00
|
|
|
import * as user_deactivation_ui from "./user_deactivation_ui";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as user_groups from "./user_groups";
|
2022-08-24 13:46:25 +02:00
|
|
|
import * as user_pill from "./user_pill";
|
2021-06-23 20:48:49 +02:00
|
|
|
import * as util from "./util";
|
|
|
|
|
2023-07-29 02:37:35 +02:00
|
|
|
let user_streams_list_widget;
|
2023-09-08 19:37:58 +02:00
|
|
|
let user_profile_subscribe_widget;
|
2023-09-09 13:13:14 +02:00
|
|
|
let toggler;
|
2023-09-25 11:29:07 +02:00
|
|
|
let bot_owner_dropdown_widget;
|
|
|
|
|
|
|
|
const INCOMING_WEBHOOK_BOT_TYPE = 2;
|
|
|
|
const OUTGOING_WEBHOOK_BOT_TYPE = "3";
|
|
|
|
const EMBEDDED_BOT_TYPE = "4";
|
2023-07-29 02:37:35 +02:00
|
|
|
|
2023-09-27 19:09:10 +02:00
|
|
|
export function show_button_spinner($button) {
|
|
|
|
const $spinner = $button.find(".modal__spinner");
|
|
|
|
const dialog_submit_button_span_width = $button.find("span").width();
|
|
|
|
const dialog_submit_button_span_height = $button.find("span").height();
|
|
|
|
$button.prop("disabled", true);
|
|
|
|
$button.find("span").hide();
|
|
|
|
loading.make_indicator($spinner, {
|
|
|
|
width: dialog_submit_button_span_width,
|
|
|
|
height: dialog_submit_button_span_height,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function hide_button_spinner($button) {
|
|
|
|
const $spinner = $button.find(".modal__spinner");
|
|
|
|
$button.prop("disabled", false);
|
|
|
|
$button.find("span").show();
|
|
|
|
loading.destroy_indicator($spinner);
|
|
|
|
}
|
|
|
|
|
2021-06-23 20:48:49 +02:00
|
|
|
function compare_by_name(a, b) {
|
|
|
|
return util.strcmp(a.name, b.name);
|
|
|
|
}
|
|
|
|
|
2023-08-16 15:00:29 +02:00
|
|
|
export function get_user_id_if_user_profile_modal_open() {
|
2023-10-11 11:19:13 +02:00
|
|
|
if (modals.any_active() && modals.active_modal() === "#user-profile-modal") {
|
2023-08-16 15:00:29 +02:00
|
|
|
const user_id = $("#user-profile-modal").data("user-id");
|
|
|
|
return user_id;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2023-07-29 02:37:35 +02:00
|
|
|
export function update_user_profile_streams_list_for_users(user_ids) {
|
|
|
|
const user_id = get_user_id_if_user_profile_modal_open();
|
|
|
|
if (user_id && user_ids.includes(user_id) && user_streams_list_widget !== undefined) {
|
|
|
|
const user_streams = stream_data.get_streams_for_user(user_id).subscribed;
|
2022-10-11 14:20:27 +02:00
|
|
|
user_streams.sort(compare_by_name);
|
2023-07-29 02:37:35 +02:00
|
|
|
user_streams_list_widget.replace_list_data(user_streams);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 13:46:25 +02:00
|
|
|
function initialize_bot_owner(element_id, bot_id) {
|
|
|
|
const user_pills = new Map();
|
|
|
|
const bot = people.get_by_user_id(bot_id);
|
|
|
|
const bot_owner = people.get_bot_owner_user(bot);
|
2022-11-14 18:02:55 +01:00
|
|
|
// Bot owner's pill displaying on bot's profile modal.
|
2022-08-24 13:46:25 +02:00
|
|
|
if (bot_owner) {
|
|
|
|
const $pill_container = $(element_id)
|
|
|
|
.find(
|
|
|
|
`.bot_owner_user_field[data-field-id="${CSS.escape(
|
|
|
|
bot_owner.user_id,
|
|
|
|
)}"] .pill-container`,
|
|
|
|
)
|
|
|
|
.expectOne();
|
|
|
|
const pills = user_pill.create_pills($pill_container);
|
|
|
|
|
|
|
|
user_pill.append_user(bot_owner, pills);
|
|
|
|
user_pills.set(bot_owner.user_id, pills);
|
|
|
|
}
|
|
|
|
return user_pills;
|
|
|
|
}
|
|
|
|
|
2023-09-08 19:37:58 +02:00
|
|
|
function render_user_profile_subscribe_widget() {
|
|
|
|
const opts = {
|
|
|
|
widget_name: "user_profile_subscribe",
|
|
|
|
get_options: get_user_unsub_streams,
|
|
|
|
item_click_callback: change_state_of_subscribe_button,
|
|
|
|
$events_container: $("#user-profile-modal"),
|
|
|
|
tippy_props: {
|
|
|
|
placement: "bottom-start",
|
|
|
|
},
|
|
|
|
};
|
stream_settings: Fix stream settings dropdown of user profile.
Previously, when the user modal is opened, and a stream is
selected from the streams tab, and then, when a new tab
is selected and you navigate back to this streams tab and
try to pick a new stream, it wouldn't allow you to do so.
This is because, preivously once a stream is picked,
and you go out of the tab and come back, then the
previous object of the subscribe widget was invalidated
and a new object was created. However, the options
still corresponded to the old object. Hence, the error.
This is fixed by checking out if a stream widget object
exists, before creating a new one. The object is cleared
out from the on_user_profile_hide method.
This error is not seen for other tabs even though they
reconstruct their entire tabs when re-visited
without saving previous state is that they don't make
modifications to the user profile from the modal itself.
They rather open some other modal to do it.
Hence, they don't need to store any state for their objects,
and hence no need to retain it.
their state.
Fixes #27422
2023-11-28 12:38:07 +01:00
|
|
|
user_profile_subscribe_widget =
|
|
|
|
user_profile_subscribe_widget || new dropdown_widget.DropdownWidget(opts);
|
2023-09-08 19:37:58 +02:00
|
|
|
user_profile_subscribe_widget.setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
function change_state_of_subscribe_button(event, dropdown) {
|
|
|
|
dropdown.hide();
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
user_profile_subscribe_widget.render();
|
|
|
|
const $subscribe_button = $("#user-profile-modal .add-subscription-button");
|
2023-08-23 20:57:31 +02:00
|
|
|
$subscribe_button.parent()[0]._tippy?.destroy();
|
2023-09-08 19:37:58 +02:00
|
|
|
$subscribe_button.prop("disabled", false);
|
|
|
|
}
|
|
|
|
|
2023-09-08 16:35:13 +02:00
|
|
|
function reset_subscribe_widget() {
|
|
|
|
$("#user-profile-modal .add-subscription-button").prop("disabled", true);
|
2024-04-03 16:14:34 +02:00
|
|
|
settings_components.initialize_disable_btn_hint_popover(
|
2023-09-08 16:35:13 +02:00
|
|
|
$("#user-profile-modal .add-subscription-button-wrapper"),
|
2024-04-18 18:36:57 +02:00
|
|
|
$t({defaultMessage: "Select a channel to subscribe"}),
|
2023-09-08 16:35:13 +02:00
|
|
|
);
|
|
|
|
$("#user_profile_subscribe_widget .dropdown_widget_value").text(
|
2024-04-18 18:36:57 +02:00
|
|
|
$t({defaultMessage: "Select a channel"}),
|
2023-09-08 16:35:13 +02:00
|
|
|
);
|
stream_settings: Fix stream settings dropdown of user profile.
Previously, when the user modal is opened, and a stream is
selected from the streams tab, and then, when a new tab
is selected and you navigate back to this streams tab and
try to pick a new stream, it wouldn't allow you to do so.
This is because, preivously once a stream is picked,
and you go out of the tab and come back, then the
previous object of the subscribe widget was invalidated
and a new object was created. However, the options
still corresponded to the old object. Hence, the error.
This is fixed by checking out if a stream widget object
exists, before creating a new one. The object is cleared
out from the on_user_profile_hide method.
This error is not seen for other tabs even though they
reconstruct their entire tabs when re-visited
without saving previous state is that they don't make
modifications to the user profile from the modal itself.
They rather open some other modal to do it.
Hence, they don't need to store any state for their objects,
and hence no need to retain it.
their state.
Fixes #27422
2023-11-28 12:38:07 +01:00
|
|
|
// There are two cases when the subscribe widget is reset: when the user_profile
|
|
|
|
// is setup (the object is null), or after subscribing of a user in the dropdown.
|
|
|
|
//
|
|
|
|
// After subscribing a user, we want the current_value of dropdown to be reset
|
|
|
|
// to null after the subscribe widget is reloaded. This is to avoid an error
|
|
|
|
// of not finding the current_value of the user_profile in the options.
|
|
|
|
if (user_profile_subscribe_widget) {
|
|
|
|
user_profile_subscribe_widget.current_value = null;
|
|
|
|
}
|
2023-09-08 16:35:13 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 19:37:58 +02:00
|
|
|
export function get_user_unsub_streams() {
|
|
|
|
const target_user_id = Number.parseInt($("#user-profile-modal").attr("data-user-id"), 10);
|
|
|
|
return stream_data
|
|
|
|
.get_streams_for_user(target_user_id)
|
2023-10-18 13:00:14 +02:00
|
|
|
.can_subscribe.map((stream) => ({
|
2023-09-08 19:37:58 +02:00
|
|
|
name: stream.name,
|
|
|
|
unique_id: stream.stream_id.toString(),
|
|
|
|
stream,
|
|
|
|
}))
|
|
|
|
.sort((a, b) => {
|
|
|
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-16 00:03:52 +02:00
|
|
|
function format_user_stream_list_item_html(stream, user) {
|
2021-06-30 08:35:25 +02:00
|
|
|
const show_unsubscribe_button =
|
2023-02-05 21:21:37 +01:00
|
|
|
people.can_admin_user(user) || stream_data.can_unsubscribe_others(stream);
|
2021-06-30 08:35:25 +02:00
|
|
|
const show_private_stream_unsub_tooltip =
|
|
|
|
people.is_my_user_id(user.user_id) && stream.invite_only;
|
2023-10-16 12:00:03 +02:00
|
|
|
const show_last_user_in_private_stream_unsub_tooltip =
|
|
|
|
stream.invite_only && peer_data.get_subscriber_count(stream.stream_id) === 1;
|
2021-06-23 20:48:49 +02:00
|
|
|
return render_user_stream_list_item({
|
|
|
|
name: stream.name,
|
|
|
|
stream_id: stream.stream_id,
|
|
|
|
stream_color: stream.color,
|
|
|
|
invite_only: stream.invite_only,
|
|
|
|
is_web_public: stream.is_web_public,
|
2021-06-30 23:07:02 +02:00
|
|
|
show_unsubscribe_button,
|
2021-06-30 08:35:25 +02:00
|
|
|
show_private_stream_unsub_tooltip,
|
2023-10-16 12:00:03 +02:00
|
|
|
show_last_user_in_private_stream_unsub_tooltip,
|
2023-11-09 20:28:32 +01:00
|
|
|
stream_edit_url: hash_util.stream_edit_url(stream, "general"),
|
2021-06-23 20:48:49 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-16 00:03:52 +02:00
|
|
|
function format_user_group_list_item_html(group) {
|
2021-06-23 20:48:49 +02:00
|
|
|
return render_user_group_list_item({
|
|
|
|
group_id: group.id,
|
|
|
|
name: group.name,
|
2024-02-20 16:12:46 +01:00
|
|
|
group_edit_url: hash_util.group_edit_url(group),
|
|
|
|
is_guest: current_user.is_guest,
|
2021-06-23 20:48:49 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function render_user_stream_list(streams, user) {
|
|
|
|
streams.sort(compare_by_name);
|
2022-01-25 11:36:19 +01:00
|
|
|
const $container = $("#user-profile-modal .user-stream-list");
|
|
|
|
$container.empty();
|
2023-07-29 02:37:35 +02:00
|
|
|
user_streams_list_widget = ListWidget.create($container, streams, {
|
2021-06-23 20:48:49 +02:00
|
|
|
name: `user-${user.user_id}-stream-list`,
|
2023-05-01 13:44:40 +02:00
|
|
|
get_item: ListWidget.default_get_item,
|
2023-09-16 00:03:52 +02:00
|
|
|
modifier_html(item) {
|
|
|
|
return format_user_stream_list_item_html(item, user);
|
2021-06-23 20:48:49 +02:00
|
|
|
},
|
2023-08-24 19:07:11 +02:00
|
|
|
callback_after_render() {
|
|
|
|
$container.parent().removeClass("empty-list");
|
|
|
|
},
|
2021-06-30 18:47:04 +02:00
|
|
|
filter: {
|
2022-01-25 11:36:19 +01:00
|
|
|
$element: $("#user-profile-streams-tab .stream-search"),
|
2021-06-30 18:47:04 +02:00
|
|
|
predicate(item, value) {
|
|
|
|
return item && item.name.toLocaleLowerCase().includes(value);
|
|
|
|
},
|
2023-08-24 19:07:11 +02:00
|
|
|
onupdate() {
|
2023-10-15 12:23:06 +02:00
|
|
|
if ($container.find(".empty-table-message").length) {
|
2023-08-24 19:07:11 +02:00
|
|
|
$container.parent().addClass("empty-list");
|
|
|
|
}
|
|
|
|
},
|
2021-06-30 18:47:04 +02:00
|
|
|
},
|
2022-01-25 11:36:19 +01:00
|
|
|
$simplebar_container: $("#user-profile-modal .modal__body"),
|
2021-06-23 20:48:49 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function render_user_group_list(groups, user) {
|
|
|
|
groups.sort(compare_by_name);
|
2022-01-25 11:36:19 +01:00
|
|
|
const $container = $("#user-profile-modal .user-group-list");
|
|
|
|
$container.empty();
|
|
|
|
ListWidget.create($container, groups, {
|
2021-06-23 20:48:49 +02:00
|
|
|
name: `user-${user.user_id}-group-list`,
|
2023-05-01 13:44:40 +02:00
|
|
|
get_item: ListWidget.default_get_item,
|
2023-08-24 19:07:11 +02:00
|
|
|
callback_after_render() {
|
|
|
|
$container.parent().removeClass("empty-list");
|
|
|
|
},
|
2023-09-16 00:03:52 +02:00
|
|
|
modifier_html(item) {
|
|
|
|
return format_user_group_list_item_html(item);
|
2021-06-23 20:48:49 +02:00
|
|
|
},
|
2022-01-25 11:36:19 +01:00
|
|
|
$simplebar_container: $("#user-profile-modal .modal__body"),
|
2021-06-23 20:48:49 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
function render_manage_profile_content(user) {
|
user_profile: Fix inconsistent height of user profile switching tabs.
This commit fixes the inconsistent height of the user profile when
switching tabs. We now have four tabs in the user profile:
"Profile," "Streams," "User Groups," and "Manage User." However,
the "Manage User" tab has footer buttons that need to remain
sticky at the bottom without changing the overall height of
the modal.
To achieve this, we wrapped the footer inside a div element and
assigned it a class called "manage-profile-tab-footer." The main
body of the user profile is given a height of 60vh. However, for
the "Manage User" tab, we decreased this height to 52vh and
allocated the remaining 8vh height to the div element to
accommodate the footer buttons. This ensures that the user
profile maintains consistent height when switching between tabs.
However, we have a 1px border in the footer, so to ensure that
the height is consistent, we reduce the height of the modal
content by 1px, making it calc(52vh - 1px).
To implement this, CSS code was added to the "popover.css" file
and accessed through the class specified in the "user_profile.js"
file.
The default padding of the buttons inside footer is 20px, but
with the above solution on large screens the buttons are not
aligned properly, so removed the padding top and bottom
and instead applied the flex box and property to align the buttons.
2023-09-09 14:26:50 +02:00
|
|
|
// Since we want the height of the profile modal to remain consistent when switching tabs,
|
|
|
|
// we need to restrict the height of the main body. This will ensure that the footer of
|
|
|
|
// the "Manage User" tab can adjust within the provided height without expanding the modal.
|
|
|
|
$("#user-profile-modal .modal__body").addClass("modal__body__manage_profile_height");
|
|
|
|
$("#user-profile-modal .manage-profile-tab-footer").addClass("modal__footer_wrapper");
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
const $container = $("#manage-profile-tab");
|
|
|
|
$container.empty();
|
2023-07-20 13:50:04 +02:00
|
|
|
if (user.is_bot) {
|
2023-09-25 11:29:07 +02:00
|
|
|
show_edit_bot_info_modal(user.user_id, $container);
|
2023-07-20 13:50:04 +02:00
|
|
|
} else {
|
2023-09-25 12:15:17 +02:00
|
|
|
show_edit_user_info_modal(user.user_id, $container);
|
2023-07-20 13:50:04 +02:00
|
|
|
}
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
}
|
|
|
|
|
2023-01-08 18:08:49 +01:00
|
|
|
export function get_custom_profile_field_data(user, field, field_types) {
|
2021-06-23 20:48:49 +02:00
|
|
|
const field_value = people.get_custom_profile_data(user.user_id, field.id);
|
|
|
|
const field_type = field.type;
|
|
|
|
const profile_field = {};
|
|
|
|
|
|
|
|
if (!field_value) {
|
|
|
|
return profile_field;
|
|
|
|
}
|
|
|
|
if (!field_value.value) {
|
|
|
|
return profile_field;
|
|
|
|
}
|
2023-03-22 10:10:58 +01:00
|
|
|
profile_field.id = field.id;
|
2021-06-23 20:48:49 +02:00
|
|
|
profile_field.name = field.name;
|
|
|
|
profile_field.is_user_field = false;
|
|
|
|
profile_field.is_link = field_type === field_types.URL.id;
|
|
|
|
profile_field.is_external_account = field_type === field_types.EXTERNAL_ACCOUNT.id;
|
|
|
|
profile_field.type = field_type;
|
2022-07-12 21:25:02 +02:00
|
|
|
profile_field.display_in_profile_summary = field.display_in_profile_summary;
|
2024-03-19 14:22:03 +01:00
|
|
|
profile_field.required = field.required;
|
2021-06-23 20:48:49 +02:00
|
|
|
|
|
|
|
switch (field_type) {
|
|
|
|
case field_types.DATE.id:
|
2023-01-08 18:08:49 +01:00
|
|
|
profile_field.value = timerender.get_localized_date_or_time_for_format(
|
|
|
|
parseISO(field_value.value),
|
|
|
|
"dayofyear_year",
|
|
|
|
);
|
2021-06-23 20:48:49 +02:00
|
|
|
break;
|
|
|
|
case field_types.USER.id:
|
|
|
|
profile_field.is_user_field = true;
|
|
|
|
profile_field.value = field_value.value;
|
|
|
|
break;
|
|
|
|
case field_types.SELECT.id: {
|
|
|
|
const field_choice_dict = JSON.parse(field.field_data);
|
|
|
|
profile_field.value = field_choice_dict[field_value.value].text;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case field_types.SHORT_TEXT.id:
|
|
|
|
case field_types.LONG_TEXT.id:
|
|
|
|
profile_field.value = field_value.value;
|
|
|
|
profile_field.rendered_value = field_value.rendered_value;
|
|
|
|
break;
|
|
|
|
case field_types.EXTERNAL_ACCOUNT.id:
|
|
|
|
profile_field.value = field_value.value;
|
|
|
|
profile_field.field_data = JSON.parse(field.field_data);
|
2022-07-12 21:25:02 +02:00
|
|
|
profile_field.subtype = profile_field.field_data.subtype;
|
2021-06-23 20:48:49 +02:00
|
|
|
profile_field.link = settings_profile_fields.get_external_account_link(profile_field);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
profile_field.value = field_value.value;
|
|
|
|
}
|
|
|
|
return profile_field;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function hide_user_profile() {
|
2023-10-10 14:31:36 +02:00
|
|
|
modals.close_if_open("user-profile-modal");
|
2021-06-23 20:48:49 +02:00
|
|
|
}
|
|
|
|
|
2023-11-26 12:25:05 +01:00
|
|
|
function on_user_profile_hide() {
|
|
|
|
user_streams_list_widget = undefined;
|
stream_settings: Fix stream settings dropdown of user profile.
Previously, when the user modal is opened, and a stream is
selected from the streams tab, and then, when a new tab
is selected and you navigate back to this streams tab and
try to pick a new stream, it wouldn't allow you to do so.
This is because, preivously once a stream is picked,
and you go out of the tab and come back, then the
previous object of the subscribe widget was invalidated
and a new object was created. However, the options
still corresponded to the old object. Hence, the error.
This is fixed by checking out if a stream widget object
exists, before creating a new one. The object is cleared
out from the on_user_profile_hide method.
This error is not seen for other tabs even though they
reconstruct their entire tabs when re-visited
without saving previous state is that they don't make
modifications to the user profile from the modal itself.
They rather open some other modal to do it.
Hence, they don't need to store any state for their objects,
and hence no need to retain it.
their state.
Fixes #27422
2023-11-28 12:38:07 +01:00
|
|
|
user_profile_subscribe_widget = undefined;
|
2024-01-05 16:00:57 +01:00
|
|
|
browser_history.exit_overlay();
|
2023-11-26 12:25:05 +01:00
|
|
|
}
|
|
|
|
|
2023-09-09 13:13:14 +02:00
|
|
|
function show_manage_user_tab(target) {
|
|
|
|
toggler.goto(target);
|
|
|
|
}
|
|
|
|
|
2022-09-11 15:14:06 +02:00
|
|
|
function initialize_user_type_fields(user) {
|
|
|
|
// Avoid duplicate pill fields, by removing existing ones.
|
|
|
|
$("#user-profile-modal .pill").remove();
|
|
|
|
if (!user.is_bot) {
|
2023-09-25 13:16:40 +02:00
|
|
|
custom_profile_fields_ui.initialize_custom_user_type_fields(
|
2022-09-11 15:14:06 +02:00
|
|
|
"#user-profile-modal #content",
|
|
|
|
user.user_id,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
initialize_bot_owner("#user-profile-modal #content", user.user_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-05 16:00:57 +01:00
|
|
|
export function show_user_profile_access_error_modal() {
|
2024-04-04 00:18:17 +02:00
|
|
|
$("body").append($(render_profile_access_error_model()));
|
2024-01-05 16:00:57 +01:00
|
|
|
|
|
|
|
// This opens the model, referencing it by it's ID('profile_access_error_model)
|
|
|
|
modals.open("profile_access_error_modal", {
|
|
|
|
autoremove: true,
|
|
|
|
on_hide() {
|
|
|
|
browser_history.exit_overlay();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-08-24 10:54:02 +02:00
|
|
|
export function show_user_profile(user, default_tab_key = "profile-tab") {
|
2024-02-13 02:08:24 +01:00
|
|
|
const field_types = realm.custom_profile_field_types;
|
|
|
|
const profile_data = realm.custom_profile_fields
|
2023-01-08 18:08:49 +01:00
|
|
|
.map((f) => get_custom_profile_field_data(user, f, field_types))
|
2021-06-23 20:48:49 +02:00
|
|
|
.filter((f) => f.name !== undefined);
|
2023-07-29 00:49:51 +02:00
|
|
|
const user_streams = stream_data.get_streams_for_user(user.user_id).subscribed;
|
2023-09-08 19:37:58 +02:00
|
|
|
// We only show the subscribe widget if the user is an admin, the user has opened their own profile,
|
|
|
|
// or if the user profile belongs to a bot whose owner has opened the user profile. However, we don't
|
|
|
|
// want to show the subscribe widget for generic bots since they are system bots and for deactivated users.
|
|
|
|
// Therefore, we also check for that condition.
|
|
|
|
const show_user_subscribe_widget =
|
2023-10-18 12:53:23 +02:00
|
|
|
(people.can_admin_user(user) || settings_data.user_can_subscribe_other_users()) &&
|
2023-09-08 19:37:58 +02:00
|
|
|
!user.is_system_bot &&
|
|
|
|
people.is_person_active(user.user_id);
|
2021-06-23 20:48:49 +02:00
|
|
|
const groups_of_user = user_groups.get_user_groups_of_user(user.user_id);
|
2023-07-20 13:50:04 +02:00
|
|
|
// We currently have the main UI for editing your own profile in
|
|
|
|
// settings, so can_manage_profile is artificially false for those.
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
const can_manage_profile =
|
2024-02-13 02:08:16 +01:00
|
|
|
(people.can_admin_user(user) || current_user.is_admin) &&
|
2023-07-20 13:50:04 +02:00
|
|
|
!user.is_system_bot &&
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
!people.is_my_user_id(user.user_id);
|
2021-06-23 20:48:49 +02:00
|
|
|
const args = {
|
2023-10-26 07:12:11 +02:00
|
|
|
can_manage_profile,
|
2023-01-08 18:08:49 +01:00
|
|
|
date_joined: timerender.get_localized_date_or_time_for_format(
|
|
|
|
parseISO(user.date_joined),
|
|
|
|
"dayofyear_year",
|
|
|
|
),
|
2023-10-26 07:12:11 +02:00
|
|
|
email: user.delivery_email,
|
|
|
|
full_name: user.full_name,
|
|
|
|
is_active: people.is_person_active(user.user_id),
|
|
|
|
is_bot: user.is_bot,
|
|
|
|
is_me: people.is_current_user(user.email),
|
2021-06-23 20:48:49 +02:00
|
|
|
last_seen: buddy_data.user_last_seen_time_status(user.user_id),
|
2023-10-26 07:12:11 +02:00
|
|
|
profile_data,
|
|
|
|
should_add_guest_user_indicator: people.should_add_guest_user_indicator(user.user_id),
|
|
|
|
show_user_subscribe_widget,
|
|
|
|
user_avatar: people.medium_avatar_url_for_person(user),
|
|
|
|
user_circle_class: buddy_data.get_user_circle_class(user.user_id),
|
|
|
|
user_id: user.user_id,
|
|
|
|
user_is_guest: user.is_guest,
|
2021-06-23 20:48:49 +02:00
|
|
|
user_time: people.get_user_time(user.user_id),
|
|
|
|
user_type: people.get_user_type(user.user_id),
|
|
|
|
};
|
|
|
|
|
2022-08-24 13:46:25 +02:00
|
|
|
if (user.is_bot) {
|
|
|
|
const is_system_bot = user.is_system_bot;
|
|
|
|
const bot_owner_id = user.bot_owner_id;
|
|
|
|
if (is_system_bot) {
|
|
|
|
args.is_system_bot = is_system_bot;
|
|
|
|
} else if (bot_owner_id) {
|
2023-12-13 08:57:11 +01:00
|
|
|
const bot_owner = people.get_bot_owner_user(user);
|
2022-08-24 13:46:25 +02:00
|
|
|
args.bot_owner = bot_owner;
|
|
|
|
}
|
2023-09-26 05:52:27 +02:00
|
|
|
args.bot_type = settings_data.bot_type_id_to_string(user.bot_type);
|
2022-08-24 13:46:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-23 20:48:49 +02:00
|
|
|
$("#user-profile-modal-holder").html(render_user_profile_modal(args));
|
2023-11-26 12:25:05 +01:00
|
|
|
modals.open("user-profile-modal", {autoremove: true, on_hide: on_user_profile_hide});
|
2021-06-23 20:48:49 +02:00
|
|
|
$(".tabcontent").hide();
|
2022-08-24 10:54:02 +02:00
|
|
|
|
|
|
|
let default_tab = 0;
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
|
2022-08-24 10:54:02 +02:00
|
|
|
if (default_tab_key === "user-profile-streams-tab") {
|
|
|
|
default_tab = 1;
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
} else if (default_tab_key === "manage-profile-tab") {
|
|
|
|
default_tab = 3;
|
2022-08-24 10:54:02 +02:00
|
|
|
}
|
|
|
|
|
2021-06-23 20:48:49 +02:00
|
|
|
const opts = {
|
2022-08-24 10:54:02 +02:00
|
|
|
selected: default_tab,
|
2021-06-23 20:48:49 +02:00
|
|
|
child_wants_focus: true,
|
|
|
|
values: [
|
|
|
|
{label: $t({defaultMessage: "Profile"}), key: "profile-tab"},
|
2024-04-18 18:36:57 +02:00
|
|
|
{label: $t({defaultMessage: "Channels"}), key: "user-profile-streams-tab"},
|
2021-07-02 21:38:15 +02:00
|
|
|
{label: $t({defaultMessage: "User groups"}), key: "user-profile-groups-tab"},
|
2021-06-23 20:48:49 +02:00
|
|
|
],
|
2023-06-29 21:59:08 +02:00
|
|
|
callback(_name, key) {
|
2021-06-23 20:48:49 +02:00
|
|
|
$(".tabcontent").hide();
|
2023-04-01 01:42:40 +02:00
|
|
|
$(`#${CSS.escape(key)}`).show();
|
2023-09-11 01:53:13 +02:00
|
|
|
$("#user-profile-modal .modal__footer").hide();
|
user_profile: Fix inconsistent height of user profile switching tabs.
This commit fixes the inconsistent height of the user profile when
switching tabs. We now have four tabs in the user profile:
"Profile," "Streams," "User Groups," and "Manage User." However,
the "Manage User" tab has footer buttons that need to remain
sticky at the bottom without changing the overall height of
the modal.
To achieve this, we wrapped the footer inside a div element and
assigned it a class called "manage-profile-tab-footer." The main
body of the user profile is given a height of 60vh. However, for
the "Manage User" tab, we decreased this height to 52vh and
allocated the remaining 8vh height to the div element to
accommodate the footer buttons. This ensures that the user
profile maintains consistent height when switching between tabs.
However, we have a 1px border in the footer, so to ensure that
the height is consistent, we reduce the height of the modal
content by 1px, making it calc(52vh - 1px).
To implement this, CSS code was added to the "popover.css" file
and accessed through the class specified in the "user_profile.js"
file.
The default padding of the buttons inside footer is 20px, but
with the above solution on large screens the buttons are not
aligned properly, so removed the padding top and bottom
and instead applied the flex box and property to align the buttons.
2023-09-09 14:26:50 +02:00
|
|
|
$("#user-profile-modal .modal__body").removeClass("modal__body__manage_profile_height");
|
|
|
|
$("#user-profile-modal .manage-profile-tab-footer").removeClass(
|
|
|
|
"modal__footer_wrapper",
|
|
|
|
);
|
2021-06-23 20:48:49 +02:00
|
|
|
switch (key) {
|
2022-09-11 15:14:06 +02:00
|
|
|
case "profile-tab":
|
|
|
|
initialize_user_type_fields(user);
|
|
|
|
break;
|
2021-07-02 21:38:15 +02:00
|
|
|
case "user-profile-groups-tab":
|
2021-06-23 20:48:49 +02:00
|
|
|
render_user_group_list(groups_of_user, user);
|
|
|
|
break;
|
2021-07-02 21:25:50 +02:00
|
|
|
case "user-profile-streams-tab":
|
2023-09-08 19:37:58 +02:00
|
|
|
if (show_user_subscribe_widget) {
|
|
|
|
render_user_profile_subscribe_widget();
|
|
|
|
}
|
2021-06-23 20:48:49 +02:00
|
|
|
render_user_stream_list(user_streams, user);
|
|
|
|
break;
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
case "manage-profile-tab":
|
2023-09-11 01:53:13 +02:00
|
|
|
$("#user-profile-modal .modal__footer").show();
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
render_manage_profile_content(user);
|
|
|
|
break;
|
2021-06-23 20:48:49 +02:00
|
|
|
}
|
2023-11-18 08:44:06 +01:00
|
|
|
setTimeout(() => {
|
|
|
|
$(".modal__body .simplebar-content-wrapper").attr("tabindex", "-1");
|
|
|
|
$(".modal__container .ind-tab").attr("tabindex", "-1");
|
|
|
|
$(".modal__container .ind-tab.selected").attr("tabindex", "0");
|
|
|
|
}, 0);
|
2021-06-23 20:48:49 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
if (can_manage_profile) {
|
2023-07-20 13:50:04 +02:00
|
|
|
const manage_profile_label = user.is_bot
|
|
|
|
? $t({defaultMessage: "Manage bot"})
|
|
|
|
: $t({defaultMessage: "Manage user"});
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
const manage_profile_tab = {
|
2023-07-20 13:50:04 +02:00
|
|
|
label: manage_profile_label,
|
settings_users: Migrate manage user modal to full profile modal.
This commit migrates the "manage user" modal to the "Full Profile"
modal. Refactored the show_edit_user_info_modal function since
earlier, we used to have a separate "Manage User" modal.
Consequently, we checked if we were coming from the
user_info_popover and then built the dialog widget accordingly.
However, with this new change, we no longer need to build the
dialog widget. Therefore, removed that part and now just pass
the container of the 'user profile modal' to get the content.
Previously, for deactivation, we used to have a separate dialog
widget. But now, since we have a dedicated function to handle
this case, refactored the deactivation code to use the
'confirm_deactivation' function.
Additionally, created two new functions to handle the loading
spinner. Since we will need these functions in the future for
the "Manage Bot" modal, we marked them as exported.
"Since we do not want to show the 'Manage User' tab to the user
looking at their own profile, in the 'can_manage_user' function
that we use to render the 'Manage User' tab, we check if the user
profile popover belongs to the same user. If it does, we set it to
'false' instead of 'true,' ensuring that the 'Manage User' tab is
not visible.
Added a new tab in the user profile modal 'manage user'.
Fixes: #21806
2023-09-09 12:42:04 +02:00
|
|
|
key: "manage-profile-tab",
|
|
|
|
};
|
|
|
|
opts.values.push(manage_profile_tab);
|
|
|
|
}
|
|
|
|
|
2023-09-09 13:13:14 +02:00
|
|
|
toggler = components.toggle(opts);
|
|
|
|
const $elem = toggler.get();
|
2022-01-25 11:36:19 +01:00
|
|
|
$elem.addClass("large allow-overflow");
|
|
|
|
$("#tab-toggle").append($elem);
|
2024-01-29 12:17:34 +01:00
|
|
|
setTimeout(() => {
|
|
|
|
$(".ind-tab.selected").trigger("focus");
|
|
|
|
}, 0);
|
2023-09-08 19:37:58 +02:00
|
|
|
if (show_user_subscribe_widget) {
|
2023-09-08 16:35:13 +02:00
|
|
|
reset_subscribe_widget();
|
2023-09-08 19:37:58 +02:00
|
|
|
}
|
2021-06-23 20:48:49 +02:00
|
|
|
}
|
|
|
|
|
2021-06-30 23:07:02 +02:00
|
|
|
function handle_remove_stream_subscription(target_user_id, sub, success, failure) {
|
|
|
|
if (people.is_my_user_id(target_user_id)) {
|
|
|
|
// Self unsubscribe.
|
|
|
|
channel.del({
|
|
|
|
url: "/json/users/me/subscriptions",
|
|
|
|
data: {subscriptions: JSON.stringify([sub.name])},
|
|
|
|
success,
|
|
|
|
error: failure,
|
|
|
|
});
|
|
|
|
} else {
|
2022-02-21 15:28:56 +01:00
|
|
|
subscriber_api.remove_user_id_from_stream(target_user_id, sub, success, failure);
|
2021-06-30 23:07:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 11:29:07 +02:00
|
|
|
export function show_edit_bot_info_modal(user_id, $container) {
|
|
|
|
const bot = people.maybe_get_user_by_id(user_id);
|
|
|
|
const owner_id = bot_data.get(user_id).owner_id;
|
|
|
|
const owner_full_name = people.get_full_name(owner_id);
|
2023-09-27 08:41:31 +02:00
|
|
|
const is_active = people.is_person_active(user_id);
|
2023-09-25 11:29:07 +02:00
|
|
|
|
|
|
|
if (!bot || !bot_data.get(user_id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const html_body = render_edit_bot_form({
|
|
|
|
user_id,
|
2023-09-27 08:41:31 +02:00
|
|
|
is_active,
|
2023-09-25 11:29:07 +02:00
|
|
|
email: bot.email,
|
|
|
|
full_name: bot.full_name,
|
|
|
|
user_role_values: settings_config.user_role_values,
|
2024-02-13 02:08:16 +01:00
|
|
|
disable_role_dropdown: !current_user.is_admin || (bot.is_owner && !current_user.is_owner),
|
2023-09-25 11:29:07 +02:00
|
|
|
bot_avatar_url: bot.avatar_url,
|
|
|
|
owner_full_name,
|
|
|
|
current_bot_owner: bot.bot_owner_id,
|
|
|
|
is_incoming_webhook_bot: bot.bot_type === INCOMING_WEBHOOK_BOT_TYPE,
|
|
|
|
});
|
2024-04-04 00:18:17 +02:00
|
|
|
$container.append($(html_body));
|
2023-09-25 11:29:07 +02:00
|
|
|
let avatar_widget;
|
|
|
|
|
|
|
|
const bot_type = bot.bot_type.toString();
|
|
|
|
const service = bot_data.get_services(bot.user_id)[0];
|
|
|
|
edit_bot_post_render();
|
|
|
|
$("#user-profile-modal").on("click", ".dialog_submit_button", () => {
|
|
|
|
const role = Number.parseInt($("#bot-role-select").val().trim(), 10);
|
|
|
|
const $full_name = $("#bot-edit-form").find("input[name='full_name']");
|
|
|
|
const url = "/json/bots/" + encodeURIComponent(bot.user_id);
|
|
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
formData.append("csrfmiddlewaretoken", csrf_token);
|
|
|
|
formData.append("full_name", $full_name.val());
|
|
|
|
formData.append("role", JSON.stringify(role));
|
|
|
|
const new_bot_owner_id = bot_owner_dropdown_widget.value();
|
|
|
|
if (new_bot_owner_id) {
|
|
|
|
formData.append("bot_owner_id", new_bot_owner_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bot_type === OUTGOING_WEBHOOK_BOT_TYPE) {
|
|
|
|
const service_payload_url = $("#edit_service_base_url").val();
|
|
|
|
const service_interface = $("#edit_service_interface").val();
|
|
|
|
formData.append("service_payload_url", JSON.stringify(service_payload_url));
|
|
|
|
formData.append("service_interface", service_interface);
|
|
|
|
} else if (bot_type === EMBEDDED_BOT_TYPE && service !== undefined) {
|
|
|
|
const config_data = {};
|
|
|
|
$("#config_edit_inputbox input").each(function () {
|
|
|
|
config_data[$(this).attr("name")] = $(this).val();
|
|
|
|
});
|
|
|
|
formData.append("config_data", JSON.stringify(config_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
const $file_input = $("#bot-edit-form").find(".edit_bot_avatar_file_input");
|
|
|
|
for (const [i, file] of Array.prototype.entries.call($file_input[0].files)) {
|
|
|
|
formData.append("file-" + i, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
const $submit_btn = $("#user-profile-modal .dialog_submit_button");
|
|
|
|
const $cancel_btn = $("#user-profile-modal .dialog_exit_button");
|
2023-09-27 19:09:10 +02:00
|
|
|
show_button_spinner($submit_btn);
|
2023-09-25 11:29:07 +02:00
|
|
|
$cancel_btn.prop("disabled", true);
|
|
|
|
|
|
|
|
channel.patch({
|
|
|
|
url,
|
|
|
|
data: formData,
|
|
|
|
processData: false,
|
|
|
|
contentType: false,
|
|
|
|
success() {
|
|
|
|
avatar_widget.clear();
|
|
|
|
hide_user_profile();
|
|
|
|
},
|
|
|
|
error(xhr) {
|
|
|
|
ui_report.error(
|
|
|
|
$t_html({defaultMessage: "Failed"}),
|
|
|
|
xhr,
|
|
|
|
$("#bot-edit-form-error"),
|
|
|
|
);
|
|
|
|
// Scrolling modal to top, to make error visible to user.
|
|
|
|
$("#bot-edit-form")
|
|
|
|
.closest(".simplebar-content-wrapper")
|
|
|
|
.animate({scrollTop: 0}, "fast");
|
2023-09-27 19:09:10 +02:00
|
|
|
hide_button_spinner($submit_btn);
|
2023-09-25 11:29:07 +02:00
|
|
|
$cancel_btn.prop("disabled", false);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
function edit_bot_post_render() {
|
|
|
|
$("#edit_bot_modal .dialog_submit_button").prop("disabled", true);
|
|
|
|
|
|
|
|
function get_options() {
|
|
|
|
const user_ids = people.get_realm_active_human_user_ids();
|
|
|
|
return user_ids.map((user_id) => ({
|
|
|
|
name: people.get_full_name(user_id),
|
|
|
|
unique_id: user_id,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
function item_click_callback(event, dropdown) {
|
|
|
|
bot_owner_dropdown_widget.render();
|
|
|
|
// Let dialog_widget know that there was a change in value.
|
2024-02-21 08:18:47 +01:00
|
|
|
$(bot_owner_dropdown_widget.widget_selector).trigger("input");
|
2023-09-25 11:29:07 +02:00
|
|
|
dropdown.hide();
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
bot_owner_dropdown_widget = new dropdown_widget.DropdownWidget({
|
|
|
|
widget_name: "edit_bot_owner",
|
|
|
|
get_options,
|
|
|
|
item_click_callback,
|
|
|
|
$events_container: $("#bot-edit-form"),
|
|
|
|
tippy_props: {
|
|
|
|
placement: "bottom-start",
|
|
|
|
},
|
|
|
|
default_id: owner_id,
|
2024-02-19 14:22:38 +01:00
|
|
|
unique_id_type: dropdown_widget.DataTypes.NUMBER,
|
2023-09-25 11:29:07 +02:00
|
|
|
});
|
|
|
|
bot_owner_dropdown_widget.setup();
|
|
|
|
|
|
|
|
$("#bot-role-select").val(bot.role);
|
2024-02-13 02:08:16 +01:00
|
|
|
if (!current_user.is_owner) {
|
2023-09-25 11:29:07 +02:00
|
|
|
$("#bot-role-select")
|
|
|
|
.find(`option[value="${CSS.escape(settings_config.user_role_values.owner.code)}"]`)
|
|
|
|
.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
avatar_widget = avatar.build_bot_edit_widget($("#bot-edit-form"));
|
|
|
|
|
|
|
|
if (bot_type === OUTGOING_WEBHOOK_BOT_TYPE) {
|
|
|
|
$("#service_data").append(
|
2024-04-04 00:18:17 +02:00
|
|
|
$(
|
|
|
|
render_settings_edit_outgoing_webhook_service({
|
|
|
|
service,
|
|
|
|
}),
|
|
|
|
),
|
2023-09-25 11:29:07 +02:00
|
|
|
);
|
|
|
|
$("#edit_service_interface").val(service.interface);
|
|
|
|
}
|
|
|
|
if (bot_type === EMBEDDED_BOT_TYPE) {
|
|
|
|
$("#service_data").append(
|
2024-04-04 00:18:17 +02:00
|
|
|
$(
|
|
|
|
render_settings_edit_embedded_bot_service({
|
|
|
|
service,
|
|
|
|
}),
|
|
|
|
),
|
2023-09-25 11:29:07 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hide the avatar if the user has uploaded an image
|
|
|
|
$("#bot-edit-form").on("input", ".edit_bot_avatar_file_input", () => {
|
|
|
|
$("#current_bot_avatar_image").hide();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Show the avatar if the user has cleared the image
|
|
|
|
$("#bot-edit-form").on("click", ".edit_bot_avatar_clear_button", () => {
|
|
|
|
$("#current_bot_avatar_image").show();
|
|
|
|
$(".edit_bot_avatar_file_input").trigger("input");
|
|
|
|
});
|
|
|
|
|
|
|
|
$("#bot-edit-form").on("click", ".deactivate_bot_button", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
const bot_id = $("#bot-edit-form").data("user-id");
|
|
|
|
function handle_confirm() {
|
|
|
|
const url = "/json/bots/" + encodeURIComponent(bot_id);
|
2024-04-04 03:36:46 +02:00
|
|
|
dialog_widget.submit_api_request(channel.del, url, {});
|
2023-09-25 11:29:07 +02:00
|
|
|
}
|
2023-09-25 19:19:40 +02:00
|
|
|
user_deactivation_ui.confirm_bot_deactivation(bot_id, handle_confirm, true);
|
2023-09-25 11:29:07 +02:00
|
|
|
});
|
|
|
|
|
2023-09-27 08:41:31 +02:00
|
|
|
// Handle reactivation
|
|
|
|
$("#bot-edit-form").on("click", ".reactivate_user_button", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
const user_id = $("#bot-edit-form").data("user-id");
|
|
|
|
function handle_confirm() {
|
|
|
|
const url = "/json/users/" + encodeURIComponent(user_id) + "/reactivate";
|
2024-04-04 03:36:46 +02:00
|
|
|
dialog_widget.submit_api_request(channel.post, url, {});
|
2023-09-27 08:41:31 +02:00
|
|
|
}
|
|
|
|
user_deactivation_ui.confirm_reactivation(user_id, handle_confirm, true);
|
|
|
|
});
|
|
|
|
|
2023-09-25 11:29:07 +02:00
|
|
|
$("#bot-edit-form").on("click", ".generate_url_for_integration", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
const current_bot_data = bot_data.get(bot.user_id);
|
2023-09-25 19:13:40 +02:00
|
|
|
integration_url_modal.show_generate_integration_url_modal(current_bot_data.api_key);
|
2023-09-25 11:29:07 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 12:15:17 +02:00
|
|
|
function get_human_profile_data(fields_user_pills) {
|
|
|
|
/*
|
|
|
|
This formats custom profile field data to send to the server.
|
|
|
|
See render_admin_human_form and open_human_form
|
|
|
|
to see how the form is built.
|
|
|
|
|
|
|
|
TODO: Ideally, this logic would be cleaned up or deduplicated with
|
|
|
|
the settings_account.js logic.
|
|
|
|
*/
|
|
|
|
const new_profile_data = [];
|
|
|
|
$("#edit-user-form .custom_user_field_value").each(function () {
|
|
|
|
// Remove duplicate datepicker input element generated flatpickr library
|
|
|
|
if (!$(this).hasClass("form-control")) {
|
|
|
|
new_profile_data.push({
|
|
|
|
id: Number.parseInt(
|
|
|
|
$(this).closest(".custom_user_field").attr("data-field-id"),
|
|
|
|
10,
|
|
|
|
),
|
|
|
|
value: $(this).val(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// Append user type field values also
|
|
|
|
for (const [field_id, field_pills] of fields_user_pills) {
|
|
|
|
if (field_pills) {
|
|
|
|
const user_ids = user_pill.get_user_ids(field_pills);
|
|
|
|
new_profile_data.push({
|
|
|
|
id: field_id,
|
|
|
|
value: user_ids,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_profile_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function show_edit_user_info_modal(user_id, $container) {
|
|
|
|
const person = people.maybe_get_user_by_id(user_id);
|
2023-09-27 08:41:31 +02:00
|
|
|
const is_active = people.is_person_active(user_id);
|
2023-09-25 12:15:17 +02:00
|
|
|
|
|
|
|
if (!person) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const html_body = render_admin_human_form({
|
|
|
|
user_id,
|
|
|
|
email: person.delivery_email,
|
|
|
|
full_name: person.full_name,
|
|
|
|
user_role_values: settings_config.user_role_values,
|
2024-02-13 02:08:16 +01:00
|
|
|
disable_role_dropdown: person.is_owner && !current_user.is_owner,
|
2023-09-25 12:15:17 +02:00
|
|
|
owner_is_only_user_in_organization: people.get_active_human_count() === 1,
|
2023-09-27 08:41:31 +02:00
|
|
|
is_active,
|
2023-09-25 12:15:17 +02:00
|
|
|
});
|
|
|
|
|
2024-04-04 00:18:17 +02:00
|
|
|
$container.append($(html_body));
|
2023-09-25 12:15:17 +02:00
|
|
|
// Set role dropdown and fields user pills
|
|
|
|
$("#user-role-select").val(person.role);
|
2024-02-13 02:08:16 +01:00
|
|
|
if (!current_user.is_owner) {
|
2023-09-25 12:15:17 +02:00
|
|
|
$("#user-role-select")
|
|
|
|
.find(`option[value="${CSS.escape(settings_config.user_role_values.owner.code)}"]`)
|
|
|
|
.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
const custom_profile_field_form_selector = "#edit-user-form .custom-profile-field-form";
|
|
|
|
$(custom_profile_field_form_selector).empty();
|
2023-09-25 13:16:40 +02:00
|
|
|
custom_profile_fields_ui.append_custom_profile_fields(
|
|
|
|
custom_profile_field_form_selector,
|
|
|
|
user_id,
|
|
|
|
);
|
|
|
|
custom_profile_fields_ui.initialize_custom_date_type_fields(custom_profile_field_form_selector);
|
|
|
|
custom_profile_fields_ui.initialize_custom_pronouns_type_fields(
|
|
|
|
custom_profile_field_form_selector,
|
|
|
|
);
|
|
|
|
const fields_user_pills = custom_profile_fields_ui.initialize_custom_user_type_fields(
|
2023-09-25 12:15:17 +02:00
|
|
|
custom_profile_field_form_selector,
|
|
|
|
user_id,
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Handle deactivation
|
|
|
|
$("#edit-user-form").on("click", ".deactivate_user_button", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
const user_id = $("#edit-user-form").data("user-id");
|
|
|
|
function handle_confirm() {
|
|
|
|
const url = "/json/users/" + encodeURIComponent(user_id);
|
2024-04-04 03:36:46 +02:00
|
|
|
dialog_widget.submit_api_request(channel.del, url, {});
|
2023-09-25 12:15:17 +02:00
|
|
|
}
|
2023-09-25 19:19:40 +02:00
|
|
|
user_deactivation_ui.confirm_deactivation(user_id, handle_confirm, true);
|
2023-09-25 12:15:17 +02:00
|
|
|
});
|
|
|
|
|
2023-09-27 08:41:31 +02:00
|
|
|
// Handle reactivation
|
|
|
|
$("#edit-user-form").on("click", ".reactivate_user_button", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
const user_id = $("#edit-user-form").data("user-id");
|
|
|
|
function handle_confirm() {
|
|
|
|
const url = "/json/users/" + encodeURIComponent(user_id) + "/reactivate";
|
2024-04-04 03:36:46 +02:00
|
|
|
dialog_widget.submit_api_request(channel.post, url, {});
|
2023-09-27 08:41:31 +02:00
|
|
|
}
|
|
|
|
user_deactivation_ui.confirm_reactivation(user_id, handle_confirm, true);
|
|
|
|
});
|
|
|
|
|
2023-09-25 12:15:17 +02:00
|
|
|
$("#user-profile-modal").on("click", ".dialog_submit_button", () => {
|
|
|
|
const role = Number.parseInt($("#user-role-select").val().trim(), 10);
|
|
|
|
const $full_name = $("#edit-user-form").find("input[name='full_name']");
|
|
|
|
const profile_data = get_human_profile_data(fields_user_pills);
|
|
|
|
|
|
|
|
const url = "/json/users/" + encodeURIComponent(user_id);
|
|
|
|
const data = {
|
|
|
|
full_name: $full_name.val(),
|
|
|
|
role: JSON.stringify(role),
|
|
|
|
profile_data: JSON.stringify(profile_data),
|
|
|
|
};
|
|
|
|
|
|
|
|
const $submit_btn = $("#user-profile-modal .dialog_submit_button");
|
|
|
|
const $cancel_btn = $("#user-profile-modal .dialog_exit_button");
|
2023-09-27 19:09:10 +02:00
|
|
|
show_button_spinner($submit_btn);
|
2023-09-25 12:15:17 +02:00
|
|
|
$cancel_btn.prop("disabled", true);
|
|
|
|
|
|
|
|
channel.patch({
|
|
|
|
url,
|
|
|
|
data,
|
|
|
|
success() {
|
|
|
|
hide_user_profile();
|
|
|
|
},
|
|
|
|
error(xhr) {
|
|
|
|
ui_report.error(
|
|
|
|
$t_html({defaultMessage: "Failed"}),
|
|
|
|
xhr,
|
|
|
|
$("#edit-user-form-error"),
|
|
|
|
);
|
|
|
|
// Scrolling modal to top, to make error visible to user.
|
|
|
|
$("#edit-user-form")
|
|
|
|
.closest(".simplebar-content-wrapper")
|
|
|
|
.animate({scrollTop: 0}, "fast");
|
2023-09-27 19:09:10 +02:00
|
|
|
hide_button_spinner($submit_btn);
|
2023-09-25 12:15:17 +02:00
|
|
|
$cancel_btn.prop("disabled", false);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-29 10:25:25 +02:00
|
|
|
export function initialize() {
|
2023-09-08 19:37:58 +02:00
|
|
|
$("body").on("click", "#user-profile-modal .add-subscription-button", (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
const stream_id = Number.parseInt(user_profile_subscribe_widget.value(), 10);
|
|
|
|
const sub = sub_store.get(stream_id);
|
|
|
|
const target_user_id = Number.parseInt($("#user-profile-modal").attr("data-user-id"), 10);
|
|
|
|
const $alert_box = $("#user-profile-streams-tab .stream_list_info");
|
|
|
|
function addition_success(data) {
|
|
|
|
if (Object.keys(data.subscribed).length > 0) {
|
2023-09-08 16:35:13 +02:00
|
|
|
reset_subscribe_widget();
|
2023-09-08 19:37:58 +02:00
|
|
|
ui_report.success(
|
|
|
|
$t_html({defaultMessage: "Subscribed successfully!"}),
|
|
|
|
$alert_box,
|
|
|
|
1200,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
ui_report.client_error(
|
|
|
|
$t_html({defaultMessage: "Already subscribed."}),
|
|
|
|
$alert_box,
|
|
|
|
1200,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function addition_failure(xhr) {
|
|
|
|
ui_report.error("", xhr, $alert_box, 1200);
|
|
|
|
}
|
|
|
|
subscriber_api.add_user_ids_to_stream(
|
|
|
|
[target_user_id],
|
|
|
|
sub,
|
|
|
|
addition_success,
|
|
|
|
addition_failure,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2021-06-30 23:07:02 +02:00
|
|
|
$("body").on("click", "#user-profile-modal .remove-subscription-button", (e) => {
|
|
|
|
e.preventDefault();
|
2022-01-25 11:36:19 +01:00
|
|
|
const $stream_row = $(e.currentTarget).closest("[data-stream-id]");
|
|
|
|
const stream_id = Number.parseInt($stream_row.attr("data-stream-id"), 10);
|
2021-06-30 23:07:02 +02:00
|
|
|
const sub = sub_store.get(stream_id);
|
2023-09-10 19:47:48 +02:00
|
|
|
const target_user_id = Number.parseInt($("#user-profile-modal").attr("data-user-id"), 10);
|
2022-01-25 11:36:19 +01:00
|
|
|
const $alert_box = $("#user-profile-streams-tab .stream_list_info");
|
2021-06-30 23:07:02 +02:00
|
|
|
|
|
|
|
function removal_success(data) {
|
|
|
|
if (data.removed.length > 0) {
|
|
|
|
ui_report.success(
|
|
|
|
$t_html({defaultMessage: "Unsubscribed successfully!"}),
|
2022-01-25 11:36:19 +01:00
|
|
|
$alert_box,
|
2021-06-30 23:07:02 +02:00
|
|
|
1200,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
ui_report.client_error(
|
|
|
|
$t_html({defaultMessage: "Already not subscribed."}),
|
2022-01-25 11:36:19 +01:00
|
|
|
$alert_box,
|
2021-06-30 23:07:02 +02:00
|
|
|
1200,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function removal_failure() {
|
|
|
|
let error_message;
|
|
|
|
if (people.is_my_user_id(target_user_id)) {
|
|
|
|
error_message = $t(
|
2024-04-18 18:36:57 +02:00
|
|
|
{defaultMessage: "Error in unsubscribing from #{channel_name}"},
|
|
|
|
{channel_name: sub.name},
|
2021-06-30 23:07:02 +02:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
error_message = $t(
|
2024-04-18 18:36:57 +02:00
|
|
|
{defaultMessage: "Error removing user from #{channel_name}"},
|
|
|
|
{channel_name: sub.name},
|
2021-06-30 23:07:02 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
ui_report.client_error(error_message, $alert_box, 1200);
|
2021-06-30 23:07:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-15 13:13:19 +01:00
|
|
|
if (
|
|
|
|
sub.invite_only &&
|
|
|
|
(people.is_my_user_id(target_user_id) ||
|
|
|
|
peer_data.get_subscriber_count(stream_id) === 1)
|
|
|
|
) {
|
2023-11-09 20:28:32 +01:00
|
|
|
const new_hash = hash_util.stream_edit_url(sub, "general");
|
2021-06-30 23:07:02 +02:00
|
|
|
hide_user_profile();
|
|
|
|
browser_history.go_to_location(new_hash);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
handle_remove_stream_subscription(target_user_id, sub, removal_success, removal_failure);
|
|
|
|
});
|
|
|
|
|
2021-06-30 22:17:19 +02:00
|
|
|
$("body").on("click", "#user-profile-modal #clear_stream_search", (e) => {
|
2022-01-25 11:36:19 +01:00
|
|
|
const $input = $("#user-profile-streams-tab .stream-search");
|
|
|
|
$input.val("");
|
2021-06-30 22:17:19 +02:00
|
|
|
|
|
|
|
// This is a hack to rerender complete
|
|
|
|
// stream list once the text is cleared.
|
2022-01-25 11:36:19 +01:00
|
|
|
$input.trigger("input");
|
2021-06-30 22:17:19 +02:00
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
2023-09-09 13:13:14 +02:00
|
|
|
|
|
|
|
$("body").on(
|
|
|
|
"click",
|
2023-08-17 13:40:56 +02:00
|
|
|
"#user-profile-modal #name .user_profile_manage_others_edit_button",
|
2023-09-09 13:13:14 +02:00
|
|
|
(e) => {
|
|
|
|
show_manage_user_tab("manage-profile-tab");
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
},
|
|
|
|
);
|
2023-08-17 13:40:56 +02:00
|
|
|
|
2021-06-23 20:48:49 +02:00
|
|
|
/* These click handlers are implemented as just deep links to the
|
|
|
|
* relevant part of the Zulip UI, so we don't want preventDefault,
|
|
|
|
* but we do want to close the modal when you click them. */
|
2023-08-17 13:40:56 +02:00
|
|
|
$("body").on("click", "#user-profile-modal #name .user_profile_manage_own_edit_button", () => {
|
2021-06-23 20:48:49 +02:00
|
|
|
hide_user_profile();
|
|
|
|
});
|
|
|
|
|
|
|
|
$("body").on("click", "#user-profile-modal .stream_list_item", () => {
|
|
|
|
hide_user_profile();
|
|
|
|
});
|
2021-06-30 22:17:19 +02:00
|
|
|
|
2024-02-20 16:12:46 +01:00
|
|
|
$("body").on("click", "#user-profile-modal .group_list_item_link", () => {
|
|
|
|
hide_user_profile();
|
|
|
|
});
|
|
|
|
|
2021-07-02 21:25:50 +02:00
|
|
|
$("body").on("input", "#user-profile-streams-tab .stream-search", () => {
|
2022-01-25 11:36:19 +01:00
|
|
|
const $input = $("#user-profile-streams-tab .stream-search");
|
|
|
|
if ($input.val().trim().length > 0) {
|
2021-07-02 21:25:50 +02:00
|
|
|
$("#user-profile-streams-tab #clear_stream_search").show();
|
2022-01-25 11:36:19 +01:00
|
|
|
$input.css("margin-right", "-20px");
|
2021-06-30 22:17:19 +02:00
|
|
|
} else {
|
2021-07-02 21:25:50 +02:00
|
|
|
$("#user-profile-streams-tab #clear_stream_search").hide();
|
2022-01-25 11:36:19 +01:00
|
|
|
$input.css("margin-right", "0");
|
2021-06-30 22:17:19 +02:00
|
|
|
}
|
|
|
|
});
|
2024-01-25 15:45:10 +01:00
|
|
|
|
|
|
|
new ClipboardJS(".copy_link_to_user_profile", {
|
|
|
|
text(trigger) {
|
|
|
|
const user_id = $(trigger).attr("data-user-id");
|
|
|
|
const user_profile_link = window.location.origin + "/#user/" + user_id;
|
|
|
|
|
|
|
|
return user_profile_link;
|
|
|
|
},
|
|
|
|
}).on("success", (e) => {
|
|
|
|
show_copied_confirmation(e.trigger);
|
|
|
|
});
|
2021-06-23 20:48:49 +02:00
|
|
|
}
|