/opt/canhelp/apps/web/src/app/payment
Edit: /opt/canhelp/apps/web/src/app/payment/page.tsx (5298B)
'use client'
import { useEffect, useState } from 'react'
import { useSearchParams } from 'next/navigation'
import Link from 'next/link'
import type { ReactNode } from 'react'
import { useLocale } from '@/context/locale'
import * as api from '@/lib/api'
// Status is determined either by:
// 1. ?status=cancelled (from our cancel redirect)
// 2. ?ref=ORDER_REF → we poll /payments/history to check the order status
export default function PaymentPage() {
const searchParams = useSearchParams()
const { t } = useLocale()
const statusParam = searchParams.get('status')
const ref = searchParams.get('ref')
const [status, setStatus] = useState<'pending' | 'success' | 'failed' | 'cancelled' | 'loading'>(
statusParam === 'cancelled' ? 'cancelled' : ref ? 'loading' : 'pending',
)
useEffect(() => {
if (statusParam === 'cancelled') {
setStatus('cancelled')
return
}
if (!ref) return
// Poll payment history to find the order status
let attempts = 0
const MAX = 12 // ~24 seconds total
const INTERVAL = 2000
const check = async () => {
attempts++
try {
const history = await api.getPaymentHistory()
const payment = history.find((p) => p.orderRef === ref)
if (payment && payment.status !== 'pending') {
setStatus(payment.status as any)
return
}
} catch {}
if (attempts < MAX) {
setTimeout(check, INTERVAL)
} else {
setStatus('pending') // timeout - show pending message
}
}
setTimeout(check, INTERVAL)
}, [ref, statusParam])
const config: Record
= {
success: {
icon: (
),
title: t('payment.success.title'),
desc: t('payment.success.desc'),
color: 'text-green-700',
bg: 'bg-green-50',
border: 'border-green-200',
},
cancelled: {
icon: (
),
title: t('payment.cancelled.title'),
desc: t('payment.cancelled.desc'),
color: 'text-yellow-700',
bg: 'bg-yellow-50',
border: 'border-yellow-200',
},
failed: {
icon: (
),
title: t('payment.cancelled.title'),
desc: t('payment.cancelled.desc'),
color: 'text-red-700',
bg: 'bg-red-50',
border: 'border-red-200',
},
pending: {
icon: (
),
title: t('payment.pending.title'),
desc: t('payment.pending.desc'),
color: 'text-green-700',
bg: 'bg-green-50',
border: 'border-green-200',
},
loading: {
icon: (
),
title: t('payment.pending.title'),
desc: t('payment.pending.desc'),
color: 'text-gray-700',
bg: 'bg-gray-50',
border: 'border-gray-200',
},
}
const current = config[status] ?? config.pending
return (
{current.icon}
{current.title}
{current.desc}
{t('payment.back_to_profile')}
)
}