'use client' import { useEffect, useState } from 'react' import { useParams, useRouter } from 'next/navigation' import { getSite, type Site } from '@/lib/api/sites' import { getStats, getRealtime, getDailyStats, getTopPages, getTopReferrers, getCountries, getCities, getRegions, getBrowsers, getOS, getDevices, getScreenResolutions, getEntryPages, getExitPages, getDashboard, getPerformanceByPage, type Stats, type DailyStat, type PerformanceByPageStat } from '@/lib/api/stats' import { formatNumber, formatDuration, getDateRange } from '@/lib/utils/format' import { toast } from 'sonner' import LoadingOverlay from '@/components/LoadingOverlay' import Select from '@/components/ui/Select' import DatePicker from '@/components/ui/DatePicker' import ContentStats from '@/components/dashboard/ContentStats' import TopReferrers from '@/components/dashboard/TopReferrers' import Locations from '@/components/dashboard/Locations' import TechSpecs from '@/components/dashboard/TechSpecs' import Chart from '@/components/dashboard/Chart' import PerformanceStats from '@/components/dashboard/PerformanceStats' export default function SiteDashboardPage() { const params = useParams() const router = useRouter() const siteId = params.id as string const [site, setSite] = useState(null) const [loading, setLoading] = useState(true) const [stats, setStats] = useState({ pageviews: 0, visitors: 0, bounce_rate: 0, avg_duration: 0 }) const [prevStats, setPrevStats] = useState(undefined) const [realtime, setRealtime] = useState(0) const [dailyStats, setDailyStats] = useState([]) const [prevDailyStats, setPrevDailyStats] = useState(undefined) const [topPages, setTopPages] = useState([]) const [entryPages, setEntryPages] = useState([]) const [exitPages, setExitPages] = useState([]) const [topReferrers, setTopReferrers] = useState([]) const [countries, setCountries] = useState([]) const [cities, setCities] = useState([]) const [regions, setRegions] = useState([]) const [browsers, setBrowsers] = useState([]) const [os, setOS] = useState([]) const [devices, setDevices] = useState([]) const [screenResolutions, setScreenResolutions] = useState([]) const [performance, setPerformance] = useState<{ lcp: number, cls: number, inp: number }>({ lcp: 0, cls: 0, inp: 0 }) const [performanceByPage, setPerformanceByPage] = useState(null) const [dateRange, setDateRange] = useState(getDateRange(30)) const [isDatePickerOpen, setIsDatePickerOpen] = useState(false) const [todayInterval, setTodayInterval] = useState<'minute' | 'hour'>('hour') useEffect(() => { loadData() const interval = setInterval(() => { loadRealtime() }, 30000) // Update every 30 seconds return () => clearInterval(interval) }, [siteId, dateRange, todayInterval]) const getPreviousDateRange = (start: string, end: string) => { const startDate = new Date(start) const endDate = new Date(end) const duration = endDate.getTime() - startDate.getTime() // * If duration is 0 (Today), set previous range to yesterday if (duration === 0) { const prevEnd = new Date(startDate.getTime() - 24 * 60 * 60 * 1000) const prevStart = prevEnd return { start: prevStart.toISOString().split('T')[0], end: prevEnd.toISOString().split('T')[0] } } const prevEnd = new Date(startDate.getTime() - 24 * 60 * 60 * 1000) const prevStart = new Date(prevEnd.getTime() - duration) return { start: prevStart.toISOString().split('T')[0], end: prevEnd.toISOString().split('T')[0] } } const loadData = async () => { try { setLoading(true) const interval = dateRange.start === dateRange.end ? todayInterval : 'day' const [data, prevStatsData, prevDailyStatsData] = await Promise.all([ getDashboard(siteId, dateRange.start, dateRange.end, 10, interval), (async () => { const prevRange = getPreviousDateRange(dateRange.start, dateRange.end) return getStats(siteId, prevRange.start, prevRange.end) })(), (async () => { const prevRange = getPreviousDateRange(dateRange.start, dateRange.end) return getDailyStats(siteId, prevRange.start, prevRange.end, interval) })() ]) setSite(data.site) setStats(data.stats || { pageviews: 0, visitors: 0, bounce_rate: 0, avg_duration: 0 }) setRealtime(data.realtime_visitors || 0) setDailyStats(Array.isArray(data.daily_stats) ? data.daily_stats : []) setPrevStats(prevStatsData) setPrevDailyStats(prevDailyStatsData) setTopPages(Array.isArray(data.top_pages) ? data.top_pages : []) setEntryPages(Array.isArray(data.entry_pages) ? data.entry_pages : []) setExitPages(Array.isArray(data.exit_pages) ? data.exit_pages : []) setTopReferrers(Array.isArray(data.top_referrers) ? data.top_referrers : []) setCountries(Array.isArray(data.countries) ? data.countries : []) setCities(Array.isArray(data.cities) ? data.cities : []) setRegions(Array.isArray(data.regions) ? data.regions : []) setBrowsers(Array.isArray(data.browsers) ? data.browsers : []) setOS(Array.isArray(data.os) ? data.os : []) setDevices(Array.isArray(data.devices) ? data.devices : []) setScreenResolutions(Array.isArray(data.screen_resolutions) ? data.screen_resolutions : []) setPerformance(data.performance || { lcp: 0, cls: 0, inp: 0 }) setPerformanceByPage(data.performance_by_page ?? null) } catch (error: any) { toast.error('Failed to load data: ' + (error.message || 'Unknown error')) } finally { setLoading(false) } } const loadRealtime = async () => { try { const data = await getRealtime(siteId) setRealtime(data.visitors) } catch (error) { // Silently fail for realtime updates } } if (loading) { return } if (!site) { return (

Site not found

) } return (

{site.name}

{site.domain}

{/* Realtime Indicator */}
{realtime} current visitors
setTodayInterval(value as 'minute' | 'hour')} options={[ { value: 'minute', label: '1 min' }, { value: 'hour', label: '1 hour' }, ]} className="min-w-[100px]" /> )}
{/* Advanced Chart with Integrated Stats */}
{/* Performance Stats - Only show if enabled */} {site.enable_performance_insights && (
)}
setIsDatePickerOpen(false)} onApply={(range) => { setDateRange(range) setIsDatePickerOpen(false) }} initialRange={dateRange} />
) }