Composer / Send As: Display lock icon for non-premium users (#2076)
This commit is contained in:
parent
04dee2ce7b
commit
d0735fcc0e
@ -11,6 +11,7 @@ import type {
|
||||
ApiExportedInvite,
|
||||
ApiChatInviteImporter,
|
||||
ApiChatSettings,
|
||||
ApiSendAsPeerId,
|
||||
} from '../../types';
|
||||
import { pick, pickTruthy } from '../../../util/iteratees';
|
||||
import {
|
||||
@ -467,3 +468,10 @@ export function buildApiChatReactions(availableReactions?: GramJs.TypeChatReacti
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildApiSendAsPeerId(sendAs: GramJs.SendAsPeer): ApiSendAsPeerId {
|
||||
return {
|
||||
id: getApiChatIdFromMtpPeer(sendAs.peer),
|
||||
isPremium: sendAs.premiumRequired,
|
||||
};
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ import {
|
||||
buildInputPollFromExisting,
|
||||
} from '../gramjsBuilders';
|
||||
import localDb from '../localDb';
|
||||
import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
||||
import { buildApiChatFromPreview, buildApiSendAsPeerId } from '../apiBuilders/chats';
|
||||
import { fetchFile } from '../../../util/files';
|
||||
import {
|
||||
addEntitiesWithPhotosToLocalDb,
|
||||
@ -65,7 +65,6 @@ import {
|
||||
} from '../helpers';
|
||||
import { interpolateArray } from '../../../util/waveform';
|
||||
import { requestChatUpdate } from './chats';
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
|
||||
const FAST_SEND_TIMEOUT = 1000;
|
||||
const INPUT_WAVEFORM_LENGTH = 63;
|
||||
@ -1311,13 +1310,13 @@ export async function fetchSendAs({
|
||||
addEntitiesWithPhotosToLocalDb(result.users);
|
||||
addEntitiesWithPhotosToLocalDb(result.chats);
|
||||
|
||||
const users = result.users.map(buildApiUser).filter<ApiUser>(Boolean as any);
|
||||
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter<ApiChat>(Boolean as any);
|
||||
const users = result.users.map(buildApiUser).filter(Boolean);
|
||||
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
|
||||
|
||||
return {
|
||||
users,
|
||||
chats,
|
||||
ids: result.peers.map((sendAsPeer) => getApiChatIdFromMtpPeer(sendAsPeer.peer)),
|
||||
sendAs: result.peers.map(buildApiSendAsPeerId),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ export interface ApiChat {
|
||||
joinRequests?: ApiChatInviteImporter[];
|
||||
isJoinToSend?: boolean;
|
||||
isJoinRequest?: boolean;
|
||||
sendAsIds?: string[];
|
||||
sendAsPeerIds?: ApiSendAsPeerId[];
|
||||
|
||||
unreadReactions?: number[];
|
||||
unreadMentions?: number[];
|
||||
@ -182,3 +182,8 @@ export interface ApiChatSettings {
|
||||
canAddContact?: boolean;
|
||||
canBlockContact?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiSendAsPeerId {
|
||||
id: string;
|
||||
isPremium?: boolean;
|
||||
}
|
||||
|
||||
@ -282,8 +282,9 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
const lastMessageSendTimeSeconds = useRef<number>();
|
||||
const prevDropAreaState = usePrevious(dropAreaState);
|
||||
const { width: windowWidth } = windowSize.get();
|
||||
const sendAsIds = chat?.sendAsIds;
|
||||
const canShowSendAs = sendAsIds && (sendAsIds.length > 1 || !sendAsIds.includes(currentUserId!));
|
||||
const sendAsPeerIds = chat?.sendAsPeerIds;
|
||||
const canShowSendAs = sendAsPeerIds
|
||||
&& (sendAsPeerIds.length > 1 || !sendAsPeerIds.some((peer) => peer.id === currentUserId!));
|
||||
// Prevent Symbol Menu from closing when calendar is open
|
||||
const [isSymbolMenuForced, forceShowSymbolMenu, cancelForceShowSymbolMenu] = useFlag();
|
||||
const sendMessageAction = useSendMessageAction(chatId, threadId);
|
||||
@ -304,10 +305,10 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
}, [isReady, chatId, loadScheduledHistory, lastSyncTime, threadId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId && chat && lastSyncTime && !sendAsIds && isReady && isChatSuperGroup(chat)) {
|
||||
if (chatId && chat && lastSyncTime && !sendAsPeerIds && isReady && isChatSuperGroup(chat)) {
|
||||
loadSendAs({ chatId });
|
||||
}
|
||||
}, [chat, chatId, isReady, lastSyncTime, loadSendAs, sendAsIds]);
|
||||
}, [chat, chatId, isReady, lastSyncTime, loadSendAs, sendAsPeerIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId && chat && lastSyncTime && !chat.fullInfo && isReady && isChatSuperGroup(chat)) {
|
||||
@ -316,10 +317,10 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
}, [chat, chatId, isReady, lastSyncTime, loadFullChat]);
|
||||
|
||||
const shouldAnimateSendAsButtonRef = useRef(false);
|
||||
useOnChange(([prevChatId, prevSendAsIds]) => {
|
||||
// We only animate send-as button if `sendAsIds` was missing when opening the chat
|
||||
shouldAnimateSendAsButtonRef.current = Boolean(chatId === prevChatId && sendAsIds && !prevSendAsIds);
|
||||
}, [chatId, sendAsIds]);
|
||||
useOnChange(([prevChatId, prevSendAsPeerIds]) => {
|
||||
// We only animate send-as button if `sendAsPeerIds` was missing when opening the chat
|
||||
shouldAnimateSendAsButtonRef.current = Boolean(chatId === prevChatId && sendAsPeerIds && !prevSendAsPeerIds);
|
||||
}, [chatId, sendAsPeerIds]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!appendixRef.current) return;
|
||||
@ -1056,7 +1057,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
onClose={closeSendAsMenu}
|
||||
chatId={chatId}
|
||||
selectedSendAsId={sendAsId}
|
||||
sendAsIds={sendAsIds}
|
||||
sendAsPeerIds={sendAsPeerIds}
|
||||
isCurrentUserPremium={isCurrentUserPremium}
|
||||
/>
|
||||
<MentionTooltip
|
||||
isOpen={isMentionTooltipOpen}
|
||||
@ -1318,8 +1320,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const keyboardMessage = botKeyboardMessageId ? selectChatMessage(global, chatId, botKeyboardMessageId) : undefined;
|
||||
const { currentUserId } = global;
|
||||
const defaultSendAsId = chat?.fullInfo ? chat?.fullInfo?.sendAsId || currentUserId : undefined;
|
||||
const sendAsId = chat?.sendAsIds && defaultSendAsId && chat.sendAsIds.includes(defaultSendAsId)
|
||||
? defaultSendAsId
|
||||
const sendAsId = chat?.sendAsPeerIds && defaultSendAsId
|
||||
&& chat.sendAsPeerIds.some((peer) => peer.id === defaultSendAsId) ? defaultSendAsId
|
||||
: (chat?.adminRights?.anonymous ? chat?.id : undefined);
|
||||
const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined;
|
||||
const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined;
|
||||
|
||||
@ -59,6 +59,10 @@
|
||||
padding: 0.5625rem 1rem !important;
|
||||
border-radius: 0;
|
||||
align-items: center;
|
||||
|
||||
& > .send-as-icon-locked {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, {
|
||||
useCallback, useEffect, useRef, memo,
|
||||
} from '../../../lib/teact/teact';
|
||||
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import type { ApiSendAsPeerId } from '../../../api/types';
|
||||
|
||||
import setTooltipItemVisible from '../../../util/setTooltipItemVisible';
|
||||
import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
|
||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||
@ -21,20 +23,22 @@ import './SendAsMenu.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
chatId?: string;
|
||||
selectedSendAsId?: string;
|
||||
sendAsIds?: string[];
|
||||
sendAsPeerIds?: ApiSendAsPeerId[];
|
||||
isCurrentUserPremium?: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const SendAsMenu: FC<OwnProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
chatId,
|
||||
selectedSendAsId,
|
||||
sendAsIds,
|
||||
sendAsPeerIds,
|
||||
isCurrentUserPremium,
|
||||
onClose,
|
||||
}) => {
|
||||
const { saveDefaultSendAs } = getActions();
|
||||
const { saveDefaultSendAs, showNotification, openPremiumModal } = getActions();
|
||||
|
||||
// No need for expensive global updates on users and chats, so we avoid them
|
||||
const usersById = getGlobal().users.byId;
|
||||
@ -59,7 +63,7 @@ const SendAsMenu: FC<OwnProps> = ({
|
||||
|
||||
const selectedSendAsIndex = useKeyboardNavigation({
|
||||
isActive: isOpen,
|
||||
items: sendAsIds,
|
||||
items: sendAsPeerIds,
|
||||
onSelect: handleUserSelect,
|
||||
shouldSelectOnTab: true,
|
||||
shouldSaveSelectionOnUpdateItems: true,
|
||||
@ -71,10 +75,10 @@ const SendAsMenu: FC<OwnProps> = ({
|
||||
}, [selectedSendAsIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sendAsIds && !sendAsIds.length) {
|
||||
if (sendAsPeerIds && !sendAsPeerIds.length) {
|
||||
onClose();
|
||||
}
|
||||
}, [sendAsIds, onClose]);
|
||||
}, [sendAsPeerIds, onClose]);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
@ -90,18 +94,31 @@ const SendAsMenu: FC<OwnProps> = ({
|
||||
noCompact
|
||||
>
|
||||
<div className="send-as-title" dir="auto">{lang('SendMessageAsTitle')}</div>
|
||||
{usersById && chatsById && sendAsIds?.map((id, index) => {
|
||||
{usersById && chatsById && sendAsPeerIds?.map(({ id, isPremium }, index) => {
|
||||
const user = isUserId(id) ? usersById[id] : undefined;
|
||||
const chat = !user ? chatsById[id] : undefined;
|
||||
const userOrChat = user || chat;
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isPremium || isCurrentUserPremium) {
|
||||
handleUserSelect(id);
|
||||
} else {
|
||||
showNotification({
|
||||
message: lang('SelectSendAsPeerPremiumHint'),
|
||||
actionText: lang('Open'),
|
||||
action: () => openPremiumModal(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={id}
|
||||
className="SendAsItem chat-item-clickable scroll-item with-avatar"
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => handleUserSelect(id)}
|
||||
onClick={handleClick}
|
||||
focus={selectedSendAsIndex === index}
|
||||
rightElement={!isCurrentUserPremium && isPremium && <i className="icon-lock-badge send-as-icon-locked" />}
|
||||
>
|
||||
<Avatar
|
||||
size="small"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.Notification-container {
|
||||
position: relative;
|
||||
width: 24rem;
|
||||
width: 27rem;
|
||||
max-width: 100vw;
|
||||
margin: 4.25rem auto 0.25rem;
|
||||
z-index: var(--z-notification);
|
||||
@ -61,8 +61,8 @@
|
||||
color: var(--color-primary);
|
||||
font-weight: 500;
|
||||
text-transform: none;
|
||||
flex: 1;
|
||||
padding: 0 2rem;
|
||||
flex-shrink: 1;
|
||||
padding: 0.25rem;
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ export const MEDIA_PROGRESSIVE_CACHE_DISABLED = false;
|
||||
export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive';
|
||||
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
|
||||
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
|
||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v13';
|
||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v14';
|
||||
export const ASSET_CACHE_NAME = 'tt-assets';
|
||||
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
|
||||
|
||||
|
||||
@ -1091,7 +1091,7 @@ addActionHandler('loadSendAs', async (global, actions, payload) => {
|
||||
const result = await callApi('fetchSendAs', { chat });
|
||||
if (!result) {
|
||||
setGlobal(updateChat(getGlobal(), chatId, {
|
||||
sendAsIds: [],
|
||||
sendAsPeerIds: [],
|
||||
}));
|
||||
|
||||
return;
|
||||
@ -1100,7 +1100,7 @@ addActionHandler('loadSendAs', async (global, actions, payload) => {
|
||||
global = getGlobal();
|
||||
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
|
||||
global = addChats(global, buildCollectionByKey(result.chats, 'id'));
|
||||
global = updateChat(global, chatId, { sendAsIds: result.ids });
|
||||
global = updateChat(global, chatId, { sendAsPeerIds: result.sendAs });
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user