Improve explorer SSR, hydration, compaction, and smoke coverage.
Defer heavy getServerSideProps on home, operator, addresses, and wallet to cut TTFB; centralize locale-safe formatters with client-only relative times; add compact ops UX, bridge/operator relay pagination, and Playwright route/scroll smoke in deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
57
frontend/src/components/common/ClientRelativeTime.tsx
Normal file
57
frontend/src/components/common/ClientRelativeTime.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { formatRelativeAgeAt } from '@/utils/format'
|
||||
|
||||
const PLACEHOLDER = '…'
|
||||
|
||||
export default function ClientRelativeTime({
|
||||
value,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
fallback = 'Unknown',
|
||||
className,
|
||||
}: {
|
||||
value?: string | null
|
||||
prefix?: string
|
||||
suffix?: string
|
||||
fallback?: string
|
||||
className?: string
|
||||
}) {
|
||||
const [label, setLabel] = useState(PLACEHOLDER)
|
||||
|
||||
useEffect(() => {
|
||||
if (!value) {
|
||||
setLabel(fallback)
|
||||
return
|
||||
}
|
||||
const parsed = Date.parse(value)
|
||||
if (!Number.isFinite(parsed)) {
|
||||
setLabel(fallback)
|
||||
return
|
||||
}
|
||||
const update = () => setLabel(formatRelativeAgeAt(Date.now(), value))
|
||||
update()
|
||||
const id = window.setInterval(update, 30_000)
|
||||
return () => window.clearInterval(id)
|
||||
}, [value, fallback])
|
||||
|
||||
const content = label === PLACEHOLDER ? PLACEHOLDER : label
|
||||
if (className) {
|
||||
return (
|
||||
<span className={className} suppressHydrationWarning>
|
||||
{prefix}
|
||||
{content}
|
||||
{suffix}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<span suppressHydrationWarning>
|
||||
{prefix}
|
||||
{content}
|
||||
{suffix}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user