fix(subscription): remove animations affecting stripe dialog

This commit is contained in:
2026-06-29 20:04:10 +08:00
parent e071fe48ec
commit 089871af3e
4 changed files with 121 additions and 164 deletions
@@ -2,26 +2,17 @@
position: fixed;
inset: 0;
z-index: 70;
display: block;
height: 100dvh;
padding:
max(24px, env(safe-area-inset-top))
20px
max(20px, env(safe-area-inset-bottom));
overflow-y: auto;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: rgba(0, 0, 0, 0.5);
overscroll-behavior: contain;
}
.dialog {
width: 100%;
max-width: 420px;
max-height: calc(
100dvh
- max(48px, env(safe-area-inset-top))
- max(20px, env(safe-area-inset-bottom))
);
margin: clamp(0px, 6dvh, 48px) auto 0;
max-height: calc(100vh - 40px);
overflow-y: auto;
border-radius: 32px;
background: var(--color-page-background, #ffffff);
@@ -13,6 +13,7 @@ import {
} from "@/stores/payment/payment-context";
import { AppEnvUtil, Logger, Result } from "@/utils";
import { StripePaymentDialog } from "./stripe-payment-dialog";
import dialogStyles from "./stripe-payment-dialog.module.css";
import { SubscriptionCtaButton } from "./subscription-cta-button";
import styles from "./subscription-cta-button.module.css";
@@ -34,6 +35,9 @@ export function SubscriptionCheckoutButton({
const payment = usePaymentState();
const paymentDispatch = usePaymentDispatch();
const launchedNonceRef = useRef(0);
const [hiddenStripeClientSecret, setHiddenStripeClientSecret] = useState<
string | null
>(null);
const [isConfirmingEzpay, setIsConfirmingEzpay] = useState(false);
useEffect(() => {
@@ -94,7 +98,7 @@ export function SubscriptionCheckoutButton({
payment.isCreatingOrder ||
payment.isPollingOrder;
const readyLabel =
subscriptionType === "topup" ? "Pay and Top Up" : "Pay and Activate";
subscriptionType === "topup" ? "Pay and Top Up" : "Pay and Activiate";
const agreementLabel =
subscriptionType === "topup"
? "Confirm the agreement and Top Up"
@@ -110,9 +114,32 @@ export function SubscriptionCheckoutButton({
const handleClick = () => {
if (disabled || isLoading) return;
setIsConfirmingEzpay(false);
setHiddenStripeClientSecret(null);
paymentDispatch({ type: "PaymentCreateOrderSubmitted" });
};
const handleStripeClose = () => {
if (stripeClientSecret) {
setHiddenStripeClientSecret(stripeClientSecret);
}
if (payment.orderStatus !== "paid") {
paymentDispatch({ type: "PaymentReset" });
}
};
const handleStripeConfirmed = () => {
if (stripeClientSecret) {
setHiddenStripeClientSecret(stripeClientSecret);
}
};
const stripeClientSecret = payment.payParams
? getStripeClientSecret(payment.payParams)
: null;
const shouldShowStripeDialog =
stripeClientSecret !== null &&
stripeClientSecret !== hiddenStripeClientSecret &&
!payment.isPaid;
const ezpayPaymentUrl = payment.payParams
? getPaymentUrl(payment.payParams)
: null;
@@ -181,6 +208,13 @@ export function SubscriptionCheckoutButton({
onConfirm={handleEzpayConfirm}
/>
) : null}
{shouldShowStripeDialog ? (
<StripePaymentDialog
clientSecret={stripeClientSecret}
onClose={handleStripeClose}
onConfirmed={handleStripeConfirmed}
/>
) : null}
</>
);
}
@@ -332,7 +366,7 @@ function EzpayRedirectConfirmDialog({
);
}
export function getStripeClientSecret(
function getStripeClientSecret(
payParams: Record<string, unknown>,
): string | null {
const provider = payParams.provider;
@@ -6,7 +6,6 @@
radial-gradient(circle at 8% 4%, rgba(255, 255, 255, 0.95) 0 90px, transparent 160px),
linear-gradient(180deg, #fff9fb 0%, #fcf3f4 52%, #fffefe 100%);
padding: 18px 20px 10px;
animation: pageEnter 360ms ease-out both;
}
.header {
@@ -24,7 +23,6 @@
flex-direction: column;
gap: 18px;
margin-top: 14px;
animation: stackEnter 420ms ease-out 80ms both;
}
.userSlot {
@@ -70,12 +68,10 @@
.paymentMethodSlot {
margin-top: 22px;
animation: stackEnter 420ms ease-out 150ms both;
}
.ctaSlot {
margin-top: 22px;
animation: stackEnter 420ms ease-out 190ms both;
}
.agreementSlot {
@@ -96,27 +92,3 @@
.agreementLink:hover {
text-decoration: underline;
}
@keyframes pageEnter {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes stackEnter {
from {
opacity: 0;
transform: translateY(14px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@@ -13,14 +13,12 @@ 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 {
@@ -51,9 +49,6 @@ 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";
@@ -161,16 +156,6 @@ 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);
@@ -184,21 +169,6 @@ 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 ?? "";
@@ -242,7 +212,6 @@ export function SubscriptionScreen({
]);
return (
<>
<MobileShell>
<div className={styles.shell}>
<header className={styles.header}>
@@ -336,14 +305,5 @@ export function SubscriptionScreen({
/>
</div>
</MobileShell>
{shouldShowStripeDialog ? (
<StripePaymentDialog
clientSecret={stripeClientSecret}
onClose={handleStripeClose}
onConfirmed={handleStripeConfirmed}
/>
) : null}
</>
);
}