create-bluecopa-react-app 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +76 -238
  2. package/package.json +1 -1
  3. package/templates/latest/{Agent.md → AGENT.md} +21 -27
  4. package/templates/latest/README.md +15 -38
  5. package/templates/latest/clean.sh +1 -0
  6. package/templates/latest/package-lock.json +8 -8
  7. package/templates/latest/package.json +1 -1
  8. package/templates/latest/setup.sh +5 -4
  9. package/templates/latest/src/App.tsx +11 -7
  10. package/templates/latest/src/components/charts/AreaChart.tsx +80 -0
  11. package/templates/latest/src/components/charts/DonutChart.tsx +73 -0
  12. package/templates/latest/src/components/charts/SparkAreaChart.tsx +52 -0
  13. package/templates/latest/src/components/layout/dashboard-header.tsx +1 -1
  14. package/templates/latest/src/components/layout/dashboard-layout.tsx +19 -11
  15. package/templates/latest/src/components/{page → layout}/navbar.tsx +2 -0
  16. package/templates/latest/src/components/layout/sidebar.tsx +2 -1
  17. package/templates/latest/src/components/page/dashboard/DashboardMetrics.tsx +97 -0
  18. package/templates/latest/src/components/page/dashboard/PaymentMethodsAnalysis.tsx +182 -0
  19. package/templates/latest/src/components/page/dashboard/RevenueAnalytics.tsx +505 -0
  20. package/templates/latest/src/components/page/dashboard/SalesAnalytics.tsx +313 -0
  21. package/templates/latest/src/components/page/dashboard/TransactionsTable.tsx +256 -0
  22. package/templates/latest/src/components/page/dashboard/dashboard-utils.ts +147 -0
  23. package/templates/latest/src/components/page/dashboard/dashboard.tsx +185 -0
  24. package/templates/latest/src/components/ui/bluecopa-logo.tsx +3 -0
  25. package/templates/latest/src/components/ui/label.tsx +0 -2
  26. package/templates/latest/src/components/ui/select.tsx +0 -2
  27. package/templates/latest/src/pages/Dashboard.tsx +1 -1
  28. package/templates/latest/src/single-spa.tsx +38 -28
  29. package/templates/latest/tailwind.config.js +1 -2
  30. package/templates/latest/tsconfig.app.json +6 -0
  31. package/templates/latest/tsconfig.json +6 -6
  32. package/templates/latest/tsconfig.node.json +5 -1
  33. package/templates/latest/vite.config.ts +1 -1
  34. package/templates/latest/src/components/page/dashboard.tsx +0 -1506
