diff --git a/shared/index.tsx b/shared/index.tsx index bf3340db..fd81542e 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -109,6 +109,7 @@ export { loginWithEmail, loginWithToken, registerWithEmail, + createTemporaryUser, searchUserWithUniqueName, checkTokenValid, modifyUserField, diff --git a/shared/model/user.ts b/shared/model/user.ts index 47dd1710..6b14f9df 100644 --- a/shared/model/user.ts +++ b/shared/model/user.ts @@ -68,6 +68,20 @@ export async function registerWithEmail( return data; } +/** + * 创建访客账号 + * @param nickname 访客昵称 + */ +export async function createTemporaryUser( + nickname: string +): Promise { + const { data } = await request.post('/api/user/createTemporaryUser', { + nickname, + }); + + return data; +} + /** * 使用唯一标识名搜索用户 * @param uniqueName 唯一标识用户昵称: 用户昵称#0000 diff --git a/web/src/routes/Entry/GuestView.tsx b/web/src/routes/Entry/GuestView.tsx new file mode 100644 index 00000000..07f14c5c --- /dev/null +++ b/web/src/routes/Entry/GuestView.tsx @@ -0,0 +1,75 @@ +import { Spinner } from '@/components/Spinner'; +import { useSearchParam } from '@/hooks/useSearchParam'; +import { setUserJWT } from '@/utils/jwt-helper'; +import { setGlobalUserLoginInfo } from '@/utils/user-helper'; +import { Icon } from '@iconify/react'; +import React, { useState } from 'react'; +import { useHistory } from 'react-router'; +import { + createTemporaryUser, + isValidStr, + t, + useAsyncRequest, +} from 'tailchat-shared'; +import { string } from 'yup'; +import { useNavToView } from './utils'; + +export const GuestView: React.FC = React.memo(() => { + const history = useHistory(); + const navToView = useNavToView(); + const navRedirect = useSearchParam('redirect'); + const [nickname, setNickname] = useState(''); + + const [{ loading }, handleCreateTemporaryUser] = useAsyncRequest(async () => { + await string().required(t('昵称不能为空')).validate(nickname); + + const data = await createTemporaryUser(nickname); + + setGlobalUserLoginInfo(data); + await setUserJWT(data.token); + + if (isValidStr(navRedirect)) { + history.push(decodeURIComponent(navRedirect)); + } else { + history.push('/main'); + } + }, [nickname, history, navRedirect]); + + return ( +
+
{t('创建访客')}
+ +
+
+
{t('昵称')}
+ setNickname(e.target.value)} + /> +
+ + + + +
+
+ ); +}); +GuestView.displayName = 'GuestView'; diff --git a/web/src/routes/Entry/LoginView.tsx b/web/src/routes/Entry/LoginView.tsx index 7b4a415e..7096c619 100644 --- a/web/src/routes/Entry/LoginView.tsx +++ b/web/src/routes/Entry/LoginView.tsx @@ -1,13 +1,15 @@ import { Icon } from '@iconify/react'; import { Divider } from 'antd'; import { isValidStr, loginWithEmail, t, useAsyncFn } from 'tailchat-shared'; -import React, { useCallback, useState } from 'react'; +import React, { useState } from 'react'; import { Spinner } from '../../components/Spinner'; import { string } from 'yup'; import { useHistory } from 'react-router'; import { setUserJWT } from '../../utils/jwt-helper'; import { setGlobalUserLoginInfo } from '../../utils/user-helper'; import { useSearchParam } from '@/hooks/useSearchParam'; +import { DevContainer } from '@/components/DevContainer'; +import { useNavToView } from './utils'; /** * TODO: @@ -58,13 +60,7 @@ export const LoginView: React.FC = React.memo(() => { } }, [email, password, history, navRedirect]); - const toRegisterView = useCallback(() => { - // 携带上下文切换路由 - history.push({ - ...history.location, - pathname: '/entry/register', - }); - }, [history]); + const navToView = useNavToView(); return (
@@ -109,11 +105,22 @@ export const LoginView: React.FC = React.memo(() => { + + + +
); diff --git a/web/src/routes/Entry/RegisterView.tsx b/web/src/routes/Entry/RegisterView.tsx index c74e5807..0bb1e622 100644 --- a/web/src/routes/Entry/RegisterView.tsx +++ b/web/src/routes/Entry/RegisterView.tsx @@ -1,5 +1,5 @@ import { isValidStr, registerWithEmail, t, useAsyncFn } from 'tailchat-shared'; -import React, { useCallback, useState } from 'react'; +import React, { useState } from 'react'; import { Spinner } from '../../components/Spinner'; import { string } from 'yup'; import { Icon } from '@iconify/react'; @@ -7,6 +7,7 @@ import { useHistory } from 'react-router'; import { setUserJWT } from '../../utils/jwt-helper'; import { setGlobalUserLoginInfo } from '../../utils/user-helper'; import { useSearchParam } from '@/hooks/useSearchParam'; +import { useNavToView } from './utils'; /** * 注册视图 @@ -40,13 +41,7 @@ export const RegisterView: React.FC = React.memo(() => { } }, [email, password, navRedirect]); - const toLoginView = useCallback(() => { - // 携带上下文切换路由 - history.push({ - ...history.location, - pathname: '/entry/login', - }); - }, [history]); + const navToView = useNavToView(); return (
@@ -90,7 +85,7 @@ export const RegisterView: React.FC = React.memo(() => {
diff --git a/web/src/routes/Entry/utils.ts b/web/src/routes/Entry/utils.ts new file mode 100644 index 00000000..f09d146e --- /dev/null +++ b/web/src/routes/Entry/utils.ts @@ -0,0 +1,22 @@ +import { useCallback } from 'react'; +import { useHistory } from 'react-router'; + +/** + * 导航到特定视图 + */ +export function useNavToView() { + const history = useHistory(); + + const navToView = useCallback( + (pathname: string) => { + // 携带上下文切换路由 + history.push({ + ...history.location, + pathname, + }); + }, + [history] + ); + + return navToView; +}