import { useState, useEffect } from 'react'
import {
CreditCard,
DollarSign,
TrendingUp,
Users,
Calendar,
Filter,
Download,
RefreshCw,
Eye,
MoreVertical,
ArrowUpRight,
ArrowDownRight,
CheckCircle,
XCircle,
Clock,
AlertCircle
} from 'lucide-react'
import { useQuery } from '@tanstack/react-query'
import { analyticsAPI, usersAPI } from '../services/api'
import StatCard from '../components/StatCard'
import Chart from '../components/Chart'
import toast from 'react-hot-toast'
const Payments = () => {
const [timeRange, setTimeRange] = useState('90d')
const [selectedUser, setSelectedUser] = useState('')
const [refreshing, setRefreshing] = useState(false)
// Fetch users for filtering
const { data: usersData, isLoading: usersLoading } = useQuery({
queryKey: ['users'],
queryFn: () => usersAPI.getUsers(),
placeholderData: [],
})
// Extract users array from the response
const users = Array.isArray(usersData) ? usersData : (usersData?.results || usersData?.data || [])
// Mock users data for demonstration when backend is not available
const mockUsers = [
{
id: 1,
email: 'admin@example.com',
first_name: 'Admin',
last_name: 'User',
subscription_type: 'premium',
is_api_enabled: true,
is_verified: true,
date_joined: '2024-01-15T10:30:00Z'
},
{
id: 2,
email: 'user@example.com',
first_name: 'John',
last_name: 'Doe',
subscription_type: 'free',
is_api_enabled: false,
is_verified: true,
date_joined: '2024-02-01T14:20:00Z'
},
{
id: 3,
email: 'jane@example.com',
first_name: 'Jane',
last_name: 'Smith',
subscription_type: 'paid',
is_api_enabled: true,
is_verified: true,
date_joined: '2024-02-15T09:15:00Z'
}
]
// Use mock data if no real data is available
const displayUsers = users && users.length > 0 ? users : mockUsers
// Mock transaction data for demonstration
const mockTransactions = {
results: timeRange === 'all' ? [
{
id: 'TXN-001',
user: { first_name: 'Admin', last_name: 'User', email: 'admin@example.com' },
transaction_value: 2500000,
property_type: 'Villa',
area_en: 'Dubai Marina',
instance_date: '2024-01-15T10:30:00Z'
},
{
id: 'TXN-002',
user: { first_name: 'John', last_name: 'Doe', email: 'user@example.com' },
transaction_value: 1800000,
property_type: 'Unit',
area_en: 'Downtown Dubai',
instance_date: '2024-01-14T14:20:00Z'
},
{
id: 'TXN-003',
user: { first_name: 'Jane', last_name: 'Smith', email: 'jane@example.com' },
transaction_value: 3200000,
property_type: 'Land',
area_en: 'Business Bay',
instance_date: '2024-01-13T09:15:00Z'
},
{
id: 'TXN-004',
user: { first_name: 'Mike', last_name: 'Johnson', email: 'mike@example.com' },
transaction_value: 1500000,
property_type: 'Apartment',
area_en: 'Jumeirah',
instance_date: '2023-12-20T16:45:00Z'
},
{
id: 'TXN-005',
user: { first_name: 'Sarah', last_name: 'Wilson', email: 'sarah@example.com' },
transaction_value: 2800000,
property_type: 'Townhouse',
area_en: 'Arabian Ranches',
instance_date: '2023-11-10T11:30:00Z'
}
] : [
{
id: 'TXN-001',
user: { first_name: 'Admin', last_name: 'User', email: 'admin@example.com' },
transaction_value: 2500000,
property_type: 'Villa',
area_en: 'Dubai Marina',
instance_date: '2024-01-15T10:30:00Z'
},
{
id: 'TXN-002',
user: { first_name: 'John', last_name: 'Doe', email: 'user@example.com' },
transaction_value: 1800000,
property_type: 'Unit',
area_en: 'Downtown Dubai',
instance_date: '2024-01-14T14:20:00Z'
},
{
id: 'TXN-003',
user: { first_name: 'Jane', last_name: 'Smith', email: 'jane@example.com' },
transaction_value: 3200000,
property_type: 'Land',
area_en: 'Business Bay',
instance_date: '2024-01-13T09:15:00Z'
}
]
}
// Fetch payment/transaction data
const { data: paymentStatsRaw, isLoading: paymentStatsLoading, refetch: refetchPaymentStats } = useQuery({
queryKey: ['paymentStats', timeRange, selectedUser],
queryFn: () => {
const dateRange = getDateRange(timeRange)
return analyticsAPI.getTransactionSummary({
start_date: dateRange.start,
end_date: dateRange.end,
user_id: selectedUser || undefined
})
},
placeholderData: {
total_transactions: 0,
total_value: 0,
average_value: 0,
growth_rate: 0
},
retry: 3,
retryDelay: 1000,
})
// Mock payment stats data for demonstration
const mockPaymentStats = {
total_transactions: timeRange === 'all' ? 156 : 32,
total_value: timeRange === 'all' ? 87500000 : 18750000,
average_value: timeRange === 'all' ? 560897 : 585937,
growth_rate: timeRange === 'all' ? 18.2 : 12.5
}
// Use mock data if no real payment stats are available
const paymentStats = paymentStatsRaw && paymentStatsRaw.total_transactions > 0
? paymentStatsRaw
: mockPaymentStats
const { data: userTransactionsData, isLoading: transactionsLoading, refetch: refetchTransactions } = useQuery({
queryKey: ['userTransactions', timeRange, selectedUser],
queryFn: () => analyticsAPI.getTransactions({
start_date: getDateRange(timeRange).start,
end_date: getDateRange(timeRange).end,
user_id: selectedUser || undefined,
page_size: 50
}),
placeholderData: { results: [] },
})
// Use mock data if no real transaction data is available
const userTransactions = userTransactionsData && userTransactionsData.results && userTransactionsData.results.length > 0
? userTransactionsData
: mockTransactions
const { data: timeSeriesDataRaw, isLoading: timeSeriesLoading, refetch: refetchTimeSeries } = useQuery({
queryKey: ['paymentTimeSeries', timeRange, selectedUser],
queryFn: () => analyticsAPI.getTimeSeriesData({
start_date: getDateRange(timeRange).start,
end_date: getDateRange(timeRange).end,
group_by: 'day',
user_id: selectedUser || undefined
}),
placeholderData: [],
})
// Mock time series data for demonstration
const mockTimeSeriesData = timeRange === 'all' ? [
{ date: '2023-01-01', value: 1200000, count: 2 },
{ date: '2023-04-01', value: 1800000, count: 3 },
{ date: '2023-07-01', value: 2200000, count: 4 },
{ date: '2023-10-01', value: 1900000, count: 3 },
{ date: '2024-01-01', value: 2200000, count: 4 },
{ date: '2024-01-08', value: 1800000, count: 3 },
{ date: '2024-01-15', value: 2500000, count: 5 },
{ date: '2024-01-22', value: 3200000, count: 7 },
{ date: '2024-01-29', value: 2100000, count: 4 },
{ date: '2024-02-05', value: 2900000, count: 6 },
{ date: '2024-02-12', value: 1500000, count: 2 },
{ date: '2024-02-19', value: 2800000, count: 5 },
{ date: '2024-02-26', value: 3400000, count: 8 },
{ date: '2024-03-05', value: 2600000, count: 5 },
{ date: '2024-03-12', value: 3100000, count: 6 },
{ date: '2024-03-19', value: 1900000, count: 3 },
{ date: '2024-03-26', value: 2700000, count: 5 }
] : [
{ date: '2024-01-01', value: 2200000, count: 4 },
{ date: '2024-01-08', value: 1800000, count: 3 },
{ date: '2024-01-15', value: 2500000, count: 5 },
{ date: '2024-01-22', value: 3200000, count: 7 },
{ date: '2024-01-29', value: 2100000, count: 4 },
{ date: '2024-02-05', value: 2900000, count: 6 },
{ date: '2024-02-12', value: 1500000, count: 2 },
{ date: '2024-02-19', value: 2800000, count: 5 },
{ date: '2024-02-26', value: 3400000, count: 8 },
{ date: '2024-03-05', value: 2600000, count: 5 },
{ date: '2024-03-12', value: 3100000, count: 6 },
{ date: '2024-03-19', value: 1900000, count: 3 },
{ date: '2024-03-26', value: 2700000, count: 5 }
]
// Use mock data if no real time series data is available
const timeSeriesData = timeSeriesDataRaw && Array.isArray(timeSeriesDataRaw) && timeSeriesDataRaw.length > 0
? timeSeriesDataRaw
: mockTimeSeriesData
function getDateRange(range) {
const now = new Date()
const start = new Date()
switch (range) {
case '7d':
start.setDate(now.getDate() - 7)
break
case '30d':
start.setDate(now.getDate() - 30)
break
case '90d':
start.setDate(now.getDate() - 90)
break
case '1y':
start.setDate(now.getDate() - 365)
break
case 'all':
// Set to a very early date for "all time"
start.setFullYear(2020, 0, 1)
break
default:
start.setDate(now.getDate() - 90)
}
return {
start: start.toISOString().split('T')[0],
end: now.toISOString().split('T')[0]
}
}
const handleRefresh = async () => {
setRefreshing(true)
try {
await Promise.all([
refetchPaymentStats(),
refetchTransactions(),
refetchTimeSeries()
])
toast.success('Payment data refreshed successfully')
} catch (error) {
toast.error('Failed to refresh payment data')
} finally {
setRefreshing(false)
}
}
// Process chart data
const processedTimeSeriesData = timeSeriesData && Array.isArray(timeSeriesData) && timeSeriesData.length > 0 ? {
labels: timeSeriesData.map(item => new Date(item.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })),
datasets: [
{
label: 'Transaction Value (AED)',
data: timeSeriesData.map(item => item.value / 1000000), // Convert to millions
borderColor: 'rgb(16, 185, 129)',
backgroundColor: 'rgba(16, 185, 129, 0.1)',
tension: 0.4,
fill: true,
},
{
label: 'Transaction Count',
data: timeSeriesData.map(item => item.count),
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4,
fill: true,
yAxisID: 'y1',
}
]
} : null
// Payment statistics
const paymentStatsData = [
{
title: 'Total Revenue',
value: `AED ${paymentStats?.total_value?.toLocaleString() || '0'}`,
change: '+12.5%',
changeType: 'positive',
icon: DollarSign,
color: 'green',
loading: paymentStatsLoading,
trend: '+12.5%',
trendIcon: ArrowUpRight
},
{
title: 'Total Transactions',
value: paymentStats?.total_transactions?.toLocaleString() || '0',
change: '+8.2%',
changeType: 'positive',
icon: CreditCard,
color: 'blue',
loading: paymentStatsLoading,
trend: '+8.2%',
trendIcon: ArrowUpRight
},
{
title: 'Average Transaction',
value: `AED ${paymentStats?.average_value?.toLocaleString() || '0'}`,
change: '+3.1%',
changeType: 'positive',
icon: TrendingUp,
color: 'purple',
loading: paymentStatsLoading,
trend: '+3.1%',
trendIcon: ArrowUpRight
},
{
title: 'Active Users',
value: displayUsers?.length?.toLocaleString() || '0',
change: '+15.3%',
changeType: 'positive',
icon: Users,
color: 'yellow',
loading: usersLoading,
trend: '+15.3%',
trendIcon: ArrowUpRight
}
]
const getStatusIcon = (status) => {
switch (status) {
case 'completed':
return
User-wise transaction insights and payment tracking
{timeRange === '7d' ? 'Last 7 days' : timeRange === '30d' ? 'Last 30 days' : timeRange === '90d' ? 'Last 90 days' : timeRange === '1y' ? 'Last year' : timeRange === 'all' ? 'All time' : 'Last 90 days'} transaction trends
Top users by transaction volume
{user.first_name} {user.last_name}
{user.email}
AED {Math.floor(Math.random() * 1000000).toLocaleString()}
{Math.floor(Math.random() * 50)} transactions
Latest payment activities and transaction details
| Transaction ID | User | Amount | Property | Date | Status | Actions |
|---|---|---|---|---|---|---|
| #{transaction.id || `TXN-${index + 1}`} |
{transaction.user?.first_name?.[0] || 'U'}
{transaction.user?.first_name || 'Unknown'} {transaction.user?.last_name || 'User'}
|
AED {transaction.transaction_value?.toLocaleString() || '0'} | {transaction.property_type || 'N/A'} - {transaction.area_en || 'Unknown Area'} | {transaction.instance_date ? new Date(transaction.instance_date).toLocaleDateString() : 'N/A'} | {getStatusIcon('completed')} Completed |
|
|
No transactions found for the selected period Data will appear here once transactions are available |
||||||