Files
oxygen-ui/src/pages/Sign.tsx
2023-12-21 18:36:31 +08:00

348 lines
14 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, { useState } from 'react'
import '@/assets/css/pages/sign.scss'
import FitFullscreen from '@/components/common/FitFullscreen'
import FitCenter from '@/components/common/FitCenter'
import FlexBox from '@/components/common/FlexBox'
import { useNavigate } from 'react-router'
import Icon from '@ant-design/icons'
import { getUserInfo, login, setToken } from '@/util/auth.tsx'
import {
PERMISSION_LOGIN_SUCCESS,
PERMISSION_LOGIN_USERNAME_PASSWORD_ERROR,
PERMISSION_USER_DISABLE,
PERMISSION_USERNAME_NOT_FOUND
} from '@/constants/common.constants.ts'
import { AppContext } from '@/App.tsx'
import { utcToLocalTime } from '@/util/datetime.tsx'
import { useUpdatedEffect } from '@/util/hooks.tsx'
const SignUp: React.FC = () => {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
return (
<div className={'sign-up'}>
<FitCenter>
<FlexBox>
<div>Welcome join us</div>
<AntdButton
onClick={() =>
navigate(
`/login${
searchParams.toString() ? `?${searchParams.toString()}` : ''
}`
)
}
>
</AntdButton>
<AntdForm>
<AntdForm.Item></AntdForm.Item>
</AntdForm>
</FlexBox>
</FitCenter>
</div>
)
}
const Forget: React.FC = () => {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const [isLoading, setIsLoading] = useState(false)
const [isFinish, setIsFinish] = useState(false)
const handleOnFinish = () => {
setIsFinish(true)
}
const handleOnRetry = () => {
setIsFinish(false)
}
return (
<div className={'forget'}>
<FitCenter>
<FlexBox>
<div className={'title'}>
<div className={'primary'}></div>
<div className={'secondary'}>Retrieve password</div>
</div>
<AntdForm autoComplete={'on'} onFinish={handleOnFinish} className={'form'}>
{!isFinish ? (
<>
<AntdForm.Item
name={'account'}
rules={[{ required: true, message: '请输入邮箱' }]}
>
<AntdInput
prefix={<Icon component={IconFatwebEmail} />}
placeholder={'邮箱'}
disabled={isLoading}
/>
</AntdForm.Item>
<AntdForm.Item>
<AntdButton
style={{ width: '100%' }}
type={'primary'}
htmlType={'submit'}
disabled={isLoading}
loading={isLoading}
>
&ensp;&ensp;&ensp;&ensp;
</AntdButton>
</AntdForm.Item>
</>
) : (
<div style={{ marginBottom: 10 }}>
<a onClick={handleOnRetry}></a>
</div>
)}
<div className={'footer'}>
<a
onClick={() =>
navigate(
`/login${
searchParams.toString()
? `?${searchParams.toString()}`
: ''
}`
)
}
>
</a>
</div>
</AntdForm>
</FlexBox>
</FitCenter>
</div>
)
}
const SignIn: React.FC = () => {
const { refreshRouter } = useContext(AppContext)
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const [isSigningIn, setIsSigningIn] = useState(false)
const handleOnFinish = (loginForm: LoginForm) => {
if (isSigningIn) {
return
}
setIsSigningIn(true)
void login(loginForm.account, loginForm.password)
.then((res) => {
const response = res.data
const { code, data } = response
switch (code) {
case PERMISSION_LOGIN_SUCCESS:
setToken(data?.token ?? '')
void message.success('登录成功')
setTimeout(() => {
void getUserInfo().then((user) => {
refreshRouter()
if (searchParams.has('redirect')) {
navigate(searchParams.get('redirect') ?? '/')
} else {
navigate('/')
}
notification.success({
message: '欢迎回来',
description: (
<>
<span>
<strong>{user.userInfo.nickname}</strong>
</span>
<br />
<span>
{user.lastLoginTime
? `${utcToLocalTime(user.lastLoginTime)}${
user.lastLoginIp
}`
: '无'}
</span>
</>
),
placement: 'topRight'
})
})
}, 1500)
break
case PERMISSION_USERNAME_NOT_FOUND:
case PERMISSION_LOGIN_USERNAME_PASSWORD_ERROR:
void message.error(
<>
<strong></strong><strong></strong>
</>
)
setIsSigningIn(false)
break
case PERMISSION_USER_DISABLE:
void message.error(
<>
<strong></strong>
</>
)
setIsSigningIn(false)
break
default:
void message.error(
<>
<strong></strong>
</>
)
setIsSigningIn(false)
}
})
.catch(() => {
setIsSigningIn(false)
})
}
return (
<div className={'sign-in'}>
<FitCenter>
<FlexBox>
<div className={'title'}>
<div className={'primary'}></div>
<div className={'secondary'}>Welcome back</div>
</div>
<AntdForm autoComplete={'on'} onFinish={handleOnFinish} className={'form'}>
<AntdForm.Item
name={'account'}
rules={[{ required: true, message: '账号为空' }]}
>
<AntdInput
prefix={<Icon component={IconFatwebUser} />}
placeholder={'邮箱/用户名'}
disabled={isSigningIn}
/>
</AntdForm.Item>
<AntdForm.Item
name={'password'}
rules={[{ required: true, message: '密码为空' }]}
>
<AntdInput.Password
prefix={<Icon component={IconFatwebPassword} />}
placeholder={'密码'}
disabled={isSigningIn}
/>
</AntdForm.Item>
<FlexBox direction={'horizontal'} className={'addition'}>
<AntdCheckbox disabled={isSigningIn}></AntdCheckbox>
<a
onClick={() => {
navigate(
`/forget${
searchParams.toString()
? `?${searchParams.toString()}`
: ''
}`
)
}}
>
</a>
</FlexBox>
<AntdForm.Item>
<AntdButton
style={{ width: '100%' }}
type={'primary'}
htmlType={'submit'}
disabled={isSigningIn}
loading={isSigningIn}
>
&ensp;&ensp;&ensp;&ensp;
</AntdButton>
</AntdForm.Item>
<div className={'footer'}>
<a
onClick={() =>
navigate(
`/register${
searchParams.toString()
? `?${searchParams.toString()}`
: ''
}`
)
}
>
</a>
</div>
</AntdForm>
</FlexBox>
</FitCenter>
</div>
)
}
const Sign: React.FC = () => {
const lastPage = useRef('none')
const currentPage = useRef('none')
const match = useMatches().reduce((_, second) => second)
const [isSwitch, setIsSwitch] = useState(false)
const leftPage = ['register', 'forget']
useUpdatedEffect(() => {
lastPage.current = currentPage.current
currentPage.current = match.id
setIsSwitch(leftPage.includes(currentPage.current))
}, [match.id])
const leftComponent = () => {
switch (leftPage.includes(currentPage.current) ? currentPage.current : lastPage.current) {
case 'forget':
return <Forget />
default:
return <SignUp />
}
}
const rightComponent = () => {
switch (leftPage.includes(currentPage.current) ? lastPage.current : currentPage.current) {
default:
return <SignIn />
}
}
return (
<>
<FitFullscreen data-component={'sign'}>
<FitCenter>
<FlexBox
direction={'horizontal'}
className={`sign-box${isSwitch ? ' switch' : ''}`}
>
<div className={`left${!isSwitch ? ' hidden' : ''}`}>{leftComponent()}</div>
<div className={`right${isSwitch ? ' hidden' : ''}`}>
{rightComponent()}
</div>
<FlexBox className={'cover'}>
<div className={'ball-box'}>
<div className={'ball'} />
</div>
<div className={'ball-box'}>
<div className={'mask'}>
<div className={'ball'} />
</div>
</div>
</FlexBox>
</FlexBox>
</FitCenter>
</FitFullscreen>
</>
)
}
export default Sign