mirror of
https://github.com/discourse/discourse.git
synced 2025-02-16 18:24:52 -06:00
FEATURE: chat redesign - back button to exit threads (#24189)
Chat redesign work to improve chat navigation: - New header title with channel name (thread list on mobile) - New header title without channel name (thread list on full page chat) - Removes the close button on threads (mobile only) - Updates to back button route within thread (mobile), taking user to: - The thread index, if they accessed the thread from the thread index. - The channel itself, if they accessed the thread directly from the channel. - The channel itself, if they accessed the thread from a notification. - Show thread title in chat drawer header - Properly convert emoji in thread titles in chat header (all devices) - Upgrades various templates to use gjs format.
This commit is contained in:
parent
b90b7ac705
commit
f20b6a0cc3
@ -0,0 +1,40 @@
|
||||
import Component from "@glimmer/component";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class ChatDrawerHeaderTitle extends Component {
|
||||
get headerTitle() {
|
||||
if (this.args.title) {
|
||||
return I18n.t(this.args.title);
|
||||
}
|
||||
return replaceEmoji(this.args.translatedTitle);
|
||||
}
|
||||
|
||||
get showChannel() {
|
||||
return this.args.channelName ?? false;
|
||||
}
|
||||
|
||||
get showIcon() {
|
||||
return this.args.icon ?? false;
|
||||
}
|
||||
|
||||
<template>
|
||||
<span class="chat-drawer-header__title">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<span class="chat-drawer-header__icon">
|
||||
{{#if this.showIcon}}
|
||||
{{icon @icon}}
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
<span class="chat-drawer-header__title-text">{{this.headerTitle}}</span>
|
||||
|
||||
{{#if this.showChannel}}
|
||||
<span class="chat-drawer-header__divider">-</span>
|
||||
<span class="chat-drawer-header__channel-name">{{@channelName}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<span class="chat-drawer-header__title">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
{{i18n @title}}
|
||||
</div>
|
||||
</span>
|
@ -0,0 +1,100 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||
import { inject as service } from "@ember/service";
|
||||
import I18n from "discourse-i18n";
|
||||
import and from "truth-helpers/helpers/and";
|
||||
import ChatDrawerHeader from "discourse/plugins/chat/discourse/components/chat-drawer/header";
|
||||
import ChatDrawerHeaderBackLink from "discourse/plugins/chat/discourse/components/chat-drawer/header/back-link";
|
||||
import ChatDrawerHeaderRightActions from "discourse/plugins/chat/discourse/components/chat-drawer/header/right-actions";
|
||||
import ChatDrawerHeaderTitle from "discourse/plugins/chat/discourse/components/chat-drawer/header/title";
|
||||
import ChatThread from "discourse/plugins/chat/discourse/components/chat-thread";
|
||||
|
||||
export default class ChatDrawerThread extends Component {
|
||||
@service appEvents;
|
||||
@service chat;
|
||||
@service chatStateManager;
|
||||
@service chatChannelsManager;
|
||||
@service chatHistory;
|
||||
|
||||
get backLink() {
|
||||
const link = {
|
||||
models: this.chat.activeChannel.routeModels,
|
||||
};
|
||||
|
||||
if (this.chatHistory.previousRoute?.name === "chat.channel.threads") {
|
||||
link.title = I18n.t("chat.return_to_threads_list");
|
||||
link.route = "chat.channel.threads";
|
||||
} else {
|
||||
link.title = I18n.t("chat.return_to_channel");
|
||||
link.route = "chat.channel";
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
get threadTitle() {
|
||||
return (
|
||||
this.chat.activeChannel?.activeThread?.title ??
|
||||
I18n.t("chat.thread.label")
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
fetchChannelAndThread() {
|
||||
if (!this.args.params?.channelId || !this.args.params?.threadId) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.chatChannelsManager
|
||||
.find(this.args.params.channelId)
|
||||
.then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
|
||||
channel.threadsManager
|
||||
.find(channel.id, this.args.params.threadId)
|
||||
.then((thread) => {
|
||||
this.chat.activeChannel.activeThread = thread;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
<ChatDrawerHeader @toggleExpand={{@drawerActions.toggleExpand}}>
|
||||
{{#if
|
||||
(and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)
|
||||
}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawerHeaderBackLink
|
||||
@route={{this.backLink.route}}
|
||||
@title={{this.backLink.title}}
|
||||
@routeModels={{this.backLink.models}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<ChatDrawerHeaderTitle @translatedTitle={{this.threadTitle}} />
|
||||
|
||||
<ChatDrawerHeaderRightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawerHeader>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div
|
||||
class="chat-drawer-content"
|
||||
{{didInsert this.fetchChannelAndThread}}
|
||||
{{didUpdate this.fetchChannelAndThread @params.channelId}}
|
||||
{{didUpdate this.fetchChannelAndThread @params.threadId}}
|
||||
>
|
||||
{{#if this.chat.activeChannel.activeThread}}
|
||||
<ChatThread
|
||||
@thread={{this.chat.activeChannel.activeThread}}
|
||||
@targetMessageId={{@params.messageId}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<ChatDrawer::Header @toggleExpand={{@drawerActions.toggleExpand}}>
|
||||
{{#if (and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawer::Header::BackLink
|
||||
@route={{this.backLink.route}}
|
||||
@title={{i18n this.backLink.title}}
|
||||
@routeModels={{this.backLink.models}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<ChatDrawer::Header::Title @title="chat.thread.label" />
|
||||
|
||||
<ChatDrawer::Header::RightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawer::Header>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div
|
||||
class="chat-drawer-content"
|
||||
{{did-insert this.fetchChannelAndThread}}
|
||||
{{did-update this.fetchChannelAndThread @params.channelId}}
|
||||
{{did-update this.fetchChannelAndThread @params.threadId}}
|
||||
>
|
||||
{{#if this.chat.activeChannel.activeThread}}
|
||||
<ChatThread
|
||||
@thread={{this.chat.activeChannel.activeThread}}
|
||||
@targetMessageId={{@params.messageId}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
@ -1,46 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerThread extends Component {
|
||||
@service appEvents;
|
||||
@service chat;
|
||||
@service chatStateManager;
|
||||
@service chatChannelsManager;
|
||||
@service chatHistory;
|
||||
|
||||
get backLink() {
|
||||
const link = {
|
||||
models: this.chat.activeChannel.routeModels,
|
||||
};
|
||||
|
||||
if (this.chatHistory.previousRoute?.name === "chat.channel.threads") {
|
||||
link.title = "chat.return_to_threads_list";
|
||||
link.route = "chat.channel.threads";
|
||||
} else {
|
||||
link.title = "chat.return_to_list";
|
||||
link.route = "chat.channel";
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
@action
|
||||
fetchChannelAndThread() {
|
||||
if (!this.args.params?.channelId || !this.args.params?.threadId) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.chatChannelsManager
|
||||
.find(this.args.params.channelId)
|
||||
.then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
|
||||
channel.threadsManager
|
||||
.find(channel.id, this.args.params.threadId)
|
||||
.then((thread) => {
|
||||
this.chat.activeChannel.activeThread = thread;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { inject as service } from "@ember/service";
|
||||
import I18n from "discourse-i18n";
|
||||
import and from "truth-helpers/helpers/and";
|
||||
import ChatDrawerHeader from "discourse/plugins/chat/discourse/components/chat-drawer/header";
|
||||
import ChatDrawerHeaderBackLink from "discourse/plugins/chat/discourse/components/chat-drawer/header/back-link";
|
||||
import ChatDrawerHeaderRightActions from "discourse/plugins/chat/discourse/components/chat-drawer/header/right-actions";
|
||||
import ChatDrawerHeaderTitle from "discourse/plugins/chat/discourse/components/chat-drawer/header/title";
|
||||
import ChatThreadList from "discourse/plugins/chat/discourse/components/chat-thread-list";
|
||||
|
||||
export default class ChatDrawerThreads extends Component {
|
||||
@service appEvents;
|
||||
@service chat;
|
||||
@service chatStateManager;
|
||||
@service chatChannelsManager;
|
||||
|
||||
backLinkTitle = I18n.t("chat.return_to_list");
|
||||
|
||||
@action
|
||||
fetchChannel() {
|
||||
if (!this.args.params?.channelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.chatChannelsManager
|
||||
.find(this.args.params.channelId)
|
||||
.then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
<ChatDrawerHeader @toggleExpand={{@drawerActions.toggleExpand}}>
|
||||
{{#if
|
||||
(and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)
|
||||
}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawerHeaderBackLink
|
||||
@route="chat.channel"
|
||||
@title={{this.backLinkTitle}}
|
||||
@routeModels={{this.chat.activeChannel.routeModels}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<ChatDrawerHeaderTitle
|
||||
@title="chat.threads.list"
|
||||
@icon="discourse-threads"
|
||||
@channelName={{this.chat.activeChannel.title}}
|
||||
/>
|
||||
|
||||
<ChatDrawerHeaderRightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawerHeader>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
|
||||
{{#if this.chat.activeChannel}}
|
||||
<ChatThreadList
|
||||
@channel={{this.chat.activeChannel}}
|
||||
@includeHeader={{false}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<ChatDrawer::Header @toggleExpand={{@drawerActions.toggleExpand}}>
|
||||
{{#if (and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawer::Header::BackLink
|
||||
@route="chat.channel"
|
||||
@title={{i18n "chat.return_to_list"}}
|
||||
@routeModels={{this.chat.activeChannel.routeModels}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<ChatDrawer::Header::Title @title="chat.threads.list" />
|
||||
|
||||
<ChatDrawer::Header::RightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawer::Header>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-content" {{did-insert this.fetchChannel}}>
|
||||
{{#if this.chat.activeChannel}}
|
||||
<ChatThreadList
|
||||
@channel={{this.chat.activeChannel}}
|
||||
@includeHeader={{false}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
@ -1,23 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerThreads extends Component {
|
||||
@service appEvents;
|
||||
@service chat;
|
||||
@service chatStateManager;
|
||||
@service chatChannelsManager;
|
||||
|
||||
@action
|
||||
fetchChannel() {
|
||||
if (!this.args.params?.channelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.chatChannelsManager
|
||||
.find(this.args.params.channelId)
|
||||
.then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { LinkTo } from "@ember/routing";
|
||||
import { inject as service } from "@ember/service";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default class ChatThreadListHeader extends Component {
|
||||
@service router;
|
||||
@service site;
|
||||
|
||||
threadListTitle = I18n.t("chat.threads.list");
|
||||
closeButtonTitle = I18n.t("chat.thread.close");
|
||||
showCloseButton = !this.site.mobileView;
|
||||
|
||||
get showBackButton() {
|
||||
return this.args.channel && this.site.mobileView;
|
||||
}
|
||||
|
||||
get backButton() {
|
||||
return {
|
||||
route: "chat.channel.index",
|
||||
models: this.args.channel.routeModels,
|
||||
title: I18n.t("chat.return_to_channel"),
|
||||
};
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="chat-thread-list-header">
|
||||
<div class="chat-thread-header__left-buttons">
|
||||
{{#if this.showBackButton}}
|
||||
<LinkTo
|
||||
class="chat-thread__back-to-previous-route btn-flat btn btn-icon no-text"
|
||||
@route={{this.backButton.route}}
|
||||
@models={{this.backButton.models}}
|
||||
title={{this.backButton.title}}
|
||||
>
|
||||
{{icon "chevron-left"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="chat-thread-list-header__label">
|
||||
<span>
|
||||
{{icon "discourse-threads"}}
|
||||
{{replaceEmoji this.threadListTitle}}
|
||||
</span>
|
||||
|
||||
{{#if this.site.mobileView}}
|
||||
<div class="chat-thread-list-header__label-channel">
|
||||
{{replaceEmoji @channel.title}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.showCloseButton}}
|
||||
<div class="chat-thread-header__buttons">
|
||||
<LinkTo
|
||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
||||
@route="chat.channel"
|
||||
@models={{@channel.routeModels}}
|
||||
title={{this.closeButtonTitle}}
|
||||
>
|
||||
{{icon "times"}}
|
||||
</LinkTo>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<div class="chat-thread-header">
|
||||
<span class="chat-thread-header__label">
|
||||
{{replace-emoji (i18n "chat.threads.list")}}
|
||||
</span>
|
||||
|
||||
<div class="chat-thread-header__buttons">
|
||||
<LinkTo
|
||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
||||
@route="chat.channel"
|
||||
@models={{@channel.routeModels}}
|
||||
title={{i18n "chat.thread.close"}}
|
||||
>
|
||||
{{d-icon "times"}}
|
||||
</LinkTo>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,166 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { LinkTo } from "@ember/routing";
|
||||
import { inject as service } from "@ember/service";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import I18n from "discourse-i18n";
|
||||
import ChatModalThreadSettings from "discourse/plugins/chat/discourse/components/chat/modal/thread-settings";
|
||||
import ChatThreadHeaderUnreadIndicator from "discourse/plugins/chat/discourse/components/chat/thread/header-unread-indicator";
|
||||
import UserChatThreadMembership from "discourse/plugins/chat/discourse/models/user-chat-thread-membership";
|
||||
import ThreadNotificationsButton from "discourse/plugins/chat/select-kit/addons/components/thread-notifications-button";
|
||||
|
||||
export default class ChatThreadHeader extends Component {
|
||||
@service currentUser;
|
||||
@service chatApi;
|
||||
@service router;
|
||||
@service chatStateManager;
|
||||
@service chatHistory;
|
||||
@service site;
|
||||
@service modal;
|
||||
|
||||
@tracked persistedNotificationLevel = true;
|
||||
|
||||
closeThreadTitle = I18n.t("chat.thread.close");
|
||||
|
||||
get backLink() {
|
||||
const prevPage = this.chatHistory.previousRoute?.name;
|
||||
let route, title;
|
||||
|
||||
if (prevPage === "chat.channel.threads") {
|
||||
route = "chat.channel.threads";
|
||||
title = I18n.t("chat.return_to_threads_list");
|
||||
} else if (prevPage === "chat.channel.index" && !this.site.mobileView) {
|
||||
route = "chat.channel.threads";
|
||||
title = I18n.t("chat.return_to_threads_list");
|
||||
} else {
|
||||
route = "chat.channel.index";
|
||||
title = I18n.t("chat.return_to_channel");
|
||||
}
|
||||
|
||||
return {
|
||||
route,
|
||||
models: this.args.channel.routeModels,
|
||||
title,
|
||||
};
|
||||
}
|
||||
|
||||
get canChangeThreadSettings() {
|
||||
if (!this.args.thread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
this.currentUser.staff ||
|
||||
this.currentUser.id === this.args.thread.originalMessage.user.id
|
||||
);
|
||||
}
|
||||
|
||||
get threadNotificationLevel() {
|
||||
return this.membership?.notificationLevel || NotificationLevels.REGULAR;
|
||||
}
|
||||
|
||||
get membership() {
|
||||
return this.args.thread.currentUserMembership;
|
||||
}
|
||||
|
||||
get headerTitle() {
|
||||
return this.args.thread?.title ?? I18n.t("chat.thread.label");
|
||||
}
|
||||
|
||||
@action
|
||||
openThreadSettings() {
|
||||
this.modal.show(ChatModalThreadSettings, { model: this.args.thread });
|
||||
}
|
||||
|
||||
@action
|
||||
updateThreadNotificationLevel(newNotificationLevel) {
|
||||
this.persistedNotificationLevel = false;
|
||||
|
||||
let currentNotificationLevel;
|
||||
|
||||
if (this.membership) {
|
||||
currentNotificationLevel = this.membership.notificationLevel;
|
||||
this.membership.notificationLevel = newNotificationLevel;
|
||||
} else {
|
||||
this.args.thread.currentUserMembership = UserChatThreadMembership.create({
|
||||
notification_level: newNotificationLevel,
|
||||
last_read_message_id: null,
|
||||
});
|
||||
}
|
||||
|
||||
return this.chatApi
|
||||
.updateCurrentUserThreadNotificationsSettings(
|
||||
this.args.thread.channel.id,
|
||||
this.args.thread.id,
|
||||
{ notificationLevel: newNotificationLevel }
|
||||
)
|
||||
.then((response) => {
|
||||
this.membership.last_read_message_id =
|
||||
response.membership.last_read_message_id;
|
||||
|
||||
this.persistedNotificationLevel = true;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.membership.notificationLevel = currentNotificationLevel;
|
||||
popupAjaxError(err);
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="chat-thread-header">
|
||||
<div class="chat-thread-header__left-buttons">
|
||||
{{#if @thread}}
|
||||
<LinkTo
|
||||
class="chat-thread__back-to-previous-route btn-flat btn btn-icon no-text"
|
||||
@route={{this.backLink.route}}
|
||||
@models={{this.backLink.models}}
|
||||
title={{this.backLink.title}}
|
||||
>
|
||||
<ChatThreadHeaderUnreadIndicator @channel={{@thread.channel}} />
|
||||
{{icon "chevron-left"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<span class="chat-thread-header__label overflow-ellipsis">
|
||||
{{replaceEmoji this.headerTitle}}
|
||||
</span>
|
||||
|
||||
<div
|
||||
class={{concatClass
|
||||
"chat-thread-header__buttons"
|
||||
(if this.persistedNotificationLevel "-persisted")
|
||||
}}
|
||||
>
|
||||
<ThreadNotificationsButton
|
||||
@value={{this.threadNotificationLevel}}
|
||||
@onChange={{this.updateThreadNotificationLevel}}
|
||||
/>
|
||||
{{#if this.canChangeThreadSettings}}
|
||||
<DButton
|
||||
@action={{this.openThreadSettings}}
|
||||
@icon="cog"
|
||||
@title="chat.thread.settings"
|
||||
class="btn-flat chat-thread-header__settings"
|
||||
/>
|
||||
{{/if}}
|
||||
{{#unless this.site.mobileView}}
|
||||
<LinkTo
|
||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
||||
@route="chat.channel"
|
||||
@models={{@thread.channel.routeModels}}
|
||||
title={{this.closeThreadTitle}}
|
||||
>
|
||||
{{icon "times"}}
|
||||
</LinkTo>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<div class="chat-thread-header">
|
||||
<div class="chat-thread-header__left-buttons">
|
||||
{{#if @thread}}
|
||||
<LinkTo
|
||||
class="chat-thread__back-to-previous-route btn-flat btn btn-icon no-text"
|
||||
@route={{this.backLink.route}}
|
||||
@models={{this.backLink.models}}
|
||||
title={{i18n "chat.return_to_threads_list"}}
|
||||
>
|
||||
<Chat::Thread::HeaderUnreadIndicator @channel={{@thread.channel}} />
|
||||
{{d-icon "chevron-left"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<span class="chat-thread-header__label overflow-ellipsis">
|
||||
{{replace-emoji @thread.title}}
|
||||
</span>
|
||||
|
||||
<div
|
||||
class={{concat-class
|
||||
"chat-thread-header__buttons"
|
||||
(if this.persistedNotificationLevel "-persisted")
|
||||
}}
|
||||
>
|
||||
<ThreadNotificationsButton
|
||||
@value={{this.threadNotificationLevel}}
|
||||
@onChange={{this.updateThreadNotificationLevel}}
|
||||
/>
|
||||
{{#if this.canChangeThreadSettings}}
|
||||
<DButton
|
||||
@action={{this.openThreadSettings}}
|
||||
@icon="cog"
|
||||
@title="chat.thread.settings"
|
||||
class="btn-flat chat-thread-header__settings"
|
||||
/>
|
||||
{{/if}}
|
||||
<LinkTo
|
||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
||||
@route="chat.channel"
|
||||
@models={{@thread.channel.routeModels}}
|
||||
title={{i18n "chat.thread.close"}}
|
||||
>
|
||||
{{d-icon "times"}}
|
||||
</LinkTo>
|
||||
</div>
|
||||
</div>
|
@ -1,96 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import ChatModalThreadSettings from "discourse/plugins/chat/discourse/components/chat/modal/thread-settings";
|
||||
import UserChatThreadMembership from "discourse/plugins/chat/discourse/models/user-chat-thread-membership";
|
||||
|
||||
export default class ChatThreadHeader extends Component {
|
||||
@service currentUser;
|
||||
@service chatApi;
|
||||
@service router;
|
||||
@service chatStateManager;
|
||||
@service chatHistory;
|
||||
@service site;
|
||||
@service modal;
|
||||
|
||||
@tracked persistedNotificationLevel = true;
|
||||
|
||||
get backLink() {
|
||||
let route;
|
||||
|
||||
if (
|
||||
this.chatHistory.previousRoute?.name === "chat.channel.index" &&
|
||||
this.site.mobileView
|
||||
) {
|
||||
route = "chat.channel.index";
|
||||
} else {
|
||||
route = "chat.channel.threads";
|
||||
}
|
||||
|
||||
return {
|
||||
route,
|
||||
models: this.args.channel.routeModels,
|
||||
};
|
||||
}
|
||||
|
||||
get canChangeThreadSettings() {
|
||||
if (!this.args.thread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
this.currentUser.staff ||
|
||||
this.currentUser.id === this.args.thread.originalMessage.user.id
|
||||
);
|
||||
}
|
||||
|
||||
get threadNotificationLevel() {
|
||||
return this.membership?.notificationLevel || NotificationLevels.REGULAR;
|
||||
}
|
||||
|
||||
get membership() {
|
||||
return this.args.thread.currentUserMembership;
|
||||
}
|
||||
|
||||
@action
|
||||
openThreadSettings() {
|
||||
this.modal.show(ChatModalThreadSettings, { model: this.args.thread });
|
||||
}
|
||||
|
||||
@action
|
||||
updateThreadNotificationLevel(newNotificationLevel) {
|
||||
this.persistedNotificationLevel = false;
|
||||
|
||||
let currentNotificationLevel;
|
||||
|
||||
if (this.membership) {
|
||||
currentNotificationLevel = this.membership.notificationLevel;
|
||||
this.membership.notificationLevel = newNotificationLevel;
|
||||
} else {
|
||||
this.args.thread.currentUserMembership = UserChatThreadMembership.create({
|
||||
notification_level: newNotificationLevel,
|
||||
last_read_message_id: null,
|
||||
});
|
||||
}
|
||||
|
||||
this.chatApi
|
||||
.updateCurrentUserThreadNotificationsSettings(
|
||||
this.args.thread.channel.id,
|
||||
this.args.thread.id,
|
||||
{ notificationLevel: newNotificationLevel }
|
||||
)
|
||||
.then((response) => {
|
||||
this.membership.last_read_message_id =
|
||||
response.membership.last_read_message_id;
|
||||
|
||||
this.persistedNotificationLevel = true;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.membership.notificationLevel = currentNotificationLevel;
|
||||
popupAjaxError(err);
|
||||
});
|
||||
}
|
||||
}
|
@ -148,6 +148,14 @@ a.chat-drawer-header__title {
|
||||
}
|
||||
}
|
||||
|
||||
.chat-drawer-header__icon {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.chat-drawer-header__divider {
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.chat-drawer-header {
|
||||
box-sizing: border-box;
|
||||
border-bottom: solid 1px var(--primary-low);
|
||||
|
@ -12,4 +12,13 @@
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
&__label span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__label-channel {
|
||||
display: block;
|
||||
font-size: var(--font-down-1-rem);
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,8 @@ en:
|
||||
save: "Save"
|
||||
select: "Select"
|
||||
return_to_list: "Return to channels list"
|
||||
return_to_threads_list: "Return to ongoing discussions"
|
||||
return_to_channel: "Return to channel"
|
||||
return_to_threads_list: "Return to threads list"
|
||||
unread_threads_count:
|
||||
one: "You have %{count} unread discussion"
|
||||
other: "You have %{count} unread discussions"
|
||||
@ -600,7 +601,7 @@ en:
|
||||
other: "+%{count}"
|
||||
threads:
|
||||
open: "Open Thread"
|
||||
list: "Ongoing discussions"
|
||||
list: "Threads"
|
||||
none: "You are not participating in any threads in this channel."
|
||||
|
||||
draft_channel_screen:
|
||||
|
@ -35,7 +35,7 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, mobile: tru
|
||||
|
||||
expect(thread_page.messages).to have_message(text: text, persisted: true)
|
||||
|
||||
thread_page.close
|
||||
thread_page.back_to_previous_route
|
||||
|
||||
expect(channel_page).to have_thread_indicator(original_message)
|
||||
end
|
||||
@ -69,7 +69,7 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, mobile: tru
|
||||
expect(thread_page.messages).to have_message(text: message_1.message)
|
||||
expect(thread_page.messages).to have_message(text: "reply to message")
|
||||
|
||||
thread_page.close
|
||||
thread_page.back_to_previous_route
|
||||
|
||||
expect(channel_page.message_thread_indicator(original_message)).to have_reply_count(2)
|
||||
expect(channel_page.messages).to have_no_message(text: "reply to message")
|
||||
|
Loading…
Reference in New Issue
Block a user