ai-wpa/app/profile/page.tsx

183 lines
7.1 KiB
TypeScript

'use client'
import { useSearchParams, useRouter } from 'next/navigation'
import { useEffect, useState, useMemo } from 'react'
import { RequireAuth } from '@/components/auth/RequireAuth'
import { ProfileCard } from '@/components/profile/ProfileCard'
import { ProfileSettings } from '@/components/profile/ProfileSettings'
import { Header } from '@/components/header'
import { Footer } from '@/components/footer'
function ProfileContent() {
const searchParams = useSearchParams()
const router = useRouter()
const [activeTab, setActiveTab] = useState('profile')
const [paymentResult, setPaymentResult] = useState<{
type: 'success' | 'failed'
message: string
amount?: string
txn?: string
paymentType?: string
} | null>(null)
const validTabs = useMemo(() => ['profile', 'balance', 'billing', 'services', 'security', 'danger'], [])
useEffect(() => {
const tab = searchParams.get('tab')
if (tab && validTabs.includes(tab)) {
setActiveTab(tab)
} else if (tab && !validTabs.includes(tab)) {
// Handle invalid tab parameter by redirecting to default
const params = new URLSearchParams(searchParams.toString())
params.delete('tab')
router.replace(`/profile${params.toString() ? `?${params.toString()}` : ''}`)
}
// Handle payment result notifications
const payment = searchParams.get('payment')
const paymentType = searchParams.get('type')
const amount = searchParams.get('amount')
const txn = searchParams.get('txn')
const reason = searchParams.get('reason')
const message = searchParams.get('message')
if (payment === 'success') {
setPaymentResult({
type: 'success',
message: paymentType === 'balance'
? `Balance successfully added! ₹${amount ? parseFloat(amount).toLocaleString('en-IN') : '0'} has been credited to your account.`
: `Payment successful! Your service payment has been processed.`,
amount,
txn,
paymentType
})
// If it's balance addition, switch to balance tab
if (paymentType === 'balance') {
setActiveTab('balance')
}
} else if (payment === 'failed') {
const failureMessages: Record<string, string> = {
'insufficient-funds': 'Payment failed due to insufficient funds.',
'card-declined': 'Your card was declined. Please try a different payment method.',
'timeout': 'Payment timed out. Please try again.',
'user-cancelled': 'Payment was cancelled.',
'invalid-details': 'Invalid payment details. Please check and try again.',
'unknown': 'Payment failed due to an unexpected error.'
}
setPaymentResult({
type: 'failed',
message: message ? decodeURIComponent(message) : (failureMessages[reason || 'unknown'] || 'Payment failed. Please try again.'),
amount,
txn,
paymentType
})
}
// Clean up URL parameters after handling payment result
if (payment) {
setTimeout(() => {
const params = new URLSearchParams(searchParams.toString())
params.delete('payment')
params.delete('type')
params.delete('amount')
params.delete('txn')
params.delete('reason')
params.delete('message')
params.delete('warning')
const queryString = params.toString()
router.replace(`/profile${queryString ? `?${queryString}` : ''}`, { scroll: false })
}, 100) // Small delay to ensure state is set
}
}, [searchParams, router, validTabs])
const handleTabChange = (tab: string) => {
if (!validTabs.includes(tab)) return
setActiveTab(tab)
const params = new URLSearchParams(searchParams.toString())
if (tab === 'profile') {
// Remove tab parameter for default tab to keep URLs clean
params.delete('tab')
} else {
params.set('tab', tab)
}
const queryString = params.toString()
router.push(`/profile${queryString ? `?${queryString}` : ''}`)
}
return (
<div className="container max-w-4xl pt-24 pb-8">
<div className="mb-8">
<h1 className="text-3xl font-bold">Profile</h1>
<p className="text-muted-foreground">Manage your account settings and preferences</p>
</div>
{/* Payment Result Notification */}
{paymentResult && (
<div className={`mb-6 p-4 rounded-lg border ${
paymentResult.type === 'success'
? 'bg-green-50 border-green-200 text-green-800 dark:bg-green-900/10 dark:border-green-700 dark:text-green-200'
: 'bg-red-50 border-red-200 text-red-800 dark:bg-red-900/10 dark:border-red-700 dark:text-red-200'
}`}>
<div className="flex items-start">
<div className={`mr-3 ${
paymentResult.type === 'success' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'
}`}>
{paymentResult.type === 'success' ? (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
) : (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
)}
</div>
<div className="flex-1">
<p className="font-medium">{paymentResult.message}</p>
{paymentResult.txn && (
<p className="mt-1 text-sm opacity-75">
Transaction ID: <code className="font-mono">{paymentResult.txn}</code>
</p>
)}
</div>
<button
onClick={() => setPaymentResult(null)}
className="ml-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
</svg>
</button>
</div>
</div>
)}
<div className="grid gap-6 md:grid-cols-1 lg:grid-cols-3">
<div className="lg:col-span-1">
<ProfileCard />
</div>
<div className="lg:col-span-2">
<ProfileSettings activeTab={activeTab} onTabChange={handleTabChange} />
</div>
</div>
</div>
)
}
export default function ProfilePage() {
return (
<div className="min-h-screen bg-background">
<Header />
<RequireAuth>
<ProfileContent />
</RequireAuth>
<Footer />
</div>
)
}