spb/internetpressure
Public
1'use client';23import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from 'react';4import { formatTime, type TimeMode, type TimeStyle } from './format';56interface TimeCtx {7 mode: TimeMode;8 setMode: (m: TimeMode) => void;9 format: (ts: string | number | Date | null | undefined, style?: TimeStyle) => string;10}1112const Ctx = createContext<TimeCtx>({ mode: 'utc', setMode: () => {}, format: (ts, style) => formatTime(ts, 'utc', style) });13const KEY = 'ip.time-mode';1415export function TimeProvider({ children }: { children: ReactNode }) {16 // UTC on the server and on first paint; the stored preference is applied after hydration (no mismatch).17 const [mode, setModeState] = useState<TimeMode>('utc');18 useEffect(() => {19 try {20 const v = window.localStorage.getItem(KEY);21 if (v === 'local' || v === 'utc') setModeState(v);22 } catch {23 /* private mode */24 }25 }, []);26 const setMode = useCallback((m: TimeMode) => {27 setModeState(m);28 try {29 window.localStorage.setItem(KEY, m);30 } catch {31 /* ignore */32 }33 }, []);34 const value = useMemo<TimeCtx>(() => ({ mode, setMode, format: (ts, style) => formatTime(ts, mode, style) }), [mode, setMode]);35 return <Ctx.Provider value={value}>{children}</Ctx.Provider>;36}3738export function useTime() {39 return useContext(Ctx);40}4142/** Inline timestamp that follows the UTC/local toggle. */43export function Time({ ts, style = 'short', className }: { ts: string | number | Date | null | undefined; style?: TimeStyle; className?: string }) {44 const { format } = useTime();45 return (46 <time dateTime={ts ? new Date(ts).toISOString() : undefined} className={className} suppressHydrationWarning>47 {format(ts, style)}48 </time>49 );50}51