323 lines
15 KiB
TypeScript
323 lines
15 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { useAppSelector, useAppDispatch } from '../../store/hooks';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { setStats, setRecentActivities, setQuickActions } from '../../store/slices/dashboardSlice';
|
|
import { loginSuccess } from '../../store/slices/authSlice';
|
|
import { mockDashboardStats, mockRecentActivities, mockResellerQuickActions, mockResellerRecentActivities, mockUser } from '../../data/mockData';
|
|
import { formatNumber, formatRelativeTime, formatPercentage } from '../../utils/format';
|
|
import RevenueChart from '../../components/charts/RevenueChart';
|
|
import ResellerPerformanceChart from '../../components/charts/ResellerPerformanceChart';
|
|
import DualCurrencyDisplay from '../../components/DualCurrencyDisplay';
|
|
import {
|
|
TrendingUp,
|
|
Users,
|
|
Cloud,
|
|
DollarSign,
|
|
UserPlus,
|
|
CheckCircle,
|
|
Briefcase,
|
|
GraduationCap,
|
|
BarChart3,
|
|
CreditCard,
|
|
Headphones,
|
|
ShoppingBag,
|
|
Award,
|
|
HelpCircle,
|
|
Settings,
|
|
Wallet,
|
|
BookOpen,
|
|
Zap,
|
|
Target,
|
|
Star,
|
|
ArrowUpRight,
|
|
Activity
|
|
} from 'lucide-react';
|
|
import { cn } from '../../utils/cn';
|
|
|
|
const ResellerDashboard: React.FC = () => {
|
|
const dispatch = useAppDispatch();
|
|
const navigate = useNavigate();
|
|
const { stats, recentActivities, quickActions } = useAppSelector((state) => state.dashboard);
|
|
|
|
useEffect(() => {
|
|
// Initialize with mock data
|
|
dispatch(loginSuccess({
|
|
user: {
|
|
...mockUser,
|
|
role: 'reseller_admin',
|
|
company: 'Tech Solutions Inc'
|
|
},
|
|
token: 'mock-token',
|
|
refreshToken: 'mock-refresh-token'
|
|
}));
|
|
dispatch(setStats(mockDashboardStats));
|
|
dispatch(setRecentActivities(mockResellerRecentActivities));
|
|
dispatch(setQuickActions(mockResellerQuickActions));
|
|
}, [dispatch]);
|
|
|
|
const handleQuickAction = (action: any) => {
|
|
switch (action.id) {
|
|
case 'add-customer':
|
|
navigate('/reseller-dashboard/customers');
|
|
break;
|
|
case 'create-instance':
|
|
navigate('/reseller-dashboard/instances');
|
|
break;
|
|
case 'billing':
|
|
navigate('/reseller-dashboard/billing');
|
|
break;
|
|
case 'support':
|
|
navigate('/reseller-dashboard/support');
|
|
break;
|
|
case 'training':
|
|
navigate('/reseller-dashboard/training');
|
|
break;
|
|
case 'reports':
|
|
navigate('/reseller-dashboard/reports');
|
|
break;
|
|
case 'wallet':
|
|
navigate('/reseller-dashboard/wallet');
|
|
break;
|
|
case 'marketplace':
|
|
navigate('/reseller-dashboard/marketplace');
|
|
break;
|
|
case 'certifications':
|
|
navigate('/reseller-dashboard/certifications');
|
|
break;
|
|
case 'knowledge-base':
|
|
navigate('/reseller-dashboard/knowledge-base');
|
|
break;
|
|
case 'settings':
|
|
navigate('/reseller-dashboard/settings');
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
{/* Welcome Section */}
|
|
<div className="bg-gradient-to-r from-emerald-600 via-teal-600 to-cyan-600 rounded-3xl p-8 text-white relative overflow-hidden">
|
|
<div className="absolute inset-0 bg-black/10"></div>
|
|
<div className="relative z-10">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-3xl font-bold mb-2">Welcome back, John! </h1>
|
|
<p className="text-emerald-100 text-lg">Here's what's happening with your cloud services business today.</p>
|
|
</div>
|
|
<div className="hidden lg:flex items-center space-x-4">
|
|
<div className="text-center">
|
|
<div className="text-2xl font-bold">{formatNumber(stats.totalResellers)}</div>
|
|
<div className="text-emerald-100 text-sm">Active Customers</div>
|
|
</div>
|
|
<div className="text-center">
|
|
<DualCurrencyDisplay
|
|
amount={stats.commissionEarned}
|
|
currency={stats.currency}
|
|
className="text-2xl font-bold text-white"
|
|
/>
|
|
<div className="text-emerald-100 text-sm">Monthly Revenue</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full -translate-y-32 translate-x-32"></div>
|
|
<div className="absolute bottom-0 left-0 w-48 h-48 bg-white/5 rounded-full translate-y-24 -translate-x-24"></div>
|
|
</div>
|
|
|
|
{/* Key Metrics */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700 hover:shadow-xl transition-all duration-300 group">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="w-12 h-12 bg-gradient-to-r from-blue-500 to-blue-600 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
|
|
<DollarSign className="w-6 h-6 text-white" />
|
|
</div>
|
|
<TrendingUp className="w-5 h-5 text-green-500" />
|
|
</div>
|
|
<h3 className="text-2xl font-bold text-slate-900 dark:text-white mb-1">
|
|
<DualCurrencyDisplay
|
|
amount={stats.totalRevenue}
|
|
currency={stats.currency}
|
|
className="text-2xl"
|
|
/>
|
|
</h3>
|
|
<p className="text-slate-600 dark:text-slate-400 text-sm">Total Revenue</p>
|
|
<div className="flex items-center mt-2 text-green-600 text-sm">
|
|
<ArrowUpRight className="w-4 h-4 mr-1" />
|
|
+{stats.monthlyGrowth}% from last month
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700 hover:shadow-xl transition-all duration-300 group">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="w-12 h-12 bg-gradient-to-r from-emerald-500 to-emerald-600 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
|
|
<Users className="w-6 h-6 text-white" />
|
|
</div>
|
|
<Activity className="w-5 h-5 text-emerald-500" />
|
|
</div>
|
|
<h3 className="text-2xl font-bold text-slate-900 dark:text-white mb-1">
|
|
{formatNumber(stats.totalResellers)}
|
|
</h3>
|
|
<p className="text-slate-600 dark:text-slate-400 text-sm">Active Customers</p>
|
|
<div className="flex items-center mt-2 text-emerald-600 text-sm">
|
|
<ArrowUpRight className="w-4 h-4 mr-1" />
|
|
+5 new this month
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700 hover:shadow-xl transition-all duration-300 group">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="w-12 h-12 bg-gradient-to-r from-purple-500 to-purple-600 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
|
|
<Cloud className="w-6 h-6 text-white" />
|
|
</div>
|
|
<Zap className="w-5 h-5 text-purple-500" />
|
|
</div>
|
|
<h3 className="text-2xl font-bold text-slate-900 dark:text-white mb-1">
|
|
{formatNumber(stats.activePartnerships)}
|
|
</h3>
|
|
<p className="text-slate-600 dark:text-slate-400 text-sm">Cloud Instances</p>
|
|
<div className="flex items-center mt-2 text-purple-600 text-sm">
|
|
<ArrowUpRight className="w-4 h-4 mr-1" />
|
|
+12 new instances
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700 hover:shadow-xl transition-all duration-300 group">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="w-12 h-12 bg-gradient-to-r from-orange-500 to-orange-600 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
|
|
<Target className="w-6 h-6 text-white" />
|
|
</div>
|
|
<Star className="w-5 h-5 text-orange-500" />
|
|
</div>
|
|
<h3 className="text-2xl font-bold text-slate-900 dark:text-white mb-1">
|
|
{formatPercentage(15)}
|
|
</h3>
|
|
<p className="text-slate-600 dark:text-slate-400 text-sm">Commission Rate</p>
|
|
<div className="flex items-center mt-2 text-orange-600 text-sm">
|
|
<CheckCircle className="w-4 h-4 mr-1" />
|
|
Premium tier
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quick Actions & Recent Activity */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
{/* Quick Actions */}
|
|
<div className="lg:col-span-1">
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700">
|
|
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-6 flex items-center">
|
|
<Zap className="w-5 h-5 mr-2 text-emerald-500" />
|
|
Quick Actions
|
|
</h3>
|
|
<div className="space-y-3">
|
|
{quickActions.slice(0, 6).map((action) => (
|
|
<button
|
|
key={action.id}
|
|
onClick={() => handleQuickAction(action)}
|
|
className="w-full flex items-center p-4 rounded-xl bg-gradient-to-r from-slate-50 to-slate-100 dark:from-slate-700 dark:to-slate-800 hover:from-emerald-50 hover:to-teal-50 dark:hover:from-emerald-900/20 dark:hover:to-teal-900/20 transition-all duration-300 group border border-slate-200 dark:border-slate-600"
|
|
>
|
|
<div className="w-10 h-10 bg-gradient-to-r from-emerald-500 to-teal-500 rounded-lg flex items-center justify-center mr-4 group-hover:scale-110 transition-transform duration-300">
|
|
{action.icon === 'UserPlus' && <UserPlus className="w-5 h-5 text-white" />}
|
|
{action.icon === 'Cloud' && <Cloud className="w-5 h-5 text-white" />}
|
|
{action.icon === 'CreditCard' && <CreditCard className="w-5 h-5 text-white" />}
|
|
{action.icon === 'Headphones' && <Headphones className="w-5 h-5 text-white" />}
|
|
{action.icon === 'GraduationCap' && <GraduationCap className="w-5 h-5 text-white" />}
|
|
{action.icon === 'BarChart3' && <BarChart3 className="w-5 h-5 text-white" />}
|
|
{action.icon === 'Wallet' && <Wallet className="w-5 h-5 text-white" />}
|
|
{action.icon === 'ShoppingBag' && <ShoppingBag className="w-5 h-5 text-white" />}
|
|
{action.icon === 'Award' && <Award className="w-5 h-5 text-white" />}
|
|
{action.icon === 'HelpCircle' && <HelpCircle className="w-5 h-5 text-white" />}
|
|
{action.icon === 'Settings' && <Settings className="w-5 h-5 text-white" />}
|
|
{action.icon === 'BookOpen' && <BookOpen className="w-5 h-5 text-white" />}
|
|
</div>
|
|
<div className="text-left flex-1">
|
|
<p className="font-semibold text-slate-900 dark:text-white group-hover:text-emerald-600 dark:group-hover:text-emerald-400 transition-colors duration-300">
|
|
{action.title}
|
|
</p>
|
|
<p className="text-sm text-slate-600 dark:text-slate-400">{action.description}</p>
|
|
</div>
|
|
<ArrowUpRight className="w-4 h-4 text-slate-400 group-hover:text-emerald-500 transition-colors duration-300" />
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Recent Activity */}
|
|
<div className="lg:col-span-2">
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700">
|
|
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-6 flex items-center">
|
|
<Activity className="w-5 h-5 mr-2 text-emerald-500" />
|
|
Recent Activity
|
|
</h3>
|
|
<div className="space-y-4">
|
|
{recentActivities.map((activity) => (
|
|
<div key={activity.id} className="flex items-start p-4 rounded-xl bg-slate-50 dark:bg-slate-700/50 hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors duration-200">
|
|
<div className="w-10 h-10 bg-gradient-to-r from-emerald-500 to-teal-500 rounded-lg flex items-center justify-center mr-4 flex-shrink-0">
|
|
{activity.type === 'customer_added' && <UserPlus className="w-5 h-5 text-white" />}
|
|
{activity.type === 'instance_created' && <Cloud className="w-5 h-5 text-white" />}
|
|
{activity.type === 'payment_received' && <CreditCard className="w-5 h-5 text-white" />}
|
|
{activity.type === 'support_ticket' && <Headphones className="w-5 h-5 text-white" />}
|
|
{activity.type === 'training_completed' && <GraduationCap className="w-5 h-5 text-white" />}
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<p className="font-semibold text-slate-900 dark:text-white mb-1">
|
|
{activity.title}
|
|
</p>
|
|
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
{activity.description}
|
|
</p>
|
|
{activity.amount && (
|
|
<div className="mb-2">
|
|
<DualCurrencyDisplay
|
|
amount={activity.amount}
|
|
currency={activity.currency}
|
|
className="text-sm font-semibold text-emerald-600"
|
|
/>
|
|
</div>
|
|
)}
|
|
<p className="text-xs text-slate-500 dark:text-slate-400">
|
|
{formatRelativeTime(activity.timestamp)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="mt-6 pt-4 border-t border-slate-200 dark:border-slate-700">
|
|
<button className="text-emerald-600 hover:text-emerald-700 dark:text-emerald-400 dark:hover:text-emerald-300 font-medium flex items-center">
|
|
View all activities
|
|
<ArrowUpRight className="w-4 h-4 ml-1" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Charts Section */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700">
|
|
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-6 flex items-center">
|
|
<BarChart3 className="w-5 h-5 mr-2 text-emerald-500" />
|
|
Revenue Overview
|
|
</h3>
|
|
<div className="h-64">
|
|
<RevenueChart />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-lg border border-slate-200 dark:border-slate-700">
|
|
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-6 flex items-center">
|
|
<Target className="w-5 h-5 mr-2 text-emerald-500" />
|
|
Customer Performance
|
|
</h3>
|
|
<div className="h-64">
|
|
<ResellerPerformanceChart />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ResellerDashboard;
|