s'
This commit is contained in:
127
app/page.tsx
127
app/page.tsx
@@ -8,6 +8,7 @@ import { usePayStatusPoll } from "@/app/lib/usePayStatusPoll";
|
||||
import { VipLayout } from "@/app/vip/components/VipLayout";
|
||||
import { LandingPage } from "@/app/vip/components/LandingPage";
|
||||
import { DashboardPage } from "@/app/vip/components/DashboardPage";
|
||||
import { PayAuthModal } from "@/app/vip/components/landing/PayAuthModal";
|
||||
import styles from "@/app/vip/components/vip.module.css";
|
||||
|
||||
const PB_URL =
|
||||
@@ -168,7 +169,19 @@ export default function Home() {
|
||||
setUserName(name);
|
||||
}, []);
|
||||
|
||||
const getOrCreateUserId = useCallback(() => {
|
||||
const getOrCreateUserId = useCallback(async () => {
|
||||
// 优先使用 PocketBase 用户 ID(已登录时)
|
||||
try {
|
||||
const meRes = await fetch("/api/auth/me");
|
||||
const meData = await meRes.json();
|
||||
if (meData?.user?.id) {
|
||||
const pbUserId = meData.user.id;
|
||||
setStorage("userId", pbUserId);
|
||||
return pbUserId;
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
let userId = getStorage("userId");
|
||||
if (userId?.startsWith("{") && userId.includes("data")) {
|
||||
try {
|
||||
@@ -215,6 +228,37 @@ export default function Home() {
|
||||
[savePaidType, saveUserName]
|
||||
);
|
||||
|
||||
/** 会员账号恢复:通过邮箱+密码验证,关联 users 后检查 site_vip / payments */
|
||||
const checkVerifyByEmail = useCallback(
|
||||
async (email: string, password: string): Promise<boolean> => {
|
||||
try {
|
||||
const { pbLogin, pbSaveAuth } = await import("@/app/lib/pocketbase");
|
||||
const result = await pbLogin(email, password);
|
||||
pbSaveAuth(result.token, result.record);
|
||||
await fetch("/api/auth/sync-session", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ token: result.token, record: result.record }),
|
||||
});
|
||||
const userId = result.record.id;
|
||||
const vipRes = await fetch("/api/vip/check");
|
||||
const vipData = await vipRes.json();
|
||||
if (vipData?.vip) {
|
||||
setStorage("userId", userId);
|
||||
savePaidType("vip");
|
||||
saveUserName(email);
|
||||
return true;
|
||||
}
|
||||
const found = await checkPaymentFromPB(userId);
|
||||
if (found) return true;
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[checkPaymentFromPB, savePaidType, saveUserName]
|
||||
);
|
||||
|
||||
const clearAllStorage = useCallback(() => {
|
||||
try {
|
||||
if (typeof window === "undefined") return;
|
||||
@@ -236,8 +280,10 @@ export default function Home() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handlePay = useCallback(async () => {
|
||||
const userId = getOrCreateUserId();
|
||||
const [authForPayOpen, setAuthForPayOpen] = useState(false);
|
||||
|
||||
const doPay = useCallback(async () => {
|
||||
const userId = await getOrCreateUserId();
|
||||
const returnUrl = `${window.location.origin}/paid`;
|
||||
const env = getPayEnv();
|
||||
const device = getDeviceFromEnv(env);
|
||||
@@ -259,6 +305,20 @@ export default function Home() {
|
||||
}
|
||||
}, [getOrCreateUserId]);
|
||||
|
||||
const handlePay = useCallback(async () => {
|
||||
try {
|
||||
const meRes = await fetch("/api/auth/me");
|
||||
const meData = await meRes.json();
|
||||
if (meData?.user?.id) {
|
||||
doPay();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
setAuthForPayOpen(true);
|
||||
}, [doPay]);
|
||||
|
||||
const handleVerifySuccess = useCallback(() => {
|
||||
window.location.reload();
|
||||
}, []);
|
||||
@@ -297,7 +357,7 @@ export default function Home() {
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
getOrCreateUserId();
|
||||
await getOrCreateUserId();
|
||||
|
||||
const localType = getStorage("paidType");
|
||||
const localUserName = getStorage("userName");
|
||||
@@ -308,6 +368,26 @@ export default function Home() {
|
||||
return;
|
||||
}
|
||||
|
||||
// SSO: 优先检查根域 Cookie(跨站登录态)
|
||||
try {
|
||||
const meRes = await fetch("/api/auth/me");
|
||||
const meData = await meRes.json();
|
||||
if (meData?.user && meData?.token) {
|
||||
const { pbSaveAuth } = await import("@/app/lib/pocketbase");
|
||||
pbSaveAuth(meData.token, { id: meData.user.id, email: meData.user.email });
|
||||
const vipRes = await fetch("/api/vip/check");
|
||||
const vipData = await vipRes.json();
|
||||
if (vipData?.vip) {
|
||||
savePaidType("vip");
|
||||
saveUserName(meData.user.email || meData.user.id);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
const userId = getStorage("userId");
|
||||
if (userId) {
|
||||
const found = await checkPaymentFromPB(userId);
|
||||
@@ -355,17 +435,34 @@ export default function Home() {
|
||||
);
|
||||
}
|
||||
|
||||
const handleLogout = useCallback(async () => {
|
||||
const { pbLogout } = await import("@/app/lib/pocketbase");
|
||||
await pbLogout();
|
||||
clearAllStorage();
|
||||
}, [clearAllStorage]);
|
||||
|
||||
return (
|
||||
<VipLayout isLoggedIn={isLoggedIn} userName={userName}>
|
||||
{isLoggedIn ? (
|
||||
<DashboardPage userName={userName} />
|
||||
) : (
|
||||
<LandingPage
|
||||
onJoin={handlePay}
|
||||
onVerify={checkPaymentFromPB}
|
||||
onVerifySuccess={handleVerifySuccess}
|
||||
/>
|
||||
)}
|
||||
</VipLayout>
|
||||
<>
|
||||
<VipLayout isLoggedIn={isLoggedIn} userName={userName} onLogout={handleLogout}>
|
||||
{isLoggedIn ? (
|
||||
<DashboardPage userName={userName} />
|
||||
) : (
|
||||
<LandingPage
|
||||
onJoin={handlePay}
|
||||
onVerify={checkPaymentFromPB}
|
||||
onVerifyByEmail={checkVerifyByEmail}
|
||||
onVerifySuccess={handleVerifySuccess}
|
||||
/>
|
||||
)}
|
||||
</VipLayout>
|
||||
<PayAuthModal
|
||||
open={authForPayOpen}
|
||||
onClose={() => setAuthForPayOpen(false)}
|
||||
onSuccess={() => {
|
||||
setAuthForPayOpen(false);
|
||||
doPay();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user