### What problem does this PR solve? fix: Login with @tanstack/react-query #1306 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.9.0
| @@ -1,5 +1,10 @@ | |||
| import { useCallback } from 'react'; | |||
| import { useDispatch } from 'umi'; | |||
| import { Authorization } from '@/constants/authorization'; | |||
| import userService from '@/services/user-service'; | |||
| import authorizationUtil from '@/utils/authorizationUtil'; | |||
| import { useMutation } from '@tanstack/react-query'; | |||
| import { message } from 'antd'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { history } from 'umi'; | |||
| export interface ILoginRequestBody { | |||
| email: string; | |||
| @@ -11,34 +16,82 @@ export interface IRegisterRequestBody extends ILoginRequestBody { | |||
| } | |||
| export const useLogin = () => { | |||
| const dispatch = useDispatch(); | |||
| const login = useCallback( | |||
| (requestBody: ILoginRequestBody) => { | |||
| // TODO: Type needs to be improved | |||
| return dispatch<any>({ | |||
| type: 'loginModel/login', | |||
| payload: requestBody, | |||
| }); | |||
| const { t } = useTranslation(); | |||
| const { | |||
| data, | |||
| isPending: loading, | |||
| mutateAsync, | |||
| } = useMutation({ | |||
| mutationKey: ['login'], | |||
| mutationFn: async (params: { email: string; password: string }) => { | |||
| const { data: res = {}, response } = await userService.login(params); | |||
| if (res.retcode === 0) { | |||
| const { data } = res; | |||
| message.success(t('message.logged')); | |||
| const authorization = response.headers.get(Authorization); | |||
| const token = data.access_token; | |||
| const userInfo = { | |||
| avatar: data.avatar, | |||
| name: data.nickname, | |||
| email: data.email, | |||
| }; | |||
| authorizationUtil.setItems({ | |||
| Authorization: authorization, | |||
| userInfo: JSON.stringify(userInfo), | |||
| Token: token, | |||
| }); | |||
| } | |||
| return res.retcode; | |||
| }, | |||
| [dispatch], | |||
| ); | |||
| }); | |||
| return login; | |||
| return { data, loading, login: mutateAsync }; | |||
| }; | |||
| export const useRegister = () => { | |||
| const dispatch = useDispatch(); | |||
| const register = useCallback( | |||
| (requestBody: IRegisterRequestBody) => { | |||
| return dispatch<any>({ | |||
| type: 'loginModel/register', | |||
| payload: requestBody, | |||
| }); | |||
| const { t } = useTranslation(); | |||
| const { | |||
| data, | |||
| isPending: loading, | |||
| mutateAsync, | |||
| } = useMutation({ | |||
| mutationKey: ['register'], | |||
| mutationFn: async (params: { | |||
| email: string; | |||
| password: string; | |||
| nickname: string; | |||
| }) => { | |||
| const { data = {} } = await userService.register(params); | |||
| if (data.retcode === 0) { | |||
| message.success(t('message.registered')); | |||
| } | |||
| return data.retcode; | |||
| }, | |||
| }); | |||
| return { data, loading, register: mutateAsync }; | |||
| }; | |||
| export const useLogout = () => { | |||
| const { t } = useTranslation(); | |||
| const { | |||
| data, | |||
| isPending: loading, | |||
| mutateAsync, | |||
| } = useMutation({ | |||
| mutationKey: ['logout'], | |||
| mutationFn: async () => { | |||
| const { data = {} } = await userService.logout(); | |||
| if (data.retcode === 0) { | |||
| message.success(t('message.logout')); | |||
| authorizationUtil.removeAll(); | |||
| history.push('/login'); | |||
| } | |||
| return data.retcode; | |||
| }, | |||
| [dispatch], | |||
| ); | |||
| }); | |||
| return register; | |||
| return { data, loading, logout: mutateAsync }; | |||
| }; | |||
| @@ -1,9 +1,8 @@ | |||
| import { ITenantInfo } from '@/interfaces/database/knowledge'; | |||
| import { ISystemStatus, IUserInfo } from '@/interfaces/database/userSetting'; | |||
| import userService from '@/services/user-service'; | |||
| import authorizationUtil from '@/utils/authorizationUtil'; | |||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | |||
| import { history, useDispatch, useSelector } from 'umi'; | |||
| import { useDispatch, useSelector } from 'umi'; | |||
| export const useFetchUserInfo = () => { | |||
| const dispatch = useDispatch(); | |||
| @@ -67,20 +66,6 @@ export const useSelectParserList = (): Array<{ | |||
| return parserList; | |||
| }; | |||
| export const useLogout = () => { | |||
| const dispatch = useDispatch(); // TODO: clear redux state | |||
| const logout = useCallback(async () => { | |||
| const retcode = await dispatch<any>({ type: 'loginModel/logout' }); | |||
| if (retcode === 0) { | |||
| authorizationUtil.removeAll(); | |||
| history.push('/login'); | |||
| } | |||
| }, [dispatch]); | |||
| return logout; | |||
| }; | |||
| export const useSaveSetting = () => { | |||
| const dispatch = useDispatch(); | |||
| @@ -1,5 +1,4 @@ | |||
| import { useLogin, useRegister } from '@/hooks/login-hooks'; | |||
| import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; | |||
| import { rsaPsw } from '@/utils'; | |||
| import { Button, Checkbox, Form, Input } from 'antd'; | |||
| import { useEffect, useState } from 'react'; | |||
| @@ -13,16 +12,10 @@ import styles from './index.less'; | |||
| const Login = () => { | |||
| const [title, setTitle] = useState('login'); | |||
| const navigate = useNavigate(); | |||
| const login = useLogin(); | |||
| const register = useRegister(); | |||
| const { login, loading: signLoading } = useLogin(); | |||
| const { register, loading: registerLoading } = useRegister(); | |||
| const { t } = useTranslation('translation', { keyPrefix: 'login' }); | |||
| // TODO: When the server address request is not accessible, the value of dva-loading always remains true. | |||
| const signLoading = useOneNamespaceEffectsLoading('loginModel', [ | |||
| 'login', | |||
| 'register', | |||
| ]); | |||
| const loading = signLoading || registerLoading; | |||
| const changeTitle = () => { | |||
| setTitle((title) => (title === 'login' ? 'register' : 'login')); | |||
| @@ -148,7 +141,7 @@ const Login = () => { | |||
| block | |||
| size="large" | |||
| onClick={onCheck} | |||
| loading={signLoading} | |||
| loading={loading} | |||
| > | |||
| {title === 'login' ? t('login') : t('continue')} | |||
| </Button> | |||
| @@ -1,69 +0,0 @@ | |||
| import { Authorization } from '@/constants/authorization'; | |||
| import i18n from '@/locales/config'; | |||
| import userService from '@/services/user-service'; | |||
| import authorizationUtil from '@/utils/authorizationUtil'; | |||
| import { message } from 'antd'; | |||
| import { DvaModel } from 'umi'; | |||
| export interface LoginModelState { | |||
| list: any[]; | |||
| info: any; | |||
| visible: boolean; | |||
| } | |||
| const model: DvaModel<LoginModelState> = { | |||
| namespace: 'loginModel', | |||
| state: { | |||
| list: [], | |||
| info: {}, | |||
| visible: false, | |||
| }, | |||
| reducers: { | |||
| updateState(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| ...payload, | |||
| }; | |||
| }, | |||
| }, | |||
| effects: { | |||
| *login({ payload = {} }, { call }) { | |||
| const { data, response } = yield call(userService.login, payload); | |||
| const { retcode, data: res } = data; | |||
| const authorization = response.headers.get(Authorization); | |||
| if (retcode === 0) { | |||
| message.success(i18n.t('message.logged')); | |||
| const token = res.access_token; | |||
| const userInfo = { | |||
| avatar: res.avatar, | |||
| name: res.nickname, | |||
| email: res.email, | |||
| }; | |||
| authorizationUtil.setItems({ | |||
| Authorization: authorization, | |||
| userInfo: JSON.stringify(userInfo), | |||
| Token: token, | |||
| }); | |||
| } | |||
| return retcode; | |||
| }, | |||
| *register({ payload = {} }, { call }) { | |||
| const { data } = yield call(userService.register, payload); | |||
| console.log(); | |||
| const { retcode } = data; | |||
| if (retcode === 0) { | |||
| message.success(i18n.t('message.registered')); | |||
| } | |||
| return retcode; | |||
| }, | |||
| *logout({ payload = {} }, { call }) { | |||
| const { data } = yield call(userService.logout, payload); | |||
| const { retcode } = data; | |||
| if (retcode === 0) { | |||
| message.success(i18n.t('message.logout')); | |||
| } | |||
| return retcode; | |||
| }, | |||
| }, | |||
| }; | |||
| export default model; | |||
| @@ -1,5 +1,8 @@ | |||
| import { Domain } from '@/constants/common'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useLogout } from '@/hooks/login-hooks'; | |||
| import { useSecondPathName } from '@/hooks/route-hook'; | |||
| import { useFetchSystemVersion } from '@/hooks/user-setting-hooks'; | |||
| import type { MenuProps } from 'antd'; | |||
| import { Flex, Menu } from 'antd'; | |||
| import React, { useEffect, useMemo } from 'react'; | |||
| @@ -9,9 +12,6 @@ import { | |||
| UserSettingIconMap, | |||
| UserSettingRouteKey, | |||
| } from '../constants'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useFetchSystemVersion, useLogout } from '@/hooks/user-setting-hooks'; | |||
| import styles from './index.less'; | |||
| type MenuItem = Required<MenuProps>['items'][number]; | |||
| @@ -19,7 +19,7 @@ type MenuItem = Required<MenuProps>['items'][number]; | |||
| const SideBar = () => { | |||
| const navigate = useNavigate(); | |||
| const pathName = useSecondPathName(); | |||
| const logout = useLogout(); | |||
| const { logout } = useLogout(); | |||
| const { t } = useTranslate('setting'); | |||
| const { version, fetchSystemVersion } = useFetchSystemVersion(); | |||
| @@ -3,7 +3,6 @@ import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/mo | |||
| import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; | |||
| import { kAModelState } from '@/pages/add-knowledge/model'; | |||
| import { ChatModelState } from '@/pages/chat/model'; | |||
| import { LoginModelState } from '@/pages/login/model'; | |||
| import { SettingModelState } from '@/pages/user-setting/model'; | |||
| declare module 'lodash'; | |||
| @@ -15,7 +14,6 @@ function useSelector<TState = RootState, TSelected = unknown>( | |||
| export interface RootState { | |||
| chatModel: ChatModelState; | |||
| loginModel: LoginModelState; | |||
| settingModel: SettingModelState; | |||
| kFModel: KFModelState; | |||
| kAModel: kAModelState; | |||