modal: Implement logic for marking various messages as read.

This commit implements the logic for marking messages as read based
on the selected option from the dropdown menu.

Below the dropdown, count of the messages to be marked as read is
displayed. The count value is updated dynamically as the selection
in the dropdown is changed.

Fixes part of #30025.
This commit is contained in:
whilstsomebody 2024-10-29 13:42:22 +05:30
parent 50e61743ea
commit 84ffb471a2
5 changed files with 87 additions and 8 deletions

View File

@ -46,7 +46,7 @@ function register_mark_all_read_handler(
>, >,
): void { ): void {
const {instance} = event.data; const {instance} = event.data;
unread_ops.confirm_mark_all_as_read(); unread_ops.confirm_mark_messages_as_read();
popover_menus.hide_current_popover_if_visible(instance); popover_menus.hide_current_popover_if_visible(instance);
} }

View File

@ -893,6 +893,8 @@ export type FullUnreadCountsData = {
stream_unread_messages: number; stream_unread_messages: number;
followed_topic_unread_messages_count: number; followed_topic_unread_messages_count: number;
followed_topic_unread_messages_with_mention_count: number; followed_topic_unread_messages_with_mention_count: number;
unfollowed_topic_unread_messages_count: number;
muted_topic_unread_messages_count: number;
stream_count: Map<number, StreamCountInfo>; stream_count: Map<number, StreamCountInfo>;
streams_with_mentions: number[]; streams_with_mentions: number[];
streams_with_unmuted_mentions: number[]; streams_with_unmuted_mentions: number[];
@ -919,6 +921,10 @@ export function get_counts(): FullUnreadCountsData {
followed_topic_unread_messages_count: topic_res.followed_topic_unread_messages, followed_topic_unread_messages_count: topic_res.followed_topic_unread_messages,
followed_topic_unread_messages_with_mention_count: followed_topic_unread_messages_with_mention_count:
unread_topic_counter.get_followed_topic_unread_mentions(), unread_topic_counter.get_followed_topic_unread_mentions(),
unfollowed_topic_unread_messages_count:
unread_messages.size - topic_res.followed_topic_unread_messages - pm_res.total_count,
muted_topic_unread_messages_count:
unread_messages.size - topic_res.stream_unread_messages - pm_res.total_count,
stream_count: topic_res.stream_count, stream_count: topic_res.stream_count,
streams_with_mentions: [...unread_topic_counter.get_streams_with_unread_mentions()], streams_with_mentions: [...unread_topic_counter.get_streams_with_unread_mentions()],
streams_with_unmuted_mentions: [ streams_with_unmuted_mentions: [

View File

@ -3,14 +3,14 @@ import _ from "lodash";
import assert from "minimalistic-assert"; import assert from "minimalistic-assert";
import {z} from "zod"; import {z} from "zod";
import render_confirm_mark_all_as_read from "../templates/confirm_dialog/confirm_mark_all_as_read.hbs"; import render_confirm_mark_messages_as_read from "../templates/confirm_dialog/confirm_mark_all_as_read.hbs";
import * as blueslip from "./blueslip.ts"; import * as blueslip from "./blueslip.ts";
import * as channel from "./channel.ts"; import * as channel from "./channel.ts";
import * as confirm_dialog from "./confirm_dialog.ts"; import * as confirm_dialog from "./confirm_dialog.ts";
import * as desktop_notifications from "./desktop_notifications.ts"; import * as desktop_notifications from "./desktop_notifications.ts";
import * as dialog_widget from "./dialog_widget.ts"; import * as dialog_widget from "./dialog_widget.ts";
import {$t_html} from "./i18n.ts"; import {$t, $t_html} from "./i18n.ts";
import * as loading from "./loading.ts"; import * as loading from "./loading.ts";
import * as message_flags from "./message_flags.ts"; import * as message_flags from "./message_flags.ts";
import * as message_lists from "./message_lists.ts"; import * as message_lists from "./message_lists.ts";
@ -48,17 +48,37 @@ export function is_window_focused(): boolean {
return window_focused; return window_focused;
} }
export function confirm_mark_all_as_read(): void { export function confirm_mark_messages_as_read(): void {
const html_body = render_confirm_mark_all_as_read(); const html_body = render_confirm_mark_messages_as_read();
const modal_id = confirm_dialog.launch({ const modal_id = confirm_dialog.launch({
html_heading: $t_html({defaultMessage: "Choose messages to mark as read"}), html_heading: $t_html({defaultMessage: "Choose messages to mark as read"}),
html_body, html_body,
on_click() { on_click() {
mark_all_as_read(modal_id); handle_mark_messages_as_read(modal_id);
}, },
loading_spinner: true, loading_spinner: true,
}); });
// When the user clicks on "Mark messages as read," the dialog box opens with a
// dropdown that, by default, displays the count of unread messages in
// topics that the user does not follow.
const default_messages_count = unread.get_counts().unfollowed_topic_unread_messages_count;
$("#message_count").text(update_message_count_text(default_messages_count));
// When the user selects another option from the dropdown, this section is executed.
$("#mark_as_read_option").on("change", function () {
const selected_option = $(this).val();
let messages_count;
if (selected_option === "muted_topics") {
messages_count = unread.get_counts().muted_topic_unread_messages_count;
} else if (selected_option === "topics_not_followed") {
messages_count = default_messages_count;
} else {
messages_count = unread.get_unread_message_count();
}
$("#message_count").text(update_message_count_text(messages_count));
});
} }
const update_flags_for_narrow_response_schema = z.object({ const update_flags_for_narrow_response_schema = z.object({
@ -70,6 +90,16 @@ const update_flags_for_narrow_response_schema = z.object({
found_newest: z.boolean(), found_newest: z.boolean(),
}); });
function update_message_count_text(count: number): string {
return $t(
{
defaultMessage:
"{count, plural, one {# message} other {# messages}} will be marked as read.",
},
{count},
);
}
function bulk_update_read_flags_for_narrow( function bulk_update_read_flags_for_narrow(
narrow: NarrowTerm[], narrow: NarrowTerm[],
op: "add" | "remove", op: "add" | "remove",
@ -240,6 +270,18 @@ function bulk_update_read_flags_for_narrow(
}); });
} }
function handle_mark_messages_as_read(modal_id: string): void {
const selected_option = $("#mark_as_read_option").val();
if (selected_option === "muted_topics") {
mark_muted_topic_messages_as_read(modal_id);
} else if (selected_option === "topics_not_followed") {
mark_unfollowed_topic_messages_as_read(modal_id);
} else {
mark_all_as_read(modal_id);
}
}
function process_newly_read_message( function process_newly_read_message(
message: Message, message: Message,
options: {from?: "pointer" | "server"}, options: {from?: "pointer" | "server"},
@ -618,7 +660,7 @@ export function mark_stream_as_read(stream_id: number): void {
); );
} }
export function mark_topic_as_read(stream_id: number, topic: string): void { export function mark_topic_as_read(stream_id: number, topic: string, modal_id?: string): void {
bulk_update_read_flags_for_narrow( bulk_update_read_flags_for_narrow(
[ [
{operator: "is", operand: "unread", negated: false}, {operator: "is", operand: "unread", negated: false},
@ -626,6 +668,8 @@ export function mark_topic_as_read(stream_id: number, topic: string): void {
{operator: "topic", operand: topic}, {operator: "topic", operand: topic},
], ],
"add", "add",
{},
modal_id,
); );
} }
@ -643,6 +687,31 @@ export function mark_all_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(all_unread_messages_narrow, "add", {}, modal_id); bulk_update_read_flags_for_narrow(all_unread_messages_narrow, "add", {}, modal_id);
} }
export function mark_muted_topic_messages_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(
[
{operator: "is", operand: "unread", negated: false},
{operator: "in", operand: "home", negated: true},
],
"add",
{},
modal_id,
);
}
export function mark_unfollowed_topic_messages_as_read(modal_id?: string): void {
bulk_update_read_flags_for_narrow(
[
{operator: "is", operand: "unread", negated: false},
{operator: "is", operand: "followed", negated: true},
{operator: "is", operand: "dm", negated: true},
],
"add",
{},
modal_id,
);
}
export function mark_pm_as_read(user_ids_string: string): void { export function mark_pm_as_read(user_ids_string: string): void {
// user_ids_string is a stringified list of user ids which are // user_ids_string is a stringified list of user ids which are
// participants in the conversation other than the current // participants in the conversation other than the current

View File

@ -354,6 +354,10 @@ select.settings_select {
& label.checkbox + label { & label.checkbox + label {
cursor: pointer; cursor: pointer;
} }
.message_count {
margin: 5px 0 0;
}
} }
/* Class for displaying an input with an /* Class for displaying an input with an

View File

@ -7,5 +7,5 @@
<option value="topics_not_followed" selected>{{t "Topics I don't follow" }}</option> <option value="topics_not_followed" selected>{{t "Topics I don't follow" }}</option>
<option value="all_messages">{{t "All messages" }}</option> <option value="all_messages">{{t "All messages" }}</option>
</select> </select>
<p id="message_count"></p> <p id="message_count" class="message_count"></p>
</div> </div>