diff --git a/src/api/gramjs/apiBuilders/chats.ts b/src/api/gramjs/apiBuilders/chats.ts index 998353735..be9b71fa1 100644 --- a/src/api/gramjs/apiBuilders/chats.ts +++ b/src/api/gramjs/apiBuilders/chats.ts @@ -607,7 +607,8 @@ export function buildApiChatlistInvite( if (invite instanceof GramJs.chatlists.ChatlistInvite) { return { slug, - title: invite.title.text, + title: buildApiFormattedText(invite.title), + noTitleAnimations: invite.titleNoanimate, emoticon: invite.emoticon, peerIds: invite.peers.map(getApiChatIdFromMtpPeer).filter(Boolean), }; diff --git a/src/api/types/chats.ts b/src/api/types/chats.ts index ca498ed45..fb7624d49 100644 --- a/src/api/types/chats.ts +++ b/src/api/types/chats.ts @@ -261,7 +261,8 @@ export interface ApiTopic { } export interface ApiChatlistInviteNew { - title: string; + title: ApiFormattedText; + noTitleAnimations?: true; emoticon?: string; peerIds: string[]; slug: string; diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index cffe7f233..3cf79d48a 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -1416,6 +1416,21 @@ "FolderLinkTitleDescription" = "Anyone with this link can add {folder} folder and {chats} selected below."; "FolderLinkTitleDescriptionChats_one" = "the chat"; "FolderLinkTitleDescriptionChats_other" = "the {count} chats"; +"FolderLinkSubtitleNew" = "Do you want to add a new chat folder and join its groups and channels?" +"FolderLinkSubtitleAlready" = "You have already added this folder and its chats." +"FolderLinkSubtitleAdd" = "Do you want to add {chats} to the folder **{title}**?" +"FolderLinkSubtitleAddCount_one" = "1 chat"; +"FolderLinkSubtitleAddCount_other" = "{count} chats"; +"FolderLinkAddFolder" = "Add Folder"; +"FolderLinkNotificationDeletedTitle" = "Folder {title} Deleted"; +"FolderLinkNotificationDeletedSubtitle_one" = "You also left {count} chat"; +"FolderLinkNotificationDeletedSubtitle_other" = "You also left {count} chats"; +"FolderLinkNotificationAddedTitle" = "Folder {title} Added"; +"FolderLinkNotificationAddedSubtitle_one" = "You also joined {count} chat"; +"FolderLinkNotificationAddedSubtitle_other" = "You also joined {count} chats"; +"FolderLinkNotificationUpdatedTitle" = "Folder {title} Updated"; +"FolderLinkNotificationUpdatedSubtitle_one" = "You have added {count} chat"; +"FolderLinkNotificationUpdatedSubtitle_other" = "You have added {count} chats"; "SearchTabChats" = "Chats"; "SearchTabChannels" = "Channels"; "SearchTabApps" = "Apps"; diff --git a/src/components/modals/chatlist/ChatlistAlready.tsx b/src/components/modals/chatlist/ChatlistAlready.tsx index 48362bc70..048c1688e 100644 --- a/src/components/modals/chatlist/ChatlistAlready.tsx +++ b/src/components/modals/chatlist/ChatlistAlready.tsx @@ -6,7 +6,9 @@ import type { ApiChatFolder, ApiChatlistInviteAlready } from '../../../api/types import buildClassName from '../../../util/buildClassName'; import renderText from '../../common/helpers/renderText'; +import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities'; +import useLang from '../../../hooks/useLang'; import useOldLang from '../../../hooks/useOldLang'; import PeerPicker from '../../common/pickers/PeerPicker'; @@ -23,17 +25,28 @@ type OwnProps = { const ChatlistAlready: FC = ({ invite, folder }) => { const { closeChatlistModal, joinChatlistInvite } = getActions(); - const lang = useOldLang(); + const lang = useLang(); + const oldLang = useOldLang(); const [selectedPeerIds, setSelectedPeerIds] = useState(invite.missingPeerIds); const hasChatsToAdd = Boolean(invite.missingPeerIds.length); + const isNew = invite.alreadyPeerIds.length === 0; const newChatsCount = hasChatsToAdd ? invite.missingPeerIds.length : 0; const badgeText = selectedPeerIds.length ? selectedPeerIds.length.toString() : undefined; - const descriptionText = hasChatsToAdd - ? lang('FolderLinkSubtitleChats', [newChatsCount, folder.title], undefined, newChatsCount) - : lang('FolderLinkSubtitleAlready', folder.title); + const descriptionText = isNew ? lang('FolderLinkSubtitleNew') + : newChatsCount ? lang('FolderLinkSubtitleAdd', { + chats: lang('FolderLinkSubtitleAddCount', { count: newChatsCount }, { pluralValue: newChatsCount }), + title: renderTextWithEntities({ + text: folder.title.text, + entities: folder.title.entities, + noCustomEmojiPlayback: folder.noTitleAnimations, + }), + }, { + withNodes: true, + withMarkdown: true, + }) : lang('FolderLinkSubtitleAlready'); const handleButtonClick = useCallback(() => { closeChatlistModal(); @@ -61,7 +74,7 @@ const ChatlistAlready: FC = ({ invite, folder }) => { <>
- {lang('FolderLinkHeaderChatsJoin', selectedPeerIds.length, 'i')} + {oldLang('FolderLinkHeaderChatsJoin', selectedPeerIds.length, 'i')}
= ({ invite, folder }) => { tabIndex={0} onClick={handleSelectionToggle} > - {selectedPeerIds.length === invite.missingPeerIds.length ? lang('DeselectAll') : lang('SelectAll')} + {selectedPeerIds.length === invite.missingPeerIds.length + ? oldLang('DeselectAll') : oldLang('SelectAll')}
= ({ invite, folder }) => { )}
- {lang('FolderLinkHeaderAlready')} + {oldLang('FolderLinkHeaderAlready')}
= ({ invite, folder }) => { onClick={handleButtonClick} >
- {!selectedPeerIds.length && lang('OK')} + {!selectedPeerIds.length && oldLang('OK')} {Boolean(selectedPeerIds.length) && ( <> - {lang('FolderLinkButtonJoinPlural', selectedPeerIds.length, 'i')} + {oldLang('FolderLinkButtonJoinPlural', selectedPeerIds.length, 'i')} )} diff --git a/src/components/modals/chatlist/ChatlistDelete.tsx b/src/components/modals/chatlist/ChatlistDelete.tsx index dd3fdf50c..75d3ad284 100644 --- a/src/components/modals/chatlist/ChatlistDelete.tsx +++ b/src/components/modals/chatlist/ChatlistDelete.tsx @@ -29,7 +29,7 @@ const ChatlistDelete: FC = ({ const lang = useOldLang(); - const [selectedPeerIds, setSelectedPeerIds] = useState(suggestedPeerIds); + const [selectedPeerIds, setSelectedPeerIds] = useState([]); const badgeText = selectedPeerIds.length ? selectedPeerIds.length.toString() : undefined; diff --git a/src/components/modals/chatlist/ChatlistModal.tsx b/src/components/modals/chatlist/ChatlistModal.tsx index 8fd7aa68b..361ef5960 100644 --- a/src/components/modals/chatlist/ChatlistModal.tsx +++ b/src/components/modals/chatlist/ChatlistModal.tsx @@ -63,7 +63,13 @@ const ChatlistInviteModal: FC = ({ noCustomEmojiPlayback: renderingFolder.noTitleAnimations, }); } - if (renderingInfo?.invite && 'title' in renderingInfo.invite) return renderingInfo.invite.title; + if (renderingInfo?.invite && 'title' in renderingInfo.invite) { + return renderTextWithEntities({ + text: renderingInfo.invite.title.text, + entities: renderingInfo.invite.title.entities, + noCustomEmojiPlayback: renderingInfo.invite.noTitleAnimations, + }); + } return undefined; }, [renderingFolder, renderingInfo]); diff --git a/src/components/modals/chatlist/ChatlistNew.tsx b/src/components/modals/chatlist/ChatlistNew.tsx index c204931a1..292fba2d7 100644 --- a/src/components/modals/chatlist/ChatlistNew.tsx +++ b/src/components/modals/chatlist/ChatlistNew.tsx @@ -7,8 +7,8 @@ import { getActions, getGlobal } from '../../../global'; import type { ApiChatlistInviteNew } from '../../../api/types'; import buildClassName from '../../../util/buildClassName'; -import renderText from '../../common/helpers/renderText'; +import useLang from '../../../hooks/useLang'; import useOldLang from '../../../hooks/useOldLang'; import PeerPicker from '../../common/pickers/PeerPicker'; @@ -24,7 +24,8 @@ type OwnProps = { const ChatlistNew: FC = ({ invite }) => { const { closeChatlistModal, joinChatlistInvite } = getActions(); - const lang = useOldLang(); + const lang = useLang(); + const oldLang = useOldLang(); const [selectedPeerIds, setSelectedPeerIds] = useState(invite.peerIds); const joinedIds = useMemo(() => { @@ -53,12 +54,12 @@ const ChatlistNew: FC = ({ invite }) => { return (
- {renderText(lang('FolderLinkSubtitle', invite.title), ['simple_markdown', 'emoji'])} + {lang('FolderLinkSubtitleNew')}
- {lang('FolderLinkHeaderChatsJoin', selectedCount, 'i')} + {oldLang('FolderLinkHeaderChatsJoin', selectedCount, 'i')}
= ({ invite }) => { tabIndex={0} onClick={handleSelectionToggle} > - {selectedPeerIds.length === invite.peerIds.length ? lang('DeselectAll') : lang('SelectAll')} + {selectedPeerIds.length === invite.peerIds.length ? oldLang('DeselectAll') : oldLang('SelectAll')}
= ({ invite }) => { disabled={!selectedPeerIds.length} >
- {lang('FolderLinkButtonAdd', invite.title)} + {lang('FolderLinkAddFolder')}
diff --git a/src/global/actions/api/chats.ts b/src/global/actions/api/chats.ts index 7448d1137..34853175c 100644 --- a/src/global/actions/api/chats.ts +++ b/src/global/actions/api/chats.ts @@ -36,7 +36,9 @@ import { formatShareText, processDeepLink } from '../../../util/deeplink'; import { isDeepLink } from '../../../util/deepLinkParser'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getOrderedIds } from '../../../util/folderManager'; -import { buildCollectionByKey, omit, pick } from '../../../util/iteratees'; +import { + buildCollectionByKey, omit, pick, unique, +} from '../../../util/iteratees'; import { isLocalMessageId } from '../../../util/keys/messageKey'; import * as langProvider from '../../../util/oldLangProvider'; import { debounce, pause, throttle } from '../../../util/schedulers'; @@ -2329,18 +2331,54 @@ addActionHandler('joinChatlistInvite', async (global, actions, payload): Promise const { invite, peerIds, tabId = getCurrentTabId() } = payload; const peers = peerIds.map((peerId) => selectChat(global, peerId)).filter(Boolean); - const notJoinedCount = peers.filter((peer) => peer.isNotJoined).length; + const currentNotJoinedCount = peers.filter((peer) => peer.isNotJoined).length; - const folder = 'folderId' in invite ? selectChatFolder(global, invite.folderId) : undefined; - const folderTitle = 'title' in invite ? invite.title : folder?.title; + const existingFolder = 'folderId' in invite ? selectChatFolder(global, invite.folderId) : undefined; + const folderTitle = ('title' in invite ? invite.title : existingFolder?.title)!; try { const result = await callApi('joinChatlistInvite', { slug: invite.slug, peers }); if (!result) return; + if (existingFolder) { + actions.showNotification({ + title: { + key: 'FolderLinkNotificationUpdatedTitle', + variables: { + title: folderTitle.text, + }, + }, + message: { + key: 'FolderLinkNotificationUpdatedSubtitle', + variables: { + count: currentNotJoinedCount, + }, + options: { + pluralValue: currentNotJoinedCount, + }, + }, + tabId, + }); + + return; + } + actions.showNotification({ - title: langProvider.oldTranslate(folder ? 'FolderLinkUpdatedTitle' : 'FolderLinkAddedTitle', folderTitle), - message: langProvider.oldTranslate('FolderLinkAddedSubtitle', notJoinedCount, 'i'), + title: { + key: 'FolderLinkNotificationAddedTitle', + variables: { + title: folderTitle.text, + }, + }, + message: { + key: 'FolderLinkNotificationAddedSubtitle', + variables: { + count: currentNotJoinedCount, + }, + options: { + pluralValue: currentNotJoinedCount, + }, + }, tabId, }); } catch (error) { @@ -2362,10 +2400,24 @@ addActionHandler('leaveChatlist', async (global, actions, payload): Promise { 'folder': V; 'chats': V; }; + 'FolderLinkSubtitleAdd': { + 'chats': V; + 'title': V; + }; + 'FolderLinkNotificationDeletedTitle': { + 'title': V; + }; + 'FolderLinkNotificationAddedTitle': { + 'title': V; + }; + 'FolderLinkNotificationUpdatedTitle': { + 'title': V; + }; } export interface LangPairPlural { @@ -1797,6 +1813,18 @@ export interface LangPairPluralWithVariables { 'FolderLinkTitleDescriptionChats': { 'count': V; }; + 'FolderLinkSubtitleAddCount': { + 'count': V; + }; + 'FolderLinkNotificationDeletedSubtitle': { + 'count': V; + }; + 'FolderLinkNotificationAddedSubtitle': { + 'count': V; + }; + 'FolderLinkNotificationUpdatedSubtitle': { + 'count': V; + }; } export type RegularLangKey = keyof LangPair; export type RegularLangKeyWithVariables = keyof LangPairWithVariables;