"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; import { Home, Trophy, PenSquare, MessageSquare, User as UserIcon, } from "lucide-react"; import { apiChatUnreadSummary, type User } from "@/lib/api"; import { useAllowMessages } from "@/components/MessagesPolicyProvider"; import { useUrlStyle } from "@/components/SiteBrandProvider"; import { onDocumentVisible } from "@/lib/visibilityReconcile"; import { parseEntityPath, userPath, leaderboardPath } from "@/lib/urlStyle"; import { realtime, RT_CHAT_UNREAD } from "@/lib/realtime"; import type { RtChatUnreadData } from "@/lib/realtime"; /** * 移动端全局底部公共菜单(lg 以下显示): * 首页 / 排行榜 / 发帖 / 消息(未登录不显示)/ 我的。 * 聊天页、发帖工作台、管理后台由 SiteChrome 控制不渲染,避免与锁视口布局冲突。 */ export default function MobileTabBar({ user, initialChatUnread = 0, }: { user: User | null; initialChatUnread?: number; }) { const pathname = usePathname(); const allowMessages = useAllowMessages(); const urlStyle = useUrlStyle(); const lbHref = leaderboardPath(urlStyle); const [chatUnread, setChatUnread] = useState(initialChatUnread); // 登录态经 router.refresh() 下发新 props 时校正徽标 useEffect(() => { setChatUnread(initialChatUnread); }, [initialChatUnread]); // 实时未读:与 Header 同源(chat:unread 对全体成员推送;在当前会话页则忽略) useEffect(() => { if (!user || !allowMessages) return; const off = realtime.on(RT_CHAT_UNREAD, (data) => { if (!data || typeof data.room_id !== "number") return; if (pathname === `/chat/${data.room_id}`) return; const delta = typeof data.delta === "number" ? data.delta : 1; setChatUnread((c) => Math.max(0, c + delta)); }); return off; }, [user, pathname, allowMessages]); // 会话内已读 / 回前台:合并对账(短时间多次同步只打一次 summary) useEffect(() => { if (!user || !allowMessages) return; let debounceTimer: ReturnType | null = null; const pullSummary = () => { apiChatUnreadSummary() .then((res) => setChatUnread(res.total || 0)) .catch(() => {}); }; const onSync = () => { if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(pullSummary, 250); }; window.addEventListener("j13-chat-unread-sync", onSync); const offVisible = onDocumentVisible(pullSummary); return () => { if (debounceTimer) clearTimeout(debounceTimer); window.removeEventListener("j13-chat-unread-sync", onSync); offVisible(); }; }, [user, allowMessages]); const showMessages = !!user && allowMessages; const isActive = (match: (p: string) => boolean) => !!pathname && match(pathname); return ( ); } function TabLink({ href, icon, label, active, prominent = false, badge = 0, }: { href: string; icon: React.ReactNode; label: string; active: boolean; prominent?: boolean; badge?: number | string; }) { const ink = active ? "var(--accent)" : "var(--ink-2)"; return ( {prominent ? ( ) : ( )} {label} ); }