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/initializers/chat-sidebar.js

493 lines
14 KiB
JavaScript

import { htmlSafe } from "@ember/template";
import slugifyChannel from "discourse/plugins/chat/discourse/lib/slugify-channel";
import { withPluginApi } from "discourse/lib/plugin-api";
import I18n from "I18n";
import { bind } from "discourse-common/utils/decorators";
import { tracked } from "@glimmer/tracking";
import { avatarUrl, escapeExpression } from "discourse/lib/utilities";
import { dasherize } from "@ember/string";
import { emojiUnescape } from "discourse/lib/text";
import { decorateUsername } from "discourse/helpers/decorate-username-selector";
import { until } from "discourse/lib/formatter";
import { inject as service } from "@ember/service";
import { computed } from "@ember/object";
export default {
name: "chat-sidebar",
initialize(container) {
this.chatService = container.lookup("service:chat");
if (!this.chatService.userCanChat) {
return;
}
withPluginApi("1.3.0", (api) => {
api.addSidebarSection(
(BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => {
const SidebarChatChannelsSectionLink = class extends BaseCustomSidebarSectionLink {
@tracked chatChannelTrackingState =
this.chatService.currentUser.chat_channel_tracking_state[
this.channel.id
];
constructor({ channel, chatService }) {
super(...arguments);
this.channel = channel;
this.chatService = chatService;
}
@bind
willDestroy() {
this.chatService.appEvents.off(
"chat:user-tracking-state-changed",
this._refreshTrackingState
);
}
@bind
didInsert() {
this.chatService.appEvents.on(
"chat:user-tracking-state-changed",
this._refreshTrackingState
);
}
@bind
_refreshTrackingState() {
this.chatChannelTrackingState =
this.chatService.currentUser.chat_channel_tracking_state[
this.channel.id
];
}
get name() {
return dasherize(slugifyChannel(this.channel));
}
@computed("chatService.activeChannel")
get classNames() {
const classes = [];
if (this.channel.current_user_membership.muted) {
classes.push("sidebar-section-link--muted");
}
if (this.channel.id === this.chatService.activeChannel?.id) {
classes.push("sidebar-section-link--active");
}
return classes.join(" ");
}
get route() {
return "chat.channel";
}
get models() {
return [this.channel.id, slugifyChannel(this.channel)];
}
get text() {
return htmlSafe(emojiUnescape(this.channel.escapedTitle));
}
get prefixType() {
return "icon";
}
get prefixValue() {
return "hashtag";
}
get prefixColor() {
return this.channel.chatable.color;
}
get title() {
return this.channel.escapedDescription
? htmlSafe(this.channel.escapedDescription)
: `${this.channel.escapedTitle} ${I18n.t("chat.title")}`;
}
get prefixBadge() {
return this.channel.chatable.read_restricted ? "lock" : "";
}
get suffixType() {
return "icon";
}
get suffixValue() {
return this.chatChannelTrackingState?.unread_count > 0
? "circle"
: "";
}
get suffixCSSClass() {
return this.chatChannelTrackingState?.unread_mentions > 0
? "urgent"
: "unread";
}
};
const SidebarChatChannelsSection = class extends BaseCustomSidebarSection {
@tracked sectionLinks = [];
@tracked sectionIndicator =
this.chatService.publicChannels &&
this.chatService.publicChannels[0].current_user_membership
.unread_count;
@tracked currentUserCanJoinPublicChannels =
this.sidebar.currentUser &&
(this.sidebar.currentUser.staff ||
this.sidebar.currentUser.has_joinable_public_channels);
constructor() {
super(...arguments);
if (container.isDestroyed) {
return;
}
this.chatService = container.lookup("service:chat");
this.router = container.lookup("service:router");
this.appEvents = container.lookup("service:app-events");
this.appEvents.on("chat:refresh-channels", this._refreshChannels);
this._refreshChannels();
}
@bind
willDestroy() {
if (!this.appEvents) {
return;
}
this.appEvents.off(
"chat:refresh-channels",
this._refreshChannels
);
}
@bind
_refreshChannels() {
const newSectionLinks = [];
this.chatService.getChannels().then((channels) => {
channels.publicChannels.forEach((channel) => {
newSectionLinks.push(
new SidebarChatChannelsSectionLink({
channel,
chatService: this.chatService,
})
);
});
this.sectionLinks = newSectionLinks;
});
}
get name() {
return "chat-channels";
}
get title() {
return I18n.t("chat.chat_channels");
}
get text() {
return I18n.t("chat.chat_channels");
}
get actions() {
return [
{
id: "browseChannels",
title: I18n.t("chat.channels_list_popup.browse"),
action: () => this.router.transitionTo("chat.browse.open"),
},
];
}
get actionsIcon() {
return "pencil-alt";
}
get links() {
return this.sectionLinks;
}
get displaySection() {
return (
this.sectionLinks.length > 0 ||
this.currentUserCanJoinPublicChannels
);
}
};
return SidebarChatChannelsSection;
}
);
api.addSidebarSection(
(BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => {
const SidebarChatDirectMessagesSectionLink = class extends BaseCustomSidebarSectionLink {
@tracked chatChannelTrackingState =
this.chatService.currentUser.chat_channel_tracking_state[
this.channel.id
];
constructor({ channel, chatService }) {
super(...arguments);
this.channel = channel;
this.chatService = chatService;
if (this.oneOnOneMessage) {
this.channel.chatable.users[0].trackStatus();
}
}
@bind
willDestroy() {
if (this.oneOnOneMessage) {
this.channel.chatable.users[0].stopTrackingStatus();
}
}
get name() {
return slugifyChannel(this.channel);
}
@computed("chatService.activeChannel")
get classNames() {
const classes = [];
if (this.channel.current_user_membership.muted) {
classes.push("sidebar-section-link--muted");
}
if (this.channel.id === this.chatService.activeChannel?.id) {
classes.push("sidebar-section-link--active");
}
return classes.join(" ");
}
get route() {
return "chat.channel";
}
get models() {
return [this.channel.id, slugifyChannel(this.channel)];
}
get title() {
return I18n.t("chat.placeholder_others", {
messageRecipient: this.channel.escapedTitle,
});
}
get oneOnOneMessage() {
return this.channel.chatable.users.length === 1;
}
get text() {
const username = this.channel.escapedTitle.replaceAll("@", "");
if (this.oneOnOneMessage) {
const status = this.channel.chatable.users[0].get("status");
const statusHtml = status ? this._userStatusHtml(status) : "";
return htmlSafe(
`${escapeExpression(
username
)}${statusHtml} ${decorateUsername(
escapeExpression(username)
)}`
);
} else {
return username;
}
}
get prefixType() {
if (this.oneOnOneMessage) {
return "image";
} else {
return "text";
}
}
get prefixValue() {
if (this.channel.chatable.users.length === 1) {
return avatarUrl(
this.channel.chatable.users[0].avatar_template,
"tiny"
);
} else {
return this.channel.chatable.users.length;
}
}
get prefixCSSClass() {
const activeUsers = this.chatService.presenceChannel.users;
const user = this.channel.chatable.users[0];
if (
!!activeUsers?.findBy("id", user?.id) ||
!!activeUsers?.findBy("username", user?.username)
) {
return "active";
}
return "";
}
get suffixType() {
return "icon";
}
get suffixValue() {
return this.chatChannelTrackingState?.unread_count > 0
? "circle"
: "";
}
get suffixCSSClass() {
return "urgent";
}
get hoverType() {
return "icon";
}
get hoverValue() {
return "times";
}
get hoverAction() {
return (event) => {
event.stopPropagation();
event.preventDefault();
this.chatService.unfollowChannel(this.channel);
};
}
get hoverTitle() {
return I18n.t("chat.direct_messages.leave");
}
_userStatusHtml(status) {
const emoji = escapeExpression(`:${status.emoji}:`);
const title = this._userStatusTitle(status);
return `<span class="user-status">${emojiUnescape(emoji, {
title,
})}</span>`;
}
_userStatusTitle(status) {
let title = `${escapeExpression(status.description)}`;
if (status.ends_at) {
const untilFormatted = until(
status.ends_at,
this.chatService.currentUser.timezone,
this.chatService.currentUser.locale
);
title += ` ${untilFormatted}`;
}
return title;
}
};
const SidebarChatDirectMessagesSection = class extends BaseCustomSidebarSection {
@service site;
@service router;
@tracked sectionLinks = [];
@tracked userCanDirectMessage =
this.chatService.userCanDirectMessage;
constructor() {
super(...arguments);
if (container.isDestroyed) {
return;
}
this.chatService = container.lookup("service:chat");
this.chatService.appEvents.on(
"chat:user-tracking-state-changed",
this._refreshDirectMessageChannels
);
this._refreshDirectMessageChannels();
}
@bind
willDestroy() {
if (container.isDestroyed) {
return;
}
this.chatService.appEvents.off(
"chat:user-tracking-state-changed",
this._refreshDirectMessageChannels
);
}
@bind
_refreshDirectMessageChannels() {
const newSectionLinks = [];
this.chatService.getChannels().then((channels) => {
this.chatService
.truncateDirectMessageChannels(channels.directMessageChannels)
.forEach((channel) => {
newSectionLinks.push(
new SidebarChatDirectMessagesSectionLink({
channel,
chatService: this.chatService,
})
);
});
this.sectionLinks = newSectionLinks;
});
}
get name() {
return "chat-dms";
}
get title() {
return I18n.t("chat.direct_messages.title");
}
get text() {
return I18n.t("chat.direct_messages.title");
}
get actions() {
if (!this.userCanDirectMessage) {
return [];
}
return [
{
id: "startDm",
title: I18n.t("chat.direct_messages.new"),
action: () => {
this.router.transitionTo("chat.draft-channel");
},
},
];
}
get actionsIcon() {
return "plus";
}
get links() {
return this.sectionLinks;
}
get displaySection() {
return this.sectionLinks.length > 0 || this.userCanDirectMessage;
}
};
return SidebarChatDirectMessagesSection;
}
);
});
},
};