import React, { useState, useEffect } from 'react'; import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, Title, Tooltip, } from 'chart.js'; import { Bar } from 'react-chartjs-2'; import userService from '../api/services/userService'; import Dropdown from '../components/Dropdown'; import { htmlLegendPlugin } from '../utils/chartUtils'; import { formatDate } from '../utils/dateTimeUtils'; import { APIKeyData } from './types'; import type { ChartData } from 'chart.js'; import SkeletonLoader from '../components/SkeletonLoader'; ChartJS.register( CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ); const filterOptions = [ { label: 'Hour', value: 'last_hour' }, { label: '24 Hours', value: 'last_24_hour' }, { label: '7 Days', value: 'last_7_days' }, { label: '15 Days', value: 'last_15_days' }, { label: '30 Days', value: 'last_30_days' }, ]; export default function Analytics() { const [messagesData, setMessagesData] = useState | null>(null); const [tokenUsageData, setTokenUsageData] = useState | null>(null); const [feedbackData, setFeedbackData] = useState | null>(null); const [chatbots, setChatbots] = useState([]); const [selectedChatbot, setSelectedChatbot] = useState(); const [messagesFilter, setMessagesFilter] = useState<{ label: string; value: string; }>({ label: '30 Days', value: 'last_30_days' }); const [tokenUsageFilter, setTokenUsageFilter] = useState<{ label: string; value: string; }>({ label: '30 Days', value: 'last_30_days' }); const [feedbackFilter, setFeedbackFilter] = useState<{ label: string; value: string; }>({ label: '30 Days', value: 'last_30_days' }); const [loadingMessages, setLoadingMessages] = useState(true); const [loadingTokens, setLoadingTokens] = useState(true); const [loadingFeedback, setLoadingFeedback] = useState(true); const fetchChatbots = async () => { try { const response = await userService.getAPIKeys(); if (!response.ok) { throw new Error('Failed to fetch Chatbots'); } const chatbots = await response.json(); setChatbots(chatbots); } catch (error) { console.error(error); } }; const fetchMessagesData = async (chatbot_id?: string, filter?: string) => { setLoadingMessages(true); try { const response = await userService.getMessageAnalytics({ api_key_id: chatbot_id, filter_option: filter, }); if (!response.ok) { throw new Error('Failed to fetch analytics data'); } const data = await response.json(); setMessagesData(data.messages); } catch (error) { console.error(error); } finally { setLoadingMessages(false); } }; const fetchTokenData = async (chatbot_id?: string, filter?: string) => { setLoadingTokens(true); try { const response = await userService.getTokenAnalytics({ api_key_id: chatbot_id, filter_option: filter, }); if (!response.ok) { throw new Error('Failed to fetch analytics data'); } const data = await response.json(); setTokenUsageData(data.token_usage); } catch (error) { console.error(error); } finally { setLoadingTokens(false); } }; const fetchFeedbackData = async (chatbot_id?: string, filter?: string) => { setLoadingFeedback(true); try { const response = await userService.getFeedbackAnalytics({ api_key_id: chatbot_id, filter_option: filter, }); if (!response.ok) { throw new Error('Failed to fetch analytics data'); } const data = await response.json(); setFeedbackData(data.feedback); } catch (error) { console.error(error); } finally { setLoadingFeedback(false); } }; useEffect(() => { fetchChatbots(); }, []); useEffect(() => { const id = selectedChatbot?.id; const filter = messagesFilter; fetchMessagesData(id, filter?.value); }, [selectedChatbot, messagesFilter]); useEffect(() => { const id = selectedChatbot?.id; const filter = tokenUsageFilter; fetchTokenData(id, filter?.value); }, [selectedChatbot, tokenUsageFilter]); useEffect(() => { const id = selectedChatbot?.id; const filter = feedbackFilter; fetchFeedbackData(id, filter?.value); }, [selectedChatbot, feedbackFilter]); return (

Filter by chatbot

({ label: chatbot.name, value: chatbot.id, })), { label: 'None', value: '' }, ]} placeholder="Select chatbot" onSelect={(chatbot: { label: string; value: string }) => { setSelectedChatbot( chatbots.find((item) => item.id === chatbot.value), ); }} selectedValue={ (selectedChatbot && { label: selectedChatbot.name, value: selectedChatbot.id, }) || null } rounded="3xl" border="border" />
{/* Messages Analytics */}

Messages

{ setMessagesFilter(selectedOption); }} selectedValue={messagesFilter ?? null} rounded="3xl" border="border" contentSize="text-sm" />
{loadingMessages ? ( ) : ( formatDate(item), ), datasets: [ { label: 'Messages', data: Object.values(messagesData || {}), backgroundColor: '#7D54D1', }, ], }} legendID="legend-container-1" maxTicksLimitInX={8} isStacked={false} /> )}
{/* Token Usage Analytics */}

Token Usage

{ setTokenUsageFilter(selectedOption); }} selectedValue={tokenUsageFilter ?? null} rounded="3xl" border="border" contentSize="text-sm" />
{loadingTokens ? ( ) : ( formatDate(item), ), datasets: [ { label: 'Tokens', data: Object.values(tokenUsageData || {}), backgroundColor: '#7D54D1', }, ], }} legendID="legend-container-2" maxTicksLimitInX={8} isStacked={false} /> )}
{/* Feedback Analytics */}

Feedback

{ setFeedbackFilter(selectedOption); }} selectedValue={feedbackFilter ?? null} rounded="3xl" border="border" contentSize="text-sm" />
{loadingFeedback ? ( ) : ( formatDate(item), ), datasets: [ { label: 'Positive Feedback', data: Object.values(feedbackData || {}).map( (item) => item.positive, ), backgroundColor: '#7D54D1', }, { label: 'Negative Feedback', data: Object.values(feedbackData || {}).map( (item) => item.negative, ), backgroundColor: '#FF6384', }, ], }} legendID="legend-container-3" maxTicksLimitInX={8} isStacked={false} /> )}
); } type AnalyticsChartProps = { data: ChartData<'bar'>; legendID: string; maxTicksLimitInX: number; isStacked: boolean; }; function AnalyticsChart({ data, legendID, maxTicksLimitInX, isStacked, }: AnalyticsChartProps) { const options = { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false, }, htmlLegend: { containerID: legendID, }, }, scales: { x: { grid: { lineWidth: 0.2, color: '#C4C4C4', }, border: { width: 0.2, color: '#C4C4C4', }, ticks: { maxTicksLimit: maxTicksLimitInX, }, stacked: isStacked, }, y: { grid: { lineWidth: 0.2, color: '#C4C4C4', }, border: { width: 0.2, color: '#C4C4C4', }, stacked: isStacked, }, }, }; return ; }