first commit
This commit is contained in:
19
hooks/use-mobile.ts
Normal file
19
hooks/use-mobile.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as React from "react"
|
||||
|
||||
const MOBILE_BREAKPOINT = 768
|
||||
|
||||
export function useIsMobile() {
|
||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
||||
|
||||
React.useEffect(() => {
|
||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
||||
const onChange = () => {
|
||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
||||
}
|
||||
mql.addEventListener("change", onChange)
|
||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
||||
return () => mql.removeEventListener("change", onChange)
|
||||
}, [])
|
||||
|
||||
return !!isMobile
|
||||
}
|
||||
66
hooks/useCollection.ts
Normal file
66
hooks/useCollection.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
|
||||
interface UseCollectionOptions {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
filter?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface CollectionResponse<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export function useCollection<T = Record<string, unknown>>(
|
||||
collectionName: string,
|
||||
options: UseCollectionOptions = {}
|
||||
) {
|
||||
const [data, setData] = useState<T[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
|
||||
const { page = 1, limit = 20, filter = {} } = options;
|
||||
|
||||
// Mémoriser la chaîne JSON du filtre pour éviter les re-renders inutiles
|
||||
const filterString = useMemo(() => JSON.stringify(filter), [filter]);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
filter: filterString
|
||||
});
|
||||
|
||||
const response = await fetch(`/api/collections/${collectionName}?${params}`);
|
||||
if (!response.ok) throw new Error(`Erreur lors du chargement de ${collectionName}`);
|
||||
|
||||
const result: CollectionResponse<T> = await response.json();
|
||||
setData(result.data);
|
||||
setTotal(result.total);
|
||||
setTotalPages(result.totalPages);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur inconnue');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [collectionName, page, limit, filterString]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
const refetch = useCallback(() => {
|
||||
return fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return { data, loading, error, total, totalPages, refetch };
|
||||
}
|
||||
34
hooks/useMetrics.ts
Normal file
34
hooks/useMetrics.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { DashboardMetrics } from '@/lib/types';
|
||||
|
||||
export function useMetrics() {
|
||||
const [metrics, setMetrics] = useState<DashboardMetrics | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchMetrics = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch('/api/metrics');
|
||||
if (!response.ok) throw new Error('Erreur lors du chargement des métriques');
|
||||
const data = await response.json();
|
||||
setMetrics(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Erreur inconnue');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchMetrics();
|
||||
}, [fetchMetrics]);
|
||||
|
||||
const refetch = useCallback(() => {
|
||||
return fetchMetrics();
|
||||
}, [fetchMetrics]);
|
||||
|
||||
return { metrics, loading, error, refetch };
|
||||
}
|
||||
54
hooks/useStats.ts
Normal file
54
hooks/useStats.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface DailyToken {
|
||||
name: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface ModelDistribution {
|
||||
name: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface StatsData {
|
||||
dailyTokens: DailyToken[];
|
||||
modelDistribution: ModelDistribution[];
|
||||
}
|
||||
|
||||
export function useStats() {
|
||||
const [stats, setStats] = useState<StatsData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchStats = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await fetch("/api/stats");
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors du chargement des statistiques");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setStats(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Erreur inconnue");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchStats();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
stats,
|
||||
loading,
|
||||
error,
|
||||
refetch: fetchStats
|
||||
};
|
||||
}
|
||||
45
hooks/useUserActivity.ts
Normal file
45
hooks/useUserActivity.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface UserActivityData {
|
||||
activeUsers: number;
|
||||
inactiveUsers: number;
|
||||
totalUsers: number;
|
||||
}
|
||||
|
||||
export function useUserActivity() {
|
||||
const [activity, setActivity] = useState<UserActivityData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchActivity = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await fetch("/api/user-activity");
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors du chargement de l'activité des utilisateurs");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setActivity(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Erreur inconnue");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchActivity();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
activity,
|
||||
loading,
|
||||
error,
|
||||
refetch: fetchActivity
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user