mirror of https://github.com/zulip/zulip.git
reactions: Convert module to typescript.
This commit is contained in:
parent
07671997ca
commit
fb7d77545f
|
@ -1,5 +1,6 @@
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
|
import type {RawReaction} from "./reactions";
|
||||||
import type {Submessage, TopicLink} from "./types";
|
import type {Submessage, TopicLink} from "./types";
|
||||||
|
|
||||||
const stored_messages = new Map();
|
const stored_messages = new Map();
|
||||||
|
@ -106,6 +107,8 @@ export type Message = (
|
||||||
| Omit<MessageWithBooleans & {type: "private"}, "reactions">
|
| Omit<MessageWithBooleans & {type: "private"}, "reactions">
|
||||||
| Omit<MessageWithBooleans & {type: "stream"}, "reactions">
|
| Omit<MessageWithBooleans & {type: "stream"}, "reactions">
|
||||||
) & {
|
) & {
|
||||||
|
// Replaced by `clean_reactions` in `reactions.set_clean_reactions`.
|
||||||
|
reactions?: RawReaction[];
|
||||||
// Added in `reactions.set_clean_reactions`.
|
// Added in `reactions.set_clean_reactions`.
|
||||||
clean_reactions: Map<string, MessageCleanReaction>;
|
clean_reactions: Map<string, MessageCleanReaction>;
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,48 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import assert from "minimalistic-assert";
|
||||||
|
|
||||||
import render_message_reaction from "../templates/message_reaction.hbs";
|
import render_message_reaction from "../templates/message_reaction.hbs";
|
||||||
|
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
import * as channel from "./channel";
|
import * as channel from "./channel";
|
||||||
import * as emoji from "./emoji";
|
import * as emoji from "./emoji";
|
||||||
|
import type {EmojiRenderingDetails} from "./emoji";
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
import * as message_store from "./message_store";
|
import * as message_store from "./message_store";
|
||||||
|
import type {Message, MessageCleanReaction} from "./message_store";
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
import * as spectators from "./spectators";
|
import * as spectators from "./spectators";
|
||||||
import {current_user} from "./state_data";
|
import {current_user} from "./state_data";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
|
||||||
const waiting_for_server_request_ids = new Set();
|
const waiting_for_server_request_ids = new Set<string>();
|
||||||
|
|
||||||
export function get_local_reaction_id(rendering_details) {
|
type ReactionEvent = {
|
||||||
|
message_id: number;
|
||||||
|
user_id: number;
|
||||||
|
local_id: string;
|
||||||
|
reaction_type: string;
|
||||||
|
emoji_name: string;
|
||||||
|
emoji_code: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function get_local_reaction_id(rendering_details: EmojiRenderingDetails): string {
|
||||||
return [rendering_details.reaction_type, rendering_details.emoji_code].join(",");
|
return [rendering_details.reaction_type, rendering_details.emoji_code].join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function current_user_has_reacted_to_emoji(message, local_id) {
|
export function current_user_has_reacted_to_emoji(message: Message, local_id: string): boolean {
|
||||||
set_clean_reactions(message);
|
set_clean_reactions(message);
|
||||||
|
|
||||||
const clean_reaction_object = message.clean_reactions.get(local_id);
|
const clean_reaction_object = message.clean_reactions.get(local_id);
|
||||||
return clean_reaction_object && clean_reaction_object.user_ids.includes(current_user.user_id);
|
return (
|
||||||
|
clean_reaction_object !== undefined &&
|
||||||
|
clean_reaction_object.user_ids.includes(current_user.user_id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_message(message_id) {
|
function get_message(message_id: number): Message | undefined {
|
||||||
const message = message_store.get(message_id);
|
const message = message_store.get(message_id);
|
||||||
if (!message) {
|
if (!message) {
|
||||||
blueslip.error("reactions: Bad message id", {message_id});
|
blueslip.error("reactions: Bad message id", {message_id});
|
||||||
|
@ -38,7 +53,17 @@ function get_message(message_id) {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_reaction(message_id, rendering_details) {
|
export type RawReaction = {
|
||||||
|
emoji_name: string;
|
||||||
|
reaction_type: string;
|
||||||
|
emoji_code: string;
|
||||||
|
user_id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function create_reaction(
|
||||||
|
message_id: number,
|
||||||
|
rendering_details: EmojiRenderingDetails,
|
||||||
|
): ReactionEvent {
|
||||||
return {
|
return {
|
||||||
message_id,
|
message_id,
|
||||||
user_id: current_user.user_id,
|
user_id: current_user.user_id,
|
||||||
|
@ -49,7 +74,10 @@ function create_reaction(message_id, rendering_details) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_ui_and_send_reaction_ajax(message_id, rendering_details) {
|
function update_ui_and_send_reaction_ajax(
|
||||||
|
message_id: number,
|
||||||
|
rendering_details: EmojiRenderingDetails,
|
||||||
|
): void {
|
||||||
if (page_params.is_spectator) {
|
if (page_params.is_spectator) {
|
||||||
// Spectators can't react, since they don't have accounts. We
|
// Spectators can't react, since they don't have accounts. We
|
||||||
// stop here to avoid a confusing reaction local echo.
|
// stop here to avoid a confusing reaction local echo.
|
||||||
|
@ -58,6 +86,9 @@ function update_ui_and_send_reaction_ajax(message_id, rendering_details) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = get_message(message_id);
|
const message = get_message(message_id);
|
||||||
|
if (message === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const local_id = get_local_reaction_id(rendering_details);
|
const local_id = get_local_reaction_id(rendering_details);
|
||||||
const has_reacted = current_user_has_reacted_to_emoji(message, local_id);
|
const has_reacted = current_user_has_reacted_to_emoji(message, local_id);
|
||||||
const operation = has_reacted ? "remove" : "add";
|
const operation = has_reacted ? "remove" : "add";
|
||||||
|
@ -83,7 +114,7 @@ function update_ui_and_send_reaction_ajax(message_id, rendering_details) {
|
||||||
success() {
|
success() {
|
||||||
waiting_for_server_request_ids.delete(reaction_request_id);
|
waiting_for_server_request_ids.delete(reaction_request_id);
|
||||||
},
|
},
|
||||||
error(xhr) {
|
error(xhr: JQuery.jqXHR) {
|
||||||
waiting_for_server_request_ids.delete(reaction_request_id);
|
waiting_for_server_request_ids.delete(reaction_request_id);
|
||||||
if (xhr.readyState !== 0) {
|
if (xhr.readyState !== 0) {
|
||||||
if (
|
if (
|
||||||
|
@ -101,13 +132,13 @@ function update_ui_and_send_reaction_ajax(message_id, rendering_details) {
|
||||||
|
|
||||||
waiting_for_server_request_ids.add(reaction_request_id);
|
waiting_for_server_request_ids.add(reaction_request_id);
|
||||||
if (operation === "add") {
|
if (operation === "add") {
|
||||||
channel.post(args);
|
void channel.post(args);
|
||||||
} else if (operation === "remove") {
|
} else if (operation === "remove") {
|
||||||
channel.del(args);
|
void channel.del(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toggle_emoji_reaction(message_id, emoji_name) {
|
export function toggle_emoji_reaction(message_id: number, emoji_name: string): void {
|
||||||
// This codepath doesn't support toggling a deactivated realm emoji.
|
// This codepath doesn't support toggling a deactivated realm emoji.
|
||||||
// Since a user can interact with a deactivated realm emoji only by
|
// Since a user can interact with a deactivated realm emoji only by
|
||||||
// clicking on a reaction and that is handled by `process_reaction_click()`
|
// clicking on a reaction and that is handled by `process_reaction_click()`
|
||||||
|
@ -118,7 +149,7 @@ export function toggle_emoji_reaction(message_id, emoji_name) {
|
||||||
update_ui_and_send_reaction_ajax(message_id, rendering_details);
|
update_ui_and_send_reaction_ajax(message_id, rendering_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function process_reaction_click(message_id, local_id) {
|
export function process_reaction_click(message_id: number, local_id: string): void {
|
||||||
const message = get_message(message_id);
|
const message = get_message(message_id);
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
|
@ -142,26 +173,33 @@ export function process_reaction_click(message_id, local_id) {
|
||||||
update_ui_and_send_reaction_ajax(message_id, rendering_details);
|
update_ui_and_send_reaction_ajax(message_id, rendering_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_title(emoji_name, user_ids) {
|
function generate_title(emoji_name: string, user_ids: number[]): string {
|
||||||
const usernames = people.get_display_full_names(
|
const usernames = people.get_display_full_names(
|
||||||
user_ids.filter((user_id) => user_id !== current_user.user_id),
|
user_ids.filter((user_id) => user_id !== current_user.user_id),
|
||||||
);
|
);
|
||||||
const current_user_reacted = user_ids.length !== usernames.length;
|
const current_user_reacted = user_ids.length !== usernames.length;
|
||||||
|
|
||||||
const context = {
|
const colon_emoji_name = ":" + emoji_name + ":";
|
||||||
emoji_name: ":" + emoji_name + ":",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (user_ids.length === 1) {
|
if (user_ids.length === 1) {
|
||||||
if (current_user_reacted) {
|
if (current_user_reacted) {
|
||||||
|
const context = {
|
||||||
|
emoji_name: colon_emoji_name,
|
||||||
|
};
|
||||||
return $t({defaultMessage: "You (click to remove) reacted with {emoji_name}"}, context);
|
return $t({defaultMessage: "You (click to remove) reacted with {emoji_name}"}, context);
|
||||||
}
|
}
|
||||||
context.username = usernames[0];
|
const context = {
|
||||||
|
emoji_name: colon_emoji_name,
|
||||||
|
username: usernames[0],
|
||||||
|
};
|
||||||
return $t({defaultMessage: "{username} reacted with {emoji_name}"}, context);
|
return $t({defaultMessage: "{username} reacted with {emoji_name}"}, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_ids.length === 2 && current_user_reacted) {
|
if (user_ids.length === 2 && current_user_reacted) {
|
||||||
context.other_username = usernames[0];
|
const context = {
|
||||||
|
emoji_name: colon_emoji_name,
|
||||||
|
other_username: usernames[0],
|
||||||
|
};
|
||||||
return $t(
|
return $t(
|
||||||
{
|
{
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
|
@ -171,8 +209,11 @@ function generate_title(emoji_name, user_ids) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.comma_separated_usernames = usernames.slice(0, -1).join(", ");
|
const context = {
|
||||||
context.last_username = usernames.at(-1);
|
emoji_name: colon_emoji_name,
|
||||||
|
comma_separated_usernames: usernames.slice(0, -1).join(", "),
|
||||||
|
last_username: usernames.at(-1),
|
||||||
|
};
|
||||||
if (current_user_reacted) {
|
if (current_user_reacted) {
|
||||||
return $t(
|
return $t(
|
||||||
{
|
{
|
||||||
|
@ -192,10 +233,13 @@ function generate_title(emoji_name, user_ids) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a tooltip showing who reacted to a message.
|
// Add a tooltip showing who reacted to a message.
|
||||||
export function get_reaction_title_data(message_id, local_id) {
|
export function get_reaction_title_data(message_id: number, local_id: string): string {
|
||||||
const message = get_message(message_id);
|
const message = get_message(message_id);
|
||||||
|
assert(message !== undefined);
|
||||||
|
|
||||||
const clean_reaction_object = message.clean_reactions.get(local_id);
|
const clean_reaction_object = message.clean_reactions.get(local_id);
|
||||||
|
assert(clean_reaction_object !== undefined);
|
||||||
|
|
||||||
const user_list = clean_reaction_object.user_ids;
|
const user_list = clean_reaction_object.user_ids;
|
||||||
const emoji_name = clean_reaction_object.emoji_name;
|
const emoji_name = clean_reaction_object.emoji_name;
|
||||||
const title = generate_title(emoji_name, user_list);
|
const title = generate_title(emoji_name, user_list);
|
||||||
|
@ -203,29 +247,29 @@ export function get_reaction_title_data(message_id, local_id) {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_reaction_sections(message_id) {
|
export function get_reaction_sections(message_id: number): JQuery {
|
||||||
const $rows = message_lists.all_rendered_row_for_message_id(message_id);
|
const $rows = message_lists.all_rendered_row_for_message_id(message_id);
|
||||||
return $rows.find(".message_reactions");
|
return $rows.find(".message_reactions");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function find_reaction(message_id, local_id) {
|
export function find_reaction(message_id: number, local_id: string): JQuery {
|
||||||
const $reaction_section = get_reaction_sections(message_id);
|
const $reaction_section = get_reaction_sections(message_id);
|
||||||
const $reaction = $reaction_section.find(`[data-reaction-id='${CSS.escape(local_id)}']`);
|
const $reaction = $reaction_section.find(`[data-reaction-id='${CSS.escape(local_id)}']`);
|
||||||
return $reaction;
|
return $reaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_add_reaction_button(message_id) {
|
export function get_add_reaction_button(message_id: number): JQuery {
|
||||||
const $reaction_section = get_reaction_sections(message_id);
|
const $reaction_section = get_reaction_sections(message_id);
|
||||||
const $add_button = $reaction_section.find(".reaction_button");
|
const $add_button = $reaction_section.find(".reaction_button");
|
||||||
return $add_button;
|
return $add_button;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set_reaction_vote_text($reaction, vote_text) {
|
export function set_reaction_vote_text($reaction: JQuery, vote_text: string): void {
|
||||||
const $count_element = $reaction.find(".message_reaction_count");
|
const $count_element = $reaction.find(".message_reaction_count");
|
||||||
$count_element.text(vote_text);
|
$count_element.text(vote_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function add_reaction(event) {
|
export function add_reaction(event: ReactionEvent): void {
|
||||||
const message_id = event.message_id;
|
const message_id = event.message_id;
|
||||||
const message = message_store.get(message_id);
|
const message = message_store.get(message_id);
|
||||||
|
|
||||||
|
@ -271,7 +315,11 @@ export function add_reaction(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_existing_reaction(clean_reaction_object, message, acting_user_id) {
|
export function update_existing_reaction(
|
||||||
|
clean_reaction_object: MessageCleanReaction,
|
||||||
|
message: Message,
|
||||||
|
acting_user_id: number,
|
||||||
|
): void {
|
||||||
// Our caller ensures that this message already has a reaction
|
// Our caller ensures that this message already has a reaction
|
||||||
// for this emoji and sets up our user_list. This function
|
// for this emoji and sets up our user_list. This function
|
||||||
// simply updates the DOM.
|
// simply updates the DOM.
|
||||||
|
@ -291,34 +339,38 @@ export function update_existing_reaction(clean_reaction_object, message, acting_
|
||||||
update_vote_text_on_message(message);
|
update_vote_text_on_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insert_new_reaction(clean_reaction_object, message, user_id) {
|
export function insert_new_reaction(
|
||||||
|
clean_reaction_object: MessageCleanReaction,
|
||||||
|
message: Message,
|
||||||
|
user_id: number,
|
||||||
|
): void {
|
||||||
// Our caller ensures we are the first user to react to this
|
// Our caller ensures we are the first user to react to this
|
||||||
// message with this emoji. We then render the emoji/title/count
|
// message with this emoji. We then render the emoji/title/count
|
||||||
// and insert it before the add button.
|
// and insert it before the add button.
|
||||||
|
|
||||||
const context = {
|
const emoji_details = emoji.get_emoji_details_for_rendering(clean_reaction_object);
|
||||||
message_id: message.id,
|
|
||||||
...emoji.get_emoji_details_for_rendering(clean_reaction_object),
|
|
||||||
};
|
|
||||||
|
|
||||||
const new_label = generate_title(
|
const new_label = generate_title(
|
||||||
clean_reaction_object.emoji_name,
|
clean_reaction_object.emoji_name,
|
||||||
clean_reaction_object.user_ids,
|
clean_reaction_object.user_ids,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.count = 1;
|
const is_realm_emoji =
|
||||||
context.label = new_label;
|
emoji_details.reaction_type === "realm_emoji" ||
|
||||||
context.local_id = get_local_reaction_id(clean_reaction_object);
|
emoji_details.reaction_type === "zulip_extra_emoji";
|
||||||
context.emoji_alt_code = user_settings.emojiset === "text";
|
const reaction_class =
|
||||||
context.is_realm_emoji =
|
user_id === current_user.user_id ? "message_reaction reacted" : "message_reaction";
|
||||||
context.reaction_type === "realm_emoji" || context.reaction_type === "zulip_extra_emoji";
|
|
||||||
context.vote_text = ""; // Updated below
|
|
||||||
|
|
||||||
if (user_id === current_user.user_id) {
|
const context = {
|
||||||
context.class = "message_reaction reacted";
|
message_id: message.id,
|
||||||
} else {
|
...emoji_details,
|
||||||
context.class = "message_reaction";
|
count: 1,
|
||||||
}
|
label: new_label,
|
||||||
|
local_id: get_local_reaction_id(clean_reaction_object),
|
||||||
|
emoji_alt_code: user_settings.emojiset === "text",
|
||||||
|
is_realm_emoji,
|
||||||
|
vote_text: "", // Updated below
|
||||||
|
class: reaction_class,
|
||||||
|
};
|
||||||
|
|
||||||
const $new_reaction = $(render_message_reaction(context));
|
const $new_reaction = $(render_message_reaction(context));
|
||||||
|
|
||||||
|
@ -329,7 +381,7 @@ export function insert_new_reaction(clean_reaction_object, message, user_id) {
|
||||||
update_vote_text_on_message(message);
|
update_vote_text_on_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function remove_reaction(event) {
|
export function remove_reaction(event: ReactionEvent): void {
|
||||||
const message_id = event.message_id;
|
const message_id = event.message_id;
|
||||||
const user_id = event.user_id;
|
const user_id = event.user_id;
|
||||||
const message = message_store.get(message_id);
|
const message = message_store.get(message_id);
|
||||||
|
@ -366,7 +418,11 @@ export function remove_reaction(event) {
|
||||||
remove_reaction_from_view(clean_reaction_object, message, user_id);
|
remove_reaction_from_view(clean_reaction_object, message, user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function remove_reaction_from_view(clean_reaction_object, message, user_id) {
|
export function remove_reaction_from_view(
|
||||||
|
clean_reaction_object: MessageCleanReaction,
|
||||||
|
message: Message,
|
||||||
|
user_id: number,
|
||||||
|
): void {
|
||||||
const local_id = get_local_reaction_id(clean_reaction_object);
|
const local_id = get_local_reaction_id(clean_reaction_object);
|
||||||
const $reaction = find_reaction(message.id, local_id);
|
const $reaction = find_reaction(message.id, local_id);
|
||||||
const reaction_count = clean_reaction_object.user_ids.length;
|
const reaction_count = clean_reaction_object.user_ids.length;
|
||||||
|
@ -394,9 +450,11 @@ export function remove_reaction_from_view(clean_reaction_object, message, user_i
|
||||||
update_vote_text_on_message(message);
|
update_vote_text_on_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_emojis_used_by_user_for_message_id(message_id) {
|
export function get_emojis_used_by_user_for_message_id(message_id: number): string[] {
|
||||||
const user_id = current_user.user_id;
|
const user_id = current_user.user_id;
|
||||||
|
assert(user_id !== undefined);
|
||||||
const message = message_store.get(message_id);
|
const message = message_store.get(message_id);
|
||||||
|
assert(message !== undefined);
|
||||||
set_clean_reactions(message);
|
set_clean_reactions(message);
|
||||||
|
|
||||||
const names = [];
|
const names = [];
|
||||||
|
@ -409,12 +467,12 @@ export function get_emojis_used_by_user_for_message_id(message_id) {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_message_reactions(message) {
|
export function get_message_reactions(message: Message): MessageCleanReaction[] {
|
||||||
set_clean_reactions(message);
|
set_clean_reactions(message);
|
||||||
return [...message.clean_reactions.values()];
|
return [...message.clean_reactions.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set_clean_reactions(message) {
|
export function set_clean_reactions(message: Message): void {
|
||||||
/*
|
/*
|
||||||
set_clean_reactions processes the raw message.reactions object,
|
set_clean_reactions processes the raw message.reactions object,
|
||||||
which will contain one object for each individual reaction, even
|
which will contain one object for each individual reaction, even
|
||||||
|
@ -441,8 +499,9 @@ export function set_clean_reactions(message) {
|
||||||
// This first loop creates a temporary distinct_reactions data
|
// This first loop creates a temporary distinct_reactions data
|
||||||
// structure, which will accumulate the set of users who have
|
// structure, which will accumulate the set of users who have
|
||||||
// reacted with each distinct reaction.
|
// reacted with each distinct reaction.
|
||||||
const distinct_reactions = new Map();
|
assert(message.reactions !== undefined);
|
||||||
const user_map = new Map();
|
const distinct_reactions = new Map<string, RawReaction>();
|
||||||
|
const user_map = new Map<string, number[]>();
|
||||||
for (const reaction of message.reactions) {
|
for (const reaction of message.reactions) {
|
||||||
const local_id = get_local_reaction_id(reaction);
|
const local_id = get_local_reaction_id(reaction);
|
||||||
const user_id = reaction.user_id;
|
const user_id = reaction.user_id;
|
||||||
|
@ -452,7 +511,7 @@ export function set_clean_reactions(message) {
|
||||||
user_map.set(local_id, []);
|
user_map.set(local_id, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
const user_ids = user_map.get(local_id);
|
const user_ids = user_map.get(local_id)!;
|
||||||
|
|
||||||
if (user_ids.includes(user_id)) {
|
if (user_ids.includes(user_id)) {
|
||||||
blueslip.error("server sent duplicate reactions", {user_id, local_id});
|
blueslip.error("server sent duplicate reactions", {user_id, local_id});
|
||||||
|
@ -471,6 +530,7 @@ export function set_clean_reactions(message) {
|
||||||
|
|
||||||
const reaction_counts_and_user_ids = [...distinct_reactions.keys()].map((local_id) => {
|
const reaction_counts_and_user_ids = [...distinct_reactions.keys()].map((local_id) => {
|
||||||
const user_ids = user_map.get(local_id);
|
const user_ids = user_map.get(local_id);
|
||||||
|
assert(user_ids !== undefined);
|
||||||
return {
|
return {
|
||||||
count: user_ids.length,
|
count: user_ids.length,
|
||||||
user_ids,
|
user_ids,
|
||||||
|
@ -480,7 +540,9 @@ export function set_clean_reactions(message) {
|
||||||
|
|
||||||
for (const local_id of distinct_reactions.keys()) {
|
for (const local_id of distinct_reactions.keys()) {
|
||||||
const reaction = distinct_reactions.get(local_id);
|
const reaction = distinct_reactions.get(local_id);
|
||||||
|
assert(reaction !== undefined);
|
||||||
const user_ids = user_map.get(local_id);
|
const user_ids = user_map.get(local_id);
|
||||||
|
assert(user_ids !== undefined);
|
||||||
|
|
||||||
message.clean_reactions.set(
|
message.clean_reactions.set(
|
||||||
local_id,
|
local_id,
|
||||||
|
@ -502,7 +564,14 @@ function make_clean_reaction({
|
||||||
emoji_code,
|
emoji_code,
|
||||||
reaction_type,
|
reaction_type,
|
||||||
should_display_reactors,
|
should_display_reactors,
|
||||||
}) {
|
}: {
|
||||||
|
local_id: string;
|
||||||
|
user_ids: number[];
|
||||||
|
emoji_name: string;
|
||||||
|
emoji_code: string;
|
||||||
|
reaction_type: string;
|
||||||
|
should_display_reactors: boolean;
|
||||||
|
}): MessageCleanReaction {
|
||||||
const emoji_details = emoji.get_emoji_details_for_rendering({
|
const emoji_details = emoji.get_emoji_details_for_rendering({
|
||||||
emoji_name,
|
emoji_name,
|
||||||
emoji_code,
|
emoji_code,
|
||||||
|
@ -537,7 +606,10 @@ function make_clean_reaction({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_user_fields(clean_reaction_object, should_display_reactors) {
|
export function update_user_fields(
|
||||||
|
clean_reaction_object: MessageCleanReaction,
|
||||||
|
should_display_reactors: boolean,
|
||||||
|
): void {
|
||||||
// update_user_fields needs to be called whenever the set of users
|
// update_user_fields needs to be called whenever the set of users
|
||||||
// who reacted on a message might have changed, including due to
|
// who reacted on a message might have changed, including due to
|
||||||
// upvote/downvotes on ANY reaction in the message, because those
|
// upvote/downvotes on ANY reaction in the message, because those
|
||||||
|
@ -547,6 +619,7 @@ export function update_user_fields(clean_reaction_object, should_display_reactor
|
||||||
clean_reaction_object.emoji_name,
|
clean_reaction_object.emoji_name,
|
||||||
clean_reaction_object.user_ids,
|
clean_reaction_object.user_ids,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (clean_reaction_object.user_ids.includes(current_user.user_id)) {
|
if (clean_reaction_object.user_ids.includes(current_user.user_id)) {
|
||||||
clean_reaction_object.class = "message_reaction reacted";
|
clean_reaction_object.class = "message_reaction reacted";
|
||||||
} else {
|
} else {
|
||||||
|
@ -567,33 +640,40 @@ export function update_user_fields(clean_reaction_object, should_display_reactor
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_reaction_counts_and_user_ids(message) {
|
type ReactionUserIdAndCount = {
|
||||||
|
count?: number;
|
||||||
|
user_ids: number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function get_reaction_counts_and_user_ids(message: Message): ReactionUserIdAndCount[] {
|
||||||
return [...message.clean_reactions.values()].map((reaction) => ({
|
return [...message.clean_reactions.values()].map((reaction) => ({
|
||||||
count: reaction.count,
|
count: reaction.count,
|
||||||
user_ids: reaction.user_ids,
|
user_ids: reaction.user_ids,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_vote_text(user_ids, should_display_reactors) {
|
export function get_vote_text(user_ids: number[], should_display_reactors: boolean): string {
|
||||||
if (should_display_reactors) {
|
if (should_display_reactors) {
|
||||||
return comma_separated_usernames(user_ids);
|
return comma_separated_usernames(user_ids);
|
||||||
}
|
}
|
||||||
return `${user_ids.length}`;
|
return `${user_ids.length}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_should_display_reactors(reaction_counts_and_user_ids) {
|
function check_should_display_reactors(
|
||||||
|
reaction_counts_and_user_ids: ReactionUserIdAndCount[],
|
||||||
|
): boolean {
|
||||||
if (!user_settings.display_emoji_reaction_users) {
|
if (!user_settings.display_emoji_reaction_users) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let total_reactions = 0;
|
let total_reactions = 0;
|
||||||
for (const {count, user_ids} of reaction_counts_and_user_ids) {
|
for (const {count, user_ids} of reaction_counts_and_user_ids) {
|
||||||
total_reactions += count || user_ids.length;
|
total_reactions += count ?? user_ids.length;
|
||||||
}
|
}
|
||||||
return total_reactions <= 3;
|
return total_reactions <= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
function comma_separated_usernames(user_list) {
|
function comma_separated_usernames(user_list: number[]): string {
|
||||||
const usernames = people.get_display_full_names(user_list);
|
const usernames = people.get_display_full_names(user_list);
|
||||||
const current_user_has_reacted = user_list.includes(current_user.user_id);
|
const current_user_has_reacted = user_list.includes(current_user.user_id);
|
||||||
|
|
||||||
|
@ -607,7 +687,7 @@ function comma_separated_usernames(user_list) {
|
||||||
return comma_separated_usernames;
|
return comma_separated_usernames;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_vote_text_on_message(message) {
|
export function update_vote_text_on_message(message: Message): void {
|
||||||
// Because whether we display a count or the names of reacting
|
// Because whether we display a count or the names of reacting
|
||||||
// users depends on total reactions on the message, we need to
|
// users depends on total reactions on the message, we need to
|
||||||
// recalculate this whenever adjusting reaction rendering on a
|
// recalculate this whenever adjusting reaction rendering on a
|
||||||
|
@ -618,7 +698,9 @@ export function update_vote_text_on_message(message) {
|
||||||
for (const [reaction, clean_reaction] of message.clean_reactions.entries()) {
|
for (const [reaction, clean_reaction] of message.clean_reactions.entries()) {
|
||||||
const reaction_elem = find_reaction(message.id, clean_reaction.local_id);
|
const reaction_elem = find_reaction(message.id, clean_reaction.local_id);
|
||||||
const vote_text = get_vote_text(clean_reaction.user_ids, should_display_reactors);
|
const vote_text = get_vote_text(clean_reaction.user_ids, should_display_reactors);
|
||||||
message.clean_reactions.get(reaction).vote_text = vote_text;
|
const message_clean_reaction = message.clean_reactions.get(reaction);
|
||||||
|
assert(message_clean_reaction !== undefined);
|
||||||
|
message_clean_reaction.vote_text = vote_text;
|
||||||
set_reaction_vote_text(reaction_elem, vote_text);
|
set_reaction_vote_text(reaction_elem, vote_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1181,7 +1181,7 @@ test("remove_reaction_from_view (last person)", () => {
|
||||||
assert.ok(removed);
|
assert.ok(removed);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("error_handling", ({override, override_rewire}) => {
|
test("error_handling", ({override}) => {
|
||||||
override(message_store, "get", noop);
|
override(message_store, "get", noop);
|
||||||
|
|
||||||
blueslip.expect("error", "reactions: Bad message id");
|
blueslip.expect("error", "reactions: Bad message id");
|
||||||
|
@ -1193,7 +1193,6 @@ test("error_handling", ({override, override_rewire}) => {
|
||||||
emoji_code: "991",
|
emoji_code: "991",
|
||||||
user_id: 99,
|
user_id: 99,
|
||||||
};
|
};
|
||||||
override_rewire(reactions, "current_user_has_reacted_to_emoji", () => true);
|
|
||||||
reactions.toggle_emoji_reaction(55, bogus_event.emoji_name);
|
reactions.toggle_emoji_reaction(55, bogus_event.emoji_name);
|
||||||
|
|
||||||
reactions.add_reaction(bogus_event);
|
reactions.add_reaction(bogus_event);
|
||||||
|
|
Loading…
Reference in New Issue