193 lines
6.8 KiB
TypeScript
193 lines
6.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||
import { analyticsAPI } from '@/lib/api';
|
||
import { BarChart, Bar, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, LineChart, Line } from 'recharts';
|
||
import DashboardLayout from '@/components/DashboardLayout';
|
||
|
||
const COLORS = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899'];
|
||
|
||
export default function Analytics() {
|
||
const [contactsByStatus, setContactsByStatus] = useState<any[]>([]);
|
||
const [contactsByType, setContactsByType] = useState<any[]>([]);
|
||
const [ticketsByStatus, setTicketsByStatus] = useState<any[]>([]);
|
||
const [ticketsByPriority, setTicketsByPriority] = useState<any[]>([]);
|
||
const [feedbackByRating, setFeedbackByRating] = useState<any[]>([]);
|
||
const [campaignPerformance, setCampaignPerformance] = useState<any[]>([]);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
fetchAnalytics();
|
||
}, []);
|
||
|
||
const fetchAnalytics = async () => {
|
||
try {
|
||
setLoading(true);
|
||
const [
|
||
statusRes,
|
||
typeRes,
|
||
ticketsStatusRes,
|
||
ticketsPriorityRes,
|
||
feedbackRes,
|
||
campaignRes,
|
||
] = await Promise.all([
|
||
analyticsAPI.getContactsByStatus(),
|
||
analyticsAPI.getContactsByType(),
|
||
analyticsAPI.getTicketsByStatus(),
|
||
analyticsAPI.getTicketsByPriority(),
|
||
analyticsAPI.getFeedbackByRating(),
|
||
analyticsAPI.getCampaignPerformance(),
|
||
]);
|
||
|
||
setContactsByStatus(statusRes.data);
|
||
setContactsByType(typeRes.data);
|
||
setTicketsByStatus(ticketsStatusRes.data);
|
||
setTicketsByPriority(ticketsPriorityRes.data);
|
||
setFeedbackByRating(feedbackRes.data);
|
||
setCampaignPerformance(campaignRes.data);
|
||
} catch (error) {
|
||
console.error('Error fetching analytics:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
if (loading) {
|
||
return (
|
||
<DashboardLayout>
|
||
<div className="text-center py-12">Зареждане...</div>
|
||
</DashboardLayout>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<DashboardLayout>
|
||
<div className="space-y-6">
|
||
<h1 className="text-3xl font-bold">Аналитика</h1>
|
||
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
{/* Contacts by Status */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Контакти по статус</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ResponsiveContainer width="100%" height={300}>
|
||
<PieChart>
|
||
<Pie
|
||
data={contactsByStatus}
|
||
dataKey="Count"
|
||
nameKey="Status"
|
||
cx="50%"
|
||
cy="50%"
|
||
outerRadius={80}
|
||
label
|
||
>
|
||
{contactsByStatus.map((entry, index) => (
|
||
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
|
||
))}
|
||
</Pie>
|
||
<Tooltip />
|
||
</PieChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Contacts by Type */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Контакти по тип</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ResponsiveContainer width="100%" height={300}>
|
||
<BarChart data={contactsByType}>
|
||
<CartesianGrid strokeDasharray="3 3" />
|
||
<XAxis dataKey="ContactType" />
|
||
<YAxis />
|
||
<Tooltip />
|
||
<Bar dataKey="Count" fill="#3b82f6" />
|
||
</BarChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Tickets by Status */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Билети по статус</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ResponsiveContainer width="100%" height={300}>
|
||
<BarChart data={ticketsByStatus}>
|
||
<CartesianGrid strokeDasharray="3 3" />
|
||
<XAxis dataKey="Status" />
|
||
<YAxis />
|
||
<Tooltip />
|
||
<Bar dataKey="Count" fill="#10b981" />
|
||
</BarChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Tickets by Priority */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Билети по приоритет</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ResponsiveContainer width="100%" height={300}>
|
||
<BarChart data={ticketsByPriority}>
|
||
<CartesianGrid strokeDasharray="3 3" />
|
||
<XAxis dataKey="Priority" />
|
||
<YAxis />
|
||
<Tooltip />
|
||
<Bar dataKey="Count" fill="#f59e0b" />
|
||
</BarChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Feedback by Rating */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Обратна връзка по рейтинг</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ResponsiveContainer width="100%" height={300}>
|
||
<BarChart data={feedbackByRating}>
|
||
<CartesianGrid strokeDasharray="3 3" />
|
||
<XAxis dataKey="Rating" />
|
||
<YAxis />
|
||
<Tooltip />
|
||
<Bar dataKey="Count" fill="#ef4444" />
|
||
</BarChart>
|
||
</ResponsiveContainer>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Campaign Performance */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>Производителност на кампаниите</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-4 max-h-80 overflow-y-auto">
|
||
{campaignPerformance.map((campaign, index) => (
|
||
<div key={index} className="border-b pb-4 last:border-b-0">
|
||
<h4 className="font-semibold text-sm">{campaign.CampaignName}</h4>
|
||
<div className="grid grid-cols-2 gap-2 mt-2 text-xs text-muted-foreground">
|
||
<div>Изпратени: {campaign.Sent}</div>
|
||
<div>Отворени: {campaign.Opened}</div>
|
||
<div>Кликнати: {campaign.Clicked}</div>
|
||
<div>Open Rate: {campaign.OpenRate}%</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</DashboardLayout>
|
||
);
|
||
}
|