diff --git a/shared/cache/utils.ts b/shared/cache/utils.ts new file mode 100644 index 00000000..2389d711 --- /dev/null +++ b/shared/cache/utils.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { FetchQueryOptions } from 'react-query'; +import { queryClient } from './'; + +/** + * 构建缓存请求 + * TODO: 这里的类型真的不好写, 先用any来过滤内部的, 只保证外部使用ok + * + * @example + * const queryData = buildCachedRequest('key')((arg1, arg2) => { + * return request.post(...) + * }) + */ +export function buildCachedRequest< + R extends any, + F extends (...args: any) => Promise +>(prefix: string, fn: F, options?: FetchQueryOptions): F { + return ((...args: any) => { + return queryClient.fetchQuery( + [prefix, JSON.stringify(args)], + () => fn(...args), + options + ); + }) as any; +} diff --git a/shared/index.tsx b/shared/index.tsx index 544dfe0f..70b6a930 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -69,6 +69,7 @@ export { loginWithToken, registerWithEmail, searchUserWithUniqueName, + checkTokenValid, } from './model/user'; // redux diff --git a/shared/model/user.ts b/shared/model/user.ts index b223eba0..675b7e6c 100644 --- a/shared/model/user.ts +++ b/shared/model/user.ts @@ -1,4 +1,5 @@ import { request } from '../api/request'; +import { buildCachedRequest } from '../cache/utils'; export interface UserBaseInfo { _id: string; @@ -117,7 +118,9 @@ export async function getUserOnlineStatus( * 将会话添加到用户私信列表 * 如果已添加则后端忽略 */ -export async function appendUserDMConverse(converseId: string) { +export async function appendUserDMConverse( + converseId: string +): Promise { const { data } = await request.post( '/api/user/dmlist/addConverse', { @@ -127,3 +130,17 @@ export async function appendUserDMConverse(converseId: string) { return data; } + +/** + * 检查Token是否可用 + */ +export const checkTokenValid = buildCachedRequest( + 'tokenValid', + async (token: string): Promise => { + const { data } = await request.post('/api/user/checkTokenValid', { + token, + }); + + return data; + } +); diff --git a/shared/utils/string-helper.ts b/shared/utils/string-helper.ts index d4eb4d21..b2584a4b 100644 --- a/shared/utils/string-helper.ts +++ b/shared/utils/string-helper.ts @@ -57,7 +57,7 @@ export function getTextColorHex(text: unknown): string { } /** - * 是一个可用的字符串 + * 是否一个可用的字符串 * 定义为有长度的字符串 */ export function isValidStr(str: unknown): str is string { diff --git a/web/src/routes/Invite/JoinBtn.tsx b/web/src/routes/Invite/JoinBtn.tsx new file mode 100644 index 00000000..f08e9bd7 --- /dev/null +++ b/web/src/routes/Invite/JoinBtn.tsx @@ -0,0 +1,43 @@ +import { getUserJWT } from '@/utils/jwt-helper'; +import { Button } from 'antd'; +import React, { useCallback } from 'react'; +import { useHistory } from 'react-router'; +import { checkTokenValid, t, useAsync } from 'tailchat-shared'; + +interface Props { + onJoinGroup: () => void; +} +export const JoinBtn: React.FC = React.memo((props) => { + const history = useHistory(); + const { loading, value: isTokenValid } = useAsync(async () => { + const token = await getUserJWT(); + const isTokenValid = await checkTokenValid(token); + return isTokenValid; + }); + + const handleRegister = useCallback(() => { + history.push( + `/entry/register?redirect=${encodeURIComponent(location.pathname)}` + ); + }, []); + + if (loading) { + return null; + } + + return isTokenValid ? ( + + ) : ( + + ); +}); +JoinBtn.displayName = 'JoinBtn'; diff --git a/web/src/routes/Invite/index.tsx b/web/src/routes/Invite/index.tsx index cef64eae..7a18a005 100644 --- a/web/src/routes/Invite/index.tsx +++ b/web/src/routes/Invite/index.tsx @@ -1,23 +1,15 @@ -import { Button, Divider } from 'antd'; +import { Divider } from 'antd'; import React, { useCallback } from 'react'; -import { useHistory, useParams } from 'react-router'; +import { useParams } from 'react-router'; import { InviteInfo } from './InviteInfo'; import bgImage from '@assets/images/bg.jpg'; -import { t } from 'tailchat-shared'; +import { JoinBtn } from './JoinBtn'; /** * 邀请界面路由 */ export const InviteRoute: React.FC = React.memo(() => { - const history = useHistory(); const { inviteCode } = useParams<{ inviteCode: string }>(); - const isLogin = true; - - const handleRegister = useCallback(() => { - history.push( - `/entry/register?redirect=${encodeURIComponent(location.pathname)}` - ); - }, []); const handleJoinGroup = useCallback(() => { // TODO @@ -34,25 +26,7 @@ export const InviteRoute: React.FC = React.memo(() => { - {isLogin ? ( - - ) : ( - - )} + );