Files
jiang13-bbs/frontend/components/CommentsPolicyProvider.tsx

79 lines
2.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import {
createContext,
useContext,
useEffect,
useRef,
useState,
type ReactNode,
} from "react";
import { useRouter } from "next/navigation";
import { realtime, RT_SETTINGS_CHANGED, type RtSettingsData } from "@/lib/realtime";
type CommentsPolicy = {
open: boolean;
requireLogin: boolean;
};
const CommentsPolicyContext = createContext<CommentsPolicy>({
open: true,
requireLogin: false,
});
/** 前台是否开放评论(SSR 初值 + 后台开关热更新) */
export function useAllowComments(): boolean {
return useContext(CommentsPolicyContext).open;
}
/** 评论是否仅登录可见 */
export function useCommentsRequireLogin(): boolean {
return useContext(CommentsPolicyContext).requireLogin;
}
/**
* 根布局注入:关闭评论后前台立即隐藏评论区/数量;
* 「登录可见」切换时刷新以重拉/清空评论树。
*/
export default function CommentsPolicyProvider({
allowComments,
requireLogin = false,
children,
}: {
allowComments: boolean;
requireLogin?: boolean;
children: ReactNode;
}) {
const router = useRouter();
const [policy, setPolicy] = useState<CommentsPolicy>({
open: allowComments,
requireLogin,
});
const policyRef = useRef(policy);
policyRef.current = policy;
useEffect(() => {
setPolicy({ open: allowComments, requireLogin });
}, [allowComments, requireLogin]);
useEffect(() => {
return realtime.on<RtSettingsData>(RT_SETTINGS_CHANGED, (data) => {
if (!data) return;
const prev = policyRef.current;
const nextOpen =
typeof data.allow_comments === "boolean" ? data.allow_comments : prev.open;
const nextRequire =
typeof data.comments_require_login === "boolean"
? data.comments_require_login
: prev.requireLogin;
if (nextOpen === prev.open && nextRequire === prev.requireLogin) return;
setPolicy({ open: nextOpen, requireLogin: nextRequire });
router.refresh();
});
}, [router]);
return (
<CommentsPolicyContext.Provider value={policy}>{children}</CommentsPolicyContext.Provider>
);
}