chore(web): put sign-in email notifications setting under paywall (#2249)
* chore: upgrade setting names to value objects * chore(web): put sign-in email notifications setting under paywall * chore: fix using setting name value objects in mocha tests * chore: fix wording on email notifications titles
This commit is contained in:
@@ -9,7 +9,7 @@ import SignOutWrapper from './SignOutView'
|
||||
import FilesSection from './Files'
|
||||
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
||||
import SubscriptionSharing from './SubscriptionSharing/SubscriptionSharing'
|
||||
import Email from './Email'
|
||||
import Email from './Email/Email'
|
||||
import DeleteAccount from '@/Components/Preferences/Panes/Account/DeleteAccount'
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { MuteMarketingEmailsOption, MuteSignInEmailsOption, SettingName } from '@standardnotes/snjs'
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
FeatureStatus,
|
||||
MuteMarketingEmailsOption,
|
||||
MuteSignInEmailsOption,
|
||||
SettingName,
|
||||
} from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
@@ -10,6 +16,7 @@ import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
||||
import Spinner from '@/Components/Spinner/Spinner'
|
||||
import NoProSubscription from '../NoProSubscription'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -20,6 +27,9 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [marketingEmailsMutedValue, setMarketingEmailsMutedValue] = useState(MuteMarketingEmailsOption.NotMuted)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const isMuteSignInEmailsFeatureAvailable =
|
||||
application.features.getFeatureStatus(FeatureIdentifier.SignInAlerts) === FeatureStatus.Entitled
|
||||
|
||||
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
await application.settings.updateSetting(settingName, payload, false)
|
||||
@@ -40,13 +50,13 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSignInEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||
SettingName.MuteSignInEmails,
|
||||
SettingName.create(SettingName.NAMES.MuteSignInEmails).getValue(),
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
setMarketingEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteMarketingEmailsOption>(
|
||||
SettingName.MuteMarketingEmails,
|
||||
SettingName.create(SettingName.NAMES.MuteMarketingEmails).getValue(),
|
||||
MuteMarketingEmailsOption.NotMuted,
|
||||
),
|
||||
)
|
||||
@@ -67,7 +77,10 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteSignInEmails).getValue(),
|
||||
newValue,
|
||||
)
|
||||
|
||||
if (!updateResult) {
|
||||
setSignInEmailsMutedValue(previousValue)
|
||||
@@ -82,7 +95,10 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
: MuteMarketingEmailsOption.Muted
|
||||
setMarketingEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteMarketingEmails, newValue)
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteMarketingEmails).getValue(),
|
||||
newValue,
|
||||
)
|
||||
|
||||
if (!updateResult) {
|
||||
setMarketingEmailsMutedValue(previousValue)
|
||||
@@ -96,25 +112,40 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable sign-in notification emails</Subtitle>
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available only to paid subscribers).
|
||||
</Text>
|
||||
<Subtitle>Sign-in notification emails</Subtitle>
|
||||
{isMuteSignInEmailsFeatureAvailable ? (
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available only to paid subscribers).
|
||||
</Text>
|
||||
) : (
|
||||
<NoProSubscription
|
||||
application={application}
|
||||
text={
|
||||
<span>
|
||||
Sign-in notification emails are available only on a{' '}
|
||||
<span className="font-bold">subscription</span> plan. Please upgrade in order to enable sign-in
|
||||
notifications.
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
isMuteSignInEmailsFeatureAvailable && (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable marketing notification emails</Subtitle>
|
||||
<Subtitle>Marketing notification emails</Subtitle>
|
||||
<Text>Disables email notifications with special deals and promotions.</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import Spinner from '@/Components/Spinner/Spinner'
|
||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||
import { SubscriptionSettingName } from '@standardnotes/snjs'
|
||||
import { SettingName } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, useEffect, useState } from 'react'
|
||||
import { Subtitle, Title } from '../../PreferencesComponents/Content'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
@@ -19,10 +19,10 @@ const FilesSection: FunctionComponent<Props> = ({ application }) => {
|
||||
useEffect(() => {
|
||||
const getFilesQuota = async () => {
|
||||
const filesQuotaUsed = await application.settings.getSubscriptionSetting(
|
||||
SubscriptionSettingName.FileUploadBytesUsed,
|
||||
SettingName.create(SettingName.NAMES.FileUploadBytesUsed).getValue(),
|
||||
)
|
||||
const filesQuotaTotal = await application.settings.getSubscriptionSetting(
|
||||
SubscriptionSettingName.FileUploadBytesLimit,
|
||||
SettingName.create(SettingName.NAMES.FileUploadBytesLimit).getValue(),
|
||||
)
|
||||
|
||||
if (filesQuotaUsed) {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { FunctionComponent, useState } from 'react'
|
||||
import { FunctionComponent, ReactNode, useState } from 'react'
|
||||
import { LinkButton, Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
text: ReactNode
|
||||
}
|
||||
|
||||
const NoProSubscription: FunctionComponent<Props> = ({ application }) => {
|
||||
const NoProSubscription: FunctionComponent<Props> = ({ application, text }) => {
|
||||
const [isLoadingPurchaseFlow, setIsLoadingPurchaseFlow] = useState(false)
|
||||
const [purchaseFlowError, setPurchaseFlowError] = useState<string | undefined>(undefined)
|
||||
|
||||
@@ -29,10 +30,7 @@ const NoProSubscription: FunctionComponent<Props> = ({ application }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text>
|
||||
Subscription sharing is available only on the <span className="font-bold">Professional</span> plan. Please
|
||||
upgrade in order to share your subscription.
|
||||
</Text>
|
||||
<Text>{text}</Text>
|
||||
{isLoadingPurchaseFlow && <Text>Redirecting you to the subscription page...</Text>}
|
||||
{purchaseFlowError && <Text className="text-danger">{purchaseFlowError}</Text>}
|
||||
|
||||
@@ -9,7 +9,7 @@ import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/Pre
|
||||
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
|
||||
import NoProSubscription from './NoProSubscription'
|
||||
import NoProSubscription from '../NoProSubscription'
|
||||
import InvitationsList from './InvitationsList'
|
||||
import Invite from './Invite/Invite'
|
||||
import Button from '@/Components/Button/Button'
|
||||
@@ -57,7 +57,15 @@ const SubscriptionSharing: FunctionComponent<Props> = ({ application, viewContro
|
||||
</ModalOverlay>
|
||||
</div>
|
||||
) : (
|
||||
<NoProSubscription application={application} />
|
||||
<NoProSubscription
|
||||
application={application}
|
||||
text={
|
||||
<span>
|
||||
Subscription sharing is available only on the <span className="font-bold">Professional</span> plan.
|
||||
Please upgrade in order to share your subscription.
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -82,18 +82,18 @@ const CloudBackupProvider: FunctionComponent<Props> = ({ application, providerNa
|
||||
|
||||
const backupSettingsData = {
|
||||
[CloudProvider.Dropbox]: {
|
||||
backupTokenSettingName: SettingName.DropboxBackupToken,
|
||||
backupFrequencySettingName: SettingName.DropboxBackupFrequency,
|
||||
backupTokenSettingName: SettingName.create(SettingName.NAMES.DropboxBackupToken).getValue(),
|
||||
backupFrequencySettingName: SettingName.create(SettingName.NAMES.DropboxBackupFrequency).getValue(),
|
||||
defaultBackupFrequency: DropboxBackupFrequency.Daily,
|
||||
},
|
||||
[CloudProvider.Google]: {
|
||||
backupTokenSettingName: SettingName.GoogleDriveBackupToken,
|
||||
backupFrequencySettingName: SettingName.GoogleDriveBackupFrequency,
|
||||
backupTokenSettingName: SettingName.create(SettingName.NAMES.GoogleDriveBackupToken).getValue(),
|
||||
backupFrequencySettingName: SettingName.create(SettingName.NAMES.GoogleDriveBackupFrequency).getValue(),
|
||||
defaultBackupFrequency: GoogleDriveBackupFrequency.Daily,
|
||||
},
|
||||
[CloudProvider.OneDrive]: {
|
||||
backupTokenSettingName: SettingName.OneDriveBackupToken,
|
||||
backupFrequencySettingName: SettingName.OneDriveBackupFrequency,
|
||||
backupTokenSettingName: SettingName.create(SettingName.NAMES.OneDriveBackupToken).getValue(),
|
||||
backupFrequencySettingName: SettingName.create(SettingName.NAMES.OneDriveBackupFrequency).getValue(),
|
||||
defaultBackupFrequency: OneDriveBackupFrequency.Daily,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ const CloudLink: FunctionComponent<Props> = ({ application }) => {
|
||||
setIsFailedCloudBackupEmailMuted(
|
||||
convertStringifiedBooleanToBoolean(
|
||||
userSettings.getSettingValue(
|
||||
SettingName.MuteFailedCloudBackupsEmails,
|
||||
SettingName.create(SettingName.NAMES.MuteFailedCloudBackupsEmails).getValue(),
|
||||
MuteFailedCloudBackupsEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
@@ -83,7 +83,7 @@ const CloudLink: FunctionComponent<Props> = ({ application }) => {
|
||||
setIsFailedCloudBackupEmailMuted(!isFailedCloudBackupEmailMuted)
|
||||
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.MuteFailedCloudBackupsEmails,
|
||||
SettingName.create(SettingName.NAMES.MuteFailedCloudBackupsEmails).getValue(),
|
||||
`${!isFailedCloudBackupEmailMuted}`,
|
||||
)
|
||||
if (!updateResult) {
|
||||
|
||||
@@ -34,14 +34,14 @@ const EmailBackups = ({ application }: Props) => {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setEmailFrequency(
|
||||
userSettings.getSettingValue<EmailBackupFrequency>(
|
||||
SettingName.EmailBackupFrequency,
|
||||
SettingName.create(SettingName.NAMES.EmailBackupFrequency).getValue(),
|
||||
EmailBackupFrequency.Disabled,
|
||||
),
|
||||
)
|
||||
setIsFailedBackupEmailMuted(
|
||||
convertStringifiedBooleanToBoolean(
|
||||
userSettings.getSettingValue<MuteFailedBackupsEmailsOption>(
|
||||
SettingName.MuteFailedBackupsEmails,
|
||||
SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue(),
|
||||
MuteFailedBackupsEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
@@ -81,7 +81,10 @@ const EmailBackups = ({ application }: Props) => {
|
||||
const previousFrequency = emailFrequency
|
||||
setEmailFrequency(frequency)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.EmailBackupFrequency, frequency)
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.EmailBackupFrequency).getValue(),
|
||||
frequency,
|
||||
)
|
||||
if (!updateResult) {
|
||||
setEmailFrequency(previousFrequency)
|
||||
}
|
||||
@@ -91,7 +94,10 @@ const EmailBackups = ({ application }: Props) => {
|
||||
const previousValue = isFailedBackupEmailMuted
|
||||
setIsFailedBackupEmailMuted(!isFailedBackupEmailMuted)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteFailedBackupsEmails, `${!isFailedBackupEmailMuted}`)
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.MuteFailedBackupsEmails).getValue(),
|
||||
`${!isFailedBackupEmailMuted}`,
|
||||
)
|
||||
if (!updateResult) {
|
||||
setIsFailedBackupEmailMuted(previousValue)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSessionUaLoggingValue(
|
||||
userSettings.getSettingValue<LogSessionUserAgentOption>(
|
||||
SettingName.LogSessionUserAgent,
|
||||
SettingName.create(SettingName.NAMES.LogSessionUserAgent).getValue(),
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
),
|
||||
)
|
||||
@@ -62,7 +62,10 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
: LogSessionUserAgentOption.Enabled
|
||||
setSessionUaLoggingValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.LogSessionUserAgent, newValue)
|
||||
const updateResult = await updateSetting(
|
||||
SettingName.create(SettingName.NAMES.LogSessionUserAgent).getValue(),
|
||||
newValue,
|
||||
)
|
||||
|
||||
if (!updateResult) {
|
||||
setSessionUaLoggingValue(previousValue)
|
||||
|
||||
Reference in New Issue
Block a user