canina/frontend/admin-panel/src/pages/Dashboard.tsx
2026-07-11 12:30:17 +03:30

129 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import { DollarSign, ShoppingCart, Users, Activity } from 'lucide-react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
import api from '../services/api';
export default function Dashboard() {
const [data, setData] = useState({
revenue: 0,
newOrders: 0,
users: 0,
todayVisits: 0
});
useEffect(() => {
const fetchStats = async () => {
try {
const response = await api.get('/admin/dashboard/stats');
if (response.data?.success) {
setData(response.data.data);
}
} catch (err) {
console.error('Failed to fetch stats', err);
}
};
fetchStats();
}, []);
const chartData = [
{ name: 'شنبه', بازدید: 400, فروش: 2400 },
{ name: 'یکشنبه', بازدید: 300, فروش: 1398 },
{ name: 'دوشنبه', بازدید: 200, فروش: 9800 },
{ name: 'سه‌شنبه', بازدید: 278, فروش: 3908 },
{ name: 'چهارشنبه', بازدید: 189, فروش: 4800 },
{ name: 'پنجشنبه', بازدید: 239, فروش: 3800 },
{ name: 'جمعه', بازدید: 349, فروش: 4300 },
];
const pieData = [
{ name: 'سگ', value: 400 },
{ name: 'گربه', value: 300 },
{ name: 'پرنده', value: 300 },
];
const COLORS = ['#0088FE', '#00C49F', '#FFBB28'];
const stats = [
{ title: 'درآمد کل', value: `${data.revenue.toLocaleString()} تومان`, icon: DollarSign, color: 'text-green-600', bg: 'bg-green-100' },
{ title: 'سفارشات جدید', value: data.newOrders.toString(), icon: ShoppingCart, color: 'text-blue-600', bg: 'bg-blue-100' },
{ title: 'کاربران فعال', value: data.users.toString(), icon: Users, color: 'text-purple-600', bg: 'bg-purple-100' },
{ title: 'بازدید امروز', value: data.todayVisits.toString(), icon: Activity, color: 'text-orange-600', bg: 'bg-orange-100' },
];
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-black text-gray-900">داشبورد</h2>
<p className="text-gray-500 font-medium mt-1">خلاصه‌ای از وضعیت فروشگاه کانینو</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{stats.map((stat, i) => {
const Icon = stat.icon;
return (
<div key={i} className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 flex items-center gap-4">
<div className={`w-14 h-14 rounded-2xl flex items-center justify-center ${stat.bg}`}>
<Icon className={`w-6 h-6 ${stat.color}`} />
</div>
<div>
<p className="text-sm font-bold text-gray-500">{stat.title}</p>
<p className="text-xl font-black text-gray-900 mt-1">{stat.value}</p>
</div>
</div>
);
})}
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 col-span-1 lg:col-span-2">
<h3 className="text-lg font-bold text-gray-900 mb-6">روند بازدید و فروش (۷ روز گذشته)</h3>
<div className="h-80 w-full" dir="ltr">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis dataKey="name" axisLine={false} tickLine={false} />
<YAxis axisLine={false} tickLine={false} />
<Tooltip />
<Line type="monotone" dataKey="فروش" stroke="#8b5cf6" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 8 }} />
<Line type="monotone" dataKey="بازدید" stroke="#10b981" strokeWidth={3} dot={{ r: 4 }} />
</LineChart>
</ResponsiveContainer>
</div>
</div>
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 col-span-1">
<h3 className="text-lg font-bold text-gray-900 mb-6">دسته‌بندی محصولات</h3>
<div className="h-80 w-full flex items-center justify-center">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={pieData}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={80}
fill="#8884d8"
paddingAngle={5}
dataKey="value"
>
{pieData.map((_entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</div>
<div className="flex justify-center gap-4 mt-4">
{pieData.map((entry, index) => (
<div key={entry.name} className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: COLORS[index % COLORS.length] }}></div>
<span className="text-sm font-medium text-gray-600">{entry.name}</span>
</div>
))}
</div>
</div>
</div>
</div>
);
}