Add chat to folder from context menu (#1477)
This commit is contained in:
parent
54d6b581da
commit
609c0cb68e
@ -19,6 +19,7 @@ export { default as NewChat } from '../components/left/newChat/NewChat';
|
|||||||
export { default as NewChatStep1 } from '../components/left/newChat/NewChatStep1';
|
export { default as NewChatStep1 } from '../components/left/newChat/NewChatStep1';
|
||||||
export { default as NewChatStep2 } from '../components/left/newChat/NewChatStep2';
|
export { default as NewChatStep2 } from '../components/left/newChat/NewChatStep2';
|
||||||
export { default as ArchivedChats } from '../components/left/ArchivedChats';
|
export { default as ArchivedChats } from '../components/left/ArchivedChats';
|
||||||
|
export { default as ChatFolderModal } from '../components/left/ChatFolderModal';
|
||||||
|
|
||||||
export { default as ContextMenuContainer } from '../components/middle/message/ContextMenuContainer';
|
export { default as ContextMenuContainer } from '../components/middle/message/ContextMenuContainer';
|
||||||
export { default as StickerSetModal } from '../components/common/StickerSetModal';
|
export { default as StickerSetModal } from '../components/common/StickerSetModal';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
getMessageContent,
|
getMessageContent,
|
||||||
getMessageSummaryText,
|
getMessageSummaryText,
|
||||||
getUserFullName,
|
getUserFullName,
|
||||||
isChat,
|
isChatPrivate,
|
||||||
} from '../../../modules/helpers';
|
} from '../../../modules/helpers';
|
||||||
import trimText from '../../../util/trimText';
|
import trimText from '../../../util/trimText';
|
||||||
import { formatCurrency } from '../../../util/formatCurrency';
|
import { formatCurrency } from '../../../util/formatCurrency';
|
||||||
@ -167,9 +167,9 @@ function renderMessageContent(lang: LangFn, message: ApiMessage, options: Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderOriginContent(lang: LangFn, origin: ApiUser | ApiChat, asPlain?: boolean) {
|
function renderOriginContent(lang: LangFn, origin: ApiUser | ApiChat, asPlain?: boolean) {
|
||||||
return isChat(origin)
|
return isChatPrivate(origin.id)
|
||||||
? renderChatContent(lang, origin, asPlain)
|
? renderUserContent(origin as ApiUser, asPlain)
|
||||||
: renderUserContent(origin, asPlain);
|
: renderChatContent(lang, origin as ApiChat, asPlain);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderUserContent(sender: ApiUser, asPlain?: boolean): string | TextPart | undefined {
|
function renderUserContent(sender: ApiUser, asPlain?: boolean): string | TextPart | undefined {
|
||||||
|
|||||||
15
src/components/left/ChatFolderModal.async.tsx
Normal file
15
src/components/left/ChatFolderModal.async.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React, { FC, memo } from '../../lib/teact/teact';
|
||||||
|
import { Bundles } from '../../util/moduleLoader';
|
||||||
|
import { OwnProps } from './ChatFolderModal';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const ChatFolderModalAsync: FC<OwnProps> = (props) => {
|
||||||
|
const { isOpen } = props;
|
||||||
|
const ChatFolderModal = useModuleLoader(Bundles.Extra, 'ChatFolderModal', !isOpen);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
return ChatFolderModal ? <ChatFolderModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ChatFolderModalAsync);
|
||||||
110
src/components/left/ChatFolderModal.tsx
Normal file
110
src/components/left/ChatFolderModal.tsx
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import React, {
|
||||||
|
FC, useCallback, memo, useMemo, useState,
|
||||||
|
} from '../../lib/teact/teact';
|
||||||
|
import { withGlobal } from '../../lib/teact/teactn';
|
||||||
|
|
||||||
|
import { GlobalActions } from '../../global/types';
|
||||||
|
import { ApiChatFolder } from '../../api/types';
|
||||||
|
|
||||||
|
import { pick } from '../../util/iteratees';
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
|
|
||||||
|
import Modal from '../ui/Modal';
|
||||||
|
import Button from '../ui/Button';
|
||||||
|
import CheckboxGroup from '../ui/CheckboxGroup';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
chatId: number;
|
||||||
|
onClose: () => void;
|
||||||
|
onCloseAnimationEnd?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
foldersById?: Record<number, ApiChatFolder>;
|
||||||
|
folderOrderedIds?: number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type DispatchProps = Pick<GlobalActions, 'editChatFolders'>;
|
||||||
|
|
||||||
|
const ChatFolderModal: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||||
|
isOpen,
|
||||||
|
chatId,
|
||||||
|
foldersById,
|
||||||
|
folderOrderedIds,
|
||||||
|
onClose,
|
||||||
|
onCloseAnimationEnd,
|
||||||
|
editChatFolders,
|
||||||
|
}) => {
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const initialSelectedFolderIds = useMemo(() => {
|
||||||
|
if (!foldersById) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(foldersById).reduce((result, folderId) => {
|
||||||
|
const { includedChatIds, pinnedChatIds } = foldersById[Number(folderId)];
|
||||||
|
if (includedChatIds.includes(chatId) || pinnedChatIds?.includes(chatId)) {
|
||||||
|
result.push(folderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, [] as string[]);
|
||||||
|
}, [chatId, foldersById]);
|
||||||
|
|
||||||
|
const [selectedFolderIds, setSelectedFolderIds] = useState<string[]>(initialSelectedFolderIds);
|
||||||
|
|
||||||
|
const folders = useMemo(() => {
|
||||||
|
return folderOrderedIds?.map((folderId) => ({
|
||||||
|
label: foldersById ? foldersById[folderId].title : '',
|
||||||
|
value: String(folderId),
|
||||||
|
})) || [];
|
||||||
|
}, [folderOrderedIds, foldersById]);
|
||||||
|
|
||||||
|
const handleSubmit = useCallback(() => {
|
||||||
|
const idsToRemove = initialSelectedFolderIds.filter((id) => !selectedFolderIds.includes(id)).map(Number);
|
||||||
|
const idsToAdd = selectedFolderIds.filter((id) => !initialSelectedFolderIds.includes(id)).map(Number);
|
||||||
|
|
||||||
|
editChatFolders({ chatId, idsToRemove, idsToAdd });
|
||||||
|
onClose();
|
||||||
|
}, [chatId, editChatFolders, initialSelectedFolderIds, onClose, selectedFolderIds]);
|
||||||
|
|
||||||
|
if (!foldersById || !folderOrderedIds) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
onCloseAnimationEnd={onCloseAnimationEnd}
|
||||||
|
onEnter={handleSubmit}
|
||||||
|
className="delete"
|
||||||
|
title={lang('FilterAddTo')}
|
||||||
|
>
|
||||||
|
<CheckboxGroup
|
||||||
|
options={folders}
|
||||||
|
selected={selectedFolderIds}
|
||||||
|
onChange={setSelectedFolderIds}
|
||||||
|
round
|
||||||
|
/>
|
||||||
|
<Button color="primary" className="confirm-dialog-button" isText onClick={handleSubmit}>
|
||||||
|
{lang('FilterAddTo')}
|
||||||
|
</Button>
|
||||||
|
<Button className="confirm-dialog-button" isText onClick={onClose}>{lang('Cancel')}</Button>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): StateProps => {
|
||||||
|
const { byId: foldersById, orderedIds: folderOrderedIds } = global.chatFolders;
|
||||||
|
|
||||||
|
return {
|
||||||
|
foldersById,
|
||||||
|
folderOrderedIds,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
(setGlobal, actions): DispatchProps => pick(actions, ['editChatFolders']),
|
||||||
|
)(ChatFolderModal));
|
||||||
@ -50,6 +50,7 @@ import LastMessageMeta from '../../common/LastMessageMeta';
|
|||||||
import DeleteChatModal from '../../common/DeleteChatModal';
|
import DeleteChatModal from '../../common/DeleteChatModal';
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import Badge from './Badge';
|
import Badge from './Badge';
|
||||||
|
import ChatFolderModal from '../ChatFolderModal.async';
|
||||||
|
|
||||||
import './Chat.scss';
|
import './Chat.scss';
|
||||||
|
|
||||||
@ -111,7 +112,9 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();
|
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();
|
||||||
|
const [isChatFolderModalOpen, openChatFolderModal, closeChatFolderModal] = useFlag();
|
||||||
const [shouldRenderDeleteModal, markRenderDeleteModal, unmarkRenderDeleteModal] = useFlag();
|
const [shouldRenderDeleteModal, markRenderDeleteModal, unmarkRenderDeleteModal] = useFlag();
|
||||||
|
const [shouldRenderChatFolderModal, markRenderChatFolderModal, unmarkRenderChatFolderModal] = useFlag();
|
||||||
|
|
||||||
const { lastMessage, typingStatus } = chat || {};
|
const { lastMessage, typingStatus } = chat || {};
|
||||||
const isAction = lastMessage && isActionMessage(lastMessage);
|
const isAction = lastMessage && isActionMessage(lastMessage);
|
||||||
@ -185,10 +188,16 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
openDeleteModal();
|
openDeleteModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleChatFolderChange() {
|
||||||
|
markRenderChatFolderModal();
|
||||||
|
openChatFolderModal();
|
||||||
|
}
|
||||||
|
|
||||||
const contextActions = useChatContextActions({
|
const contextActions = useChatContextActions({
|
||||||
chat,
|
chat,
|
||||||
privateChatUser,
|
privateChatUser,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
|
handleChatFolderChange,
|
||||||
folderId,
|
folderId,
|
||||||
isPinned,
|
isPinned,
|
||||||
isMuted,
|
isMuted,
|
||||||
@ -299,6 +308,14 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
chat={chat}
|
chat={chat}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{shouldRenderChatFolderModal && (
|
||||||
|
<ChatFolderModal
|
||||||
|
isOpen={isChatFolderModalOpen}
|
||||||
|
onClose={closeChatFolderModal}
|
||||||
|
onCloseAnimationEnd={unmarkRenderChatFolderModal}
|
||||||
|
chatId={chatId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import PrivateChatInfo from '../../common/PrivateChatInfo';
|
|||||||
import GroupChatInfo from '../../common/GroupChatInfo';
|
import GroupChatInfo from '../../common/GroupChatInfo';
|
||||||
import DeleteChatModal from '../../common/DeleteChatModal';
|
import DeleteChatModal from '../../common/DeleteChatModal';
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
|
import ChatFolderModal from '../ChatFolderModal.async';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: number;
|
chatId: number;
|
||||||
@ -41,6 +42,7 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
|||||||
onClick,
|
onClick,
|
||||||
}) => {
|
}) => {
|
||||||
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();
|
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();
|
||||||
|
const [isChatFolderModalOpen, openChatFolderModal, closeChatFolderModal] = useFlag();
|
||||||
|
|
||||||
const contextActions = useChatContextActions({
|
const contextActions = useChatContextActions({
|
||||||
chat,
|
chat,
|
||||||
@ -48,6 +50,7 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
|||||||
isPinned,
|
isPinned,
|
||||||
isMuted,
|
isMuted,
|
||||||
handleDelete: openDeleteModal,
|
handleDelete: openDeleteModal,
|
||||||
|
handleChatFolderChange: openChatFolderModal,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@ -77,6 +80,11 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={closeDeleteModal}
|
onClose={closeDeleteModal}
|
||||||
chat={chat}
|
chat={chat}
|
||||||
/>
|
/>
|
||||||
|
<ChatFolderModal
|
||||||
|
isOpen={isChatFolderModalOpen}
|
||||||
|
onClose={closeChatFolderModal}
|
||||||
|
chatId={chatId}
|
||||||
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import React, { FC, memo, useCallback } from '../../lib/teact/teact';
|
|||||||
|
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
import renderText from '../common/helpers/renderText';
|
||||||
|
|
||||||
import Spinner from './Spinner';
|
import Spinner from './Spinner';
|
||||||
|
|
||||||
@ -69,8 +70,8 @@ const Checkbox: FC<OwnProps> = ({
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<div className="Checkbox-main">
|
<div className="Checkbox-main">
|
||||||
<span className="label" dir="auto">{label}</span>
|
<span className="label" dir="auto">{renderText(label)}</span>
|
||||||
{subLabel && <span className="subLabel" dir="auto">{subLabel}</span>}
|
{subLabel && <span className="subLabel" dir="auto">{renderText(subLabel)}</span>}
|
||||||
</div>
|
</div>
|
||||||
{isLoading && <Spinner />}
|
{isLoading && <Spinner />}
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const CheckboxGroup: FC<OwnProps> = ({
|
|||||||
loadingOptions,
|
loadingOptions,
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const [values, setValues] = useState<string[]>([]);
|
const [values, setValues] = useState<string[]>(selected || []);
|
||||||
|
|
||||||
const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const { value, checked } = event.currentTarget;
|
const { value, checked } = event.currentTarget;
|
||||||
|
|||||||
@ -460,7 +460,7 @@ export type ActionTypes = (
|
|||||||
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |
|
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |
|
||||||
'updateChat' | 'toggleSignatures' | 'loadGroupsForDiscussion' | 'linkDiscussionGroup' | 'unlinkDiscussionGroup' |
|
'updateChat' | 'toggleSignatures' | 'loadGroupsForDiscussion' | 'linkDiscussionGroup' | 'unlinkDiscussionGroup' |
|
||||||
'loadProfilePhotos' | 'loadMoreMembers' | 'setActiveChatFolder' | 'openNextChat' |
|
'loadProfilePhotos' | 'loadMoreMembers' | 'setActiveChatFolder' | 'openNextChat' |
|
||||||
'addChatMembers' | 'deleteChatMember' | 'openPreviousChat' |
|
'addChatMembers' | 'deleteChatMember' | 'openPreviousChat' | 'editChatFolders' |
|
||||||
// messages
|
// messages
|
||||||
'loadViewportMessages' | 'selectMessage' | 'sendMessage' | 'cancelSendingMessage' | 'pinMessage' | 'deleteMessages' |
|
'loadViewportMessages' | 'selectMessage' | 'sendMessage' | 'cancelSendingMessage' | 'pinMessage' | 'deleteMessages' |
|
||||||
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export default ({
|
|||||||
chat,
|
chat,
|
||||||
privateChatUser,
|
privateChatUser,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
|
handleChatFolderChange,
|
||||||
folderId,
|
folderId,
|
||||||
isPinned,
|
isPinned,
|
||||||
isMuted,
|
isMuted,
|
||||||
@ -19,6 +20,7 @@ export default ({
|
|||||||
chat: ApiChat | undefined;
|
chat: ApiChat | undefined;
|
||||||
privateChatUser: ApiUser | undefined;
|
privateChatUser: ApiUser | undefined;
|
||||||
handleDelete: () => void;
|
handleDelete: () => void;
|
||||||
|
handleChatFolderChange: () => void;
|
||||||
folderId?: number;
|
folderId?: number;
|
||||||
isPinned?: boolean;
|
isPinned?: boolean;
|
||||||
isMuted?: boolean;
|
isMuted?: boolean;
|
||||||
@ -37,6 +39,12 @@ export default ({
|
|||||||
toggleChatUnread,
|
toggleChatUnread,
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
|
const actionAddToFolder = {
|
||||||
|
title: lang('ChatList.Filter.AddToFolder'),
|
||||||
|
icon: 'folder',
|
||||||
|
handler: handleChatFolderChange,
|
||||||
|
};
|
||||||
|
|
||||||
const actionPin = isPinned
|
const actionPin = isPinned
|
||||||
? {
|
? {
|
||||||
title: lang('UnpinFromTop'),
|
title: lang('UnpinFromTop'),
|
||||||
@ -46,7 +54,7 @@ export default ({
|
|||||||
: { title: lang('PinToTop'), icon: 'pin', handler: () => toggleChatPinned({ id: chat.id, folderId }) };
|
: { title: lang('PinToTop'), icon: 'pin', handler: () => toggleChatPinned({ id: chat.id, folderId }) };
|
||||||
|
|
||||||
if (isInSearch) {
|
if (isInSearch) {
|
||||||
return [actionPin];
|
return [actionPin, actionAddToFolder];
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionUnreadMark = chat.unreadCount || chat.hasUnreadMark
|
const actionUnreadMark = chat.unreadCount || chat.hasUnreadMark
|
||||||
@ -81,6 +89,7 @@ export default ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
actionAddToFolder,
|
||||||
actionUnreadMark,
|
actionUnreadMark,
|
||||||
actionPin,
|
actionPin,
|
||||||
...(!privateChatUser?.isSelf ? [
|
...(!privateChatUser?.isSelf ? [
|
||||||
@ -89,5 +98,7 @@ export default ({
|
|||||||
] : []),
|
] : []),
|
||||||
actionDelete,
|
actionDelete,
|
||||||
];
|
];
|
||||||
}, [chat, isPinned, lang, isInSearch, isMuted, handleDelete, privateChatUser?.isSelf, folderId]);
|
}, [
|
||||||
|
chat, isPinned, lang, isInSearch, isMuted, handleDelete, handleChatFolderChange, privateChatUser?.isSelf, folderId,
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -435,6 +435,37 @@ addReducer('loadRecommendedChatFolders', () => {
|
|||||||
void loadRecommendedChatFolders();
|
void loadRecommendedChatFolders();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('editChatFolders', (global, actions, payload) => {
|
||||||
|
const { chatId, idsToRemove, idsToAdd } = payload!;
|
||||||
|
|
||||||
|
(idsToRemove as number[]).forEach(async (id) => {
|
||||||
|
const folder = selectChatFolder(global, id);
|
||||||
|
if (folder) {
|
||||||
|
await callApi('editChatFolder', {
|
||||||
|
id,
|
||||||
|
folderUpdate: {
|
||||||
|
...folder,
|
||||||
|
pinnedChatIds: folder.pinnedChatIds?.filter((pinnedId) => pinnedId !== chatId),
|
||||||
|
includedChatIds: folder.includedChatIds.filter((includedId) => includedId !== chatId),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(idsToAdd as number[]).forEach(async (id) => {
|
||||||
|
const folder = selectChatFolder(global, id);
|
||||||
|
if (folder) {
|
||||||
|
await callApi('editChatFolder', {
|
||||||
|
id,
|
||||||
|
folderUpdate: {
|
||||||
|
...folder,
|
||||||
|
includedChatIds: folder.includedChatIds.concat(chatId),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
addReducer('editChatFolder', (global, actions, payload) => {
|
addReducer('editChatFolder', (global, actions, payload) => {
|
||||||
const { id, folderUpdate } = payload!;
|
const { id, folderUpdate } = payload!;
|
||||||
const folder = selectChatFolder(global, id);
|
const folder = selectChatFolder(global, id);
|
||||||
|
|||||||
@ -498,14 +498,6 @@ function getFolderChatsCount(
|
|||||||
return pinnedChats.length + otherChats.length;
|
return pinnedChats.length + otherChats.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isChat(chatOrUser?: ApiUser | ApiChat): chatOrUser is ApiChat {
|
|
||||||
if (!chatOrUser) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return chatOrUser.id < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMessageSenderName(lang: LangFn, chatId: number, sender?: ApiUser) {
|
export function getMessageSenderName(lang: LangFn, chatId: number, sender?: ApiUser) {
|
||||||
if (!sender || isChatPrivate(chatId)) {
|
if (!sender || isChatPrivate(chatId)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user