TelegramPWA/src/components/left/settings/SettingsPrivacy.tsx

507 lines
16 KiB
TypeScript

import type { FC } from '../../../lib/teact/teact';
import { memo, useCallback, useEffect, useMemo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { ApiPrivacySettings } from '../../../api/types';
import type { GlobalState } from '../../../global/types';
import { SettingsScreens } from '../../../types';
import { ACCOUNT_TTL_OPTIONS } from '../../../config';
import {
selectCanSetPasscode, selectIsCurrentUserFrozen,
selectIsCurrentUserPremium,
} from '../../../global/selectors';
import { selectSharedSettings } from '../../../global/selectors/sharedState';
import { getClosestEntry } from '../../../util/getClosestEntry';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import StarIcon from '../../common/icons/StarIcon';
import Button from '../../ui/Button';
import Checkbox from '../../ui/Checkbox';
import ListItem from '../../ui/ListItem';
type OwnProps = {
isActive?: boolean;
onReset: () => void;
};
type StateProps = {
isCurrentUserPremium?: boolean;
hasPassword?: boolean;
hasPasscode?: boolean;
canSetPasscode?: boolean;
blockedCount: number;
webAuthCount: number;
isSensitiveEnabled?: boolean;
canChangeSensitive?: boolean;
canDisplayAutoarchiveSetting: boolean;
shouldArchiveAndMuteNewNonContact?: boolean;
shouldNewNonContactPeersRequirePremium?: boolean;
shouldChargeForMessages: boolean;
canDisplayChatInTitle?: boolean;
isCurrentUserFrozen?: boolean;
needAgeVideoVerification?: boolean;
privacy: GlobalState['settings']['privacy'];
accountDaysTtl?: number;
};
const DAYS_PER_MONTH = 30;
const SettingsPrivacy: FC<OwnProps & StateProps> = ({
isActive,
isCurrentUserPremium,
hasPassword,
hasPasscode,
blockedCount,
webAuthCount,
isSensitiveEnabled,
canChangeSensitive,
canDisplayAutoarchiveSetting,
shouldArchiveAndMuteNewNonContact,
shouldNewNonContactPeersRequirePremium,
shouldChargeForMessages,
canDisplayChatInTitle,
canSetPasscode,
needAgeVideoVerification,
privacy,
onReset,
isCurrentUserFrozen,
accountDaysTtl,
}) => {
const {
openDeleteAccountModal,
loadPrivacySettings,
loadBlockedUsers,
updateContentSettings,
loadGlobalPrivacySettings,
updateGlobalPrivacySettings,
loadWebAuthorizations,
setSharedSettingOption,
openSettingsScreen,
loadAccountDaysTtl,
openAgeVerificationModal,
} = getActions();
useEffect(() => {
if (!isCurrentUserFrozen) {
loadBlockedUsers();
loadPrivacySettings();
loadWebAuthorizations();
}
}, [isCurrentUserFrozen]);
useEffect(() => {
if (isActive && !isCurrentUserFrozen) {
loadGlobalPrivacySettings();
loadAccountDaysTtl();
}
}, [isActive, isCurrentUserFrozen, loadGlobalPrivacySettings]);
const oldLang = useOldLang();
const lang = useLang();
useHistoryBack({
isActive,
onBack: onReset,
});
const handleArchiveAndMuteChange = useCallback((isEnabled: boolean) => {
updateGlobalPrivacySettings({
shouldArchiveAndMuteNewNonContact: isEnabled,
});
}, [updateGlobalPrivacySettings]);
const handleChatInTitleChange = useCallback((isChecked: boolean) => {
setSharedSettingOption({
canDisplayChatInTitle: isChecked,
});
}, []);
const handleUpdateContentSettings = useCallback((isChecked: boolean) => {
updateContentSettings({ isSensitiveEnabled: isChecked });
}, [updateContentSettings]);
const handleAgeVerification = useCallback(() => {
openAgeVerificationModal();
}, [openAgeVerificationModal]);
const handleOpenDeleteAccountModal = useLastCallback(() => {
if (!accountDaysTtl) return;
openDeleteAccountModal({ days: accountDaysTtl });
});
const dayOption = useMemo(() => {
if (!accountDaysTtl) return undefined;
return getClosestEntry(ACCOUNT_TTL_OPTIONS, accountDaysTtl / DAYS_PER_MONTH).toString();
}, [accountDaysTtl]);
function getVisibilityValue(setting?: ApiPrivacySettings) {
if (!setting) return oldLang('Loading');
const { visibility, shouldAllowPremium, botsPrivacy } = setting;
const isAllowBots = botsPrivacy === 'allow';
const isVisibilityEverybody = visibility === 'everybody';
const shouldShowBotsString = isAllowBots && !isVisibilityEverybody;
const blockCount = setting.blockChatIds.length + setting.blockUserIds.length;
const allowCount = setting.allowChatIds.length + setting.allowUserIds.length;
const total = [];
if (blockCount) total.push(`-${blockCount}`);
if (allowCount && !isVisibilityEverybody) total.push(`+${allowCount}`);
const botPrivacyString = shouldShowBotsString ? lang('PrivacyValueBots') : '';
const totalString = lang.conjunction(total);
const exceptionString = [botPrivacyString, totalString].filter(Boolean).join(' ');
if (shouldShowBotsString && !isVisibilityEverybody) return exceptionString;
if (shouldAllowPremium) {
return oldLang(exceptionString ? 'ContactsAndPremium' : 'PrivacyPremium');
}
switch (visibility) {
case 'everybody':
return `${oldLang('P2PEverybody')} ${exceptionString}`;
case 'contacts':
return `${oldLang('P2PContacts')} ${exceptionString}`;
case 'nobody':
return `${oldLang('P2PNobody')} ${exceptionString}`;
}
return undefined;
}
return (
<div className="settings-content custom-scroll">
<div className="settings-item">
<ListItem
icon="delete-user"
narrow
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyBlockedUsers })}
>
{oldLang('BlockedUsers')}
<span className="settings-item__current-value">{blockedCount || ''}</span>
</ListItem>
{canSetPasscode && (
<ListItem
icon="key"
narrow
onClick={() => openSettingsScreen({
screen: hasPasscode ? SettingsScreens.PasscodeEnabled : SettingsScreens.PasscodeDisabled,
})}
>
<div className="multiline-item">
<span className="title">{oldLang('Passcode')}</span>
<span className="subtitle" dir="auto">
{oldLang(hasPasscode ? 'PasswordOn' : 'PasswordOff')}
</span>
</div>
</ListItem>
)}
<ListItem
icon="lock"
narrow
onClick={() => openSettingsScreen({
screen: hasPassword ? SettingsScreens.TwoFaEnabled : SettingsScreens.TwoFaDisabled,
})}
>
<div className="multiline-item">
<span className="title">{oldLang('TwoStepVerification')}</span>
<span className="subtitle" dir="auto">
{oldLang(hasPassword ? 'PasswordOn' : 'PasswordOff')}
</span>
</div>
</ListItem>
{webAuthCount > 0 && (
<ListItem
icon="web"
narrow
onClick={() => openSettingsScreen({ screen: SettingsScreens.ActiveWebsites })}
>
{oldLang('PrivacySettings.WebSessions')}
<span className="settings-item__current-value">{webAuthCount}</span>
</ListItem>
)}
</div>
<div className="settings-item">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{oldLang('PrivacyTitle')}</h4>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyPhoneNumber })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyPhoneTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.phoneNumber)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyLastSeen })}
>
<div className="multiline-item">
<span className="title">{oldLang('LastSeenTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.lastSeen)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyProfilePhoto })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyProfilePhotoTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.profilePhoto)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyBio })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyBio')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.bio)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyBirthday })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyBirthday')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.birthday)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyGifts })}
>
<div className="multiline-item">
<span className="title">{lang('PrivacyGifts')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.gifts)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyForwarding })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyForwardsTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.forwards)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyPhoneCall })}
>
<div className="multiline-item">
<span className="title">{oldLang('WhoCanCallMe')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.phoneCall)}
</span>
</div>
</ListItem>
<ListItem
narrow
allowDisabledClick
rightElement={isCurrentUserPremium && <StarIcon size="big" type="premium" />}
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyVoiceMessages })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyVoiceMessagesTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.voiceMessages)}
</span>
</div>
</ListItem>
<ListItem
narrow
rightElement={isCurrentUserPremium && <StarIcon size="big" type="premium" />}
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyMessages })}
>
<div className="multiline-item">
<span className="title">{oldLang('PrivacyMessagesTitle')}</span>
<span className="subtitle" dir="auto">
{shouldChargeForMessages ? lang('PrivacyPaidMessagesValue')
: shouldNewNonContactPeersRequirePremium
? oldLang('PrivacyMessagesContactsAndPremium')
: oldLang('P2PEverybody')}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
onClick={() => openSettingsScreen({ screen: SettingsScreens.PrivacyGroupChats })}
>
<div className="multiline-item">
<span className="title">{oldLang('WhoCanAddMe')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacy.chatInvite)}
</span>
</div>
</ListItem>
</div>
{canChangeSensitive && (
<div className="settings-item fluid-container">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{oldLang('lng_settings_sensitive_title')}
</h4>
<Checkbox
label={oldLang('lng_settings_sensitive_disable_filtering')}
subLabel={oldLang('lng_settings_sensitive_about')}
checked={Boolean(isSensitiveEnabled)}
disabled={!canChangeSensitive || (!isSensitiveEnabled && needAgeVideoVerification)}
onCheck={handleUpdateContentSettings}
/>
{!isSensitiveEnabled && needAgeVideoVerification && (
<Button
color="primary"
fluid
noForcedUpperCase
className="settings-unlock-button"
onClick={handleAgeVerification}
>
<span className="settings-unlock-button-title">
{lang('ButtonAgeVerification')}
</span>
</Button>
)}
</div>
)}
{canDisplayAutoarchiveSetting && (
<div className="settings-item">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{oldLang('NewChatsFromNonContacts')}
</h4>
<Checkbox
label={oldLang('ArchiveAndMute')}
subLabel={oldLang('ArchiveAndMuteInfo')}
checked={Boolean(shouldArchiveAndMuteNewNonContact)}
onCheck={handleArchiveAndMuteChange}
/>
</div>
)}
<div className="settings-item">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{oldLang('lng_settings_window_system')}
</h4>
<Checkbox
label={oldLang('lng_settings_title_chat_name')}
checked={Boolean(canDisplayChatInTitle)}
onCheck={handleChatInTitleChange}
/>
</div>
<div className="settings-item">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
{lang('DeleteMyAccount')}
</h4>
<ListItem
narrow
onClick={handleOpenDeleteAccountModal}
>
{lang('DeleteAccountIfAwayFor')}
<span className="settings-item__current-value">
{lang('Months', { count: dayOption }, { pluralValue: 1 })}
</span>
</ListItem>
</div>
</div>
);
};
export default memo(withGlobal<OwnProps>(
(global): Complete<StateProps> => {
const {
settings: {
byKey: {
hasPassword, isSensitiveEnabled, canChangeSensitive, shouldArchiveAndMuteNewNonContact,
shouldNewNonContactPeersRequirePremium, nonContactPeersPaidStars,
},
privacy,
accountDaysTtl,
},
blocked,
passcode: {
hasPasscode,
},
appConfig,
} = global;
const { canDisplayChatInTitle } = selectSharedSettings(global);
const shouldChargeForMessages = Boolean(nonContactPeersPaidStars);
const isCurrentUserFrozen = selectIsCurrentUserFrozen(global);
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
return {
isCurrentUserPremium,
hasPassword,
hasPasscode: Boolean(hasPasscode),
blockedCount: blocked.totalCount,
webAuthCount: global.activeWebSessions.orderedHashes.length,
isSensitiveEnabled,
canDisplayAutoarchiveSetting: appConfig.canDisplayAutoarchiveSetting || isCurrentUserPremium,
shouldArchiveAndMuteNewNonContact,
canChangeSensitive,
shouldNewNonContactPeersRequirePremium,
shouldChargeForMessages,
needAgeVideoVerification: Boolean(appConfig.needAgeVideoVerification),
privacy,
canDisplayChatInTitle,
canSetPasscode: selectCanSetPasscode(global),
isCurrentUserFrozen,
accountDaysTtl,
};
},
)(SettingsPrivacy));