"use client"; import type { ReactNode, FormEvent } from "react"; import { Lock } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useId, useState } from "react"; import { apiUnlockPost, apiUnlockPostPassword } from "@/lib/api"; import { CSRF_COOKIE } from "@/lib/cookies"; import { toast } from "@/lib/toast"; import { hideKindLabel, type HideKind } from "@/lib/hideBlocks"; /** 若浏览器尚无 CSRF cookie,请求公开接口以触发后端签发 */ async function ensureGuestCSRF() { if (typeof document === "undefined") return; const escaped = CSRF_COOKIE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); if (new RegExp(`(?:^|;\\s*)${escaped}=`).test(document.cookie)) return; try { await fetch("/api/me", { credentials: "include", cache: "no-store" }); } catch { /* 忽略:后续解锁会报 CSRF 错误 */ } } type MdHideBlockProps = { kind: HideKind; points?: number; locked?: boolean; postId?: number; loggedIn?: boolean; children?: ReactNode; }; /** 正文内嵌隐藏块:已解锁显示徽章容器;locked 显示就地门禁 */ export default function MdHideBlock({ kind, points = 0, locked = false, postId, loggedIn = false, children, }: MdHideBlockProps) { const router = useRouter(); const pwdErrId = useId(); const [busy, setBusy] = useState(false); const [pwd, setPwd] = useState(""); const [pwdError, setPwdError] = useState(""); const label = hideKindLabel(kind); if (locked) { const unlockPoints = async () => { if (!postId) return; setBusy(true); try { const res = await apiUnlockPost(String(postId)); if (res.post) { toast("已解锁隐藏内容", "ok"); router.refresh(); } else { toast(res.error || "解锁失败", "error"); } } catch { toast("解锁失败", "error"); } finally { setBusy(false); } }; const unlockPassword = async (e: FormEvent) => { e.preventDefault(); if (!postId) return; const password = pwd.trim(); if (!password) { setPwdError("请输入密码"); return; } setBusy(true); setPwdError(""); try { // 游客可能尚无 CSRF:先打一次公开 GET 让后端签发,再提交解锁 await ensureGuestCSRF(); const res = await apiUnlockPostPassword(String(postId), password); if (res.post) { toast("密码正确,已解锁", "ok"); setPwd(""); setPwdError(""); router.refresh(); } else { setPwdError(res.error || "密码错误,请重试"); } } catch { setPwdError("验证失败,请稍后重试"); } finally { setBusy(false); } }; return ( ); } return (
{label} {kind === "points" && points > 0 && ( {points} 积分 )}
{children}
); }