Files
oxygen-ui/src/pages/sign_/Forget.tsx
2024-01-05 11:03:51 +08:00

274 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useCallback } from 'react'
import Icon from '@ant-design/icons'
import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile'
import {
H_CAPTCHA_SITE_KEY,
PERMISSION_FORGET_SUCCESS,
PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED,
PERMISSION_RETRIEVE_SUCCESS,
PERMISSION_USER_NOT_FOUND,
SYSTEM_INVALID_CAPTCHA_CODE
} from '@/constants/common.constants'
import { useUpdatedEffect } from '@/util/hooks'
import { r_auth_forget, r_auth_retrieve } from '@/services/auth'
import FitCenter from '@/components/common/FitCenter'
import FlexBox from '@/components/common/FlexBox'
const Forget: React.FC = () => {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const turnstileRef = useRef<TurnstileInstance>()
const turnstileRefCallback = useCallback(
(node: TurnstileInstance) => {
turnstileRef.current = node
if (location.pathname === '/forget' && !searchParams.get('code')) {
turnstileRef.current?.execute()
}
},
[location.pathname, searchParams]
)
const retrieveTurnstileRef = useRef<TurnstileInstance>()
const retrieveTurnstileRefCallback = useCallback(
(node: TurnstileInstance) => {
retrieveTurnstileRef.current = node
if (location.pathname === '/forget' && searchParams.get('code')) {
retrieveTurnstileRef.current?.execute()
}
},
[location.pathname, searchParams]
)
const [isSending, setIsSending] = useState(false)
const [isSent, setIsSent] = useState(false)
const [isChanging, setIsChanging] = useState(false)
const [isChanged, setIsChanged] = useState(false)
const [captchaCode, setCaptchaCode] = useState('')
const [retrieveCaptchaCode, setRetrieveCaptchaCode] = useState('')
useUpdatedEffect(() => {
if (!isSending) {
setCaptchaCode('')
turnstileRef.current?.reset()
turnstileRef.current?.execute()
}
}, [isSending])
useUpdatedEffect(() => {
if (!isChanging) {
setRetrieveCaptchaCode('')
retrieveTurnstileRef.current?.reset()
retrieveTurnstileRef.current?.execute()
}
}, [isChanging])
const handleOnSend = (forgetParam: ForgetParam) => {
if (isSending) {
return
}
setIsSending(true)
if (!captchaCode) {
void message.warning('请先通过验证')
setIsSending(false)
return
}
void r_auth_forget({ email: forgetParam.email, captchaCode })
.then((res) => {
const response = res.data
switch (response.code) {
case PERMISSION_FORGET_SUCCESS:
void message.success('已发送验证邮件,请查收')
setIsSent(true)
break
case PERMISSION_USER_NOT_FOUND:
void message.error('用户不存在')
break
case SYSTEM_INVALID_CAPTCHA_CODE:
void message.error('验证码有误,请重试')
break
default:
void message.error('出错了,请稍后重试')
}
})
.finally(() => {
setIsSending(false)
})
}
const handleOnRetry = () => {
setIsSent(false)
}
const handleOnChange = (retrieveParam: RetrieveParam) => {
if (isChanging) {
return
}
setIsChanging(true)
void r_auth_retrieve({
code: searchParams.get('code') ?? '',
password: retrieveParam.password,
captchaCode: retrieveCaptchaCode
})
.then((res) => {
const response = res.data
switch (response.code) {
case PERMISSION_RETRIEVE_SUCCESS:
void message.success('密码已更新')
setIsChanged(true)
break
case PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED:
void message.error('请重新获取邮件')
break
case SYSTEM_INVALID_CAPTCHA_CODE:
void message.error('验证码有误,请重试')
break
default:
void message.error('出错了,请稍后重试')
}
})
.finally(() => {
setIsChanging(false)
})
}
return (
<div className={'forget'}>
<FitCenter>
<FlexBox>
<div className={'title'}>
<div className={'primary'}></div>
<div className={'secondary'}>Retrieve password</div>
</div>
<div className={'form'}>
{!searchParams.get('code') ? (
!isSent ? (
<>
<AntdForm autoComplete={'on'} onFinish={handleOnSend}>
<AntdForm.Item
name={'email'}
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '不是有效的邮箱地址' }
]}
>
<AntdInput
prefix={<Icon component={IconOxygenEmail} />}
placeholder={'邮箱'}
disabled={isSending}
/>
</AntdForm.Item>
<AntdForm.Item>
<Turnstile
id={'forget-turnstile'}
ref={turnstileRefCallback}
siteKey={H_CAPTCHA_SITE_KEY}
options={{ theme: 'light', execution: 'execute' }}
onSuccess={setCaptchaCode}
/>
</AntdForm.Item>
<AntdForm.Item>
<AntdButton
style={{ width: '100%' }}
type={'primary'}
htmlType={'submit'}
disabled={isSending}
loading={isSending}
>
&ensp;&ensp;&ensp;&ensp;
</AntdButton>
</AntdForm.Item>
</AntdForm>
</>
) : (
<div className={'retry'}>
<a onClick={handleOnRetry}></a>
</div>
)
) : !isChanged ? (
<>
<AntdForm autoComplete={'on'} onFinish={handleOnChange}>
<AntdForm.Item
name={'password'}
rules={[
{ required: true, message: '请输入密码' },
{ min: 10, message: '密码至少为10位' },
{ max: 30, message: '密码最多为30位' }
]}
>
<AntdInput.Password
addonBefore={
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
}
placeholder={'密码'}
disabled={isChanging}
/>
</AntdForm.Item>
<AntdForm.Item
name={'passwordConfirm'}
rules={[
{ required: true, message: '请确认密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (
!value ||
getFieldValue('password') === value
) {
return Promise.resolve()
}
return Promise.reject(
new Error('两次密码输入必须一致')
)
}
})
]}
>
<AntdInput.Password
addonBefore={'确认密码'}
placeholder={'确认密码'}
disabled={isChanging}
/>
</AntdForm.Item>
<AntdForm.Item>
<Turnstile
id={'retrieve-turnstile'}
ref={retrieveTurnstileRefCallback}
siteKey={H_CAPTCHA_SITE_KEY}
options={{ theme: 'light', execution: 'execute' }}
onSuccess={setRetrieveCaptchaCode}
/>
</AntdForm.Item>
<AntdForm.Item>
<AntdButton
style={{ width: '100%' }}
type={'primary'}
htmlType={'submit'}
disabled={isChanging}
loading={isChanging}
>
&ensp;&ensp;&ensp;&ensp;
</AntdButton>
</AntdForm.Item>
</AntdForm>
</>
) : (
<div className={'success'}></div>
)}
<div className={'footer'}>
<a onClick={() => navigate(`/login`, { replace: true })}></a>
</div>
</div>
</FlexBox>
</FitCenter>
</div>
)
}
export default Forget