/** * Real-time state hook for the live auction bidder view. * Subscribes to item_activated, next_live_bid, live_bid_accepted, * item_state_changed, item_sold. */ import { useState, useEffect } from "react"; import { getSocket } from "../lib/socket.js"; import { useConnectivityStore } from "../store/connectivity.js"; import type { AuctionItem, Bid, ItemState } from "@storybid/shared"; export interface LiveAuctionState { currentItem: AuctionItem | null; currentBid: number | null; calledAmount: number | null; state: ItemState | null; recentBids: Bid[]; } export function useLiveAuction(eventId: string) { const socketVersion = useConnectivityStore((s) => s.socketVersion); const [state, setState] = useState({ currentItem: null, currentBid: null, calledAmount: null, state: null, recentBids: [], }); useEffect(() => { const socket = getSocket(); socket.emit("join_event", eventId); socket.on("item_activated", ({ item }) => { setState({ currentItem: item, currentBid: item.currentHighBid, calledAmount: item.openingBid, state: item.state, recentBids: [], }); }); socket.on("next_live_bid", ({ amount }) => { setState((prev) => ({ ...prev, calledAmount: amount })); }); socket.on("live_bid_accepted", ({ bid, item }) => { setState((prev) => ({ ...prev, currentBid: item.currentHighBid, state: item.state, currentItem: item, recentBids: [bid, ...prev.recentBids].slice(0, 10), })); }); socket.on("item_state_changed", ({ itemId, state: newState }) => { setState((prev) => { if (prev.currentItem?.id !== itemId) return prev; return { ...prev, state: newState }; }); }); socket.on("item_sold", ({ itemId, amount }) => { setState((prev) => { if (prev.currentItem?.id !== itemId) return prev; return { ...prev, currentBid: amount, state: "sold" }; }); }); return () => { socket.emit("leave_event", eventId); socket.off("item_activated"); socket.off("next_live_bid"); socket.off("live_bid_accepted"); socket.off("item_state_changed"); socket.off("item_sold"); }; }, [eventId, socketVersion]); const placeBid = (itemId: string, amount: number, deviceId: string, clientSeq: number) => { const socket = getSocket(); socket.emit("place_live_bid", { itemId, amount, deviceId, clientSeq, clientCreatedAt: new Date().toISOString(), }); }; return { ...state, placeBid }; }