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
Gerhard Schlager 7ef482a292
REFACTOR: Fix pluralized strings in chat plugin (#20357)
* FIX: Use pluralized string

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Fix misuse of pluralized string

* DEV: Remove linting of `one` key in MessageFormat string, it doesn't work

* REFACTOR: Fix misuse of pluralized string

This also ensures that the URL works on subfolder and shows the site setting link only for admins instead of staff. The string is quite complicated, so the best option was to switch to MessageFormat.

* REFACTOR: Fix misuse of pluralized string

* FIX: Use pluralized string

This also ensures that the URL works on subfolder and shows the site setting link only for admins instead of staff.

* REFACTOR: Correctly pluralize reaction tooltips in chat

This also ensures that maximum 5 usernames are shown and fixes the number of "others" which was off by 1 if the current user reacted on a message.

* REFACTOR: Use translatable string as comma separator

* DEV: Add comment to translation to clarify the meaning of `%{identifier}`

* REFACTOR: Use translatable comma separator and use explicit interpolation keys

* REFACTOR: Don't interpolate lowercase channel status

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Don't interpolate channel status

* REFACTOR: Use %{count} interpolation key

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Correctly pluralize DM chat channel titles
2023-02-20 10:31:02 +01:00

416 lines
12 KiB
JavaScript

import { htmlSafe } from "@ember/template";
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 {
constructor({ channel, chatService }) {
super(...arguments);
this.channel = channel;
this.chatService = chatService;
}
get name() {
return dasherize(this.channel.slugifiedTitle);
}
@computed("chatService.activeChannel")
get classNames() {
const classes = [];
if (this.channel.currentUserMembership.muted) {
classes.push("sidebar-section-link--muted");
}
if (this.channel.id === this.chatService.activeChannel?.id) {
classes.push("sidebar-section-link--active");
}
classes.push(`channel-${this.channel.id}`);
return classes.join(" ");
}
get route() {
return "chat.channel";
}
get models() {
return this.channel.routeModels;
}
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.channel.currentUserMembership.unread_count > 0
? "circle"
: "";
}
get suffixCSSClass() {
return this.channel.currentUserMembership.unread_mentions > 0
? "urgent"
: "unread";
}
};
const SidebarChatChannelsSection = class extends BaseCustomSidebarSection {
@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.chatChannelsManager = container.lookup(
"service:chat-channels-manager"
);
this.router = container.lookup("service:router");
}
get sectionLinks() {
return this.chatChannelsManager.publicMessageChannels.map(
(channel) =>
new SidebarChatChannelsSectionLink({
channel,
chatService: this.chatService,
})
);
}
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 {
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 this.channel.slugifiedTitle;
}
@computed("chatService.activeChannel")
get classNames() {
const classes = [];
if (this.channel.currentUserMembership.muted) {
classes.push("sidebar-section-link--muted");
}
if (this.channel.id === this.chatService.activeChannel?.id) {
classes.push("sidebar-section-link--active");
}
classes.push(`channel-${this.channel.id}`);
return classes.join(" ");
}
get route() {
return "chat.channel";
}
get models() {
return this.channel.routeModels;
}
get title() {
return I18n.t("chat.placeholder_channel", {
channelName: 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.channel.currentUserMembership.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.user_option.timezone,
this.chatService.currentUser.locale
);
title += ` ${untilFormatted}`;
}
return title;
}
};
const SidebarChatDirectMessagesSection = class extends BaseCustomSidebarSection {
@service site;
@service router;
@tracked userCanDirectMessage =
this.chatService.userCanDirectMessage;
constructor() {
super(...arguments);
if (container.isDestroyed) {
return;
}
this.chatService = container.lookup("service:chat");
this.chatChannelsManager = container.lookup(
"service:chat-channels-manager"
);
}
get sectionLinks() {
return this.chatChannelsManager.truncatedDirectMessageChannels.map(
(channel) =>
new SidebarChatDirectMessagesSectionLink({
channel,
chatService: this.chatService,
})
);
}
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;
}
);
});
},
};