Initial digitCRM project with backend and frontend

This commit is contained in:
2026-06-28 14:16:11 +03:00
commit fd30a5f2d1
94 changed files with 10919 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
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>
);
}