fix(subscription): render stripe dialog at screen root
This commit is contained in:
@@ -13,12 +13,14 @@ import { useUserDispatch } from "@/stores/user/user-context";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
|
||||
import {
|
||||
getStripeClientSecret,
|
||||
SubscriptionBackLink,
|
||||
SubscriptionCheckoutButton,
|
||||
SubscriptionCoinsOfferSection,
|
||||
SubscriptionPaymentMethod,
|
||||
SubscriptionPaymentSuccessDialog,
|
||||
SubscriptionVipOfferSection,
|
||||
StripePaymentDialog,
|
||||
} from "./components";
|
||||
import styles from "./components/subscription-screen.module.css";
|
||||
import {
|
||||
@@ -49,6 +51,9 @@ export function SubscriptionScreen({
|
||||
const refreshedPaidOrderRef = useRef<string | null>(null);
|
||||
const resumedPendingOrderRef = useRef<string | null>(null);
|
||||
const successDialogShownOrderRef = useRef<string | null>(null);
|
||||
const [hiddenStripeDialogKey, setHiddenStripeDialogKey] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [showPaymentSuccessDialog, setShowPaymentSuccessDialog] =
|
||||
useState(false);
|
||||
const canSubscribeVip = subscriptionType === "vip";
|
||||
@@ -156,6 +161,16 @@ export function SubscriptionScreen({
|
||||
payment.isPollingOrder;
|
||||
const canActivate =
|
||||
selectedPlan !== null && payment.agreed && !isPaymentBusy;
|
||||
const stripeClientSecret = payment.payParams
|
||||
? getStripeClientSecret(payment.payParams)
|
||||
: null;
|
||||
const stripeDialogKey = stripeClientSecret
|
||||
? `${payment.launchNonce}:${stripeClientSecret}`
|
||||
: null;
|
||||
const shouldShowStripeDialog =
|
||||
stripeClientSecret !== null &&
|
||||
stripeDialogKey !== hiddenStripeDialogKey &&
|
||||
!payment.isPaid;
|
||||
|
||||
const finishPaymentSuccessClose = () => {
|
||||
setShowPaymentSuccessDialog(false);
|
||||
@@ -169,6 +184,21 @@ export function SubscriptionScreen({
|
||||
finishPaymentSuccessClose();
|
||||
};
|
||||
|
||||
const handleStripeClose = () => {
|
||||
if (stripeDialogKey) {
|
||||
setHiddenStripeDialogKey(stripeDialogKey);
|
||||
}
|
||||
if (payment.orderStatus !== "paid") {
|
||||
paymentDispatch({ type: "PaymentReset" });
|
||||
}
|
||||
};
|
||||
|
||||
const handleStripeConfirmed = () => {
|
||||
if (stripeDialogKey) {
|
||||
setHiddenStripeDialogKey(stripeDialogKey);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (canSubscribeVip) {
|
||||
const firstVipPlanId = vipOfferPlans[0]?.id ?? "";
|
||||
@@ -212,16 +242,28 @@ export function SubscriptionScreen({
|
||||
]);
|
||||
|
||||
return (
|
||||
<MobileShell>
|
||||
<div className={styles.shell}>
|
||||
<header className={styles.header}>
|
||||
<SubscriptionBackLink className={styles.backSlot} />
|
||||
</header>
|
||||
<>
|
||||
<MobileShell>
|
||||
<div className={styles.shell}>
|
||||
<header className={styles.header}>
|
||||
<SubscriptionBackLink className={styles.backSlot} />
|
||||
</header>
|
||||
|
||||
<div className={styles.offerStack}>
|
||||
{canSubscribeVip ? (
|
||||
<SubscriptionVipOfferSection
|
||||
plans={vipOfferPlans}
|
||||
<div className={styles.offerStack}>
|
||||
{canSubscribeVip ? (
|
||||
<SubscriptionVipOfferSection
|
||||
plans={vipOfferPlans}
|
||||
selectedPlanId={payment.selectedPlanId || selectedPlan?.id || null}
|
||||
onSelectPlan={(planId) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentPlanSelected",
|
||||
planId,
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<SubscriptionCoinsOfferSection
|
||||
plans={directCoinsPlans}
|
||||
selectedPlanId={payment.selectedPlanId || selectedPlan?.id || null}
|
||||
onSelectPlan={(planId) =>
|
||||
paymentDispatch({
|
||||
@@ -230,80 +272,78 @@ export function SubscriptionScreen({
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<SubscriptionCoinsOfferSection
|
||||
plans={directCoinsPlans}
|
||||
selectedPlanId={payment.selectedPlanId || selectedPlan?.id || null}
|
||||
onSelectPlan={(planId) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentPlanSelected",
|
||||
planId,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className={styles.paymentMethodSlot}>
|
||||
<SubscriptionPaymentMethod
|
||||
value={payment.payChannel}
|
||||
disabled={isPaymentBusy}
|
||||
onChange={(payChannel) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentPayChannelChanged",
|
||||
payChannel,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</section>
|
||||
<section className={styles.paymentMethodSlot}>
|
||||
<SubscriptionPaymentMethod
|
||||
value={payment.payChannel}
|
||||
disabled={isPaymentBusy}
|
||||
onChange={(payChannel) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentPayChannelChanged",
|
||||
payChannel,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<div className={styles.ctaSlot}>
|
||||
<SubscriptionCheckoutButton
|
||||
disabled={!canActivate}
|
||||
<div className={styles.ctaSlot}>
|
||||
<SubscriptionCheckoutButton
|
||||
disabled={!canActivate}
|
||||
subscriptionType={subscriptionType}
|
||||
returnTo={returnTo}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.agreementSlot}>
|
||||
<Checkbox
|
||||
checked={payment.agreed}
|
||||
onChange={(agreed) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentAgreementChanged",
|
||||
agreed,
|
||||
})
|
||||
}
|
||||
label={
|
||||
<span className={styles.agreementLabel}>
|
||||
I agree to the{" "}
|
||||
<a
|
||||
href={AppConstants.privacyPolicyUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.agreementLink}
|
||||
>
|
||||
VIP Membership Benefits Agreement
|
||||
</a>{" "}
|
||||
and{" "}
|
||||
<a
|
||||
href={AppConstants.termsOfServiceUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.agreementLink}
|
||||
>
|
||||
Automatic renewal Agreement
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SubscriptionPaymentSuccessDialog
|
||||
open={showPaymentSuccessDialog}
|
||||
subscriptionType={subscriptionType}
|
||||
returnTo={returnTo}
|
||||
onClose={handlePaymentSuccessClose}
|
||||
/>
|
||||
</div>
|
||||
</MobileShell>
|
||||
|
||||
<div className={styles.agreementSlot}>
|
||||
<Checkbox
|
||||
checked={payment.agreed}
|
||||
onChange={(agreed) =>
|
||||
paymentDispatch({
|
||||
type: "PaymentAgreementChanged",
|
||||
agreed,
|
||||
})
|
||||
}
|
||||
label={
|
||||
<span className={styles.agreementLabel}>
|
||||
I agree to the{" "}
|
||||
<a
|
||||
href={AppConstants.privacyPolicyUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.agreementLink}
|
||||
>
|
||||
VIP Membership Benefits Agreement
|
||||
</a>{" "}
|
||||
and{" "}
|
||||
<a
|
||||
href={AppConstants.termsOfServiceUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.agreementLink}
|
||||
>
|
||||
Automatic renewal Agreement
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SubscriptionPaymentSuccessDialog
|
||||
open={showPaymentSuccessDialog}
|
||||
subscriptionType={subscriptionType}
|
||||
onClose={handlePaymentSuccessClose}
|
||||
{shouldShowStripeDialog ? (
|
||||
<StripePaymentDialog
|
||||
clientSecret={stripeClientSecret}
|
||||
onClose={handleStripeClose}
|
||||
onConfirmed={handleStripeConfirmed}
|
||||
/>
|
||||
</div>
|
||||
</MobileShell>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user