This commit is contained in:
parent
17413303e4
commit
c7638f240a
|
|
@ -10,9 +10,67 @@ const PAY_METHOD_LIST = [
|
|||
|
||||
const ORDER_POLLING_INTERVAL = 2000
|
||||
const ORDER_POLLING_MAX_COUNT = 60
|
||||
const PENDING_PAYMENT_STORAGE_KEY = 'pending-payment-order'
|
||||
const PENDING_PAYMENT_MAX_AGE = ORDER_POLLING_INTERVAL * ORDER_POLLING_MAX_COUNT
|
||||
|
||||
type PayMethodInfo = (typeof PAY_METHOD_LIST)[number]
|
||||
|
||||
type PendingPayment = {
|
||||
expiresAt: number
|
||||
orderId: string
|
||||
}
|
||||
|
||||
function getPendingPayment(): PendingPayment | null {
|
||||
try {
|
||||
const rawPendingPayment = window.localStorage.getItem(PENDING_PAYMENT_STORAGE_KEY)
|
||||
|
||||
if (!rawPendingPayment) {
|
||||
return null
|
||||
}
|
||||
|
||||
const pendingPayment: unknown = JSON.parse(rawPendingPayment)
|
||||
if (
|
||||
!pendingPayment ||
|
||||
typeof pendingPayment !== 'object' ||
|
||||
typeof (pendingPayment as PendingPayment).orderId !== 'string' ||
|
||||
typeof (pendingPayment as PendingPayment).expiresAt !== 'number' ||
|
||||
(pendingPayment as PendingPayment).expiresAt <= Date.now()
|
||||
) {
|
||||
window.localStorage.removeItem(PENDING_PAYMENT_STORAGE_KEY)
|
||||
return null
|
||||
}
|
||||
|
||||
return pendingPayment as PendingPayment
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function savePendingPayment(orderId: string) {
|
||||
try {
|
||||
const pendingPayment: PendingPayment = {
|
||||
orderId,
|
||||
expiresAt: Date.now() + PENDING_PAYMENT_MAX_AGE,
|
||||
}
|
||||
|
||||
window.localStorage.setItem(PENDING_PAYMENT_STORAGE_KEY, JSON.stringify(pendingPayment))
|
||||
} catch {
|
||||
// The current page can still poll when browser storage is unavailable.
|
||||
}
|
||||
}
|
||||
|
||||
function clearPendingPayment(orderId?: string) {
|
||||
try {
|
||||
const pendingPayment = getPendingPayment()
|
||||
|
||||
if (!orderId || !pendingPayment || pendingPayment.orderId === orderId) {
|
||||
window.localStorage.removeItem(PENDING_PAYMENT_STORAGE_KEY)
|
||||
}
|
||||
} catch {
|
||||
// Ignore storage cleanup failures.
|
||||
}
|
||||
}
|
||||
|
||||
function getSupportedPayMethods(goods?: GoodsItem) {
|
||||
if (!goods?.pay_type) {
|
||||
return []
|
||||
|
|
@ -58,6 +116,7 @@ function PayPage() {
|
|||
const cancelPaymentFlow = useCallback(() => {
|
||||
paymentAttemptRef.current += 1
|
||||
stopOrderPolling()
|
||||
clearPendingPayment()
|
||||
|
||||
if (isMountedRef.current) {
|
||||
setIsPaying(false)
|
||||
|
|
@ -121,6 +180,8 @@ function PayPage() {
|
|||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true
|
||||
|
||||
return () => {
|
||||
isMountedRef.current = false
|
||||
stopOrderPolling()
|
||||
|
|
@ -142,7 +203,11 @@ function PayPage() {
|
|||
const hasSelectionChanged =
|
||||
previousSelection.planId !== selectedPlanId || previousSelection.payType !== selectedPayType
|
||||
|
||||
if (isPaying && hasSelectionChanged) {
|
||||
const hasCompleteSelection = Boolean(
|
||||
previousSelection.planId && previousSelection.payType && selectedPlanId && selectedPayType,
|
||||
)
|
||||
|
||||
if (isPaying && hasCompleteSelection && hasSelectionChanged) {
|
||||
cancelPaymentFlow()
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +238,7 @@ function PayPage() {
|
|||
|
||||
if (data.status === '2') {
|
||||
stopOrderPolling()
|
||||
clearPendingPayment(orderId)
|
||||
navigate('/pay-result?success=true')
|
||||
return
|
||||
}
|
||||
|
|
@ -182,6 +248,7 @@ function PayPage() {
|
|||
}
|
||||
|
||||
stopOrderPolling()
|
||||
clearPendingPayment(orderId)
|
||||
if (isMountedRef.current) {
|
||||
setIsPaying(false)
|
||||
}
|
||||
|
|
@ -190,6 +257,7 @@ function PayPage() {
|
|||
|
||||
if (pollingCountRef.current >= ORDER_POLLING_MAX_COUNT) {
|
||||
stopOrderPolling()
|
||||
clearPendingPayment(orderId)
|
||||
if (isMountedRef.current) {
|
||||
setIsPaying(false)
|
||||
}
|
||||
|
|
@ -208,6 +276,17 @@ function PayPage() {
|
|||
[navigate, stopOrderPolling],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const pendingPayment = getPendingPayment()
|
||||
|
||||
if (!pendingPayment) {
|
||||
return
|
||||
}
|
||||
|
||||
setIsPaying(true)
|
||||
startOrderPolling(pendingPayment.orderId)
|
||||
}, [startOrderPolling])
|
||||
|
||||
const handlePay = useCallback(async () => {
|
||||
if (isPaying || !selectedPlan || !selectedPayType) {
|
||||
return
|
||||
|
|
@ -246,6 +325,7 @@ function PayPage() {
|
|||
throw new Error('Failed to open Alipay window')
|
||||
}
|
||||
|
||||
savePendingPayment(data.orderId)
|
||||
startOrderPolling(data.orderId)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue