Initial commit
This commit is contained in:
107
src/components/krow/ActivityCharts.jsx
Normal file
107
src/components/krow/ActivityCharts.jsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
ResponsiveContainer,
|
||||
LineChart,
|
||||
Line,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
BarChart,
|
||||
Bar,
|
||||
PieChart,
|
||||
Pie,
|
||||
Cell,
|
||||
Legend,
|
||||
} from 'recharts';
|
||||
|
||||
const PIE_COLORS = ['#0A39DF', '#059669', '#333F48', '#D97706', '#DC2626', '#0891B2', '#DB2777'];
|
||||
|
||||
function last7Days() {
|
||||
const days = [];
|
||||
for (let i = 6; i >= 0; i--) {
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() - i);
|
||||
days.push(d.toISOString().split('T')[0]);
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
export default function ActivityCharts({ activities }) {
|
||||
const timeSeries = useMemo(() => {
|
||||
const days = last7Days();
|
||||
return days.map((day) => {
|
||||
const dayActivities = activities.filter((a) => (a.created_date || '').slice(0, 10) === day);
|
||||
return {
|
||||
date: day.slice(5),
|
||||
signups: dayActivities.filter((a) => a.event_type === 'signup').length,
|
||||
logins: dayActivities.filter((a) => a.event_type === 'login').length,
|
||||
actions: dayActivities.length,
|
||||
};
|
||||
});
|
||||
}, [activities]);
|
||||
|
||||
const byType = useMemo(() => {
|
||||
const counts = {};
|
||||
activities.forEach((a) => {
|
||||
counts[a.event_type] = (counts[a.event_type] || 0) + 1;
|
||||
});
|
||||
return Object.entries(counts).map(([name, value]) => ({ name, value }));
|
||||
}, [activities]);
|
||||
|
||||
const byRole = useMemo(() => {
|
||||
const counts = {};
|
||||
activities.forEach((a) => {
|
||||
counts[a.account_type] = (counts[a.account_type] || 0) + 1;
|
||||
});
|
||||
return Object.entries(counts).map(([name, value]) => ({ name, value }));
|
||||
}, [activities]);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div className="bg-white rounded-xl border border-[#E5E7EB] p-5">
|
||||
<h3 className="text-[14px] font-semibold text-[#111827] mb-4">Activity (Last 7 Days)</h3>
|
||||
<ResponsiveContainer width="100%" height={240}>
|
||||
<LineChart data={timeSeries}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#F3F4F6" />
|
||||
<XAxis dataKey="date" tick={{ fontSize: 11 }} stroke="#9CA3AF" />
|
||||
<YAxis tick={{ fontSize: 11 }} stroke="#9CA3AF" allowDecimals={false} />
|
||||
<Tooltip />
|
||||
<Legend wrapperStyle={{ fontSize: 12 }} />
|
||||
<Line type="monotone" dataKey="signups" stroke="#0A39DF" strokeWidth={2} />
|
||||
<Line type="monotone" dataKey="logins" stroke="#059669" strokeWidth={2} />
|
||||
<Line type="monotone" dataKey="actions" stroke="#D97706" strokeWidth={2} />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl border border-[#E5E7EB] p-5">
|
||||
<h3 className="text-[14px] font-semibold text-[#111827] mb-4">Actions by Type</h3>
|
||||
<ResponsiveContainer width="100%" height={240}>
|
||||
<BarChart data={byType}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#F3F4F6" />
|
||||
<XAxis dataKey="name" tick={{ fontSize: 10 }} stroke="#9CA3AF" interval={0} angle={-20} textAnchor="end" height={50} />
|
||||
<YAxis tick={{ fontSize: 11 }} stroke="#9CA3AF" allowDecimals={false} />
|
||||
<Tooltip />
|
||||
<Bar dataKey="value" fill="#0A39DF" radius={[4, 4, 0, 0]} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl border border-[#E5E7EB] p-5">
|
||||
<h3 className="text-[14px] font-semibold text-[#111827] mb-4">Users by Role</h3>
|
||||
<ResponsiveContainer width="100%" height={240}>
|
||||
<PieChart>
|
||||
<Pie data={byRole} dataKey="value" nameKey="name" cx="50%" cy="50%" outerRadius={80} label>
|
||||
{byRole.map((_, i) => (
|
||||
<Cell key={i} fill={PIE_COLORS[i % PIE_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip />
|
||||
<Legend wrapperStyle={{ fontSize: 12 }} />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user