'use client' import { useEffect, useState } from 'react' import type { TrumpPost } from '@/types' function fmtPct(n: number | null | undefined) { if (n == null || isNaN(n)) return '—' // null = window not yet closed const s = n.toFixed(2) + '%' return n >= 0 ? '+' + s : s } function fmtImpactPct(v: number | null | undefined) { if (v == null || isNaN(v)) return '—' const s = Math.abs(v).toFixed(2) + '%' return v >= 0 ? '+' + s : '-' + s } function timeAgo(iso: string) { const diff = Date.now() - new Date(iso).getTime() const m = Math.floor(diff / 60000) if (m < 1) return 'just now' if (m < 60) return m + 'm' const h = Math.floor(m / 60) if (h < 24) return h + 'h' return Math.floor(h / 24) + 'd' } /** * Hydration-safe wrapper for relative time. Returns an empty placeholder on * SSR / first client render, then the real relative time after mount. Prevents * the SSR/CSR "5m vs 6m" mismatch error. */ function TimeAgo({ iso, suffix = '' }: { iso: string; suffix?: string }) { const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) }, []) if (!mounted) return … return {timeAgo(iso)}{suffix} } /** * Hydration-safe absolute date formatter. Uses fixed 'en-US' locale + options * so the server/client outputs match once mounted; renders a placeholder before * mount to avoid timezone mismatches. */ function LocalDateTime({ iso, opts }: { iso: string; opts?: Intl.DateTimeFormatOptions }) { const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) }, []) if (!mounted) return … return {new Date(iso).toLocaleString('en-US', opts)} } function SourceIcon({ source: _source }: { source: string }) { // Truth Social only — no X/Twitter support. return
{expanded ? post.text : (post.text.slice(0, 180) + (post.text.length > 180 ? '…' : ''))}