feat: 优化整体项目ui
This commit is contained in:
@@ -31,6 +31,29 @@ type GameRoundSlice = Pick<
|
||||
| 'trends'
|
||||
>
|
||||
|
||||
export type RevealAnimationPhase = 'idle' | 'spinning' | 'stopping' | 'result'
|
||||
export type RewardAnimationType = 'none' | 'small' | 'big'
|
||||
|
||||
export interface RevealAnimationState {
|
||||
pendingRewardType: RewardAnimationType
|
||||
phase: RevealAnimationPhase
|
||||
revealKey: string | null
|
||||
rewardType: RewardAnimationType
|
||||
roundId: string | null
|
||||
winningCellId: number | null
|
||||
}
|
||||
|
||||
function createIdleRevealAnimation(): RevealAnimationState {
|
||||
return {
|
||||
pendingRewardType: 'none',
|
||||
phase: 'idle',
|
||||
revealKey: null,
|
||||
rewardType: 'none',
|
||||
roundId: null,
|
||||
winningCellId: null,
|
||||
}
|
||||
}
|
||||
|
||||
function resolveRecentActiveChipId(
|
||||
chips: Chip[],
|
||||
selections: BetSelection[],
|
||||
@@ -54,14 +77,25 @@ function resolveRecentActiveChipId(
|
||||
export interface GameRoundStoreState extends GameRoundSlice {
|
||||
activeChipId: string
|
||||
clearSelections: () => void
|
||||
clearRewardAnimation: () => void
|
||||
finishRevealAnimation: () => void
|
||||
hydrateRound: (snapshot: GameRoundSlice) => void
|
||||
placeBet: (cellId: number) => void
|
||||
playPreparedRevealAnimation: (roundId?: string | null) => void
|
||||
prepareRevealAnimation: (input: {
|
||||
hasSmallReward: boolean
|
||||
revealKey: string
|
||||
roundId: string
|
||||
winningCellId: number
|
||||
}) => void
|
||||
recentSuccessfulSelections: BetSelection[]
|
||||
revealAnimation: RevealAnimationState
|
||||
removeSelectionsForCell: (cellId: number) => void
|
||||
restoreRecentSuccessfulSelections: () => boolean
|
||||
setRecentSuccessfulSelections: (selections: BetSelection[]) => void
|
||||
selectChip: (chipId: string) => void
|
||||
setPhase: (phase: RoundPhase) => void
|
||||
showJackpotReward: (roundId?: string | null) => void
|
||||
syncRound: (round: Partial<RoundSnapshot>) => void
|
||||
upsertSelections: (selections: BetSelection[]) => void
|
||||
}
|
||||
@@ -69,6 +103,7 @@ export interface GameRoundStoreState extends GameRoundSlice {
|
||||
function createInitialRoundState(): GameRoundSlice & {
|
||||
activeChipId: string
|
||||
recentSuccessfulSelections: BetSelection[]
|
||||
revealAnimation: RevealAnimationState
|
||||
} {
|
||||
const snapshot = createEmptyGameBootstrapSnapshot()
|
||||
|
||||
@@ -79,6 +114,7 @@ function createInitialRoundState(): GameRoundSlice & {
|
||||
history: snapshot.history,
|
||||
maxSelectionCount: snapshot.maxSelectionCount,
|
||||
recentSuccessfulSelections: [],
|
||||
revealAnimation: createIdleRevealAnimation(),
|
||||
round: snapshot.round,
|
||||
selections: snapshot.selections,
|
||||
trends: snapshot.trends,
|
||||
@@ -90,6 +126,37 @@ export const useGameRoundStore = create<GameRoundStoreState>()((set) => ({
|
||||
clearSelections: () => {
|
||||
set({ selections: [] })
|
||||
},
|
||||
clearRewardAnimation: () => {
|
||||
set((state) => ({
|
||||
revealAnimation: {
|
||||
...state.revealAnimation,
|
||||
rewardType: 'none',
|
||||
},
|
||||
}))
|
||||
},
|
||||
finishRevealAnimation: () => {
|
||||
set((state) => {
|
||||
if (
|
||||
state.revealAnimation.phase !== 'stopping' &&
|
||||
state.revealAnimation.phase !== 'spinning'
|
||||
) {
|
||||
return state
|
||||
}
|
||||
|
||||
const rewardType =
|
||||
state.revealAnimation.rewardType === 'big'
|
||||
? 'big'
|
||||
: state.revealAnimation.pendingRewardType
|
||||
|
||||
return {
|
||||
revealAnimation: {
|
||||
...state.revealAnimation,
|
||||
phase: 'result',
|
||||
rewardType,
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
hydrateRound: (snapshot) => {
|
||||
set((state) => ({
|
||||
activeChipId: getChipById(snapshot.chips, state.activeChipId)
|
||||
@@ -101,6 +168,10 @@ export const useGameRoundStore = create<GameRoundStoreState>()((set) => ({
|
||||
chips: snapshot.chips,
|
||||
history: snapshot.history,
|
||||
maxSelectionCount: snapshot.maxSelectionCount,
|
||||
revealAnimation:
|
||||
snapshot.round.phase === 'betting' || snapshot.round.phase === 'waiting'
|
||||
? createIdleRevealAnimation()
|
||||
: state.revealAnimation,
|
||||
round: snapshot.round,
|
||||
selections: snapshot.selections,
|
||||
trends: snapshot.trends,
|
||||
@@ -143,6 +214,61 @@ export const useGameRoundStore = create<GameRoundStoreState>()((set) => ({
|
||||
}
|
||||
})
|
||||
},
|
||||
playPreparedRevealAnimation: (roundId) => {
|
||||
set((state) => {
|
||||
const nextRoundId = roundId ?? state.revealAnimation.roundId
|
||||
|
||||
if (
|
||||
state.revealAnimation.winningCellId === null ||
|
||||
state.revealAnimation.revealKey === null ||
|
||||
state.revealAnimation.phase !== 'idle'
|
||||
) {
|
||||
return state
|
||||
}
|
||||
|
||||
return {
|
||||
revealAnimation: {
|
||||
...state.revealAnimation,
|
||||
phase: 'stopping',
|
||||
roundId: nextRoundId,
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
prepareRevealAnimation: ({
|
||||
hasSmallReward,
|
||||
revealKey,
|
||||
roundId,
|
||||
winningCellId,
|
||||
}) => {
|
||||
set((state) => {
|
||||
if (state.revealAnimation.revealKey === revealKey) {
|
||||
return state
|
||||
}
|
||||
|
||||
const pendingRewardType =
|
||||
state.revealAnimation.pendingRewardType === 'big'
|
||||
? 'big'
|
||||
: hasSmallReward
|
||||
? 'small'
|
||||
: 'none'
|
||||
|
||||
return {
|
||||
revealAnimation: {
|
||||
...state.revealAnimation,
|
||||
pendingRewardType,
|
||||
phase: 'idle',
|
||||
revealKey,
|
||||
rewardType:
|
||||
state.revealAnimation.rewardType === 'big'
|
||||
? 'big'
|
||||
: state.revealAnimation.rewardType,
|
||||
roundId,
|
||||
winningCellId,
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
recentSuccessfulSelections: [],
|
||||
removeSelectionsForCell: (cellId) => {
|
||||
set((state) => ({
|
||||
@@ -215,13 +341,38 @@ export const useGameRoundStore = create<GameRoundStoreState>()((set) => ({
|
||||
nextState.selections = []
|
||||
}
|
||||
|
||||
if (phase === 'locked' || phase === 'revealing') {
|
||||
nextState.selections = []
|
||||
}
|
||||
|
||||
if (phase === 'betting' || phase === 'waiting') {
|
||||
nextState.revealAnimation = createIdleRevealAnimation()
|
||||
}
|
||||
|
||||
return nextState
|
||||
})
|
||||
},
|
||||
showJackpotReward: (roundId) => {
|
||||
set((state) => {
|
||||
const nextRoundId =
|
||||
roundId ?? state.round.id ?? state.revealAnimation.roundId
|
||||
const isResultReady = state.revealAnimation.phase === 'result'
|
||||
|
||||
return {
|
||||
revealAnimation: {
|
||||
...state.revealAnimation,
|
||||
pendingRewardType: 'big',
|
||||
rewardType: isResultReady ? 'big' : state.revealAnimation.rewardType,
|
||||
roundId: nextRoundId,
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
syncRound: (round) => {
|
||||
set((state) => {
|
||||
const previousRound = state.round
|
||||
const nextRound = {
|
||||
...state.round,
|
||||
...previousRound,
|
||||
...round,
|
||||
}
|
||||
|
||||
@@ -233,6 +384,17 @@ export const useGameRoundStore = create<GameRoundStoreState>()((set) => ({
|
||||
nextState.selections = []
|
||||
}
|
||||
|
||||
if (nextRound.phase === 'locked' || nextRound.phase === 'revealing') {
|
||||
nextState.selections = []
|
||||
}
|
||||
|
||||
if (
|
||||
nextRound.id !== previousRound.id &&
|
||||
(nextRound.phase === 'betting' || nextRound.phase === 'waiting')
|
||||
) {
|
||||
nextState.revealAnimation = createIdleRevealAnimation()
|
||||
}
|
||||
|
||||
return nextState
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,43 +1,13 @@
|
||||
import { create } from 'zustand'
|
||||
import { INITIAL_MODAL_VISIBILITY, MODAL_KEYS } from '@/constants'
|
||||
import type { WithdrawTopupType } from '@/type'
|
||||
|
||||
export const MODAL_KEYS = [
|
||||
/**@description 桌面端登录弹窗*/
|
||||
'desktopLogin',
|
||||
/**@description 桌面端注册弹窗*/
|
||||
'desktopRegister',
|
||||
/**@description 桌面端多语言弹窗*/
|
||||
'desktopLanguage',
|
||||
/**@description 桌面端规则弹窗*/
|
||||
'desktopRules',
|
||||
/**@description 桌面端用户信息弹窗*/
|
||||
'desktopUserInfo',
|
||||
/**@description 桌面端公告弹窗*/
|
||||
'desktopNotice',
|
||||
/**@description 桌面端自动托管弹窗*/
|
||||
'desktopAutoSetting',
|
||||
/**@description 桌面端充值提现前置选择弹窗*/
|
||||
'desktopProcedures',
|
||||
/**@description 桌面端充值/提现弹窗*/
|
||||
'desktopWithdrawTopup',
|
||||
] as const
|
||||
export { MODAL_KEYS }
|
||||
|
||||
export type ModalKey = (typeof MODAL_KEYS)[number]
|
||||
|
||||
type ModalVisibilityMap = Record<ModalKey, boolean>
|
||||
|
||||
const INITIAL_MODAL_VISIBILITY: ModalVisibilityMap = {
|
||||
desktopLogin: false,
|
||||
desktopRegister: false,
|
||||
desktopLanguage: false,
|
||||
desktopRules: false,
|
||||
desktopUserInfo: false,
|
||||
desktopNotice: false,
|
||||
desktopAutoSetting: false,
|
||||
desktopProcedures: false,
|
||||
desktopWithdrawTopup: false,
|
||||
}
|
||||
|
||||
export interface ModalStoreState {
|
||||
modals: ModalVisibilityMap
|
||||
withdrawTopupType: WithdrawTopupType
|
||||
|
||||
Reference in New Issue
Block a user