Initial commit with 2026 World Cup Quant Platform core modules and CI/CD
This commit is contained in:
83
platform/web/hooks/useLiveMatchData.ts
Normal file
83
platform/web/hooks/useLiveMatchData.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
type OddsPayload = {
|
||||
matchId: string;
|
||||
market: string;
|
||||
bookmaker: string;
|
||||
odds: number;
|
||||
};
|
||||
|
||||
type MatchEventPayload = {
|
||||
matchId: string;
|
||||
type: 'goal' | 'yellow' | 'red' | 'substitution';
|
||||
minute: number;
|
||||
detail: string;
|
||||
};
|
||||
|
||||
type WSMessage =
|
||||
| ({ eventType: 'odds'; payload: OddsPayload })
|
||||
| ({ eventType: 'event'; payload: MatchEventPayload })
|
||||
| Record<string, unknown>;
|
||||
|
||||
export function useLiveMatchData(matchId: string | null) {
|
||||
const [odds, setOdds] = useState<OddsPayload[]>([]);
|
||||
const [events, setEvents] = useState<MatchEventPayload[]>([]);
|
||||
|
||||
const wsBase = process.env.NEXT_PUBLIC_WS_URL || 'ws://localhost:8000/ws/matches';
|
||||
|
||||
useEffect(() => {
|
||||
if (!matchId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let isMounted = true;
|
||||
const ws = new WebSocket(`${wsBase}/${matchId}`);
|
||||
|
||||
ws.onopen = () => {
|
||||
if (!isMounted) return;
|
||||
ws.send(JSON.stringify({ action: 'subscribe', matchId }));
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
let message: WSMessage;
|
||||
try {
|
||||
message = JSON.parse(event.data);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.eventType === 'odds') {
|
||||
setOdds((prev) => {
|
||||
const next = [...prev.filter((item) => item.market !== message.payload.market), message.payload];
|
||||
return next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.eventType === 'event') {
|
||||
setEvents((prev) => [message.payload, ...prev].slice(0, 80));
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
console.error('WebSocket 錯誤', matchId);
|
||||
};
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
ws.close(1000);
|
||||
};
|
||||
}, [matchId, wsBase]);
|
||||
|
||||
const liveState = useMemo(
|
||||
() => ({
|
||||
odds,
|
||||
events,
|
||||
}),
|
||||
[odds, events],
|
||||
);
|
||||
|
||||
return liveState;
|
||||
}
|
||||
Reference in New Issue
Block a user