···
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
12
-
import { toast } from "@/hooks/use-toast"
12
+
import { toast } from "@/hooks/use-toast";
import { useState, useEffect } from "react";
15
-
import { getLinkClickStats, getLinkSourceStats } from '../api/client';
16
-
import { ClickStats, SourceStats } from '../types/api';
15
+
import { getLinkClickStats, getLinkSourceStats } from "../api/client";
16
+
import { ClickStats, SourceStats } from "../types/api";
interface StatisticsModalProps {
20
-
onClose: () => void;
20
+
onClose: () => void;
24
+
interface EnhancedClickStats extends ClickStats {
25
+
sources?: { source: string; count: number }[];
28
+
const CustomTooltip = ({
37
+
if (active && payload && payload.length > 0) {
38
+
const data = payload[0].payload;
40
+
<div className="bg-background text-foreground p-4 rounded-lg shadow-lg border">
41
+
<p className="font-medium">{label}</p>
42
+
<p className="text-sm">Clicks: {data.clicks}</p>
43
+
{data.sources && data.sources.length > 0 && (
44
+
<div className="mt-2">
45
+
<p className="font-medium text-sm">Sources:</p>
46
+
<ul className="text-sm">
47
+
{data.sources.map((source: { source: string; count: number }) => (
48
+
<li key={source.source}>
49
+
{source.source}: {source.count}
export function StatisticsModal({ isOpen, onClose, linkId }: StatisticsModalProps) {
25
-
const [clicksOverTime, setClicksOverTime] = useState<ClickStats[]>([]);
26
-
const [sourcesData, setSourcesData] = useState<SourceStats[]>([]);
27
-
const [loading, setLoading] = useState(true);
62
+
const [clicksOverTime, setClicksOverTime] = useState<EnhancedClickStats[]>([]);
63
+
const [sourcesData, setSourcesData] = useState<SourceStats[]>([]);
64
+
const [loading, setLoading] = useState(true);
67
+
if (isOpen && linkId) {
68
+
const fetchData = async () => {
71
+
const [clicksData, sourcesData] = await Promise.all([
72
+
getLinkClickStats(linkId),
73
+
getLinkSourceStats(linkId),
30
-
if (isOpen && linkId) {
31
-
const fetchData = async () => {
34
-
const [clicksData, sourcesData] = await Promise.all([
35
-
getLinkClickStats(linkId),
36
-
getLinkSourceStats(linkId),
38
-
setClicksOverTime(clicksData);
39
-
setSourcesData(sourcesData);
40
-
} catch (error: any) {
41
-
console.error("Failed to fetch statistics:", error);
43
-
variant: "destructive",
45
-
description: error.response?.data || "Failed to load statistics",
76
+
// Enhance clicks data with source information
77
+
const enhancedClicksData = clicksData.map((clickData) => ({
79
+
sources: sourcesData.filter((source) => source.date === clickData.date),
82
+
setClicksOverTime(enhancedClicksData);
83
+
setSourcesData(sourcesData);
84
+
} catch (error: any) {
85
+
console.error("Failed to fetch statistics:", error);
87
+
variant: "destructive",
89
+
description: error.response?.data || "Failed to load statistics",
54
-
}, [isOpen, linkId]);
57
-
<Dialog open={isOpen} onOpenChange={onClose}>
58
-
<DialogContent className="max-w-3xl">
60
-
<DialogTitle>Link Statistics</DialogTitle>
98
+
}, [isOpen, linkId]);
64
-
<div className="flex items-center justify-center h-64">Loading...</div>
66
-
<div className="grid gap-4">
69
-
<CardTitle>Clicks Over Time</CardTitle>
72
-
<div className="h-[300px]">
73
-
<ResponsiveContainer width="100%" height="100%">
74
-
<LineChart data={clicksOverTime}>
75
-
<CartesianGrid strokeDasharray="3 3" />
76
-
<XAxis dataKey="date" />
86
-
</ResponsiveContainer>
101
+
<Dialog open={isOpen} onOpenChange={onClose}>
102
+
<DialogContent className="max-w-3xl">
104
+
<DialogTitle>Link Statistics</DialogTitle>
93
-
<CardTitle>Top Sources</CardTitle>
96
-
<ul className="space-y-2">
97
-
{sourcesData.map((source, index) => (
100
-
className="flex items-center justify-between py-2 border-b last:border-0"
102
-
<span className="text-sm">
103
-
<span className="font-medium text-muted-foreground mr-2">
108
-
<span className="text-sm font-medium">
109
-
{source.count} clicks
108
+
<div className="flex items-center justify-center h-64">Loading...</div>
110
+
<div className="grid gap-4">
113
+
<CardTitle>Clicks Over Time</CardTitle>
116
+
<div className="h-[300px]">
117
+
<ResponsiveContainer width="100%" height="100%">
118
+
<LineChart data={clicksOverTime}>
119
+
<CartesianGrid strokeDasharray="3 3" />
120
+
<XAxis dataKey="date" />
122
+
<Tooltip content={<CustomTooltip />} />
130
+
</ResponsiveContainer>
137
+
<CardTitle>Top Sources</CardTitle>
140
+
<ul className="space-y-2">
141
+
{sourcesData.map((source, index) => (
143
+
key={source.source}
144
+
className="flex items-center justify-between py-2 border-b last:border-0"
146
+
<span className="text-sm">
147
+
<span className="font-medium text-muted-foreground mr-2">
152
+
<span className="text-sm font-medium">
153
+
{source.count} clicks