refactor: replace 'preact' with 'react' (#1048)
This commit is contained in:
@@ -1,54 +1,15 @@
|
||||
import { Icon } from '@/Components/Icon/Icon'
|
||||
import { STRING_E2E_ENABLED, STRING_ENC_NOT_ENABLED, STRING_LOCAL_ENC_ENABLED } from '@/Strings'
|
||||
import { AppState } from '@/UIModels/AppState'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ComponentChild, FunctionComponent } from 'preact'
|
||||
import { PreferencesGroup, PreferencesSegment, Text, Title } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { FunctionComponent } from 'react'
|
||||
import { Title, Text } from '../../PreferencesComponents/Content'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import EncryptionEnabled from './EncryptionEnabled'
|
||||
|
||||
const formatCount = (count: number, itemType: string) => `${count} / ${count} ${itemType}`
|
||||
type Props = { appState: AppState }
|
||||
|
||||
export const EncryptionStatusItem: FunctionComponent<{
|
||||
icon: ComponentChild
|
||||
status: string
|
||||
checkmark?: boolean
|
||||
}> = ({ icon, status, checkmark = true }) => (
|
||||
<div className="w-full rounded py-1.5 px-3 text-input my-1 min-h-8 flex flex-row items-center bg-contrast no-border focus-within:ring-info">
|
||||
{icon}
|
||||
<div className="min-w-3 min-h-1" />
|
||||
<div className="flex-grow color-text text-sm">{status}</div>
|
||||
<div className="min-w-3 min-h-1" />
|
||||
{checkmark && <Icon className="success min-w-4 min-h-4" type="check-bold" />}
|
||||
</div>
|
||||
)
|
||||
|
||||
const EncryptionEnabled: FunctionComponent<{ appState: AppState }> = observer(({ appState }) => {
|
||||
const count = appState.accountMenu.structuredNotesAndTagsCount
|
||||
const notes = formatCount(count.notes, 'notes')
|
||||
const tags = formatCount(count.tags, 'tags')
|
||||
const archived = formatCount(count.archived, 'archived notes')
|
||||
const deleted = formatCount(count.deleted, 'trashed notes')
|
||||
|
||||
const noteIcon = <Icon type="rich-text" className="min-w-5 min-h-5" />
|
||||
const tagIcon = <Icon type="hashtag" className="min-w-5 min-h-5" />
|
||||
const archiveIcon = <Icon type="archive" className="min-w-5 min-h-5" />
|
||||
const trashIcon = <Icon type="trash" className="min-w-5 min-h-5" />
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row items-start pb-1 pt-1.5">
|
||||
<EncryptionStatusItem status={notes} icon={[noteIcon]} />
|
||||
<div className="min-w-3" />
|
||||
<EncryptionStatusItem status={tags} icon={[tagIcon]} />
|
||||
</div>
|
||||
<div className="flex flex-row items-start">
|
||||
<EncryptionStatusItem status={archived} icon={[archiveIcon]} />
|
||||
<div className="min-w-3" />
|
||||
<EncryptionStatusItem status={deleted} icon={[trashIcon]} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
export const Encryption: FunctionComponent<{ appState: AppState }> = observer(({ appState }) => {
|
||||
const Encryption: FunctionComponent<Props> = ({ appState }) => {
|
||||
const app = appState.application
|
||||
const hasUser = app.hasAccount()
|
||||
const hasPasscode = app.hasPasscode()
|
||||
@@ -70,4 +31,6 @@ export const Encryption: FunctionComponent<{ appState: AppState }> = observer(({
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default observer(Encryption)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { AppState } from '@/UIModels/AppState'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent } from 'react'
|
||||
import EncryptionStatusItem from './EncryptionStatusItem'
|
||||
import { formatCount } from './formatCount'
|
||||
|
||||
type Props = {
|
||||
appState: AppState
|
||||
}
|
||||
|
||||
const EncryptionEnabled: FunctionComponent<Props> = ({ appState }) => {
|
||||
const count = appState.accountMenu.structuredNotesAndTagsCount
|
||||
const notes = formatCount(count.notes, 'notes')
|
||||
const tags = formatCount(count.tags, 'tags')
|
||||
const archived = formatCount(count.archived, 'archived notes')
|
||||
const deleted = formatCount(count.deleted, 'trashed notes')
|
||||
|
||||
const noteIcon = <Icon type="rich-text" className="min-w-5 min-h-5" />
|
||||
const tagIcon = <Icon type="hashtag" className="min-w-5 min-h-5" />
|
||||
const archiveIcon = <Icon type="archive" className="min-w-5 min-h-5" />
|
||||
const trashIcon = <Icon type="trash" className="min-w-5 min-h-5" />
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row items-start pb-1 pt-1.5">
|
||||
<EncryptionStatusItem status={notes} icon={noteIcon} />
|
||||
<div className="min-w-3" />
|
||||
<EncryptionStatusItem status={tags} icon={tagIcon} />
|
||||
</div>
|
||||
<div className="flex flex-row items-start">
|
||||
<EncryptionStatusItem status={archived} icon={archiveIcon} />
|
||||
<div className="min-w-3" />
|
||||
<EncryptionStatusItem status={deleted} icon={trashIcon} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(EncryptionEnabled)
|
||||
@@ -0,0 +1,20 @@
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { FunctionComponent, ReactNode } from 'react'
|
||||
|
||||
type Props = {
|
||||
icon: ReactNode
|
||||
status: string
|
||||
checkmark?: boolean
|
||||
}
|
||||
|
||||
const EncryptionStatusItem: FunctionComponent<Props> = ({ icon, status, checkmark = true }) => (
|
||||
<div className="w-full rounded py-1.5 px-3 text-input my-1 min-h-8 flex flex-row items-center bg-contrast no-border focus-within:ring-info">
|
||||
{icon}
|
||||
<div className="min-w-3 min-h-1" />
|
||||
<div className="flex-grow color-text text-sm">{status}</div>
|
||||
<div className="min-w-3 min-h-1" />
|
||||
{checkmark && <Icon className="success min-w-4 min-h-4" type="check-bold" />}
|
||||
</div>
|
||||
)
|
||||
|
||||
export default EncryptionStatusItem
|
||||
@@ -1,26 +1,21 @@
|
||||
import { AppState } from '@/UIModels/AppState'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent } from 'preact'
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Text,
|
||||
Title,
|
||||
Subtitle,
|
||||
} from '@/Components/Preferences/PreferencesComponents'
|
||||
import { Fragment, FunctionComponent, useState } from 'react'
|
||||
import { Text, Title, Subtitle } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import {
|
||||
ButtonType,
|
||||
ClientDisplayableError,
|
||||
DisplayStringForContentType,
|
||||
EncryptedItemInterface,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Button } from '@/Components/Button/Button'
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { useState } from 'preact/hooks'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
|
||||
type Props = { appState: AppState }
|
||||
|
||||
export const ErroredItems: FunctionComponent<Props> = observer(({ appState }: Props) => {
|
||||
const ErroredItems: FunctionComponent<Props> = ({ appState }: Props) => {
|
||||
const app = appState.application
|
||||
|
||||
const [erroredItems, setErroredItems] = useState(app.items.invalidItems)
|
||||
@@ -96,7 +91,7 @@ export const ErroredItems: FunctionComponent<Props> = observer(({ appState }: Pr
|
||||
|
||||
{erroredItems.map((item, index) => {
|
||||
return (
|
||||
<>
|
||||
<Fragment key={item.uuid}>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>{`${getContentTypeDisplay(item)} created on ${item.createdAtString}`}</Subtitle>
|
||||
@@ -134,10 +129,12 @@ export const ErroredItems: FunctionComponent<Props> = observer(({ appState }: Pr
|
||||
</div>
|
||||
</div>
|
||||
{index < erroredItems.length - 1 && <HorizontalSeparator classes="mt-5 mb-3" />}
|
||||
</>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default observer(ErroredItems)
|
||||
|
||||
@@ -10,23 +10,22 @@ import {
|
||||
} from '@/Strings'
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { preventRefreshing } from '@/Utils'
|
||||
import { JSXInternal } from 'preact/src/jsx'
|
||||
import TargetedEvent = JSXInternal.TargetedEvent
|
||||
import TargetedMouseEvent = JSXInternal.TargetedMouseEvent
|
||||
import { alertDialog } from '@/Services/AlertService'
|
||||
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
|
||||
import { ChangeEventHandler, FormEvent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { ApplicationEvent } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { AppState } from '@/UIModels/AppState'
|
||||
import { PreferencesSegment, Title, Text, PreferencesGroup } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { Button } from '@/Components/Button/Button'
|
||||
import { Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
appState: AppState
|
||||
}
|
||||
|
||||
export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
const PasscodeLock = ({ application, appState }: Props) => {
|
||||
const keyStorageInfo = StringUtils.keyStorageInfo(application)
|
||||
const passcodeAutoLockOptions = application.getAutolockService().getAutoLockIntervalOptions()
|
||||
|
||||
@@ -34,8 +33,8 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
|
||||
const passcodeInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const [passcode, setPasscode] = useState<string | undefined>(undefined)
|
||||
const [passcodeConfirmation, setPasscodeConfirmation] = useState<string | undefined>(undefined)
|
||||
const [passcode, setPasscode] = useState<string>()
|
||||
const [passcodeConfirmation, setPasscodeConfirmation] = useState<string>()
|
||||
const [selectedAutoLockInterval, setSelectedAutoLockInterval] = useState<unknown>(null)
|
||||
const [isPasscodeFocused, setIsPasscodeFocused] = useState(false)
|
||||
const [showPasscodeForm, setShowPasscodeForm] = useState(false)
|
||||
@@ -93,17 +92,17 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
})
|
||||
}
|
||||
|
||||
const handlePasscodeChange = (event: TargetedEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target as HTMLInputElement
|
||||
const handlePasscodeChange: ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||
const { value } = event.target
|
||||
setPasscode(value)
|
||||
}
|
||||
|
||||
const handleConfirmPasscodeChange = (event: TargetedEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target as HTMLInputElement
|
||||
const handleConfirmPasscodeChange: ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||
const { value } = event.target
|
||||
setPasscodeConfirmation(value)
|
||||
}
|
||||
|
||||
const submitPasscodeForm = async (event: TargetedEvent<HTMLFormElement> | TargetedMouseEvent<HTMLButtonElement>) => {
|
||||
const submitPasscodeForm = async (event: MouseEvent | FormEvent) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (!passcode || passcode.length === 0) {
|
||||
@@ -167,6 +166,12 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
}
|
||||
}, [application])
|
||||
|
||||
const cancelPasscodeForm = () => {
|
||||
setShowPasscodeForm(false)
|
||||
setPasscode(undefined)
|
||||
setPasscodeConfirmation(undefined)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
@@ -197,20 +202,20 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
className="sk-input contrast"
|
||||
type="password"
|
||||
ref={passcodeInputRef}
|
||||
value={passcode}
|
||||
value={passcode ? passcode : ''}
|
||||
onChange={handlePasscodeChange}
|
||||
placeholder="Passcode"
|
||||
/>
|
||||
<input
|
||||
className="sk-input contrast"
|
||||
type="password"
|
||||
value={passcodeConfirmation}
|
||||
value={passcodeConfirmation ? passcodeConfirmation : ''}
|
||||
onChange={handleConfirmPasscodeChange}
|
||||
placeholder="Confirm Passcode"
|
||||
/>
|
||||
<div className="min-h-2" />
|
||||
<Button variant="primary" onClick={submitPasscodeForm} label="Set Passcode" className="mr-3" />
|
||||
<Button variant="normal" onClick={() => setShowPasscodeForm(false)} label="Cancel" />
|
||||
<Button variant="normal" onClick={cancelPasscodeForm} label="Cancel" />
|
||||
</form>
|
||||
)}
|
||||
|
||||
@@ -237,6 +242,7 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
{passcodeAutoLockOptions.map((option) => {
|
||||
return (
|
||||
<a
|
||||
key={option.value}
|
||||
className={`sk-a info mr-3 ${option.value === selectedAutoLockInterval ? 'boxed' : ''}`}
|
||||
onClick={() => selectAutoLockInterval(option.value)}
|
||||
>
|
||||
@@ -251,4 +257,6 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
|
||||
)}
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default observer(PasscodeLock)
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { Switch } from '@/Components/Switch/Switch'
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Subtitle,
|
||||
Text,
|
||||
Title,
|
||||
} from '@/Components/Preferences/PreferencesComponents'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { MuteSignInEmailsOption, LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionalComponent } from 'preact'
|
||||
import { useCallback, useEffect, useState } from 'preact/hooks'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Strings'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
export const Privacy: FunctionalComponent<Props> = observer(({ application }: Props) => {
|
||||
const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState<MuteSignInEmailsOption>(
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
)
|
||||
const [sessionUaLoggingValue, setSessionUaLoggingValue] = useState<LogSessionUserAgentOption>(
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
@@ -110,7 +105,7 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className={'sk-spinner info small'} />
|
||||
<div className={'sk-spinner info small flex-shrink-0 ml-2'} />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
@@ -118,7 +113,7 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="mt-5 mb-3" />
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Session user agent logging</Subtitle>
|
||||
@@ -129,7 +124,7 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className={'sk-spinner info small'} />
|
||||
<div className={'sk-spinner info small flex-shrink-0 ml-2'} />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleSessionLogging}
|
||||
@@ -141,4 +136,6 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default observer(Privacy)
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { FunctionalComponent } from 'preact'
|
||||
import { useCallback, useState, useEffect } from 'preact/hooks'
|
||||
import { FunctionComponent, useCallback, useState, useEffect } from 'react'
|
||||
import { ApplicationEvent } from '@standardnotes/snjs'
|
||||
import { isSameDay } from '@/Utils'
|
||||
import { PreferencesGroup, PreferencesSegment, Title, Text } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { Button } from '@/Components/Button/Button'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import { Title, Text } from '../../PreferencesComponents/Content'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
export const Protections: FunctionalComponent<Props> = ({ application }) => {
|
||||
const Protections: FunctionComponent<Props> = ({ application }) => {
|
||||
const enableProtections = () => {
|
||||
application.clearProtectionSession().catch(console.error)
|
||||
}
|
||||
@@ -88,3 +89,5 @@ export const Protections: FunctionalComponent<Props> = ({ application }) => {
|
||||
</PreferencesGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export default Protections
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { AppState } from '@/UIModels/AppState'
|
||||
import { FunctionComponent } from 'preact'
|
||||
import { PreferencesPane } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { TwoFactorAuthWrapper } from '../TwoFactorAuth/TwoFactorAuthWrapper'
|
||||
import { FunctionComponent } from 'react'
|
||||
import TwoFactorAuthWrapper from '../TwoFactorAuth/TwoFactorAuthWrapper'
|
||||
import { MfaProps } from '../TwoFactorAuth/MfaProps'
|
||||
import { Encryption } from './Encryption'
|
||||
import { PasscodeLock } from './PasscodeLock'
|
||||
import { Privacy } from './Privacy'
|
||||
import { Protections } from './Protections'
|
||||
import { ErroredItems } from './ErroredItems'
|
||||
import Encryption from './Encryption'
|
||||
import PasscodeLock from './PasscodeLock'
|
||||
import Privacy from './Privacy'
|
||||
import Protections from './Protections'
|
||||
import ErroredItems from './ErroredItems'
|
||||
import PreferencesPane from '@/Components/Preferences/PreferencesComponents/PreferencesPane'
|
||||
|
||||
interface SecurityProps extends MfaProps {
|
||||
appState: AppState
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
export const securityPrefsHasBubble = (application: WebApplication): boolean => {
|
||||
return application.items.invalidItems.length > 0
|
||||
}
|
||||
|
||||
export const Security: FunctionComponent<SecurityProps> = (props) => (
|
||||
const Security: FunctionComponent<SecurityProps> = (props) => (
|
||||
<PreferencesPane>
|
||||
<Encryption appState={props.appState} />
|
||||
{props.application.items.invalidItems.length > 0 && <ErroredItems appState={props.appState} />}
|
||||
@@ -29,3 +25,5 @@ export const Security: FunctionComponent<SecurityProps> = (props) => (
|
||||
{props.application.getUser() && <Privacy application={props.application} />}
|
||||
</PreferencesPane>
|
||||
)
|
||||
|
||||
export default Security
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const formatCount = (count: number, itemType: string) => `${count} / ${count} ${itemType}`
|
||||
@@ -0,0 +1,5 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
|
||||
export const securityPrefsHasBubble = (application: WebApplication): boolean => {
|
||||
return application.items.invalidItems.length > 0
|
||||
}
|
||||
Reference in New Issue
Block a user