import React, { useState, useMemo, useCallback } from 'react'; import type { IAgentDashboardData } from '../../service/agent-analytics/agent-analytics.interface'; import { recomaze_ai_personalization_env } from '../../env'; import Section from './Section'; import ChartCanvas from './ChartCanvas'; import EmptyState from './EmptyState'; import ErrorBanner from './ErrorBanner'; import { ChartSkeleton } from './CardSkeleton'; import { formatNumber, formatPercentage } from './helpers'; import InfoTooltip from './InfoTooltip'; import { BAR_CHART_OPTIONS, DOUGHNUT_CHART_OPTIONS, LINE_CHART_OPTIONS, LINE_CHART_OPTIONS_NO_LEGEND, PRODUCT_SORT_KEYS, getDefaultProductPerformance, getDefaultIntentSentiment, getDefaultChatbotPerformance, getDefaultCompetitiveIntel, getDefaultEngagementPatterns, buildCategoryDistributionChartData, buildIntentDistributionChartData, buildSentimentBreakdownChartData, buildOutcomeDistributionChartData, buildSentimentTrendChartData, buildSatisfactionTrendChartData, buildPeakHoursChartData, buildLanguageDistributionChartData, } from './analyticsTab.utils'; interface AnalyticsTabProps { data: IAgentDashboardData | null; loading: boolean; error: string | null; onRetry: () => void; } type SortDirection = 'ascending' | 'descending'; const PRODUCTS_PAGE_SIZE = 10; const SortIcon = ({ direction, active, }: { direction: SortDirection; active: boolean; }) => ( {direction === 'ascending' ? '\u2191' : '\u2193'} ); const AnalyticsTab = ({ data, loading, error, onRetry, }: AnalyticsTabProps): JSX.Element => { const [sortIndex, setSortIndex] = useState(0); const [sortDirection, setSortDirection] = useState('descending'); const [visibleProductsCount, setVisibleProductsCount] = useState(PRODUCTS_PAGE_SIZE); const currencySymbol = recomaze_ai_personalization_env?.currency || 'USD'; const handleSort = useCallback( (headingIndex: number) => { if (sortIndex === headingIndex) { setSortDirection(d => (d === 'ascending' ? 'descending' : 'ascending')); } else { setSortIndex(headingIndex); setSortDirection('descending'); } setVisibleProductsCount(PRODUCTS_PAGE_SIZE); }, [sortIndex] ); if (loading) { return (
); } if (error) return ; if (!data) return ; const pp = data.product_performance || getDefaultProductPerformance(); const is_ = data.intent_sentiment || getDefaultIntentSentiment(); const cp = data.chatbot_performance || getDefaultChatbotPerformance(); const ci = data.competitive_intel || getDefaultCompetitiveIntel(); const ep = data.engagement_patterns || getDefaultEngagementPatterns(); const sortedProducts = useMemo(() => { const sorted = [...(pp.top_products || [])]; const key = PRODUCT_SORT_KEYS[sortIndex]; if (!key) return sorted; sorted.sort((a, b) => { const va = (a[key] as number) ?? 0; const vb = (b[key] as number) ?? 0; return sortDirection === 'ascending' ? va - vb : vb - va; }); return sorted; }, [pp.top_products, sortIndex, sortDirection]); const visibleProducts = sortedProducts.slice(0, visibleProductsCount); const remainingProducts = sortedProducts.length - visibleProducts.length; const catData = buildCategoryDistributionChartData( pp.category_distribution || {} ); const intentData = buildIntentDistributionChartData( is_.intent_distribution || {} ); const sentData = buildSentimentBreakdownChartData( is_.sentiment_breakdown || { positive: 0, neutral: 0, negative: 0 } ); const outcomeData = buildOutcomeDistributionChartData( is_.outcome_distribution || {} ); const sentTrendData = buildSentimentTrendChartData(is_.sentiment_trend || []); const satData = buildSatisfactionTrendChartData(cp.satisfaction_trend || []); const peakData = buildPeakHoursChartData(ep.peak_hours || {}); const langData = buildLanguageDistributionChartData( ep.language_distribution || {} ); const tableHeadings = [ 'Recommended', 'Clicked', 'Added to cart', 'Click Rate', 'Cart Rate', ]; return (
{/* Product Performance */}
{sortedProducts.length > 0 ? (
{tableHeadings.map((h, i) => ( ))} {visibleProducts.map(p => ( ))}
Product handleSort(i)} > {h}
{p.name || p.sku} {p.price > 0 && ( {`${currencySymbol} ${formatNumber(p.price, 2)}`} )} {formatNumber(p.times_recommended)} {formatNumber(p.times_clicked)} {formatNumber(p.times_carted)} {formatPercentage(p.click_rate)} {formatPercentage(p.cart_rate)}
{remainingProducts > 0 && (
Showing {visibleProducts.length} of {sortedProducts.length} {sortedProducts.length > PRODUCTS_PAGE_SIZE * 2 && ( )}
)} {visibleProducts.length > PRODUCTS_PAGE_SIZE && remainingProducts === 0 && (
)}
) : ( )}
{/* Missing Products + Category Distribution */}
{(pp.missing_products || []).length > 0 ? (
{pp.missing_products.map((m, i) => (
{m.name} {m.times_requested}x requested
))}
) : ( )}
{catData ? ( ) : ( )}
{/* Intent & Sentiment */}
{intentData ? ( ) : ( )}
{sentData ? ( ) : ( )}
{outcomeData ? ( ) : ( )}
{sentTrendData ? ( ) : ( )}
{/* Chatbot Performance */}

Satisfaction Trend

{satData ? ( ) : ( )}

Common Questions

{(cp.common_questions || []).length > 0 ? (
{cp.common_questions.map((q, i) => (
{q.question} {q.count}x
))}
) : ( )}

Pain Points

{(cp.common_pain_points || []).length > 0 ? (
{cp.common_pain_points.map((p, i) => (
{p.issue} {p.count}x
))}
) : ( )}
{/* Competitive Intelligence */}
{(ci.competitors || []).length > 0 ? (
{ci.competitors.map(c => ( ))}
Competitor Mentions Contexts
{c.name} {c.mention_count}
{(c.contexts || []).slice(0, 3).map((ctx, j) => ( {ctx} ))}
) : ( )}
{/* Engagement Patterns */}
{peakData ? ( ) : ( )}
{langData ? ( ) : ( )}

Avg User Message

{formatNumber(ep.avg_user_message_length, 0)}{' '} chars

Avg AI Response

{formatNumber(ep.avg_ai_response_length, 0)}{' '} chars

With Products

{formatNumber(ep.conversations_with_products)}

Product Engagement

{formatPercentage(ep.product_engagement_rate)}

); }; export default AnalyticsTab;