forked from cardosofelipe/pragma-stack
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:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user