This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/plugins/chat/assets/javascripts/discourse/services/chat-channels-manager.js
Joffrey JAFFEUX b5e736504a
PERF: applies optimisations on chat-live pane (#20532)
- group writes when computing separators positions
- shows skeleton only on initial load
- forces date separator to be pinned when first message to prevent a pinned - not pinned - pinned sequence when loading more in past
- relies on `message.visible` property instead of checking `isElementInViewport`
- attempts to load next/prev messages earlier
- do not scroll to on fetch more
- hides `last visit` text while pinned
2023-03-06 16:42:11 +01:00

162 lines
4.3 KiB
JavaScript

import Service, { inject as service } from "@ember/service";
import Promise from "rsvp";
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
import { tracked } from "@glimmer/tracking";
import { TrackedObject } from "@ember-compat/tracked-built-ins";
import { popupAjaxError } from "discourse/lib/ajax-error";
const DIRECT_MESSAGE_CHANNELS_LIMIT = 20;
/*
The ChatChannelsManager service is responsible for managing the loaded chat channels.
It provides helpers to facilitate using and managing laoded channels instead of constantly
fetching them from the server.
*/
export default class ChatChannelsManager extends Service {
@service chatSubscriptionsManager;
@service chatApi;
@service currentUser;
@tracked _cached = new TrackedObject();
async find(id, options = { fetchIfNotFound: true }) {
const existingChannel = this.#findStale(id);
if (existingChannel) {
return Promise.resolve(existingChannel);
} else if (options.fetchIfNotFound) {
return this.#find(id);
} else {
return Promise.resolve();
}
}
get channels() {
return Object.values(this._cached);
}
store(channelObject) {
let model = this.#findStale(channelObject.id);
if (!model) {
model = ChatChannel.create(channelObject);
this.#cache(model);
}
if (
channelObject.meta?.message_bus_last_ids?.channel_message_bus_last_id !==
undefined
) {
model.channelMessageBusLastId =
channelObject.meta.message_bus_last_ids.channel_message_bus_last_id;
}
return model;
}
async follow(model) {
this.chatSubscriptionsManager.startChannelSubscription(model);
if (!model.currentUserMembership.following) {
return this.chatApi.followChannel(model.id).then((membership) => {
model.currentUserMembership.following = membership.following;
model.currentUserMembership.muted = membership.muted;
model.currentUserMembership.desktop_notification_level =
membership.desktop_notification_level;
model.currentUserMembership.mobile_notification_level =
membership.mobile_notification_level;
return model;
});
} else {
return Promise.resolve(model);
}
}
async unfollow(model) {
this.chatSubscriptionsManager.stopChannelSubscription(model);
return this.chatApi.unfollowChannel(model.id).then((membership) => {
model.currentUserMembership = membership;
return model;
});
}
get unreadCount() {
let count = 0;
this.publicMessageChannels.forEach((channel) => {
count += channel.currentUserMembership.unread_count || 0;
});
return count;
}
get unreadUrgentCount() {
let count = 0;
this.channels.forEach((channel) => {
if (channel.isDirectMessageChannel) {
count += channel.currentUserMembership.unread_count || 0;
}
count += channel.currentUserMembership.unread_mentions || 0;
});
return count;
}
get publicMessageChannels() {
return this.channels
.filter(
(channel) =>
channel.isCategoryChannel && channel.currentUserMembership.following
)
.sort((a, b) => a?.slug?.localeCompare?.(b?.slug));
}
get directMessageChannels() {
return this.#sortDirectMessageChannels(
this.channels.filter((channel) => {
const membership = channel.currentUserMembership;
return channel.isDirectMessageChannel && membership.following;
})
);
}
get truncatedDirectMessageChannels() {
return this.directMessageChannels.slice(0, DIRECT_MESSAGE_CHANNELS_LIMIT);
}
async #find(id) {
return this.chatApi
.channel(id)
.catch(popupAjaxError)
.then((channel) => {
this.#cache(channel);
return channel;
});
}
#cache(channel) {
if (!channel) {
return;
}
this._cached[channel.id] = channel;
}
#findStale(id) {
return this._cached[id];
}
#sortDirectMessageChannels(channels) {
return channels.sort((a, b) => {
const unreadCountA = a.currentUserMembership.unread_count || 0;
const unreadCountB = b.currentUserMembership.unread_count || 0;
if (unreadCountA === unreadCountB) {
return new Date(a.lastMessageSentAt) > new Date(b.lastMessageSentAt)
? -1
: 1;
} else {
return unreadCountA > unreadCountB ? -1 : 1;
}
});
}
}