-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support lock window for Neuron (#3064)
Co-authored-by: Chen Yu <keithwhisper@gmail.com>
- Loading branch information
Showing
38 changed files
with
903 additions
and
17 deletions.
There are no files selected for viewing
113 changes: 113 additions & 0 deletions
113
packages/neuron-ui/src/components/GeneralSetting/LockWindowDialog/hooks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { TFunction } from 'i18next' | ||
import { useCallback, useState } from 'react' | ||
import { verifyLockWindowPassword } from 'services/remote' | ||
import { updateLockWindowInfo, useDispatch } from 'states' | ||
import { isSuccessResponse } from 'utils' | ||
|
||
export const passwordLength = 4 | ||
|
||
export const useOldPassword = ({ t }: { t: TFunction }) => { | ||
const [oldPasswordErr, setOldPasswordErr] = useState('') | ||
const [oldPassword, setOldPassword] = useState(new Array(passwordLength).fill('')) | ||
const [verifySuccess, setVerifySuccess] = useState(false) | ||
const onUpdateOldPassword = useCallback( | ||
(v: string, idx: number) => { | ||
const updatedOldPassword = oldPassword.toSpliced(idx, 1, v).join('') | ||
if (updatedOldPassword.length === passwordLength) { | ||
verifyLockWindowPassword(updatedOldPassword) | ||
.then(res => { | ||
if (isSuccessResponse(res)) { | ||
// verify success | ||
setVerifySuccess(true) | ||
} | ||
throw new Error('verify failed') | ||
}) | ||
.catch(() => { | ||
setOldPassword(new Array(passwordLength).fill('')) | ||
setOldPasswordErr(t('settings.general.lock-window.password-error')) | ||
}) | ||
} else { | ||
setOldPassword(value => value.toSpliced(idx, 1, v)) | ||
} | ||
}, | ||
[oldPassword] | ||
) | ||
const resetOldPassword = useCallback(() => { | ||
setOldPasswordErr('') | ||
setOldPassword(new Array(passwordLength).fill('')) | ||
setVerifySuccess(false) | ||
}, []) | ||
return { | ||
oldPasswordErr, | ||
oldPassword, | ||
onUpdateOldPassword, | ||
verifySuccess, | ||
setVerifySuccess, | ||
resetOldPassword, | ||
} | ||
} | ||
|
||
export const usePassword = () => { | ||
const [password, setPassword] = useState(new Array(passwordLength).fill('')) | ||
const onUpdatePassword = useCallback((v: string, idx: number) => { | ||
setPassword(value => value.toSpliced(idx, 1, v)) | ||
}, []) | ||
const resetPassword = useCallback(() => { | ||
setPassword(new Array(passwordLength).fill('')) | ||
}, []) | ||
return { | ||
password, | ||
onUpdatePassword, | ||
resetPassword, | ||
} | ||
} | ||
|
||
export const useRepeatPassword = ({ | ||
password, | ||
t, | ||
encryptedPassword, | ||
onCancel, | ||
}: { | ||
password: string | ||
t: TFunction | ||
encryptedPassword?: string | ||
onCancel: () => void | ||
}) => { | ||
const dispatch = useDispatch() | ||
const [errMsg, setErrMsg] = useState('') | ||
const [repeatPassword, setRepeatPassword] = useState(new Array(passwordLength).fill('')) | ||
const [isSuccess, setIsSuccess] = useState(false) | ||
const onUpdateRepeatPassword = useCallback( | ||
(v: string, idx: number) => { | ||
const updatedRepeatPassword = repeatPassword.toSpliced(idx, 1, v).join('') | ||
if (updatedRepeatPassword.length === passwordLength) { | ||
if (updatedRepeatPassword !== password) { | ||
setErrMsg(t('settings.general.lock-window.different-password')) | ||
setRepeatPassword(new Array(passwordLength).fill('')) | ||
} else { | ||
setIsSuccess(true) | ||
updateLockWindowInfo( | ||
encryptedPassword ? { password: updatedRepeatPassword } : { password: updatedRepeatPassword, locked: true } | ||
)(dispatch) | ||
onCancel() | ||
} | ||
} else { | ||
setErrMsg('') | ||
setRepeatPassword(value => value.toSpliced(idx, 1, v)) | ||
} | ||
}, | ||
[password, t, repeatPassword] | ||
) | ||
const resetRepeatPassword = useCallback(() => { | ||
setErrMsg('') | ||
setRepeatPassword(new Array(passwordLength).fill('')) | ||
setIsSuccess(false) | ||
}, []) | ||
return { | ||
errMsg, | ||
repeatPassword, | ||
onUpdateRepeatPassword, | ||
resetRepeatPassword, | ||
isSuccess, | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
packages/neuron-ui/src/components/GeneralSetting/LockWindowDialog/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import React, { useCallback, useEffect, useMemo } from 'react' | ||
import { useTranslation } from 'react-i18next' | ||
import Dialog from 'widgets/Dialog' | ||
import SplitPasswordInput from 'widgets/SplitPasswordInput' | ||
import Alert from 'widgets/Alert' | ||
import Button from 'widgets/Button' | ||
import { passwordLength, useOldPassword, usePassword, useRepeatPassword } from './hooks' | ||
import styles from './lockWindowDialog.module.scss' | ||
|
||
const LockWindowDialog = ({ | ||
show, | ||
onCancel, | ||
encryptedPassword, | ||
}: { | ||
show: boolean | ||
onCancel: () => void | ||
encryptedPassword?: string | ||
}) => { | ||
const [t] = useTranslation() | ||
const { oldPasswordErr, verifySuccess, oldPassword, onUpdateOldPassword, resetOldPassword } = useOldPassword({ t }) | ||
const { password, onUpdatePassword, resetPassword } = usePassword() | ||
const joinedPassword = useMemo(() => password.join(''), [password]) | ||
const { errMsg, repeatPassword, onUpdateRepeatPassword, resetRepeatPassword, isSuccess } = useRepeatPassword({ | ||
t, | ||
password: joinedPassword, | ||
encryptedPassword, | ||
onCancel, | ||
}) | ||
useEffect(() => { | ||
// when dialog open, reset all status | ||
if (show) { | ||
resetOldPassword() | ||
resetPassword() | ||
resetRepeatPassword() | ||
} | ||
}, [show, resetOldPassword, resetPassword, resetRepeatPassword]) | ||
const onReset = useCallback(() => { | ||
resetPassword() | ||
resetRepeatPassword() | ||
}, [resetPassword, resetRepeatPassword]) | ||
const content = () => { | ||
if (encryptedPassword && !verifySuccess) { | ||
// is verify old password | ||
return ( | ||
<> | ||
<span className={styles.secTitle}>{t('settings.general.lock-window.enter-current-password')}</span> | ||
<div className={styles.password}> | ||
<SplitPasswordInput values={oldPassword} onChange={onUpdateOldPassword} /> | ||
<div className={styles.err}>{oldPasswordErr}</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
if (joinedPassword.length !== passwordLength) { | ||
// enter password | ||
return ( | ||
<> | ||
<span className={styles.secTitle}>{t(`settings.general.lock-window.set-password`)}</span> | ||
<div className={styles.password}> | ||
<SplitPasswordInput values={password} onChange={onUpdatePassword} /> | ||
</div> | ||
</> | ||
) | ||
} | ||
// is verify repeat password | ||
return ( | ||
<> | ||
<span className={styles.secTitle}>{t(`settings.general.lock-window.confirm-password`)}</span> | ||
<div className={styles.password}> | ||
<SplitPasswordInput values={repeatPassword} onChange={onUpdateRepeatPassword} /> | ||
<div className={styles.err}>{errMsg}</div> | ||
{errMsg ? ( | ||
<Button type="primary" onClick={onReset}> | ||
{t('settings.general.lock-window.reset')} | ||
</Button> | ||
) : null} | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
return ( | ||
<> | ||
<Dialog | ||
show={show} | ||
title={t(`settings.general.${encryptedPassword ? 'change-lock-password' : 'set-lock-password'}`)} | ||
onCancel={onCancel} | ||
showFooter={false} | ||
className={styles.dialog} | ||
> | ||
<div className={styles.content}>{content()}</div> | ||
</Dialog> | ||
{isSuccess ? ( | ||
<Alert status="success" className={styles.notice}> | ||
{t(`settings.general.lock-window.${encryptedPassword ? 'change-password-success' : 'set-password-success'}`)} | ||
</Alert> | ||
) : null} | ||
</> | ||
) | ||
} | ||
|
||
LockWindowDialog.displayName = 'LockWindowDialog' | ||
export default LockWindowDialog |
30 changes: 30 additions & 0 deletions
30
...ges/neuron-ui/src/components/GeneralSetting/LockWindowDialog/lockWindowDialog.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
@import '../../../styles/mixin.scss'; | ||
|
||
.content { | ||
text-align: center; | ||
|
||
.secTitle { | ||
color: var(--secondary-text-color); | ||
font-size: 14px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: normal; | ||
} | ||
|
||
.password { | ||
margin-top: 24px; | ||
} | ||
|
||
.err { | ||
color: var(--error-color); | ||
margin: 16px 0 24px 0; | ||
} | ||
} | ||
|
||
.dialog { | ||
width: 680px; | ||
} | ||
|
||
.notice { | ||
@include dialog-copy-animation; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
128e425
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Packaging for test is done in 8874779385
128e425
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Packaging for test is done in 8874779638