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_INTERVAL = 2000
|
||||||
const ORDER_POLLING_MAX_COUNT = 60
|
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 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) {
|
function getSupportedPayMethods(goods?: GoodsItem) {
|
||||||
if (!goods?.pay_type) {
|
if (!goods?.pay_type) {
|
||||||
return []
|
return []
|
||||||
|
|
@ -58,6 +116,7 @@ function PayPage() {
|
||||||
const cancelPaymentFlow = useCallback(() => {
|
const cancelPaymentFlow = useCallback(() => {
|
||||||
paymentAttemptRef.current += 1
|
paymentAttemptRef.current += 1
|
||||||
stopOrderPolling()
|
stopOrderPolling()
|
||||||
|
clearPendingPayment()
|
||||||
|
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
setIsPaying(false)
|
setIsPaying(false)
|
||||||
|
|
@ -121,6 +180,8 @@ function PayPage() {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
isMountedRef.current = true
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
isMountedRef.current = false
|
isMountedRef.current = false
|
||||||
stopOrderPolling()
|
stopOrderPolling()
|
||||||
|
|
@ -142,7 +203,11 @@ function PayPage() {
|
||||||
const hasSelectionChanged =
|
const hasSelectionChanged =
|
||||||
previousSelection.planId !== selectedPlanId || previousSelection.payType !== selectedPayType
|
previousSelection.planId !== selectedPlanId || previousSelection.payType !== selectedPayType
|
||||||
|
|
||||||
if (isPaying && hasSelectionChanged) {
|
const hasCompleteSelection = Boolean(
|
||||||
|
previousSelection.planId && previousSelection.payType && selectedPlanId && selectedPayType,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isPaying && hasCompleteSelection && hasSelectionChanged) {
|
||||||
cancelPaymentFlow()
|
cancelPaymentFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,6 +238,7 @@ function PayPage() {
|
||||||
|
|
||||||
if (data.status === '2') {
|
if (data.status === '2') {
|
||||||
stopOrderPolling()
|
stopOrderPolling()
|
||||||
|
clearPendingPayment(orderId)
|
||||||
navigate('/pay-result?success=true')
|
navigate('/pay-result?success=true')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +248,7 @@ function PayPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
stopOrderPolling()
|
stopOrderPolling()
|
||||||
|
clearPendingPayment(orderId)
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
setIsPaying(false)
|
setIsPaying(false)
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +257,7 @@ function PayPage() {
|
||||||
|
|
||||||
if (pollingCountRef.current >= ORDER_POLLING_MAX_COUNT) {
|
if (pollingCountRef.current >= ORDER_POLLING_MAX_COUNT) {
|
||||||
stopOrderPolling()
|
stopOrderPolling()
|
||||||
|
clearPendingPayment(orderId)
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
setIsPaying(false)
|
setIsPaying(false)
|
||||||
}
|
}
|
||||||
|
|
@ -208,6 +276,17 @@ function PayPage() {
|
||||||
[navigate, stopOrderPolling],
|
[navigate, stopOrderPolling],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const pendingPayment = getPendingPayment()
|
||||||
|
|
||||||
|
if (!pendingPayment) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsPaying(true)
|
||||||
|
startOrderPolling(pendingPayment.orderId)
|
||||||
|
}, [startOrderPolling])
|
||||||
|
|
||||||
const handlePay = useCallback(async () => {
|
const handlePay = useCallback(async () => {
|
||||||
if (isPaying || !selectedPlan || !selectedPayType) {
|
if (isPaying || !selectedPlan || !selectedPayType) {
|
||||||
return
|
return
|
||||||
|
|
@ -246,6 +325,7 @@ function PayPage() {
|
||||||
throw new Error('Failed to open Alipay window')
|
throw new Error('Failed to open Alipay window')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
savePendingPayment(data.orderId)
|
||||||
startOrderPolling(data.orderId)
|
startOrderPolling(data.orderId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue