diff --git a/components/behavior/FrustrationByPageTable.tsx b/components/behavior/FrustrationByPageTable.tsx new file mode 100644 index 0000000..99ae877 --- /dev/null +++ b/components/behavior/FrustrationByPageTable.tsx @@ -0,0 +1,107 @@ +'use client' + +import { formatNumber } from '@ciphera-net/ui' +import type { FrustrationByPage } from '@/lib/api/stats' + +interface FrustrationByPageTableProps { + pages: FrustrationByPage[] + loading: boolean +} + +function SkeletonRows() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( +
+
+
+
+
+
+
+
+
+ ))} +
+ ) +} + +export default function FrustrationByPageTable({ pages, loading }: FrustrationByPageTableProps) { + const hasData = pages.length > 0 + const maxTotal = Math.max(...pages.map(p => p.total), 1) + + return ( +
+
+

+ Frustration by Page +

+
+

+ Pages with the most frustration signals +

+ + {loading ? ( + + ) : hasData ? ( +
+ {/* Header */} +
+ Page +
+ Rage + Dead + Total + Elements +
+
+ + {/* Rows */} +
+ {pages.map((page) => { + const barWidth = (page.total / maxTotal) * 100 + return ( +
+ {/* Background bar */} +
+ + {page.page_path} + +
+ + {formatNumber(page.rage_clicks)} + + + {formatNumber(page.dead_clicks)} + + + {formatNumber(page.total)} + + + {page.unique_elements} + +
+
+ ) + })} +
+
+ ) : ( +
+

+ No frustration signals detected in this period +

+
+ )} +
+ ) +}