@enigma-lake/tower-play-controller-sdk 2.2.4 → 2.2.5
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 +212 -489
- 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,30 @@ 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
|
-
const riskColor = useRef(riskColors[currentRisk ?? RiskTypes.LOW]);
|
|
776
|
+
const riskColor = useRef(dropdownConfig.riskColorConfig[currentRisk ?? RiskTypes.LOW]);
|
|
1028
777
|
function onRiskSelected(value) {
|
|
1029
|
-
riskColor.current =
|
|
778
|
+
riskColor.current = dropdownConfig.riskColorConfig[value];
|
|
1030
779
|
onRiskChange(value);
|
|
1031
780
|
}
|
|
1032
|
-
return (jsx("div", { className: style_difficulty.base, children: jsx(Selector, { currentValue: currentRisk, label:
|
|
781
|
+
return (jsx("div", { className: style_difficulty.base, children: jsx(Selector, { currentValue: currentRisk, label: SELECTORS.RISK, values: risks, onSelect: onRiskSelected, disabled: disabledMenu, riskColor: riskColor.current, isClassicGame: isClassicGame }) }));
|
|
1033
782
|
};
|
|
1034
783
|
|
|
1035
784
|
const ALLOWED_SEPARATORS = [",", "."];
|
|
@@ -1052,7 +801,7 @@ function cleanInputNumber(value) {
|
|
|
1052
801
|
return `${integerPart}.${decimalPart}`;
|
|
1053
802
|
}
|
|
1054
803
|
|
|
1055
|
-
var styles$
|
|
804
|
+
var styles$4 = {"base":"Input-module__base___IifiA","disabled":"Input-module__disabled___WqyKa","disabledClassic":"Input-module__disabledClassic___hzsCt"};
|
|
1056
805
|
|
|
1057
806
|
const Input = ({ onChange, disabled, className, max, isClassicGame = false, ...restProps }) => {
|
|
1058
807
|
const handleChange = React.useCallback((event) => {
|
|
@@ -1067,32 +816,31 @@ const Input = ({ onChange, disabled, className, max, isClassicGame = false, ...r
|
|
|
1067
816
|
event.target.value = clamped;
|
|
1068
817
|
onChange?.(event);
|
|
1069
818
|
}, [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$
|
|
819
|
+
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, {
|
|
820
|
+
[styles$4.disabled]: disabled && !isClassicGame,
|
|
821
|
+
[styles$4.disabledClassic]: disabled && isClassicGame,
|
|
1073
822
|
}) }));
|
|
1074
823
|
};
|
|
1075
824
|
|
|
1076
|
-
var styles$
|
|
825
|
+
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
826
|
|
|
1078
827
|
const Switch = ({ enabled, onSwitch, disabled, isPlaying, }) => {
|
|
1079
828
|
const { config } = useAutoManualPlayState();
|
|
1080
|
-
const { t } = useTranslation();
|
|
1081
829
|
const { current } = config.currencyOptions;
|
|
1082
830
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1083
831
|
const defaultClassName = useMemo(() => {
|
|
1084
832
|
if (current.code === Currency.GOLD) {
|
|
1085
|
-
return styles$
|
|
833
|
+
return styles$3.gold;
|
|
1086
834
|
}
|
|
1087
835
|
if (current.code === Currency.SWEEPS) {
|
|
1088
|
-
return styles$
|
|
836
|
+
return styles$3.sweeps;
|
|
1089
837
|
}
|
|
1090
|
-
return styles$
|
|
838
|
+
return styles$3.default;
|
|
1091
839
|
}, [current.code]);
|
|
1092
|
-
const switcherClassName = useMemo(() => cx$1(styles$
|
|
1093
|
-
[styles$
|
|
1094
|
-
[styles$
|
|
1095
|
-
[styles$
|
|
840
|
+
const switcherClassName = useMemo(() => cx$1(styles$3.switcher, defaultClassName, {
|
|
841
|
+
[styles$3.checked]: enabled,
|
|
842
|
+
[styles$3.unchecked]: !enabled,
|
|
843
|
+
[styles$3.disabled]: disabled,
|
|
1096
844
|
}), [defaultClassName, enabled, disabled]);
|
|
1097
845
|
useEffect(() => {
|
|
1098
846
|
const handleGlobalKeyDown = (event) => {
|
|
@@ -1113,18 +861,18 @@ const Switch = ({ enabled, onSwitch, disabled, isPlaying, }) => {
|
|
|
1113
861
|
};
|
|
1114
862
|
}, []);
|
|
1115
863
|
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$
|
|
864
|
+
[styles$3.isClassicGame]: isClassicGame,
|
|
865
|
+
[styles$3.base]: !isClassicGame,
|
|
866
|
+
}), 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
867
|
};
|
|
1120
868
|
|
|
1121
|
-
var styles$
|
|
869
|
+
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
870
|
|
|
1123
871
|
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$
|
|
872
|
+
return (jsxs("div", { className: cx$1(styles$2.base, className, {
|
|
873
|
+
[styles$2.disabled]: switcherConfig.disabled,
|
|
874
|
+
[styles$2.classic]: isClassicGame,
|
|
875
|
+
}), 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
876
|
};
|
|
1129
877
|
|
|
1130
878
|
function getDefaultExportFromCjs (x) {
|
|
@@ -1228,18 +976,14 @@ const WidgetContainer = ({ state, widgets, displayPlayAmountView, }) => {
|
|
|
1228
976
|
return (jsxs("div", { className: cx("controllerWidgets"), children: [renderZone(left, "left"), renderZone(center, "center"), renderZone(right, "right")] }));
|
|
1229
977
|
};
|
|
1230
978
|
|
|
1231
|
-
var styles$
|
|
979
|
+
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
980
|
|
|
1233
981
|
const PlayValueList = () => {
|
|
1234
982
|
const [forceRefresh, setForceRefresh] = useState(false);
|
|
1235
983
|
const { config } = useAutoManualPlayState();
|
|
1236
|
-
const { t } = useTranslation();
|
|
1237
984
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1238
|
-
const { onChangeAmount, playAmount, totalBalance,
|
|
985
|
+
const { onChangeAmount, playAmount, totalBalance, playValues: { displayPlayAmountView, togglePlayAmountView }, } = usePlayController();
|
|
1239
986
|
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
987
|
if (!displayPlayAmountView) {
|
|
1244
988
|
return null;
|
|
1245
989
|
}
|
|
@@ -1270,9 +1014,6 @@ const PlayValueList = () => {
|
|
|
1270
1014
|
setForceRefresh(!forceRefresh);
|
|
1271
1015
|
};
|
|
1272
1016
|
const handleClick = (e) => {
|
|
1273
|
-
if (isAutoplayPlaying) {
|
|
1274
|
-
return;
|
|
1275
|
-
}
|
|
1276
1017
|
const el = e.target?.closest("[data-value]");
|
|
1277
1018
|
if (!el) {
|
|
1278
1019
|
return;
|
|
@@ -1286,43 +1027,60 @@ const PlayValueList = () => {
|
|
|
1286
1027
|
applyValue(value);
|
|
1287
1028
|
}
|
|
1288
1029
|
};
|
|
1289
|
-
return (jsx("div", { className: cx$1(styles$
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
[styles$2.selectedPlayValue]: playValue === playAmount,
|
|
1293
|
-
[styles$2.disabledPlayValue]: playValue > totalBalance,
|
|
1030
|
+
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, {
|
|
1031
|
+
[styles$1.selectedPlayValue]: playValue === playAmount,
|
|
1032
|
+
[styles$1.disabledPlayValue]: playValue > totalBalance,
|
|
1294
1033
|
}), "data-value": playValue, role: "option", tabIndex: 0, "aria-selected": false, children: format(playValue, config.currencyOptions.current.decimals) }, `${config.currencyOptions.current.code}-${playValue}`))) }) }));
|
|
1295
1034
|
};
|
|
1296
1035
|
|
|
1297
|
-
var styles
|
|
1036
|
+
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
1037
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
//
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1038
|
+
const COIN_TYPE_SWEEPS = 0;
|
|
1039
|
+
const COIN_TYPE_GOLD = 1;
|
|
1040
|
+
// B2C coin decimals (platform convention): Sweeps shows 2 dp, Gold 0 dp.
|
|
1041
|
+
const COIN_DECIMALS = {
|
|
1042
|
+
[COIN_TYPE_SWEEPS]: 2,
|
|
1043
|
+
[COIN_TYPE_GOLD]: 0,
|
|
1044
|
+
};
|
|
1045
|
+
const resolveCurrencyLabel = ({ coinType, currency, }) => {
|
|
1046
|
+
if (currency) {
|
|
1047
|
+
return currency;
|
|
1048
|
+
}
|
|
1049
|
+
if (coinType === COIN_TYPE_SWEEPS) {
|
|
1050
|
+
return "SC";
|
|
1051
|
+
}
|
|
1052
|
+
if (coinType === COIN_TYPE_GOLD) {
|
|
1053
|
+
return "GC";
|
|
1054
|
+
}
|
|
1055
|
+
return "";
|
|
1056
|
+
};
|
|
1057
|
+
// The stake belongs to the GRANT's coin, which can differ from the player's
|
|
1058
|
+
// active currency (e.g. a Sweeps grant surfaced while the player is on Gold).
|
|
1059
|
+
// Use the grant coin's decimals so a 0.20 SC stake doesn't render as "0" under
|
|
1060
|
+
// Gold's 0-dp formatting. B2B grants (operator `currency`) fall back to the
|
|
1061
|
+
// operator currency decimals passed in via `decimals`.
|
|
1062
|
+
const resolveDecimals = ({ coinType, currency, fallback, }) => {
|
|
1063
|
+
if (!currency && coinType != null && coinType in COIN_DECIMALS) {
|
|
1064
|
+
return COIN_DECIMALS[coinType];
|
|
1065
|
+
}
|
|
1066
|
+
return fallback;
|
|
1067
|
+
};
|
|
1068
|
+
// Centered "Play Now / Play Later" intro modal. Renders + fires callbacks only;
|
|
1069
|
+
// the SDK does no fetching. `onPlayNow` should engage free-round mode + close,
|
|
1070
|
+
// `onPlayLater` should close and stay on paid play.
|
|
1071
|
+
const FreeRoundsIntroModal = ({ open, roundsRemaining, stakeCents, coinType, currency, decimals = 2, onPlayNow, onPlayLater, }) => {
|
|
1305
1072
|
const handleClose = () => onPlayLater?.();
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1073
|
+
const currencyLabel = resolveCurrencyLabel({ coinType, currency });
|
|
1074
|
+
const stakeDecimals = resolveDecimals({
|
|
1308
1075
|
coinType,
|
|
1309
1076
|
currency,
|
|
1310
1077
|
fallback: decimals,
|
|
1311
1078
|
});
|
|
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") })] })] }) }) }));
|
|
1079
|
+
const stakeDisplay = format(stakeCents / 100, stakeDecimals);
|
|
1080
|
+
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
1081
|
};
|
|
1323
1082
|
|
|
1324
1083
|
const AutoManualPlayProvider = ({ children, config, }) => {
|
|
1325
|
-
const t = useMemo(() => createTranslator(resolveLanguage(config.language)), [config.language]);
|
|
1326
1084
|
const [mode, setMode] = useState(GAME_MODE.MANUAL);
|
|
1327
1085
|
const [autoplayState, setAutoplayState] = useState(AUTO_PLAY_STATE.IDLE);
|
|
1328
1086
|
const [doubleOrNothingState, setDoubleOrNothingState] = useState(DOUBLE_OR_NOTHING_STATE.IDLE);
|
|
@@ -1334,31 +1092,17 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1334
1092
|
const isControllerDisabled = config.playOptions.disabledController;
|
|
1335
1093
|
const isGamePlaying = config.playOptions.isPlaying;
|
|
1336
1094
|
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;
|
|
1095
|
+
// Free rounds are MANUAL-only. While a grant is engaged the player must not
|
|
1096
|
+
// be able to flip into autoplay (which would silently drop the manual-gated
|
|
1097
|
+
// engaged state and let PAID autoplay start). This is independent of `mode`
|
|
1098
|
+
// so it stays true even if a switch attempt slipped through.
|
|
1099
|
+
const isFreeRoundsEngaged = Boolean(config.freeRoundsOptions?.engaged &&
|
|
1100
|
+
(config.freeRoundsOptions?.roundsRemaining ?? 0) > 0);
|
|
1347
1101
|
const isSimplified = config.withoutRiskAndAutoplay === true;
|
|
1348
1102
|
const isClassicGame = Boolean(config?.isClassicGame || config?.classicGame?.forceLeftStyle);
|
|
1349
1103
|
const togglePlayAmountView = useCallback(() => {
|
|
1350
1104
|
setDisplayPlayAmountView((v) => !v);
|
|
1351
1105
|
}, []);
|
|
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
1106
|
const startAutoplay = useCallback((numPlays) => {
|
|
1363
1107
|
setMode(GAME_MODE.AUTOPLAY);
|
|
1364
1108
|
setAutoplayState(AUTO_PLAY_STATE.SELECTING);
|
|
@@ -1398,15 +1142,12 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1398
1142
|
setSelection([]);
|
|
1399
1143
|
}, []);
|
|
1400
1144
|
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).
|
|
1145
|
+
// No-op while a free-round grant is engaged: manual-only, no-exit. The
|
|
1146
|
+
// player cannot switch to autoplay until the grant is consumed/released.
|
|
1406
1147
|
if (isGamePlaying ||
|
|
1407
1148
|
isControllerDisabled ||
|
|
1408
1149
|
isAutoplayPlaying ||
|
|
1409
|
-
|
|
1150
|
+
isFreeRoundsEngaged) {
|
|
1410
1151
|
return;
|
|
1411
1152
|
}
|
|
1412
1153
|
setNumberOfPlays(AUTOPLAY_DEFAULT_PLAY_ROUNDS_COUNT);
|
|
@@ -1415,7 +1156,7 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1415
1156
|
isAutoplayPlaying,
|
|
1416
1157
|
isControllerDisabled,
|
|
1417
1158
|
isGamePlaying,
|
|
1418
|
-
|
|
1159
|
+
isFreeRoundsEngaged,
|
|
1419
1160
|
]);
|
|
1420
1161
|
const updateSelection = useCallback((values) => {
|
|
1421
1162
|
if (!isAutoPlaying) {
|
|
@@ -1475,60 +1216,42 @@ const AutoManualPlayProvider = ({ children, config, }) => {
|
|
|
1475
1216
|
displayPlayAmountView,
|
|
1476
1217
|
togglePlayAmountView,
|
|
1477
1218
|
]);
|
|
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") })] }) }));
|
|
1219
|
+
return (jsxs(AutoManualPlayStateContext.Provider, { value: contextValue, children: [typeof children === "function" ? children(contextValue) : children, mode === GAME_MODE.MANUAL &&
|
|
1220
|
+
config.freeRoundsOptions?.showIntroModal && (jsx("div", { style: {
|
|
1221
|
+
"--play-panel-bg": hexToRgb(config.panel.bgColorHex ?? "#01243A"),
|
|
1222
|
+
}, 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, {
|
|
1223
|
+
[styles_ui.baseForceLeft]: config.classicGame?.forceLeftStyle,
|
|
1224
|
+
[styles_ui.isClassicGame]: config.isClassicGame,
|
|
1225
|
+
[styles_ui.inActiveRound]: mode === GAME_MODE.MANUAL && isGamePlaying,
|
|
1226
|
+
}), style: {
|
|
1227
|
+
"--play-bottom": config.panel.bottom ?? 0,
|
|
1228
|
+
"--play-panel-bg": hexToRgb(config.panel.bgColorHex ?? "#01243A"),
|
|
1229
|
+
"--play-dropdown-bg": hexToRgb(config.classicGame?.dropdown?.bgColorHex ??
|
|
1230
|
+
config.dropdown.bgColorHex ??
|
|
1231
|
+
"#01243A"),
|
|
1232
|
+
"--play-panel-bg-opacity": config.panel.bgColorOpacity ?? 0.5,
|
|
1233
|
+
}, children: jsxs("div", { className: cx$1(styles_ui.container, {
|
|
1234
|
+
[styles_ui.containerSpread]: config.classicGame?.forceLeftStyle,
|
|
1235
|
+
}), 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: {
|
|
1236
|
+
...config.playOptions,
|
|
1237
|
+
disabledMenu: isControllerDisabled || config.playOptions.disabledMenu,
|
|
1238
|
+
}, 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: {
|
|
1239
|
+
onSwitch: toggleMode,
|
|
1240
|
+
isPlaying: isAutoPlaying || isGamePlaying,
|
|
1241
|
+
enabled: mode !== GAME_MODE.MANUAL,
|
|
1242
|
+
disabled: isControllerDisabled ||
|
|
1243
|
+
isAutoplayPlaying ||
|
|
1244
|
+
isFreeRoundsEngaged,
|
|
1245
|
+
}, children: !isClassicGame && (jsx("span", { className: cx$1({
|
|
1246
|
+
[styles_ui.disabled]: mode !== GAME_MODE.AUTOPLAY ||
|
|
1247
|
+
numberOfPlays !== Infinity ||
|
|
1248
|
+
isAutoplayPlaying,
|
|
1249
|
+
}), children: "\u221E" })) })] })) : null, mode === GAME_MODE.MANUAL ? (jsx(ManualPlayController, {})) : (jsx(AutoPlayController, {}))] }), jsx(WidgetContainer, { state: autoplayState, displayPlayAmountView: displayPlayAmountView, widgets: {
|
|
1250
|
+
left: config.leftWidgets,
|
|
1251
|
+
center: config.centerWidgets,
|
|
1252
|
+
right: config.rightWidgets,
|
|
1253
|
+
} })] }) }))] }));
|
|
1531
1254
|
};
|
|
1532
1255
|
|
|
1533
|
-
export { AUTO_PLAY_STATE, AutoManualPlayProvider,
|
|
1256
|
+
export { AUTO_PLAY_STATE, AutoManualPlayProvider, DOUBLE_OR_NOTHING_STATE, FreeRoundsIntroModal, GAME_MODE, WIDGET, canAutoplaySpaceTrigger, createAutoplayButtonAction, createManualCashoutClickHandler, format, isAutoplayButtonDisabled, isManualCashoutDisabled };
|
|
1534
1257
|
//# sourceMappingURL=index.mjs.map
|