![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.ca/private_html/src/pages/user/ |
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import LayoutWithSidebar from '../../components/LayoutWithSidebar';
import { motion } from 'framer-motion';
import {
BarChart3, TrendingUp, TrendingDown, Users, Eye,
DollarSign, Calendar, Target, Award, Activity
} from 'lucide-react';
import toast from 'react-hot-toast';
import { useRequireRole, USER_ROLES } from '../../lib/auth-utils';
interface AnalyticsData {
profileViews: {
total: number;
thisMonth: number;
lastMonth: number;
trend: number;
};
leads: {
total: number;
thisMonth: number;
lastMonth: number;
conversionRate: number;
};
revenue: {
total: number;
thisMonth: number;
lastMonth: number;
trend: number;
};
performance: {
responseTime: number;
clientSatisfaction: number;
caseSuccessRate: number;
};
monthlyData: Array<{
month: string;
views: number;
leads: number;
revenue: number;
}>;
}
const BusinessAnalyticsPage: React.FC = () => {
const { data: session, status } = useSession();
const router = useRouter();
// Add permission guard
const { isAuthorized } = useRequireRole([
USER_ROLES.CLIENT,
USER_ROLES.USER,
USER_ROLES.LAWYER,
USER_ROLES.ADMIN,
USER_ROLES.SUPERADMIN
], '/auth/login');
const [analyticsData, setAnalyticsData] = useState<AnalyticsData | null>(null);
const [loading, setLoading] = useState(true);
const [timeRange, setTimeRange] = useState('30d');
useEffect(() => {
if (status === 'authenticated') {
fetchAnalyticsData();
}
}, [status, timeRange]);
const fetchAnalyticsData = async () => {
try {
setLoading(true);
const response = await fetch(`/api/user/business-analytics?range=${timeRange}`);
if (response.ok) {
const data = await response.json();
setAnalyticsData(data);
} else {
toast.error('Failed to load analytics data');
}
} catch (error) {
console.error('Error fetching analytics:', error);
toast.error('Error loading analytics data');
} finally {
setLoading(false);
}
};
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-CA', {
style: 'currency',
currency: 'CAD'
}).format(amount);
};
const formatPercentage = (value: number) => {
return `${value > 0 ? '+' : ''}${value.toFixed(1)}%`;
};
if (loading) {
return (
<LayoutWithSidebar>
<div className="flex items-center justify-center min-h-96">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-purple-600"></div>
</div>
</LayoutWithSidebar>
);
}
if (!analyticsData) {
return (
<LayoutWithSidebar>
<div className="max-w-4xl mx-auto px-4 py-8">
<div className="text-center">
<BarChart3 className="h-16 w-16 text-gray-400 mx-auto mb-4" />
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
Analytics Not Available
</h2>
<p className="text-gray-600 dark:text-gray-400">
Analytics data will be available once you have a business profile and some activity.
</p>
</div>
</div>
</LayoutWithSidebar>
);
}
return (
<LayoutWithSidebar>
<div className="max-w-7xl mx-auto px-4 py-8">
{/* Header */}
<div className="mb-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">Business Analytics</h1>
<p className="text-gray-600 dark:text-gray-400 mt-2">
Track your business performance and growth metrics
</p>
</div>
<div className="flex items-center space-x-2">
<select
value={timeRange}
onChange={(e) => setTimeRange(e.target.value)}
className="px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white"
>
<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>
</div>
</div>
</div>
{/* Key Metrics */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<div className="flex items-center">
<Eye className="h-8 w-8 text-blue-500 mr-4" />
<div>
<p className="text-sm font-medium text-gray-600 dark:text-gray-400">Profile Views</p>
<p className="text-2xl font-bold text-gray-900 dark:text-white">
{analyticsData.profileViews.thisMonth.toLocaleString()}
</p>
<div className="flex items-center mt-1">
{analyticsData.profileViews.trend > 0 ? (
<TrendingUp className="h-4 w-4 text-green-500 mr-1" />
) : (
<TrendingDown className="h-4 w-4 text-red-500 mr-1" />
)}
<span className={`text-sm ${
analyticsData.profileViews.trend > 0 ? 'text-green-600' : 'text-red-600'
}`}>
{formatPercentage(analyticsData.profileViews.trend)}
</span>
</div>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<div className="flex items-center">
<Users className="h-8 w-8 text-green-500 mr-4" />
<div>
<p className="text-sm font-medium text-gray-600 dark:text-gray-400">Leads Generated</p>
<p className="text-2xl font-bold text-gray-900 dark:text-white">
{analyticsData.leads.thisMonth}
</p>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
{analyticsData.leads.conversionRate.toFixed(1)}% conversion rate
</p>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<div className="flex items-center">
<DollarSign className="h-8 w-8 text-yellow-500 mr-4" />
<div>
<p className="text-sm font-medium text-gray-600 dark:text-gray-400">Revenue</p>
<p className="text-2xl font-bold text-gray-900 dark:text-white">
{formatCurrency(analyticsData.revenue.thisMonth)}
</p>
<div className="flex items-center mt-1">
{analyticsData.revenue.trend > 0 ? (
<TrendingUp className="h-4 w-4 text-green-500 mr-1" />
) : (
<TrendingDown className="h-4 w-4 text-red-500 mr-1" />
)}
<span className={`text-sm ${
analyticsData.revenue.trend > 0 ? 'text-green-600' : 'text-red-600'
}`}>
{formatPercentage(analyticsData.revenue.trend)}
</span>
</div>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<div className="flex items-center">
<Award className="h-8 w-8 text-purple-500 mr-4" />
<div>
<p className="text-sm font-medium text-gray-600 dark:text-gray-400">Success Rate</p>
<p className="text-2xl font-bold text-gray-900 dark:text-white">
{analyticsData.performance.caseSuccessRate}%
</p>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
Case success rate
</p>
</div>
</div>
</motion.div>
</div>
{/* Performance Metrics */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">Performance Metrics</h3>
<div className="space-y-4">
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Response Time</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{analyticsData.performance.responseTime}h avg
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Client Satisfaction</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{analyticsData.performance.clientSatisfaction}/5
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Case Success Rate</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{analyticsData.performance.caseSuccessRate}%
</span>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">Monthly Overview</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Total Profile Views</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{analyticsData.profileViews.total.toLocaleString()}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Total Leads</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{analyticsData.leads.total}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-600 dark:text-gray-400">Total Revenue</span>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{formatCurrency(analyticsData.revenue.total)}
</span>
</div>
</div>
</motion.div>
</div>
{/* Chart Placeholder */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6 }}
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">Performance Trends</h3>
<div className="h-64 flex items-center justify-center bg-gray-50 dark:bg-gray-700 rounded-lg">
<div className="text-center">
<BarChart3 className="h-12 w-12 text-gray-400 mx-auto mb-2" />
<p className="text-gray-600 dark:text-gray-400">Chart visualization coming soon</p>
</div>
</div>
</motion.div>
</div>
</LayoutWithSidebar>
);
};
export default BusinessAnalyticsPage;