feat: implement site statistics fetching and display in SiteList component

This commit is contained in:
Usman Baig
2026-02-22 00:20:54 +01:00
parent 1a970279b5
commit 2aedc656d7
4 changed files with 215 additions and 127 deletions

View File

@@ -6,6 +6,8 @@ import { motion } from 'framer-motion'
import { useAuth } from '@/lib/auth/context'
import { initiateOAuthFlow, initiateSignupFlow } from '@/lib/api/oauth'
import { listSites, deleteSite, type Site } from '@/lib/api/sites'
import { getStats, getDailyStats } from '@/lib/api/stats'
import type { Stats, DailyStat } from '@/lib/api/stats'
import { getSubscription, type SubscriptionDetails } from '@/lib/api/billing'
import { LoadingOverlay } from '@ciphera-net/ui'
import SiteList from '@/components/sites/SiteList'
@@ -97,10 +99,13 @@ function ComparisonSection() {
}
type SiteStatsMap = Record<string, { stats: Stats; dailyStats: DailyStat[] }>
export default function HomePage() {
const { user, loading: authLoading } = useAuth()
const [sites, setSites] = useState<Site[]>([])
const [sitesLoading, setSitesLoading] = useState(true)
const [siteStats, setSiteStats] = useState<SiteStatsMap>({})
const [subscription, setSubscription] = useState<SubscriptionDetails | null>(null)
const [subscriptionLoading, setSubscriptionLoading] = useState(false)
const [showFinishSetupBanner, setShowFinishSetupBanner] = useState(true)
@@ -112,6 +117,37 @@ export default function HomePage() {
}
}, [user])
useEffect(() => {
if (sites.length === 0) {
setSiteStats({})
return
}
let cancelled = false
const today = new Date().toISOString().split('T')[0]
const start7d = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
const load = async () => {
const results = await Promise.allSettled(
sites.map(async (site) => {
const [statsRes, dailyRes] = await Promise.all([
getStats(site.id, today, today),
getDailyStats(site.id, start7d, today, 'day'),
])
return { siteId: site.id, stats: statsRes, dailyStats: dailyRes ?? [] }
})
)
if (cancelled) return
const map: SiteStatsMap = {}
for (const r of results) {
if (r.status === 'fulfilled') {
map[r.value.siteId] = { stats: r.value.stats, dailyStats: r.value.dailyStats }
}
}
setSiteStats(map)
}
load()
return () => { cancelled = true }
}, [sites])
useEffect(() => {
if (typeof window === 'undefined') return
if (localStorage.getItem('pulse_welcome_completed') === 'true') setShowFinishSetupBanner(false)
@@ -370,7 +406,11 @@ export default function HomePage() {
</div>
<div className="rounded-2xl border border-neutral-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900">
<p className="text-sm text-neutral-500 dark:text-neutral-400">Total Visitors (24h)</p>
<p className="text-2xl font-bold text-neutral-900 dark:text-white">--</p>
<p className="text-2xl font-bold text-neutral-900 dark:text-white">
{sites.length === 0 || Object.keys(siteStats).length < sites.length
? '--'
: Object.values(siteStats).reduce((sum, { stats }) => sum + (stats?.visitors ?? 0), 0).toLocaleString()}
</p>
</div>
<div className="rounded-2xl border border-neutral-200 bg-brand-orange/10 p-4 dark:border-neutral-800">
<p className="text-sm text-brand-orange">Plan & usage</p>
@@ -456,7 +496,7 @@ export default function HomePage() {
)}
{(sitesLoading || sites.length > 0) && (
<SiteList sites={sites} loading={sitesLoading} onDelete={handleDelete} />
<SiteList sites={sites} siteStats={siteStats} loading={sitesLoading} onDelete={handleDelete} />
)}
</div>
)