"use client"; import { useState, useEffect } from "react"; import { Link } from "@/i18n/navigation"; import { HERO_CONFIG, CURRICULUM_CONFIG } from "@/config/course"; import { useAuthAndVip } from "@/app/lib/useAuthAndVip"; import { getStoredToken, getStoredUser } from "@/app/lib/pocketbase"; import { getLastWatched, getProgress } from "@/app/lib/learning"; import AuthModal from "@/app/components/AuthModal"; import { getPayEnv, redirectToPay, getDeviceFromEnv, } from "@/app/lib/payment"; const TOTAL_LESSONS = CURRICULUM_CONFIG.modules.reduce((s, m) => s + m.lessons.length, 0); export function CourseHero() { const { user, vip, refetch } = useAuthAndVip(); const [last, setLast] = useState>(null); const [progress, setProgress] = useState({ completed: 0, percent: 0 }); const [authOpen, setAuthOpen] = useState(false); const [payRedirecting, setPayRedirecting] = useState(false); useEffect(() => { setLast(getLastWatched()); setProgress(getProgress(TOTAL_LESSONS)); const onProgress = () => { setLast(getLastWatched()); setProgress(getProgress(TOTAL_LESSONS)); }; window.addEventListener("learning:progress", onProgress); return () => window.removeEventListener("learning:progress", onProgress); }, []); const paid = !!user && vip; const startPay = (userId: string) => { const env = getPayEnv(); const channel = "wxpay"; const device = getDeviceFromEnv(env); const returnUrl = `${window.location.origin}/`; redirectToPay({ user_id: userId, return_url: returnUrl, channel, device, type: "video", useJoinConfig: true, }); }; const handleEnroll = async () => { if (payRedirecting) return; setPayRedirecting(true); try { // 先验证登录态 let meRes = await fetch("/api/auth/me", { credentials: "include" }); let meData = await meRes.json().catch(() => ({})); if (meData?.user?.id) { // 已登录:先校验 VIP,已是 VIP 则无需支付 const vipRes = await fetch(`/api/vip/check?email=${encodeURIComponent(meData.user.email)}`, { credentials: "include" }); const vipData = await vipRes.json().catch(() => ({})); if (vipData?.vip) { await refetch(); return; } startPay(meData.user.id); return; } const storedUser = getStoredUser(); const storedToken = getStoredToken(); if (storedUser?.id && storedToken) { await fetch("/api/auth/sync-session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: storedToken, record: storedUser }), credentials: "include", }).catch(() => null); meRes = await fetch("/api/auth/me", { credentials: "include" }); meData = await meRes.json().catch(() => ({})); if (meData?.user?.id) { const vipRes = await fetch(`/api/vip/check?email=${encodeURIComponent(meData.user.email)}`, { credentials: "include" }); const vipData = await vipRes.json().catch(() => ({})); if (vipData?.vip) { await refetch(); return; } startPay(meData.user.id); return; } } setAuthOpen(true); } finally { setPayRedirecting(false); } }; return (

{HERO_CONFIG.title}

{HERO_CONFIG.subtitle}

{HERO_CONFIG.stats.map((s) => (
{s.value}
{s.label}
))}
{paid && last ? ( 继续学习 → ) : paid ? ( 进入课程 → ) : ( )}
{paid && progress.completed > 0 && (
学习进度 {progress.completed}/{TOTAL_LESSONS} 节
)}
setAuthOpen(false)} onSuccess={() => { setAuthOpen(false); void refetch(); }} />
); }