183 lines
7.1 KiB
TypeScript
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>
|
|
)
|
|
}
|