Files
2026-03-27 18:20:36 -05:00

134 lines
4.4 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 { useEffect, useState } from "react";
import { Copyable } from "../Copyable";
import styles from "../vip.module.css";
const COMMUNITY_URL = "https://qun.hackrobot.cn";
const DEFAULT_PASSWORD = "12345678";
function getStorage(key: string): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(key);
}
function isAnonymousUserId(value: string | null): value is string {
return !!value && /^user\d+$/.test(value);
}
type CommunityAccessModalProps = {
open: boolean;
onClose: () => void;
};
/** 与 WelcomeBlock 同步的社群登录账号解析,用于弹窗展示 */
export function CommunityAccessModal({ open, onClose }: CommunityAccessModalProps) {
const userId = typeof window !== "undefined" ? getStorage("userId") : null;
const [backendMemosAccount, setBackendMemosAccount] = useState<string | null>(null);
const memosAccount =
getStorage("memosAccount") ||
backendMemosAccount ||
(isAnonymousUserId(userId) ? userId : null);
useEffect(() => {
if (!open || !userId) return;
fetch(`/api/vip/linked-email?user_id=${encodeURIComponent(userId)}`, {
cache: "no-store",
})
.then((res) => res.json())
.then((data) => {
const linkedAnonymousUserId =
typeof data?.anonymousUserId === "string" && /^user\d+$/.test(data.anonymousUserId)
? data.anonymousUserId
: null;
if (linkedAnonymousUserId && typeof window !== "undefined") {
setBackendMemosAccount(linkedAnonymousUserId);
localStorage.setItem("memosAccount", linkedAnonymousUserId);
}
})
.catch(() => {});
}, [open, userId]);
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
return (
<div
className={styles.communityModalBackdrop}
role="presentation"
onClick={onClose}
>
<div
className={styles.communityModalPanel}
role="dialog"
aria-modal="true"
aria-labelledby="community-modal-title"
onClick={(e) => e.stopPropagation()}
>
<div className={styles.communityModalGlow} aria-hidden />
<button
type="button"
className={styles.communityModalClose}
onClick={onClose}
aria-label="关闭"
>
×
</button>
<div className={styles.communityModalIconWrap}>
<span className={styles.communityModalIcon}>👥</span>
</div>
<h2 id="community-modal-title" className={styles.communityModalTitle}>
·
</h2>
<p className={styles.communityModalDesc}>
使访
</p>
<div className={styles.communityModalRows}>
<div className={styles.communityModalRow}>
<span className={styles.communityModalLabel}></span>
<div className={styles.communityModalValueWrap}>
<Copyable text={COMMUNITY_URL} className={styles.communityModalCopyable}>
<span className={styles.communityModalMono}>qun.hackrobot.cn</span>
</Copyable>
<a
href={COMMUNITY_URL}
target="_blank"
rel="noopener noreferrer"
className={styles.communityModalOpenLink}
>
</a>
</div>
</div>
<div className={styles.communityModalRow}>
<span className={styles.communityModalLabel}></span>
<Copyable text={memosAccount || ""} className={styles.communityModalCopyable}>
<span className={styles.communityModalMono}>{memosAccount || "—"}</span>
</Copyable>
</div>
<div className={styles.communityModalRow}>
<span className={styles.communityModalLabel}></span>
<Copyable text={DEFAULT_PASSWORD} className={styles.communityModalCopyable}>
<span className={styles.communityModalMono}>{DEFAULT_PASSWORD}</span>
</Copyable>
</div>
</div>
<button type="button" className={styles.communityModalDone} onClick={onClose}>
</button>
</div>
</div>
);
}