'use client'; import { fetchLatestPrices } from '@/actions/prices.js'; import type { getLatestPrices } from '@/generated/prisma/sql.js'; import { deserialize } from '@/lib/superjson.js'; import { useEffect, useRef } from 'react'; import { toast } from 'sonner'; const PRICE_SPIKE_THRESHOLD_MWH = 100; const CHECK_INTERVAL_MS = 60_000; export function PriceAlertMonitor() { const previousPricesRef = useRef>(new Map()); const initialLoadRef = useRef(true); useEffect(() => { async function checkForSpikes() { const result = await fetchLatestPrices(); if (!result.ok) return; const prices = deserialize(result.data); const prevPrices = previousPricesRef.current; for (const p of prices) { const prevPrice = prevPrices.get(p.region_code); if (!initialLoadRef.current) { if (p.price_mwh >= PRICE_SPIKE_THRESHOLD_MWH) { toast.error(`Price Spike: ${p.region_code}`, { description: `${p.region_name} hit $${p.price_mwh.toFixed(2)}/MWh — above $${PRICE_SPIKE_THRESHOLD_MWH} threshold`, duration: 8000, }); } else if (prevPrice !== undefined && p.price_mwh > prevPrice * 1.15) { toast.warning(`Price Jump: ${p.region_code}`, { description: `${p.region_name} jumped to $${p.price_mwh.toFixed(2)}/MWh (+${(((p.price_mwh - prevPrice) / prevPrice) * 100).toFixed(1)}%)`, duration: 6000, }); } } prevPrices.set(p.region_code, p.price_mwh); } initialLoadRef.current = false; } void checkForSpikes(); const interval = setInterval(() => void checkForSpikes(), CHECK_INTERVAL_MS); return () => clearInterval(interval); }, []); return null; }