first commit

This commit is contained in:
nBiqoz
2025-10-05 16:10:35 +02:00
parent 201fca4e68
commit 13cd637391
70 changed files with 7287 additions and 130 deletions

View File

@@ -0,0 +1,95 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";
interface ModelDistributionChartProps {
title: string;
data: Array<{
name: string;
value: number;
}>;
}
interface TooltipPayload {
value: number;
payload: {
name: string;
value: number;
};
}
interface CustomTooltipProps {
active?: boolean;
payload?: TooltipPayload[];
}
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
if (active && payload && payload.length) {
return (
<div style={{
backgroundColor: "hsl(var(--background))",
border: "1px solid hsl(var(--border))",
borderRadius: "8px",
padding: "8px",
fontSize: "12px"
}}>
<p style={{ margin: 0, color: "#ff0000" }}>
{`${payload[0].value.toLocaleString()} tokens`}
</p>
<p style={{ margin: 0, color: "#ff0000" }}>
{payload[0].payload.name}
</p>
</div>
);
}
return null;
};
export function ModelDistributionChart({
title,
data,
}: ModelDistributionChartProps) {
return (
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
</CardHeader>
<CardContent className="pt-0">
<ResponsiveContainer width="100%" height={200}>
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted/20" />
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
tick={false}
/>
<YAxis
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
/>
<Tooltip content={<CustomTooltip />} />
<Bar
dataKey="value"
fill="#000000"
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,58 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from "recharts";
interface ModelUsageChartProps {
data: Record<string, number>;
}
export function ModelUsageChart({ data }: ModelUsageChartProps) {
const chartData = Object.entries(data).map(([model, usage]) => ({
model: model.replace('gpt-', 'GPT-').replace('claude-', 'Claude-'),
usage,
}));
return (
<Card>
<CardHeader>
<CardTitle className="text-base font-medium">Usage par modèle</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="model"
className="text-xs fill-muted-foreground"
angle={-45}
textAnchor="end"
height={60}
/>
<YAxis className="text-xs fill-muted-foreground" />
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
}}
/>
<Bar
dataKey="usage"
fill="hsl(var(--primary))"
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,110 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend,
} from "recharts";
import { useUserActivity } from "@/hooks/useUserActivity";
import { AlertCircle } from "lucide-react";
export function RealUserActivityChart() {
const { activity, loading, error } = useUserActivity();
if (loading) {
return (
<Card>
<CardContent className="flex items-center justify-center h-64">
<div className="h-64 bg-muted animate-pulse rounded-lg w-full" />
</CardContent>
</Card>
);
}
if (error || !activity) {
return (
<Card>
<CardContent className="flex items-center justify-center h-64">
<div className="text-center">
<AlertCircle className="h-8 w-8 text-destructive mx-auto mb-2" />
<p className="text-sm text-muted-foreground">
Erreur lors du chargement
</p>
</div>
</CardContent>
</Card>
);
}
const data = [
{
name: "Utilisateurs actifs",
value: activity.activeUsers,
color: "#22c55e", // Vert clair pour actifs
},
{
name: "Utilisateurs inactifs",
value: activity.inactiveUsers,
color: "#ef4444", // Rouge pour inactifs
},
];
const total = activity.activeUsers + activity.inactiveUsers;
return (
<Card>
<CardHeader>
<CardTitle className="text-base font-medium">
Activité des utilisateurs
</CardTitle>
<p className="text-sm text-muted-foreground">
Actifs = connectés dans les 7 derniers jours
</p>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
paddingAngle={5}
dataKey="value"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: "hsl(var(--background))",
border: "1px solid hsl(var(--border))",
borderRadius: "8px",
}}
formatter={(value: number) => [
`${value} utilisateurs (${((value / total) * 100).toFixed(
1
)}%)`,
"",
]}
/>
<Legend
formatter={(value, entry) => (
<span style={{ color: entry.color }}>
{value}: {entry.payload?.value} (
{((entry.payload?.value / total) * 100).toFixed(1)}%)
</span>
)}
/>
</PieChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,62 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from "recharts";
interface SimpleBarChartProps {
title: string;
data: Array<{
name: string;
value: number;
}>;
color?: string;
}
export function SimpleBarChart({ title, data, color = "hsl(var(--primary))" }: SimpleBarChartProps) {
return (
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">{title}</CardTitle>
</CardHeader>
<CardContent className="pt-0">
<ResponsiveContainer width="100%" height={200}>
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted/20" />
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
/>
<YAxis
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
fontSize: '12px'
}}
/>
<Bar
dataKey="value"
fill={color}
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,70 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from "recharts";
interface SimpleStatsChartProps {
title: string;
data: Array<{
name: string;
value: number;
}>;
color?: string;
}
export function SimpleStatsChart({ title, data, color = "hsl(var(--primary))" }: SimpleStatsChartProps) {
return (
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">{title}</CardTitle>
</CardHeader>
<CardContent className="pt-0">
<ResponsiveContainer width="100%" height={200}>
<AreaChart data={data}>
<defs>
<linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={color} stopOpacity={0.3}/>
<stop offset="95%" stopColor={color} stopOpacity={0}/>
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted/20" />
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
/>
<YAxis
axisLine={false}
tickLine={false}
className="text-xs fill-muted-foreground"
/>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
fontSize: '12px'
}}
/>
<Area
type="monotone"
dataKey="value"
stroke={color}
strokeWidth={2}
fill="url(#colorGradient)"
/>
</AreaChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,74 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from "recharts";
interface UsageChartProps {
data: Array<{
date: string;
conversations: number;
tokens: number;
}>;
}
export function UsageChart({ data }: UsageChartProps) {
return (
<Card>
<CardHeader>
<CardTitle className="text-base font-medium">Usage quotidien</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis
dataKey="date"
className="text-xs fill-muted-foreground"
tickFormatter={(value) => new Date(value).toLocaleDateString('fr-FR', {
month: 'short',
day: 'numeric'
})}
/>
<YAxis className="text-xs fill-muted-foreground" />
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
}}
labelFormatter={(value) => new Date(value).toLocaleDateString('fr-FR')}
formatter={(value: number, name: string) => {
if (name === 'tokens') {
return [Math.round(value / 1000), "Tokens (k)"];
}
return [value, name];
}}
/>
<Line
type="monotone"
dataKey="conversations"
stroke="hsl(var(--primary))"
strokeWidth={2}
name="Conversations"
/>
<Line
type="monotone"
dataKey="tokens"
stroke="hsl(var(--destructive))"
strokeWidth={2}
name="tokens"
/>
</LineChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,81 @@
"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend
} from "recharts";
interface UserActivityChartProps {
activeUsers: number;
inactiveUsers: number;
}
export function UserActivityChart({ activeUsers, inactiveUsers }: UserActivityChartProps) {
const data = [
{
name: 'Utilisateurs actifs',
value: activeUsers,
color: '#22c55e' // Vert clair pour actifs
},
{
name: 'Utilisateurs inactifs',
value: inactiveUsers,
color: '#ef4444' // Rouge pour inactifs
},
];
const total = activeUsers + inactiveUsers;
return (
<Card>
<CardHeader>
<CardTitle className="text-base font-medium">Activité des utilisateurs</CardTitle>
<p className="text-sm text-muted-foreground">
Actifs = connectés dans les 7 derniers jours
</p>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
paddingAngle={5}
dataKey="value"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: 'hsl(var(--background))',
border: '1px solid hsl(var(--border))',
borderRadius: '8px',
}}
formatter={(value: number) => [
`${value} utilisateurs (${((value / total) * 100).toFixed(1)}%)`,
''
]}
/>
<Legend
formatter={(value, entry) => (
<span style={{ color: entry.color }}>
{value}: {entry.payload?.value} ({((entry.payload?.value / total) * 100).toFixed(1)}%)
</span>
)}
/>
</PieChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}