Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619)
This reverts commit 6824dd2d5f.
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
|||||||
ListedAuthorSecretsData,
|
ListedAuthorSecretsData,
|
||||||
LogSessionUserAgentOption,
|
LogSessionUserAgentOption,
|
||||||
SettingName,
|
SettingName,
|
||||||
|
MuteMarketingEmailsOption,
|
||||||
} from '@standardnotes/settings'
|
} from '@standardnotes/settings'
|
||||||
|
|
||||||
type SettingType =
|
type SettingType =
|
||||||
@@ -23,6 +24,7 @@ type SettingType =
|
|||||||
| MuteFailedBackupsEmailsOption
|
| MuteFailedBackupsEmailsOption
|
||||||
| MuteFailedCloudBackupsEmailsOption
|
| MuteFailedCloudBackupsEmailsOption
|
||||||
| MuteSignInEmailsOption
|
| MuteSignInEmailsOption
|
||||||
|
| MuteMarketingEmailsOption
|
||||||
| OneDriveBackupFrequency
|
| OneDriveBackupFrequency
|
||||||
|
|
||||||
export class SettingsList {
|
export class SettingsList {
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||||
|
import Switch from '@/Components/Switch/Switch'
|
||||||
|
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
|
import { WebApplication } from '@/Application/Application'
|
||||||
|
import { MuteMarketingEmailsOption, MuteSignInEmailsOption, SettingName } from '@standardnotes/snjs'
|
||||||
|
import { observer } from 'mobx-react-lite'
|
||||||
|
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||||
|
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||||
|
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||||
|
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||||
|
import Spinner from '@/Components/Spinner/Spinner'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
application: WebApplication
|
||||||
|
}
|
||||||
|
|
||||||
|
const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||||
|
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState(MuteSignInEmailsOption.NotMuted)
|
||||||
|
const [marketingEmailsMutedValue, setMarketingEmailsMutedValue] = useState(MuteMarketingEmailsOption.NotMuted)
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
|
||||||
|
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||||
|
try {
|
||||||
|
await application.settings.updateSetting(settingName, payload, false)
|
||||||
|
return true
|
||||||
|
} catch (e) {
|
||||||
|
application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING).catch(console.error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadSettings = useCallback(async () => {
|
||||||
|
if (!application.getUser()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userSettings = await application.settings.listSettings()
|
||||||
|
setSignInEmailsMutedValue(
|
||||||
|
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||||
|
SettingName.MuteSignInEmails,
|
||||||
|
MuteSignInEmailsOption.NotMuted,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
setMarketingEmailsMutedValue(
|
||||||
|
userSettings.getSettingValue<MuteMarketingEmailsOption>(
|
||||||
|
SettingName.MuteMarketingEmails,
|
||||||
|
MuteMarketingEmailsOption.NotMuted,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}, [application])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadSettings().catch(console.error)
|
||||||
|
}, [loadSettings])
|
||||||
|
|
||||||
|
const toggleMuteSignInEmails = async () => {
|
||||||
|
const previousValue = signInEmailsMutedValue
|
||||||
|
const newValue =
|
||||||
|
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||||
|
setSignInEmailsMutedValue(newValue)
|
||||||
|
|
||||||
|
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||||
|
|
||||||
|
if (!updateResult) {
|
||||||
|
setSignInEmailsMutedValue(previousValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleMuteMarketingEmails = async () => {
|
||||||
|
const previousValue = marketingEmailsMutedValue
|
||||||
|
const newValue =
|
||||||
|
previousValue === MuteMarketingEmailsOption.Muted
|
||||||
|
? MuteMarketingEmailsOption.NotMuted
|
||||||
|
: MuteMarketingEmailsOption.Muted
|
||||||
|
setMarketingEmailsMutedValue(newValue)
|
||||||
|
|
||||||
|
const updateResult = await updateSetting(SettingName.MuteMarketingEmails, newValue)
|
||||||
|
|
||||||
|
if (!updateResult) {
|
||||||
|
setMarketingEmailsMutedValue(previousValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PreferencesGroup>
|
||||||
|
<PreferencesSegment>
|
||||||
|
<Title>Email</Title>
|
||||||
|
<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 to paid subscribers).
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
{isLoading ? (
|
||||||
|
<Spinner className="ml-2 flex-shrink-0" />
|
||||||
|
) : (
|
||||||
|
<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>
|
||||||
|
<Text>Disables email notifications with special deals and promotions.</Text>
|
||||||
|
</div>
|
||||||
|
{isLoading ? (
|
||||||
|
<Spinner className="ml-2 flex-shrink-0" />
|
||||||
|
) : (
|
||||||
|
<Switch
|
||||||
|
onChange={toggleMuteMarketingEmails}
|
||||||
|
checked={marketingEmailsMutedValue === MuteMarketingEmailsOption.Muted}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PreferencesSegment>
|
||||||
|
</PreferencesGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default observer(Email)
|
||||||
@@ -8,6 +8,7 @@ import Defaults from './Defaults'
|
|||||||
import LabsPane from './Labs/Labs'
|
import LabsPane from './Labs/Labs'
|
||||||
import Advanced from '@/Components/Preferences/Panes/General/Advanced/AdvancedSection'
|
import Advanced from '@/Components/Preferences/Panes/General/Advanced/AdvancedSection'
|
||||||
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
||||||
|
import Email from './Email'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
viewControllerManager: ViewControllerManager
|
viewControllerManager: ViewControllerManager
|
||||||
@@ -19,6 +20,7 @@ const General: FunctionComponent<Props> = ({ viewControllerManager, application,
|
|||||||
<PreferencesPane>
|
<PreferencesPane>
|
||||||
<Tools application={application} />
|
<Tools application={application} />
|
||||||
<Defaults application={application} />
|
<Defaults application={application} />
|
||||||
|
<Email application={application} />
|
||||||
<LabsPane application={application} />
|
<LabsPane application={application} />
|
||||||
<Advanced
|
<Advanced
|
||||||
application={application}
|
application={application}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
|||||||
import Switch from '@/Components/Switch/Switch'
|
import Switch from '@/Components/Switch/Switch'
|
||||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import { MuteSignInEmailsOption, LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||||
@@ -15,9 +15,6 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState<MuteSignInEmailsOption>(
|
|
||||||
MuteSignInEmailsOption.NotMuted,
|
|
||||||
)
|
|
||||||
const [sessionUaLoggingValue, setSessionUaLoggingValue] = useState<LogSessionUserAgentOption>(
|
const [sessionUaLoggingValue, setSessionUaLoggingValue] = useState<LogSessionUserAgentOption>(
|
||||||
LogSessionUserAgentOption.Enabled,
|
LogSessionUserAgentOption.Enabled,
|
||||||
)
|
)
|
||||||
@@ -41,12 +38,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const userSettings = await application.settings.listSettings()
|
const userSettings = await application.settings.listSettings()
|
||||||
setSignInEmailsMutedValue(
|
|
||||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
|
||||||
SettingName.MuteSignInEmails,
|
|
||||||
MuteSignInEmailsOption.NotMuted,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
setSessionUaLoggingValue(
|
setSessionUaLoggingValue(
|
||||||
userSettings.getSettingValue<LogSessionUserAgentOption>(
|
userSettings.getSettingValue<LogSessionUserAgentOption>(
|
||||||
SettingName.LogSessionUserAgent,
|
SettingName.LogSessionUserAgent,
|
||||||
@@ -64,19 +55,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
|||||||
loadSettings().catch(console.error)
|
loadSettings().catch(console.error)
|
||||||
}, [loadSettings])
|
}, [loadSettings])
|
||||||
|
|
||||||
const toggleMuteSignInEmails = async () => {
|
|
||||||
const previousValue = signInEmailsMutedValue
|
|
||||||
const newValue =
|
|
||||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
|
||||||
setSignInEmailsMutedValue(newValue)
|
|
||||||
|
|
||||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
|
||||||
|
|
||||||
if (!updateResult) {
|
|
||||||
setSignInEmailsMutedValue(previousValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleSessionLogging = async () => {
|
const toggleSessionLogging = async () => {
|
||||||
const previousValue = sessionUaLoggingValue
|
const previousValue = sessionUaLoggingValue
|
||||||
const newValue =
|
const newValue =
|
||||||
@@ -97,23 +75,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
|||||||
<PreferencesSegment>
|
<PreferencesSegment>
|
||||||
<Title>Privacy</Title>
|
<Title>Privacy</Title>
|
||||||
<div>
|
<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 to paid subscribers).
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
{isLoading ? (
|
|
||||||
<Spinner className="ml-2 flex-shrink-0" />
|
|
||||||
) : (
|
|
||||||
<Switch
|
|
||||||
onChange={toggleMuteSignInEmails}
|
|
||||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<HorizontalSeparator classes="my-4" />
|
<HorizontalSeparator classes="my-4" />
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
|||||||
@@ -29,9 +29,18 @@ export class PreferencesController {
|
|||||||
closePreferences = (): void => {
|
closePreferences = (): void => {
|
||||||
this._open = false
|
this._open = false
|
||||||
this.currentPane = DEFAULT_PANE
|
this.currentPane = DEFAULT_PANE
|
||||||
|
this.removePreferencesToggleFromURLQueryParameters()
|
||||||
}
|
}
|
||||||
|
|
||||||
get isOpen(): boolean {
|
get isOpen(): boolean {
|
||||||
return this._open
|
return this._open
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private removePreferencesToggleFromURLQueryParameters() {
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||||
|
urlSearchParams.delete('settings')
|
||||||
|
|
||||||
|
const newUrl = `${window.location.origin}${window.location.pathname}${urlSearchParams.toString()}`
|
||||||
|
window.history.replaceState(null, document.title, newUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import { NavigationController } from './Navigation/NavigationController'
|
|||||||
import { FilePreviewModalController } from './FilePreviewModalController'
|
import { FilePreviewModalController } from './FilePreviewModalController'
|
||||||
import { SelectedItemsController } from './SelectedItemsController'
|
import { SelectedItemsController } from './SelectedItemsController'
|
||||||
import { HistoryModalController } from './NoteHistory/HistoryModalController'
|
import { HistoryModalController } from './NoteHistory/HistoryModalController'
|
||||||
|
import { PreferenceId } from '@/Components/Preferences/PreferencesMenu'
|
||||||
|
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
|
||||||
|
|
||||||
export class ViewControllerManager {
|
export class ViewControllerManager {
|
||||||
readonly enableUnfinishedFeatures: boolean = window?.enabledUnfinishedFeatures
|
readonly enableUnfinishedFeatures: boolean = window?.enabledUnfinishedFeatures
|
||||||
@@ -209,11 +211,31 @@ export class ViewControllerManager {
|
|||||||
|
|
||||||
addAppEventObserver() {
|
addAppEventObserver() {
|
||||||
this.unsubAppEventObserver = this.application.addEventObserver(async (eventName) => {
|
this.unsubAppEventObserver = this.application.addEventObserver(async (eventName) => {
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||||
|
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
case ApplicationEvent.Launched:
|
case ApplicationEvent.Launched:
|
||||||
if (window.location.search.includes('purchase=true')) {
|
if (urlSearchParams.get('purchase')) {
|
||||||
this.purchaseFlowController.openPurchaseFlow()
|
this.purchaseFlowController.openPurchaseFlow()
|
||||||
}
|
}
|
||||||
|
if (urlSearchParams.get('settings')) {
|
||||||
|
const user = this.application.getUser()
|
||||||
|
if (user === undefined) {
|
||||||
|
this.accountMenuController.setShow(true)
|
||||||
|
this.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preferencesController.openPreferences()
|
||||||
|
this.preferencesController.setCurrentPane(urlSearchParams.get('settings') as PreferenceId)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case ApplicationEvent.SignedIn:
|
||||||
|
if (urlSearchParams.get('settings')) {
|
||||||
|
this.preferencesController.openPreferences()
|
||||||
|
this.preferencesController.setCurrentPane(urlSearchParams.get('settings') as PreferenceId)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case ApplicationEvent.SyncStatusChanged:
|
case ApplicationEvent.SyncStatusChanged:
|
||||||
this.syncStatusController.update(this.application.sync.getSyncStatus())
|
this.syncStatusController.update(this.application.sync.getSyncStatus())
|
||||||
|
|||||||
Reference in New Issue
Block a user