feat: add AutoRefresh component for automatic data refreshing on pages
Build Images and Deploy / Update-PROD-Stack (push) Failing after 33s

This commit is contained in:
2026-03-19 22:10:50 -04:00
parent d0dc52f82b
commit 005b4543f6
7 changed files with 42 additions and 3 deletions
+2
View File
@@ -6,6 +6,7 @@ import { formatCurrency, formatPnl, pnlColor } from '@/lib/utils'
import { formatDistanceToNow } from 'date-fns' import { formatDistanceToNow } from 'date-fns'
import Link from 'next/link' import Link from 'next/link'
import { Building2, TrendingUp, TrendingDown } from 'lucide-react' import { Building2, TrendingUp, TrendingDown } from 'lucide-react'
import { AutoRefresh } from '@/components/AutoRefresh'
import { calcFundNav } from '@/lib/pricing' import { calcFundNav } from '@/lib/pricing'
import InvestPanel from './InvestPanel' import InvestPanel from './InvestPanel'
import { PriceChart } from '@/components/PriceChart' import { PriceChart } from '@/components/PriceChart'
@@ -88,6 +89,7 @@ export default async function FundPage({ params }: { params: { slug: string } })
return ( return (
<div className="max-w-4xl mx-auto space-y-8"> <div className="max-w-4xl mx-auto space-y-8">
<AutoRefresh intervalMs={30_000} />
{/* Header */} {/* Header */}
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4"> <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div> <div>
+3 -1
View File
@@ -9,6 +9,7 @@ import { ResearchPanel } from './ResearchPanel'
import { Hash, Clock, Link as LinkIcon, AlertTriangle } from 'lucide-react' import { Hash, Clock, Link as LinkIcon, AlertTriangle } from 'lucide-react'
import { formatDistanceToNow } from 'date-fns' import { formatDistanceToNow } from 'date-fns'
import Link from 'next/link' import Link from 'next/link'
import { AutoRefresh } from '@/components/AutoRefresh'
const ZOMBIE_ZERO_COUNT = parseInt(process.env.ZOMBIE_ZERO_COUNT ?? '1000', 10) const ZOMBIE_ZERO_COUNT = parseInt(process.env.ZOMBIE_ZERO_COUNT ?? '1000', 10)
const PRICE_UPDATE_INTERVAL_MINUTES = parseInt(process.env.PRICE_UPDATE_INTERVAL_MINUTES ?? '60', 10) const PRICE_UPDATE_INTERVAL_MINUTES = parseInt(process.env.PRICE_UPDATE_INTERVAL_MINUTES ?? '60', 10)
@@ -126,7 +127,8 @@ export default async function HashtagPage({ params, searchParams }: Props) {
return ( return (
<div className="space-y-8"> <div className="space-y-8">
{/* Header */} <AutoRefresh intervalMs={30_000} />
{/* Header */}}
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4"> <div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4">
<div> <div>
<h1 className="text-3xl font-bold">#{hashtag.displayTag}</h1> <h1 className="text-3xl font-bold">#{hashtag.displayTag}</h1>
+2
View File
@@ -5,6 +5,7 @@ import { formatCurrency } from '@/lib/utils'
import { calcFundNav } from '@/lib/pricing' import { calcFundNav } from '@/lib/pricing'
import Link from 'next/link' import Link from 'next/link'
import { Trophy, TrendingUp, TrendingDown, Building2, Users } from 'lucide-react' import { Trophy, TrendingUp, TrendingDown, Building2, Users } from 'lucide-react'
import { AutoRefresh } from '@/components/AutoRefresh'
export const dynamic = 'force-dynamic' export const dynamic = 'force-dynamic'
@@ -119,6 +120,7 @@ export default async function LeaderboardPage({
return ( return (
<div className="max-w-3xl mx-auto space-y-6"> <div className="max-w-3xl mx-auto space-y-6">
<AutoRefresh intervalMs={30_000} />
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Trophy className="h-7 w-7 text-amber-400" /> <Trophy className="h-7 w-7 text-amber-400" />
<div> <div>
+2 -1
View File
@@ -6,6 +6,7 @@ import { TrendingUp, Users, Hash, AlertTriangle } from 'lucide-react'
import Link from 'next/link' import Link from 'next/link'
import { formatPnl, pnlColor } from '@/lib/utils' import { formatPnl, pnlColor } from '@/lib/utils'
import { formatDistanceToNow } from 'date-fns' import { formatDistanceToNow } from 'date-fns'
import { AutoRefresh } from '@/components/AutoRefresh'
const ZOMBIE_ZERO_COUNT = parseInt(process.env.ZOMBIE_ZERO_COUNT ?? '1000', 10) const ZOMBIE_ZERO_COUNT = parseInt(process.env.ZOMBIE_ZERO_COUNT ?? '1000', 10)
const PRICE_UPDATE_INTERVAL_MINUTES = parseInt(process.env.PRICE_UPDATE_INTERVAL_MINUTES ?? '60', 10) const PRICE_UPDATE_INTERVAL_MINUTES = parseInt(process.env.PRICE_UPDATE_INTERVAL_MINUTES ?? '60', 10)
@@ -93,7 +94,7 @@ export default async function HomePage() {
return ( return (
<div className="space-y-10"> <div className="space-y-10">
{/* Hero */} <AutoRefresh intervalMs={30_000} />}
<div className="text-center py-8"> <div className="text-center py-8">
<h1 className="text-4xl font-bold tracking-tight mb-3"> <h1 className="text-4xl font-bold tracking-tight mb-3">
The{' '} The{' '}
+2
View File
@@ -5,6 +5,7 @@ import { redirect } from 'next/navigation'
import { formatCurrency, formatNumber, formatPnl, pnlColor } from '@/lib/utils' import { formatCurrency, formatNumber, formatPnl, pnlColor } from '@/lib/utils'
import Link from 'next/link' import Link from 'next/link'
import { Coins, ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react' import { Coins, ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react'
import { AutoRefresh } from '@/components/AutoRefresh'
export const dynamic = 'force-dynamic' export const dynamic = 'force-dynamic'
@@ -130,6 +131,7 @@ export default async function PositionsPage({
return ( return (
<div className="max-w-4xl mx-auto space-y-6"> <div className="max-w-4xl mx-auto space-y-6">
<AutoRefresh intervalMs={30_000} />
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Coins className="h-6 w-6 text-indigo-400" /> <Coins className="h-6 w-6 text-indigo-400" />
<h1 className="text-2xl font-bold">Open Positions</h1> <h1 className="text-2xl font-bold">Open Positions</h1>
+3 -1
View File
@@ -2,6 +2,7 @@ import { prisma } from '@/lib/prisma'
import { formatCurrency, pnlColor } from '@/lib/utils' import { formatCurrency, pnlColor } from '@/lib/utils'
import Link from 'next/link' import Link from 'next/link'
import { ArrowUp, ArrowDown, ArrowUpDown, BarChart2, Building2 } from 'lucide-react' import { ArrowUp, ArrowDown, ArrowUpDown, BarChart2, Building2 } from 'lucide-react'
import { AutoRefresh } from '@/components/AutoRefresh'
import { formatDistanceToNow } from 'date-fns' import { formatDistanceToNow } from 'date-fns'
import { calcFundNav } from '@/lib/pricing' import { calcFundNav } from '@/lib/pricing'
@@ -197,7 +198,8 @@ export default async function StocksPage({ searchParams }: PageProps) {
return ( return (
<div className="max-w-5xl mx-auto space-y-6"> <div className="max-w-5xl mx-auto space-y-6">
{/* Header */} <AutoRefresh intervalMs={30_000} />
{/* Header */}}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<BarChart2 className="h-6 w-6 text-indigo-400" /> <BarChart2 className="h-6 w-6 text-indigo-400" />
+28
View File
@@ -0,0 +1,28 @@
'use client'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
/**
* Silently refreshes all server-component data on the current page by calling
* router.refresh() on an interval and whenever the tab regains focus.
*
* Drop this anywhere inside a server-component page — it renders nothing.
*/
export function AutoRefresh({ intervalMs = 30_000 }: { intervalMs?: number }) {
const router = useRouter()
useEffect(() => {
const id = setInterval(() => router.refresh(), intervalMs)
const onFocus = () => router.refresh()
document.addEventListener('visibilitychange', onFocus)
return () => {
clearInterval(id)
document.removeEventListener('visibilitychange', onFocus)
}
}, [router, intervalMs])
return null
}