94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
/**
|
|
* 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<LiveAuctionState>({
|
|
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 };
|
|
}
|