forked from 77media/video-flow
修复: 使用页内请求重定向
This commit is contained in:
parent
ef428058c1
commit
e2eda2ddb8
@ -2,38 +2,75 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { TailwindSpinner } from "@/components/common/GlobalLoad";
|
import { TailwindSpinner } from "@/components/common/GlobalLoad";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
import { createCheckoutSession, buyTokens } from "@/lib/stripe";
|
||||||
|
|
||||||
export default function PayRedirectPage() {
|
export default function PayRedirectPage() {
|
||||||
const [status, setStatus] = React.useState<string>("Waiting for secure checkout redirect...");
|
const [status, setStatus] = React.useState<string>("Preparing checkout...");
|
||||||
const [error, setError] = React.useState<string>("");
|
const [error, setError] = React.useState<string>("");
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const handleMessage = (event: MessageEvent) => {
|
const type = (searchParams.get("type") || "").toLowerCase();
|
||||||
|
if (!type) {
|
||||||
|
setStatus("");
|
||||||
|
setError("Missing payment type.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirectTo = async () => {
|
||||||
try {
|
try {
|
||||||
if (event.origin !== window.location.origin) return;
|
if (type === "token") {
|
||||||
const data = event.data || {};
|
const amountStr = searchParams.get("amount");
|
||||||
if (data?.type === "redirect-to-payment" && typeof data?.url === "string") {
|
const pkg = searchParams.get("pkg") || "basic";
|
||||||
setStatus("Redirecting to Stripe Checkout...");
|
const amount = Number(amountStr);
|
||||||
window.location.href = data.url as string;
|
if (!amount || amount <= 0) {
|
||||||
} else if (data?.type === "redirect-error") {
|
throw new Error("Invalid token amount");
|
||||||
setError(typeof data?.message === "string" ? data.message : "Failed to create payment. Please close this page and try again.");
|
}
|
||||||
|
setStatus("Creating token purchase session...");
|
||||||
|
const resp = await buyTokens({ token_amount: amount, package_type: pkg });
|
||||||
|
if (resp?.successful && resp?.data?.checkout_url) {
|
||||||
|
setStatus("Redirecting to Stripe Checkout...");
|
||||||
|
window.location.href = resp.data.checkout_url as string;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(resp?.message || "Failed to create token checkout session");
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
setError("An error occurred while processing redirect info. Please close this page and try again.");
|
if (type === "subscription") {
|
||||||
|
const plan = searchParams.get("plan");
|
||||||
|
const billing = (searchParams.get("billing") || "month") as "month" | "year";
|
||||||
|
if (!plan) {
|
||||||
|
throw new Error("Missing plan name");
|
||||||
|
}
|
||||||
|
const currentUser = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
||||||
|
if (!currentUser?.id) {
|
||||||
|
throw new Error("Not logged in. Please sign in and try again.");
|
||||||
|
}
|
||||||
|
setStatus("Creating subscription session...");
|
||||||
|
const result = await createCheckoutSession({
|
||||||
|
user_id: String(currentUser.id),
|
||||||
|
plan_name: plan,
|
||||||
|
billing_cycle: billing,
|
||||||
|
});
|
||||||
|
if (result?.successful && result?.data?.checkout_url) {
|
||||||
|
setStatus("Redirecting to Stripe Checkout...");
|
||||||
|
window.location.href = result.data.checkout_url as string;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(result?.message || "Failed to create subscription session");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Unsupported payment type");
|
||||||
|
} catch (e: unknown) {
|
||||||
|
setStatus("");
|
||||||
|
setError(e instanceof Error ? e.message : "Failed to prepare checkout.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("message", handleMessage);
|
redirectTo();
|
||||||
const timeoutId = window.setTimeout(() => {
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
setStatus("");
|
}, [searchParams]);
|
||||||
setError("No redirect instruction received. It may be a network issue or the page was blocked. Please go back and try again.");
|
|
||||||
}, 15000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("message", handleMessage);
|
|
||||||
window.clearTimeout(timeoutId);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-alt="pay-redirect-page" className="min-h-screen w-full flex items-center justify-center bg-black text-white">
|
<div data-alt="pay-redirect-page" className="min-h-screen w-full flex items-center justify-center bg-black text-white">
|
||||||
|
|||||||
@ -85,54 +85,18 @@ function HomeModule5() {
|
|||||||
|
|
||||||
const handleSubscribe = async (planName: string) => {
|
const handleSubscribe = async (planName: string) => {
|
||||||
setLoadingPlan(planName);
|
setLoadingPlan(planName);
|
||||||
|
// 改为直接携带参数打开 pay-redirect,由其内部完成创建与跳转
|
||||||
// 先同步打开同域重定向页,避免拦截
|
const url = `/pay-redirect?type=subscription&plan=${encodeURIComponent(planName)}&billing=${encodeURIComponent(billingType)}`;
|
||||||
const redirectWindow = window.open('/pay-redirect', '_blank');
|
const win = window.open(url, '_blank');
|
||||||
if (!redirectWindow) {
|
// 通知当前窗口等待支付(显示loading模态框)
|
||||||
|
window.postMessage({
|
||||||
|
type: 'waiting-payment',
|
||||||
|
paymentType: 'subscription',
|
||||||
|
}, '*');
|
||||||
|
if (!win) {
|
||||||
setLoadingPlan(null);
|
setLoadingPlan(null);
|
||||||
throw new Error('Unable to open redirect window, please check popup settings');
|
throw new Error('Unable to open redirect window, please check popup settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const { createCheckoutSession } = await import("@/lib/stripe");
|
|
||||||
|
|
||||||
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
|
||||||
if (!User.id) {
|
|
||||||
throw new Error("Unable to obtain user ID, please log in again");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await createCheckoutSession({
|
|
||||||
user_id: String(User.id),
|
|
||||||
plan_name: planName,
|
|
||||||
billing_cycle: billingType,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.successful || !result.data?.checkout_url) {
|
|
||||||
throw new Error("create checkout session failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通知当前窗口等待支付(显示loading模态框)
|
|
||||||
window.postMessage({
|
|
||||||
type: 'waiting-payment',
|
|
||||||
paymentType: 'subscription',
|
|
||||||
}, '*');
|
|
||||||
|
|
||||||
// 通过 postMessage 通知新页面执行重定向
|
|
||||||
redirectWindow.postMessage({
|
|
||||||
type: 'redirect-to-payment',
|
|
||||||
url: result.data.checkout_url,
|
|
||||||
}, window.location.origin);
|
|
||||||
} catch (error) {
|
|
||||||
// 通知新页错误信息
|
|
||||||
try {
|
|
||||||
redirectWindow.postMessage({
|
|
||||||
type: 'redirect-error',
|
|
||||||
message: 'Failed to create checkout session',
|
|
||||||
}, window.location.origin);
|
|
||||||
} catch {}
|
|
||||||
setLoadingPlan(null);
|
|
||||||
throw new Error("create checkout session failed, please try again later");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -88,7 +88,7 @@ export function TopBar({ collapsed, isDesktop=true }: { collapsed: boolean, isDe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理Token购买(同域新页 + postMessage 方式重定向)
|
// 处理Token购买(改为携带参数打开 pay-redirect)
|
||||||
const handleBuyTokens = async (tokenAmount: number) => {
|
const handleBuyTokens = async (tokenAmount: number) => {
|
||||||
if (!currentUser?.id) {
|
if (!currentUser?.id) {
|
||||||
console.error("用户未登录");
|
console.error("用户未登录");
|
||||||
@ -99,52 +99,14 @@ export function TopBar({ collapsed, isDesktop=true }: { collapsed: boolean, isDe
|
|||||||
console.error("Token数量必须大于0");
|
console.error("Token数量必须大于0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 直接打开带参数的 pay-redirect,新窗口内自行创建会话并跳转
|
||||||
// 先同步打开同域新页面,避免被拦截
|
const url = `/pay-redirect?type=token&amount=${encodeURIComponent(tokenAmount)}&pkg=basic`;
|
||||||
const redirectWindow = window.open("/pay-redirect", "_blank");
|
window.open(url, "_blank");
|
||||||
if (!redirectWindow) {
|
// 通知当前窗口等待支付(显示loading模态框)
|
||||||
console.error("无法打开支付重定向页面,可能被浏览器拦截");
|
window.postMessage({
|
||||||
return;
|
type: 'waiting-payment',
|
||||||
}
|
paymentType: 'subscription',
|
||||||
|
}, '*');
|
||||||
setIsBuyingTokens(true);
|
|
||||||
try {
|
|
||||||
const response = await buyTokens({
|
|
||||||
token_amount: tokenAmount,
|
|
||||||
package_type: "basic"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.successful && response.data?.checkout_url) {
|
|
||||||
// 通知当前窗口等待支付,标识为Token购买
|
|
||||||
window.postMessage({
|
|
||||||
type: "waiting-payment",
|
|
||||||
paymentType: "token"
|
|
||||||
}, "*");
|
|
||||||
sessionStorage.setItem('session_id', response.data.session_id);
|
|
||||||
// 通过 postMessage 通知新页面进行重定向
|
|
||||||
redirectWindow.postMessage({
|
|
||||||
type: "redirect-to-payment",
|
|
||||||
url: response.data.checkout_url
|
|
||||||
}, window.location.origin);
|
|
||||||
} else {
|
|
||||||
console.error("创建Token购买失败:", response.message);
|
|
||||||
// 通知新页显示错误
|
|
||||||
redirectWindow.postMessage({
|
|
||||||
type: "redirect-error",
|
|
||||||
message: response.message || "创建支付失败"
|
|
||||||
}, window.location.origin);
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
console.error("Token购买失败:", error);
|
|
||||||
try {
|
|
||||||
redirectWindow.postMessage({
|
|
||||||
type: "redirect-error",
|
|
||||||
message: "网络或服务异常,请关闭此页重试"
|
|
||||||
}, window.location.origin);
|
|
||||||
} catch {}
|
|
||||||
} finally {
|
|
||||||
setIsBuyingTokens(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理自定义金额购买
|
// 处理自定义金额购买
|
||||||
|
|||||||
@ -1249,34 +1249,16 @@ function HomeModule5() {
|
|||||||
|
|
||||||
const handleSubscribe = async (planName: string) => {
|
const handleSubscribe = async (planName: string) => {
|
||||||
localStorage.setItem("callBackUrl", pathname);
|
localStorage.setItem("callBackUrl", pathname);
|
||||||
try {
|
// 改为直接携带参数打开 pay-redirect,由其内部完成创建与跳转
|
||||||
// 使用新的Checkout Session方案(更简单!)
|
const url = `/pay-redirect?type=subscription&plan=${encodeURIComponent(planName)}&billing=${encodeURIComponent(billingType)}`;
|
||||||
const { createCheckoutSession, redirectToCheckout } = await import(
|
const win = window.open(url, "_blank");
|
||||||
"@/lib/stripe"
|
// 通知当前窗口等待支付(显示loading模态框)
|
||||||
);
|
window.postMessage({
|
||||||
|
type: 'waiting-payment',
|
||||||
// 从localStorage获取当前用户信息
|
paymentType: 'subscription',
|
||||||
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
}, '*');
|
||||||
|
if (!win) {
|
||||||
if (!User.id) {
|
throw new Error("Unable to open redirect window, please check popup settings");
|
||||||
throw new Error("无法获取用户ID,请重新登录");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 创建Checkout Session
|
|
||||||
const result = await createCheckoutSession({
|
|
||||||
user_id: String(User.id),
|
|
||||||
plan_name: planName,
|
|
||||||
billing_cycle: billingType,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.successful || !result.data) {
|
|
||||||
throw new Error("create checkout session failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
setShowCallbackModal(true);
|
|
||||||
window.open(result.data.checkout_url, "_blank");
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error("create checkout session failed, please try again later");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user