Add registration_activity chart and enhance admin statistics

- Introduced `RegistrationActivityChart` to display user registration trends over 14 days.
- Enhanced `AdminStatsResponse` with `registration_activity`, providing improved insights for admin users.
- Updated demo data to include realistic registration activity and organization details.
- Refactored admin page to use updated statistics data model and improved query handling.
- Fixed inconsistent timezone handling in statistical analytics and demo user timestamps.
This commit is contained in:
Felipe Cardoso
2025-11-24 17:42:43 +01:00
parent 9f655913b1
commit a05def5906
9 changed files with 664 additions and 226 deletions

View File

@@ -14,39 +14,56 @@ import {
Tooltip,
ResponsiveContainer,
Legend,
Rectangle,
} from 'recharts';
import { ChartCard } from './ChartCard';
import { CHART_PALETTES } from '@/lib/chart-colors';
export interface OrganizationDistributionData {
export interface OrgDistributionData {
name: string;
value: number;
}
interface OrganizationDistributionChartProps {
data?: OrganizationDistributionData[];
data?: OrgDistributionData[];
loading?: boolean;
error?: string | null;
}
// Generate mock data for development/demo
function generateMockData(): OrganizationDistributionData[] {
return [
{ name: 'Engineering', value: 45 },
{ name: 'Marketing', value: 28 },
{ name: 'Sales', value: 35 },
{ name: 'Operations', value: 22 },
{ name: 'HR', value: 15 },
{ name: 'Finance', value: 18 },
];
}
// Custom tooltip with proper theme colors
const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
return (
<div
style={{
backgroundColor: 'hsl(var(--popover) / 0.95)',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
padding: '10px 14px',
boxShadow: '0 2px 2px rgba(0, 0, 0, 0.5)',
backdropFilter: 'blur(8px)',
}}
>
<p style={{ color: 'hsl(var(--popover-foreground))', margin: 0, fontSize: '14px', fontWeight: 600 }}>
{payload[0].payload.name}
</p>
<p style={{ color: 'hsl(var(--muted-foreground))', margin: '4px 0 0 0', fontSize: '13px' }}>
Members: <span style={{ fontWeight: 600, color: 'hsl(var(--popover-foreground))' }}>{payload[0].value}</span>
</p>
</div>
);
}
return null;
};
export function OrganizationDistributionChart({
data,
loading,
error,
}: OrganizationDistributionChartProps) {
const chartData = data || generateMockData();
// Show empty chart if no data available
const rawData = data || [];
const hasData = rawData.length > 0 && rawData.some((d) => d.value > 0);
return (
<ChartCard
@@ -55,42 +72,33 @@ export function OrganizationDistributionChart({
loading={loading}
error={error}
>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="name"
stroke="hsl(var(--border))"
tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }}
tickLine={{ stroke: 'hsl(var(--border))' }}
/>
<YAxis
stroke="hsl(var(--border))"
tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }}
tickLine={{ stroke: 'hsl(var(--border))' }}
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--popover))',
border: '1px solid hsl(var(--border))',
borderRadius: '6px',
color: 'hsl(var(--popover-foreground))',
}}
labelStyle={{ color: 'hsl(var(--popover-foreground))' }}
/>
<Legend
wrapperStyle={{
paddingTop: '20px',
}}
/>
<Bar
dataKey="value"
name="Total Members"
fill={CHART_PALETTES.bar[0]}
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
{!hasData && !loading && !error ? (
<div className="flex items-center justify-center h-[300px] text-muted-foreground">
<p>No organization data available</p>
</div>
) : (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={rawData} margin={{ top: 5, right: 30, left: 20, bottom: 80 }}>
<CartesianGrid strokeDasharray="3 3" style={{ stroke: 'var(--muted)', opacity: 0.2 }} />
<XAxis
dataKey="name"
angle={-45}
textAnchor="end"
style={{ fill: 'var(--muted-foreground)', fontSize: '12px' }}
/>
<YAxis
style={{ fill: 'var(--muted-foreground)', fontSize: '12px' }}
/>
<Tooltip content={<CustomTooltip />} />
<Bar
dataKey="value"
fill={CHART_PALETTES.bar[0]}
radius={[4, 4, 0, 0]}
activeBar={{ fill: CHART_PALETTES.bar[0] }}
/>
</BarChart>
</ResponsiveContainer>
)}
</ChartCard>
);
}