Settings: Implement settings privacy for gifts (#5802)
This commit is contained in:
parent
97bd26df00
commit
05ff8a385b
@ -1,6 +1,7 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type {
|
||||
ApiDisallowedGiftsSettings,
|
||||
ApiInputSavedStarGift,
|
||||
ApiSavedStarGift,
|
||||
ApiStarGift,
|
||||
@ -156,3 +157,21 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId
|
||||
isPinned: pinnedToTop,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiDisallowedGiftsSettings(
|
||||
result: GramJs.TypeDisallowedGiftsSettings,
|
||||
): ApiDisallowedGiftsSettings {
|
||||
const {
|
||||
disallowUnlimitedStargifts,
|
||||
disallowLimitedStargifts,
|
||||
disallowUniqueStargifts,
|
||||
disallowPremiumGifts,
|
||||
} = result;
|
||||
|
||||
return {
|
||||
shouldDisallowUnlimitedStarGifts: disallowUnlimitedStargifts,
|
||||
shouldDisallowLimitedStarGifts: disallowLimitedStargifts,
|
||||
shouldDisallowUniqueStarGifts: disallowUniqueStargifts,
|
||||
shouldDisallowPremiumGifts: disallowPremiumGifts,
|
||||
};
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import { buildApiBusinessIntro, buildApiBusinessLocation, buildApiBusinessWorkHo
|
||||
import {
|
||||
buildApiBotVerification, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
} from './common';
|
||||
import { buildApiDisallowedGiftsSettings } from './gifts';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiEmojiStatus, buildApiPeerColor, buildApiPeerId } from './peers';
|
||||
|
||||
@ -25,7 +26,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
fallbackPhoto, personalPhoto, translationsDisabled, storiesPinnedAvailable,
|
||||
contactRequirePremium, businessWorkHours, businessLocation, businessIntro,
|
||||
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled, stargiftsCount, botVerification,
|
||||
botCanManageEmojiStatus, settings, sendPaidMessagesStars,
|
||||
botCanManageEmojiStatus, settings, sendPaidMessagesStars, displayGiftsButton, disallowedGifts,
|
||||
},
|
||||
users,
|
||||
} = mtpUserFull;
|
||||
@ -45,6 +46,8 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
personalPhoto: personalPhoto instanceof GramJs.Photo ? buildApiPhoto(personalPhoto) : undefined,
|
||||
botInfo: botInfo && buildApiBotInfo(botInfo, userId),
|
||||
isContactRequirePremium: contactRequirePremium,
|
||||
shouldDisplayGiftsButton: displayGiftsButton,
|
||||
disallowedGifts: disallowedGifts && buildApiDisallowedGiftsSettings(disallowedGifts),
|
||||
birthday: birthday && buildApiBirthday(birthday),
|
||||
businessLocation: businessLocation && buildApiBusinessLocation(businessLocation),
|
||||
businessWorkHours: businessWorkHours && buildApiBusinessWorkHours(businessWorkHours),
|
||||
|
||||
@ -8,6 +8,7 @@ import type {
|
||||
ApiChatBannedRights,
|
||||
ApiChatFolder,
|
||||
ApiChatReactions,
|
||||
ApiDisallowedGiftsSettings,
|
||||
ApiEmojiStatusType,
|
||||
ApiFormattedText,
|
||||
ApiGroupCall,
|
||||
@ -644,6 +645,15 @@ function buildPremiumGiftCodeOption(optionData: ApiPremiumGiftCodeOption) {
|
||||
});
|
||||
}
|
||||
|
||||
export function buildDisallowedGiftsSettings(disallowedGifts: ApiDisallowedGiftsSettings) {
|
||||
return new GramJs.DisallowedGiftsSettings({
|
||||
disallowUnlimitedStargifts: disallowedGifts.shouldDisallowLimitedStarGifts,
|
||||
disallowLimitedStargifts: disallowedGifts.shouldDisallowUnlimitedStarGifts,
|
||||
disallowUniqueStargifts: disallowedGifts.shouldDisallowUniqueStarGifts,
|
||||
disallowPremiumGifts: disallowedGifts.shouldDisallowPremiumGifts,
|
||||
});
|
||||
}
|
||||
|
||||
export function buildInputInvoice(invoice: ApiRequestInputInvoice) {
|
||||
switch (invoice.type) {
|
||||
case 'message': {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import BigInt from 'big-integer';
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import { RPCError } from '../../../lib/gramjs/errors';
|
||||
|
||||
import type {
|
||||
ApiChat,
|
||||
@ -184,21 +185,14 @@ export async function getPaymentForm(inputInvoice: ApiRequestInputInvoice, theme
|
||||
}
|
||||
|
||||
return buildApiPaymentForm(result);
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
// Can be removed if separate error handling is added to payment UI
|
||||
sendApiUpdate({
|
||||
'@type': 'error',
|
||||
error: {
|
||||
message: err.message,
|
||||
hasErrorKey: true,
|
||||
},
|
||||
});
|
||||
} catch (err: any) {
|
||||
if (err instanceof RPCError) {
|
||||
return {
|
||||
error: err.message,
|
||||
error: err.errorMessage,
|
||||
};
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import type { LANG_PACKS } from '../../../config';
|
||||
import type {
|
||||
ApiAppConfig,
|
||||
ApiConfig,
|
||||
ApiDisallowedGiftsSettings,
|
||||
ApiInputPrivacyRules,
|
||||
ApiLanguage,
|
||||
ApiNotifyPeerType,
|
||||
@ -24,6 +25,7 @@ import {
|
||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||
import { buildAppConfig } from '../apiBuilders/appConfig';
|
||||
import { buildApiPhoto, buildPrivacyRules } from '../apiBuilders/common';
|
||||
import { buildApiDisallowedGiftsSettings } from '../apiBuilders/gifts';
|
||||
import {
|
||||
buildApiConfig,
|
||||
buildApiCountryList,
|
||||
@ -39,6 +41,7 @@ import {
|
||||
} from '../apiBuilders/misc';
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import {
|
||||
buildDisallowedGiftsSettings,
|
||||
buildInputEntity, buildInputPeer, buildInputPhoto,
|
||||
buildInputPrivacyKey,
|
||||
buildInputPrivacyRules,
|
||||
@ -657,6 +660,8 @@ export async function fetchGlobalPrivacySettings() {
|
||||
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
||||
shouldNewNonContactPeersRequirePremium: Boolean(result.newNoncontactPeersRequirePremium),
|
||||
nonContactPeersPaidStars: Number(result.noncontactPeersPaidStars),
|
||||
shouldDisplayGiftsButton: Boolean(result.displayGiftsButton),
|
||||
disallowedGifts: result.disallowedGifts && buildApiDisallowedGiftsSettings(result.disallowedGifts),
|
||||
};
|
||||
}
|
||||
|
||||
@ -665,18 +670,24 @@ export async function updateGlobalPrivacySettings({
|
||||
shouldHideReadMarks,
|
||||
shouldNewNonContactPeersRequirePremium,
|
||||
nonContactPeersPaidStars,
|
||||
shouldDisplayGiftsButton,
|
||||
disallowedGifts,
|
||||
}: {
|
||||
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||
shouldHideReadMarks?: boolean;
|
||||
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||
nonContactPeersPaidStars?: number | null;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
disallowedGifts?: ApiDisallowedGiftsSettings;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.account.SetGlobalPrivacySettings({
|
||||
settings: new GramJs.GlobalPrivacySettings({
|
||||
...(shouldArchiveAndMuteNewNonContact && { archiveAndMuteNewNoncontactPeers: true }),
|
||||
...(shouldHideReadMarks && { hideReadMarks: true }),
|
||||
...(shouldNewNonContactPeersRequirePremium && { newNoncontactPeersRequirePremium: true }),
|
||||
displayGiftsButton: shouldDisplayGiftsButton || undefined,
|
||||
noncontactPeersPaidStars: BigInt(nonContactPeersPaidStars || 0),
|
||||
disallowedGifts: disallowedGifts && buildDisallowedGiftsSettings(disallowedGifts),
|
||||
}),
|
||||
}));
|
||||
|
||||
@ -689,6 +700,8 @@ export async function updateGlobalPrivacySettings({
|
||||
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
||||
shouldNewNonContactPeersRequirePremium: Boolean(result.newNoncontactPeersRequirePremium),
|
||||
nonContactPeersPaidStars: Number(result.noncontactPeersPaidStars),
|
||||
shouldDisplayGiftsButton,
|
||||
disallowedGifts,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -215,3 +215,10 @@ export interface ApiStarsGiveawayWinnerOption {
|
||||
users: number;
|
||||
perUserStars: number;
|
||||
}
|
||||
|
||||
export interface ApiDisallowedGiftsSettings {
|
||||
shouldDisallowUnlimitedStarGifts?: true;
|
||||
shouldDisallowLimitedStarGifts?: true;
|
||||
shouldDisallowUniqueStarGifts?: true;
|
||||
shouldDisallowPremiumGifts?: true;
|
||||
}
|
||||
|
||||
@ -55,6 +55,8 @@ export interface ApiUserFullInfo {
|
||||
areAdsEnabled?: boolean;
|
||||
hasPinnedStories?: boolean;
|
||||
isContactRequirePremium?: boolean;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
disallowedGifts?: ApiDisallowedGifts;
|
||||
birthday?: ApiBirthday;
|
||||
personalChannelId?: string;
|
||||
personalChannelMessageId?: number;
|
||||
@ -156,3 +158,10 @@ export interface ApiBirthday {
|
||||
month: number;
|
||||
year?: number;
|
||||
}
|
||||
|
||||
export interface ApiDisallowedGifts {
|
||||
shouldDisallowUnlimitedStarGifts?: boolean;
|
||||
shouldDisallowLimitedStarGifts?: boolean;
|
||||
shouldDisallowUniqueStarGifts?: boolean;
|
||||
shouldDisallowPremiumGifts?: boolean;
|
||||
}
|
||||
|
||||
@ -1564,7 +1564,28 @@
|
||||
"PrivacyGifts" = "Gifts";
|
||||
"PrivacyGiftsTitle" = "Who can display gifts on my profile?";
|
||||
"PrivacyGiftsInfo" = "Choose whether gifts from specific senders need your approval before they're visible to others on your profile.";
|
||||
"PrivacyAcceptedGiftTitle" = "Accepted gift types";
|
||||
"PrivacyAcceptedGiftInfo" = "Choose the types of gifts that you allow others to send you.";
|
||||
"PrivacyValueBots" = "Mini Apps";
|
||||
"PrivacyGiftLimitedEdition" = "Limited-Edition";
|
||||
"PrivacyGiftUnlimited" = "Unlimited";
|
||||
"PrivacyGiftUnique" = "Unique";
|
||||
"PrivacyGiftPremiumSubscription" = "Premium Subscription";
|
||||
"PrivacyDisplayGiftsButton" = "Show gift icon in chats";
|
||||
"PrivacyDisplayGift" = "Gift";
|
||||
"SendDisallowError" = "User is not accepting gifts";
|
||||
"PrivacyDisplayGiftIconInChats" = "Display the {icon} {gift} in the message input field for both participants in all chats.";
|
||||
"PrivacySubscribeToTelegramPremium" = "Subscribe to **Telegram Premium** to select this option.";
|
||||
"PrivacyDisableLimitedEditionStarGifts" = "Disable Limited-Edition Star Gifts";
|
||||
"PrivacyEnableLimitedEditionStarGifts" = "Enable Limited-Edition Star Gifts";
|
||||
"PrivacyDisableUnlimitedStarGifts" = "Disable Unlimited Star Gifts";
|
||||
"PrivacyEnableUnlimitedStarGifts" = "Enable Unlimited Star Gifts";
|
||||
"PrivacyDisableUniqueStarGifts" = "Disable Unique Star Gifts";
|
||||
"PrivacyEnableUniqueStarGifts" = "Enable Unique Star Gifts";
|
||||
"PrivacyDisablePremiumGifts" = "Disable Premium Gifts";
|
||||
"PrivacyEnablePremiumGifts" = "Enable Premium Gifts";
|
||||
"DisplayGiftsButton" = "Display Gifts Button";
|
||||
"HideGiftsButton" = "Hide Gifts Button";
|
||||
"CustomShareGiftsInfo" = "You can add users or entire groups as exceptions that will override the settings above.";
|
||||
"StarsSubscribeBotText_one" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** star per month?";
|
||||
"StarsSubscribeBotText_other" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** stars per month?";
|
||||
|
||||
@ -15,6 +15,7 @@ import type {
|
||||
ApiBotMenuButton,
|
||||
ApiChat,
|
||||
ApiChatFullInfo,
|
||||
ApiDisallowedGifts,
|
||||
ApiDraft,
|
||||
ApiFormattedText,
|
||||
ApiMessage,
|
||||
@ -227,6 +228,7 @@ type StateProps =
|
||||
isRightColumnShown?: boolean;
|
||||
isSelectModeActive?: boolean;
|
||||
isReactionPickerOpen?: boolean;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
isForwarding?: boolean;
|
||||
forwardedMessagesCount?: number;
|
||||
pollModal: TabState['pollModal'];
|
||||
@ -292,6 +294,7 @@ type StateProps =
|
||||
isPaymentMessageConfirmDialogOpen: boolean;
|
||||
starsBalance: number;
|
||||
isStarsBalanceModalOpen: boolean;
|
||||
disallowedGifts?: ApiDisallowedGifts;
|
||||
isAccountFrozen?: boolean;
|
||||
isAppConfigLoaded?: boolean;
|
||||
};
|
||||
@ -346,6 +349,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
isRightColumnShown,
|
||||
isSelectModeActive,
|
||||
isReactionPickerOpen,
|
||||
shouldDisplayGiftsButton,
|
||||
isForwarding,
|
||||
forwardedMessagesCount,
|
||||
pollModal,
|
||||
@ -414,6 +418,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
isPaymentMessageConfirmDialogOpen,
|
||||
starsBalance,
|
||||
isStarsBalanceModalOpen,
|
||||
disallowedGifts,
|
||||
isAccountFrozen,
|
||||
isAppConfigLoaded,
|
||||
}) => {
|
||||
@ -434,6 +439,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
showNotification,
|
||||
showAllowedMessageTypesNotification,
|
||||
openStoryReactionPicker,
|
||||
openGiftModal,
|
||||
closeReactionPicker,
|
||||
sendStoryReaction,
|
||||
editMessage,
|
||||
@ -835,6 +841,15 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
};
|
||||
}, [chatId, threadId, resetComposerRef, stopRecordingVoiceRef]);
|
||||
|
||||
const areAllGiftsDisallowed = useMemo(() => {
|
||||
if (!disallowedGifts) {
|
||||
return undefined;
|
||||
}
|
||||
return Object.values(disallowedGifts).every(Boolean);
|
||||
}, [disallowedGifts]);
|
||||
|
||||
const shouldShowGiftButton = Boolean(!isChatWithSelf && shouldDisplayGiftsButton && !areAllGiftsDisallowed);
|
||||
|
||||
const showCustomEmojiPremiumNotification = useLastCallback(() => {
|
||||
const notificationNumber = customEmojiNotificationNumber.current;
|
||||
if (!notificationNumber) {
|
||||
@ -1488,6 +1503,10 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
});
|
||||
|
||||
const handleGiftClick = useLastCallback(() => {
|
||||
openGiftModal({ forUserId: chatId });
|
||||
});
|
||||
|
||||
const handleToggleSilentPosting = useLastCallback(() => {
|
||||
const newValue = !isSilentPosting;
|
||||
updateChatSilentPosting({ chatId, isEnabled: newValue });
|
||||
@ -2061,6 +2080,17 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
<Icon name="schedule" />
|
||||
</Button>
|
||||
)}
|
||||
{shouldShowGiftButton && (
|
||||
<Button
|
||||
round
|
||||
faded
|
||||
className="composer-action-button"
|
||||
color="translucent"
|
||||
onClick={handleGiftClick}
|
||||
>
|
||||
<Icon name="gift" />
|
||||
</Button>
|
||||
)}
|
||||
{Boolean(botKeyboardMessageId) && !activeVoiceRecording && !editingMessage && (
|
||||
<ResponsiveHoverButton
|
||||
className={buildClassName('composer-action-button', isBotKeyboardOpen && 'activated')}
|
||||
@ -2464,6 +2494,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
isPaymentMessageConfirmDialogOpen: tabState.isPaymentMessageConfirmDialogOpen,
|
||||
starsBalance,
|
||||
isStarsBalanceModalOpen,
|
||||
shouldDisplayGiftsButton: userFullInfo?.shouldDisplayGiftsButton,
|
||||
disallowedGifts: userFullInfo?.disallowedGifts,
|
||||
isAccountFrozen,
|
||||
isAppConfigLoaded,
|
||||
};
|
||||
|
||||
@ -188,6 +188,10 @@
|
||||
&[dir="rtl"] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.gift-icon {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
}
|
||||
|
||||
.ListItem {
|
||||
|
||||
158
src/components/left/settings/SettingsAcceptedGift.tsx
Normal file
158
src/components/left/settings/SettingsAcceptedGift.tsx
Normal file
@ -0,0 +1,158 @@
|
||||
import React, { memo } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiDisallowedGiftsSettings } from '../../../api/types';
|
||||
|
||||
import { selectIsCurrentUserPremium } from '../../../global/selectors';
|
||||
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
import ListItem from '../../ui/ListItem';
|
||||
import Switcher from '../../ui/Switcher';
|
||||
|
||||
type StateProps = {
|
||||
disallowedGifts?: ApiDisallowedGiftsSettings;
|
||||
isCurrentUserPremium: boolean;
|
||||
};
|
||||
|
||||
const SettingsAcceptedGift = ({
|
||||
disallowedGifts, isCurrentUserPremium,
|
||||
}: StateProps) => {
|
||||
const { showNotification, updateGlobalPrivacySettings } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const handleOpenTelegramPremiumModal = useLastCallback(() => {
|
||||
showNotification({
|
||||
message: lang('PrivacySubscribeToTelegramPremium'),
|
||||
action: {
|
||||
action: 'openPremiumModal',
|
||||
payload: {},
|
||||
},
|
||||
actionText: { key: 'Open' },
|
||||
icon: 'star',
|
||||
});
|
||||
});
|
||||
|
||||
const handleLimitedEditionChange = useLastCallback(() => {
|
||||
if (!isCurrentUserPremium) {
|
||||
handleOpenTelegramPremiumModal();
|
||||
return;
|
||||
}
|
||||
|
||||
updateGlobalPrivacySettings({
|
||||
disallowedGifts: {
|
||||
...disallowedGifts,
|
||||
shouldDisallowLimitedStarGifts: !disallowedGifts?.shouldDisallowLimitedStarGifts || undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleUnlimitedEditionChange = useLastCallback(() => {
|
||||
if (!isCurrentUserPremium) {
|
||||
handleOpenTelegramPremiumModal();
|
||||
return;
|
||||
}
|
||||
updateGlobalPrivacySettings({
|
||||
disallowedGifts: {
|
||||
...disallowedGifts,
|
||||
shouldDisallowUnlimitedStarGifts: !disallowedGifts?.shouldDisallowUnlimitedStarGifts || undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleUniqueChange = useLastCallback(() => {
|
||||
if (!isCurrentUserPremium) {
|
||||
handleOpenTelegramPremiumModal();
|
||||
return;
|
||||
}
|
||||
updateGlobalPrivacySettings({
|
||||
disallowedGifts: {
|
||||
...disallowedGifts,
|
||||
shouldDisallowUniqueStarGifts: !disallowedGifts?.shouldDisallowUniqueStarGifts || undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handlePremiumSubscriptionChange = useLastCallback(() => {
|
||||
if (!isCurrentUserPremium) {
|
||||
handleOpenTelegramPremiumModal();
|
||||
return;
|
||||
}
|
||||
updateGlobalPrivacySettings({
|
||||
disallowedGifts: {
|
||||
...disallowedGifts,
|
||||
shouldDisallowPremiumGifts: !disallowedGifts?.shouldDisallowPremiumGifts || undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
{lang('PrivacyAcceptedGiftTitle')}
|
||||
</h4>
|
||||
<ListItem onClick={handleLimitedEditionChange}>
|
||||
<span>{lang('PrivacyGiftLimitedEdition')}</span>
|
||||
<Switcher
|
||||
id="limited_edition"
|
||||
label={disallowedGifts?.shouldDisallowLimitedStarGifts ? lang('PrivacyDisableLimitedEditionStarGifts')
|
||||
: lang('PrivacyEnableLimitedEditionStarGifts')}
|
||||
disabled={!isCurrentUserPremium}
|
||||
checked={!isCurrentUserPremium ? true : !disallowedGifts?.shouldDisallowLimitedStarGifts}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem onClick={handleUnlimitedEditionChange}>
|
||||
<span>{lang('PrivacyGiftUnlimited')}</span>
|
||||
<Switcher
|
||||
id="unlimited"
|
||||
label={disallowedGifts?.shouldDisallowUnlimitedStarGifts ? lang('PrivacyDisableUnlimitedStarGifts')
|
||||
: lang('PrivacyEnableUnlimitedStarGifts')}
|
||||
disabled={!isCurrentUserPremium}
|
||||
checked={!isCurrentUserPremium ? true : !disallowedGifts?.shouldDisallowUnlimitedStarGifts}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem onClick={handleUniqueChange}>
|
||||
<span>{lang('PrivacyGiftUnique')}</span>
|
||||
<Switcher
|
||||
id="unique"
|
||||
label={disallowedGifts?.shouldDisallowUniqueStarGifts ? lang('PrivacyDisableUniqueStarGifts')
|
||||
: lang('PrivacyEnableUniqueStarGifts')}
|
||||
disabled={!isCurrentUserPremium}
|
||||
checked={!isCurrentUserPremium ? true : !disallowedGifts?.shouldDisallowUniqueStarGifts}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem onClick={handlePremiumSubscriptionChange}>
|
||||
<span>{lang('PrivacyGiftPremiumSubscription')}</span>
|
||||
<Switcher
|
||||
id="premium_subscription"
|
||||
label={disallowedGifts?.shouldDisallowPremiumGifts ? lang('PrivacyDisablePremiumGifts')
|
||||
: lang('PrivacyEnablePremiumGifts')}
|
||||
disabled={!isCurrentUserPremium}
|
||||
checked={!isCurrentUserPremium ? true : !disallowedGifts?.shouldDisallowPremiumGifts}
|
||||
/>
|
||||
</ListItem>
|
||||
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
{lang('PrivacyAcceptedGiftInfo')}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
settings: {
|
||||
byKey: {
|
||||
disallowedGifts,
|
||||
},
|
||||
},
|
||||
} = global;
|
||||
|
||||
return {
|
||||
disallowedGifts,
|
||||
isCurrentUserPremium: selectIsCurrentUserPremium(global),
|
||||
};
|
||||
},
|
||||
)(SettingsAcceptedGift));
|
||||
@ -13,10 +13,13 @@ import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
import RadioGroup from '../../ui/RadioGroup';
|
||||
import Switcher from '../../ui/Switcher';
|
||||
import PremiumStatusItem from './PremiumStatusItem';
|
||||
import PrivacyLockedOption from './PrivacyLockedOption';
|
||||
import SettingsAcceptedGift from './SettingsAcceptedGift';
|
||||
import SettingsPrivacyLastSeen from './SettingsPrivacyLastSeen';
|
||||
import SettingsPrivacyPublicProfilePhoto from './SettingsPrivacyPublicProfilePhoto';
|
||||
|
||||
@ -34,6 +37,8 @@ type StateProps = {
|
||||
primaryPrivacy?: ApiPrivacySettings;
|
||||
secondaryPrivacy?: ApiPrivacySettings;
|
||||
isPremiumRequired?: boolean;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
isCurrentUserPremium?: boolean;
|
||||
};
|
||||
|
||||
const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
||||
@ -47,12 +52,36 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
||||
isPremiumRequired,
|
||||
onScreenSelect,
|
||||
onReset,
|
||||
shouldDisplayGiftsButton,
|
||||
isCurrentUserPremium,
|
||||
}) => {
|
||||
const lang = useLang();
|
||||
|
||||
const { updateGlobalPrivacySettings, showNotification } = getActions();
|
||||
|
||||
useHistoryBack({
|
||||
isActive,
|
||||
onBack: onReset,
|
||||
});
|
||||
|
||||
const handleShowGiftIconInChats = useLastCallback(() => {
|
||||
if (!isCurrentUserPremium) {
|
||||
showNotification({
|
||||
message: lang('PrivacySubscribeToTelegramPremium'),
|
||||
action: {
|
||||
action: 'openPremiumModal',
|
||||
payload: {},
|
||||
},
|
||||
actionText: { key: 'Open' },
|
||||
icon: 'star',
|
||||
});
|
||||
return;
|
||||
}
|
||||
updateGlobalPrivacySettings({
|
||||
shouldDisplayGiftsButton: !shouldDisplayGiftsButton,
|
||||
});
|
||||
});
|
||||
|
||||
const secondaryScreen = useMemo(() => {
|
||||
switch (screen) {
|
||||
case SettingsScreens.PrivacyPhoneCall:
|
||||
@ -67,6 +96,27 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
||||
|
||||
return (
|
||||
<div className="settings-content custom-scroll">
|
||||
{screen === SettingsScreens.PrivacyGifts && (
|
||||
<div className="settings-item">
|
||||
<ListItem onClick={handleShowGiftIconInChats}>
|
||||
<span>{lang('PrivacyDisplayGiftsButton')}</span>
|
||||
<Switcher
|
||||
id="gift"
|
||||
disabled={!isCurrentUserPremium}
|
||||
label={shouldDisplayGiftsButton ? lang('HideGiftsButton') : lang('DisplayGiftsButton')}
|
||||
checked={shouldDisplayGiftsButton}
|
||||
/>
|
||||
</ListItem>
|
||||
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
{lang('PrivacyDisplayGiftIconInChats', {
|
||||
icon: <Icon name="gift" className="gift-icon" />,
|
||||
gift: lang('PrivacyDisplayGift'),
|
||||
}, {
|
||||
withNodes: true,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<PrivacySubsection
|
||||
screen={screen}
|
||||
privacy={primaryPrivacy}
|
||||
@ -83,6 +133,9 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
||||
{screen === SettingsScreens.PrivacyLastSeen && (
|
||||
<SettingsPrivacyLastSeen visibility={primaryPrivacy?.visibility} />
|
||||
)}
|
||||
{screen === SettingsScreens.PrivacyGifts && (
|
||||
<SettingsAcceptedGift />
|
||||
)}
|
||||
{secondaryScreen && (
|
||||
<PrivacySubsection
|
||||
screen={secondaryScreen}
|
||||
@ -361,7 +414,12 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const {
|
||||
currentUserId,
|
||||
settings: { privacy },
|
||||
settings: {
|
||||
privacy,
|
||||
byKey: {
|
||||
shouldDisplayGiftsButton,
|
||||
},
|
||||
},
|
||||
} = global;
|
||||
|
||||
const currentUserFullInfo = selectUserFullInfo(global, currentUserId!);
|
||||
@ -426,6 +484,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
hasCurrentUserFullInfo: Boolean(currentUserFullInfo),
|
||||
currentUserFallbackPhoto: currentUserFullInfo?.fallbackPhoto,
|
||||
isPremiumRequired: screen === SettingsScreens.PrivacyVoiceMessages && !selectIsCurrentUserPremium(global),
|
||||
shouldDisplayGiftsButton,
|
||||
isCurrentUserPremium: selectIsCurrentUserPremium(global),
|
||||
};
|
||||
},
|
||||
)(SettingsPrivacyVisibility));
|
||||
|
||||
@ -4,7 +4,9 @@ import React, {
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type { ApiBotCommand, ApiChat } from '../../api/types';
|
||||
import type {
|
||||
ApiBotCommand, ApiChat, ApiDisallowedGifts,
|
||||
} from '../../api/types';
|
||||
import type { IAnchorPosition, ThreadId } from '../../types';
|
||||
import type { IconName } from '../../types/icons';
|
||||
import { MAIN_THREAD_ID } from '../../api/types';
|
||||
@ -22,6 +24,7 @@ import {
|
||||
isUserRightBanned,
|
||||
} from '../../global/helpers';
|
||||
import { getIsChatMuted } from '../../global/helpers/notifications';
|
||||
import { getPeerFullTitle } from '../../global/helpers/peers';
|
||||
import {
|
||||
selectBot,
|
||||
selectCanGift,
|
||||
@ -44,6 +47,7 @@ import { disableScrolling } from '../../util/scrollLock';
|
||||
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import usePrevDuringAnimation from '../../hooks/usePrevDuringAnimation';
|
||||
@ -123,6 +127,7 @@ type StateProps = {
|
||||
isBot?: boolean;
|
||||
isChatWithSelf?: boolean;
|
||||
savedDialog?: ApiChat;
|
||||
disallowedGifts?: ApiDisallowedGifts;
|
||||
isAccountFrozen?: boolean;
|
||||
};
|
||||
|
||||
@ -178,6 +183,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
onAsMessagesClick,
|
||||
onClose,
|
||||
onCloseAnimationEnd,
|
||||
disallowedGifts,
|
||||
isAccountFrozen,
|
||||
}) => {
|
||||
const {
|
||||
@ -207,8 +213,12 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
setViewForumAsMessages,
|
||||
openBoostModal,
|
||||
reportMessages,
|
||||
showNotification,
|
||||
} = getActions();
|
||||
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const { isMobile } = useAppLayout();
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(true);
|
||||
const [shouldCloseFast, setShouldCloseFast] = useState(false);
|
||||
@ -222,6 +232,13 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
(!isChatInfoShown && isForum) ? true : undefined, CLOSE_MENU_ANIMATION_DURATION,
|
||||
);
|
||||
|
||||
const areAllGiftsDisallowed = useMemo(() => {
|
||||
if (!disallowedGifts) {
|
||||
return undefined;
|
||||
}
|
||||
return Object.values(disallowedGifts).every(Boolean);
|
||||
}, [disallowedGifts]);
|
||||
|
||||
const closeMuteModal = useLastCallback(() => {
|
||||
setIsMuteModalOpen(false);
|
||||
onClose();
|
||||
@ -357,6 +374,11 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
const handleGiftClick = useLastCallback(() => {
|
||||
if (areAllGiftsDisallowed && chat) {
|
||||
showNotification({ message: lang('SendDisallowError') });
|
||||
return;
|
||||
}
|
||||
openGiftModal({ forUserId: chatId });
|
||||
if (isAccountFrozen) {
|
||||
openFrozenAccountModal();
|
||||
} else {
|
||||
@ -469,8 +491,6 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
|
||||
useEffect(disableScrolling, []);
|
||||
|
||||
const lang = useOldLang();
|
||||
|
||||
const botButtons = useMemo(() => {
|
||||
const commandButtons = botCommands?.map(({ command }) => {
|
||||
const cmd = BOT_BUTTONS[command];
|
||||
@ -488,7 +508,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={handleClick}
|
||||
>
|
||||
{lang(cmd.label)}
|
||||
{oldLang(cmd.label)}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
@ -503,39 +523,39 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
if (hasPrivacyCommand && !botPrivacyPolicyUrl) {
|
||||
sendBotCommand({ command: '/privacy' });
|
||||
} else {
|
||||
openUrl({ url: botPrivacyPolicyUrl || lang('BotDefaultPrivacyPolicy') });
|
||||
openUrl({ url: botPrivacyPolicyUrl || oldLang('BotDefaultPrivacyPolicy') });
|
||||
}
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
{lang('BotPrivacyPolicy')}
|
||||
{oldLang('BotPrivacyPolicy')}
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
return [...commandButtons || [], privacyButton].filter(Boolean);
|
||||
}, [botCommands, lang, botPrivacyPolicyUrl, isBot]);
|
||||
}, [botCommands, oldLang, botPrivacyPolicyUrl, isBot]);
|
||||
|
||||
const deleteTitle = useMemo(() => {
|
||||
if (!chat) return undefined;
|
||||
|
||||
if (savedDialog) {
|
||||
return lang('Delete');
|
||||
return oldLang('Delete');
|
||||
}
|
||||
|
||||
if (isPrivate) {
|
||||
return lang('DeleteChatUser');
|
||||
return oldLang('DeleteChatUser');
|
||||
}
|
||||
|
||||
if (canDeleteChat) {
|
||||
return lang('GroupInfo.DeleteAndExit');
|
||||
return oldLang('GroupInfo.DeleteAndExit');
|
||||
}
|
||||
|
||||
if (isChannel) {
|
||||
return lang('LeaveChannel');
|
||||
return oldLang('LeaveChannel');
|
||||
}
|
||||
|
||||
return lang('Group.LeaveGroup');
|
||||
}, [canDeleteChat, chat, isChannel, isPrivate, savedDialog, lang]);
|
||||
return oldLang('Group.LeaveGroup');
|
||||
}, [canDeleteChat, chat, isChannel, isPrivate, savedDialog, oldLang]);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
@ -552,7 +572,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="search"
|
||||
onClick={handleSearch}
|
||||
>
|
||||
{lang('Search')}
|
||||
{oldLang('Search')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{withForumActions && canCreateTopic && (
|
||||
@ -561,7 +581,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="comments"
|
||||
onClick={handleCreateTopicClick}
|
||||
>
|
||||
{lang('lng_forum_create_topic')}
|
||||
{oldLang('lng_forum_create_topic')}
|
||||
</MenuItem>
|
||||
<MenuSeparator />
|
||||
</>
|
||||
@ -571,7 +591,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="info"
|
||||
onClick={handleViewGroupInfo}
|
||||
>
|
||||
{isTopic ? lang('lng_context_view_topic') : lang('lng_context_view_group')}
|
||||
{isTopic ? oldLang('lng_context_view_topic') : oldLang('lng_context_view_group')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canManage && !canEditTopic && (
|
||||
@ -579,7 +599,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="edit"
|
||||
onClick={handleEditClick}
|
||||
>
|
||||
{lang('Edit')}
|
||||
{oldLang('Edit')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canEditTopic && (
|
||||
@ -587,7 +607,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="edit"
|
||||
onClick={handleEditTopicClick}
|
||||
>
|
||||
{lang('lng_forum_topic_edit')}
|
||||
{oldLang('lng_forum_topic_edit')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isMobile && !withForumActions && isForum && !isTopic && (
|
||||
@ -595,7 +615,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="forums"
|
||||
onClick={handleViewAsTopicsClick}
|
||||
>
|
||||
{lang('Chat.ContextViewAsTopics')}
|
||||
{oldLang('Chat.ContextViewAsTopics')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{withForumActions && Boolean(pendingJoinRequests) && (
|
||||
@ -603,7 +623,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="user"
|
||||
onClick={onJoinRequestsClick}
|
||||
>
|
||||
{isChannel ? lang('SubscribeRequests') : lang('MemberRequests')}
|
||||
{isChannel ? oldLang('SubscribeRequests') : oldLang('MemberRequests')}
|
||||
<div className="right-badge">{pendingJoinRequests}</div>
|
||||
</MenuItem>
|
||||
)}
|
||||
@ -612,7 +632,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="message"
|
||||
onClick={handleOpenAsMessages}
|
||||
>
|
||||
{lang('lng_forum_view_as_messages')}
|
||||
{oldLang('lng_forum_view_as_messages')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{withExtraActions && canStartBot && (
|
||||
@ -620,7 +640,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="bots"
|
||||
onClick={handleStartBot}
|
||||
>
|
||||
{lang('BotStart')}
|
||||
{oldLang('BotStart')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{withExtraActions && canSubscribe && (
|
||||
@ -628,7 +648,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon={isChannel ? 'channel' : 'group'}
|
||||
onClick={handleSubscribe}
|
||||
>
|
||||
{lang(isChannel ? 'ProfileJoinChannel' : 'ProfileJoinGroup')}
|
||||
{oldLang(isChannel ? 'ProfileJoinChannel' : 'ProfileJoinGroup')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canShowBoostModal && !canViewBoosts && (
|
||||
@ -636,7 +656,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="boost-outline"
|
||||
onClick={handleBoostClick}
|
||||
>
|
||||
{lang(isChannel ? 'BoostingBoostChannelMenu' : 'BoostingBoostGroupMenu')}
|
||||
{oldLang(isChannel ? 'BoostingBoostChannelMenu' : 'BoostingBoostGroupMenu')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canAddContact && (
|
||||
@ -644,7 +664,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="add-user"
|
||||
onClick={handleAddContactClick}
|
||||
>
|
||||
{lang('AddContact')}
|
||||
{oldLang('AddContact')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isMobile && canCall && (
|
||||
@ -652,7 +672,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="phone"
|
||||
onClick={handleCall}
|
||||
>
|
||||
{lang('Call')}
|
||||
{oldLang('Call')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canCall && (
|
||||
@ -660,7 +680,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="video-outlined"
|
||||
onClick={handleVideoCall}
|
||||
>
|
||||
{lang('VideoCall')}
|
||||
{oldLang('VideoCall')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canMute && (isMuted ? (
|
||||
@ -668,7 +688,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="unmute"
|
||||
onClick={handleUnmuteClick}
|
||||
>
|
||||
{lang('ChatsUnmute')}
|
||||
{oldLang('ChatsUnmute')}
|
||||
</MenuItem>
|
||||
)
|
||||
: (
|
||||
@ -676,7 +696,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="mute"
|
||||
onClick={handleMuteClick}
|
||||
>
|
||||
{lang('ChatsMute')}...
|
||||
{oldLang('ChatsMute')}...
|
||||
</MenuItem>
|
||||
)
|
||||
)}
|
||||
@ -685,7 +705,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="voice-chat"
|
||||
onClick={handleEnterVoiceChatClick}
|
||||
>
|
||||
{lang(canCreateVoiceChat ? 'StartVoipChat' : 'VoipGroupJoinCall')}
|
||||
{oldLang(canCreateVoiceChat ? 'StartVoipChat' : 'VoipGroupJoinCall')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{hasLinkedChat && (
|
||||
@ -693,7 +713,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon={isChannel ? 'comments' : 'channel'}
|
||||
onClick={handleLinkedChatClick}
|
||||
>
|
||||
{lang(isChannel ? 'ViewDiscussion' : 'lng_profile_view_channel')}
|
||||
{oldLang(isChannel ? 'ViewDiscussion' : 'lng_profile_view_channel')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{!withForumActions && (
|
||||
@ -701,7 +721,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="select"
|
||||
onClick={handleSelectMessages}
|
||||
>
|
||||
{lang('ReportSelectMessages')}
|
||||
{oldLang('ReportSelectMessages')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canViewBoosts && (
|
||||
@ -709,7 +729,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="boost-outline"
|
||||
onClick={handleBoostClick}
|
||||
>
|
||||
{lang('Boosts')}
|
||||
{oldLang('Boosts')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canViewStatistics && (
|
||||
@ -717,7 +737,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="stats"
|
||||
onClick={handleStatisticsClick}
|
||||
>
|
||||
{lang('Statistics')}
|
||||
{oldLang('Statistics')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isChannel && canViewMonetization && (
|
||||
@ -725,7 +745,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="cash-circle"
|
||||
onClick={handleMonetizationClick}
|
||||
>
|
||||
{lang('lng_channel_earn_title')}
|
||||
{oldLang('lng_channel_earn_title')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canTranslate && (
|
||||
@ -733,7 +753,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="language"
|
||||
onClick={handleEnableTranslations}
|
||||
>
|
||||
{lang('lng_context_translate')}
|
||||
{oldLang('lng_context_translate')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canReportChat && (
|
||||
@ -741,7 +761,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="flag"
|
||||
onClick={handleReport}
|
||||
>
|
||||
{lang('ReportPeer.Report')}
|
||||
{oldLang('ReportPeer.Report')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{botButtons}
|
||||
@ -750,7 +770,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon="gift"
|
||||
onClick={handleGiftClick}
|
||||
>
|
||||
{lang('ProfileSendAGift')}
|
||||
{oldLang('ProfileSendAGift')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isBot && (
|
||||
@ -758,7 +778,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon={isBlocked ? 'bots' : 'hand-stop'}
|
||||
onClick={isBlocked ? handleRestartBot : handleBlock}
|
||||
>
|
||||
{isBlocked ? lang('BotRestart') : lang('Bot.Stop')}
|
||||
{isBlocked ? oldLang('BotRestart') : oldLang('Bot.Stop')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isPrivate && !isChatWithSelf && !isBot && (
|
||||
@ -766,7 +786,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
icon={isBlocked ? 'user' : 'hand-stop'}
|
||||
onClick={isBlocked ? handleUnblock : handleBlock}
|
||||
>
|
||||
{isBlocked ? lang('Unblock') : lang('BlockUser')}
|
||||
{isBlocked ? oldLang('Unblock') : oldLang('BlockUser')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{canLeave && (
|
||||
@ -861,6 +881,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isBot: Boolean(chatBot),
|
||||
isChatWithSelf,
|
||||
savedDialog,
|
||||
disallowedGifts: userFullInfo?.disallowedGifts,
|
||||
isAccountFrozen,
|
||||
};
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { ChangeEvent } from 'react';
|
||||
import React, {
|
||||
memo, useMemo, useState,
|
||||
memo, useEffect, useMemo, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
@ -10,11 +10,9 @@ import {
|
||||
type ApiMessage, type ApiPeer, type ApiStarsAmount, MAIN_THREAD_ID,
|
||||
} from '../../../api/types';
|
||||
|
||||
import {
|
||||
} from '../../../global/helpers';
|
||||
import { getPeerTitle, isApiPeerUser } from '../../../global/helpers/peers';
|
||||
import {
|
||||
selectPeer, selectPeerPaidMessagesStars, selectTabState, selectTheme, selectThemeValues,
|
||||
selectPeer, selectPeerPaidMessagesStars, selectTabState, selectTheme, selectThemeValues, selectUserFullInfo,
|
||||
} from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import buildStyle from '../../../util/buildStyle';
|
||||
@ -53,6 +51,8 @@ export type StateProps = {
|
||||
isPaymentFormLoading?: boolean;
|
||||
starBalance?: ApiStarsAmount;
|
||||
paidMessagesStars?: number;
|
||||
areUniqueStarGiftsDisallowed?: boolean;
|
||||
shouldDisallowLimitedStarGifts?: boolean;
|
||||
};
|
||||
|
||||
const LIMIT_DISPLAY_THRESHOLD = 50;
|
||||
@ -72,6 +72,8 @@ function GiftComposer({
|
||||
isPaymentFormLoading,
|
||||
starBalance,
|
||||
paidMessagesStars,
|
||||
areUniqueStarGiftsDisallowed,
|
||||
shouldDisallowLimitedStarGifts,
|
||||
}: OwnProps & StateProps) {
|
||||
const {
|
||||
sendStarGift, sendPremiumGiftByStars, openInvoice, openGiftUpgradeModal, openStarsBalanceModal,
|
||||
@ -86,6 +88,12 @@ function GiftComposer({
|
||||
|
||||
const customBackgroundValue = useCustomBackground(theme, customBackground);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldDisallowLimitedStarGifts) {
|
||||
setShouldPayForUpgrade(true);
|
||||
}
|
||||
}, [shouldDisallowLimitedStarGifts, shouldPayForUpgrade]);
|
||||
|
||||
const isStarGift = 'id' in gift;
|
||||
const hasPremiumByStars = giftByStars && 'amount' in giftByStars;
|
||||
const isPeerUser = peer && isApiPeerUser(peer);
|
||||
@ -248,8 +256,14 @@ function GiftComposer({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isStarGift && gift.upgradeStars && (
|
||||
<ListItem className={styles.switcher} narrow ripple onClick={handleShouldPayForUpgradeChange}>
|
||||
{isStarGift && gift.upgradeStars && !areUniqueStarGiftsDisallowed && (
|
||||
<ListItem
|
||||
className={styles.switcher}
|
||||
narrow
|
||||
ripple
|
||||
onClick={handleShouldPayForUpgradeChange}
|
||||
disabled={shouldDisallowLimitedStarGifts}
|
||||
>
|
||||
<span>
|
||||
{lang('GiftMakeUnique', {
|
||||
stars: formatStarsAsIcon(lang, gift.upgradeStars, { className: styles.switcherStarIcon }),
|
||||
@ -262,7 +276,7 @@ function GiftComposer({
|
||||
/>
|
||||
</ListItem>
|
||||
)}
|
||||
{isStarGift && gift.upgradeStars && (
|
||||
{isStarGift && gift.upgradeStars && !areUniqueStarGiftsDisallowed && (
|
||||
<div className={styles.description}>
|
||||
{isPeerUser
|
||||
? lang('GiftMakeUniqueDescription', {
|
||||
@ -388,6 +402,13 @@ export default memo(withGlobal<OwnProps>(
|
||||
} = selectThemeValues(global, theme) || {};
|
||||
const peer = selectPeer(global, peerId);
|
||||
const paidMessagesStars = selectPeerPaidMessagesStars(global, peerId);
|
||||
const userFullInfo = selectUserFullInfo(global, peerId);
|
||||
const currentUserId = global.currentUserId;
|
||||
const isGiftForSelf = currentUserId === peerId;
|
||||
const areUniqueStarGiftsDisallowed = !isGiftForSelf
|
||||
&& userFullInfo?.disallowedGifts?.shouldDisallowUniqueStarGifts;
|
||||
const shouldDisallowLimitedStarGifts = !isGiftForSelf
|
||||
&& userFullInfo?.disallowedGifts?.shouldDisallowLimitedStarGifts;
|
||||
|
||||
const tabState = selectTabState(global);
|
||||
|
||||
@ -403,6 +424,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
currentUserId: global.currentUserId,
|
||||
isPaymentFormLoading: tabState.isPaymentFormLoading,
|
||||
paidMessagesStars,
|
||||
areUniqueStarGiftsDisallowed,
|
||||
shouldDisallowLimitedStarGifts,
|
||||
};
|
||||
},
|
||||
)(GiftComposer));
|
||||
|
||||
@ -5,6 +5,7 @@ import React, {
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiDisallowedGifts,
|
||||
ApiPeer,
|
||||
ApiPremiumGiftCodeOption,
|
||||
ApiStarGiftRegular,
|
||||
@ -16,7 +17,7 @@ import type { StarGiftCategory } from '../../../types';
|
||||
import { STARS_CURRENCY_CODE } from '../../../config';
|
||||
import { getUserFullName } from '../../../global/helpers';
|
||||
import { getPeerTitle, isApiPeerChat, isApiPeerUser } from '../../../global/helpers/peers';
|
||||
import { selectPeer } from '../../../global/selectors';
|
||||
import { selectPeer, selectUserFullInfo } from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { throttle } from '../../../util/schedulers';
|
||||
|
||||
@ -54,6 +55,7 @@ type StateProps = {
|
||||
starBalance?: ApiStarsAmount;
|
||||
peer?: ApiPeer;
|
||||
isSelf?: boolean;
|
||||
disallowedGifts?: ApiDisallowedGifts;
|
||||
};
|
||||
|
||||
const AVATAR_SIZE = 100;
|
||||
@ -69,6 +71,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
||||
starBalance,
|
||||
peer,
|
||||
isSelf,
|
||||
disallowedGifts,
|
||||
}) => {
|
||||
const {
|
||||
closeGiftModal,
|
||||
@ -96,6 +99,20 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const [selectedCategory, setSelectedCategory] = useState<StarGiftCategory>('all');
|
||||
|
||||
const areAllGiftsDisallowed = useMemo(() => {
|
||||
if (!disallowedGifts) {
|
||||
return undefined;
|
||||
}
|
||||
const {
|
||||
shouldDisallowPremiumGifts,
|
||||
...disallowedGiftTypes
|
||||
} = disallowedGifts;
|
||||
return !isSelf && Object.values(disallowedGiftTypes).every(Boolean);
|
||||
}, [isSelf, disallowedGifts]);
|
||||
|
||||
const areUnlimitedStarGiftsDisallowed = !isSelf && disallowedGifts?.shouldDisallowUnlimitedStarGifts;
|
||||
const areLimitedStarGiftsDisallowed = !isSelf && disallowedGifts?.shouldDisallowLimitedStarGifts;
|
||||
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
const allGifts = renderingModal?.gifts;
|
||||
@ -221,12 +238,31 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
function renderStarGifts() {
|
||||
const filteredGiftIds = starGiftIdsByCategory?.[selectedCategory]?.filter((giftId) => {
|
||||
const gift = starGiftsById?.[giftId];
|
||||
if (!gift) return false;
|
||||
|
||||
const { isLimited, isSoldOut, upgradeStars } = gift;
|
||||
if (areUnlimitedStarGiftsDisallowed && !areLimitedStarGiftsDisallowed) {
|
||||
return isLimited;
|
||||
}
|
||||
if (areLimitedStarGiftsDisallowed && !areUnlimitedStarGiftsDisallowed) {
|
||||
return !isLimited && !isSoldOut;
|
||||
}
|
||||
if (areUnlimitedStarGiftsDisallowed && areLimitedStarGiftsDisallowed) {
|
||||
return Boolean(isLimited && !!upgradeStars);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.starGiftsContainer}>
|
||||
{starGiftsById && starGiftIdsByCategory?.[selectedCategory].map((giftId) => {
|
||||
{starGiftsById && filteredGiftIds?.map((giftId) => {
|
||||
const gift = starGiftsById[giftId];
|
||||
return (
|
||||
<GiftItemStar
|
||||
key={giftId}
|
||||
gift={gift}
|
||||
observeIntersection={observeIntersection}
|
||||
onClick={handleGiftClick}
|
||||
@ -276,20 +312,31 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
||||
/>
|
||||
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
|
||||
</div>
|
||||
{!isSelf && !chat && renderGiftPremiumHeader()}
|
||||
{!isSelf && !chat && renderGiftPremiumDescription()}
|
||||
{!isSelf && !chat && renderPremiumGifts()}
|
||||
{!isSelf && !chat && !disallowedGifts?.shouldDisallowPremiumGifts && (
|
||||
<>
|
||||
{renderGiftPremiumHeader()}
|
||||
{renderGiftPremiumDescription()}
|
||||
{renderPremiumGifts()}
|
||||
</>
|
||||
)}
|
||||
|
||||
{renderStarGiftsHeader()}
|
||||
{renderStarGiftsDescription()}
|
||||
<StarGiftCategoryList onCategoryChanged={onCategoryChanged} />
|
||||
<Transition
|
||||
name="zoomFade"
|
||||
activeKey={getCategoryKey(selectedCategory)}
|
||||
className={styles.starGiftsTransition}
|
||||
>
|
||||
{renderStarGifts()}
|
||||
</Transition>
|
||||
{!areAllGiftsDisallowed && (
|
||||
<>
|
||||
{renderStarGiftsHeader()}
|
||||
{renderStarGiftsDescription()}
|
||||
<StarGiftCategoryList
|
||||
areLimitedStarGiftsDisallowed={areLimitedStarGiftsDisallowed}
|
||||
onCategoryChanged={onCategoryChanged}
|
||||
/>
|
||||
<Transition
|
||||
name="zoomFade"
|
||||
activeKey={getCategoryKey(selectedCategory)}
|
||||
className={styles.starGiftsTransition}
|
||||
>
|
||||
{renderStarGifts()}
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -361,6 +408,7 @@ export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
|
||||
|
||||
const peer = modal?.forPeerId ? selectPeer(global, modal.forPeerId) : undefined;
|
||||
const isSelf = Boolean(currentUserId && modal?.forPeerId === currentUserId);
|
||||
const userFullInfo = peer ? selectUserFullInfo(global, peer?.id) : undefined;
|
||||
|
||||
return {
|
||||
boostPerSentGift: global.appConfig?.boostsPerSentGift,
|
||||
@ -369,6 +417,7 @@ export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
|
||||
starBalance: stars?.balance,
|
||||
peer,
|
||||
isSelf,
|
||||
disallowedGifts: userFullInfo?.disallowedGifts,
|
||||
};
|
||||
})(GiftModal));
|
||||
|
||||
|
||||
@ -20,11 +20,13 @@ type OwnProps = {
|
||||
|
||||
type StateProps = {
|
||||
idsByCategory?: Record<StarGiftCategory, string[]>;
|
||||
areLimitedStarGiftsDisallowed?: boolean;
|
||||
};
|
||||
|
||||
const StarGiftCategoryList = ({
|
||||
idsByCategory,
|
||||
onCategoryChanged,
|
||||
areLimitedStarGiftsDisallowed,
|
||||
}: StateProps & OwnProps) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
@ -78,7 +80,7 @@ const StarGiftCategoryList = ({
|
||||
return (
|
||||
<div ref={ref} className={buildClassName(styles.list, 'no-scrollbar')}>
|
||||
{renderCategoryItem('all')}
|
||||
{renderCategoryItem('limited')}
|
||||
{!areLimitedStarGiftsDisallowed && renderCategoryItem('limited')}
|
||||
{renderCategoryItem('stock')}
|
||||
{starCategories?.map(renderCategoryItem)}
|
||||
</div>
|
||||
|
||||
@ -1099,6 +1099,7 @@ async function payInputStarInvoice<T extends GlobalState>(
|
||||
setGlobal(global);
|
||||
|
||||
if ('error' in form) {
|
||||
actions.showDialog({ data: { message: form.error || 'Error', hasErrorKey: true }, tabId });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -725,6 +725,10 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const nonContactPeersPaidStars = payload.nonContactPeersPaidStars === null ? undefined
|
||||
: payload.nonContactPeersPaidStars || global.settings.byKey.nonContactPeersPaidStars;
|
||||
const shouldDisplayGiftsButton = payload.shouldDisplayGiftsButton
|
||||
?? Boolean(global.settings.byKey.shouldDisplayGiftsButton);
|
||||
const disallowedGifts = payload.disallowedGifts
|
||||
?? global.settings.byKey.disallowedGifts;
|
||||
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const shouldUpdateUsersSettings = (payload.nonContactPeersPaidStars === null)
|
||||
@ -736,6 +740,8 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
||||
shouldHideReadMarks,
|
||||
shouldNewNonContactPeersRequirePremium,
|
||||
nonContactPeersPaidStars,
|
||||
shouldDisplayGiftsButton,
|
||||
disallowedGifts,
|
||||
});
|
||||
setGlobal(global);
|
||||
|
||||
@ -744,6 +750,8 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
||||
shouldHideReadMarks,
|
||||
shouldNewNonContactPeersRequirePremium,
|
||||
nonContactPeersPaidStars,
|
||||
shouldDisplayGiftsButton,
|
||||
disallowedGifts,
|
||||
});
|
||||
|
||||
global = getGlobal();
|
||||
@ -758,6 +766,8 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
||||
nonContactPeersPaidStars: !result
|
||||
? undefined
|
||||
: result.nonContactPeersPaidStars,
|
||||
shouldDisplayGiftsButton: !result ? !shouldDisplayGiftsButton : result.shouldDisplayGiftsButton,
|
||||
disallowedGifts: !result ? disallowedGifts : result.disallowedGifts,
|
||||
});
|
||||
|
||||
if (shouldUpdateUsersSettings) {
|
||||
|
||||
@ -299,6 +299,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
shouldUpdateStickerSetOrder: true,
|
||||
shouldArchiveAndMuteNewNonContact: false,
|
||||
shouldNewNonContactPeersRequirePremium: false,
|
||||
disallowedGifts: undefined,
|
||||
nonContactPeersPaidStars: 0,
|
||||
shouldHideReadMarks: false,
|
||||
canTranslate: false,
|
||||
|
||||
@ -8,6 +8,7 @@ import type {
|
||||
ApiChatlistInvite,
|
||||
ApiChatReactions,
|
||||
ApiChatType,
|
||||
ApiDisallowedGiftsSettings,
|
||||
ApiDraft,
|
||||
ApiExportedInvite,
|
||||
ApiFormattedText,
|
||||
@ -2329,6 +2330,8 @@ export interface ActionPayloads {
|
||||
shouldHideReadMarks?: boolean;
|
||||
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||
nonContactPeersPaidStars?: number | null;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
disallowedGifts?: ApiDisallowedGiftsSettings;
|
||||
};
|
||||
|
||||
// Premium
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
ApiChat,
|
||||
ApiChatInviteImporter,
|
||||
ApiContact,
|
||||
ApiDisallowedGiftsSettings,
|
||||
ApiDocument,
|
||||
ApiDraft,
|
||||
ApiExportedInvite,
|
||||
@ -147,6 +148,8 @@ export interface AccountSettings {
|
||||
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||
nonContactPeersPaidStars?: number;
|
||||
shouldDisplayGiftsButton?: boolean;
|
||||
disallowedGifts?: ApiDisallowedGiftsSettings;
|
||||
shouldHideReadMarks?: boolean;
|
||||
canTranslate: boolean;
|
||||
canTranslateChats: boolean;
|
||||
|
||||
24
src/types/language.d.ts
vendored
24
src/types/language.d.ts
vendored
@ -1282,7 +1282,16 @@ export interface LangPair {
|
||||
'PrivacyGifts': undefined;
|
||||
'PrivacyGiftsTitle': undefined;
|
||||
'PrivacyGiftsInfo': undefined;
|
||||
'PrivacyAcceptedGiftTitle': undefined;
|
||||
'PrivacyAcceptedGiftInfo': undefined;
|
||||
'PrivacyDisplayGiftsButton': undefined;
|
||||
'PrivacyDisplayGift': undefined;
|
||||
'SendDisallowError': undefined;
|
||||
'PrivacyValueBots': undefined;
|
||||
'PrivacyGiftLimitedEdition': undefined;
|
||||
'PrivacyGiftUnlimited': undefined;
|
||||
'PrivacyGiftUnique': undefined;
|
||||
'PrivacyGiftPremiumSubscription': undefined;
|
||||
'CustomShareGiftsInfo': undefined;
|
||||
'AllChatsSearchContext': undefined;
|
||||
'PrivateChatsSearchContext': undefined;
|
||||
@ -1466,6 +1475,17 @@ export interface LangPair {
|
||||
'DescriptionRestrictedMedia': undefined;
|
||||
'DescriptionScheduledPaidMediaNotAllowed': undefined;
|
||||
'DescriptionScheduledPaidMessagesNotAllowed': undefined;
|
||||
'PrivacySubscribeToTelegramPremium': undefined;
|
||||
'PrivacyDisableLimitedEditionStarGifts': undefined;
|
||||
'PrivacyEnableLimitedEditionStarGifts': undefined;
|
||||
'PrivacyDisableUnlimitedStarGifts': undefined;
|
||||
'PrivacyEnableUnlimitedStarGifts': undefined;
|
||||
'PrivacyDisableUniqueStarGifts': undefined;
|
||||
'PrivacyEnableUniqueStarGifts': undefined;
|
||||
'PrivacyDisablePremiumGifts': undefined;
|
||||
'PrivacyEnablePremiumGifts': undefined;
|
||||
'DisplayGiftsButton': undefined;
|
||||
'HideGiftsButton': undefined;
|
||||
'FrozenAccountModalTitle': undefined;
|
||||
'FrozenAccountViolationTitle': undefined;
|
||||
'FrozenAccountViolationSubtitle': undefined;
|
||||
@ -1555,6 +1575,10 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
'SpeakingWithVolume': {
|
||||
'volume': V;
|
||||
};
|
||||
'PrivacyDisplayGiftIconInChats':{
|
||||
'icon': V;
|
||||
'gift': V;
|
||||
};
|
||||
'CallEmojiKeyTooltip': {
|
||||
'user': V;
|
||||
};
|
||||
|
||||
@ -81,6 +81,8 @@ const READABLE_ERROR_MESSAGES: Record<string, string> = {
|
||||
PEERS_LIST_EMPTY: 'No chats are added to the list',
|
||||
|
||||
PAID_MEDIA_FORBIDDEN: 'You can\'t send paid media in this chat',
|
||||
|
||||
USER_DISALLOWED_STARGIFTS: 'User is not accepting gifts',
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user