"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { AlertCircle, BarChart as BarChartIcon, LineChart, RefreshCw, Users, ShoppingCart, TrendingUp, TrendingDown, DollarSign, MessageSquare, Clock, Landmark } from "lucide-react"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { ResponsiveContainer, PieChart, Pie, Cell, Tooltip, Legend, XAxis, YAxis, BarChart, Bar } from "recharts"; // API response data structure interface AnalyticsData { vendors?: { total?: number; newToday?: number; newThisWeek?: number; activeToday?: number; active?: number; stores?: number; dailyGrowth?: { date: string; count: number }[]; data?: { date: string; count: number }[]; }; orders?: { total?: number; totalToday?: number; totalThisWeek?: number; recent?: number; pending?: number; completed?: number; dailyOrders?: { date: string; count: number }[]; data?: { date: string; count: number }[]; }; revenue?: { total?: number; today?: number; thisWeek?: number; dailyRevenue?: { date: string; amount: number }[]; }; engagement?: { totalMessages?: number; activeChats?: number; avgResponseTime?: number; dailyMessages?: { date: string; count: number }[]; }; products?: { total?: number; recent?: number; }; stores?: { total?: number; active?: number; }; sessions?: { total?: number; active?: number; }; promotions?: { total?: number; active?: number; used?: number; totalDiscountAmount?: number; discountPercentage?: number; topPromotions?: { _id: string; count: number; totalDiscount: number }[]; discountByType?: { percentage?: { count: number; totalDiscount: number }; fixed?: { count: number; totalDiscount: number }; }; }; chats?: { totalChats?: number; activeChats?: number; totalMessages?: number; recentMessages?: number; messagesBySender?: { buyer: number; vendor: number }; avgResponseTimeMin?: number; messagesByHour?: number[]; }; telegram?: { totalUsers?: number; totalStoreConnections?: number; avgStoresPerUser?: number; multiStoreUsers?: number; }; escrow?: { total?: number; active?: number; released?: number; disputed?: number; disputeRate?: number; totalByCurrency?: { ltc: number; btc: number; xmr: number }; heldByCurrency?: { ltc: number; btc: number; xmr: number }; avgReleaseTimeHours?: number; }; security?: { blockedUsers?: { total?: number; recentlyBlocked?: number; } }; } export default function AdminAnalytics() { const [analyticsData, setAnalyticsData] = useState(null); const [loading, setLoading] = useState(true); const [dateRange, setDateRange] = useState("7days"); const [errorMessage, setErrorMessage] = useState(null); const [refreshing, setRefreshing] = useState(false); const fetchAnalyticsData = async () => { try { setLoading(true); setErrorMessage(null); const token = document.cookie .split("; ") .find((row) => row.startsWith("Authorization=")) ?.split("=")[1]; console.log("Token from cookie:", token ? token.substring(0, 10) + "..." : "not found"); console.log("API URL:", `${process.env.NEXT_PUBLIC_API_URL}/admin/analytics?range=${dateRange}`); const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/admin/analytics?range=${dateRange}`, { method: "GET", headers: { Authorization: `Bearer ${token}`, }, }); console.log("Response status:", response.status); console.log("Response ok:", response.ok); if (!response.ok) { const errorText = await response.text(); console.error("Error response:", errorText); throw new Error(`Failed to fetch analytics data: ${response.status} ${errorText}`); } const data = await response.json(); console.log("Analytics data received:", data); setAnalyticsData(data); } catch (error: any) { console.error("Error fetching analytics data:", error); setErrorMessage(`Failed to load analytics data: ${error.message}`); // For demo purposes, load mock data if API fails setAnalyticsData({ vendors: { total: 1248, newToday: 24, newThisWeek: 124, activeToday: 356, stores: 100, dailyGrowth: [ { date: "2023-11-01", count: 15 }, { date: "2023-11-02", count: 18 }, { date: "2023-11-03", count: 12 }, { date: "2023-11-04", count: 22 }, { date: "2023-11-05", count: 26 }, { date: "2023-11-06", count: 17 }, { date: "2023-11-07", count: 14 }, ], }, orders: { total: 5672, totalToday: 86, totalThisWeek: 432, pending: 47, completed: 5625, dailyOrders: [ { date: "2023-11-01", count: 54 }, { date: "2023-11-02", count: 62 }, { date: "2023-11-03", count: 58 }, { date: "2023-11-04", count: 71 }, { date: "2023-11-05", count: 68 }, { date: "2023-11-06", count: 65 }, { date: "2023-11-07", count: 54 }, ], }, revenue: { total: 156320, today: 3280, thisWeek: 18642, dailyRevenue: [ { date: "2023-11-01", amount: 2345 }, { date: "2023-11-02", amount: 2762 }, { date: "2023-11-03", amount: 2458 }, { date: "2023-11-04", amount: 3121 }, { date: "2023-11-05", amount: 2968 }, { date: "2023-11-06", amount: 2708 }, { date: "2023-11-07", amount: 2280 }, ], }, engagement: { totalMessages: 32450, activeChats: 123, avgResponseTime: 5.2, dailyMessages: [ { date: "2023-11-01", count: 432 }, { date: "2023-11-02", count: 512 }, { date: "2023-11-03", count: 478 }, { date: "2023-11-04", count: 541 }, { date: "2023-11-05", count: 498 }, { date: "2023-11-06", count: 465 }, { date: "2023-11-07", count: 423 }, ], }, }); } finally { setLoading(false); setRefreshing(false); } }; useEffect(() => { fetchAnalyticsData(); }, [dateRange]); const handleRefresh = () => { setRefreshing(true); fetchAnalyticsData(); }; if (loading && !analyticsData) { return (
); } // These would normally be real chart components // For this example, we'll use simplified representations const SimpleAreaChart = ({ data, label, color }: { data: any[]; label: string; color: string }) => { // Handle empty data or undefined if (!data || data.length === 0) { return (
No data available
); } return (
{/* Simplified chart visualization */}
{data.map((item, index) => { // Normalize height between 10% and 90% const values = data.map(d => d.count || d.amount); const max = Math.max(...values); const min = Math.min(...values); const range = max - min; const value = item.count || item.amount; const normalizedHeight = range === 0 ? 50 : 10 + (((value - min) / range) * 80); return (
); })}
{new Date(data[0].date).toLocaleDateString('en-US', {month: 'short', day: 'numeric'})} {new Date(data[data.length - 1].date).toLocaleDateString('en-US', {month: 'short', day: 'numeric'})}
); }; // Function to render trend indicator const TrendIndicator = ({ value, prefix = "", suffix = "" }: { value: number, prefix?: string, suffix?: string }) => { if (value === 0) return null; return (
0 ? 'text-green-500' : 'text-red-500'}`}> {value > 0 ? : } {prefix}{Math.abs(value).toFixed(1)}{suffix}
); }; // Mini sparkline component for metric cards const MiniSparkline = ({ data, color = "#3b82f6" }: { data: any[], color?: string }) => { if (!data || data.length === 0) return null; const values = data.map(item => item.count || item.amount || 0); const max = Math.max(...values, 1); return (
{values.map((value, index) => { const height = (value / max) * 100; return (
); })}
); }; return (

Platform Analytics

{errorMessage && ( Error {errorMessage} )} Orders Vendors Revenue Promotions Communication Payments Order Analytics Order volume and revenue metrics {analyticsData && (
Total Orders
{analyticsData.orders?.total?.toLocaleString() || '0'}
Orders Today
{analyticsData.orders?.totalToday?.toLocaleString() || '0'}
Pending Orders
{analyticsData.orders?.pending?.toLocaleString() || '0'}
Revenue
${analyticsData.revenue?.total?.toLocaleString() || '0'}
)}

Order & Revenue Trends

{analyticsData && (

Order and revenue charts would render here

)}
Vendor Analytics Detailed vendor metrics and store statistics {analyticsData && (
Total Vendors
{analyticsData.vendors?.total?.toLocaleString() || '0'}
New Today
{analyticsData.vendors?.newToday?.toLocaleString() || '0'}
New This Week
{analyticsData.vendors?.newThisWeek?.toLocaleString() || '0'}
Active Stores
{analyticsData.vendors?.stores?.toLocaleString() || analyticsData.stores?.total?.toLocaleString() || '0'}
)}

Vendor Growth Trend

{analyticsData && (

Vendor growth chart would render here

)}
Revenue Analytics Revenue and financial metrics {analyticsData && (
Total Processed
${analyticsData.revenue?.total?.toLocaleString() || '0'}
Today's Revenue
${analyticsData.revenue?.today?.toLocaleString() || '0'}
This Week
${analyticsData.revenue?.thisWeek?.toLocaleString() || '0'}
Average Per Order
${analyticsData.revenue && analyticsData.orders?.total ? Math.round((analyticsData.revenue.total || 0) / analyticsData.orders.total).toLocaleString() : '0'}
)}

Revenue Trend

{analyticsData && ( )}
Active Promotions
{analyticsData?.promotions?.active || 0}

out of {analyticsData?.promotions?.total || 0} total

Total Discount Amount
${analyticsData?.promotions?.totalDiscountAmount?.toLocaleString() || 0}

{analyticsData?.promotions?.discountPercentage || 0}% of revenue

Promotion Uses
{analyticsData?.promotions?.used || 0}
Top Promotions Most used promotion codes
{analyticsData?.promotions?.topPromotions?.map((promo, i) => (

{promo._id}

{promo.count} uses ยท ${promo.totalDiscount.toLocaleString()}

${(promo.totalDiscount / promo.count).toFixed(2)} avg
))}
Discount Types Breakdown by discount type
{analyticsData?.promotions?.discountByType && (

Percentage Discounts

{analyticsData.promotions.discountByType.percentage?.count || 0} uses

${analyticsData.promotions.discountByType.percentage?.totalDiscount?.toLocaleString() || 0}

Fixed Amount Discounts

{analyticsData.promotions.discountByType.fixed?.count || 0} uses

${analyticsData.promotions.discountByType.fixed?.totalDiscount?.toLocaleString() || 0}
)}
Total Chats
{analyticsData?.chats?.totalChats || 0}

{analyticsData?.chats?.activeChats || 0} active in selected period

Total Messages
{analyticsData?.chats?.totalMessages?.toLocaleString() || 0}

{analyticsData?.chats?.recentMessages?.toLocaleString() || 0} in selected period

Avg Response Time
{analyticsData?.chats?.avgResponseTimeMin || 0} min
Message Volume by Hour Chat activity distribution
{analyticsData?.chats?.messagesByHour && ( ({ hour, count }))}> )}
Message Breakdown By sender type
{analyticsData?.chats?.messagesBySender && ( )}
Telegram Users Bot user statistics

Total Users

{analyticsData?.telegram?.totalUsers || 0}

Store Connections

{analyticsData?.telegram?.totalStoreConnections || 0}

Avg Stores per User

{analyticsData?.telegram?.avgStoresPerUser?.toFixed(2) || 0}

Multi-Store Users

{analyticsData?.telegram?.multiStoreUsers || 0}
Security Blocked users and security metrics

Total Blocked Users

{analyticsData?.security?.blockedUsers?.total || 0}

Recently Blocked

In selected period

{analyticsData?.security?.blockedUsers?.recentlyBlocked || 0}
Active Escrows
{analyticsData?.escrow?.active || 0}

out of {analyticsData?.escrow?.total || 0} total

Released Escrows
{analyticsData?.escrow?.released || 0}
Dispute Rate
{analyticsData?.escrow?.disputeRate?.toFixed(1) || 0}%

{analyticsData?.escrow?.disputed || 0} disputed escrows

Escrow by Currency Currently held amounts
{analyticsData?.escrow?.heldByCurrency && ( <>

Bitcoin (BTC)

{analyticsData.escrow.heldByCurrency.btc.toFixed(4)} BTC

Litecoin (LTC)

{analyticsData.escrow.heldByCurrency.ltc.toFixed(2)} LTC

Monero (XMR)

{analyticsData.escrow.heldByCurrency.xmr.toFixed(2)} XMR
)}
Escrow Metrics Release time and amounts

Avg Release Time

{analyticsData?.escrow?.avgReleaseTimeHours ? ( <> {Math.floor(analyticsData.escrow.avgReleaseTimeHours / 24)} days, {analyticsData.escrow.avgReleaseTimeHours % 24} hours ) : ( "8 days, 0 hours" )}
{analyticsData?.escrow?.totalByCurrency && (

Total Processed (lifetime)

BTC: {analyticsData.escrow.totalByCurrency.btc.toFixed(4)} BTC
LTC: {analyticsData.escrow.totalByCurrency.ltc.toFixed(2)} LTC
XMR: {analyticsData.escrow.totalByCurrency.xmr.toFixed(2)} XMR
)}
); }