You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailchat/client/web/src/routes/Main/Provider.tsx

105 lines
2.8 KiB
TypeScript

import {
createSocket,
setupRedux,
useAsync,
userActions,
t,
ReduxProvider,
UserLoginInfo,
getReduxStore,
} from 'tailchat-shared';
import React, { PropsWithChildren } from 'react';
import { LoadingSpinner } from '@/components/LoadingSpinner';
import { tryAutoLogin } from '@/utils/user-helper';
import _isNil from 'lodash/isNil';
import { useNavigate } from 'react-router';
import { SidebarContextProvider } from './SidebarContext';
import { PortalHost } from '@/components/Portal';
import { setGlobalSocket, setGlobalStore } from '@/utils/global-state-helper';
import { SocketContextProvider } from '@/context/SocketContext';
import { Problem } from '@/components/Problem';
import { KeepAliveOverlayHost } from '@/components/KeepAliveOverlay';
/**
* 应用状态管理hooks
*/
function useAppState() {
const navigate = useNavigate();
const { value, loading, error } = useAsync(async () => {
let userLoginInfo: UserLoginInfo;
try {
userLoginInfo = await tryAutoLogin();
} catch (e) {
// 当前 Token 不存在或已过期
navigate(
`/entry/login?redirect=${encodeURIComponent(location.pathname)}`,
{ replace: true }
);
return;
}
// 到这里 userLoginInfo 必定存在
// 创建Redux store
const store = getReduxStore();
store.dispatch(userActions.setUserInfo(userLoginInfo));
setGlobalStore(store);
// 创建 websocket 连接
const socket = await createSocket(userLoginInfo.token);
setGlobalSocket(socket);
// 初始化Redux
setupRedux(socket, store);
return { store, socket };
}, []);
const store = value?.store;
const socket = value?.socket;
return { loading, store, socket, error };
}
/**
* 主页面核心数据Provider
* 在主页存在
*/
export const MainProvider: React.FC<PropsWithChildren> = React.memo((props) => {
const { loading, store, error, socket } = useAppState();
if (loading) {
return (
<div className="fixed inset-0 flex items-center justify-center bg-content-light dark:bg-content-dark text-gray-700 dark:text-white text-xl">
<LoadingSpinner tip={t('正在连接到聊天服务器...')} />
</div>
);
}
if (error) {
console.error('[MainProvider]', error);
return <div>{error.message}</div>;
}
if (_isNil(store)) {
return <Problem text={t('出现异常, Store 创建失败')} />;
}
if (_isNil(socket)) {
return <Problem text={t('出现异常, Socket 创建失败')} />;
}
return (
<ReduxProvider store={store}>
<SocketContextProvider socket={socket}>
<SidebarContextProvider>
<KeepAliveOverlayHost>
<PortalHost>{props.children}</PortalHost>
</KeepAliveOverlayHost>
</SidebarContextProvider>
</SocketContextProvider>
</ReduxProvider>
);
});
MainProvider.displayName = 'MainProvider';