diff --git a/src/app/(main)/(admin)/dashboard/page.tsx b/src/app/(main)/(admin)/dashboard/page.tsx index c4ac62ac..3a8024c1 100644 --- a/src/app/(main)/(admin)/dashboard/page.tsx +++ b/src/app/(main)/(admin)/dashboard/page.tsx @@ -7,7 +7,7 @@ import { differenceInDays } from 'date-fns'; import { ArrowRightIcon, BarChartIcon, BinaryIcon, ListTodoIcon, MessageSquareTextIcon, MessagesSquareIcon, UserIcon } from 'lucide-react'; import Link from 'next/link'; import { useMemo } from 'react'; -import { Bar, BarChart, ResponsiveContainer } from 'recharts'; +import { Bar, BarChart, Legend, ResponsiveContainer } from 'recharts'; import useSWR from 'swr'; export default function Page () { @@ -69,7 +69,7 @@ function TaskStats () { } type ChatStatsData = Partial>; -type DailyChatStatsData = (ChatStatsData & { date: string })[]; +type DailyChatStatsData = (ChatStatsData & { date: string, user_type: 'bot' | 'admin' | 'anonymous' | 'user' })[]; function ChatStats () { const { data, isLoading } = useSWR(['get', '/api/v1/stats/chats'], fetcher); @@ -103,15 +103,32 @@ function ChatDailyStats () { const { data = [] } = useSWR(['get', '/api/v1/stats/chats_daily'], fetcher); const refinedData = useMemo(() => { - const res: { day: number, value: number }[] = []; + const res: { day: number, value: number, user: number, admin: number, bot: number, anonymous: number }[] = []; for (let i = 0; i < 28; i++) { - res[i] = { day: 0, value: 0 }; + res[i] = { day: 0, value: 0, user: 0, admin: 0, bot: 0, anonymous: 0 }; } const now = new Date(); data.forEach(item => { const i = differenceInDays(now, item.date); if (i >= 0 && i < 28) { - res[i].value = item.chat_messages ?? 0; + switch (item.user_type) { + case 'admin': + res[i].admin = item.chat_messages ?? 0; + res[i].value += res[i].admin; + break; + case 'bot': + res[i].bot = item.chat_messages ?? 0; + res[i].value += res[i].bot; + break; + case 'anonymous': + res[i].anonymous = item.chat_messages ?? 0; + res[i].value += res[i].anonymous; + break; + case 'user': + res[i].user = item.chat_messages ?? 0; + res[i].value += res[i].user; + break; + } } }); return res; @@ -125,7 +142,30 @@ function ChatDailyStats () { > - + + + + + ( +
    +
  • + + Admin +
  • +
  • + + Bot +
  • +
  • + + User +
  • +
  • + + Anonymous +
  • +
+ )} />
diff --git a/src/app/api/v1/stats/[type]/route.ts b/src/app/api/v1/stats/[type]/route.ts index b23e92c5..218a8539 100644 --- a/src/app/api/v1/stats/[type]/route.ts +++ b/src/app/api/v1/stats/[type]/route.ts @@ -1,6 +1,7 @@ import { getDb } from '@/core/db'; import { getDocumentIndexTasksSummary } from '@/core/repositories/document_index_task'; import { defineHandler } from '@/lib/next/handler'; +import { sql } from 'kysely'; import { notFound } from 'next/navigation'; import { z } from 'zod'; @@ -87,14 +88,25 @@ async function getChatDailyStats () { .leftJoin('chat', 'chat.id', 'chat_message.chat_id') .select([ eb => eb.fn.count('chat.id').distinct().as('chats'), + eb => eb.case() + .when(sql`chat.created_by LIKE '\\$\\$a_%'`).then('anonymous') + .when(sql`chat.created_by LIKE '%-bot'`).then('bot') + .when(sql`chat.created_by = 'admin'`).then('admin') + .else('user') + .end().as('user_type'), eb => eb.fn.count('chat_message.id').as('chat_messages'), eb => eb.fn.count('chat.created_by').distinct().as('sessions'), eb => eb.fn('DATE', ['chat_message.created_at']).as('date'), ]) .where('role', '=', eb => eb.val('user')) - .groupBy('date') + .groupBy(['date', eb => eb.case() + .when(sql`chat.created_by LIKE '\\$\\$a_%'`).then('anonymous') + .when(sql`chat.created_by LIKE '%-bot'`).then('bot') + .when(sql`chat.created_by = 'admin'`).then('admin') + .else('user') + .end()]) .orderBy('date desc') - .limit(28) + .limit(28 * 4) .execute(); }