PageSpeed monitoring, Polar billing, sidebar polish, frontend consistency audit #68

Merged
uz1mani merged 45 commits from staging into main 2026-03-23 19:07:54 +00:00
5 changed files with 707 additions and 0 deletions
Showing only changes of commit 2fd9bf82f1 - Show all commits

View File

@@ -1,7 +1,7 @@
'use client' 'use client'
import { useAuth } from '@/lib/auth/context' import { useAuth } from '@/lib/auth/context'
import { useEffect, useState } from 'react' import { useEffect, useState, useRef, useCallback } from 'react'
import { useParams } from 'next/navigation' import { useParams } from 'next/navigation'
import { useSite, usePageSpeedConfig, usePageSpeedLatest, usePageSpeedHistory } from '@/lib/swr/dashboard' import { useSite, usePageSpeedConfig, usePageSpeedLatest, usePageSpeedHistory } from '@/lib/swr/dashboard'
import { updatePageSpeedConfig, triggerPageSpeedCheck, type PageSpeedCheck, type AuditSummary } from '@/lib/api/pagespeed' import { updatePageSpeedConfig, triggerPageSpeedCheck, type PageSpeedCheck, type AuditSummary } from '@/lib/api/pagespeed'
@@ -116,15 +116,47 @@ export default function PageSpeedPage() {
} }
// * Trigger a manual PageSpeed check // * Trigger a manual PageSpeed check
// * Poll for results after triggering an async check
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)
const stopPolling = useCallback(() => {
if (pollRef.current) {
clearInterval(pollRef.current)
pollRef.current = null
}
}, [])
// * Clean up polling on unmount
useEffect(() => () => stopPolling(), [stopPolling])
const handleRunCheck = async () => { const handleRunCheck = async () => {
setRunning(true) setRunning(true)
try { try {
await triggerPageSpeedCheck(siteId) await triggerPageSpeedCheck(siteId)
mutateLatest() toast.success('PageSpeed check started — results will appear in 30-60 seconds')
toast.success('PageSpeed check complete')
// * Poll every 5s for up to 2 minutes until new results appear
const startedAt = Date.now()
const initialCheckedAt = latestChecks?.[0]?.checked_at
stopPolling()
pollRef.current = setInterval(async () => {
const elapsed = Date.now() - startedAt
if (elapsed > 120_000) {
stopPolling()
setRunning(false)
toast.error('Check is taking longer than expected. Results will appear when ready.')
return
}
const freshData = await mutateLatest()
const freshCheckedAt = freshData?.[0]?.checked_at
if (freshCheckedAt && freshCheckedAt !== initialCheckedAt) {
stopPolling()
setRunning(false)
toast.success('PageSpeed check complete')
}
}, 5000)
} catch (err: any) { } catch (err: any) {
toast.error(err?.message || 'Failed to run check') toast.error(err?.message || 'Failed to start check')
} finally {
setRunning(false) setRunning(false)
} }
} }

View File

@@ -75,17 +75,8 @@ export async function getPageSpeedCheck(siteId: string, checkId: string): Promis
return apiRequest<PageSpeedCheck>(`/sites/${siteId}/pagespeed/checks/${checkId}`) return apiRequest<PageSpeedCheck>(`/sites/${siteId}/pagespeed/checks/${checkId}`)
} }
export async function triggerPageSpeedCheck(siteId: string): Promise<PageSpeedCheck[]> { // * Triggers an async PageSpeed check. Returns immediately (202).
// * PSI checks take 10-30s per strategy (mobile + desktop sequential = up to 60s) // * Caller should poll getPageSpeedLatest() for results.
const controller = new AbortController() export async function triggerPageSpeedCheck(siteId: string): Promise<void> {
const timeoutId = setTimeout(() => controller.abort(), 120_000) await apiRequest(`/sites/${siteId}/pagespeed/check`, { method: 'POST' })
try {
const res = await apiRequest<{ checks: PageSpeedCheck[] }>(`/sites/${siteId}/pagespeed/check`, {
method: 'POST',
signal: controller.signal,
})
return res?.checks ?? []
} finally {
clearTimeout(timeoutId)
}
} }