diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts
index 12b39124d..c5e6dfa58 100644
--- a/src/api/gramjs/apiBuilders/messages.ts
+++ b/src/api/gramjs/apiBuilders/messages.ts
@@ -879,6 +879,7 @@ function buildAction(
let photo: ApiPhoto | undefined;
let score: number | undefined;
let months: number | undefined;
+ let topicEmojiIconId: string | undefined;
const targetUserIds = 'users' in action
? action.users && action.users.map((id) => buildApiPeerId(id, 'user'))
@@ -1036,8 +1037,11 @@ function buildAction(
} else if (action.title) {
text = 'TopicRenamedTo';
translationValues.push('%action_origin%', action.title);
+ } else if (action.iconEmojiId) {
+ text = 'TopicWasIconChangedToAction';
+ translationValues.push('%action_origin%', '%action_topic_icon%');
+ topicEmojiIconId = action.iconEmojiId.toString();
} else {
- // TODO[forums] Support icon changed action
text = 'ChatList.UnsupportedMessage';
}
} else {
@@ -1062,6 +1066,7 @@ function buildAction(
phoneCall,
score,
months,
+ topicEmojiIconId,
};
}
diff --git a/src/api/gramjs/methods/chats.ts b/src/api/gramjs/methods/chats.ts
index 5cfc4e292..4078ec653 100644
--- a/src/api/gramjs/methods/chats.ts
+++ b/src/api/gramjs/methods/chats.ts
@@ -26,6 +26,7 @@ import {
ALL_FOLDER_ID,
MAX_INT_32,
TOPICS_SLICE,
+ GENERAL_TOPIC_ID,
} from '../../../config';
import { invokeRequest, uploadFile } from './client';
import {
@@ -1516,7 +1517,7 @@ export function editTopic({
channel: buildInputPeer(id, accessHash),
topicId,
title,
- iconEmojiId: BigInt(iconEmojiId || '0'),
+ iconEmojiId: topicId !== GENERAL_TOPIC_ID && iconEmojiId ? BigInt(iconEmojiId) : undefined,
closed: isClosed,
hidden: isHidden,
}), true);
diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts
index 493489244..4d943d2ce 100644
--- a/src/api/types/messages.ts
+++ b/src/api/types/messages.ts
@@ -268,6 +268,7 @@ export interface ApiAction {
phoneCall?: PhoneCallAction;
score?: number;
months?: number;
+ topicEmojiIconId?: string;
}
export interface ApiWebPage {
diff --git a/src/components/common/helpers/renderActionMessageText.tsx b/src/components/common/helpers/renderActionMessageText.tsx
index a2cfb550c..29413c831 100644
--- a/src/components/common/helpers/renderActionMessageText.tsx
+++ b/src/components/common/helpers/renderActionMessageText.tsx
@@ -21,6 +21,8 @@ import MessageLink from '../MessageLink';
import ChatLink from '../ChatLink';
import GroupCallLink from '../GroupCallLink';
import MessageSummary from '../MessageSummary';
+import CustomEmoji from '../CustomEmoji';
+import TopicDefaultIcon from '../TopicDefaultIcon';
interface RenderOptions {
asPlainText?: boolean;
@@ -48,7 +50,7 @@ export function renderActionMessageText(
}
const {
- text, translationValues, amount, currency, call, score,
+ text, translationValues, amount, currency, call, score, topicEmojiIconId,
} = message.content.action;
const content: TextPart[] = [];
const noLinks = options.asPlainText || options.isEmbedded;
@@ -95,10 +97,26 @@ export function renderActionMessageText(
content.push(...processed);
if (unprocessed.includes('%action_topic%')) {
+ const topicEmoji = topic?.iconEmojiId ? : '';
+ const topicString = topic ? `${topic.title}` : 'a topic';
processed = processPlaceholder(
unprocessed,
'%action_topic%',
- topic ? topic.title : 'a topic',
+ [topicEmoji, topicString],
+ '',
+ );
+ unprocessed = processed.pop() as string;
+ content.push(...processed);
+ }
+
+ if (unprocessed.includes('%action_topic_icon%')) {
+ const topicIcon = topicEmojiIconId || topic?.iconEmojiId;
+ const hasIcon = topicIcon && topicIcon !== '0';
+ processed = processPlaceholder(
+ unprocessed,
+ '%action_topic_icon%',
+ hasIcon ?
+ : topic ? : '...',
);
unprocessed = processed.pop() as string;
content.push(...processed);
@@ -256,7 +274,9 @@ function renderMigratedContent(chatId: string, noLinks?: boolean): string | Text
return {text};
}
-function processPlaceholder(text: string, placeholder: string, replaceValue?: TextPart | TextPart[]): TextPart[] {
+function processPlaceholder(
+ text: string, placeholder: string, replaceValue?: TextPart | TextPart[], separator = ',',
+): TextPart[] {
const placeholderPosition = text.indexOf(placeholder);
if (placeholderPosition < 0 || !replaceValue) {
return [text];
@@ -268,7 +288,7 @@ function processPlaceholder(text: string, placeholder: string, replaceValue?: Te
replaceValue.forEach((value, index) => {
content.push(value);
if (index + 1 < replaceValue.length) {
- content.push(', ');
+ content.push(`${separator} `);
}
});
} else {
diff --git a/src/components/left/main/hooks/useTopicContextActions.ts b/src/components/left/main/hooks/useTopicContextActions.ts
index 8feadd5f4..c21d3536b 100644
--- a/src/components/left/main/hooks/useTopicContextActions.ts
+++ b/src/components/left/main/hooks/useTopicContextActions.ts
@@ -3,7 +3,7 @@ import { getActions } from '../../../../global';
import type { ApiChat, ApiTopic } from '../../../../api/types';
import { compact } from '../../../../util/iteratees';
-import { getHasAdminRight } from '../../../../global/helpers';
+import { getCanManageTopic, getHasAdminRight } from '../../../../global/helpers';
import useLang from '../../../../hooks/useLang';
import { useMemo } from '../../../../lib/teact/teact';
@@ -19,7 +19,7 @@ export default function useTopicContextActions(
return useMemo(() => {
const {
- isPinned, isMuted, isClosed, isOwner, id: topicId,
+ isPinned, isMuted, isClosed, id: topicId,
} = topic;
const chatId = chat.id;
@@ -31,7 +31,7 @@ export default function useTopicContextActions(
updateTopicMutedState,
} = getActions();
- const canToggleClosed = isOwner || chat.isCreator || getHasAdminRight(chat, 'manageTopics');
+ const canToggleClosed = getCanManageTopic(chat, topic);
const canTogglePinned = chat.isCreator || getHasAdminRight(chat, 'manageTopics');
const actionUnreadMark = topic.unreadCount || !wasOpened
diff --git a/src/components/right/EditTopic.tsx b/src/components/right/EditTopic.tsx
index 5c620a4cd..960a17450 100644
--- a/src/components/right/EditTopic.tsx
+++ b/src/components/right/EditTopic.tsx
@@ -26,6 +26,7 @@ import Transition from '../ui/Transition';
import styles from './ManageTopic.module.scss';
const ICON_SIZE = 5 * REM;
+const RESET_ICON_ID = '0';
export type OwnProps = {
isActive: boolean;
@@ -92,7 +93,7 @@ const EditTopic: FC = ({
}
if (emoji.id === DEFAULT_TOPIC_ICON_STICKER_ID) {
- setIconEmojiId(undefined);
+ setIconEmojiId(RESET_ICON_ID);
return;
}
diff --git a/src/global/actions/api/chats.ts b/src/global/actions/api/chats.ts
index 4f433054e..718809fc3 100644
--- a/src/global/actions/api/chats.ts
+++ b/src/global/actions/api/chats.ts
@@ -1427,13 +1427,15 @@ addActionHandler('createTopic', async (global, actions, payload) => {
const chat = selectChat(global, chatId);
if (!chat) return;
- setGlobal({
- ...global,
- createTopicPanel: {
- chatId,
- isLoading: true,
- },
- });
+ if (global.createTopicPanel) {
+ setGlobal({
+ ...global,
+ createTopicPanel: {
+ chatId,
+ isLoading: true,
+ },
+ });
+ }
const topicId = await callApi('createTopic', {
chat, title, iconColor, iconEmojiId,
@@ -1464,14 +1466,16 @@ addActionHandler('editTopic', async (global, actions, payload) => {
const topic = chat?.topics?.[topicId];
if (!chat || !topic) return;
- setGlobal({
- ...global,
- editTopicPanel: {
- chatId,
- topicId,
- isLoading: true,
- },
- });
+ if (global.editTopicPanel) {
+ setGlobal({
+ ...global,
+ editTopicPanel: {
+ chatId,
+ topicId,
+ isLoading: true,
+ },
+ });
+ }
const result = await callApi('editTopic', { chat, topicId, ...rest });
if (!result) return;