359 lines
16 KiB
TypeScript
359 lines
16 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
BarChart3,
|
|
TrendingUp,
|
|
Users,
|
|
DollarSign,
|
|
ShoppingCart,
|
|
Award,
|
|
Target,
|
|
Calendar,
|
|
Filter,
|
|
Download,
|
|
Eye,
|
|
EyeOff,
|
|
RefreshCw,
|
|
ArrowUp,
|
|
ArrowDown,
|
|
Activity,
|
|
PieChart,
|
|
LineChart,
|
|
BarChart,
|
|
AreaChart
|
|
} from 'lucide-react';
|
|
|
|
const Analytics: React.FC = () => {
|
|
const [dateRange, setDateRange] = useState('30d');
|
|
const [showDetailedMetrics, setShowDetailedMetrics] = useState(false);
|
|
|
|
// Mock data
|
|
const analyticsData = {
|
|
totalRevenue: 1250000,
|
|
totalResellers: 156,
|
|
activeResellers: 142,
|
|
totalDeals: 89,
|
|
conversionRate: 23.5,
|
|
averageDealSize: 14000,
|
|
monthlyGrowth: 12.8,
|
|
topPerformingResellers: [
|
|
{ name: 'John Smith', revenue: 89000, deals: 12, growth: 15.2 },
|
|
{ name: 'Sarah Johnson', revenue: 76000, deals: 9, growth: 8.7 },
|
|
{ name: 'Mike Davis', revenue: 68000, deals: 11, growth: 22.1 },
|
|
{ name: 'Lisa Wilson', revenue: 54000, deals: 7, growth: 5.3 },
|
|
{ name: 'David Brown', revenue: 48000, deals: 6, growth: 18.9 }
|
|
],
|
|
revenueByMonth: [
|
|
{ month: 'Jan', revenue: 85000, deals: 8 },
|
|
{ month: 'Feb', revenue: 92000, deals: 9 },
|
|
{ month: 'Mar', revenue: 78000, deals: 7 },
|
|
{ month: 'Apr', revenue: 105000, deals: 10 },
|
|
{ month: 'May', revenue: 118000, deals: 11 },
|
|
{ month: 'Jun', revenue: 125000, deals: 12 }
|
|
],
|
|
categoryPerformance: [
|
|
{ category: 'Cloud Services', revenue: 450000, percentage: 36 },
|
|
{ category: 'Security Solutions', revenue: 320000, percentage: 25.6 },
|
|
{ category: 'Data Analytics', revenue: 280000, percentage: 22.4 },
|
|
{ category: 'Consulting', revenue: 200000, percentage: 16 }
|
|
],
|
|
regionalPerformance: [
|
|
{ region: 'North America', revenue: 520000, growth: 15.2 },
|
|
{ region: 'Europe', revenue: 380000, growth: 8.7 },
|
|
{ region: 'Asia Pacific', revenue: 250000, growth: 22.1 },
|
|
{ region: 'Latin America', revenue: 100000, growth: 5.3 }
|
|
]
|
|
};
|
|
|
|
const getGrowthColor = (growth: number) => {
|
|
return growth >= 0 ? 'text-success-600 dark:text-success-400' : 'text-danger-600 dark:text-danger-400';
|
|
};
|
|
|
|
const getGrowthIcon = (growth: number) => {
|
|
return growth >= 0 ? <ArrowUp className="w-4 h-4" /> : <ArrowDown className="w-4 h-4" />;
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between space-y-4 sm:space-y-0">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="p-2 bg-primary-100 dark:bg-primary-900 rounded-lg">
|
|
<BarChart3 className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
<div>
|
|
<h1 className="text-2xl sm:text-3xl font-bold text-secondary-900 dark:text-white">
|
|
Analytics Dashboard
|
|
</h1>
|
|
<p className="text-secondary-600 dark:text-secondary-400 mt-1">
|
|
Comprehensive insights into your business performance
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center space-x-3">
|
|
<select
|
|
value={dateRange}
|
|
onChange={(e) => setDateRange(e.target.value)}
|
|
className="input text-sm"
|
|
>
|
|
<option value="7d">Last 7 days</option>
|
|
<option value="30d">Last 30 days</option>
|
|
<option value="90d">Last 90 days</option>
|
|
<option value="1y">Last year</option>
|
|
</select>
|
|
<button
|
|
onClick={() => setShowDetailedMetrics(!showDetailedMetrics)}
|
|
className="inline-flex items-center px-3 py-2 bg-secondary-100 dark:bg-secondary-800 text-secondary-700 dark:text-secondary-300 rounded-lg text-sm font-medium hover:bg-secondary-200 dark:hover:bg-secondary-700 transition-colors"
|
|
>
|
|
{showDetailedMetrics ? <EyeOff className="w-4 h-4 mr-2" /> : <Eye className="w-4 h-4 mr-2" />}
|
|
{showDetailedMetrics ? 'Hide Details' : 'Show Details'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Key Metrics */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium text-secondary-600 dark:text-secondary-400">Total Revenue</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">
|
|
${((Number(analyticsData.totalRevenue) || 0) / 1000).toFixed(0)}K
|
|
</p>
|
|
</div>
|
|
<div className="p-3 bg-primary-100 dark:bg-primary-900 rounded-lg">
|
|
<DollarSign className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center mt-4">
|
|
<TrendingUp className="w-4 h-4 text-success-600 mr-1" />
|
|
<span className="text-sm text-success-600">+{analyticsData.monthlyGrowth}% from last month</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium text-secondary-600 dark:text-secondary-400">Active Resellers</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">{analyticsData.activeResellers}</p>
|
|
</div>
|
|
<div className="p-3 bg-success-100 dark:bg-success-900 rounded-lg">
|
|
<Users className="w-6 h-6 text-success-600 dark:text-success-400" />
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center mt-4">
|
|
<TrendingUp className="w-4 h-4 text-success-600 mr-1" />
|
|
<span className="text-sm text-success-600">+8% from last month</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium text-secondary-600 dark:text-secondary-400">Total Deals</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">{analyticsData.totalDeals}</p>
|
|
</div>
|
|
<div className="p-3 bg-warning-100 dark:bg-warning-900 rounded-lg">
|
|
<ShoppingCart className="w-6 h-6 text-warning-600 dark:text-warning-400" />
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center mt-4">
|
|
<TrendingUp className="w-4 h-4 text-success-600 mr-1" />
|
|
<span className="text-sm text-success-600">+15% from last month</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-sm font-medium text-secondary-600 dark:text-secondary-400">Conversion Rate</p>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">{analyticsData.conversionRate}%</p>
|
|
</div>
|
|
<div className="p-3 bg-danger-100 dark:bg-danger-900 rounded-lg">
|
|
<Target className="w-6 h-6 text-danger-600 dark:text-danger-400" />
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center mt-4">
|
|
<TrendingUp className="w-4 h-4 text-success-600 mr-1" />
|
|
<span className="text-sm text-success-600">+2.3% from last month</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Charts Section */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* Revenue Trend */}
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">Revenue Trend</h3>
|
|
<button className="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300">
|
|
View Details
|
|
</button>
|
|
</div>
|
|
<div className="h-64 bg-gray-50 dark:bg-gray-800 rounded-lg flex items-center justify-center">
|
|
<div className="text-center">
|
|
<LineChart className="w-16 h-16 text-secondary-400 mx-auto mb-4" />
|
|
<p className="text-secondary-600 dark:text-secondary-400">Revenue trend chart</p>
|
|
<p className="text-sm text-secondary-500">Monthly revenue progression</p>
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 grid grid-cols-2 gap-4">
|
|
{analyticsData.revenueByMonth.slice(-4).map((item, index) => (
|
|
<div key={index} className="text-center">
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">{item.month}</p>
|
|
<p className="font-semibold text-secondary-900 dark:text-white">${((Number(item.revenue) || 0) / 1000).toFixed(0)}K</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Category Performance */}
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">Category Performance</h3>
|
|
<button className="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300">
|
|
View Details
|
|
</button>
|
|
</div>
|
|
<div className="h-64 bg-gray-50 dark:bg-gray-800 rounded-lg flex items-center justify-center">
|
|
<div className="text-center">
|
|
<PieChart className="w-16 h-16 text-secondary-400 mx-auto mb-4" />
|
|
<p className="text-secondary-600 dark:text-secondary-400">Category distribution chart</p>
|
|
<p className="text-sm text-secondary-500">Revenue by product category</p>
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 space-y-3">
|
|
{analyticsData.categoryPerformance.map((category, index) => (
|
|
<div key={index} className="flex items-center justify-between">
|
|
<span className="text-sm text-secondary-600 dark:text-secondary-400">{category.category}</span>
|
|
<div className="flex items-center space-x-2">
|
|
<div className="w-20 bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
|
<div
|
|
className="bg-primary-600 h-2 rounded-full"
|
|
style={{ width: `${category.percentage}%` }}
|
|
></div>
|
|
</div>
|
|
<span className="text-sm font-medium text-secondary-900 dark:text-white">{category.percentage}%</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Top Performing Resellers */}
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">Top Performing Resellers</h3>
|
|
<button className="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300">
|
|
View All
|
|
</button>
|
|
</div>
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead>
|
|
<tr className="border-b border-gray-200 dark:border-gray-700">
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-secondary-600 dark:text-secondary-400">Reseller</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-secondary-600 dark:text-secondary-400">Revenue</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-secondary-600 dark:text-secondary-400">Deals</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-secondary-600 dark:text-secondary-400">Growth</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-secondary-600 dark:text-secondary-400">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{analyticsData.topPerformingResellers.map((reseller, index) => (
|
|
<tr key={index} className="border-b border-gray-100 dark:border-gray-800">
|
|
<td className="py-3 px-4">
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-8 h-8 bg-primary-100 dark:bg-primary-900 rounded-full flex items-center justify-center">
|
|
<Users className="w-4 h-4 text-primary-600 dark:text-primary-400" />
|
|
</div>
|
|
<span className="text-sm font-medium text-secondary-900 dark:text-white">{reseller.name}</span>
|
|
</div>
|
|
</td>
|
|
<td className="py-3 px-4 text-sm text-secondary-900 dark:text-white">
|
|
${((Number(reseller.revenue) || 0) / 1000).toFixed(0)}K
|
|
</td>
|
|
<td className="py-3 px-4 text-sm text-secondary-600 dark:text-secondary-400">
|
|
{reseller.deals}
|
|
</td>
|
|
<td className="py-3 px-4">
|
|
<div className="flex items-center space-x-1">
|
|
{getGrowthIcon(reseller.growth)}
|
|
<span className={`text-sm ${getGrowthColor(reseller.growth)}`}>
|
|
{reseller.growth}%
|
|
</span>
|
|
</div>
|
|
</td>
|
|
<td className="py-3 px-4">
|
|
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-success-100 text-success-800 dark:bg-success-900 dark:text-success-300">
|
|
Active
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Regional Performance */}
|
|
<div className="card p-6">
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white mb-6">Regional Performance</h3>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
{analyticsData.regionalPerformance.map((region, index) => (
|
|
<div key={index} className="bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
|
|
<div className="flex items-center justify-between mb-3">
|
|
<h4 className="font-medium text-secondary-900 dark:text-white">{region.region}</h4>
|
|
<div className="flex items-center space-x-1">
|
|
{getGrowthIcon(region.growth)}
|
|
<span className={`text-sm ${getGrowthColor(region.growth)}`}>
|
|
{region.growth}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<p className="text-2xl font-bold text-secondary-900 dark:text-white">
|
|
${((Number(region.revenue) || 0) / 1000).toFixed(0)}K
|
|
</p>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400 mt-1">Revenue</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Export Options */}
|
|
<div className="card p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-secondary-900 dark:text-white">Export Analytics</h3>
|
|
<p className="text-sm text-secondary-600 dark:text-secondary-400">Download analytics data in various formats</p>
|
|
</div>
|
|
<div className="flex items-center space-x-3">
|
|
<button
|
|
onClick={() => console.log('Exporting PDF...')}
|
|
className="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg text-sm font-medium hover:bg-primary-700 transition-colors"
|
|
>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Export PDF
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('Exporting Excel...')}
|
|
className="inline-flex items-center px-4 py-2 bg-success-600 text-white rounded-lg text-sm font-medium hover:bg-success-700 transition-colors"
|
|
>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Export Excel
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('Exporting CSV...')}
|
|
className="inline-flex items-center px-4 py-2 bg-warning-600 text-white rounded-lg text-sm font-medium hover:bg-warning-700 transition-colors"
|
|
>
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Export CSV
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Analytics;
|