diff --git a/src/app/cache/useRehydrate.ts b/src/app/cache/useRehydrate.ts index e70adc42..e2e74a2e 100644 --- a/src/app/cache/useRehydrate.ts +++ b/src/app/cache/useRehydrate.ts @@ -1,5 +1,5 @@ import { useState } from "react"; -import { useDispatch, batch } from "react-redux"; +import { useDispatch } from "react-redux"; import { fillReactionMessage } from "../slices/message.reaction"; import { fillServer } from "../slices/server"; import { fillMessage } from "../slices/message"; @@ -10,11 +10,22 @@ import { fillUsers } from "../slices/users"; import { fillFootprint } from "../slices/footprint"; import { fillFileMessage } from "../slices/message.file"; import { fillUI } from "../slices/ui"; +import { useAppSelector } from "../store"; const useRehydrate = () => { const [iterated, setIterated] = useState(false); const dispatch = useDispatch(); + const { isGuest } = useAppSelector((store) => { + return { + isGuest: store.authData.user?.create_by == "guest" + }; + }); const rehydrate = async () => { + // 如果是游客,直接忽略 + if (isGuest) { + setIterated(true); + return; + } const rehydrateData = { channels: [], users: [], @@ -74,20 +85,18 @@ const useRehydrate = () => { }); }) ); - batch(() => { - dispatch(fillUsers(rehydrateData.users)); - dispatch(fillServer(rehydrateData.server)); - console.log("fill channels from indexedDB"); - dispatch(fillChannels(rehydrateData.channels)); - // file message - dispatch(fillFileMessage(rehydrateData.fileMessage.list)); - dispatch(fillChannelMsg(rehydrateData.channelMessage)); - dispatch(fillUserMsg(rehydrateData.userMessage)); - dispatch(fillMessage(rehydrateData.message)); - dispatch(fillFootprint(rehydrateData.footprint)); - dispatch(fillUI(rehydrateData.ui)); - dispatch(fillReactionMessage(rehydrateData.reactionMessage)); - }); + dispatch(fillUsers(rehydrateData.users)); + dispatch(fillServer(rehydrateData.server)); + console.log("fill channels from indexedDB"); + dispatch(fillChannels(rehydrateData.channels)); + // file message + dispatch(fillFileMessage(rehydrateData.fileMessage.list)); + dispatch(fillChannelMsg(rehydrateData.channelMessage)); + dispatch(fillUserMsg(rehydrateData.userMessage)); + dispatch(fillMessage(rehydrateData.message)); + dispatch(fillFootprint(rehydrateData.footprint)); + dispatch(fillUI(rehydrateData.ui)); + dispatch(fillReactionMessage(rehydrateData.reactionMessage)); setIterated(true); console.log("iterate results", rehydrateData, results); diff --git a/src/app/listener.middleware/index.ts b/src/app/listener.middleware/index.ts index 29ce4d05..84bda282 100644 --- a/src/app/listener.middleware/index.ts +++ b/src/app/listener.middleware/index.ts @@ -10,6 +10,7 @@ import fileMessageHandler from "./handler.file.msg"; import reactionHandler from "./handler.reaction"; import UIHandler from "./handler.ui"; import footprintHandler from "./handler.footprint"; +import { RootState } from "../store"; const operations = [ "__rtkq", @@ -41,11 +42,14 @@ listenerMiddleware.startListening({ }, effect: async (action, listenerApi) => { const { type = "", payload } = action; - const [prefix, operation] = type.split("/"); + const [prefix, operation]: [keyof RootState | "__rtkq", string] = type.split("/"); // console.log("effect opt", action); if (!window.CACHE && prefix !== "__rtkq") return; - - const state = listenerApi.getState()[prefix]; + const currentState = listenerApi.getState() as RootState; + // 如果是guest,则忽略 + const isGuest = currentState.authData.user?.create_by === "guest"; + if (isGuest) return; + const state = prefix == "__rtkq" ? null : currentState[prefix]; switch (prefix) { case "__rtkq": { diff --git a/src/app/services/auth.ts b/src/app/services/auth.ts index 99fef4c6..8abbb650 100644 --- a/src/app/services/auth.ts +++ b/src/app/services/auth.ts @@ -57,6 +57,21 @@ export const authApi = createApi({ } } }), + guestLogin: builder.query({ + query: () => ({ url: "/token/login_guest" }), + async onQueryStarted(params, { dispatch, queryFulfilled }) { + try { + const { data } = await queryFulfilled; + if (data) { + dispatch(setAuthData(data)); + } + // 从localstorage 去掉 magic token + localStorage.removeItem(KEY_LOCAL_MAGIC_TOKEN); + } catch { + console.log("guest login error"); + } + } + }), register: builder.mutation({ query: (data) => ({ url: `user/register`, @@ -186,6 +201,8 @@ export const authApi = createApi({ }); export const { + useLazyGuestLoginQuery, + useGuestLoginQuery, useLazyCheckEmailQuery, useGetInitializedQuery, useSendLoginMagicLinkMutation, diff --git a/src/app/services/base.query.ts b/src/app/services/base.query.ts index 3ca65b88..bd479918 100644 --- a/src/app/services/base.query.ts +++ b/src/app/services/base.query.ts @@ -6,6 +6,7 @@ import BASE_URL, { tokenHeader } from "../config"; import { RootState } from "../store"; const whiteList = [ + "guestLogin", "login", "register", "sendLoginMagicLink", diff --git a/src/common/component/GuestOnly.tsx b/src/common/component/GuestOnly.tsx new file mode 100644 index 00000000..719708ad --- /dev/null +++ b/src/common/component/GuestOnly.tsx @@ -0,0 +1,37 @@ +import { FC, ReactElement, useEffect } from "react"; +import { Navigate } from "react-router-dom"; +import { useGetInitializedQuery, useLazyGuestLoginQuery } from "../../app/services/auth"; +import { useGetLoginConfigQuery } from "../../app/services/server"; +import { useAppSelector } from "../../app/store"; + +interface Props { + children: ReactElement; +} + +const GuestOnly: FC = ({ children }) => { + const { data: loginConfig, isLoading: fetchingConfig } = useGetLoginConfigQuery(); + const { isLoading: initChecking } = useGetInitializedQuery(); + const [guestLogin, { isLoading: guestSigning }] = useLazyGuestLoginQuery(); + const { token, user, initialized } = useAppSelector((store) => store.authData); + + useEffect(() => { + // 未登录 + if (!token) { + guestLogin(); + } + }, [token, user]); + + // 已登录的非guest用户 + if (token && user?.create_by !== "guest") { + return ; + } + if (initChecking || guestSigning || fetchingConfig) return null; + // console.log("wtfff", token, user); + // 检查有没有开启guest mode + if (!loginConfig?.guest) return ; + // 未初始化 则先走setup 流程 + if (!initialized) return ; + return token ? children : null; +}; + +export default GuestOnly; diff --git a/src/common/component/Message/index.tsx b/src/common/component/Message/index.tsx index 0ec754b0..be4c2860 100644 --- a/src/common/component/Message/index.tsx +++ b/src/common/component/Message/index.tsx @@ -155,7 +155,7 @@ const Message: FC = ({ edited }) )} - {reactions && } + {reactions && } diff --git a/src/common/hook/usePreload.ts b/src/common/hook/usePreload.ts index 97bcebe7..42802203 100644 --- a/src/common/hook/usePreload.ts +++ b/src/common/hook/usePreload.ts @@ -6,17 +6,24 @@ import { useLazyGetUsersQuery } from "../../app/services/user"; import { useLazyGetServerQuery } from "../../app/services/server"; import useStreaming from "./useStreaming"; import { useAppSelector } from "../../app/store"; +import { useLazyGetHistoryMessagesQuery } from "../../app/services/channel"; // type Props={ // guest?:boolean // } +let preloadChannelMsgs = false; export default function usePreload() { + const [preloadChannelMessages] = useLazyGetHistoryMessagesQuery(); const { rehydrate, rehydrated } = useRehydrate(); const { loginUid, token, - expireTime = +new Date() + expireTime = +new Date(), + channelMessageData, + channelIds } = useAppSelector((store) => { return { + channelIds: store.channels.ids, + channelMessageData: store.channelMessage, loginUid: store.authData.user?.uid, token: store.authData.token, expireTime: store.authData.expireTime @@ -48,6 +55,16 @@ export default function usePreload() { }; }, []); + useEffect(() => { + if (channelIds.length > 0 && !preloadChannelMsgs) { + const tmps = channelIds.filter((cid) => !channelMessageData[cid]); + console.log("tmpss", tmps); + tmps.forEach((id) => { + preloadChannelMessages({ id, limit: 50 }); + }); + preloadChannelMsgs = true; + } + }, [channelIds, channelMessageData]); useEffect(() => { if (rehydrated) { getUsers(); diff --git a/src/routes/chat/Layout/LoginTip.tsx b/src/routes/chat/Layout/LoginTip.tsx index b6ecf705..f2e8bc51 100644 --- a/src/routes/chat/Layout/LoginTip.tsx +++ b/src/routes/chat/Layout/LoginTip.tsx @@ -1,36 +1,49 @@ -import React from "react"; -import { NavLink } from "react-router-dom"; +// import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; import styled from "styled-components"; +import { resetAuthData } from "../../../app/slices/auth.data"; +import Button from "../../../common/component/styled/Button"; +import useLogout from "../../../common/hook/useLogout"; const Styled = styled.div` display: flex; align-items: center; + justify-content: space-between; background: #e5e7eb; border-radius: var(--br); width: 100%; width: -webkit-fill-available; - padding: 14px 18px; - color: #aaa; - .hand { - font-size: 22px; - margin-right: 10px; - } - .link { - font-weight: bold; - color: #333; - padding: 0 8px; + padding: 16px 18px; + .txt { + font-weight: 500; + font-size: 14px; + line-height: 20px; + color: #98a2b3; + .hand { + font-size: 20px; + margin-right: 10px; + } } `; -type Props = {}; +// type Props = {}; + +const LoginTip = () => { + const dispatch = useDispatch(); + const { clearLocalData } = useLogout(); + const navigateTo = useNavigate(); + const handleSignIn = () => { + dispatch(resetAuthData()); + clearLocalData(); + navigateTo("/login"); + }; -const LoginTip = (props: Props) => { return ( - 👋 - Please{" "} - - Login/Register - {" "} - before you can send message + + 👋 + Please sign in to send message + + ); }; diff --git a/src/routes/guest/OffTip.tsx b/src/routes/guest/OffTip.tsx new file mode 100644 index 00000000..f1d4a73d --- /dev/null +++ b/src/routes/guest/OffTip.tsx @@ -0,0 +1,20 @@ +// import React from "react"; +import styled from "styled-components"; +const Styled = styled.div` + display: flex; + align-items: center; + font-size: 28px; + font-weight: bold; + color: orange; + padding: 50px; + height: calc(100vh - 24px); + text-transform: uppercase; + letter-spacing: 2px; +`; +// type Props = {}; + +const OffTip = () => { + return Guest Mode Off; +}; + +export default OffTip; diff --git a/src/routes/guest/index.tsx b/src/routes/guest/index.tsx index 71e5ccda..e1f2f4ea 100644 --- a/src/routes/guest/index.tsx +++ b/src/routes/guest/index.tsx @@ -1,5 +1,5 @@ // import React from 'react'; -import { NavLink, useParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import StyledWrapper from "./styled"; import Loading from "../../common/component/Loading"; import Manifest from "../../common/component/Manifest"; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 8498ee4e..4a833736 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -28,6 +28,8 @@ import GeustPage from "./guest"; import ChatPage from "./chat"; import Loading from "../common/component/Loading"; import store, { useAppSelector } from "../app/store"; +import OffTip from "./guest/OffTip"; +import GuestOnly from "../common/component/GuestOnly"; let toastId: string; const PageRoutes = () => { const { @@ -92,9 +94,24 @@ const PageRoutes = () => { } /> } /> {/* guest mode */} - - } /> - } /> + + + + + } + /> + + + + } + /> + } />