diff --git a/components/collections/transactions-table.tsx b/components/collections/transactions-table.tsx index 2e19165..b2c7102 100644 --- a/components/collections/transactions-table.tsx +++ b/components/collections/transactions-table.tsx @@ -14,7 +14,7 @@ import { import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { ChevronLeft, ChevronRight } from "lucide-react"; -import { formatDate, formatCurrency } from "@/lib/utils"; +import { formatDate } from "@/lib/utils"; import { LibreChatTransaction, LibreChatUser } from "@/lib/types"; // Interface étendue pour les transactions avec description optionnelle @@ -53,29 +53,24 @@ export function TransactionsTable() { return user?.name || user?.email || `Utilisateur ${userId.slice(-8)}`; }; - // Fonction pour formater le montant en euros - const formatAmount = (rawAmount: number): string => { - // Convertir les tokens en euros (exemple: 1000 tokens = 1 euro) - const euros = rawAmount / 1000; - return formatCurrency(euros); - }; - // Fonction pour obtenir la description const getDescription = (transaction: LibreChatTransaction): string => { const transactionWithDesc = transaction as TransactionWithDescription; - - if (transactionWithDesc.description && - typeof transactionWithDesc.description === 'string' && - transactionWithDesc.description !== "undefined") { + + if ( + transactionWithDesc.description && + typeof transactionWithDesc.description === "string" && + transactionWithDesc.description !== "undefined" + ) { return transactionWithDesc.description; } - + // Générer une description basée sur le type et le montant const amount = Math.abs(Number(transaction.rawAmount) || 0); if (amount > 0) { return `Consommation de ${amount.toLocaleString()} tokens`; } - + return "Transaction sans description"; }; @@ -111,7 +106,6 @@ export function TransactionsTable() { ID Utilisateur Type - Montant Tokens Description Date @@ -151,11 +145,6 @@ export function TransactionsTable() { {isCredit ? "Crédit" : "Débit"} - - - {formatAmount(transaction.rawAmount)} - - {tokenAmount > 0 && ( diff --git a/components/dashboard/dashboard-users-list.tsx b/components/dashboard/dashboard-users-list.tsx index a954a19..fc6a376 100644 --- a/components/dashboard/dashboard-users-list.tsx +++ b/components/dashboard/dashboard-users-list.tsx @@ -10,7 +10,6 @@ import { useCollection } from "@/hooks/useCollection"; import { LibreChatUser, LibreChatConversation, - LibreChatTransaction, LibreChatBalance, LibreChatMessage, } from "@/lib/types"; @@ -23,15 +22,28 @@ interface DashboardUser { credits: number; } -// Fonction utilitaire pour valider et convertir les dates +// Interfaces pour les collections tokens et toolcalls +interface TokenDocument { + _id: string; + user?: string; + userId?: string; + amount?: number; + tokens?: number; + count?: number; +} + +interface ToolcallDocument { + _id: string; + user?: string; + userId?: string; + tokens?: number; + tokenCount?: number; +} + const isValidDate = (value: unknown): value is string | number | Date => { if (!value) return false; - if (value instanceof Date) return !isNaN(value.getTime()); - if (typeof value === 'string' || typeof value === 'number') { - const date = new Date(value); - return !isNaN(date.getTime()); - } - return false; + const date = new Date(value as string | number | Date); + return !isNaN(date.getTime()); }; export function DashboardUsersList() { @@ -39,23 +51,32 @@ export function DashboardUsersList() { const [isLoading, setIsLoading] = useState(true); // Récupérer toutes les données nécessaires - const { data: users, loading: usersLoading } = useCollection("users"); - const { data: conversations, loading: conversationsLoading } = useCollection("conversations"); - const { data: transactions, loading: transactionsLoading } = useCollection("transactions"); - const { data: balances, loading: balancesLoading } = useCollection("balances"); - const { data: messages, loading: messagesLoading } = useCollection("messages"); - const { data: tokens, loading: tokensLoading } = useCollection("tokens"); - const { data: toolcalls, loading: toolcallsLoading } = useCollection("toolcalls"); + const { data: users, loading: usersLoading } = + useCollection("users"); + const { data: conversations, loading: conversationsLoading } = + useCollection("conversations"); + const { data: balances, loading: balancesLoading } = + useCollection("balances"); + const { data: messages, loading: messagesLoading } = + useCollection("messages"); + const { data: tokens, loading: tokensLoading } = + useCollection("tokens"); + const { data: toolcalls, loading: toolcallsLoading } = + useCollection("toolcalls"); const processUsers = useCallback(() => { - if (!users?.length || !conversations?.length || !balances?.length || !messages?.length) { + if ( + !users?.length || + !conversations?.length || + !balances?.length || + !messages?.length + ) { return; } console.log("🔄 Processing users data..."); console.log("Users:", users.length); console.log("Conversations:", conversations.length); - console.log("Transactions:", transactions?.length || 0); console.log("Balances:", balances.length); console.log("Messages:", messages.length); console.log("Tokens collection:", tokens?.length || 0); @@ -81,11 +102,13 @@ export function DashboardUsersList() { ); // Calculer les tokens depuis les conversations de l'utilisateur - const userConversationIds = userConversations.map(conv => conv.conversationId); - const conversationMessages = messages.filter( - (msg: LibreChatMessage) => userConversationIds.includes(msg.conversationId) + const userConversationIds = userConversations.map( + (conv) => conv.conversationId ); - + const conversationMessages = messages.filter((msg: LibreChatMessage) => + userConversationIds.includes(msg.conversationId) + ); + const totalTokensFromConversations = conversationMessages.reduce( (sum: number, msg: LibreChatMessage) => sum + (msg.tokenCount || 0), 0 @@ -96,17 +119,29 @@ export function DashboardUsersList() { let tokensFromToolcalls = 0; if (tokens?.length) { - const userTokens = tokens.filter((token: any) => token.user === user._id || token.userId === user._id); - tokensFromTokensCollection = userTokens.reduce((sum: number, token: any) => { - return sum + (token.amount || token.tokens || token.count || 0); - }, 0); + const userTokens = tokens.filter( + (token: TokenDocument) => + token.user === user._id || token.userId === user._id + ); + tokensFromTokensCollection = userTokens.reduce( + (sum: number, token: TokenDocument) => { + return sum + (token.amount || token.tokens || token.count || 0); + }, + 0 + ); } if (toolcalls?.length) { - const userToolcalls = toolcalls.filter((toolcall: any) => toolcall.user === user._id || toolcall.userId === user._id); - tokensFromToolcalls = userToolcalls.reduce((sum: number, toolcall: any) => { - return sum + (toolcall.tokens || toolcall.tokenCount || 0); - }, 0); + const userToolcalls = toolcalls.filter( + (toolcall: ToolcallDocument) => + toolcall.user === user._id || toolcall.userId === user._id + ); + tokensFromToolcalls = userToolcalls.reduce( + (sum: number, toolcall: ToolcallDocument) => { + return sum + (toolcall.tokens || toolcall.tokenCount || 0); + }, + 0 + ); } // Obtenir les balances de l'utilisateur @@ -118,16 +153,19 @@ export function DashboardUsersList() { const sortedBalances = userBalances.sort((a, b) => { const dateA = a.updatedAt || a.createdAt; const dateB = b.updatedAt || b.createdAt; - + // Vérifier que les dates sont valides avant de les comparer if (isValidDate(dateA) && isValidDate(dateB)) { - return new Date(dateB as string | number | Date).getTime() - new Date(dateA as string | number | Date).getTime(); + return ( + new Date(dateB as string | number | Date).getTime() - + new Date(dateA as string | number | Date).getTime() + ); } - + // Si seulement une date existe et est valide, la privilégier if (isValidDate(dateA) && !isValidDate(dateB)) return -1; if (!isValidDate(dateA) && isValidDate(dateB)) return 1; - + // Si aucune date n'existe ou n'est valide, garder l'ordre actuel return 0; }); @@ -163,23 +201,24 @@ export function DashboardUsersList() { creditsUsed: creditsUsed, tokensFromCredits: tokensFromCredits, finalTokens: totalTokens, - messagesSample: userMessages.slice(0, 2).map(m => ({ - tokenCount: m.tokenCount, + messagesSample: userMessages.slice(0, 2).map((m) => ({ + tokenCount: m.tokenCount, model: m.model, isCreatedByUser: m.isCreatedByUser, - conversationId: m.conversationId + conversationId: m.conversationId, })), - conversationsSample: userConversations.slice(0, 2).map(c => ({ + conversationsSample: userConversations.slice(0, 2).map((c) => ({ conversationId: c.conversationId, - messagesCount: c.messages?.length || 0 - })) + messagesCount: c.messages?.length || 0, + })), }); // Ajouter l'utilisateur seulement s'il a des données significatives if (userConversations.length > 0 || totalTokens > 0 || credits > 0) { processedUsers.push({ userId: user._id, - userName: user.name || user.username || user.email || 'Utilisateur inconnu', + userName: + user.name || user.username || user.email || "Utilisateur inconnu", conversations: userConversations.length, tokens: totalTokens, credits: credits, @@ -195,17 +234,31 @@ export function DashboardUsersList() { console.log("✅ Top 5 users processed:", sortedUsers); setTopUsers(sortedUsers); setIsLoading(false); - }, [users, conversations, transactions, balances, messages, tokens, toolcalls]); + }, [users, conversations, balances, messages, tokens, toolcalls]); useEffect(() => { - const allDataLoaded = !usersLoading && !conversationsLoading && !balancesLoading && !messagesLoading && !tokensLoading && !toolcallsLoading; - + const allDataLoaded = + !usersLoading && + !conversationsLoading && + !balancesLoading && + !messagesLoading && + !tokensLoading && + !toolcallsLoading; + if (allDataLoaded) { processUsers(); } else { setIsLoading(true); } - }, [usersLoading, conversationsLoading, balancesLoading, messagesLoading, tokensLoading, toolcallsLoading, processUsers]); + }, [ + usersLoading, + conversationsLoading, + balancesLoading, + messagesLoading, + tokensLoading, + toolcallsLoading, + processUsers, + ]); if (isLoading) { return ( @@ -222,7 +275,10 @@ export function DashboardUsersList() {
{[...Array(5)].map((_, i) => ( -
+
@@ -250,7 +306,7 @@ export function DashboardUsersList() { Top 5 utilisateurs - + @@ -286,13 +342,17 @@ export function DashboardUsersList() { className="flex items-center justify-between p-3 border rounded-lg hover:bg-gray-50 transition-colors" >
- + {index + 1}

{user.userName}

- {user.conversations} conversation{user.conversations !== 1 ? 's' : ''} + {user.conversations} conversation + {user.conversations !== 1 ? "s" : ""}

@@ -310,4 +370,4 @@ export function DashboardUsersList() { ); -} \ No newline at end of file +}