@enigma-lake/tower-play-controller-sdk 2.2.4 → 2.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/base/DifficultySelector/DifficultySelector.d.ts +6 -2
- package/dist/components/base/DifficultySelector/Selector.d.ts +1 -1
- package/dist/components/base/DifficultySelector/types.d.ts +0 -2
- package/dist/components/base/FreeRoundsAffordance/FreeRoundsAffordance.d.ts +10 -0
- package/dist/components/base/FreeRoundsAffordance/index.d.ts +2 -0
- package/dist/components/base/FreeRoundsIntroModal/FreeRoundsIntroModal.d.ts +2 -3
- package/dist/components/hooks/usePlayController.d.ts +2 -0
- package/dist/index.d.ts +18 -84
- package/dist/index.mjs +211 -492
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/playController.d.ts +14 -16
- package/package.json +1 -1
- package/dist/components/base/FreeRoundsIntroModal/freeRoundsCoin.d.ts +0 -11
- package/dist/components/base/FreeRoundsSummaryModal/FreeRoundsSummaryModal.d.ts +0 -9
- package/dist/components/base/FreeRoundsSummaryModal/index.d.ts +0 -3
- package/dist/i18n/I18nContext.d.ts +0 -13
- package/dist/i18n/index.d.ts +0 -5
- package/dist/i18n/locales/en.d.ts +0 -2
- package/dist/i18n/locales/zh-CN.d.ts +0 -2
- package/dist/i18n/translator.d.ts +0 -5
- package/dist/i18n/types.d.ts +0 -41
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import React, { createContext, useContext,
|
|
2
|
+
import React, { createContext, useContext, useRef, useEffect, useCallback, useState, useMemo, Fragment as Fragment$1 } from 'react';
|
|
3
3
|
import cx$1 from 'classnames';
|
|
4
|
-
import {
|
|
5
|
-
export { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES, SUPPORTED_LANGUAGE_CODES, resolveLanguage } from '@enigma-lake/zoot-platform-sdk';
|
|
4
|
+
import { Currency, sendSetUserCurrencyEvent, sendSetUserCurrencyEventV2, setToggleGameWidgetsVisibility, setToggleGameWidgetsExpansion, getUserInformationEvent, EVENTS, sendOpenHighPlayModalEvent } from '@enigma-lake/zoot-platform-sdk';
|
|
6
5
|
import { Menu, MenuButton, MenuItems, MenuItem, Switch as Switch$1, Dialog, DialogPanel, DialogTitle } from '@headlessui/react';
|
|
7
6
|
|
|
8
7
|
const hexToRgb = (hex) => {
|
|
@@ -103,23 +102,6 @@ const createAutoplayButtonAction = ({ state, cashoutDisabled, onStopPlay, onPlay
|
|
|
103
102
|
};
|
|
104
103
|
};
|
|
105
104
|
|
|
106
|
-
var SELECTORS;
|
|
107
|
-
(function (SELECTORS) {
|
|
108
|
-
SELECTORS["RISK"] = "Risk";
|
|
109
|
-
})(SELECTORS || (SELECTORS = {}));
|
|
110
|
-
var RiskTypes;
|
|
111
|
-
(function (RiskTypes) {
|
|
112
|
-
RiskTypes["LOW"] = "LOW";
|
|
113
|
-
RiskTypes["MEDIUM"] = "MEDIUM";
|
|
114
|
-
RiskTypes["HIGH"] = "HIGH";
|
|
115
|
-
})(RiskTypes || (RiskTypes = {}));
|
|
116
|
-
// standard controller palette (matches multi/plinko play-controller SDKs)
|
|
117
|
-
const DEFAULT_RISK_COLORS = {
|
|
118
|
-
[RiskTypes.LOW]: "#1AE380",
|
|
119
|
-
[RiskTypes.MEDIUM]: "#FFC058",
|
|
120
|
-
[RiskTypes.HIGH]: "#FF5646",
|
|
121
|
-
};
|
|
122
|
-
|
|
123
105
|
const AutoManualPlayStateContext = createContext(undefined);
|
|
124
106
|
const useAutoManualPlayState = () => {
|
|
125
107
|
const context = useContext(AutoManualPlayStateContext);
|
|
@@ -129,104 +111,6 @@ const useAutoManualPlayState = () => {
|
|
|
129
111
|
return context;
|
|
130
112
|
};
|
|
131
113
|
|
|
132
|
-
const en = {
|
|
133
|
-
playNow: "PLAY NOW",
|
|
134
|
-
playFreeRound: "PLAY FREE ROUND",
|
|
135
|
-
selectPlayAmount: "SELECT PLAY AMOUNT",
|
|
136
|
-
cashout: "CASHOUT",
|
|
137
|
-
collect: "COLLECT",
|
|
138
|
-
doubleTitle: "DOUBLE",
|
|
139
|
-
doubleSubtitle: "OR NOTHING",
|
|
140
|
-
startAutoplay: "START AUTOPLAY",
|
|
141
|
-
stopAutoplay: "STOP AUTOPLAY",
|
|
142
|
-
numberOfPlays: "Number of Plays",
|
|
143
|
-
selectPlayAmountAria: "Select play amount",
|
|
144
|
-
playAmountLabel: "Play amount",
|
|
145
|
-
autoLabel: "Auto",
|
|
146
|
-
selectTileToast: "Please select at least one tile to start autoplay.",
|
|
147
|
-
riskLabel: "Risk",
|
|
148
|
-
riskLow: "Low",
|
|
149
|
-
riskMedium: "Medium",
|
|
150
|
-
riskHigh: "High",
|
|
151
|
-
freeRoundLeftOne: "FREE ROUND LEFT",
|
|
152
|
-
freeRoundLeftOther: "FREE ROUNDS LEFT",
|
|
153
|
-
freeRoundsModalTitle: "Free Game Rounds",
|
|
154
|
-
freeRoundsHave: "You have",
|
|
155
|
-
freeRoundsUnitOne: "FREE GAME ROUND",
|
|
156
|
-
freeRoundsUnitOther: "FREE GAME ROUNDS",
|
|
157
|
-
freeRoundsPerRound: "{amount} per round",
|
|
158
|
-
freeRoundsExpiresIn: "Expires in {days} {unit}",
|
|
159
|
-
dayUnitOne: "day",
|
|
160
|
-
dayUnitOther: "days",
|
|
161
|
-
freeRoundsModalPlayNow: "Play now",
|
|
162
|
-
freeRoundsModalPlayLater: "Maybe later",
|
|
163
|
-
freeRoundsSummaryWon: "You won",
|
|
164
|
-
freeRoundsSummaryIn: "in",
|
|
165
|
-
freeRoundsSummaryUnitOne: "free game round",
|
|
166
|
-
freeRoundsSummaryUnitOther: "free game rounds",
|
|
167
|
-
freeRoundsSummaryCredited: "Winnings have been credited to your bonus balance.",
|
|
168
|
-
freeRoundsSummaryClose: "Close",
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const zhCN = {
|
|
172
|
-
playNow: "立即游戏",
|
|
173
|
-
playFreeRound: "免费游戏",
|
|
174
|
-
selectPlayAmount: "选择下注金额",
|
|
175
|
-
cashout: "提现",
|
|
176
|
-
collect: "收取",
|
|
177
|
-
doubleTitle: "双倍",
|
|
178
|
-
doubleSubtitle: "或全无",
|
|
179
|
-
startAutoplay: "开始自动游戏",
|
|
180
|
-
stopAutoplay: "停止自动游戏",
|
|
181
|
-
numberOfPlays: "游戏次数",
|
|
182
|
-
selectPlayAmountAria: "选择下注金额",
|
|
183
|
-
playAmountLabel: "下注金额",
|
|
184
|
-
autoLabel: "自动",
|
|
185
|
-
selectTileToast: "请至少选择一个方块以开始自动游戏。",
|
|
186
|
-
riskLabel: "风险",
|
|
187
|
-
riskLow: "低",
|
|
188
|
-
riskMedium: "中",
|
|
189
|
-
riskHigh: "高",
|
|
190
|
-
freeRoundLeftOne: "剩余免费回合",
|
|
191
|
-
freeRoundLeftOther: "剩余免费回合",
|
|
192
|
-
freeRoundsModalTitle: "免费游戏回合",
|
|
193
|
-
freeRoundsHave: "您有",
|
|
194
|
-
freeRoundsUnitOne: "个免费游戏回合",
|
|
195
|
-
freeRoundsUnitOther: "个免费游戏回合",
|
|
196
|
-
freeRoundsPerRound: "每回合 {amount}",
|
|
197
|
-
freeRoundsExpiresIn: "{days} {unit}后到期",
|
|
198
|
-
dayUnitOne: "天",
|
|
199
|
-
dayUnitOther: "天",
|
|
200
|
-
freeRoundsModalPlayNow: "立即游戏",
|
|
201
|
-
freeRoundsModalPlayLater: "稍后再玩",
|
|
202
|
-
freeRoundsSummaryWon: "您赢得了",
|
|
203
|
-
freeRoundsSummaryIn: ",共",
|
|
204
|
-
freeRoundsSummaryUnitOne: "个免费游戏回合",
|
|
205
|
-
freeRoundsSummaryUnitOther: "个免费游戏回合",
|
|
206
|
-
freeRoundsSummaryCredited: "奖金已存入您的奖金余额。",
|
|
207
|
-
freeRoundsSummaryClose: "关闭",
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const dictionaries = {
|
|
211
|
-
en,
|
|
212
|
-
"zh-CN": zhCN,
|
|
213
|
-
};
|
|
214
|
-
const createTranslator = (language) => createTranslator$1(dictionaries, language);
|
|
215
|
-
|
|
216
|
-
const I18nContext = createContext(undefined);
|
|
217
|
-
const I18nProvider = ({ language, children, }) => {
|
|
218
|
-
const value = useMemo(() => {
|
|
219
|
-
const resolved = resolveLanguage(language);
|
|
220
|
-
return { language: resolved, t: createTranslator(resolved) };
|
|
221
|
-
}, [language]);
|
|
222
|
-
return jsx(I18nContext.Provider, { value: value, children: children });
|
|
223
|
-
};
|
|
224
|
-
const DEFAULT_VALUE = {
|
|
225
|
-
language: DEFAULT_LANGUAGE,
|
|
226
|
-
t: createTranslator(DEFAULT_LANGUAGE),
|
|
227
|
-
};
|
|
228
|
-
const useTranslation = () => useContext(I18nContext) ?? DEFAULT_VALUE;
|
|
229
|
-
|
|
230
114
|
const getNextPlayAmount = ({ currentAmount, defaultBetOptions, direction, }) => {
|
|
231
115
|
if (!defaultBetOptions.length) {
|
|
232
116
|
return currentAmount;
|
|
@@ -257,7 +141,6 @@ function isFullMode(config) {
|
|
|
257
141
|
return config.withoutRiskAndAutoplay !== true;
|
|
258
142
|
}
|
|
259
143
|
const usePlayController = () => {
|
|
260
|
-
const { t } = useTranslation();
|
|
261
144
|
const { config, mode, autoPlay: { setNumberOfPlays, numberOfPlays, setPlayedRounds, playedRounds, selection, setState, state, }, playValues: { displayPlayAmountView, setDisplayPlayAmountView, togglePlayAmountView, }, } = useAutoManualPlayState();
|
|
262
145
|
const { current } = config.currencyOptions;
|
|
263
146
|
const { isPlaying, canCashout, disabledCashout = false, disabledController, playHook, totalBalance, } = config.playOptions;
|
|
@@ -272,19 +155,17 @@ const usePlayController = () => {
|
|
|
272
155
|
const { playAmount: rawPlayAmount = 0, playLimits, setPlayAmount: rawSetPlayAmount = () => { }, } = playHook?.() ?? {};
|
|
273
156
|
const minPlayAmount = playLimits?.[current.code]?.limits.min ?? 0;
|
|
274
157
|
const maxPlayAmount = playLimits?.[current.code]?.limits.max ?? 0;
|
|
275
|
-
// Free rounds (opt-in): only when the player has ENGAGED
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
// By default engagement is MANUAL-mode only (free rounds are never engaged
|
|
281
|
-
// in auto-play mode). Games whose autoplay submission path funds rounds
|
|
282
|
-
// from engaged grants opt into engaged autoplay via
|
|
283
|
-
// `supportsGrantFundedAutoplay`, which drops the manual-mode requirement.
|
|
158
|
+
// Free rounds (opt-in, MANUAL-mode only): only when the player has ENGAGED
|
|
159
|
+
// free-round mode are the stake/coin locked to the grant. `available` (pending
|
|
160
|
+
// grants exist) does not lock anything on its own — it surfaces a "Use Free
|
|
161
|
+
// Rounds" affordance. Free rounds are never available/engaged in auto-play
|
|
162
|
+
// mode, and engagement coexists with the cashout flow.
|
|
284
163
|
const isManualMode = mode === GAME_MODE.MANUAL;
|
|
285
164
|
const freeRoundsOptions = config.freeRoundsOptions;
|
|
286
|
-
const
|
|
287
|
-
|
|
165
|
+
const isFreeRoundsAvailable = Boolean(isManualMode &&
|
|
166
|
+
freeRoundsOptions?.available &&
|
|
167
|
+
freeRoundsOptions.roundsRemaining > 0);
|
|
168
|
+
const isFreeRoundsEngaged = Boolean(isManualMode &&
|
|
288
169
|
freeRoundsOptions?.engaged &&
|
|
289
170
|
freeRoundsOptions.roundsRemaining > 0);
|
|
290
171
|
// playAmount is in display units everywhere in this SDK (e.g. 1.00), while the
|
|
@@ -301,33 +182,6 @@ const usePlayController = () => {
|
|
|
301
182
|
: rawSetPlayAmount;
|
|
302
183
|
const playIntervalRef = useRef(null);
|
|
303
184
|
const isAutoplayActiveRef = useRef(false);
|
|
304
|
-
// Each setTimeout tick invokes the `loopRounds` closure from the render that
|
|
305
|
-
// scheduled it, so reading `config.freeRoundsOptions` there can see a stale,
|
|
306
|
-
// pre-engagement value. Keep the latest free-rounds state in a ref
|
|
307
|
-
// (refreshed every render) so the loop's hard-stop checks always see live
|
|
308
|
-
// values — a grant engaged mid-loop still hard-stops paid autoplay, and an
|
|
309
|
-
// engaged grant-funded loop sees the live remaining count.
|
|
310
|
-
const freeRoundsLiveRef = useRef({
|
|
311
|
-
engaged: false,
|
|
312
|
-
remaining: 0,
|
|
313
|
-
supportsGrantFundedAutoplay: false,
|
|
314
|
-
});
|
|
315
|
-
freeRoundsLiveRef.current = {
|
|
316
|
-
engaged: Boolean(config.freeRoundsOptions?.engaged),
|
|
317
|
-
remaining: config.freeRoundsOptions?.roundsRemaining ?? 0,
|
|
318
|
-
supportsGrantFundedAutoplay,
|
|
319
|
-
};
|
|
320
|
-
// Per-session accounting for engaged (grant-funded) autoplay.
|
|
321
|
-
// roundsRemaining is game-driven and only decrements via an async refetch
|
|
322
|
-
// AFTER each settlement, so the live ref can still read stale-high when the
|
|
323
|
-
// loop schedules the next round. We therefore also count submissions
|
|
324
|
-
// locally: a session that started engaged may never submit more rounds than
|
|
325
|
-
// the grants available when it started, regardless of refetch timing.
|
|
326
|
-
const autoplaySessionRef = useRef({
|
|
327
|
-
startedEngaged: false,
|
|
328
|
-
grantsAtStart: 0,
|
|
329
|
-
roundsSubmitted: 0,
|
|
330
|
-
});
|
|
331
185
|
const stopAutoplay = () => {
|
|
332
186
|
isAutoplayActiveRef.current = false;
|
|
333
187
|
if (playIntervalRef.current) {
|
|
@@ -347,35 +201,6 @@ const usePlayController = () => {
|
|
|
347
201
|
if (!isAutoplayActiveRef.current || !autoplayEnabled) {
|
|
348
202
|
return;
|
|
349
203
|
}
|
|
350
|
-
// Free-rounds gates — all live values come from refs (closures here are
|
|
351
|
-
// stale across rounds).
|
|
352
|
-
const live = freeRoundsLiveRef.current;
|
|
353
|
-
const session = autoplaySessionRef.current;
|
|
354
|
-
if (!live.supportsGrantFundedAutoplay) {
|
|
355
|
-
// Legacy (flag absent/false): tower free rounds are MANUAL-only — there
|
|
356
|
-
// is no free autoplay. If a grant is engaged (or becomes engaged) while
|
|
357
|
-
// an autoplay loop is live, hard-stop instead of letting PAID autoplay
|
|
358
|
-
// run alongside the grant.
|
|
359
|
-
if (live.engaged) {
|
|
360
|
-
stopAutoplay();
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else if (session.startedEngaged) {
|
|
365
|
-
// Grant-funded autoplay: an autoplay session that started on free
|
|
366
|
-
// rounds ends the moment the grants are exhausted or engagement ends
|
|
367
|
-
// mid-session — it must never submit a paid round. Checked BEFORE each
|
|
368
|
-
// submission so the round that consumes the last grant completes
|
|
369
|
-
// normally, then the loop halts via the normal stop path. Uses the
|
|
370
|
-
// local per-session submission count as well because the game's
|
|
371
|
-
// roundsRemaining refetch can lag behind the next scheduled round.
|
|
372
|
-
const grantsExhausted = session.roundsSubmitted >= session.grantsAtStart || live.remaining <= 0;
|
|
373
|
-
if (grantsExhausted || !live.engaged) {
|
|
374
|
-
setNumberOfPlays(AUTOPLAY_DEFAULT_PLAY_ROUNDS_COUNT);
|
|
375
|
-
stopAutoplay();
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
204
|
if (remainingPlays < 1 || numberOfPlays === 0) {
|
|
380
205
|
setNumberOfPlays(AUTOPLAY_DEFAULT_PLAY_ROUNDS_COUNT);
|
|
381
206
|
stopAutoplay();
|
|
@@ -383,7 +208,6 @@ const usePlayController = () => {
|
|
|
383
208
|
}
|
|
384
209
|
setPlayedRounds(currentPlayedRounds + 1);
|
|
385
210
|
setNumberOfPlays((prev) => Math.max(prev - 1, 0));
|
|
386
|
-
session.roundsSubmitted += 1;
|
|
387
211
|
// onAutoPlay exists only in full mode (guarded by autoplayEnabled)
|
|
388
212
|
config.onAutoPlay(selection, () => {
|
|
389
213
|
if (!isAutoplayActiveRef.current) {
|
|
@@ -401,32 +225,13 @@ const usePlayController = () => {
|
|
|
401
225
|
if (selection.length === 0) {
|
|
402
226
|
showAutoPlayToast?.({
|
|
403
227
|
type: "info",
|
|
404
|
-
message:
|
|
228
|
+
message: "Please select at least one tile to start autoplay.",
|
|
405
229
|
});
|
|
406
230
|
return;
|
|
407
231
|
}
|
|
408
|
-
// Grant-funded autoplay: the effective play count is clamped to the
|
|
409
|
-
// remaining grants so autoplay can never spill into paid rounds (and an
|
|
410
|
-
// infinite/over-cap count stops at roundsRemaining). The game client
|
|
411
|
-
// enforces actual per-round grant consumption; this is the UI cap.
|
|
412
|
-
const effectiveNumberOfPlays = supportsGrantFundedAutoplay && isFreeRoundsEngaged
|
|
413
|
-
? Math.min(numberOfPlays, freeRoundsOptions?.roundsRemaining ?? 0)
|
|
414
|
-
: numberOfPlays;
|
|
415
|
-
if (effectiveNumberOfPlays !== numberOfPlays) {
|
|
416
|
-
setNumberOfPlays(effectiveNumberOfPlays);
|
|
417
|
-
}
|
|
418
|
-
// Snapshot the free-rounds state for this session. Uses the RAW engaged
|
|
419
|
-
// flag (not isFreeRoundsEngaged, which also requires remaining > 0) so a
|
|
420
|
-
// session started while engaged with 0 grants fails closed on the first
|
|
421
|
-
// loop iteration instead of silently becoming a paid session.
|
|
422
|
-
autoplaySessionRef.current = {
|
|
423
|
-
startedEngaged: Boolean(freeRoundsOptions?.engaged),
|
|
424
|
-
grantsAtStart: freeRoundsOptions?.roundsRemaining ?? 0,
|
|
425
|
-
roundsSubmitted: 0,
|
|
426
|
-
};
|
|
427
232
|
isAutoplayActiveRef.current = true;
|
|
428
233
|
setState(AUTO_PLAY_STATE.PLAYING);
|
|
429
|
-
loopRounds(playedRounds,
|
|
234
|
+
loopRounds(playedRounds, numberOfPlays);
|
|
430
235
|
};
|
|
431
236
|
const adjustPlayAmount = ({ direction }) => {
|
|
432
237
|
if (isDisabled()) {
|
|
@@ -484,15 +289,16 @@ const usePlayController = () => {
|
|
|
484
289
|
setDisplayPlayAmountView,
|
|
485
290
|
togglePlayAmountView,
|
|
486
291
|
},
|
|
487
|
-
// free rounds (
|
|
488
|
-
// unless the game opts into grant-funded autoplay)
|
|
292
|
+
// free rounds (manual-mode only)
|
|
489
293
|
freeRounds: {
|
|
294
|
+
isAvailable: isFreeRoundsAvailable,
|
|
490
295
|
isEngaged: isFreeRoundsEngaged,
|
|
491
296
|
roundsRemaining: freeRoundsOptions?.roundsRemaining ?? 0,
|
|
492
297
|
totalRounds: freeRoundsOptions?.totalRounds ?? 0,
|
|
493
298
|
stakeCents: freeRoundsOptions?.stakeCents ?? 0,
|
|
494
299
|
coinType: freeRoundsOptions?.coinType,
|
|
495
300
|
currency: freeRoundsOptions?.currency,
|
|
301
|
+
onUseFreeRounds: freeRoundsOptions?.onUseFreeRounds,
|
|
496
302
|
},
|
|
497
303
|
};
|
|
498
304
|
};
|
|
@@ -586,117 +392,42 @@ const SelectMenu = ({ disabled = false }) => {
|
|
|
586
392
|
}) })] })) }));
|
|
587
393
|
};
|
|
588
394
|
|
|
589
|
-
var styles$
|
|
395
|
+
var styles$5 = {"base":"PlayValueInput-module__base___sTNW2","icon":"PlayValueInput-module__icon___jZj7O","playValueInput":"PlayValueInput-module__playValueInput___7pJtn","playValueInputWithLabel":"PlayValueInput-module__playValueInputWithLabel___S55Cr","label":"PlayValueInput-module__label___1ZSAV","inputContainer":"PlayValueInput-module__inputContainer___RKr1l","playValueWithLabel":"PlayValueInput-module__playValueWithLabel___K4-pr","isClassicGame":"PlayValueInput-module__isClassicGame___lQzVE"};
|
|
590
396
|
|
|
591
397
|
const PlayValueInput = ({ disabled, children, className, value, onClick, isClassicGame = false, }) => {
|
|
592
|
-
const { t } = useTranslation();
|
|
593
398
|
const handleOnClick = () => {
|
|
594
399
|
if (disabled) {
|
|
595
400
|
return;
|
|
596
401
|
}
|
|
597
402
|
onClick();
|
|
598
403
|
};
|
|
599
|
-
return (jsxs("div", { className: cx$1(styles$
|
|
600
|
-
[styles$
|
|
601
|
-
[styles$
|
|
602
|
-
}), children: [children && jsx("div", { className: cx$1(styles$
|
|
404
|
+
return (jsxs("div", { className: cx$1(styles$5.base, className, {
|
|
405
|
+
[styles$5.disabled]: disabled,
|
|
406
|
+
[styles$5.isClassicGame]: isClassicGame,
|
|
407
|
+
}), children: [children && jsx("div", { className: cx$1(styles$5.icon), children: children }), jsxs("div", { className: cx$1(styles$5.inputContainer), onClick: (e) => {
|
|
603
408
|
e.preventDefault();
|
|
604
409
|
handleOnClick();
|
|
605
|
-
}, children: [jsx("span", { className: styles$
|
|
606
|
-
[styles$
|
|
410
|
+
}, children: [jsx("span", { className: styles$5.label, children: "Play amount" }), jsx("div", { className: cx$1(styles$5.playValueInput, {
|
|
411
|
+
[styles$5.playValueInputWithLabel]: true,
|
|
607
412
|
}), children: value })] })] }));
|
|
608
413
|
};
|
|
609
414
|
|
|
610
|
-
const COIN_TYPE_SWEEPS = 0;
|
|
611
|
-
const COIN_TYPE_GOLD = 1;
|
|
612
|
-
// B2C coin decimals (platform convention): Sweeps shows 2 dp, Gold 0 dp.
|
|
613
|
-
const COIN_DECIMALS = {
|
|
614
|
-
[COIN_TYPE_SWEEPS]: 2,
|
|
615
|
-
[COIN_TYPE_GOLD]: 0,
|
|
616
|
-
};
|
|
617
|
-
const resolveFreeRoundsCoinLabel = ({ coinType, currency, }) => {
|
|
618
|
-
if (currency) {
|
|
619
|
-
return currency;
|
|
620
|
-
}
|
|
621
|
-
if (coinType === COIN_TYPE_SWEEPS) {
|
|
622
|
-
return "SC";
|
|
623
|
-
}
|
|
624
|
-
if (coinType === COIN_TYPE_GOLD) {
|
|
625
|
-
return "GC";
|
|
626
|
-
}
|
|
627
|
-
return "";
|
|
628
|
-
};
|
|
629
|
-
// The per-round value belongs to the GRANT's coin, which can differ from the
|
|
630
|
-
// player's active currency (e.g. a Sweeps grant surfaced while the player is
|
|
631
|
-
// on Gold). Use the grant coin's decimals so a 0.20 SC value doesn't render as
|
|
632
|
-
// "0" under Gold's 0-dp formatting. B2B grants (operator `currency`) fall back
|
|
633
|
-
// to the operator currency decimals passed in via `fallback`.
|
|
634
|
-
const resolveFreeRoundsDecimals = ({ coinType, currency, fallback, }) => {
|
|
635
|
-
if (!currency && coinType !== undefined && coinType in COIN_DECIMALS) {
|
|
636
|
-
return COIN_DECIMALS[coinType];
|
|
637
|
-
}
|
|
638
|
-
return fallback;
|
|
639
|
-
};
|
|
640
|
-
// Resolves display decimals from a coin/currency LABEL (cross-SDK standard):
|
|
641
|
-
// SC/SWEEPS = 2, GC/GOLD = 0, B2B operator currency strings = 2.
|
|
642
|
-
const resolveCoinLabelDecimals = (coin) => {
|
|
643
|
-
const normalized = coin.trim().toUpperCase();
|
|
644
|
-
if (normalized === "GC" || normalized === "GOLD") {
|
|
645
|
-
return 0;
|
|
646
|
-
}
|
|
647
|
-
return 2;
|
|
648
|
-
};
|
|
649
|
-
const MS_PER_DAY = 86_400_000;
|
|
650
|
-
// Computes the whole-day countdown for "*Expires in {N} days". Rounds UP so a
|
|
651
|
-
// grant expiring in 36 hours reads "2 days" (it is still claimable on day 2).
|
|
652
|
-
// Returns null when the input is missing/invalid or already expired.
|
|
653
|
-
const computeExpiresInDays = (expiresAt, now = Date.now()) => {
|
|
654
|
-
if (expiresAt === null || expiresAt === undefined) {
|
|
655
|
-
return null;
|
|
656
|
-
}
|
|
657
|
-
const expiryMs = new Date(expiresAt).getTime();
|
|
658
|
-
if (Number.isNaN(expiryMs)) {
|
|
659
|
-
return null;
|
|
660
|
-
}
|
|
661
|
-
const remainingMs = expiryMs - now;
|
|
662
|
-
if (remainingMs <= 0) {
|
|
663
|
-
return null;
|
|
664
|
-
}
|
|
665
|
-
return Math.ceil(remainingMs / MS_PER_DAY);
|
|
666
|
-
};
|
|
667
|
-
|
|
668
415
|
const PlayAmountControl = ({ isDisabled, forceRefresh, lockCurrency = false, }) => {
|
|
669
416
|
const { config } = useAutoManualPlayState();
|
|
670
|
-
const { playAmount, adjustPlayAmount, playValues: { togglePlayAmountView }, autoPlay: { state },
|
|
417
|
+
const { playAmount, adjustPlayAmount, playValues: { togglePlayAmountView }, autoPlay: { state }, } = usePlayController();
|
|
671
418
|
const isClassicGame = Boolean(config.isClassicGame || config.classicGame?.forceLeftStyle);
|
|
672
|
-
// While a free-rounds grant is engaged, the input is locked to the GRANT's
|
|
673
|
-
// per-round value and coin (which can differ from the active currency), so
|
|
674
|
-
// the locked amount is always truthful.
|
|
675
|
-
const { current } = config.currencyOptions;
|
|
676
|
-
const grantCoinLabel = resolveFreeRoundsCoinLabel({
|
|
677
|
-
coinType: freeRounds.coinType,
|
|
678
|
-
currency: freeRounds.currency,
|
|
679
|
-
});
|
|
680
|
-
const valueDecimals = freeRounds.isEngaged
|
|
681
|
-
? resolveFreeRoundsDecimals({
|
|
682
|
-
coinType: freeRounds.coinType,
|
|
683
|
-
currency: freeRounds.currency,
|
|
684
|
-
fallback: current.decimals,
|
|
685
|
-
})
|
|
686
|
-
: current.decimals;
|
|
687
|
-
const coinLabel = freeRounds.isEngaged && grantCoinLabel ? grantCoinLabel : current.abbr;
|
|
688
419
|
const handleTogglePlayAmount = () => {
|
|
689
420
|
setToggleGameWidgetsVisibility();
|
|
690
421
|
togglePlayAmountView();
|
|
691
422
|
setToggleGameWidgetsExpansion();
|
|
692
423
|
};
|
|
693
|
-
return (jsxs(GroupRow, { isClassicGame: isClassicGame, children: [jsx(PlayValueInput, { className: styles_group.groupItem, value: `${format(playAmount,
|
|
424
|
+
return (jsxs(GroupRow, { isClassicGame: isClassicGame, children: [jsx(PlayValueInput, { className: styles_group.groupItem, value: `${format(playAmount, config.currencyOptions.current.decimals)} ${config.currencyOptions.current.abbr}`, disabled: isDisabled() ||
|
|
694
425
|
config.playOptions.disableInput ||
|
|
695
426
|
config.playOptions.disabledController ||
|
|
696
427
|
state === AUTO_PLAY_STATE.PLAYING ||
|
|
697
|
-
lockCurrency, onClick: handleTogglePlayAmount, isClassicGame: isClassicGame, children: jsx(SelectMenu, { disabled: isDisabled() || lockCurrency }) }), jsx(Button, { className: styles_group.groupItem, onClick: () => adjustPlayAmount({ direction: -1 }), theme: "ghost", disabled: isDisabled()
|
|
428
|
+
lockCurrency, onClick: handleTogglePlayAmount, isClassicGame: isClassicGame, children: jsx(SelectMenu, { disabled: isDisabled() || lockCurrency }) }), jsx(Button, { className: styles_group.groupItem, onClick: () => adjustPlayAmount({ direction: -1 }), theme: "ghost", disabled: isDisabled(), children: jsx("span", { className: styles_group.x2, children: "-" }) }), jsx(Button, { className: styles_group.refreshButton, onClick: () => {
|
|
698
429
|
forceRefresh();
|
|
699
|
-
}, "data-button-refresh": true, children: jsx("span", { className: cx$1(styles_group.x2, styles_group.first) }) }), jsx(Button, { className: styles_group.groupItem, onClick: () => adjustPlayAmount({ direction: 1 }), theme: "ghost", disabled: isDisabled()
|
|
430
|
+
}, "data-button-refresh": true, children: jsx("span", { className: cx$1(styles_group.x2, styles_group.first) }) }), jsx(Button, { className: styles_group.groupItem, onClick: () => adjustPlayAmount({ direction: 1 }), theme: "ghost", disabled: isDisabled(), children: jsx("span", { className: cx$1(styles_group.x2, styles_group.last), children: "+" }) })] }));
|
|
700
431
|
};
|
|
701
432
|
|
|
702
433
|
const getDefaultButtonClassName = (currencyCode, styles) => {
|
|
@@ -718,11 +449,17 @@ const getActiveButtonClassName = (currencyCode, styles) => {
|
|
|
718
449
|
return styles.buttonDefault__active;
|
|
719
450
|
};
|
|
720
451
|
|
|
452
|
+
var AUTOPLAY_LABEL;
|
|
453
|
+
(function (AUTOPLAY_LABEL) {
|
|
454
|
+
AUTOPLAY_LABEL["START"] = "START AUTOPLAY";
|
|
455
|
+
AUTOPLAY_LABEL["STOP"] = "STOP AUTOPLAY";
|
|
456
|
+
})(AUTOPLAY_LABEL || (AUTOPLAY_LABEL = {}));
|
|
457
|
+
|
|
721
458
|
// Space activates buttons/links natively. If the user has keyboard focus on a
|
|
722
|
-
// different interactive control (the
|
|
723
|
-
// buttons, etc.), let Space activate THAT control
|
|
724
|
-
// click the play button — otherwise a paid play can
|
|
725
|
-
// trying to engage free rounds.
|
|
459
|
+
// different interactive control (the "Use Free Rounds" affordance, the intro
|
|
460
|
+
// modal's PLAY NOW / PLAY LATER buttons, etc.), let Space activate THAT control
|
|
461
|
+
// instead of hijacking it to click the play button — otherwise a paid play can
|
|
462
|
+
// fire while the user is trying to engage free rounds.
|
|
726
463
|
const isOtherInteractiveControlFocused = (button) => {
|
|
727
464
|
const active = document.activeElement;
|
|
728
465
|
return Boolean(active &&
|
|
@@ -780,29 +517,20 @@ const useSpacebarButtonTrigger = ({ roleButton, activeClassName, canTrigger, sup
|
|
|
780
517
|
|
|
781
518
|
const AutoPlayController = () => {
|
|
782
519
|
const { config } = useAutoManualPlayState();
|
|
783
|
-
const { t } = useTranslation();
|
|
784
520
|
const [forceRefresh, setForceRefresh] = useState(false);
|
|
785
|
-
const { isValidPlayAmount,
|
|
521
|
+
const { isValidPlayAmount, playValues: { displayPlayAmountView, togglePlayAmountView }, autoPlay: { isDisabled, state, onPlay, onStopPlay, cashoutDisabled }, } = usePlayController();
|
|
786
522
|
const { current } = config.currencyOptions;
|
|
787
523
|
const roleButton = GAME_MODE.AUTOPLAY;
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
let buttonLabel = isStopState
|
|
792
|
-
? t("stopAutoplay")
|
|
793
|
-
: t("startAutoplay");
|
|
794
|
-
if (isStopState && freeRounds.isEngaged) {
|
|
795
|
-
buttonLabel = `${t("stopAutoplay")} (${freeRounds.roundsRemaining})`;
|
|
796
|
-
}
|
|
524
|
+
const buttonLabel = state === AUTO_PLAY_STATE.PLAYING
|
|
525
|
+
? AUTOPLAY_LABEL.STOP
|
|
526
|
+
: AUTOPLAY_LABEL.START;
|
|
797
527
|
const activeClassName = getActiveButtonClassName(current.code, styles_button);
|
|
798
|
-
// Cashout styling keys off the PLAYING state (not the label text) so the
|
|
799
|
-
// engaged "(N)" label suffix can never break the style comparison.
|
|
800
528
|
const defaultClassName = useMemo(() => {
|
|
801
|
-
if (
|
|
529
|
+
if (buttonLabel === AUTOPLAY_LABEL.STOP) {
|
|
802
530
|
return styles_button.buttonCashout;
|
|
803
531
|
}
|
|
804
532
|
return getDefaultButtonClassName(current.code, styles_button);
|
|
805
|
-
}, [
|
|
533
|
+
}, [buttonLabel, current.code]);
|
|
806
534
|
useSpacebarButtonTrigger({
|
|
807
535
|
roleButton,
|
|
808
536
|
activeClassName,
|
|
@@ -811,10 +539,6 @@ const AutoPlayController = () => {
|
|
|
811
539
|
cashoutDisabled,
|
|
812
540
|
isDisabled: isDisabled(),
|
|
813
541
|
}),
|
|
814
|
-
// Suppress the global Space shortcut while the free-rounds intro modal is
|
|
815
|
-
// open so Space belongs to the modal's PLAY NOW / PLAY LATER buttons
|
|
816
|
-
// instead of starting/stopping the autoplay mounted behind it.
|
|
817
|
-
suppressed: Boolean(config.freeRoundsOptions?.showIntroModal),
|
|
818
542
|
});
|
|
819
543
|
const isButtonDisabled = isAutoplayButtonDisabled({
|
|
820
544
|
state,
|
|
@@ -839,7 +563,7 @@ const AutoPlayController = () => {
|
|
|
839
563
|
}, [togglePlayAmountView]);
|
|
840
564
|
const renderButton = useMemo(() => {
|
|
841
565
|
if (displayPlayAmountView) {
|
|
842
|
-
return (jsx(Button, { className: styles_button.buttonPlayAmount, onClick: handleTogglePlayAmount, roleType: roleButton, children:
|
|
566
|
+
return (jsx(Button, { className: styles_button.buttonPlayAmount, onClick: handleTogglePlayAmount, roleType: roleButton, children: "SELECT PLAY AMOUNT" }));
|
|
843
567
|
}
|
|
844
568
|
return (jsx(Button, { disabled: isButtonDisabled, className: defaultClassName, onClick: buttonAction, roleType: roleButton, children: buttonLabel }));
|
|
845
569
|
}, [
|
|
@@ -850,11 +574,27 @@ const AutoPlayController = () => {
|
|
|
850
574
|
handleTogglePlayAmount,
|
|
851
575
|
isButtonDisabled,
|
|
852
576
|
roleButton,
|
|
853
|
-
t,
|
|
854
577
|
]);
|
|
855
578
|
return (jsxs(Fragment, { children: [jsx(PlayAmountControl, { isDisabled: isDisabled, forceRefresh: () => setForceRefresh(!forceRefresh), "data-force-refresh": `mini-play-amount-control-data-${forceRefresh.toString()}` }, `mini-play-amount-control-key-${forceRefresh.toString()}`), renderButton] }));
|
|
856
579
|
};
|
|
857
580
|
|
|
581
|
+
var freeRoundsStyles = {"affordance":"FreeRoundsAffordance-module__affordance___wBGcv","row":"FreeRoundsAffordance-module__row___KwByQ","playSlot":"FreeRoundsAffordance-module__playSlot___hCXTv","freeSlot":"FreeRoundsAffordance-module__freeSlot___-mQ8T","chip":"FreeRoundsAffordance-module__chip___OajJb","chipDisabled":"FreeRoundsAffordance-module__chipDisabled___W9hSU"};
|
|
582
|
+
|
|
583
|
+
// The "Use Free Rounds (N)" chip.
|
|
584
|
+
// - available && !engaged → renders the chip (engages via onUseFreeRounds).
|
|
585
|
+
// It is laid out beside the Play Now button (35/65 row) by
|
|
586
|
+
// ManualPlayController; this component only renders the chip itself.
|
|
587
|
+
// - engaged → renders nothing. There is intentionally NO "exit free rounds"
|
|
588
|
+
// affordance: once engaged the player cannot leave free-round mode from the
|
|
589
|
+
// controller. The engaged play button label is owned by ManualPlayController.
|
|
590
|
+
// Purely renders + fires the callback; the game owns the engaged state.
|
|
591
|
+
const FreeRoundsAffordance = ({ isAvailable, isEngaged, roundsRemaining, onUseFreeRounds, disabled = false, }) => {
|
|
592
|
+
if (isEngaged || !isAvailable || !onUseFreeRounds) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
return (jsxs("button", { type: "button", disabled: disabled, className: cx$1(freeRoundsStyles.chip, { [freeRoundsStyles.chipDisabled]: disabled }), onClick: disabled ? undefined : onUseFreeRounds, children: ["USE FREE ROUNDS (", roundsRemaining, ")"] }));
|
|
596
|
+
};
|
|
597
|
+
|
|
858
598
|
const useIsRunningExternal = () => {
|
|
859
599
|
const [isRunningExternal, setIsRunningExternal] = useState(false);
|
|
860
600
|
useEffect(() => {
|
|
@@ -879,7 +619,6 @@ const useIsRunningExternal = () => {
|
|
|
879
619
|
|
|
880
620
|
const ManualPlayController = () => {
|
|
881
621
|
const { config, doubleOrNothing } = useAutoManualPlayState();
|
|
882
|
-
const { t } = useTranslation();
|
|
883
622
|
const { isRunningExternal } = useIsRunningExternal();
|
|
884
623
|
const [forceRefresh, setForceRefresh] = useState(false);
|
|
885
624
|
const { isValidPlayAmount, playValues: { displayPlayAmountView, togglePlayAmountView }, manualPlay: { isDisabled, onPlay, canCashout, cashoutDisabled }, freeRounds, } = usePlayController();
|
|
@@ -929,7 +668,7 @@ const ManualPlayController = () => {
|
|
|
929
668
|
}), [cashoutDisabled, config.onCashout]);
|
|
930
669
|
const renderButton = useMemo(() => {
|
|
931
670
|
if (displayPlayAmountView) {
|
|
932
|
-
return (jsx(Button, { className: styles_button.buttonPlayAmount, onClick: handleTogglePlayAmount, roleType: roleButton, children:
|
|
671
|
+
return (jsx(Button, { className: styles_button.buttonPlayAmount, onClick: handleTogglePlayAmount, roleType: roleButton, children: "SELECT PLAY AMOUNT" }));
|
|
933
672
|
}
|
|
934
673
|
if (canCashout) {
|
|
935
674
|
const isCashoutDisabled = isManualCashoutDisabled({
|
|
@@ -943,29 +682,21 @@ const ManualPlayController = () => {
|
|
|
943
682
|
doubleOrNothing.state === DOUBLE_OR_NOTHING_STATE.PROGRESS;
|
|
944
683
|
return (jsxs("div", { className: styles_button.buttonRow, children: [jsxs(Button, { disabled: isCashoutDisabled, className: cx$1(styles_button.buttonCashout, {
|
|
945
684
|
[styles_button.buttonRow__cashout]: showDoubleOrNothing,
|
|
946
|
-
}), onClick: handleCashoutClick, roleType: roleButton, children: [isRunningExternal ?
|
|
685
|
+
}), onClick: handleCashoutClick, roleType: roleButton, children: [isRunningExternal ? "COLLECT" : "CASHOUT", " ", format(current.possibleWin ?? 0, current.decimals), " ", current.abbr] }), showDoubleOrNothing ? (jsx(Button, { disabled: isDoubleOrNothingDisabled, className: cx$1(styles_button.buttonDON, styles_button.buttonRow__don, {
|
|
947
686
|
[styles_button.buttonDON__disabled]: isDoubleOrNothingDisabled,
|
|
948
|
-
}), onClick: handleDoubleOrNothingClick, roleType: roleButton, children: jsxs("div", { className: styles_button.buttonDON__content, children: [jsx("p", { className: styles_button.buttonDON__title, children:
|
|
949
|
-
}
|
|
950
|
-
// While a game-driven autoplay loop is running, the game's stop-autoplay
|
|
951
|
-
// control is the only action — don't stack the manual play CTA behind it.
|
|
952
|
-
// The play amount, widgets and free-rounds footer stay as-is.
|
|
953
|
-
if (config.freeRoundsOptions?.autoplayActive) {
|
|
954
|
-
return null;
|
|
687
|
+
}), onClick: handleDoubleOrNothingClick, roleType: roleButton, children: jsxs("div", { className: styles_button.buttonDON__content, children: [jsx("p", { className: styles_button.buttonDON__title, children: "DOUBLE" }), jsx("p", { className: styles_button.buttonDON__subtitle, children: "OR NOTHING" })] }) })) : null] }));
|
|
955
688
|
}
|
|
956
689
|
// Free rounds reuse the play button label while ENGAGED — it becomes
|
|
957
|
-
// "PLAY FREE ROUND
|
|
958
|
-
// "{N} FREE ROUNDS LEFT" footer).
|
|
690
|
+
// "PLAY FREE ROUND (N)". Denominator removed to simplify ("7/10" → "7").
|
|
959
691
|
const playNowText = freeRounds.isEngaged
|
|
960
|
-
?
|
|
961
|
-
:
|
|
692
|
+
? `PLAY FREE ROUND (${freeRounds.roundsRemaining})`
|
|
693
|
+
: "PLAY NOW";
|
|
962
694
|
return (jsx(Button, { disabled: isButtonDisabled, className: defaultClassName, onClick: onPlay, roleType: roleButton, children: playNowText }));
|
|
963
695
|
}, [
|
|
964
696
|
canCashout,
|
|
965
697
|
cashoutDisabled,
|
|
966
698
|
config.doubleOrNothing?.disabled,
|
|
967
699
|
config.doubleOrNothing?.display,
|
|
968
|
-
config.freeRoundsOptions?.autoplayActive,
|
|
969
700
|
config.playOptions.disabledController,
|
|
970
701
|
config.playOptions.isPlaying,
|
|
971
702
|
current.abbr,
|
|
@@ -975,6 +706,7 @@ const ManualPlayController = () => {
|
|
|
975
706
|
displayPlayAmountView,
|
|
976
707
|
doubleOrNothing.state,
|
|
977
708
|
freeRounds.isEngaged,
|
|
709
|
+
freeRounds.roundsRemaining,
|
|
978
710
|
handleDoubleOrNothingClick,
|
|
979
711
|
handleCashoutClick,
|
|
980
712
|
handleTogglePlayAmount,
|
|
@@ -982,20 +714,33 @@ const ManualPlayController = () => {
|
|
|
982
714
|
isRunningExternal,
|
|
983
715
|
onPlay,
|
|
984
716
|
roleButton,
|
|
985
|
-
t,
|
|
986
717
|
]);
|
|
987
|
-
|
|
718
|
+
// Grants exist but the player hasn't engaged → show the side-by-side row
|
|
719
|
+
// (Play Now at 35%, "Use Free Rounds" chip at 65%) instead of a full-width
|
|
720
|
+
// play button. Only when not cashing out and not in the play-amount view.
|
|
721
|
+
const showFreeRoundsRow = !displayPlayAmountView &&
|
|
722
|
+
!canCashout &&
|
|
723
|
+
freeRounds.isAvailable &&
|
|
724
|
+
!freeRounds.isEngaged;
|
|
725
|
+
// Engaging free rounds must be impossible while the controller is disabled or
|
|
726
|
+
// a (non-cashout) round is in progress — same signals that disable the play
|
|
727
|
+
// button. We deliberately exclude `!isValidPlayAmount` (the chip engages a
|
|
728
|
+
// grant, not the paid stake) and rely on `isDisabled()` /
|
|
729
|
+
// `disabledController` / `isPlaying` already in scope.
|
|
730
|
+
const isFreeRoundsAffordanceDisabled = isDisabled() ||
|
|
731
|
+
config.playOptions.disabledController ||
|
|
732
|
+
config.playOptions.isPlaying;
|
|
733
|
+
return (jsxs(Fragment, { children: [jsx(PlayAmountControl, { isDisabled: isDisabled || displayPlayAmountView, lockCurrency: freeRounds.isEngaged, forceRefresh: () => setForceRefresh(!forceRefresh), "data-force-refresh": `mini-play-amount-control-data-${forceRefresh.toString()}` }, `mini-play-amount-control-key-${forceRefresh.toString()}`), showFreeRoundsRow ? (jsxs("div", { className: freeRoundsStyles.row, children: [jsx("div", { className: freeRoundsStyles.playSlot, children: renderButton }), jsx("div", { className: freeRoundsStyles.freeSlot, children: jsx(FreeRoundsAffordance, { isAvailable: freeRounds.isAvailable, isEngaged: freeRounds.isEngaged, roundsRemaining: freeRounds.roundsRemaining, totalRounds: freeRounds.totalRounds, onUseFreeRounds: freeRounds.onUseFreeRounds, disabled: isFreeRoundsAffordanceDisabled }) })] })) : (renderButton)] }));
|
|
988
734
|
};
|
|
989
735
|
|
|
990
|
-
var styles_ui = {"base":"UI-module__base___wThyQ","container":"UI-module__container___gMSiK","betForm":"UI-module__betForm___hQkYd","isClassicGame":"UI-module__isClassicGame___zV1we","baseForceLeft":"UI-module__baseForceLeft___xfc-h","containerSpread":"UI-module__containerSpread___Axb7e","disabled":"UI-module__disabled___dnZJX","auto":"UI-module__auto___5peb8","
|
|
736
|
+
var styles_ui = {"base":"UI-module__base___wThyQ","container":"UI-module__container___gMSiK","betForm":"UI-module__betForm___hQkYd","isClassicGame":"UI-module__isClassicGame___zV1we","baseForceLeft":"UI-module__baseForceLeft___xfc-h","containerSpread":"UI-module__containerSpread___Axb7e","disabled":"UI-module__disabled___dnZJX","auto":"UI-module__auto___5peb8","controllerWidgets":"UI-module__controllerWidgets___x2lBy","sideWidget":"UI-module__sideWidget___WMGRy","centerWidget":"UI-module__centerWidget___sLLUi","left":"UI-module__left___1wtUp","center":"UI-module__center___E0ILH","right":"UI-module__right___yLHvk","controls":"UI-module__controls___Z6L-V","inActiveRound":"UI-module__inActiveRound___HYAx2"};
|
|
991
737
|
|
|
992
738
|
var style_difficulty = {"base":"DifficultySelector-module__base___lDaQ-"};
|
|
993
739
|
|
|
994
740
|
var style_select = {"base":"Selector-module__base___-q0yf","label":"Selector-module__label___JJdbd","button":"Selector-module__button___MeRoC","menu":"Selector-module__menu___P0ROg","menuItems":"Selector-module__menuItems___chFk2","menuItem":"Selector-module__menuItem___isa4c","selected":"Selector-module__selected___nUJtR","disabled":"Selector-module__disabled___f1qGJ","disabledClassic":"Selector-module__disabledClassic___baiGO"};
|
|
995
741
|
|
|
996
742
|
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
997
|
-
const Selector = ({ currentValue, label, riskColor, values, onSelect, disabled, isClassicGame = false,
|
|
998
|
-
const display = (value) => formatDisplay ? formatDisplay(value) : capitalize(String(value));
|
|
743
|
+
const Selector = ({ currentValue, label, riskColor, values, onSelect, disabled, isClassicGame = false, }) => {
|
|
999
744
|
const handleClick = (e) => {
|
|
1000
745
|
if (disabled) {
|
|
1001
746
|
return;
|
|
@@ -1010,26 +755,26 @@ const Selector = ({ currentValue, label, riskColor, values, onSelect, disabled,
|
|
|
1010
755
|
return (jsxs("div", { className: cx$1(style_select.base), children: [label && jsx("span", { className: cx$1(style_select.label), children: label }), jsx(Menu, { as: "div", className: cx$1(style_select.menu), children: ({ open }) => (jsxs(Fragment, { children: [jsxs(MenuButton, { className: cx$1(style_select.button, {
|
|
1011
756
|
[style_select.disabled]: disabled && !isClassicGame,
|
|
1012
757
|
[style_select.disabledClassic]: disabled && isClassicGame,
|
|
1013
|
-
}), style: { color: riskColor }, disabled: disabled, "data-difficulty-selector-button": true, children: [
|
|
758
|
+
}), style: { color: riskColor }, disabled: disabled, "data-difficulty-selector-button": true, children: [capitalize(String(currentValue)), jsx(ChevronIcon, { open: open, disabled: disabled })] }), jsx(MenuItems, { anchor: { to: "top start" }, className: cx$1(style_select.menuItems), children: values.map((value) => (jsx(MenuItem, { as: "div", "data-value": value, onClick: handleClick, className: cx$1(style_select.menuItem, {
|
|
1014
759
|
[style_select.selected]: String(currentValue) === String(value),
|
|
1015
|
-
}), children:
|
|
760
|
+
}), children: capitalize(String(value)) }, `element-${value}`))) })] })) })] }));
|
|
1016
761
|
};
|
|
1017
762
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
[
|
|
1021
|
-
|
|
1022
|
-
|
|
763
|
+
var SELECTORS;
|
|
764
|
+
(function (SELECTORS) {
|
|
765
|
+
SELECTORS["RISK"] = "Risk";
|
|
766
|
+
})(SELECTORS || (SELECTORS = {}));
|
|
767
|
+
var RiskTypes;
|
|
768
|
+
(function (RiskTypes) {
|
|
769
|
+
RiskTypes["LOW"] = "LOW";
|
|
770
|
+
RiskTypes["MEDIUM"] = "MEDIUM";
|
|
771
|
+
RiskTypes["HIGH"] = "HIGH";
|
|
772
|
+
})(RiskTypes || (RiskTypes = {}));
|
|
773
|
+
|
|
1023
774
|
const DifficultySelector = ({ playOptions, dropdownConfig, isClassicGame = false, }) => {
|
|
1024
|
-
const { t } = useTranslation();
|
|
1025
775
|
const { risks, disabledMenu, currentRisk, onRiskChange } = playOptions;
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
function onRiskSelected(value) {
|
|
1029
|
-
riskColor.current = riskColors[value];
|
|
1030
|
-
onRiskChange(value);
|
|
1031
|
-
}
|
|
1032
|
-
return (jsx("div", { className: style_difficulty.base, children: jsx(Selector, { currentValue: currentRisk, label: t("riskLabel"), values: risks, onSelect: onRiskSelected, disabled: disabledMenu, riskColor: riskColor.current, isClassicGame: isClassicGame, formatDisplay: (risk) => t(RISK_LABEL_KEY[risk]) }) }));
|
|
776
|
+
const riskColor = dropdownConfig.riskColorConfig[currentRisk ?? RiskTypes.LOW];
|
|
777
|
+
return (jsx("div", { className: style_difficulty.base, children: jsx(Selector, { currentValue: currentRisk, label: SELECTORS.RISK, values: risks, onSelect: onRiskChange, disabled: disabledMenu, riskColor: riskColor, isClassicGame: isClassicGame }) }));
|
|
1033
778
|
};
|
|
1034
779
|
|
|
1035
780
|
const ALLOWED_SEPARATORS = [",", "."];
|
|
@@ -1052,7 +797,7 @@ function cleanInputNumber(value) {
|
|
|
1052
797
|
return `${integerPart}.${decimalPart}`;
|
|
1053
798
|
}
|
|
1054
799
|
|
|
1055
|
-
var styles$
|
|
800
|
+
var styles$4 = {"base":"Input-module__base___IifiA","disabled":"Input-module__disabled___WqyKa","disabledClassic":"Input-module__disabledClassic___hzsCt"};
|
|
1056
801
|
|
|
1057
802
|
const Input = ({ onChange, disabled, className, max, isClassicGame = false, ...restProps }) => {
|
|
1058
803
|
const handleChange = React.useCallback((event) => {
|
|
@@ -1067,32 +812,31 @@ const Input = ({ onChange, disabled, className, max, isClassicGame = false, ...r
|
|
|
1067
812
|
event.target.value = clamped;
|
|
1068
813
|
onChange?.(event);
|
|
1069
814
|
}, [disabled, max, onChange]);
|
|
1070
|
-
return (jsx("input", { ...restProps, type: "text", max: max, inputMode: "numeric", pattern: "\\d*", maxLength: 2, disabled: disabled, onChange: handleChange, className: cx$1(styles$
|
|
1071
|
-
[styles$
|
|
1072
|
-
[styles$
|
|
815
|
+
return (jsx("input", { ...restProps, type: "text", max: max, inputMode: "numeric", pattern: "\\d*", maxLength: 2, disabled: disabled, onChange: handleChange, className: cx$1(styles$4.base, className, {
|
|
816
|
+
[styles$4.disabled]: disabled && !isClassicGame,
|
|
817
|
+
[styles$4.disabledClassic]: disabled && isClassicGame,
|
|
1073
818
|
}) }));
|
|
1074
819
|
};
|
|
1075
820
|
|
|
1076
|
-
var styles$
|
|
821
|
+
var styles$3 = {"base":"Switch-module__base___gj2ey","isClassicGame":"Switch-module__isClassicGame___H2Ffo","switcher":"Switch-module__switcher___gHXIx","gold":"Switch-module__gold___oewnb","sweeps":"Switch-module__sweeps___yS-IY","default":"Switch-module__default___TmHoU","unchecked":"Switch-module__unchecked___ooSS2","disabled":"Switch-module__disabled___lMRv0","thumb":"Switch-module__thumb___1wJ9D","move-right":"Switch-module__move-right___ca-6D","label":"Switch-module__label___pG2uz"};
|
|
1077
822
|
|
|
1078
823
|
const Switch = ({ enabled, onSwitch, disabled, isPlaying, }) => {
|
|
1079
824
|
const { config } = useAutoManualPlayState();
|
|
1080
|
-
const { t } = useTranslation();
|
|
1081
825
|
const { current } = config.currencyOptions;
|
|
1082
826
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1083
827
|
const defaultClassName = useMemo(() => {
|
|
1084
828
|
if (current.code === Currency.GOLD) {
|
|
1085
|
-
return styles$
|
|
829
|
+
return styles$3.gold;
|
|
1086
830
|
}
|
|
1087
831
|
if (current.code === Currency.SWEEPS) {
|
|
1088
|
-
return styles$
|
|
832
|
+
return styles$3.sweeps;
|
|
1089
833
|
}
|
|
1090
|
-
return styles$
|
|
834
|
+
return styles$3.default;
|
|
1091
835
|
}, [current.code]);
|
|
1092
|
-
const switcherClassName = useMemo(() => cx$1(styles$
|
|
1093
|
-
[styles$
|
|
1094
|
-
[styles$
|
|
1095
|
-
[styles$
|
|
836
|
+
const switcherClassName = useMemo(() => cx$1(styles$3.switcher, defaultClassName, {
|
|
837
|
+
[styles$3.checked]: enabled,
|
|
838
|
+
[styles$3.unchecked]: !enabled,
|
|
839
|
+
[styles$3.disabled]: disabled,
|
|
1096
840
|
}), [defaultClassName, enabled, disabled]);
|
|
1097
841
|
useEffect(() => {
|
|
1098
842
|
const handleGlobalKeyDown = (event) => {
|
|
@@ -1113,18 +857,18 @@ const Switch = ({ enabled, onSwitch, disabled, isPlaying, }) => {
|
|
|
1113
857
|
};
|
|
1114
858
|
}, []);
|
|
1115
859
|
return (jsx(Switch$1, { checked: enabled, onChange: onSwitch, as: Fragment$1, disabled: isPlaying, children: jsxs("div", { className: cx$1({
|
|
1116
|
-
[styles$
|
|
1117
|
-
[styles$
|
|
1118
|
-
}), children: [jsx("span", { className: styles$
|
|
860
|
+
[styles$3.isClassicGame]: isClassicGame,
|
|
861
|
+
[styles$3.base]: !isClassicGame,
|
|
862
|
+
}), children: [jsx("span", { className: styles$3.label, children: "Auto" }), jsx("div", { className: switcherClassName, children: jsx("span", { className: cx$1(styles$3.thumb, { [styles$3["move-right"]]: enabled }) }) })] }) }));
|
|
1119
863
|
};
|
|
1120
864
|
|
|
1121
|
-
var styles$
|
|
865
|
+
var styles$2 = {"base":"InputWithSwitch-module__base___vjLoh","icon":"InputWithSwitch-module__icon___upeAL","input":"InputWithSwitch-module__input___K6RCD","label":"InputWithSwitch-module__label___tEjpj","classic":"InputWithSwitch-module__classic___3AzII"};
|
|
1122
866
|
|
|
1123
867
|
const InputWithSwitch = ({ children, switcherConfig, disabled, className, isClassicGame = false, ...restProps }) => {
|
|
1124
|
-
return (jsxs("div", { className: cx$1(styles$
|
|
1125
|
-
[styles$
|
|
1126
|
-
[styles$
|
|
1127
|
-
}), children: [jsx(Switch, { ...switcherConfig }), jsx(Input, { ...restProps, className: cx$1(styles$
|
|
868
|
+
return (jsxs("div", { className: cx$1(styles$2.base, className, {
|
|
869
|
+
[styles$2.disabled]: switcherConfig.disabled,
|
|
870
|
+
[styles$2.classic]: isClassicGame,
|
|
871
|
+
}), children: [jsx(Switch, { ...switcherConfig }), jsx(Input, { ...restProps, className: cx$1(styles$2.input), disabled: disabled, isClassicGame: isClassicGame }), jsx("div", { className: cx$1(styles$2.icon), children: children })] }));
|
|
1128
872
|
};
|
|
1129
873
|
|
|
1130
874
|
function getDefaultExportFromCjs (x) {
|
|
@@ -1228,18 +972,14 @@ const WidgetContainer = ({ state, widgets, displayPlayAmountView, }) => {
|
|
|
1228
972
|
return (jsxs("div", { className: cx("controllerWidgets"), children: [renderZone(left, "left"), renderZone(center, "center"), renderZone(right, "right")] }));
|
|
1229
973
|
};
|
|
1230
974
|
|
|
1231
|
-
var styles$
|
|
975
|
+
var styles$1 = {"base":"PlayValueList-module__base___5duc6","playValuesWrapper":"PlayValueList-module__playValuesWrapper___-zfj2","playValue":"PlayValueList-module__playValue___TJQhI","selectedPlayValue":"PlayValueList-module__selectedPlayValue___3DhDC","disabledPlayValue":"PlayValueList-module__disabledPlayValue___U9Bkj","isClassicGame":"PlayValueList-module__isClassicGame___AjnGE"};
|
|
1232
976
|
|
|
1233
977
|
const PlayValueList = () => {
|
|
1234
978
|
const [forceRefresh, setForceRefresh] = useState(false);
|
|
1235
979
|
const { config } = useAutoManualPlayState();
|
|
1236
|
-
const { t } = useTranslation();
|
|
1237
980
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1238
|
-
const { onChangeAmount, playAmount, totalBalance,
|
|
981
|
+
const { onChangeAmount, playAmount, totalBalance, playValues: { displayPlayAmountView, togglePlayAmountView }, } = usePlayController();
|
|
1239
982
|
const { playLimits } = config.playOptions.playHook();
|
|
1240
|
-
// While autoplay is running the stake is locked for the whole session, so
|
|
1241
|
-
// the play-amount table must not accept changes until it stops.
|
|
1242
|
-
const isAutoplayPlaying = autoplayState === AUTO_PLAY_STATE.PLAYING;
|
|
1243
983
|
if (!displayPlayAmountView) {
|
|
1244
984
|
return null;
|
|
1245
985
|
}
|
|
@@ -1270,9 +1010,6 @@ const PlayValueList = () => {
|
|
|
1270
1010
|
setForceRefresh(!forceRefresh);
|
|
1271
1011
|
};
|
|
1272
1012
|
const handleClick = (e) => {
|
|
1273
|
-
if (isAutoplayPlaying) {
|
|
1274
|
-
return;
|
|
1275
|
-
}
|
|
1276
1013
|
const el = e.target?.closest("[data-value]");
|
|
1277
1014
|
if (!el) {
|
|
1278
1015
|
return;
|
|
@@ -1286,43 +1023,60 @@ const PlayValueList = () => {
|
|
|
1286
1023
|
applyValue(value);
|
|
1287
1024
|
}
|
|
1288
1025
|
};
|
|
1289
|
-
return (jsx("div", { className: cx$1(styles$
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
[styles$2.selectedPlayValue]: playValue === playAmount,
|
|
1293
|
-
[styles$2.disabledPlayValue]: playValue > totalBalance,
|
|
1026
|
+
return (jsx("div", { className: cx$1(styles$1.base, { [styles$1.isClassicGame]: isClassicGame }), "data-force-refresh": forceRefresh, children: jsx("div", { className: cx$1(styles$1.playValuesWrapper), onClick: handleClick, role: "listbox", "aria-label": "Select play amount", "data-testid": "play-value-list", children: playLimits?.[config.currencyOptions.current.code].defaultBetOptions.map((playValue) => (jsx("div", { className: cx$1(styles$1.playValue, {
|
|
1027
|
+
[styles$1.selectedPlayValue]: playValue === playAmount,
|
|
1028
|
+
[styles$1.disabledPlayValue]: playValue > totalBalance,
|
|
1294
1029
|
}), "data-value": playValue, role: "option", tabIndex: 0, "aria-selected": false, children: format(playValue, config.currencyOptions.current.decimals) }, `${config.currencyOptions.current.code}-${playValue}`))) }) }));
|
|
1295
1030
|
};
|
|
1296
1031
|
|
|
1297
|
-
var styles
|
|
1032
|
+
var styles = {"backdrop":"FreeRoundsIntroModal-module__backdrop___qIgNx","panel":"FreeRoundsIntroModal-module__panel___-zQpe","title":"FreeRoundsIntroModal-module__title___1csj0","details":"FreeRoundsIntroModal-module__details___qXMR-","count":"FreeRoundsIntroModal-module__count___lVep8","stake":"FreeRoundsIntroModal-module__stake___vCcPI","actions":"FreeRoundsIntroModal-module__actions___toCBq","button":"FreeRoundsIntroModal-module__button___bSTmX","playNow":"FreeRoundsIntroModal-module__playNow___iVhdt","playLater":"FreeRoundsIntroModal-module__playLater___l9031"};
|
|
1298
1033
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
//
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1034
|
+
const COIN_TYPE_SWEEPS = 0;
|
|
1035
|
+
const COIN_TYPE_GOLD = 1;
|
|
1036
|
+
// B2C coin decimals (platform convention): Sweeps shows 2 dp, Gold 0 dp.
|
|
1037
|
+
const COIN_DECIMALS = {
|
|
1038
|
+
[COIN_TYPE_SWEEPS]: 2,
|
|
1039
|
+
[COIN_TYPE_GOLD]: 0,
|
|
1040
|
+
};
|
|
1041
|
+
const resolveCurrencyLabel = ({ coinType, currency, }) => {
|
|
1042
|
+
if (currency) {
|
|
1043
|
+
return currency;
|
|
1044
|
+
}
|
|
1045
|
+
if (coinType === COIN_TYPE_SWEEPS) {
|
|
1046
|
+
return "SC";
|
|
1047
|
+
}
|
|
1048
|
+
if (coinType === COIN_TYPE_GOLD) {
|
|
1049
|
+
return "GC";
|
|
1050
|
+
}
|
|
1051
|
+
return "";
|
|
1052
|
+
};
|
|
1053
|
+
// The stake belongs to the GRANT's coin, which can differ from the player's
|
|
1054
|
+
// active currency (e.g. a Sweeps grant surfaced while the player is on Gold).
|
|
1055
|
+
// Use the grant coin's decimals so a 0.20 SC stake doesn't render as "0" under
|
|
1056
|
+
// Gold's 0-dp formatting. B2B grants (operator `currency`) fall back to the
|
|
1057
|
+
// operator currency decimals passed in via `decimals`.
|
|
1058
|
+
const resolveDecimals = ({ coinType, currency, fallback, }) => {
|
|
1059
|
+
if (!currency && coinType != null && coinType in COIN_DECIMALS) {
|
|
1060
|
+
return COIN_DECIMALS[coinType];
|
|
1061
|
+
}
|
|
1062
|
+
return fallback;
|
|
1063
|
+
};
|
|
1064
|
+
// Centered "Play Now / Play Later" intro modal. Renders + fires callbacks only;
|
|
1065
|
+
// the SDK does no fetching. `onPlayNow` should engage free-round mode + close,
|
|
1066
|
+
// `onPlayLater` should close and stay on paid play.
|
|
1067
|
+
const FreeRoundsIntroModal = ({ open, roundsRemaining, stakeCents, coinType, currency, decimals = 2, onPlayNow, onPlayLater, }) => {
|
|
1305
1068
|
const handleClose = () => onPlayLater?.();
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1069
|
+
const currencyLabel = resolveCurrencyLabel({ coinType, currency });
|
|
1070
|
+
const stakeDecimals = resolveDecimals({
|
|
1308
1071
|
coinType,
|
|
1309
1072
|
currency,
|
|
1310
1073
|
fallback: decimals,
|
|
1311
1074
|
});
|
|
1312
|
-
const
|
|
1313
|
-
|
|
1314
|
-
return (jsx(Dialog, { open: open, onClose: handleClose, className: styles$1.backdrop, children: jsx("div", { className: styles$1.column, children: jsxs(DialogPanel, { className: styles$1.panel, children: [jsx(DialogTitle, { className: styles$1.header, children: t("freeRoundsModalTitle") }), jsxs("div", { className: styles$1.summary, children: [t("freeRoundsHave"), " ", jsx("span", { className: styles$1.accent, children: roundsRemaining }), " ", roundsRemaining === 1
|
|
1315
|
-
? t("freeRoundsUnitOne")
|
|
1316
|
-
: t("freeRoundsUnitOther")] }), jsx("div", { className: styles$1.perRound, children: t("freeRoundsPerRound", {
|
|
1317
|
-
amount: `${perRoundDisplay}${coinLabel ? ` ${coinLabel}` : ""}`,
|
|
1318
|
-
}) }), expiresInDays !== null && (jsx("div", { className: styles$1.expiry, children: t("freeRoundsExpiresIn", {
|
|
1319
|
-
days: expiresInDays,
|
|
1320
|
-
unit: expiresInDays === 1 ? t("dayUnitOne") : t("dayUnitOther"),
|
|
1321
|
-
}) })), jsxs("div", { className: styles$1.actions, children: [jsx("button", { type: "button", className: `${styles$1.button} ${styles$1.playNow}`, onClick: onPlayNow, children: t("freeRoundsModalPlayNow") }), jsx("button", { type: "button", className: `${styles$1.button} ${styles$1.playLater}`, onClick: onPlayLater, children: t("freeRoundsModalPlayLater") })] })] }) }) }));
|
|
1075
|
+
const stakeDisplay = format(stakeCents / 100, stakeDecimals);
|
|
1076
|
+
return (jsx(Dialog, { open: open, onClose: handleClose, className: styles.backdrop, children: jsxs(DialogPanel, { className: styles.panel, children: [jsx(DialogTitle, { className: styles.title, children: "You have free rounds!" }), jsx("div", { className: styles.count, children: roundsRemaining }), jsxs("div", { className: styles.details, children: [roundsRemaining === 1 ? "free round" : "free rounds", " ready to play"] }), jsxs("div", { className: styles.stake, children: [stakeDisplay, currencyLabel ? ` ${currencyLabel}` : "", " per round"] }), jsxs("div", { className: styles.actions, children: [jsx("button", { type: "button", className: `${styles.button} ${styles.playNow}`, onClick: onPlayNow, children: "PLAY NOW" }), jsx("button", { type: "button", className: `${styles.button} ${styles.playLater}`, onClick: onPlayLater, children: "PLAY LATER" })] })] }) }));
|
|
1322
1077
|
};
|
|
1323
1078
|
|
|
1324
1079
|
const AutoManualPlayProvider = ({ children, config, }) => {
|
|
1325
|
-
const t = useMemo(() => createTranslator(resolveLanguage(config.language)), [config.language]);
|
|
1326
1080
|
const [mode, setMode] = useState(GAME_MODE.MANUAL);
|
|
1327
1081
|
const [autoplayState, setAutoplayState] = useState(AUTO_PLAY_STATE.IDLE);
|
|
1328
1082
|
const [doubleOrNothingState, setDoubleOrNothingState] = useState(DOUBLE_OR_NOTHING_STATE.IDLE);
|
|
@@ -1334,31 +1088,17 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1334
1088
|
const isControllerDisabled = config.playOptions.disabledController;
|
|
1335
1089
|
const isGamePlaying = config.playOptions.isPlaying;
|
|
1336
1090
|
const isAutoplayPlaying = autoplayState === AUTO_PLAY_STATE.PLAYING;
|
|
1337
|
-
// Free rounds are MANUAL-only
|
|
1338
|
-
//
|
|
1339
|
-
//
|
|
1340
|
-
//
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
const freeRoundsRemaining = config.freeRoundsOptions?.roundsRemaining ?? 0;
|
|
1344
|
-
const isFreeRoundsEngaged = Boolean(config.freeRoundsOptions?.engaged && freeRoundsRemaining > 0);
|
|
1345
|
-
const supportsGrantFundedAutoplay = Boolean(config.freeRoundsOptions?.supportsGrantFundedAutoplay);
|
|
1346
|
-
const isModeLockedByFreeRounds = isFreeRoundsEngaged && !supportsGrantFundedAutoplay;
|
|
1091
|
+
// Free rounds are MANUAL-only. While a grant is engaged the player must not
|
|
1092
|
+
// be able to flip into autoplay (which would silently drop the manual-gated
|
|
1093
|
+
// engaged state and let PAID autoplay start). This is independent of `mode`
|
|
1094
|
+
// so it stays true even if a switch attempt slipped through.
|
|
1095
|
+
const isFreeRoundsEngaged = Boolean(config.freeRoundsOptions?.engaged &&
|
|
1096
|
+
(config.freeRoundsOptions?.roundsRemaining ?? 0) > 0);
|
|
1347
1097
|
const isSimplified = config.withoutRiskAndAutoplay === true;
|
|
1348
1098
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1349
1099
|
const togglePlayAmountView = useCallback(() => {
|
|
1350
1100
|
setDisplayPlayAmountView((v) => !v);
|
|
1351
1101
|
}, []);
|
|
1352
|
-
// Grant-funded autoplay: while free rounds are engaged the selectable
|
|
1353
|
-
// autoplay count is hard-capped to the remaining grants (covers the default
|
|
1354
|
-
// count and the ∞ option — Infinity clamps down to roundsRemaining, so ∞ is
|
|
1355
|
-
// effectively disabled while engaged). No paid spillover.
|
|
1356
|
-
useEffect(() => {
|
|
1357
|
-
if (!supportsGrantFundedAutoplay || !isFreeRoundsEngaged) {
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
setNumberOfPlays((prev) => prev > freeRoundsRemaining ? freeRoundsRemaining : prev);
|
|
1361
|
-
}, [supportsGrantFundedAutoplay, isFreeRoundsEngaged, freeRoundsRemaining]);
|
|
1362
1102
|
const startAutoplay = useCallback((numPlays) => {
|
|
1363
1103
|
setMode(GAME_MODE.AUTOPLAY);
|
|
1364
1104
|
setAutoplayState(AUTO_PLAY_STATE.SELECTING);
|
|
@@ -1398,15 +1138,12 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1398
1138
|
setSelection([]);
|
|
1399
1139
|
}, []);
|
|
1400
1140
|
const toggleMode = useCallback(() => {
|
|
1401
|
-
// No-op while a free-round grant is engaged
|
|
1402
|
-
//
|
|
1403
|
-
// switch to autoplay until the grant is consumed/released. When the game
|
|
1404
|
-
// sets `supportsGrantFundedAutoplay`, engaged switching is allowed (still
|
|
1405
|
-
// blocked while a round is in flight via the gates above).
|
|
1141
|
+
// No-op while a free-round grant is engaged: manual-only, no-exit. The
|
|
1142
|
+
// player cannot switch to autoplay until the grant is consumed/released.
|
|
1406
1143
|
if (isGamePlaying ||
|
|
1407
1144
|
isControllerDisabled ||
|
|
1408
1145
|
isAutoplayPlaying ||
|
|
1409
|
-
|
|
1146
|
+
isFreeRoundsEngaged) {
|
|
1410
1147
|
return;
|
|
1411
1148
|
}
|
|
1412
1149
|
setNumberOfPlays(AUTOPLAY_DEFAULT_PLAY_ROUNDS_COUNT);
|
|
@@ -1415,7 +1152,7 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1415
1152
|
isAutoplayPlaying,
|
|
1416
1153
|
isControllerDisabled,
|
|
1417
1154
|
isGamePlaying,
|
|
1418
|
-
|
|
1155
|
+
isFreeRoundsEngaged,
|
|
1419
1156
|
]);
|
|
1420
1157
|
const updateSelection = useCallback((values) => {
|
|
1421
1158
|
if (!isAutoPlaying) {
|
|
@@ -1475,60 +1212,42 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1475
1212
|
displayPlayAmountView,
|
|
1476
1213
|
togglePlayAmountView,
|
|
1477
1214
|
]);
|
|
1478
|
-
return (
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
center: config.centerWidgets,
|
|
1514
|
-
right: config.rightWidgets,
|
|
1515
|
-
} })] }) }))] }) }));
|
|
1516
|
-
};
|
|
1517
|
-
|
|
1518
|
-
var styles = {"backdrop":"FreeRoundsSummaryModal-module__backdrop___tNi3I","panel":"FreeRoundsSummaryModal-module__panel___2MIEp","header":"FreeRoundsSummaryModal-module__header___-BkpP","summary":"FreeRoundsSummaryModal-module__summary___YExX9","accent":"FreeRoundsSummaryModal-module__accent___z9aBF","hint":"FreeRoundsSummaryModal-module__hint___CYWqA","close":"FreeRoundsSummaryModal-module__close___4-irR"};
|
|
1519
|
-
|
|
1520
|
-
// END pop-up — shown by the game after the last free round settles. The game
|
|
1521
|
-
// owns visibility: it mounts open when the play-through completes, unmount
|
|
1522
|
-
// onClose.
|
|
1523
|
-
const FreeRoundsSummaryModal = ({ totalWinAmount, coin, roundsPlayed, decimals, onClose, }) => {
|
|
1524
|
-
const { t } = useTranslation();
|
|
1525
|
-
// Shared monetary formatter — truncates (never rounds up) so the summary
|
|
1526
|
-
// can't display more winnings than were actually credited.
|
|
1527
|
-
const winDisplay = format(totalWinAmount, decimals ?? resolveCoinLabelDecimals(coin));
|
|
1528
|
-
return (jsx(Dialog, { open: true, onClose: onClose, className: styles.backdrop, children: jsxs(DialogPanel, { className: styles.panel, children: [jsx(DialogTitle, { className: styles.header, children: t("freeRoundsModalTitle") }), jsxs("div", { className: styles.summary, children: [t("freeRoundsSummaryWon"), " ", jsxs("span", { className: styles.accent, children: [winDisplay, " ", coin] }), " ", t("freeRoundsSummaryIn"), " ", roundsPlayed, " ", roundsPlayed === 1
|
|
1529
|
-
? t("freeRoundsSummaryUnitOne")
|
|
1530
|
-
: t("freeRoundsSummaryUnitOther")] }), jsx("div", { className: styles.hint, children: t("freeRoundsSummaryCredited") }), jsx("button", { type: "button", className: styles.close, onClick: onClose, children: t("freeRoundsSummaryClose") })] }) }));
|
|
1215
|
+
return (jsxs(AutoManualPlayStateContext.Provider, { value: contextValue, children: [typeof children === "function" ? children(contextValue) : children, mode === GAME_MODE.MANUAL &&
|
|
1216
|
+
config.freeRoundsOptions?.showIntroModal && (jsx("div", { style: {
|
|
1217
|
+
"--play-panel-bg": hexToRgb(config.panel.bgColorHex ?? "#01243A"),
|
|
1218
|
+
}, children: jsx(FreeRoundsIntroModal, { open: config.freeRoundsOptions.showIntroModal, roundsRemaining: config.freeRoundsOptions.roundsRemaining, totalRounds: config.freeRoundsOptions.totalRounds, stakeCents: config.freeRoundsOptions.stakeCents, coinType: config.freeRoundsOptions.coinType, currency: config.freeRoundsOptions.currency, decimals: config.currencyOptions.current.decimals, onPlayNow: config.freeRoundsOptions.onPlayNow, onPlayLater: config.freeRoundsOptions.onPlayLater }) })), config.playOptions.displayController && (jsx("div", { className: cx$1(styles_ui.base, styles_ui.betForm, {
|
|
1219
|
+
[styles_ui.baseForceLeft]: config.classicGame?.forceLeftStyle,
|
|
1220
|
+
[styles_ui.isClassicGame]: config.isClassicGame,
|
|
1221
|
+
[styles_ui.inActiveRound]: mode === GAME_MODE.MANUAL && isGamePlaying,
|
|
1222
|
+
}), style: {
|
|
1223
|
+
"--play-bottom": config.panel.bottom ?? 0,
|
|
1224
|
+
"--play-panel-bg": hexToRgb(config.panel.bgColorHex ?? "#01243A"),
|
|
1225
|
+
"--play-dropdown-bg": hexToRgb(config.classicGame?.dropdown?.bgColorHex ??
|
|
1226
|
+
config.dropdown.bgColorHex ??
|
|
1227
|
+
"#01243A"),
|
|
1228
|
+
"--play-panel-bg-opacity": config.panel.bgColorOpacity ?? 0.5,
|
|
1229
|
+
}, children: jsxs("div", { className: cx$1(styles_ui.container, {
|
|
1230
|
+
[styles_ui.containerSpread]: config.classicGame?.forceLeftStyle,
|
|
1231
|
+
}), children: [jsxs("div", { className: cx$1(styles_ui.controls), children: [jsx(PlayValueList, {}), !isSimplified ? (jsxs("div", { className: cx$1(styles_ui.auto), children: [jsx(DifficultySelector, { playOptions: {
|
|
1232
|
+
...config.playOptions,
|
|
1233
|
+
disabledMenu: isControllerDisabled || config.playOptions.disabledMenu,
|
|
1234
|
+
}, dropdownConfig: config.dropdown, isClassicGame: isClassicGame }), jsx(InputWithSwitch, { value: numberOfPlays === Infinity ? 0 : numberOfPlays, type: "number", onChange: (e) => setNumberOfPlays(Number(e.currentTarget.value)), placeholder: "Number of Plays", min: 0, max: 99, disabled: isControllerDisabled || mode === GAME_MODE.MANUAL, isClassicGame: isClassicGame, switcherConfig: {
|
|
1235
|
+
onSwitch: toggleMode,
|
|
1236
|
+
isPlaying: isAutoPlaying || isGamePlaying,
|
|
1237
|
+
enabled: mode !== GAME_MODE.MANUAL,
|
|
1238
|
+
disabled: isControllerDisabled ||
|
|
1239
|
+
isAutoplayPlaying ||
|
|
1240
|
+
isFreeRoundsEngaged,
|
|
1241
|
+
}, children: !isClassicGame && (jsx("span", { className: cx$1({
|
|
1242
|
+
[styles_ui.disabled]: mode !== GAME_MODE.AUTOPLAY ||
|
|
1243
|
+
numberOfPlays !== Infinity ||
|
|
1244
|
+
isAutoplayPlaying,
|
|
1245
|
+
}), children: "\u221E" })) })] })) : null, mode === GAME_MODE.MANUAL ? (jsx(ManualPlayController, {})) : (jsx(AutoPlayController, {}))] }), jsx(WidgetContainer, { state: autoplayState, displayPlayAmountView: displayPlayAmountView, widgets: {
|
|
1246
|
+
left: config.leftWidgets,
|
|
1247
|
+
center: config.centerWidgets,
|
|
1248
|
+
right: config.rightWidgets,
|
|
1249
|
+
} })] }) }))] }));
|
|
1531
1250
|
};
|
|
1532
1251
|
|
|
1533
|
-
export { AUTO_PLAY_STATE, AutoManualPlayProvider,
|
|
1252
|
+
export { AUTO_PLAY_STATE, AutoManualPlayProvider, DOUBLE_OR_NOTHING_STATE, FreeRoundsIntroModal, GAME_MODE, WIDGET, canAutoplaySpaceTrigger, createAutoplayButtonAction, createManualCashoutClickHandler, format, isAutoplayButtonDisabled, isManualCashoutDisabled };
|
|
1534
1253
|
//# sourceMappingURL=index.mjs.map
|