'use client' import { useState, useEffect, useMemo } from 'react' import { logger } from '@/lib/utils/logger' import { getDailyStats } from '@/lib/api/stats' import type { DailyStat } from '@/lib/api/stats' interface PeakHoursProps { siteId: string dateRange: { start: string, end: string } } const DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] const HOUR_LABELS: Record = { 0: '12am', 6: '6am', 12: '12pm', 18: '6pm' } export default function PeakHours({ siteId, dateRange }: PeakHoursProps) { const [data, setData] = useState([]) const [isLoading, setIsLoading] = useState(true) const [tooltip, setTooltip] = useState<{ day: number; hour: number; value: number } | null>(null) useEffect(() => { const fetchData = async () => { setIsLoading(true) try { const result = await getDailyStats(siteId, dateRange.start, dateRange.end, 'hour') setData(result) } catch (e) { logger.error(e) } finally { setIsLoading(false) } } fetchData() }, [siteId, dateRange]) const { grid, max } = useMemo(() => { // grid[adjustedDay][hour] where Mon=0 ... Sun=6 const grid: number[][] = Array.from({ length: 7 }, () => Array(24).fill(0)) for (const d of data) { const date = new Date(d.date) const day = date.getDay() // 0=Sun const hour = date.getHours() const adjustedDay = day === 0 ? 6 : day - 1 // Mon=0 ... Sun=6 grid[adjustedDay][hour] += d.pageviews } const max = Math.max(...grid.flat(), 1) return { grid, max } }, [data]) const hasData = data.some(d => d.pageviews > 0) return (

Peak Hours

When your visitors are most active

{isLoading ? (
{Array.from({ length: 7 }).map((_, i) => (
))}
) : hasData ? (
{grid.map((hours, dayIdx) => (
{DAYS[dayIdx]}
{hours.map((value, hour) => (
setTooltip({ day: dayIdx, hour, value })} onMouseLeave={() => setTooltip(null)} /> ))}
))} {/* Hour axis labels */}
{Object.entries(HOUR_LABELS).map(([h, label]) => ( {label} ))} 12am
{/* Tooltip */} {tooltip && (
{DAYS[tooltip.day]} {tooltip.hour}:00 — {tooltip.value} pageviews
)}
) : (

No data available for this period

)}
) }