@@ -1,1506 +0,0 @@
1
- 'use client'
2
-
3
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
4
- import { Button } from '@/components/ui/button'
5
- import { Badge } from '@/components/ui/badge'
6
- import { Alert, AlertDescription } from '@/components/ui/alert'
7
- import { useMetricDataDemo, useDatasetDataDemo, useUserData } from '@/hooks/use-api'
8
- import {
9
- RefreshCw,
10
- Loader2,
11
- AlertCircle,
12
- CheckCircle,
13
- Clock,
14
- Users,
15
- DollarSign,
16
- ShoppingCart,
17
- TrendingUp,
18
- ArrowUpRight,
19
- ArrowDownRight
20
- } from 'lucide-react'
21
- import {
22
- ResponsiveContainer,
23
- AreaChart as RechartsAreaChart,
24
- BarChart as RechartsBarChart,
25
- PieChart,
26
- Cell,
27
- Area,
28
- Bar,
29
- XAxis,
30
- YAxis,
31
- CartesianGrid,
32
- Tooltip,
33
- Legend,
34
- Pie
35
- } from 'recharts'
36
-
37
- // Simple table components since they're not in the UI library
38
- const Table = ({ children, className = "" }: { children: React.ReactNode, className?: string }) => (
39
- <div className={`overflow-x-auto ${className}`}>
40
- <table className="min-w-full divide-y divide-gray-200">
41
- {children}
42
- </table>
43
- </div>
44
- )
45
-
46
- const TableHead = ({ children }: { children: React.ReactNode }) => (
47
- <thead className="bg-gray-50">{children}</thead>
48
- )
49
-
50
- const TableBody = ({ children }: { children: React.ReactNode }) => (
51
- <tbody className="bg-white divide-y divide-gray-200">{children}</tbody>
52
- )
53
-
54
- const TableRow = ({ children }: { children: React.ReactNode }) => (
55
- <tr className="hover:bg-gray-50">{children}</tr>
56
- )
57
-
58
- const TableHeaderCell = ({ children }: { children: React.ReactNode }) => (
59
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
60
- {children}
61
- </th>
62
- )
63
-
64
- const TableCell = ({ children, className = "" }: { children: React.ReactNode, className?: string }) => (
65
- <td className={`px-6 py-4 whitespace-nowrap text-sm text-gray-900 ${className}`}>
66
- {children}
67
- </td>
68
- )
69
-
70
- // Custom chart components using Recharts
71
- const AreaChart = ({
72
- data,
73
- index,
74
- categories,
75
- colors = ['#3B82F6'],
76
- className = "h-80",
77
- valueFormatter,
78
- showLegend = true,
79
- showGridLines = true,
80
- showXAxis = true,
81
- showYAxis = true,
82
- yAxisWidth
83
- }: any) => {
84
- const colorMap: { [key: string]: string } = {
85
- blue: '#3B82F6',
86
- emerald: '#10B981',
87
- violet: '#8B5CF6',
88
- rose: '#F43F5E',
89
- amber: '#F59E0B',
90
- cyan: '#06B6D4',
91
- slate: '#64748B',
92
- indigo: '#6366F1'
93
- }
94
-
95
- const getColor = (color: string, index: number) => {
96
- return colorMap[color] || colors[index] || '#3B82F6'
97
- }
98
-
99
- return (
100
- <div className={className}>
101
- <ResponsiveContainer width="100%" height="100%">
102
- <RechartsAreaChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
103
- {showGridLines && <CartesianGrid strokeDasharray="3 3" />}
104
- {showXAxis && <XAxis dataKey={index} />}
105
- {showYAxis && <YAxis width={yAxisWidth || 60} />}
106
- <Tooltip
107
- formatter={(value: any) => valueFormatter ? valueFormatter(value) : value}
108
- />
109
- {showLegend && <Legend />}
110
- {categories?.map((category: string, idx: number) => (
111
- <Area
112
- key={category}
113
- type="monotone"
114
- dataKey={category}
115
- stroke={getColor(colors[idx], idx)}
116
- fill={getColor(colors[idx], idx)}
117
- fillOpacity={0.3}
118
- />
119
- ))}
120
- </RechartsAreaChart>
121
- </ResponsiveContainer>
122
- </div>
123
- )
124
- }
125
-
126
- const DonutChart = ({
127
- data,
128
- category,
129
- index,
130
- colors = ['#3B82F6'],
131
- className = "h-64",
132
- valueFormatter,
133
- variant = "donut"
134
- }: any) => {
135
- const colorMap: { [key: string]: string } = {
136
- blue: '#3B82F6',
137
- emerald: '#10B981',
138
- violet: '#8B5CF6',
139
- rose: '#F43F5E',
140
- amber: '#F59E0B',
141
- cyan: '#06B6D4',
142
- slate: '#64748B',
143
- indigo: '#6366F1'
144
- }
145
-
146
- const getColor = (color: string, index: number) => {
147
- return colorMap[color] || colors[index] || '#3B82F6'
148
- }
149
-
150
- const COLORS = colors.map((color: string, idx: number) => getColor(color, idx))
151
-
152
- return (
153
- <div className={className}>
154
- <ResponsiveContainer width="100%" height="100%">
155
- <PieChart>
156
- <Pie
157
- data={data}
158
- cx="50%"
159
- cy="50%"
160
- innerRadius={variant === "donut" ? 60 : 0}
161
- outerRadius={80}
162
- paddingAngle={5}
163
- dataKey={category}
164
- nameKey={index}
165
- >
166
- {data.map((_entry: any, index: number) => (
167
- <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
168
- ))}
169
- </Pie>
170
- <Tooltip
171
- formatter={(value: any) => valueFormatter ? valueFormatter(value) : value}
172
- />
173
- <Legend />
174
- </PieChart>
175
- </ResponsiveContainer>
176
- </div>
177
- )
178
- }
179
-
180
- const SparkAreaChart = ({
181
- data,
182
- categories,
183
- colors = ['#3B82F6'],
184
- className = "h-10"
185
- }: any) => {
186
- const colorMap: { [key: string]: string } = {
187
- blue: '#3B82F6',
188
- emerald: '#10B981',
189
- violet: '#8B5CF6',
190
- rose: '#F43F5E',
191
- amber: '#F59E0B',
192
- cyan: '#06B6D4'
193
- }
194
-
195
- const getColor = (color: string, index: number) => {
196
- return colorMap[color] || colors[index] || '#3B82F6'
197
- }
198
-
199
- return (
200
- <div className={className}>
201
- <ResponsiveContainer width="100%" height="100%">
202
- <RechartsAreaChart data={data} margin={{ top: 0, right: 0, left: 0, bottom: 0 }}>
203
- {categories?.map((category: string, idx: number) => (
204
- <Area
205
- key={category}
206
- type="monotone"
207
- dataKey={category}
208
- stroke={getColor(colors[idx], idx)}
209
- fill={getColor(colors[idx], idx)}
210
- fillOpacity={0.6}
211
- />
212
- ))}
213
- </RechartsAreaChart>
214
- </ResponsiveContainer>
215
- </div>
216
- )
217
- }
218
-
219
- export default function Dashboard() {
220
- const metricQuery = useMetricDataDemo()
221
- const datasetQuery = useDatasetDataDemo()
222
- const userQuery = useUserData()
223
-
224
- // Helper function to render query state
225
- const renderQueryState = (query: any, title: string) => {
226
- if (query.isLoading) {
227
- return (
228
- <div className="flex items-center gap-2 text-blue-600">
229
- <Loader2 className="h-4 w-4 animate-spin" />
230
- <span className="text-sm">{title}: Loading...</span>
231
- </div>
232
- )
233
- }
234
-
235
- if (query.isError) {
236
- return (
237
- <div className="flex items-center gap-2 text-red-600">
238
- <AlertCircle className="h-4 w-4" />
239
- <span className="text-sm">{title}: Error</span>
240
- </div>
241
- )
242
- }
243
-
244
- if (query.isSuccess) {
245
- return (
246
- <div className="flex items-center gap-2 text-green-600">
247
- <CheckCircle className="h-4 w-4" />
248
- <span className="text-sm">{title}: Success</span>
249
- </div>
250
- )
251
- }
252
-
253
- return (
254
- <div className="flex items-center gap-2 text-gray-500">
255
- <Clock className="h-4 w-4" />
256
- <span className="text-sm">{title}: Idle</span>
257
- </div>
258
- )
259
- }
260
-
261
- // Process data for ecommerce metrics and charts
262
- const rawApiData = datasetQuery.data?.data?.data || []
263
-
264
- // Fallback sample data when API returns empty data
265
- const sampleTransactionData = [
266
- { transaction_id: '001', customer_name: 'John Doe', total_amount: 1250, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-01-15', state: 'CA' },
267
- { transaction_id: '002', customer_name: 'Jane Smith', total_amount: 780, category: 'Clothing', payment_method: 'PayPal', transaction_date: '2024-01-18', state: 'NY' },
268
- { transaction_id: '003', customer_name: 'Mike Johnson', total_amount: 2100, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-02-02', state: 'TX' },
269
- { transaction_id: '004', customer_name: 'Sarah Wilson', total_amount: 450, category: 'Books', payment_method: 'Debit Card', transaction_date: '2024-02-05', state: 'FL' },
270
- { transaction_id: '005', customer_name: 'David Brown', total_amount: 890, category: 'Sports', payment_method: 'Credit Card', transaction_date: '2024-02-10', state: 'CA' },
271
- { transaction_id: '006', customer_name: 'Lisa Garcia', total_amount: 1650, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-02-15', state: 'WA' },
272
- { transaction_id: '007', customer_name: 'Robert Lee', total_amount: 320, category: 'Books', payment_method: 'Cash', transaction_date: '2024-02-20', state: 'OR' },
273
- { transaction_id: '008', customer_name: 'Emily Davis', total_amount: 950, category: 'Clothing', payment_method: 'Credit Card', transaction_date: '2024-03-01', state: 'NY' },
274
- { transaction_id: '009', customer_name: 'Alex Rodriguez', total_amount: 1480, category: 'Sports', payment_method: 'Debit Card', transaction_date: '2024-03-05', state: 'TX' },
275
- { transaction_id: '010', customer_name: 'Maria Martinez', total_amount: 670, category: 'Beauty', payment_method: 'PayPal', transaction_date: '2024-03-08', state: 'FL' },
276
- { transaction_id: '011', customer_name: 'Chris Anderson', total_amount: 2200, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-03-12', state: 'CA' },
277
- { transaction_id: '012', customer_name: 'Amanda White', total_amount: 520, category: 'Clothing', payment_method: 'Debit Card', transaction_date: '2024-03-15', state: 'WA' },
278
- { transaction_id: '013', customer_name: 'James Taylor', total_amount: 1100, category: 'Sports', payment_method: 'Credit Card', transaction_date: '2024-03-18', state: 'OR' },
279
- { transaction_id: '014', customer_name: 'Jennifer Moore', total_amount: 380, category: 'Books', payment_method: 'Cash', transaction_date: '2024-03-22', state: 'NY' },
280
- { transaction_id: '015', customer_name: 'Kevin Jackson', total_amount: 1850, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-03-25', state: 'TX' },
281
- { transaction_id: '016', customer_name: 'Nicole Thompson', total_amount: 760, category: 'Beauty', payment_method: 'Credit Card', transaction_date: '2024-04-01', state: 'FL' },
282
- { transaction_id: '017', customer_name: 'Brian Wilson', total_amount: 1320, category: 'Sports', payment_method: 'Debit Card', transaction_date: '2024-04-05', state: 'CA' },
283
- { transaction_id: '018', customer_name: 'Jessica Clark', total_amount: 590, category: 'Clothing', payment_method: 'Credit Card', transaction_date: '2024-04-08', state: 'WA' },
284
- { transaction_id: '019', customer_name: 'Michael Lewis', total_amount: 2400, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-04-12', state: 'OR' },
285
- { transaction_id: '020', customer_name: 'Ashley Hall', total_amount: 450, category: 'Books', payment_method: 'Cash', transaction_date: '2024-04-15', state: 'NY' }
286
- ]
287
-
288
- // Use real data if available, otherwise use sample data
289
- const rawData = rawApiData.length > 0 ? rawApiData : sampleTransactionData
290
-
291
- const orderData = rawData.reduce((acc: any, transaction: any) => {
292
- const existing = acc.find((item: any) => item.category === transaction.category)
293
- if (existing) {
294
- existing.total += transaction.total_amount
295
- existing.count += 1
296
- } else {
297
- acc.push({
298
- category: transaction.category,
299
- total: transaction.total_amount,
300
- count: 1
301
- })
302
- }
303
- return acc
304
- }, [])
305
-
306
- const paymentMethodData = rawData.reduce((acc: any, transaction: any) => {
307
- const existing = acc.find((item: any) => item.method === transaction.payment_method)
308
- if (existing) {
309
- existing.total += transaction.total_amount
310
- existing.count += 1
311
- } else {
312
- acc.push({
313
- method: transaction.payment_method,
314
- total: transaction.total_amount,
315
- count: 1
316
- })
317
- }
318
- return acc
319
- }, [])
320
-
321
- // Process data for time-series charts
322
- const monthlyRevenueData = rawData.reduce((acc: any, transaction: any) => {
323
- if (!transaction.transaction_date) return acc
324
-
325
- const date = new Date(transaction.transaction_date)
326
- const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
327
-
328
- const existing = acc.find((item: any) => item.month === monthKey)
329
- if (existing) {
330
- existing.revenue += transaction.total_amount
331
- existing.orders += 1
332
- } else {
333
- acc.push({
334
- month: monthKey,
335
- revenue: transaction.total_amount,
336
- orders: 1
337
- })
338
- }
339
- return acc
340
- }, []).sort((a: any, b: any) => a.month.localeCompare(b.month))
341
-
342
- // Process data for tables
343
- const recentTransactions = rawData
344
- .slice(0, 10)
345
- .map((transaction: any) => ({
346
- id: transaction.transaction_id,
347
- customer: transaction.customer_name || 'N/A',
348
- amount: transaction.total_amount,
349
- category: transaction.category,
350
- payment_method: transaction.payment_method,
351
- date: transaction.transaction_date ? new Date(transaction.transaction_date).toLocaleDateString() : 'N/A'
352
- }))
353
-
354
- const totalOrders = rawData.length || 0
355
- const totalRevenue = rawData.reduce((sum: number, t: any) => sum + t.total_amount, 0)
356
- const averageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0
357
-
358
- // Mock data for ecommerce metrics
359
- const ecommerceMetrics = [
360
- {
361
- title: 'Total Revenue',
362
- value: `$${totalRevenue.toLocaleString()}`,
363
- change: '+12.5%',
364
- trend: 'up',
365
- icon: DollarSign,
366
- color: 'text-green-600'
367
- },
368
- {
369
- title: 'Orders',
370
- value: totalOrders.toLocaleString(),
371
- change: '+8.2%',
372
- trend: 'up',
373
- icon: ShoppingCart,
374
- color: 'text-blue-600'
375
- },
376
- {
377
- title: 'Average Order Value',
378
- value: `$${averageOrderValue.toFixed(2)}`,
379
- change: '+3.1%',
380
- trend: 'up',
381
- icon: TrendingUp,
382
- color: 'text-purple-600'
383
- },
384
- {
385
- title: 'Total Customers',
386
- value: '2,847',
387
- change: '+15.3%',
388
- trend: 'up',
389
- icon: Users,
390
- color: 'text-orange-600'
391
- }
392
- ]
393
-
394
- return (
395
- <div className="space-y-6">
396
- {/* API Status */}
397
- <div className="flex items-center justify-between">
398
- <div className="flex items-center space-x-4">
399
- {renderQueryState(metricQuery, 'Metrics API')}
400
- {renderQueryState(datasetQuery, 'Dataset API')}
401
- {renderQueryState(userQuery, 'User API')}
402
- </div>
403
- <Button
404
- variant="outline"
405
- size="sm"
406
- onClick={() => {
407
- metricQuery.refetch()
408
- datasetQuery.refetch()
409
- userQuery.refetch()
410
- }}
411
- disabled={metricQuery.isLoading || datasetQuery.isLoading || userQuery.isLoading ||
412
- metricQuery.isFetching || datasetQuery.isFetching || userQuery.isFetching}
413
- >
414
- {(metricQuery.isFetching || datasetQuery.isFetching || userQuery.isFetching) ? (
415
- <Loader2 className="h-4 w-4 mr-2 animate-spin" />
416
- ) : (
417
- <RefreshCw className="h-4 w-4 mr-2" />
418
- )}
419
- Refresh Data
420
- </Button>
421
- </div>
422
-
423
- {/* Key Metrics */}
424
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
425
- {ecommerceMetrics.map((metric, index) => (
426
- <Card key={index}>
427
- <CardContent className="pt-6">
428
- <div className="flex items-center justify-between space-y-0 pb-2">
429
- <CardTitle className="text-sm font-medium text-gray-600">
430
- {metric.title}
431
- </CardTitle>
432
- <metric.icon className={`h-4 w-4 ${metric.color}`} />
433
- </div>
434
- <div className="flex items-center space-x-2">
435
- <div className="text-2xl font-bold">{metric.value}</div>
436
- <div className={`flex items-center text-sm ${
437
- metric.trend === 'up' ? 'text-green-600' : 'text-red-600'
438
- }`}>
439
- {metric.trend === 'up' ? (
440
- <ArrowUpRight className="h-4 w-4" />
441
- ) : (
442
- <ArrowDownRight className="h-4 w-4" />
443
- )}
444
- {metric.change}
445
- </div>
446
- </div>
447
- {/* Mini trend chart */}
448
- {monthlyRevenueData.length > 0 && (
449
- <div className="mt-4">
450
- <SparkAreaChart
451
- data={monthlyRevenueData.slice(-6)} // Last 6 months
452
- categories={[index === 0 ? "revenue" : "orders"]}
453
- index="month"
454
- colors={[index === 0 ? "emerald" : index === 1 ? "blue" : index === 2 ? "violet" : "amber"]}
455
- className="h-10 w-full"
456
- />
457
- </div>
458
- )}
459
- </CardContent>
460
- </Card>
461
- ))}
462
- </div>
463
-
464
- {/* Sales Analytics Row */}
465
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
466
- {/* Enhanced Sales by Category */}
467
- <Card>
468
- <CardHeader className="pb-4">
469
- <div className="flex items-center justify-between">
470
- <div>
471
- <CardTitle className="text-lg font-bold">Sales by Category</CardTitle>
472
- <CardDescription className="text-sm text-gray-600">
473
- Performance breakdown by product categories
474
- </CardDescription>
475
- </div>
476
- <Badge variant="outline" className="text-emerald-600 border-emerald-200">
477
- {orderData.length} Categories
478
- </Badge>
479
- </div>
480
- </CardHeader>
481
- <CardContent>
482
- {orderData.length > 0 ? (
483
- <div className="space-y-4">
484
- {/* Category Trend Overview */}
485
- <div className="grid grid-cols-3 gap-4 p-4 bg-gradient-to-r from-emerald-50 to-blue-50 rounded-lg border border-emerald-100">
486
- <div className="text-center">
487
- <div className="text-xl font-bold text-emerald-700">
488
- {orderData.length}
489
- </div>
490
- <div className="text-xs text-emerald-600 font-medium">Categories</div>
491
- </div>
492
- <div className="text-center">
493
- <div className="text-xl font-bold text-blue-700">
494
- ${Math.max(...orderData.map((item: any) => item.total)).toLocaleString()}
495
- </div>
496
- <div className="text-xs text-blue-600 font-medium">Top Revenue</div>
497
- </div>
498
- <div className="text-center">
499
- <div className="text-xl font-bold text-violet-700">
500
- {Math.round(orderData.reduce((sum: number, item: any) => sum + item.count, 0) / orderData.length)}
501
- </div>
502
- <div className="text-xs text-violet-600 font-medium">Avg Orders</div>
503
- </div>
504
- </div>
505
-
506
- {/* Area Chart for Category Trends */}
507
- <div className="h-80">
508
- <ResponsiveContainer width="100%" height="100%">
509
- <RechartsAreaChart
510
- data={orderData.map((item: any, index: number) => ({
511
- category: item.category,
512
- revenue: item.total,
513
- orders: item.count * 10, // Scale for visualization
514
- trend: item.total * (1 + (index * 0.1)) // Mock trend data
515
- }))}
516
- margin={{ top: 20, right: 30, left: 20, bottom: 5 }}
517
- >
518
- <defs>
519
- <linearGradient id="revenueGradient" x1="0" y1="0" x2="0" y2="1">
520
- <stop offset="5%" stopColor="#10B981" stopOpacity={0.8}/>
521
- <stop offset="95%" stopColor="#10B981" stopOpacity={0.1}/>
522
- </linearGradient>
523
- <linearGradient id="ordersGradient" x1="0" y1="0" x2="0" y2="1">
524
- <stop offset="5%" stopColor="#3B82F6" stopOpacity={0.8}/>
525
- <stop offset="95%" stopColor="#3B82F6" stopOpacity={0.1}/>
526
- </linearGradient>
527
- </defs>
528
- <CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
529
- <XAxis
530
- dataKey="category"
531
- tick={{ fontSize: 12 }}
532
- angle={-45}
533
- textAnchor="end"
534
- height={80}
535
- />
536
- <YAxis tick={{ fontSize: 12 }} />
537
- <Tooltip
538
- formatter={(value: any, name: string) => [
539
- name === 'revenue' ? `$${value.toLocaleString()}` : `${Math.round(value / 10)} orders`,
540
- name === 'revenue' ? 'Revenue' : 'Orders'
541
- ]}
542
- labelStyle={{ color: '#374151' }}
543
- contentStyle={{
544
- backgroundColor: '#fff',
545
- border: '1px solid #e5e7eb',
546
- borderRadius: '8px',
547
- boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
548
- }}
549
- />
550
- <Legend />
551
- <Area
552
- type="monotone"
553
- dataKey="revenue"
554
- stroke="#10B981"
555
- fillOpacity={1}
556
- fill="url(#revenueGradient)"
557
- strokeWidth={2}
558
- />
559
- <Area
560
- type="monotone"
561
- dataKey="orders"
562
- stroke="#3B82F6"
563
- fillOpacity={1}
564
- fill="url(#ordersGradient)"
565
- strokeWidth={2}
566
- />
567
- </RechartsAreaChart>
568
- </ResponsiveContainer>
569
- </div>
570
- </div>
571
- ) : (
572
- <div className="text-center text-gray-500 py-12">
573
- <ShoppingCart className="h-12 w-12 mx-auto text-gray-300 mb-4" />
574
- <p className="text-lg font-medium">No category data available</p>
575
- <p className="text-sm">Start selling to see category breakdown</p>
576
- </div>
577
- )}
578
- </CardContent>
579
- </Card>
580
-
581
- {/* Enhanced Payment Method Distribution */}
582
- <Card>
583
- <CardHeader className="pb-4">
584
- <div className="flex items-center justify-between">
585
- <div>
586
- <CardTitle className="text-lg font-bold">Payment Methods</CardTitle>
587
- <CardDescription className="text-sm text-gray-600">
588
- Transaction distribution by payment type
589
- </CardDescription>
590
- </div>
591
- <Badge variant="outline" className="text-blue-600 border-blue-200">
592
- {paymentMethodData.length} Methods
593
- </Badge>
594
- </div>
595
- </CardHeader>
596
- <CardContent>
597
- {paymentMethodData.length > 0 ? (
598
- <div className="space-y-6">
599
- {/* Enhanced Payment Method Donut Chart */}
600
- <div className="relative bg-gradient-to-br from-blue-50 to-indigo-50 p-6 rounded-lg border border-blue-100">
601
- <h3 className="text-sm font-semibold text-blue-800 mb-4 text-center">Payment Distribution</h3>
602
- <div className="h-80">
603
- <ResponsiveContainer width="100%" height="100%">
604
- <PieChart>
605
- <defs>
606
- <filter id="shadow" height="130%">
607
- <feDropShadow dx="2" dy="2" stdDeviation="3" floodOpacity="0.2"/>
608
- </filter>
609
- </defs>
610
- <Pie
611
- data={paymentMethodData.map((item: any) => ({
612
- name: item.method,
613
- value: item.total,
614
- count: item.count,
615
- percentage: Math.round((item.total / paymentMethodData.reduce((sum: number, m: any) => sum + m.total, 0)) * 100)
616
- }))}
617
- cx="50%"
618
- cy="50%"
619
- labelLine={false}
620
- label={({ name, percentage }: any) => `${name}: ${percentage}%`}
621
- outerRadius={100}
622
- innerRadius={60}
623
- paddingAngle={5}
624
- dataKey="value"
625
- filter="url(#shadow)"
626
- >
627
- {paymentMethodData.map((_entry: any, index: number) => {
628
- const colors = ['#3B82F6', '#10B981', '#8B5CF6', '#F59E0B', '#F43F5E', '#06B6D4']
629
- return (
630
- <Cell
631
- key={`cell-${index}`}
632
- fill={colors[index % colors.length]}
633
- stroke="#fff"
634
- strokeWidth={2}
635
- />
636
- )
637
- })}
638
- </Pie>
639
- <Tooltip
640
- formatter={(value: any, name: string, props: any) => [
641
- `$${value.toLocaleString()}`,
642
- `${name} (${props.payload.count} transactions)`
643
- ]}
644
- labelStyle={{ color: '#374151', fontWeight: 'bold' }}
645
- contentStyle={{
646
- backgroundColor: '#fff',
647
- border: '1px solid #e5e7eb',
648
- borderRadius: '8px',
649
- boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
650
- }}
651
- />
652
- <Legend
653
- verticalAlign="bottom"
654
- height={36}
655
- iconType="circle"
656
- wrapperStyle={{ fontSize: '12px', paddingTop: '20px' }}
657
- />
658
- </PieChart>
659
- </ResponsiveContainer>
660
- </div>
661
- </div>
662
-
663
- {/* Enhanced Payment Method Details */}
664
- <div className="space-y-3">
665
- <h3 className="text-sm font-semibold text-gray-700">Payment Method Breakdown</h3>
666
- {paymentMethodData.map((method: any, index: number) => {
667
- const colors = ['bg-blue-500', 'bg-emerald-500', 'bg-violet-500', 'bg-amber-500', 'bg-rose-500', 'bg-cyan-500']
668
- const textColors = ['text-blue-600', 'text-emerald-600', 'text-violet-600', 'text-amber-600', 'text-rose-600', 'text-cyan-600']
669
- const bgColors = ['bg-blue-50', 'bg-emerald-50', 'bg-violet-50', 'bg-amber-50', 'bg-rose-50', 'bg-cyan-50']
670
- const percentage = Math.round((method.total / paymentMethodData.reduce((sum: number, m: any) => sum + m.total, 0)) * 100)
671
-
672
- return (
673
- <div key={index} className={`flex items-center justify-between p-4 rounded-lg border hover:shadow-sm transition-all ${bgColors[index] || 'bg-gray-50'}`}>
674
- <div className="flex items-center space-x-4">
675
- <div className={`w-4 h-4 rounded-full ${colors[index] || 'bg-gray-400'}`} />
676
- <div>
677
- <div className="font-semibold text-gray-900">{method.method}</div>
678
- <div className="text-sm text-gray-500">{method.count} transactions</div>
679
- </div>
680
- </div>
681
- <div className="text-right">
682
- <div className={`text-lg font-bold ${textColors[index] || 'text-gray-600'}`}>
683
- ${method.total.toLocaleString()}
684
- </div>
685
- <div className="text-sm text-gray-500">{percentage}% of total</div>
686
- <div className="w-20 bg-gray-200 rounded-full h-1.5 mt-1">
687
- <div
688
- className={`h-1.5 rounded-full ${colors[index] || 'bg-gray-400'}`}
689
- style={{ width: `${percentage}%` }}
690
- />
691
- </div>
692
- </div>
693
- </div>
694
- )
695
- })}
696
- </div>
697
- </div>
698
- ) : (
699
- <div className="text-center text-gray-500 py-12">
700
- <DollarSign className="h-12 w-12 mx-auto text-gray-300 mb-4" />
701
- <p className="text-lg font-medium">No payment data available</p>
702
- <p className="text-sm">Process payments to see distribution</p>
703
- </div>
704
- )}
705
- </CardContent>
706
- </Card>
707
- </div>
708
-
709
- {/* Enhanced Recent Transactions Table */}
710
- <Card>
711
- <CardHeader>
712
- <div className="flex items-center justify-between">
713
- <div>
714
- <CardTitle className="text-lg font-bold flex items-center gap-2">
715
- 📋 Recent Transactions
716
- </CardTitle>
717
- <CardDescription>
718
- Latest customer transactions with comprehensive details and analytics
719
- </CardDescription>
720
- </div>
721
- <div className="flex items-center space-x-2">
722
- <Badge variant="outline" className="text-blue-600 border-blue-200">
723
- {recentTransactions.length} Recent
724
- </Badge>
725
- <Badge variant="outline" className="text-emerald-600 border-emerald-200">
726
- ${recentTransactions.reduce((sum: number, t: any) => sum + t.amount, 0).toLocaleString()} Total
727
- </Badge>
728
- </div>
729
- </div>
730
- </CardHeader>
731
- <CardContent>
732
- {recentTransactions.length > 0 ? (
733
- <div className="space-y-4">
734
- {/* Transaction Summary Cards */}
735
- <div className="grid grid-cols-1 md:grid-cols-4 gap-4 p-4 bg-gradient-to-r from-gray-50 to-slate-50 rounded-lg border border-gray-100">
736
- <div className="text-center">
737
- <div className="text-xl font-bold text-gray-700">
738
- {recentTransactions.length}
739
- </div>
740
- <div className="text-xs text-gray-600 font-medium">Total Transactions</div>
741
- </div>
742
- <div className="text-center">
743
- <div className="text-xl font-bold text-emerald-700">
744
- ${Math.round(recentTransactions.reduce((sum: number, t: any) => sum + t.amount, 0) / recentTransactions.length).toLocaleString()}
745
- </div>
746
- <div className="text-xs text-emerald-600 font-medium">Average Value</div>
747
- </div>
748
- <div className="text-center">
749
- <div className="text-xl font-bold text-blue-700">
750
- ${Math.max(...recentTransactions.map((t: any) => t.amount)).toLocaleString()}
751
- </div>
752
- <div className="text-xs text-blue-600 font-medium">Highest Transaction</div>
753
- </div>
754
- <div className="text-center">
755
- <div className="text-xl font-bold text-violet-700">
756
- {new Set(recentTransactions.map((t: any) => t.category)).size}
757
- </div>
758
- <div className="text-xs text-violet-600 font-medium">Categories</div>
759
- </div>
760
- </div>
761
-
762
- {/* Enhanced Data Table */}
763
- <div className="overflow-hidden rounded-lg border border-gray-200 shadow-sm">
764
- <Table className="min-w-full">
765
- <TableHead>
766
- <TableRow>
767
- <TableHeaderCell>Transaction ID</TableHeaderCell>
768
- <TableHeaderCell>Customer</TableHeaderCell>
769
- <TableHeaderCell>Category</TableHeaderCell>
770
- <TableHeaderCell>Amount</TableHeaderCell>
771
- <TableHeaderCell>Payment Method</TableHeaderCell>
772
- <TableHeaderCell>Date</TableHeaderCell>
773
- <TableHeaderCell>Status</TableHeaderCell>
774
- </TableRow>
775
- </TableHead>
776
- <TableBody>
777
- {recentTransactions.map((transaction: any) => (
778
- <TableRow key={transaction.id}>
779
- <TableCell className="font-mono text-sm font-medium text-gray-900">
780
- #{transaction.id}
781
- </TableCell>
782
- <TableCell className="font-medium text-gray-900">
783
- <div className="flex items-center space-x-2">
784
- <div className="w-8 h-8 bg-gradient-to-br from-blue-400 to-blue-600 rounded-full flex items-center justify-center text-white text-xs font-bold">
785
- {transaction.customer.split(' ').map((n: string) => n[0]).join('')}
786
- </div>
787
- <span>{transaction.customer}</span>
788
- </div>
789
- </TableCell>
790
- <TableCell>
791
- <Badge
792
- variant="outline"
793
- className={`text-xs ${
794
- transaction.category === 'Electronics' ? 'text-blue-600 border-blue-200 bg-blue-50' :
795
- transaction.category === 'Clothing' ? 'text-emerald-600 border-emerald-200 bg-emerald-50' :
796
- transaction.category === 'Sports' ? 'text-violet-600 border-violet-200 bg-violet-50' :
797
- transaction.category === 'Books' ? 'text-amber-600 border-amber-200 bg-amber-50' :
798
- 'text-rose-600 border-rose-200 bg-rose-50'
799
- }`}
800
- >
801
- {transaction.category}
802
- </Badge>
803
- </TableCell>
804
- <TableCell className="font-bold text-right">
805
- <div className={`text-lg ${
806
- transaction.amount > 1500 ? 'text-emerald-600' :
807
- transaction.amount > 1000 ? 'text-blue-600' :
808
- transaction.amount > 500 ? 'text-amber-600' :
809
- 'text-gray-600'
810
- }`}>
811
- ${transaction.amount.toLocaleString()}
812
- </div>
813
- </TableCell>
814
- <TableCell>
815
- <div className="flex items-center space-x-2">
816
- <div className={`w-2 h-2 rounded-full ${
817
- transaction.payment_method === 'Credit Card' ? 'bg-blue-500' :
818
- transaction.payment_method === 'PayPal' ? 'bg-yellow-500' :
819
- transaction.payment_method === 'Debit Card' ? 'bg-emerald-500' :
820
- 'bg-gray-500'
821
- }`} />
822
- <span className="text-sm">{transaction.payment_method}</span>
823
- </div>
824
- </TableCell>
825
- <TableCell className="text-gray-500 text-sm">
826
- {transaction.date}
827
- </TableCell>
828
- <TableCell>
829
- <Badge
830
- variant="outline"
831
- className="text-xs text-emerald-600 border-emerald-200 bg-emerald-50"
832
- >
833
- Completed
834
- </Badge>
835
- </TableCell>
836
- </TableRow>
837
- ))}
838
- </TableBody>
839
- </Table>
840
- </div>
841
-
842
- {/* Table Footer with Pagination Info */}
843
- <div className="flex items-center justify-between p-4 bg-gray-50 rounded-lg border border-gray-100">
844
- <div className="text-sm text-gray-600">
845
- Showing <span className="font-medium">{recentTransactions.length}</span> of <span className="font-medium">{totalOrders}</span> transactions
846
- </div>
847
- <div className="text-sm text-gray-600">
848
- Total Value: <span className="font-bold text-emerald-600">${recentTransactions.reduce((sum: number, t: any) => sum + t.amount, 0).toLocaleString()}</span>
849
- </div>
850
- </div>
851
- </div>
852
- ) : (
853
- <div className="text-center text-gray-500 py-12">
854
- <div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center">
855
- 📊
856
- </div>
857
- <p className="text-lg font-medium">No transaction data available</p>
858
- <p className="text-sm">Start processing transactions to see them here</p>
859
- </div>
860
- )}
861
- </CardContent>
862
- </Card>
863
-
864
- {/* Enhanced Sales Analytics */}
865
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
866
- {/* Top Categories Performance */}
867
- <Card>
868
- <CardHeader>
869
- <CardTitle>Top Performing Categories</CardTitle>
870
- <CardDescription>
871
- Revenue performance by category
872
- </CardDescription>
873
- </CardHeader>
874
- <CardContent>
875
- {orderData.length > 0 ? (
876
- <div className="space-y-4">
877
- {orderData.slice(0, 5).map((category: any, index: number) => {
878
- const percentage = Math.round((category.total / orderData.reduce((sum: number, cat: any) => sum + cat.total, 0)) * 100)
879
- return (
880
- <div key={index} className="space-y-2">
881
- <div className="flex items-center justify-between">
882
- <div className="flex items-center space-x-2">
883
- <div className={`w-3 h-3 rounded-full ${
884
- index === 0 ? 'bg-emerald-500' :
885
- index === 1 ? 'bg-blue-500' :
886
- index === 2 ? 'bg-violet-500' :
887
- index === 3 ? 'bg-amber-500' : 'bg-rose-500'
888
- }`} />
889
- <span className="text-sm font-medium">{category.category}</span>
890
- </div>
891
- <div className="text-right">
892
- <div className="text-sm font-bold">${category.total.toLocaleString()}</div>
893
- <div className="text-xs text-gray-500">{percentage}%</div>
894
- </div>
895
- </div>
896
- <div className="w-full bg-gray-200 rounded-full h-2">
897
- <div
898
- className={`h-2 rounded-full ${
899
- index === 0 ? 'bg-emerald-500' :
900
- index === 1 ? 'bg-blue-500' :
901
- index === 2 ? 'bg-violet-500' :
902
- index === 3 ? 'bg-amber-500' : 'bg-rose-500'
903
- }`}
904
- style={{ width: `${percentage}%` }}
905
- />
906
- </div>
907
- </div>
908
- )
909
- })}
910
- </div>
911
- ) : (
912
- <div className="text-center text-gray-500 py-8">
913
- No category data available
914
- </div>
915
- )}
916
- </CardContent>
917
- </Card>
918
-
919
- {/* Sales Insights */}
920
- <Card>
921
- <CardHeader>
922
- <CardTitle>Sales Insights</CardTitle>
923
- <CardDescription>
924
- Key performance indicators
925
- </CardDescription>
926
- </CardHeader>
927
- <CardContent>
928
- <div className="space-y-6">
929
- <div className="text-center">
930
- <div className="text-3xl font-bold text-emerald-600">
931
- ${averageOrderValue.toFixed(2)}
932
- </div>
933
- <div className="text-sm text-gray-500">Average Order Value</div>
934
- <div className="mt-2">
935
- <Badge variant="outline" className="text-green-600 border-green-200">
936
- +5.2% vs last month
937
- </Badge>
938
- </div>
939
- </div>
940
-
941
- <div className="text-center">
942
- <div className="text-3xl font-bold text-blue-600">
943
- {totalOrders > 0 ? Math.round(totalRevenue / totalOrders * 12) : 0}%
944
- </div>
945
- <div className="text-sm text-gray-500">Conversion Rate</div>
946
- <div className="mt-2">
947
- <Badge variant="outline" className="text-blue-600 border-blue-200">
948
- Industry average: 2.3%
949
- </Badge>
950
- </div>
951
- </div>
952
-
953
- <div className="text-center">
954
- <div className="text-3xl font-bold text-violet-600">
955
- {paymentMethodData.length}
956
- </div>
957
- <div className="text-sm text-gray-500">Payment Methods</div>
958
- <div className="mt-2">
959
- <Badge variant="outline" className="text-violet-600 border-violet-200">
960
- Active channels
961
- </Badge>
962
- </div>
963
- </div>
964
- </div>
965
- </CardContent>
966
- </Card>
967
-
968
- {/* Recent Activity */}
969
- <Card>
970
- <CardHeader>
971
- <CardTitle>Recent Activity</CardTitle>
972
- <CardDescription>
973
- Latest updates and activities
974
- </CardDescription>
975
- </CardHeader>
976
- <CardContent>
977
- <div className="space-y-4">
978
- <div className="flex items-center space-x-4 p-3 bg-emerald-50 rounded-lg border border-emerald-100">
979
- <div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse" />
980
- <div className="flex-1">
981
- <p className="text-sm font-medium text-emerald-800">High Revenue Day</p>
982
- <p className="text-xs text-emerald-600">Revenue exceeded daily target by 15%</p>
983
- </div>
984
- <Badge variant="outline" className="text-emerald-600 border-emerald-200">Live</Badge>
985
- </div>
986
-
987
- <div className="flex items-center space-x-4 p-3 bg-blue-50 rounded-lg border border-blue-100">
988
- <ShoppingCart className="h-5 w-5 text-blue-600" />
989
- <div className="flex-1">
990
- <p className="text-sm font-medium text-blue-800">New Order Received</p>
991
- <p className="text-xs text-blue-600">Order #ORD-{Date.now().toString().slice(-4)} - ${(Math.random() * 500 + 50).toFixed(2)}</p>
992
- </div>
993
- <Badge variant="outline" className="text-blue-600 border-blue-200">New</Badge>
994
- </div>
995
-
996
- <div className="flex items-center space-x-4 p-3 bg-violet-50 rounded-lg border border-violet-100">
997
- <TrendingUp className="h-5 w-5 text-violet-600" />
998
- <div className="flex-1">
999
- <p className="text-sm font-medium text-violet-800">Sales Trending Up</p>
1000
- <p className="text-xs text-violet-600">12% increase in last 24 hours</p>
1001
- </div>
1002
- <Badge variant="outline" className="text-violet-600 border-violet-200">Trend</Badge>
1003
- </div>
1004
-
1005
- <div className="flex items-center space-x-4 p-3 bg-amber-50 rounded-lg border border-amber-100">
1006
- <Users className="h-5 w-5 text-amber-600" />
1007
- <div className="flex-1">
1008
- <p className="text-sm font-medium text-amber-800">Customer Milestone</p>
1009
- <p className="text-xs text-amber-600">Reached 1,000+ customers this month</p>
1010
- </div>
1011
- <Badge variant="outline" className="text-amber-600 border-amber-200">Achievement</Badge>
1012
- </div>
1013
- </div>
1014
- </CardContent>
1015
- </Card>
1016
- </div>
1017
-
1018
- {/* Enhanced Revenue and Analytics Section */}
1019
- <div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
1020
- {/* Sales by Category Chart */}
1021
- <Card>
1022
- <CardHeader>
1023
- <CardTitle>Sales by Category</CardTitle>
1024
- <CardDescription>
1025
- Revenue breakdown by product category
1026
- </CardDescription>
1027
- </CardHeader>
1028
- <CardContent>
1029
- <DonutChart
1030
- className="h-64"
1031
- data={orderData.map((item: any) => ({
1032
- category: item.category,
1033
- sales: item.total
1034
- }))}
1035
- category="sales"
1036
- index="category"
1037
- valueFormatter={(number: number) =>
1038
- `$${Intl.NumberFormat("us").format(number)}`
1039
- }
1040
- colors={["slate", "violet", "indigo", "rose", "cyan", "amber"]}
1041
- />
1042
- </CardContent>
1043
- </Card>
1044
-
1045
- {/* Payment Method Distribution */}
1046
- <Card>
1047
- <CardHeader>
1048
- <CardTitle>Payment Method Distribution</CardTitle>
1049
- <CardDescription>
1050
- Transaction count by payment method
1051
- </CardDescription>
1052
- </CardHeader>
1053
- <CardContent>
1054
- <DonutChart
1055
- className="h-64"
1056
- data={paymentMethodData.map((item: any) => ({
1057
- method: item.method,
1058
- count: item.count
1059
- }))}
1060
- category="count"
1061
- index="method"
1062
- valueFormatter={(number: number) =>
1063
- `${number} transactions`
1064
- }
1065
- colors={["emerald", "blue", "violet", "rose", "amber"]}
1066
- />
1067
- </CardContent>
1068
- </Card>
1069
-
1070
- {/* Revenue Analytics Summary */}
1071
- <Card>
1072
- <CardHeader>
1073
- <CardTitle>Revenue Analytics</CardTitle>
1074
- <CardDescription>
1075
- Key performance indicators
1076
- </CardDescription>
1077
- </CardHeader>
1078
- <CardContent>
1079
- <div className="space-y-4">
1080
- {/* Top Category */}
1081
- <div className="p-4 bg-gradient-to-r from-emerald-50 to-blue-50 rounded-lg border border-emerald-100">
1082
- <div className="text-sm text-emerald-600 font-medium">Top Revenue Category</div>
1083
- <div className="text-xl font-bold text-emerald-800">
1084
- {orderData.length > 0 ? orderData.sort((a: any, b: any) => b.total - a.total)[0]?.category || 'N/A' : 'Electronics'}
1085
- </div>
1086
- <div className="text-xs text-emerald-600">
1087
- ${orderData.length > 0 ? orderData.sort((a: any, b: any) => b.total - a.total)[0]?.total?.toLocaleString() || '0' : '8,750'}
1088
- </div>
1089
- </div>
1090
-
1091
- {/* Average Order Value */}
1092
- <div className="p-4 bg-gradient-to-r from-blue-50 to-violet-50 rounded-lg border border-blue-100">
1093
- <div className="text-sm text-blue-600 font-medium">Average Order Value</div>
1094
- <div className="text-xl font-bold text-blue-800">
1095
- ${averageOrderValue.toFixed(0)}
1096
- </div>
1097
- <div className="text-xs text-blue-600">
1098
- +12% vs last month
1099
- </div>
1100
- </div>
1101
-
1102
- {/* Total Revenue */}
1103
- <div className="p-4 bg-gradient-to-r from-violet-50 to-purple-50 rounded-lg border border-violet-100">
1104
- <div className="text-sm text-violet-600 font-medium">Total Revenue</div>
1105
- <div className="text-xl font-bold text-violet-800">
1106
- ${(totalRevenue / 1000).toFixed(1)}K
1107
- </div>
1108
- <div className="text-xs text-violet-600">
1109
- {monthlyRevenueData.length} active months
1110
- </div>
1111
- </div>
1112
-
1113
- {/* Revenue Growth Trend */}
1114
- <div className="p-4 bg-gradient-to-r from-amber-50 to-orange-50 rounded-lg border border-amber-100">
1115
- <div className="text-sm text-amber-600 font-medium">Growth Trend</div>
1116
- <div className="text-xl font-bold text-amber-800">
1117
- +{totalRevenue > 0 ? ((totalRevenue / 50000) * 100).toFixed(1) : 15.3}%
1118
- </div>
1119
- <div className="mt-2">
1120
- <SparkAreaChart
1121
- data={monthlyRevenueData.slice(-6)}
1122
- categories={["revenue"]}
1123
- index="month"
1124
- colors={["amber"]}
1125
- className="h-6 w-full"
1126
- />
1127
- </div>
1128
- </div>
1129
- </div>
1130
- </CardContent>
1131
- </Card>
1132
- </div>
1133
-
1134
- {/* Top Performing Categories Analytics */}
1135
- <Card>
1136
- <CardHeader>
1137
- <div className="flex items-center justify-between">
1138
- <div>
1139
- <CardTitle className="text-xl font-bold flex items-center gap-2">
1140
- <TrendingUp className="h-5 w-5 text-emerald-600" />
1141
- Top Performing Categories
1142
- </CardTitle>
1143
- <CardDescription className="text-sm text-gray-600 mt-1">
1144
- Comprehensive category performance analysis with revenue and order metrics
1145
- </CardDescription>
1146
- </div>
1147
- <Badge variant="outline" className="text-emerald-600 border-emerald-200">
1148
- {orderData.length} Active Categories
1149
- </Badge>
1150
- </div>
1151
- </CardHeader>
1152
- <CardContent>
1153
- {orderData.length > 0 ? (
1154
- <div className="space-y-6">
1155
- {/* Category Performance Overview */}
1156
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
1157
- {orderData.slice(0, 4).map((category: any, index: number) => {
1158
- const colors = ['bg-emerald-50 text-emerald-700 border-emerald-200', 'bg-blue-50 text-blue-700 border-blue-200',
1159
- 'bg-violet-50 text-violet-700 border-violet-200', 'bg-amber-50 text-amber-700 border-amber-200']
1160
- const iconColors = ['text-emerald-500', 'text-blue-500', 'text-violet-500', 'text-amber-500']
1161
-
1162
- return (
1163
- <div key={index} className={`p-4 rounded-lg border ${colors[index] || 'bg-gray-50 text-gray-700 border-gray-200'}`}>
1164
- <div className="flex items-center justify-between mb-2">
1165
- <ShoppingCart className={`h-4 w-4 ${iconColors[index] || 'text-gray-500'}`} />
1166
- <span className="text-xs font-medium">#{index + 1}</span>
1167
- </div>
1168
- <div className="text-lg font-bold">${category.total.toLocaleString()}</div>
1169
- <div className="text-xs font-medium mb-1">{category.category}</div>
1170
- <div className="text-xs opacity-75">{category.count} orders</div>
1171
- </div>
1172
- )
1173
- })}
1174
- </div>
1175
-
1176
- {/* Enhanced Bar Chart for Category Performance */}
1177
- <div className="bg-gradient-to-r from-slate-50 to-gray-50 p-6 rounded-lg border border-slate-200">
1178
- <h3 className="text-lg font-semibold text-slate-800 mb-4 flex items-center gap-2">
1179
- 📊 Revenue by Category Performance
1180
- </h3>
1181
- <div className="h-80">
1182
- <ResponsiveContainer width="100%" height="100%">
1183
- <RechartsBarChart
1184
- data={orderData.map((item: any) => ({
1185
- category: item.category,
1186
- revenue: item.total,
1187
- orders: item.count,
1188
- avgOrderValue: Math.round(item.total / item.count),
1189
- performance: (item.total / orderData.reduce((sum: number, cat: any) => sum + cat.total, 0)) * 100
1190
- }))}
1191
- margin={{ top: 20, right: 30, left: 20, bottom: 60 }}
1192
- >
1193
- <CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
1194
- <XAxis
1195
- dataKey="category"
1196
- tick={{ fontSize: 12, fill: '#64748b' }}
1197
- angle={-45}
1198
- textAnchor="end"
1199
- height={80}
1200
- />
1201
- <YAxis tick={{ fontSize: 12, fill: '#64748b' }} />
1202
- <Tooltip
1203
- formatter={(value: any, name: string) => [
1204
- name === 'revenue' ? `$${value.toLocaleString()}` : value,
1205
- name === 'revenue' ? 'Revenue' : name === 'orders' ? 'Orders' : 'Avg Order Value'
1206
- ]}
1207
- labelStyle={{ color: '#374151', fontWeight: 'bold' }}
1208
- contentStyle={{
1209
- backgroundColor: '#fff',
1210
- border: '1px solid #e5e7eb',
1211
- borderRadius: '8px',
1212
- boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
1213
- }}
1214
- />
1215
- <Legend />
1216
- <Bar dataKey="revenue" name="Revenue" radius={[4, 4, 0, 0]}>
1217
- {orderData.map((_entry: any, index: number) => {
1218
- const colors = ['#10B981', '#3B82F6', '#8B5CF6', '#F59E0B', '#F43F5E', '#06B6D4', '#64748B', '#6366F1']
1219
- return <Cell key={`cell-${index}`} fill={colors[index % colors.length]} />
1220
- })}
1221
- </Bar>
1222
- <Bar dataKey="orders" name="Orders" radius={[4, 4, 0, 0]} fill="#94A3B8" fillOpacity={0.7} />
1223
- </RechartsBarChart>
1224
- </ResponsiveContainer>
1225
- </div>
1226
- </div>
1227
-
1228
- {/* Category Performance Details */}
1229
- <div className="space-y-3">
1230
- <h3 className="text-sm font-semibold text-gray-700">Detailed Performance Breakdown</h3>
1231
- {orderData.map((category: any, index: number) => {
1232
- const percentage = Math.round((category.total / orderData.reduce((sum: number, cat: any) => sum + cat.total, 0)) * 100)
1233
- const avgOrder = Math.round(category.total / category.count)
1234
- const colors = ['bg-emerald-500', 'bg-blue-500', 'bg-violet-500', 'bg-amber-500', 'bg-rose-500', 'bg-cyan-500', 'bg-indigo-500']
1235
-
1236
- return (
1237
- <div key={index} className="flex items-center justify-between p-4 bg-white rounded-lg border border-gray-100 hover:shadow-sm transition-shadow">
1238
- <div className="flex items-center space-x-4">
1239
- <div className={`w-4 h-4 rounded-full ${colors[index] || 'bg-gray-400'}`} />
1240
- <div>
1241
- <div className="font-medium text-gray-900">{category.category}</div>
1242
- <div className="text-sm text-gray-500">{category.count} orders • Avg: ${avgOrder}</div>
1243
- </div>
1244
- </div>
1245
- <div className="text-right">
1246
- <div className="font-bold text-gray-900">${category.total.toLocaleString()}</div>
1247
- <div className="text-sm text-gray-500">{percentage}% of total</div>
1248
- </div>
1249
- </div>
1250
- )
1251
- })}
1252
- </div>
1253
- </div>
1254
- ) : (
1255
- <div className="text-center text-gray-500 py-16">
1256
- <ShoppingCart className="h-16 w-16 mx-auto text-gray-300 mb-4" />
1257
- <p className="text-lg font-medium">No category data available</p>
1258
- <p className="text-sm">Start selling products to see category performance</p>
1259
- </div>
1260
- )}
1261
- </CardContent>
1262
- </Card>
1263
-
1264
- {/* Revenue Analytics Dashboard */}
1265
- <div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
1266
- <Card className="xl:col-span-2">
1267
- <CardHeader>
1268
- <div className="flex items-center justify-between">
1269
- <div>
1270
- <CardTitle className="text-xl font-bold flex items-center gap-2">
1271
- <DollarSign className="h-5 w-5 text-blue-600" />
1272
- Revenue Analytics
1273
- </CardTitle>
1274
- <CardDescription className="text-sm text-gray-600 mt-1">
1275
- Comprehensive revenue analysis with trends, forecasting, and performance metrics
1276
- </CardDescription>
1277
- </div>
1278
- <div className="flex items-center space-x-2">
1279
- <Badge variant="outline" className="text-blue-600 border-blue-200">
1280
- ${(totalRevenue / 1000).toFixed(1)}K Total
1281
- </Badge>
1282
- <Badge variant="outline" className="text-emerald-600 border-emerald-200">
1283
- +{totalRevenue > 0 ? ((totalRevenue / 50000) * 100).toFixed(1) : 15.3}% Growth
1284
- </Badge>
1285
- </div>
1286
- </div>
1287
- </CardHeader>
1288
- <CardContent>
1289
- <div className="space-y-6">
1290
- {/* Revenue Metrics Grid */}
1291
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
1292
- <div className="p-4 bg-gradient-to-br from-emerald-50 to-emerald-100 rounded-lg border border-emerald-200">
1293
- <div className="flex items-center justify-between mb-2">
1294
- <DollarSign className="h-5 w-5 text-emerald-600" />
1295
- <ArrowUpRight className="h-4 w-4 text-emerald-600" />
1296
- </div>
1297
- <div className="text-2xl font-bold text-emerald-800">${(totalRevenue / 1000).toFixed(1)}K</div>
1298
- <div className="text-sm text-emerald-600 font-medium">Total Revenue</div>
1299
- <div className="text-xs text-emerald-600">+12.5% vs last month</div>
1300
- </div>
1301
-
1302
- <div className="p-4 bg-gradient-to-br from-blue-50 to-blue-100 rounded-lg border border-blue-200">
1303
- <div className="flex items-center justify-between mb-2">
1304
- <TrendingUp className="h-5 w-5 text-blue-600" />
1305
- <ArrowUpRight className="h-4 w-4 text-blue-600" />
1306
- </div>
1307
- <div className="text-2xl font-bold text-blue-800">${averageOrderValue.toFixed(0)}</div>
1308
- <div className="text-sm text-blue-600 font-medium">Avg Order Value</div>
1309
- <div className="text-xs text-blue-600">+8.2% vs last month</div>
1310
- </div>
1311
-
1312
- <div className="p-4 bg-gradient-to-br from-violet-50 to-violet-100 rounded-lg border border-violet-200">
1313
- <div className="flex items-center justify-between mb-2">
1314
- <Users className="h-5 w-5 text-violet-600" />
1315
- <ArrowUpRight className="h-4 w-4 text-violet-600" />
1316
- </div>
1317
- <div className="text-2xl font-bold text-violet-800">{monthlyRevenueData.length}</div>
1318
- <div className="text-sm text-violet-600 font-medium">Active Months</div>
1319
- <div className="text-xs text-violet-600">Growing steadily</div>
1320
- </div>
1321
-
1322
- <div className="p-4 bg-gradient-to-br from-amber-50 to-amber-100 rounded-lg border border-amber-200">
1323
- <div className="flex items-center justify-between mb-2">
1324
- <ShoppingCart className="h-5 w-5 text-amber-600" />
1325
- <ArrowUpRight className="h-4 w-4 text-amber-600" />
1326
- </div>
1327
- <div className="text-2xl font-bold text-amber-800">{totalOrders}</div>
1328
- <div className="text-sm text-amber-600 font-medium">Total Orders</div>
1329
- <div className="text-xs text-amber-600">+15.3% growth</div>
1330
- </div>
1331
- </div>
1332
-
1333
- {/* Revenue Trend Analysis */}
1334
- {monthlyRevenueData.length > 0 && (
1335
- <div className="bg-gradient-to-r from-blue-50 to-indigo-50 p-6 rounded-lg border border-blue-200">
1336
- <h3 className="text-lg font-semibold text-blue-800 mb-4 flex items-center gap-2">
1337
- <TrendingUp className="h-5 w-5 text-blue-600" />
1338
- Revenue Trend Analysis
1339
- </h3>
1340
- <AreaChart
1341
- className="h-80"
1342
- data={monthlyRevenueData.map((item: any) => ({
1343
- ...item,
1344
- growth: monthlyRevenueData.indexOf(item) > 0 ?
1345
- ((item.revenue - monthlyRevenueData[monthlyRevenueData.indexOf(item) - 1].revenue) /
1346
- monthlyRevenueData[monthlyRevenueData.indexOf(item) - 1].revenue * 100) : 0,
1347
- cumulative: monthlyRevenueData.slice(0, monthlyRevenueData.indexOf(item) + 1)
1348
- .reduce((sum: number, month: any) => sum + month.revenue, 0)
1349
- }))}
1350
- index="month"
1351
- categories={["revenue", "cumulative"]}
1352
- colors={["blue", "emerald"]}
1353
- valueFormatter={(number: number) =>
1354
- `$${Intl.NumberFormat("us").format(number)}`
1355
- }
1356
- showLegend={true}
1357
- showGridLines={true}
1358
- showXAxis={true}
1359
- showYAxis={true}
1360
- />
1361
- </div>
1362
- )}
1363
-
1364
- {/* Revenue Distribution by Category */}
1365
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1366
- <div className="bg-white p-6 rounded-lg border border-gray-200">
1367
- <h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
1368
- <PieChart className="h-5 w-5 text-gray-600" />
1369
- Revenue Distribution
1370
- </h3>
1371
- <DonutChart
1372
- className="h-64"
1373
- data={orderData.map((item: any) => ({
1374
- name: item.category,
1375
- value: item.total,
1376
- percentage: Math.round((item.total / orderData.reduce((sum: number, cat: any) => sum + cat.total, 0)) * 100)
1377
- }))}
1378
- category="value"
1379
- index="name"
1380
- valueFormatter={(number: number) =>
1381
- `$${Intl.NumberFormat("us").format(number)}`
1382
- }
1383
- colors={["emerald", "blue", "violet", "amber", "rose", "cyan"]}
1384
- />
1385
- </div>
1386
-
1387
- <div className="bg-white p-6 rounded-lg border border-gray-200">
1388
- <h3 className="text-lg font-semibold text-gray-800 mb-4">Revenue Insights</h3>
1389
- <div className="space-y-4">
1390
- {/* Top Revenue Category */}
1391
- <div className="p-4 bg-gradient-to-r from-emerald-50 to-emerald-100 rounded-lg border border-emerald-200">
1392
- <div className="flex items-center justify-between">
1393
- <div>
1394
- <div className="text-sm text-emerald-600 font-medium">Top Revenue Category</div>
1395
- <div className="text-xl font-bold text-emerald-800">
1396
- {orderData.length > 0 ? orderData.sort((a: any, b: any) => b.total - a.total)[0]?.category || 'N/A' : 'Electronics'}
1397
- </div>
1398
- </div>
1399
- <div className="text-right">
1400
- <div className="text-lg font-bold text-emerald-700">
1401
- ${orderData.length > 0 ? orderData.sort((a: any, b: any) => b.total - a.total)[0]?.total?.toLocaleString() || '0' : '8,750'}
1402
- </div>
1403
- <div className="text-xs text-emerald-600">
1404
- {orderData.length > 0 ? Math.round((orderData.sort((a: any, b: any) => b.total - a.total)[0]?.total || 0) / orderData.reduce((sum: number, cat: any) => sum + cat.total, 0) * 100) : 35}% of total
1405
- </div>
1406
- </div>
1407
- </div>
1408
- </div>
1409
-
1410
- {/* Revenue Growth Prediction */}
1411
- <div className="p-4 bg-gradient-to-r from-blue-50 to-blue-100 rounded-lg border border-blue-200">
1412
- <div className="text-sm text-blue-600 font-medium">Projected Growth</div>
1413
- <div className="text-xl font-bold text-blue-800">
1414
- +{totalRevenue > 0 ? ((totalRevenue / 50000) * 100).toFixed(1) : 18.5}%
1415
- </div>
1416
- <div className="text-xs text-blue-600">Next quarter forecast</div>
1417
- <div className="mt-2">
1418
- <SparkAreaChart
1419
- data={monthlyRevenueData.slice(-6)}
1420
- categories={["revenue"]}
1421
- index="month"
1422
- colors={["blue"]}
1423
- className="h-8 w-full"
1424
- />
1425
- </div>
1426
- </div>
1427
-
1428
- {/* Performance Score */}
1429
- <div className="p-4 bg-gradient-to-r from-violet-50 to-violet-100 rounded-lg border border-violet-200">
1430
- <div className="text-sm text-violet-600 font-medium">Performance Score</div>
1431
- <div className="flex items-center space-x-2">
1432
- <div className="text-xl font-bold text-violet-800">
1433
- {Math.min(100, Math.round((totalRevenue / 30000) * 100))}%
1434
- </div>
1435
- <div className="flex-1 bg-violet-200 rounded-full h-2">
1436
- <div
1437
- className="bg-violet-500 h-2 rounded-full transition-all duration-1000"
1438
- style={{ width: `${Math.min(100, Math.round((totalRevenue / 30000) * 100))}%` }}
1439
- />
1440
- </div>
1441
- </div>
1442
- <div className="text-xs text-violet-600 mt-1">Excellent performance</div>
1443
- </div>
1444
- </div>
1445
- </div>
1446
- </div>
1447
- </div>
1448
- </CardContent>
1449
- </Card>
1450
- </div>
1451
-
1452
- {/* Advanced Data Table Section */}
1453
- <Card>
1454
- <CardHeader>
1455
- <CardTitle>Recent Transactions</CardTitle>
1456
- <CardDescription>
1457
- Latest transaction data with comprehensive details
1458
- </CardDescription>
1459
- </CardHeader>
1460
- <CardContent>
1461
- <Table>
1462
- <TableHead>
1463
- <TableRow>
1464
- <TableHeaderCell>Transaction ID</TableHeaderCell>
1465
- <TableHeaderCell>Customer</TableHeaderCell>
1466
- <TableHeaderCell>Category</TableHeaderCell>
1467
- <TableHeaderCell>Amount</TableHeaderCell>
1468
- <TableHeaderCell>Payment Method</TableHeaderCell>
1469
- <TableHeaderCell>Date</TableHeaderCell>
1470
- </TableRow>
1471
- </TableHead>
1472
- <TableBody>
1473
- {recentTransactions.map((transaction: any) => (
1474
- <TableRow key={transaction.id}>
1475
- <TableCell className="font-medium">{transaction.id}</TableCell>
1476
- <TableCell>{transaction.customer}</TableCell>
1477
- <TableCell>
1478
- <Badge variant="outline" className="text-xs">
1479
- {transaction.category}
1480
- </Badge>
1481
- </TableCell>
1482
- <TableCell className="font-semibold text-emerald-600">
1483
- ${transaction.amount.toLocaleString()}
1484
- </TableCell>
1485
- <TableCell>{transaction.payment_method}</TableCell>
1486
- <TableCell className="text-gray-500">{transaction.date}</TableCell>
1487
- </TableRow>
1488
- ))}
1489
- </TableBody>
1490
- </Table>
1491
- </CardContent>
1492
- </Card>
1493
-
1494
- {/* Data Source Info */}
1495
- {userQuery.data?.user && (
1496
- <Alert>
1497
- <AlertCircle className="h-4 w-4" />
1498
- <AlertDescription>
1499
- Data is being fetched from Copa-lib APIs. Current user: {userQuery.data.user.name}
1500
- ({userQuery.data.user.organization || 'No organization'})
1501
- </AlertDescription>
1502
- </Alert>
1503
- )}
1504
- </div>
1505
- )
1506
- }