'use client'; import { useEffect, useState, useRef } from 'react'; interface PriceDisplayProps { productId: string; className?: string; perNight?: boolean; } interface PricingData { price: number; currency: string; cachedAt: string; } interface SessionData { sessionId: string; experimentId?: string; } const fetchSession = async (): Promise => { try { const res = await fetch('/api/session'); const data = await res.json(); return { sessionId: data.sessionId || '', experimentId: data.experimentId || '', }; } catch (err) { console.error('failed to fetch session:', err); return { sessionId: '', experimentId: '' }; } }; const formatPrice = (price: number, currency: string) => { return new Intl.NumberFormat('en-US', { // like an std localization style: 'currency', currency, }).format(price); }; const isCacheStale = (cachedAt: string, thresholdMs = 60000) => { const cacheTime = new Date(cachedAt).getTime(); const now = Date.now(); return now - cacheTime > thresholdMs; }; export default function PriceDisplay({ productId, className = '', perNight = false, }: PriceDisplayProps) { const sessionRef = useRef(null); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const initAndFetch = async () => { setLoading(true); setError(null); try { // fetch session if not already loaded if (!sessionRef.current) { sessionRef.current = await fetchSession(); } const { sessionId, experimentId } = sessionRef.current; if (!sessionId) { setError('Invalid session'); setLoading(false); return; } const params = new URLSearchParams({ productId, sessionId, experimentId: experimentId || '', }); const res = await fetch(`/api/pricing?${params.toString()}`); if (!res.ok) { throw new Error(`Failed to fetch price: ${res.status}`); } const pricingData: PricingData = await res.json(); setData(pricingData); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setLoading(false); } }; initAndFetch(); }, [productId]); if (loading) { return (
Loading...
); } if (error || !data) { return (
Price unavailable
); } const isStale = isCacheStale(data.cachedAt); const formattedPrice = formatPrice(data.price, data.currency); return (
{formattedPrice} {perNight && /night}
{isStale && ( prices may be outdated )}
); }