Files
cozsweet-frontend-nextjs/src/stores/sync/chat-auth-sync.tsx
T

74 lines
1.9 KiB
TypeScript

"use client";
/**
* Auth → Chat 同步器
*
* Chat machine 不直接感知 Auth machine;这里作为根级桥接器,持续监听
* loginStatus 变化并派发 chat 鉴权生命周期事件。这样页面组件只负责 UI,
* 不再承担全局状态同步职责。
*/
import { useEffect, useRef } from "react";
import { shallowEqual } from "@xstate/react";
import { AuthStorage } from "@/data/storage/auth";
import {
selectAuthIsLoading,
useAuthSelector,
} from "@/stores/auth/auth-context";
import { useChatDispatch } from "@/stores/chat/chat-context";
export function ChatAuthSync() {
const authState = useAuthSelector(
(state) => ({
hasInitialized: state.context.hasInitialized,
isLoading: selectAuthIsLoading(state),
loginStatus: state.context.loginStatus,
}),
shallowEqual,
);
const chatDispatch = useChatDispatch();
const prevSessionKeyRef = useRef<string | null>(null);
useEffect(() => {
if (!authState.hasInitialized || authState.isLoading) return;
const sessionKey = authState.loginStatus;
if (prevSessionKeyRef.current === sessionKey) return;
if (authState.loginStatus === "notLoggedIn") {
prevSessionKeyRef.current = sessionKey;
chatDispatch({ type: "ChatLogout" });
return;
}
if (authState.loginStatus === "guest") {
prevSessionKeyRef.current = sessionKey;
chatDispatch({ type: "ChatGuestLogin" });
return;
}
let cancelled = false;
void (async () => {
const tokenR = await AuthStorage.getInstance().getLoginToken();
if (!cancelled && tokenR.success && tokenR.data) {
prevSessionKeyRef.current = sessionKey;
chatDispatch({
type: "ChatUserLogin",
token: tokenR.data,
});
}
})();
return () => {
cancelled = true;
};
}, [
authState.hasInitialized,
authState.isLoading,
authState.loginStatus,
chatDispatch,
]);
return null;
}