'init'
This commit is contained in:
135
app/components/CommunityButton.tsx
Normal file
135
app/components/CommunityButton.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import { COMMUNITY_CONFIG } from "@/config/course";
|
||||
import { isPaid } from "@/app/lib/payment";
|
||||
|
||||
export function CommunityButton() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [paid, setPaid] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setPaid(isPaid());
|
||||
const onPay = () => setPaid(isPaid());
|
||||
window.addEventListener("pay:updated", onPay);
|
||||
return () => window.removeEventListener("pay:updated", onPay);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") setOpen(false);
|
||||
};
|
||||
if (open) {
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
if (!COMMUNITY_CONFIG.enabled || !COMMUNITY_CONFIG.wechat) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen(true)}
|
||||
className="text-sm text-[var(--muted-foreground)] transition hover:text-[var(--foreground)]"
|
||||
>
|
||||
{COMMUNITY_CONFIG.wechat}
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm p-4"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<div
|
||||
className="relative w-full max-w-[420px] overflow-hidden rounded-2xl border border-[var(--border)] bg-[var(--background)] shadow-2xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-[var(--accent)] via-cyan-400 to-[var(--accent)]" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen(false)}
|
||||
className="absolute right-3 top-3 rounded-full p-2 text-[var(--muted-foreground)] transition hover:bg-[var(--muted)] hover:text-[var(--foreground)]"
|
||||
aria-label="关闭"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{paid ? (
|
||||
<div className="p-8 pt-10">
|
||||
<div className="mb-6 text-center">
|
||||
<div className="mb-3 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-gradient-to-br from-[var(--accent)]/30 to-cyan-500/20 text-3xl shadow-lg">
|
||||
💬
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold">加入数字游民社群</h3>
|
||||
<p className="mt-2 text-sm text-[var(--muted-foreground)]">
|
||||
与导师、同学一起交流,获取持续支持与灵感
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<div className="relative flex h-56 w-56 items-center justify-center rounded-2xl bg-gradient-to-br from-[var(--card)] to-[var(--muted)]/30 p-5 shadow-inner ring-2 ring-[var(--accent)]/20">
|
||||
<img
|
||||
src={COMMUNITY_CONFIG.qrCodeUrl}
|
||||
alt="社群二维码"
|
||||
className="h-full w-full object-contain"
|
||||
onError={(e) => {
|
||||
const target = e.target as HTMLImageElement;
|
||||
target.style.display = "none";
|
||||
const fallback = target.parentElement?.querySelector(".qr-fallback");
|
||||
if (fallback) (fallback as HTMLElement).classList.remove("hidden");
|
||||
}}
|
||||
/>
|
||||
<div className="qr-fallback hidden absolute inset-0 flex flex-col items-center justify-center gap-2 rounded-2xl bg-[var(--muted)]/40 p-4 text-center text-sm text-[var(--muted-foreground)]">
|
||||
<span className="text-4xl">📱</span>
|
||||
<span>请配置社群二维码</span>
|
||||
<span className="text-xs">config/course.ts → qrCodeUrl</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-5 text-center text-sm text-[var(--muted-foreground)]">
|
||||
长按识别二维码加入
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-8 pt-10">
|
||||
<div className="mb-6 text-center">
|
||||
<div className="mb-3 inline-flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-amber-500/20 to-orange-500/10 text-4xl shadow-lg">
|
||||
🔒
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold">报名后解锁社群</h3>
|
||||
<p className="mt-2 text-sm leading-relaxed text-[var(--muted-foreground)]">
|
||||
完成课程报名后,即可加入专属社群,与导师、同学交流答疑
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Link
|
||||
href="/pay"
|
||||
className="rounded-xl bg-[var(--accent)] px-6 py-4 text-center font-medium text-[var(--accent-foreground)] transition hover:opacity-90"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
立即报名
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen(false)}
|
||||
className="rounded-xl border border-[var(--border)] px-6 py-3 text-sm transition hover:bg-[var(--muted)]"
|
||||
>
|
||||
稍后再说
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user