diff --git a/src/hooks/use-auto-hosting-runner.ts b/src/hooks/use-auto-hosting-runner.ts
index 652a568..6dd6341 100644
--- a/src/hooks/use-auto-hosting-runner.ts
+++ b/src/hooks/use-auto-hosting-runner.ts
@@ -91,6 +91,9 @@ export function useAutoHostingRunner() {
const setCurrentUser = useAuthStore((state) => state.setCurrentUser)
const round = useGameRoundStore((state) => state.round)
const clearSelections = useGameRoundStore((state) => state.clearSelections)
+ const setRecentSuccessfulSelections = useGameRoundStore(
+ (state) => state.setRecentSuccessfulSelections,
+ )
const tableLimitMax = useGameSessionStore(
(state) => state.dashboard.tableLimitMax,
)
@@ -245,6 +248,7 @@ export function useAutoHostingRunner() {
lastBetPeriodNo: submittingRoundId,
})
markRoundSubmitted(submittingRoundId, parseBalance(latestBalance))
+ setRecentSuccessfulSelections(selections)
clearSelections()
} catch (error) {
if (useGameAutoHostingStore.getState().isHosting) {
@@ -272,6 +276,7 @@ export function useAutoHostingRunner() {
round.phase,
selections,
setCurrentUser,
+ setRecentSuccessfulSelections,
stopHosting,
tableLimitMax,
t,
diff --git a/src/hooks/use-game-realtime-sync.ts b/src/hooks/use-game-realtime-sync.ts
index 697a1fa..049eed0 100644
--- a/src/hooks/use-game-realtime-sync.ts
+++ b/src/hooks/use-game-realtime-sync.ts
@@ -239,7 +239,8 @@ function applyJackpotHitMessage(message: GameSocketMessage) {
if (jackpotHitData?.hits.length) {
useGameSessionStore.getState().pushJackpotBroadcasts(
jackpotHitData.hits.map((hit) => ({
- id: `${jackpotHitData.period_no}:${hit.result_number}:${hit.nickname}:${hit.total_win}`,
+ currentStreak: hit.current_streak,
+ id: `${jackpotHitData.period_no}:${hit.result_number}:${hit.nickname}:${hit.current_streak}:${hit.total_win}`,
nickname: hit.nickname,
periodNo: hit.period_no,
totalWin: hit.total_win,
diff --git a/src/lib/ws/message-parsers.ts b/src/lib/ws/message-parsers.ts
index 6c7e1e3..0d67034 100644
--- a/src/lib/ws/message-parsers.ts
+++ b/src/lib/ws/message-parsers.ts
@@ -224,12 +224,19 @@ function extractJackpotHitItem(value: unknown): JackpotHitItemDto | null {
}
const resultNumber = toOptionalNumber(source.result_number)
+ const currentStreak = toOptionalNumber(source.current_streak)
- if (typeof resultNumber !== 'number' || !Number.isInteger(resultNumber)) {
+ if (
+ typeof resultNumber !== 'number' ||
+ !Number.isInteger(resultNumber) ||
+ typeof currentStreak !== 'number' ||
+ !Number.isInteger(currentStreak)
+ ) {
return null
}
return {
+ current_streak: currentStreak,
nickname: source.nickname,
period_no: source.period_no,
result_number: resultNumber,
diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts
index ff33c3c..501e3a6 100644
--- a/src/locales/en-US.ts
+++ b/src/locales/en-US.ts
@@ -168,6 +168,16 @@ export default {
title: 'Round {{roundId}}',
action: 'Start Betting',
},
+ jackpotBroadcast: {
+ ariaLabel: 'Jackpot broadcast',
+ ariaMessage:
+ '{{nickname}} is on a {{streak}}-win streak and won {{amount}}',
+ iconAlt: 'Broadcast',
+ prefix: 'Jackpot hit',
+ separator: 'with',
+ streak: '{{count}}-win streak',
+ winAction: 'won',
+ },
actions: {
unifiedBetHint: 'Unified bet',
totalBet: 'Total bet',
@@ -532,6 +542,9 @@ export default {
tapToEnter: 'Tap To Enter',
getStart: 'Get Start',
noBet: 'No Bet',
+ noReward: 'No Win This Round',
+ selectedResult: 'Your Picks',
+ winningResult: 'Winning Flower',
},
history: {
title: 'History',
diff --git a/src/locales/id-ID.ts b/src/locales/id-ID.ts
index 445ff7c..f2b3c02 100644
--- a/src/locales/id-ID.ts
+++ b/src/locales/id-ID.ts
@@ -167,6 +167,16 @@ export default {
title: 'Ronde {{roundId}}',
action: 'Mulai Bertaruh',
},
+ jackpotBroadcast: {
+ ariaLabel: 'Siaran jackpot',
+ ariaMessage:
+ '{{nickname}} sedang streak {{streak}} menang dan memenangkan {{amount}}',
+ iconAlt: 'Siaran',
+ prefix: 'Jackpot kena',
+ separator: 'dengan',
+ streak: 'streak {{count}} menang',
+ winAction: 'memenangkan',
+ },
actions: {
unifiedBetHint: 'Bet seragam',
totalBet: 'Total bet',
@@ -532,6 +542,9 @@ export default {
tapToEnter: 'Ketuk Untuk Masuk',
getStart: 'Mulai',
noBet: 'Belum Bertaruh',
+ noReward: 'Belum Menang Ronde Ini',
+ selectedResult: 'Pilihan Kamu',
+ winningResult: 'Bunga Menang',
},
history: {
title: 'Riwayat',
diff --git a/src/locales/ms-MY.ts b/src/locales/ms-MY.ts
index 4747d00..c6cced3 100644
--- a/src/locales/ms-MY.ts
+++ b/src/locales/ms-MY.ts
@@ -170,6 +170,16 @@ export default {
title: 'Pusingan {{roundId}}',
action: 'Mula Bertaruh',
},
+ jackpotBroadcast: {
+ ariaLabel: 'Siaran jackpot',
+ ariaMessage:
+ '{{nickname}} sedang dalam streak {{streak}} menang dan memenangi {{amount}}',
+ iconAlt: 'Siaran',
+ prefix: 'Jackpot kena',
+ separator: 'dengan',
+ streak: 'streak {{count}} menang',
+ winAction: 'memenangi',
+ },
actions: {
unifiedBetHint: 'Taruhan seragam',
totalBet: 'Jumlah taruhan',
@@ -537,6 +547,9 @@ export default {
tapToEnter: 'Ketik Untuk Masuk',
getStart: 'Mula',
noBet: 'Belum Bertaruh',
+ noReward: 'Belum Menang Pusingan Ini',
+ selectedResult: 'Pilihan Anda',
+ winningResult: 'Bunga Menang',
},
history: {
title: 'Sejarah',
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index b3177a8..d17a313 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -166,6 +166,15 @@ export default {
title: '{{roundId}}期',
action: '开始下注',
},
+ jackpotBroadcast: {
+ ariaLabel: 'Jackpot 播报',
+ ariaMessage: '{{nickname}} 连胜 {{streak}} 次,赢得 {{amount}}',
+ iconAlt: '播报',
+ prefix: 'Jackpot 喜讯',
+ separator: '达成',
+ streak: '{{count}} 连胜',
+ winAction: '赢得',
+ },
actions: {
unifiedBetHint: '统一下注额',
totalBet: '总下注',
@@ -518,6 +527,9 @@ export default {
tapToEnter: '点击进入',
getStart: '开始游戏',
noBet: '未下注',
+ noReward: '本期未中奖',
+ selectedResult: '已下注字花',
+ winningResult: '中奖字花',
},
history: {
title: '历史记录',
diff --git a/src/main/mobile-entry.tsx b/src/main/mobile-entry.tsx
index 27e2cb3..f21b0f8 100644
--- a/src/main/mobile-entry.tsx
+++ b/src/main/mobile-entry.tsx
@@ -1,4 +1,4 @@
-import { MessageBroadcast } from '@/features/game/components/desktop/desktop-title.tsx'
+import { MessageBroadcast } from '@/components/message-broadcast.tsx'
import { MobileAnimal } from '@/features/game/components/mobile/mobile-animal.tsx'
import { MobileBettingStartAlert } from '@/features/game/components/mobile/mobile-betting-start-alert.tsx'
import { MobileControl } from '@/features/game/components/mobile/mobile-control.tsx'
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 5cd285c..ec7bbd6 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -12,7 +12,6 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as LangRouteRouteImport } from './routes/$lang/route'
import { Route as IndexRouteImport } from './routes/index'
import { Route as LangIndexRouteImport } from './routes/$lang/index'
-import { Route as LangWsTestRouteImport } from './routes/$lang/ws-test'
const LangRouteRoute = LangRouteRouteImport.update({
id: '/$lang',
@@ -29,36 +28,28 @@ const LangIndexRoute = LangIndexRouteImport.update({
path: '/',
getParentRoute: () => LangRouteRoute,
} as any)
-const LangWsTestRoute = LangWsTestRouteImport.update({
- id: '/ws-test',
- path: '/ws-test',
- getParentRoute: () => LangRouteRoute,
-} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/$lang': typeof LangRouteRouteWithChildren
- '/$lang/ws-test': typeof LangWsTestRoute
'/$lang/': typeof LangIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
- '/$lang/ws-test': typeof LangWsTestRoute
'/$lang': typeof LangIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/$lang': typeof LangRouteRouteWithChildren
- '/$lang/ws-test': typeof LangWsTestRoute
'/$lang/': typeof LangIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/$lang' | '/$lang/ws-test' | '/$lang/'
+ fullPaths: '/' | '/$lang' | '/$lang/'
fileRoutesByTo: FileRoutesByTo
- to: '/' | '/$lang/ws-test' | '/$lang'
- id: '__root__' | '/' | '/$lang' | '/$lang/ws-test' | '/$lang/'
+ to: '/' | '/$lang'
+ id: '__root__' | '/' | '/$lang' | '/$lang/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
@@ -89,23 +80,14 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof LangIndexRouteImport
parentRoute: typeof LangRouteRoute
}
- '/$lang/ws-test': {
- id: '/$lang/ws-test'
- path: '/ws-test'
- fullPath: '/$lang/ws-test'
- preLoaderRoute: typeof LangWsTestRouteImport
- parentRoute: typeof LangRouteRoute
- }
}
}
interface LangRouteRouteChildren {
- LangWsTestRoute: typeof LangWsTestRoute
LangIndexRoute: typeof LangIndexRoute
}
const LangRouteRouteChildren: LangRouteRouteChildren = {
- LangWsTestRoute: LangWsTestRoute,
LangIndexRoute: LangIndexRoute,
}
diff --git a/src/routes/$lang/ws-test.tsx b/src/routes/$lang/ws-test.tsx
deleted file mode 100644
index d454414..0000000
--- a/src/routes/$lang/ws-test.tsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import { createFileRoute } from '@tanstack/react-router'
-import { useEffect, useState } from 'react'
-
-const TEST_WS_URL =
- 'wss://zihua-api.h55555game.top/ws/?token=d77371f4-d053-475a-9c53-bfa11eb921c2&auth_token=708df54d-c647-46fc-b6ee-4339298d1ed4&device_id=web_0bc09c22-9157-4398-b4b3-57584ece9da9&lang=zh'
-
-const TEST_TOPICS = [
- 'period.tick',
- 'user.streak',
- 'period.opened',
- 'period.locked',
- 'period.payout',
- 'bet.accepted',
- 'wallet.changed',
- 'auto.spin.progress',
- 'admin.live.snapshot',
- 'admin.live.opened',
- 'jackpot.hit',
- 'bet.win',
-] as const
-
-type WsTestLog = {
- at: string
- id: string
- message: string
-}
-
-export const Route = createFileRoute('/$lang/ws-test')({
- component: WsTestPage,
-})
-
-function WsTestPage() {
- const [logs, setLogs] = useState
([])
- const [status, setStatus] = useState('idle')
-
- useEffect(() => {
- const appendLog = (message: string) => {
- setLogs((current) => [
- ...current,
- {
- at: new Date().toISOString(),
- id: crypto.randomUUID(),
- message,
- },
- ])
- }
-
- appendLog(`creating websocket: ${TEST_WS_URL}`)
- setStatus('connecting')
-
- const socket = new WebSocket(TEST_WS_URL)
-
- socket.addEventListener('open', () => {
- appendLog('open')
- socket.send(
- JSON.stringify({
- action: 'subscribe',
- topics: [...TEST_TOPICS],
- }),
- )
- appendLog(`subscribe: ${TEST_TOPICS.join(', ')}`)
- setStatus('open')
- })
-
- socket.addEventListener('message', (event) => {
- appendLog(`message: ${String(event.data)}`)
- })
-
- socket.addEventListener('error', () => {
- appendLog('error')
- setStatus('error')
- })
-
- socket.addEventListener('close', (event) => {
- appendLog(
- `close code=${event.code} reason=${event.reason || '(empty)'} wasClean=${event.wasClean}`,
- )
- setStatus('closed')
- })
-
- return () => {
- socket.close()
- }
- }, [])
-
- return (
-
- WS Test
-
-
-
URL
-
- {TEST_WS_URL}
-
-
-
-
Topics
-
- {TEST_TOPICS.join(', ')}
-
-
-
-
Logs
-
- {logs.length === 0 ? (
-
No logs yet
- ) : (
- logs.map((log) => (
-
- [{log.at}] {log.message}
-
- ))
- )}
-
-
-
- )
-}
diff --git a/src/type/game.type.ts b/src/type/game.type.ts
index 0e7401b..dee5c64 100644
--- a/src/type/game.type.ts
+++ b/src/type/game.type.ts
@@ -193,6 +193,7 @@ export interface AutoHostingStopRules {
}
export interface JackpotBroadcastItem {
+ currentStreak: number
id: string
nickname: string
periodNo: string
@@ -428,6 +429,7 @@ export interface GamePeriodTickDto {
}
export interface JackpotHitItemDto {
+ current_streak: number
nickname: string
period_no: string
result_number: number