sitcod3 commited on
Commit
95bd9da
·
verified ·
1 Parent(s): 5064251

Upload src/pages/Analytics.tsx with huggingface_hub

Browse files
Files changed (1) hide show
  1. src/pages/Analytics.tsx +247 -0
src/pages/Analytics.tsx ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { apiClient } from "../lib/apiClient";
3
+ import {
4
+ BarChart2,
5
+ TrendingUp,
6
+ Download,
7
+ Calendar,
8
+ Mail,
9
+ Inbox,
10
+ Flame,
11
+ ShieldCheck,
12
+ Percent,
13
+ ArrowUpRight
14
+ } from "lucide-react";
15
+ import {
16
+ ResponsiveContainer,
17
+ LineChart,
18
+ Line,
19
+ BarChart,
20
+ Bar,
21
+ XAxis,
22
+ YAxis,
23
+ CartesianGrid,
24
+ Tooltip,
25
+ Legend
26
+ } from "recharts";
27
+ import { useState } from "react";
28
+ import StatCard from "../components/StatCard";
29
+ import CsvExportButton from "../components/CsvExportButton";
30
+
31
+ const timelineData = [
32
+ { date: "Oct 1", sent: 820, opens: 530, replies: 48, bounces: 4 },
33
+ { date: "Oct 5", sent: 1140, opens: 760, replies: 72, bounces: 8 },
34
+ { date: "Oct 10", sent: 1650, opens: 1120, replies: 98, bounces: 11 },
35
+ { date: "Oct 15", sent: 2100, opens: 1450, replies: 134, bounces: 15 },
36
+ { date: "Oct 20", sent: 2800, opens: 1980, replies: 182, bounces: 21 },
37
+ { date: "Oct 25", sent: 3400, opens: 2450, replies: 226, bounces: 28 },
38
+ { date: "Oct 30", sent: 4120, opens: 2980, replies: 280, bounces: 34 },
39
+ ];
40
+
41
+ const campaignComparisonData = [
42
+ { name: "SaaS Enterprise VPs", sent: 4200, opens: 2600, replies: 240 },
43
+ { name: "Series A Tech Founders", sent: 3100, opens: 2100, replies: 195 },
44
+ { name: "Agency Owners Q4", sent: 2400, opens: 1400, replies: 120 },
45
+ { name: "E-commerce Directors", sent: 1800, opens: 980, replies: 84 },
46
+ { name: "RevOps Decision Makers", sent: 1200, opens: 720, replies: 65 },
47
+ ];
48
+
49
+ export default function Analytics() {
50
+ const [dateRange, setDateRange] = useState("30d");
51
+
52
+ const { data: analytics } = useQuery({
53
+ queryKey: ["analytics-campaigns"],
54
+ queryFn: async () => {
55
+ const res = await apiClient.get("/analytics/campaigns");
56
+ return res.data;
57
+ },
58
+ });
59
+
60
+ const { data: emailAccounts = [] } = useQuery({
61
+ queryKey: ["email-accounts"],
62
+ queryFn: async () => {
63
+ const res = await apiClient.get("/email-accounts");
64
+ return res.data;
65
+ },
66
+ });
67
+
68
+ return (
69
+ <div className="p-6 max-w-7xl mx-auto space-y-6">
70
+ {/* Header */}
71
+ <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
72
+ <div>
73
+ <h1 className="text-2xl font-bold tracking-tight text-zinc-100 flex items-center gap-2.5">
74
+ <BarChart2 className="w-6 h-6 text-indigo-400" />
75
+ Outbound Analytics & Intelligence
76
+ </h1>
77
+ <p className="text-zinc-400 text-sm mt-1">
78
+ Global deliverability performance, engagement conversion funnels, and mailbox health telemetry.
79
+ </p>
80
+ </div>
81
+
82
+ <div className="flex items-center gap-3">
83
+ <select
84
+ value={dateRange}
85
+ onChange={(e) => setDateRange(e.target.value)}
86
+ className="bg-zinc-900 border border-zinc-800 rounded-lg py-2 px-3 text-xs text-zinc-200 focus:outline-none focus:border-indigo-500"
87
+ >
88
+ <option value="7d">Last 7 Days</option>
89
+ <option value="14d">Last 14 Days</option>
90
+ <option value="30d">Last 30 Days</option>
91
+ <option value="90d">Last 90 Days</option>
92
+ </select>
93
+ <CsvExportButton data={timelineData} filename="smartlead-analytics-export.csv" />
94
+ </div>
95
+ </div>
96
+
97
+ {/* KPI Conversion Cards */}
98
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
99
+ <StatCard
100
+ title="Open Rate"
101
+ value="64.8%"
102
+ subtitle="4,890 unique opens"
103
+ icon={Mail}
104
+ iconColor="emerald"
105
+ change={{ value: "+3.4%", isPositive: true, period: "vs benchmark" }}
106
+ />
107
+ <StatCard
108
+ title="Click Rate (CTR)"
109
+ value="18.2%"
110
+ subtitle="1,120 link clicks"
111
+ icon={ArrowUpRight}
112
+ iconColor="blue"
113
+ change={{ value: "+1.1%", isPositive: true, period: "last 30 days" }}
114
+ />
115
+ <StatCard
116
+ title="Reply Rate"
117
+ value="6.2%"
118
+ subtitle="378 prospect responses"
119
+ icon={Inbox}
120
+ iconColor="purple"
121
+ change={{ value: "+0.8%", isPositive: true, period: "positive intent" }}
122
+ />
123
+ <StatCard
124
+ title="Bounce Rate"
125
+ value="0.7%"
126
+ subtitle="Deliverability safe"
127
+ icon={ShieldCheck}
128
+ iconColor="teal"
129
+ change={{ value: "-0.2%", isPositive: true, period: "health optimal" }}
130
+ />
131
+ </div>
132
+
133
+ {/* Timeline Chart */}
134
+ <div className="bg-white/5 border border-white/10 backdrop-blur-md rounded-xl p-5 shadow-[0_8px_32px_-8px_rgba(6,10,12,0.65)]">
135
+ <div className="flex items-center justify-between mb-6">
136
+ <div>
137
+ <h3 className="text-base font-semibold text-zinc-100">Cumulative Volume & Responses</h3>
138
+ <p className="text-xs text-zinc-400 mt-0.5">
139
+ Daily trajectory of outbound sends, unique opens, and replied prospects.
140
+ </p>
141
+ </div>
142
+ </div>
143
+
144
+ <div className="h-[320px] w-full">
145
+ <ResponsiveContainer width="100%" height="100%">
146
+ <LineChart data={timelineData} margin={{ top: 5, right: 20, bottom: 5, left: 0 }}>
147
+ <CartesianGrid strokeDasharray="3 3" stroke="rgba(246,248,242,0.05)" vertical={false} />
148
+ <XAxis dataKey="date" stroke="var(--nt-text-muted)" fontSize={12} tickLine={false} axisLine={false} />
149
+ <YAxis stroke="var(--nt-text-muted)" fontSize={12} tickLine={false} axisLine={false} tickFormatter={(val) => new Intl.NumberFormat('en-US').format(val)} className="font-mono" />
150
+ <Tooltip
151
+ contentStyle={{
152
+ backgroundColor: "rgba(6, 10, 12, 0.88)",
153
+ backdropFilter: "blur(12px)",
154
+ borderColor: "rgba(37,125,104,0.2)",
155
+ borderRadius: "12px",
156
+ fontSize: "12px",
157
+ color: "var(--nt-text-primary)"
158
+ }}
159
+ />
160
+ <Legend wrapperStyle={{ fontSize: "12px", paddingTop: "10px" }} />
161
+ <Line type="monotone" dataKey="sent" name="Emails Sent" stroke="var(--nt-deep-teal-600)" strokeWidth={3} dot={{ r: 4, fill: 'var(--nt-deep-teal-600)', strokeWidth: 2, stroke: 'var(--nt-focus-ring-offset)' }} activeDot={{ r: 6, fill: 'var(--nt-deep-teal-700)' }} animationDuration={1500} />
162
+ <Line type="monotone" dataKey="opens" name="Opens" stroke="var(--nt-deep-teal-500)" strokeWidth={3} dot={{ r: 4, fill: 'var(--nt-deep-teal-500)', strokeWidth: 2, stroke: 'var(--nt-focus-ring-offset)' }} activeDot={{ r: 6, fill: 'var(--nt-deep-teal-700)' }} animationDuration={1500} />
163
+ <Line type="monotone" dataKey="replies" name="Replies" stroke="var(--nt-terracotta-500)" strokeWidth={3} dot={{ r: 4, fill: 'var(--nt-terracotta-500)', strokeWidth: 2, stroke: 'var(--nt-focus-ring-offset)' }} activeDot={{ r: 6, fill: 'var(--nt-terracotta-700)' }} animationDuration={1500} />
164
+ </LineChart>
165
+ </ResponsiveContainer>
166
+ </div>
167
+ </div>
168
+
169
+ {/* Comparison Grid */}
170
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
171
+ {/* Top Campaigns Comparison */}
172
+ <div className="bg-white/5 border border-white/10 backdrop-blur-md rounded-xl p-5 shadow-[0_8px_32px_-8px_rgba(6,10,12,0.65)]">
173
+ <h3 className="text-base font-semibold text-zinc-100 mb-1">Top Campaign Performance</h3>
174
+ <p className="text-xs text-zinc-400 mb-4">Volume dispatched vs. engaged prospects.</p>
175
+
176
+ <div className="h-[280px] w-full">
177
+ <ResponsiveContainer width="100%" height="100%">
178
+ <BarChart data={campaignComparisonData} layout="vertical" margin={{ top: 5, right: 20, bottom: 5, left: 40 }}>
179
+ <defs>
180
+ <linearGradient id="colorOpens" x1="0" y1="0" x2="1" y2="0">
181
+ <stop offset="0%" stopColor="var(--nt-deep-teal-500)" stopOpacity={0.8}/>
182
+ <stop offset="100%" stopColor="var(--nt-deep-teal-700)" stopOpacity={1}/>
183
+ </linearGradient>
184
+ <linearGradient id="colorReplies" x1="0" y1="0" x2="1" y2="0">
185
+ <stop offset="0%" stopColor="var(--nt-terracotta-400)" stopOpacity={0.8}/>
186
+ <stop offset="100%" stopColor="var(--nt-terracotta-700)" stopOpacity={1}/>
187
+ </linearGradient>
188
+ </defs>
189
+ <CartesianGrid strokeDasharray="3 3" stroke="rgba(246,248,242,0.05)" horizontal={false} />
190
+ <XAxis type="number" stroke="var(--nt-text-muted)" fontSize={11} tickLine={false} axisLine={false} className="font-mono" />
191
+ <YAxis dataKey="name" type="category" stroke="var(--nt-text-muted)" fontSize={11} tickLine={false} axisLine={false} />
192
+ <Tooltip
193
+ contentStyle={{
194
+ backgroundColor: "rgba(6, 10, 12, 0.88)",
195
+ backdropFilter: "blur(12px)",
196
+ borderColor: "rgba(37,125,104,0.2)",
197
+ borderRadius: "12px",
198
+ fontSize: "12px",
199
+ }}
200
+ />
201
+ <Bar dataKey="opens" name="Opens" fill="url(#colorOpens)" radius={[0, 4, 4, 0]} animationDuration={1500}>
202
+ </Bar>
203
+ <Bar dataKey="replies" name="Replies" fill="url(#colorReplies)" radius={[0, 4, 4, 0]} animationDuration={1500} />
204
+ </BarChart>
205
+ </ResponsiveContainer>
206
+ </div>
207
+ </div>
208
+
209
+ {/* Mailbox Deliverability Health Matrix */}
210
+ <div className="bg-white/5 border border-white/10 backdrop-blur-md rounded-xl p-5 shadow-[0_8px_32px_-8px_rgba(6,10,12,0.65)] flex flex-col justify-between">
211
+ <div>
212
+ <h3 className="text-base font-semibold text-zinc-100 mb-1">Mailbox Deliverability Matrix</h3>
213
+ <p className="text-xs text-zinc-400 mb-4">DNS authentication, warmup status, and health metrics.</p>
214
+
215
+ <div className="space-y-3">
216
+ {emailAccounts.map((acc: any) => (
217
+ <div
218
+ key={acc.id}
219
+ className="flex items-center justify-between p-3 bg-white/5 border border-white/10 rounded-lg text-xs hover:bg-white/10 transition-colors"
220
+ >
221
+ <div>
222
+ <span className="font-semibold text-zinc-200">{acc.from_email}</span>
223
+ <div className="text-[10px] text-zinc-400 mt-0.5">
224
+ SPF: PASS • DKIM: PASS • DMARC: PASS
225
+ </div>
226
+ </div>
227
+
228
+ <div className="flex items-center gap-3 font-mono">
229
+ <span className="text-emerald-400 font-bold drop-shadow-[0_0_8px_rgba(63,156,132,0.5)]">99.4%</span>
230
+ <span className="px-2 py-0.5 bg-emerald-500/20 text-emerald-300 border border-emerald-500/30 rounded text-[10px]">
231
+ Optimal
232
+ </span>
233
+ </div>
234
+ </div>
235
+ ))}
236
+ </div>
237
+ </div>
238
+
239
+ <div className="mt-4 pt-3 border-t border-white/10 text-[11px] text-zinc-400 flex items-center justify-between">
240
+ <span>Global Reputation: <span className="font-mono text-zinc-300">98.4 / 100</span></span>
241
+ <span className="text-emerald-400 flex items-center gap-1.5"><ShieldCheck className="w-3.5 h-3.5" /> All Nodes Secure</span>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+ );
247
+ }