Settings: Private message permissions (#4245)
This commit is contained in:
parent
3d4ba7c47b
commit
7569689fb2
@ -615,17 +615,24 @@ export async function fetchGlobalPrivacySettings() {
|
|||||||
return {
|
return {
|
||||||
shouldArchiveAndMuteNewNonContact: Boolean(result.archiveAndMuteNewNoncontactPeers),
|
shouldArchiveAndMuteNewNonContact: Boolean(result.archiveAndMuteNewNoncontactPeers),
|
||||||
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
||||||
|
shouldNewNonContactPeersRequirePremium: Boolean(result.newNoncontactPeersRequirePremium),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateGlobalPrivacySettings({ shouldArchiveAndMuteNewNonContact, shouldHideReadMarks }: {
|
export async function updateGlobalPrivacySettings({
|
||||||
shouldArchiveAndMuteNewNonContact: boolean;
|
shouldArchiveAndMuteNewNonContact,
|
||||||
shouldHideReadMarks: boolean;
|
shouldHideReadMarks,
|
||||||
|
shouldNewNonContactPeersRequirePremium,
|
||||||
|
}: {
|
||||||
|
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||||
|
shouldHideReadMarks?: boolean;
|
||||||
|
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const result = await invokeRequest(new GramJs.account.SetGlobalPrivacySettings({
|
const result = await invokeRequest(new GramJs.account.SetGlobalPrivacySettings({
|
||||||
settings: new GramJs.GlobalPrivacySettings({
|
settings: new GramJs.GlobalPrivacySettings({
|
||||||
...(shouldArchiveAndMuteNewNonContact && { archiveAndMuteNewNoncontactPeers: true }),
|
...(shouldArchiveAndMuteNewNonContact && { archiveAndMuteNewNoncontactPeers: true }),
|
||||||
...(shouldHideReadMarks && { hideReadMarks: true }),
|
...(shouldHideReadMarks && { hideReadMarks: true }),
|
||||||
|
...(shouldNewNonContactPeersRequirePremium && { newNoncontactPeersRequirePremium: true }),
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -636,6 +643,7 @@ export async function updateGlobalPrivacySettings({ shouldArchiveAndMuteNewNonCo
|
|||||||
return {
|
return {
|
||||||
shouldArchiveAndMuteNewNonContact: Boolean(result.archiveAndMuteNewNoncontactPeers),
|
shouldArchiveAndMuteNewNonContact: Boolean(result.archiveAndMuteNewNoncontactPeers),
|
||||||
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
shouldHideReadMarks: Boolean(result.hideReadMarks),
|
||||||
|
shouldNewNonContactPeersRequirePremium: Boolean(result.newNoncontactPeersRequirePremium),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -194,6 +194,7 @@ function LeftColumn({
|
|||||||
case SettingsScreens.PrivacyForwarding:
|
case SettingsScreens.PrivacyForwarding:
|
||||||
case SettingsScreens.PrivacyGroupChats:
|
case SettingsScreens.PrivacyGroupChats:
|
||||||
case SettingsScreens.PrivacyVoiceMessages:
|
case SettingsScreens.PrivacyVoiceMessages:
|
||||||
|
case SettingsScreens.PrivacyMessages:
|
||||||
case SettingsScreens.PrivacyBlockedUsers:
|
case SettingsScreens.PrivacyBlockedUsers:
|
||||||
case SettingsScreens.ActiveWebsites:
|
case SettingsScreens.ActiveWebsites:
|
||||||
case SettingsScreens.TwoFaDisabled:
|
case SettingsScreens.TwoFaDisabled:
|
||||||
|
|||||||
33
src/components/left/settings/PremiumStatusItem.tsx
Normal file
33
src/components/left/settings/PremiumStatusItem.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import PremiumIcon from '../../common/PremiumIcon';
|
||||||
|
import ListItem from '../../ui/ListItem';
|
||||||
|
|
||||||
|
function PremiumStatusItem() {
|
||||||
|
const { openPremiumModal } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
const handleOpenPremiumModal = useLastCallback(() => openPremiumModal());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="settings-item">
|
||||||
|
<ListItem
|
||||||
|
leftElement={<PremiumIcon className="icon" withGradient big />}
|
||||||
|
onClick={handleOpenPremiumModal}
|
||||||
|
>
|
||||||
|
{lang('PrivacyLastSeenPremium')}
|
||||||
|
</ListItem>
|
||||||
|
<p
|
||||||
|
className="settings-item-description-larger premium-info"
|
||||||
|
dir={lang.isRtl ? 'rtl' : undefined}
|
||||||
|
>
|
||||||
|
{lang('lng_messages_privacy_premium_about')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(PremiumStatusItem);
|
||||||
12
src/components/left/settings/PrivacyLockedOption.module.scss
Normal file
12
src/components/left/settings/PrivacyLockedOption.module.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.contacts_and_premium_option-title {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lock-icon {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
position: absolute;
|
||||||
|
left: 1.0625rem;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: var(--color-gray);
|
||||||
|
}
|
||||||
29
src/components/left/settings/PrivacyLockedOption.tsx
Normal file
29
src/components/left/settings/PrivacyLockedOption.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
|
import Icon from '../../common/Icon';
|
||||||
|
|
||||||
|
import styles from './PrivacyLockedOption.module.scss';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function PrivacyLockedOption({ label }: OwnProps) {
|
||||||
|
const lang = useLang();
|
||||||
|
const { showNotification } = getActions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={styles.contactsAndPremiumOptionTitle}
|
||||||
|
onClick={() => showNotification({ message: lang('OptionPremiumRequiredMessage') })}
|
||||||
|
>
|
||||||
|
<span>{label}</span>
|
||||||
|
<Icon name="lock-badge" className={styles.lockIcon} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(PrivacyLockedOption);
|
||||||
80
src/components/left/settings/PrivacyMessages.tsx
Normal file
80
src/components/left/settings/PrivacyMessages.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
|
import { selectIsCurrentUserPremium, selectNewNoncontactPeersRequirePremium } from '../../../global/selectors';
|
||||||
|
|
||||||
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import RadioGroup from '../../ui/RadioGroup';
|
||||||
|
import PremiumStatusItem from './PremiumStatusItem';
|
||||||
|
import PrivacyLockedOption from './PrivacyLockedOption';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
isActive?: boolean;
|
||||||
|
onReset: VoidFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||||
|
isCurrentUserPremium?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function PrivacyMessages({
|
||||||
|
isActive, onReset, shouldNewNonContactPeersRequirePremium, isCurrentUserPremium,
|
||||||
|
}: OwnProps & StateProps) {
|
||||||
|
const { updateGlobalPrivacySettings } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const options = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{ value: 'everybody', label: lang('P2PEverybody') },
|
||||||
|
{
|
||||||
|
value: 'contacts_and_premium',
|
||||||
|
label: isCurrentUserPremium ? (
|
||||||
|
lang('PrivacyMessagesContactsAndPremium')
|
||||||
|
) : (
|
||||||
|
<PrivacyLockedOption label={lang('PrivacyMessagesContactsAndPremium')} />
|
||||||
|
),
|
||||||
|
hidden: !isCurrentUserPremium,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [lang, isCurrentUserPremium]);
|
||||||
|
|
||||||
|
const handleChange = useLastCallback((privacy: string) => {
|
||||||
|
updateGlobalPrivacySettings({ shouldNewNonContactPeersRequirePremium: privacy === 'contacts_and_premium' });
|
||||||
|
});
|
||||||
|
|
||||||
|
useHistoryBack({
|
||||||
|
isActive,
|
||||||
|
onBack: onReset,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="settings-item">
|
||||||
|
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
|
{lang('PrivacyMessagesTitle')}
|
||||||
|
</h4>
|
||||||
|
<RadioGroup
|
||||||
|
name="privacy-messages"
|
||||||
|
options={options}
|
||||||
|
onChange={handleChange}
|
||||||
|
selected={shouldNewNonContactPeersRequirePremium ? 'contacts_and_premium' : 'everybody'}
|
||||||
|
/>
|
||||||
|
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
|
{lang('Privacy.Messages.SectionFooter')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{!isCurrentUserPremium && <PremiumStatusItem />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||||
|
return {
|
||||||
|
shouldNewNonContactPeersRequirePremium: selectNewNoncontactPeersRequirePremium(global),
|
||||||
|
isCurrentUserPremium: selectIsCurrentUserPremium(global),
|
||||||
|
};
|
||||||
|
})(PrivacyMessages));
|
||||||
@ -180,6 +180,10 @@
|
|||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
|
|
||||||
|
&.premium-info {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
&[dir="rtl"] {
|
&[dir="rtl"] {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
|||||||
import Transition from '../../ui/Transition';
|
import Transition from '../../ui/Transition';
|
||||||
import SettingsFolders from './folders/SettingsFolders';
|
import SettingsFolders from './folders/SettingsFolders';
|
||||||
import SettingsPasscode from './passcode/SettingsPasscode';
|
import SettingsPasscode from './passcode/SettingsPasscode';
|
||||||
|
import PrivacyMessages from './PrivacyMessages';
|
||||||
import SettingsActiveSessions from './SettingsActiveSessions';
|
import SettingsActiveSessions from './SettingsActiveSessions';
|
||||||
import SettingsActiveWebsites from './SettingsActiveWebsites';
|
import SettingsActiveWebsites from './SettingsActiveWebsites';
|
||||||
import SettingsCustomEmoji from './SettingsCustomEmoji';
|
import SettingsCustomEmoji from './SettingsCustomEmoji';
|
||||||
@ -372,6 +373,14 @@ const Settings: FC<OwnProps> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case SettingsScreens.PrivacyMessages:
|
||||||
|
return (
|
||||||
|
<PrivacyMessages
|
||||||
|
isActive={isScreenActive}
|
||||||
|
onReset={handleReset}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
case SettingsScreens.Folders:
|
case SettingsScreens.Folders:
|
||||||
case SettingsScreens.FoldersCreateFolder:
|
case SettingsScreens.FoldersCreateFolder:
|
||||||
case SettingsScreens.FoldersEditFolder:
|
case SettingsScreens.FoldersEditFolder:
|
||||||
|
|||||||
@ -119,6 +119,8 @@ const SettingsHeader: FC<OwnProps> = ({
|
|||||||
return <h3>{lang('PrivacyForwards')}</h3>;
|
return <h3>{lang('PrivacyForwards')}</h3>;
|
||||||
case SettingsScreens.PrivacyVoiceMessages:
|
case SettingsScreens.PrivacyVoiceMessages:
|
||||||
return <h3>{lang('PrivacyVoiceMessages')}</h3>;
|
return <h3>{lang('PrivacyVoiceMessages')}</h3>;
|
||||||
|
case SettingsScreens.PrivacyMessages:
|
||||||
|
return <h3>{lang('PrivacyMessages')}</h3>;
|
||||||
case SettingsScreens.PrivacyGroupChats:
|
case SettingsScreens.PrivacyGroupChats:
|
||||||
return <h3>{lang('AutodownloadGroupChats')}</h3>;
|
return <h3>{lang('AutodownloadGroupChats')}</h3>;
|
||||||
case SettingsScreens.PrivacyPhoneCall:
|
case SettingsScreens.PrivacyPhoneCall:
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { selectCanSetPasscode, selectIsCurrentUserPremium } from '../../../globa
|
|||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
|
import PremiumIcon from '../../common/PremiumIcon';
|
||||||
import Checkbox from '../../ui/Checkbox';
|
import Checkbox from '../../ui/Checkbox';
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ type StateProps = {
|
|||||||
canChangeSensitive?: boolean;
|
canChangeSensitive?: boolean;
|
||||||
canDisplayAutoarchiveSetting: boolean;
|
canDisplayAutoarchiveSetting: boolean;
|
||||||
shouldArchiveAndMuteNewNonContact?: boolean;
|
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||||
|
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||||
canDisplayChatInTitle?: boolean;
|
canDisplayChatInTitle?: boolean;
|
||||||
privacyPhoneNumber?: ApiPrivacySettings;
|
privacyPhoneNumber?: ApiPrivacySettings;
|
||||||
privacyLastSeen?: ApiPrivacySettings;
|
privacyLastSeen?: ApiPrivacySettings;
|
||||||
@ -52,6 +54,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
canChangeSensitive,
|
canChangeSensitive,
|
||||||
canDisplayAutoarchiveSetting,
|
canDisplayAutoarchiveSetting,
|
||||||
shouldArchiveAndMuteNewNonContact,
|
shouldArchiveAndMuteNewNonContact,
|
||||||
|
shouldNewNonContactPeersRequirePremium,
|
||||||
canDisplayChatInTitle,
|
canDisplayChatInTitle,
|
||||||
canSetPasscode,
|
canSetPasscode,
|
||||||
privacyPhoneNumber,
|
privacyPhoneNumber,
|
||||||
@ -73,7 +76,6 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
loadGlobalPrivacySettings,
|
loadGlobalPrivacySettings,
|
||||||
updateGlobalPrivacySettings,
|
updateGlobalPrivacySettings,
|
||||||
loadWebAuthorizations,
|
loadWebAuthorizations,
|
||||||
showNotification,
|
|
||||||
setSettingOption,
|
setSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
@ -103,16 +105,6 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
}, [updateGlobalPrivacySettings]);
|
}, [updateGlobalPrivacySettings]);
|
||||||
|
|
||||||
const handleVoiceMessagesClick = useCallback(() => {
|
|
||||||
if (isCurrentUserPremium) {
|
|
||||||
onScreenSelect(SettingsScreens.PrivacyVoiceMessages);
|
|
||||||
} else {
|
|
||||||
showNotification({
|
|
||||||
message: lang('PrivacyVoiceMessagesPremiumOnly'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [isCurrentUserPremium, lang, onScreenSelect, showNotification]);
|
|
||||||
|
|
||||||
const handleChatInTitleChange = useCallback((isChecked: boolean) => {
|
const handleChatInTitleChange = useCallback((isChecked: boolean) => {
|
||||||
setSettingOption({
|
setSettingOption({
|
||||||
canDisplayChatInTitle: isChecked,
|
canDisplayChatInTitle: isChecked,
|
||||||
@ -298,11 +290,11 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem
|
<ListItem
|
||||||
narrow
|
narrow
|
||||||
disabled={!isCurrentUserPremium}
|
|
||||||
allowDisabledClick
|
allowDisabledClick
|
||||||
rightElement={!isCurrentUserPremium && <i className="icon icon-lock-badge settings-icon-locked" />}
|
rightElement={isCurrentUserPremium && <PremiumIcon big withGradient />}
|
||||||
className="no-icon"
|
className="no-icon"
|
||||||
onClick={handleVoiceMessagesClick}
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
onClick={() => onScreenSelect(SettingsScreens.PrivacyVoiceMessages)}
|
||||||
>
|
>
|
||||||
<div className="multiline-menu-item">
|
<div className="multiline-menu-item">
|
||||||
<span className="title">{lang('PrivacyVoiceMessagesTitle')}</span>
|
<span className="title">{lang('PrivacyVoiceMessagesTitle')}</span>
|
||||||
@ -311,6 +303,22 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItem
|
||||||
|
narrow
|
||||||
|
rightElement={isCurrentUserPremium && <PremiumIcon big withGradient />}
|
||||||
|
className="no-icon"
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
onClick={() => onScreenSelect(SettingsScreens.PrivacyMessages)}
|
||||||
|
>
|
||||||
|
<div className="multiline-menu-item">
|
||||||
|
<span className="title">{lang('PrivacyMessagesTitle')}</span>
|
||||||
|
<span className="subtitle" dir="auto">
|
||||||
|
{shouldNewNonContactPeersRequirePremium
|
||||||
|
? lang('PrivacyMessagesContactsAndPremium')
|
||||||
|
: lang('P2PEverybody')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ListItem>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{canDisplayAutoarchiveSetting && (
|
{canDisplayAutoarchiveSetting && (
|
||||||
@ -362,7 +370,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
settings: {
|
settings: {
|
||||||
byKey: {
|
byKey: {
|
||||||
hasPassword, isSensitiveEnabled, canChangeSensitive, shouldArchiveAndMuteNewNonContact,
|
hasPassword, isSensitiveEnabled, canChangeSensitive, shouldArchiveAndMuteNewNonContact,
|
||||||
canDisplayChatInTitle,
|
canDisplayChatInTitle, shouldNewNonContactPeersRequirePremium,
|
||||||
},
|
},
|
||||||
privacy,
|
privacy,
|
||||||
},
|
},
|
||||||
@ -383,6 +391,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
canDisplayAutoarchiveSetting: Boolean(appConfig?.canDisplayAutoarchiveSetting),
|
canDisplayAutoarchiveSetting: Boolean(appConfig?.canDisplayAutoarchiveSetting),
|
||||||
shouldArchiveAndMuteNewNonContact,
|
shouldArchiveAndMuteNewNonContact,
|
||||||
canChangeSensitive,
|
canChangeSensitive,
|
||||||
|
shouldNewNonContactPeersRequirePremium,
|
||||||
privacyPhoneNumber: privacy.phoneNumber,
|
privacyPhoneNumber: privacy.phoneNumber,
|
||||||
privacyLastSeen: privacy.lastSeen,
|
privacyLastSeen: privacy.lastSeen,
|
||||||
privacyProfilePhoto: privacy.profilePhoto,
|
privacyProfilePhoto: privacy.profilePhoto,
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
:global(.settings-item-description-larger).premiumInfo {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
import type { PrivacyVisibility } from '../../../types';
|
import type { PrivacyVisibility } from '../../../types';
|
||||||
|
|
||||||
import { selectIsCurrentUserPremium, selectShouldHideReadMarks } from '../../../global/selectors';
|
import { selectIsCurrentUserPremium, selectShouldHideReadMarks } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -14,8 +13,6 @@ import PremiumIcon from '../../common/PremiumIcon';
|
|||||||
import Checkbox from '../../ui/Checkbox';
|
import Checkbox from '../../ui/Checkbox';
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
|
|
||||||
import styles from './SettingsPrivacyLastSeen.module.scss';
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
visibility?: PrivacyVisibility;
|
visibility?: PrivacyVisibility;
|
||||||
};
|
};
|
||||||
@ -59,10 +56,7 @@ const SettingsPrivacyLastSeen = ({
|
|||||||
{isCurrentUserPremium ? lang('PrivacyLastSeenPremiumForPremium') : lang('PrivacyLastSeenPremium')}
|
{isCurrentUserPremium ? lang('PrivacyLastSeenPremiumForPremium') : lang('PrivacyLastSeenPremium')}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<p
|
<p
|
||||||
className={buildClassName(
|
className="settings-item-description-larger premium-info"
|
||||||
'settings-item-description-larger',
|
|
||||||
styles.premiumInfo,
|
|
||||||
)}
|
|
||||||
dir={lang.isRtl ? 'rtl' : undefined}
|
dir={lang.isRtl ? 'rtl' : undefined}
|
||||||
>
|
>
|
||||||
{isCurrentUserPremium
|
{isCurrentUserPremium
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import type { ApiPhoto } from '../../../api/types';
|
|||||||
import type { ApiPrivacySettings } from '../../../types';
|
import type { ApiPrivacySettings } from '../../../types';
|
||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { selectUserFullInfo } from '../../../global/selectors';
|
import { selectIsCurrentUserPremium, selectUserFullInfo } from '../../../global/selectors';
|
||||||
import { getPrivacyKey } from './helpers/privacy';
|
import { getPrivacyKey } from './helpers/privacy';
|
||||||
|
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
@ -15,6 +15,8 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
|||||||
|
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import RadioGroup from '../../ui/RadioGroup';
|
import RadioGroup from '../../ui/RadioGroup';
|
||||||
|
import PremiumStatusItem from './PremiumStatusItem';
|
||||||
|
import PrivacyLockedOption from './PrivacyLockedOption';
|
||||||
import SettingsPrivacyLastSeen from './SettingsPrivacyLastSeen';
|
import SettingsPrivacyLastSeen from './SettingsPrivacyLastSeen';
|
||||||
import SettingsPrivacyPublicProfilePhoto from './SettingsPrivacyPublicProfilePhoto';
|
import SettingsPrivacyPublicProfilePhoto from './SettingsPrivacyPublicProfilePhoto';
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ type StateProps = {
|
|||||||
currentUserFallbackPhoto?: ApiPhoto;
|
currentUserFallbackPhoto?: ApiPhoto;
|
||||||
primaryPrivacy?: ApiPrivacySettings;
|
primaryPrivacy?: ApiPrivacySettings;
|
||||||
secondaryPrivacy?: ApiPrivacySettings;
|
secondaryPrivacy?: ApiPrivacySettings;
|
||||||
|
isPremiumRequired?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
||||||
@ -41,6 +44,7 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
hasCurrentUserFullInfo,
|
hasCurrentUserFullInfo,
|
||||||
currentUserFallbackPhoto,
|
currentUserFallbackPhoto,
|
||||||
|
isPremiumRequired,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
onReset,
|
onReset,
|
||||||
}) => {
|
}) => {
|
||||||
@ -67,6 +71,7 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
|
|||||||
screen={screen}
|
screen={screen}
|
||||||
privacy={primaryPrivacy}
|
privacy={primaryPrivacy}
|
||||||
onScreenSelect={onScreenSelect}
|
onScreenSelect={onScreenSelect}
|
||||||
|
isPremiumRequired={isPremiumRequired}
|
||||||
/>
|
/>
|
||||||
{screen === SettingsScreens.PrivacyProfilePhoto && primaryPrivacy?.visibility !== 'everybody' && (
|
{screen === SettingsScreens.PrivacyProfilePhoto && primaryPrivacy?.visibility !== 'everybody' && (
|
||||||
<SettingsPrivacyPublicProfilePhoto
|
<SettingsPrivacyPublicProfilePhoto
|
||||||
@ -93,9 +98,11 @@ function PrivacySubsection({
|
|||||||
screen,
|
screen,
|
||||||
privacy,
|
privacy,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
|
isPremiumRequired,
|
||||||
}: {
|
}: {
|
||||||
screen: SettingsScreens;
|
screen: SettingsScreens;
|
||||||
privacy?: ApiPrivacySettings;
|
privacy?: ApiPrivacySettings;
|
||||||
|
isPremiumRequired?: boolean;
|
||||||
onScreenSelect: (screen: SettingsScreens) => void;
|
onScreenSelect: (screen: SettingsScreens) => void;
|
||||||
}) {
|
}) {
|
||||||
const { setPrivacyVisibility } = getActions();
|
const { setPrivacyVisibility } = getActions();
|
||||||
@ -105,13 +112,30 @@ function PrivacySubsection({
|
|||||||
const hasNobody = screen !== SettingsScreens.PrivacyAddByPhone;
|
const hasNobody = screen !== SettingsScreens.PrivacyAddByPhone;
|
||||||
const options = [
|
const options = [
|
||||||
{ value: 'everybody', label: lang('P2PEverybody') },
|
{ value: 'everybody', label: lang('P2PEverybody') },
|
||||||
{ value: 'contacts', label: lang('P2PContacts') },
|
{
|
||||||
|
value: 'contacts',
|
||||||
|
label: isPremiumRequired ? (
|
||||||
|
<PrivacyLockedOption label={lang('P2PContacts')} />
|
||||||
|
) : (
|
||||||
|
lang('P2PContacts')
|
||||||
|
),
|
||||||
|
hidden: isPremiumRequired,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (hasNobody) {
|
if (hasNobody) {
|
||||||
options.push({ value: 'nobody', label: lang('P2PNobody') });
|
options.push({
|
||||||
|
value: 'nobody',
|
||||||
|
label: isPremiumRequired ? (
|
||||||
|
<PrivacyLockedOption label={lang('P2PNobody')} />
|
||||||
|
) : (
|
||||||
|
lang('P2PNobody')
|
||||||
|
),
|
||||||
|
hidden: isPremiumRequired,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}, [lang, screen]);
|
}, [lang, screen, isPremiumRequired]);
|
||||||
|
|
||||||
const primaryExceptionLists = useMemo(() => {
|
const primaryExceptionLists = useMemo(() => {
|
||||||
if (screen === SettingsScreens.PrivacyAddByPhone) {
|
if (screen === SettingsScreens.PrivacyAddByPhone) {
|
||||||
@ -136,6 +160,8 @@ function PrivacySubsection({
|
|||||||
case SettingsScreens.PrivacyAddByPhone: {
|
case SettingsScreens.PrivacyAddByPhone: {
|
||||||
return privacy?.visibility === 'everybody' ? lang('PrivacyPhoneInfo') : lang('PrivacyPhoneInfo3');
|
return privacy?.visibility === 'everybody' ? lang('PrivacyPhoneInfo') : lang('PrivacyPhoneInfo3');
|
||||||
}
|
}
|
||||||
|
case SettingsScreens.PrivacyVoiceMessages:
|
||||||
|
return lang('PrivacyVoiceMessagesInfo');
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -257,7 +283,7 @@ function PrivacySubsection({
|
|||||||
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>{descriptionText}</p>
|
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>{descriptionText}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{(primaryExceptionLists.shouldShowAllowed || primaryExceptionLists.shouldShowDenied) && (
|
{!isPremiumRequired && (primaryExceptionLists.shouldShowAllowed || primaryExceptionLists.shouldShowDenied) && (
|
||||||
<div className="settings-item">
|
<div className="settings-item">
|
||||||
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>
|
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
{lang('PrivacyExceptions')}
|
{lang('PrivacyExceptions')}
|
||||||
@ -294,6 +320,7 @@ function PrivacySubsection({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isPremiumRequired && <PremiumStatusItem />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -361,6 +388,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
currentUserId: currentUserId!,
|
currentUserId: currentUserId!,
|
||||||
hasCurrentUserFullInfo: Boolean(currentUserFullInfo),
|
hasCurrentUserFullInfo: Boolean(currentUserFullInfo),
|
||||||
currentUserFallbackPhoto: currentUserFullInfo?.fallbackPhoto,
|
currentUserFallbackPhoto: currentUserFullInfo?.fallbackPhoto,
|
||||||
|
isPremiumRequired: screen === SettingsScreens.PrivacyVoiceMessages && !selectIsCurrentUserPremium(global),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(SettingsPrivacyVisibility));
|
)(SettingsPrivacyVisibility));
|
||||||
|
|||||||
@ -20,6 +20,7 @@ type OwnProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
|
className?: string;
|
||||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,18 +34,20 @@ const Radio: FC<OwnProps> = ({
|
|||||||
disabled,
|
disabled,
|
||||||
hidden,
|
hidden,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
className,
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
const className = buildClassName(
|
const fullClassName = buildClassName(
|
||||||
'Radio',
|
'Radio',
|
||||||
|
className,
|
||||||
disabled && 'disabled',
|
disabled && 'disabled',
|
||||||
hidden && 'hidden-widget',
|
hidden && 'hidden-widget',
|
||||||
isLoading && 'loading',
|
isLoading && 'loading',
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label className={className} dir={lang.isRtl ? 'rtl' : undefined}>
|
<label className={fullClassName} dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name={name}
|
name={name}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export type IRadioOption = {
|
|||||||
subLabel?: string;
|
subLabel?: string;
|
||||||
value: string;
|
value: string;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
@ -47,6 +48,7 @@ const RadioGroup: FC<OwnProps> = ({
|
|||||||
hidden={option.hidden}
|
hidden={option.hidden}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
isLoading={loadingOption ? loadingOption === option.value : undefined}
|
isLoading={loadingOption ? loadingOption === option.value : undefined}
|
||||||
|
className={option.className}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -674,6 +674,8 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
|||||||
const shouldArchiveAndMuteNewNonContact = payload.shouldArchiveAndMuteNewNonContact
|
const shouldArchiveAndMuteNewNonContact = payload.shouldArchiveAndMuteNewNonContact
|
||||||
?? Boolean(global.settings.byKey.shouldArchiveAndMuteNewNonContact);
|
?? Boolean(global.settings.byKey.shouldArchiveAndMuteNewNonContact);
|
||||||
const shouldHideReadMarks = payload.shouldHideReadMarks ?? Boolean(global.settings.byKey.shouldHideReadMarks);
|
const shouldHideReadMarks = payload.shouldHideReadMarks ?? Boolean(global.settings.byKey.shouldHideReadMarks);
|
||||||
|
const shouldNewNonContactPeersRequirePremium = payload.shouldNewNonContactPeersRequirePremium
|
||||||
|
?? Boolean(global.settings.byKey.shouldNewNonContactPeersRequirePremium);
|
||||||
|
|
||||||
global = replaceSettings(global, { shouldArchiveAndMuteNewNonContact, shouldHideReadMarks });
|
global = replaceSettings(global, { shouldArchiveAndMuteNewNonContact, shouldHideReadMarks });
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
@ -681,6 +683,7 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
|||||||
const result = await callApi('updateGlobalPrivacySettings', {
|
const result = await callApi('updateGlobalPrivacySettings', {
|
||||||
shouldArchiveAndMuteNewNonContact,
|
shouldArchiveAndMuteNewNonContact,
|
||||||
shouldHideReadMarks,
|
shouldHideReadMarks,
|
||||||
|
shouldNewNonContactPeersRequirePremium,
|
||||||
});
|
});
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
@ -689,6 +692,9 @@ addActionHandler('updateGlobalPrivacySettings', async (global, actions, payload)
|
|||||||
? !shouldArchiveAndMuteNewNonContact
|
? !shouldArchiveAndMuteNewNonContact
|
||||||
: result.shouldArchiveAndMuteNewNonContact,
|
: result.shouldArchiveAndMuteNewNonContact,
|
||||||
shouldHideReadMarks: !result ? !shouldHideReadMarks : result.shouldHideReadMarks,
|
shouldHideReadMarks: !result ? !shouldHideReadMarks : result.shouldHideReadMarks,
|
||||||
|
shouldNewNonContactPeersRequirePremium: !result
|
||||||
|
? !shouldNewNonContactPeersRequirePremium
|
||||||
|
: result.shouldNewNonContactPeersRequirePremium,
|
||||||
});
|
});
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -242,6 +242,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
wasTimeFormatSetManually: false,
|
wasTimeFormatSetManually: false,
|
||||||
isConnectionStatusMinimized: true,
|
isConnectionStatusMinimized: true,
|
||||||
shouldArchiveAndMuteNewNonContact: false,
|
shouldArchiveAndMuteNewNonContact: false,
|
||||||
|
shouldNewNonContactPeersRequirePremium: false,
|
||||||
shouldHideReadMarks: false,
|
shouldHideReadMarks: false,
|
||||||
canTranslate: false,
|
canTranslate: false,
|
||||||
canTranslateChats: true,
|
canTranslateChats: true,
|
||||||
|
|||||||
@ -20,6 +20,10 @@ export function selectTranslationLanguage<T extends GlobalState>(global: T) {
|
|||||||
return global.settings.byKey.translationLanguage || selectLanguageCode(global);
|
return global.settings.byKey.translationLanguage || selectLanguageCode(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function selectNewNoncontactPeersRequirePremium<T extends GlobalState>(global: T) {
|
||||||
|
return global.settings.byKey.shouldNewNonContactPeersRequirePremium;
|
||||||
|
}
|
||||||
|
|
||||||
export function selectShouldHideReadMarks<T extends GlobalState>(global: T) {
|
export function selectShouldHideReadMarks<T extends GlobalState>(global: T) {
|
||||||
return global.settings.byKey.shouldHideReadMarks;
|
return global.settings.byKey.shouldHideReadMarks;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2873,7 +2873,11 @@ export interface ActionPayloads {
|
|||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
closeShareChatFolderModal: undefined | WithTabId;
|
closeShareChatFolderModal: undefined | WithTabId;
|
||||||
loadGlobalPrivacySettings: undefined;
|
loadGlobalPrivacySettings: undefined;
|
||||||
updateGlobalPrivacySettings: { shouldArchiveAndMuteNewNonContact?: boolean; shouldHideReadMarks?: boolean };
|
updateGlobalPrivacySettings: {
|
||||||
|
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||||
|
shouldHideReadMarks?: boolean;
|
||||||
|
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// Premium
|
// Premium
|
||||||
openPremiumModal: ({
|
openPremiumModal: ({
|
||||||
|
|||||||
@ -101,6 +101,7 @@ export interface ISettings extends NotifySettings, Record<string, any> {
|
|||||||
wasTimeFormatSetManually: boolean;
|
wasTimeFormatSetManually: boolean;
|
||||||
isConnectionStatusMinimized: boolean;
|
isConnectionStatusMinimized: boolean;
|
||||||
shouldArchiveAndMuteNewNonContact?: boolean;
|
shouldArchiveAndMuteNewNonContact?: boolean;
|
||||||
|
shouldNewNonContactPeersRequirePremium?: boolean;
|
||||||
shouldHideReadMarks?: boolean;
|
shouldHideReadMarks?: boolean;
|
||||||
canTranslate: boolean;
|
canTranslate: boolean;
|
||||||
canTranslateChats: boolean;
|
canTranslateChats: boolean;
|
||||||
@ -183,6 +184,7 @@ export enum SettingsScreens {
|
|||||||
PrivacyPhoneP2P,
|
PrivacyPhoneP2P,
|
||||||
PrivacyForwarding,
|
PrivacyForwarding,
|
||||||
PrivacyVoiceMessages,
|
PrivacyVoiceMessages,
|
||||||
|
PrivacyMessages,
|
||||||
PrivacyGroupChats,
|
PrivacyGroupChats,
|
||||||
PrivacyPhoneNumberAllowedContacts,
|
PrivacyPhoneNumberAllowedContacts,
|
||||||
PrivacyPhoneNumberDeniedContacts,
|
PrivacyPhoneNumberDeniedContacts,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user