|
|
@@ -3,91 +3,199 @@ import { useCallback } from 'react';
|
|
|
import { Trans, useTranslation } from 'react-i18next';
|
|
|
|
|
|
import LoginForm from '@/components/LoginForm';
|
|
|
+import { PayUrlShowType } from '@/defines';
|
|
|
import { useAppUrls } from '@/hooks/useAppUrls';
|
|
|
import { dialogModel } from '@/models/dialogModel';
|
|
|
import { fetchPayOrderCreate } from '@/services/config';
|
|
|
import { getToken } from '@/utils/authUtils';
|
|
|
import { currentUnixTimestamp } from '@/utils/timeUtils';
|
|
|
|
|
|
+import { PayQrContent } from './components/OrderSummary/PayQrContent';
|
|
|
import { PayWaitingContent } from './components/OrderSummary/PayWaitingContent';
|
|
|
import type { Plan } from './useService';
|
|
|
|
|
|
const ORDER_TYPE_PLAN = 1;
|
|
|
|
|
|
+type PayOrder = { orderId: string; payUrl: string; showType: PayUrlShowType };
|
|
|
+
|
|
|
export interface UseActionReturn {
|
|
|
handlePayNow: (plan: Plan, payMethod: string) => void;
|
|
|
}
|
|
|
|
|
|
-export function useAction(): UseActionReturn {
|
|
|
+function useLoginDialog() {
|
|
|
const { t } = useTranslation();
|
|
|
const { openDialog, closeDialog } = dialogModel.useModel();
|
|
|
const { deeplinkUrl, downloadUrlByPlatform } = useAppUrls();
|
|
|
|
|
|
+ return useCallback(() => {
|
|
|
+ const id = openDialog({
|
|
|
+ title: t('pages.pricing.payFlow.loginTitle'),
|
|
|
+ content: (
|
|
|
+ <div className="flex flex-col gap-2">
|
|
|
+ <p className="text-white/80 text-sm mb-2">
|
|
|
+ <Trans
|
|
|
+ i18nKey="pages.pricing.payFlow.loginPrompt"
|
|
|
+ components={{
|
|
|
+ linkText: (() => {
|
|
|
+ const Wrap = ({
|
|
|
+ children,
|
|
|
+ }: {
|
|
|
+ children?: React.ReactNode;
|
|
|
+ }) =>
|
|
|
+ deeplinkUrl ? (
|
|
|
+ <a
|
|
|
+ href={deeplinkUrl}
|
|
|
+ className="text-[#0EA5E9] hover:underline"
|
|
|
+ target="_blank"
|
|
|
+ rel="noopener noreferrer"
|
|
|
+ >
|
|
|
+ {children}
|
|
|
+ </a>
|
|
|
+ ) : (
|
|
|
+ <span>{children}</span>
|
|
|
+ );
|
|
|
+ return <Wrap />;
|
|
|
+ })(),
|
|
|
+ downloadLink: (() => {
|
|
|
+ const Wrap = ({
|
|
|
+ children,
|
|
|
+ }: {
|
|
|
+ children?: React.ReactNode;
|
|
|
+ }) =>
|
|
|
+ downloadUrlByPlatform ? (
|
|
|
+ <a
|
|
|
+ href={downloadUrlByPlatform}
|
|
|
+ className="text-[#0EA5E9] hover:underline"
|
|
|
+ target="_blank"
|
|
|
+ rel="noopener noreferrer"
|
|
|
+ >
|
|
|
+ {children}
|
|
|
+ </a>
|
|
|
+ ) : (
|
|
|
+ <span>{children}</span>
|
|
|
+ );
|
|
|
+ return <Wrap />;
|
|
|
+ })(),
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </p>
|
|
|
+ <LoginForm onSuccess={() => closeDialog(id)} />
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ maskClosable: false,
|
|
|
+ closeable: true,
|
|
|
+ });
|
|
|
+ }, [t, openDialog, closeDialog, deeplinkUrl, downloadUrlByPlatform]);
|
|
|
+}
|
|
|
+
|
|
|
+function useQrPayDialog() {
|
|
|
+ const { t } = useTranslation();
|
|
|
+ const { openDialog, closeDialog } = dialogModel.useModel();
|
|
|
+
|
|
|
+ return useCallback(
|
|
|
+ (order: PayOrder) => {
|
|
|
+ const qrDialogId = openDialog({
|
|
|
+ title: t('pages.pricing.payFlow.waitingTitle'),
|
|
|
+ content: (
|
|
|
+ <PayQrContent
|
|
|
+ orderId={order.orderId}
|
|
|
+ payUrl={order.payUrl}
|
|
|
+ onClose={() => closeDialog(qrDialogId)}
|
|
|
+ />
|
|
|
+ ),
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ label: t('pages.pricing.payFlow.closeWaiting'),
|
|
|
+ variant: 'secondary' as const,
|
|
|
+ onClick: (
|
|
|
+ _e: React.MouseEvent<HTMLButtonElement>,
|
|
|
+ dialogId: string
|
|
|
+ ) => {
|
|
|
+ closeDialog(dialogId);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ maskClosable: false,
|
|
|
+ closeable: true,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ [t, openDialog, closeDialog],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function useJumpToPayDialog() {
|
|
|
+ const { t } = useTranslation();
|
|
|
+ const { openDialog, closeDialog } = dialogModel.useModel();
|
|
|
+
|
|
|
+ return useCallback(
|
|
|
+ (order: PayOrder) => {
|
|
|
+ openDialog({
|
|
|
+ title: t('pages.pricing.payFlow.goToPayTitle'),
|
|
|
+ content: (
|
|
|
+ <p className="text-white/90 text-sm leading-[1.43]">
|
|
|
+ {t('pages.pricing.payFlow.goToPayDesc')}
|
|
|
+ </p>
|
|
|
+ ),
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ label: t('pages.pricing.payFlow.goToPayButton'),
|
|
|
+ variant: 'primary' as const,
|
|
|
+ onClick: (
|
|
|
+ _e: React.MouseEvent<HTMLButtonElement>,
|
|
|
+ dialogId: string
|
|
|
+ ) => {
|
|
|
+ window.open(order.payUrl, '_blank');
|
|
|
+ closeDialog(dialogId);
|
|
|
+ const waitId = openDialog({
|
|
|
+ title: t('pages.pricing.payFlow.waitingTitle'),
|
|
|
+ content: (
|
|
|
+ <PayWaitingContent
|
|
|
+ orderId={order.orderId}
|
|
|
+ onClose={() => closeDialog(waitId)}
|
|
|
+ />
|
|
|
+ ),
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ label: t('pages.pricing.payFlow.closeWaiting'),
|
|
|
+ variant: 'secondary' as const,
|
|
|
+ onClick: (
|
|
|
+ _e: React.MouseEvent<HTMLButtonElement>,
|
|
|
+ d: string
|
|
|
+ ) => {
|
|
|
+ closeDialog(d);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ maskClosable: false,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ maskClosable: false,
|
|
|
+ closeable: true,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ [t, openDialog, closeDialog],
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+export function useAction(): UseActionReturn {
|
|
|
+ const openLoginDialog = useLoginDialog();
|
|
|
+ const openQrPayDialog = useQrPayDialog();
|
|
|
+ const openJumpToPayDialog = useJumpToPayDialog();
|
|
|
+
|
|
|
const handlePayNow = useCallback(
|
|
|
(selectedPlan: Plan, selectedPayMethod: string) => {
|
|
|
const token = getToken();
|
|
|
const expired =
|
|
|
!token?.accessExpires || (token.accessExpires ?? 0) - currentUnixTimestamp() <= 0;
|
|
|
if (!token?.accessToken || expired) {
|
|
|
- const id = openDialog({
|
|
|
- title: t('pages.pricing.payFlow.loginTitle'),
|
|
|
- content: (
|
|
|
- <div className="flex flex-col gap-2">
|
|
|
- <p className="text-white/80 text-sm mb-2">
|
|
|
- <Trans
|
|
|
- i18nKey="pages.pricing.payFlow.loginPrompt"
|
|
|
- components={{
|
|
|
- linkText: (() => {
|
|
|
- const Wrap = ({
|
|
|
- children,
|
|
|
- }: {
|
|
|
- children?: React.ReactNode;
|
|
|
- }) =>
|
|
|
- deeplinkUrl ? (
|
|
|
- <a
|
|
|
- href={deeplinkUrl}
|
|
|
- className="text-[#0EA5E9] hover:underline"
|
|
|
- target="_blank"
|
|
|
- rel="noopener noreferrer"
|
|
|
- >
|
|
|
- {children}
|
|
|
- </a>
|
|
|
- ) : (
|
|
|
- <span>{children}</span>
|
|
|
- );
|
|
|
- return <Wrap />;
|
|
|
- })(),
|
|
|
- downloadLink: (() => {
|
|
|
- const Wrap = ({
|
|
|
- children,
|
|
|
- }: {
|
|
|
- children?: React.ReactNode;
|
|
|
- }) =>
|
|
|
- downloadUrlByPlatform ? (
|
|
|
- <a
|
|
|
- href={downloadUrlByPlatform}
|
|
|
- className="text-[#0EA5E9] hover:underline"
|
|
|
- target="_blank"
|
|
|
- rel="noopener noreferrer"
|
|
|
- >
|
|
|
- {children}
|
|
|
- </a>
|
|
|
- ) : (
|
|
|
- <span>{children}</span>
|
|
|
- );
|
|
|
- return <Wrap />;
|
|
|
- })(),
|
|
|
- }}
|
|
|
- />
|
|
|
- </p>
|
|
|
- <LoginForm onSuccess={() => closeDialog(id)} />
|
|
|
- </div>
|
|
|
- ),
|
|
|
- maskClosable: true,
|
|
|
- });
|
|
|
+ // 如果用户未登录,则打开登录对话框
|
|
|
+ openLoginDialog();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // 创建订单
|
|
|
fetchPayOrderCreate({
|
|
|
orderType: ORDER_TYPE_PLAN,
|
|
|
payType: selectedPayMethod,
|
|
|
@@ -97,54 +205,17 @@ export function useAction(): UseActionReturn {
|
|
|
const order = res?.data?.userPayOrder;
|
|
|
if (!order?.payUrl || !order?.orderId) return;
|
|
|
|
|
|
- openDialog({
|
|
|
- title: t('pages.pricing.payFlow.goToPayTitle'),
|
|
|
- content: (
|
|
|
- <p className="text-white/90 text-sm leading-[1.43]">
|
|
|
- {t('pages.pricing.payFlow.goToPayDesc')}
|
|
|
- </p>
|
|
|
- ),
|
|
|
- buttons: [
|
|
|
- {
|
|
|
- label: t('pages.pricing.payFlow.goToPayButton'),
|
|
|
- variant: 'primary',
|
|
|
- onClick: (
|
|
|
- _e: React.MouseEvent<HTMLButtonElement>,
|
|
|
- dialogId: string
|
|
|
- ) => {
|
|
|
- window.open(order.payUrl, '_blank');
|
|
|
- closeDialog(dialogId);
|
|
|
- const waitId = openDialog({
|
|
|
- title: t('pages.pricing.payFlow.waitingTitle'),
|
|
|
- content: (
|
|
|
- <PayWaitingContent
|
|
|
- orderId={order.orderId}
|
|
|
- onClose={() => closeDialog(waitId)}
|
|
|
- />
|
|
|
- ),
|
|
|
- buttons: [
|
|
|
- {
|
|
|
- label: t('pages.pricing.payFlow.closeWaiting'),
|
|
|
- variant: 'secondary',
|
|
|
- onClick: (
|
|
|
- _e: React.MouseEvent<HTMLButtonElement>,
|
|
|
- dialogId: string
|
|
|
- ) => {
|
|
|
- closeDialog(dialogId);
|
|
|
- },
|
|
|
- },
|
|
|
- ],
|
|
|
- maskClosable: false,
|
|
|
- });
|
|
|
- },
|
|
|
- },
|
|
|
- ],
|
|
|
- maskClosable: true,
|
|
|
- });
|
|
|
+ if (order.showType === PayUrlShowType.SHOW_QR_CODE) {
|
|
|
+ // 如果订单支付地址的显示类型为二维码,则打开二维码支付对话框
|
|
|
+ openQrPayDialog(order);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果订单支付地址的显示类型为跳转,则跳转到支付地址并打开等待支付对话框
|
|
|
+ openJumpToPayDialog(order);
|
|
|
})
|
|
|
.catch(() => {});
|
|
|
},
|
|
|
- [t, openDialog, closeDialog, deeplinkUrl, downloadUrlByPlatform]
|
|
|
+ [openLoginDialog, openQrPayDialog, openJumpToPayDialog],
|
|
|
);
|
|
|
|
|
|
return {
|