@devrongx/games 0.4.15 → 0.4.16
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/package.json
CHANGED
|
@@ -115,7 +115,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
115
115
|
|
|
116
116
|
// ── Bet state ─────────────────────────────────────────────────────────────
|
|
117
117
|
const [bets, setBets] = useState<IUserBets>({});
|
|
118
|
-
const [expandedPicker, setExpandedPicker] = useState<Record<number, number>>({});
|
|
119
118
|
const [userFlowState, setUserFlowState] = useState<UserFlowState>("intro");
|
|
120
119
|
const [showFullLeaderboard, setShowFullLeaderboard] = useState(false);
|
|
121
120
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -128,7 +127,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
128
127
|
if (!poolId || !config || !entryData || realBetsRestoredRef.current) return;
|
|
129
128
|
if (entryData.bets.length === 0) return;
|
|
130
129
|
const loaded: IUserBets = {};
|
|
131
|
-
const pickers: Record<number, number> = {};
|
|
132
130
|
for (const bet of entryData.bets) {
|
|
133
131
|
if (bet.parlay_id !== null) continue;
|
|
134
132
|
const mIdx = config.markets.findIndex((m) => m.backendChallengeId === bet.challenge_id);
|
|
@@ -138,12 +136,10 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
138
136
|
);
|
|
139
137
|
if (oIdx < 0) continue;
|
|
140
138
|
loaded[mIdx] = { optionIdx: oIdx, amount: bet.coin_amount, parlaySlot: null };
|
|
141
|
-
pickers[mIdx] = oIdx;
|
|
142
139
|
}
|
|
143
140
|
if (Object.keys(loaded).length === 0) return;
|
|
144
141
|
setBets(loaded);
|
|
145
142
|
setSubmittedBets(loaded);
|
|
146
|
-
setExpandedPicker(pickers);
|
|
147
143
|
setUserFlowState("game");
|
|
148
144
|
realBetsRestoredRef.current = true;
|
|
149
145
|
}, [poolId, config, entryData]);
|
|
@@ -172,12 +168,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
172
168
|
setBets(restored);
|
|
173
169
|
if (answeredCount >= 5) {
|
|
174
170
|
// 5+ questions answered — skip straight to game screen
|
|
175
|
-
// Expand cards that have no amount set so the picker is visible
|
|
176
|
-
const pickers: Record<number, number> = {};
|
|
177
|
-
for (const [mIdxStr, entry] of Object.entries(restored)) {
|
|
178
|
-
if (entry.amount === 0) pickers[Number(mIdxStr)] = entry.optionIdx;
|
|
179
|
-
}
|
|
180
|
-
setExpandedPicker(pickers);
|
|
181
171
|
setUserFlowState("game");
|
|
182
172
|
} else {
|
|
183
173
|
// Partial — restore into questions at the first unanswered question
|
|
@@ -244,11 +234,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
244
234
|
// ── Handlers ─────────────────────────────────────────────────────────────
|
|
245
235
|
const handleQuestionsComplete = useCallback((selections: IUserBets) => {
|
|
246
236
|
setBets(selections);
|
|
247
|
-
const pickers: Record<number, number> = {};
|
|
248
|
-
for (const [mIdxStr, entry] of Object.entries(selections)) {
|
|
249
|
-
pickers[Number(mIdxStr)] = entry.optionIdx;
|
|
250
|
-
}
|
|
251
|
-
setExpandedPicker(pickers);
|
|
252
237
|
setUserFlowState("game");
|
|
253
238
|
}, []);
|
|
254
239
|
|
|
@@ -258,10 +243,8 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
258
243
|
if (existing?.optionIdx === oIdx) {
|
|
259
244
|
const next = { ...prev };
|
|
260
245
|
delete next[mIdx];
|
|
261
|
-
setExpandedPicker((p) => { const n = { ...p }; delete n[mIdx]; return n; });
|
|
262
246
|
return next;
|
|
263
247
|
}
|
|
264
|
-
setExpandedPicker((p) => ({ ...p, [mIdx]: oIdx }));
|
|
265
248
|
return {
|
|
266
249
|
...prev,
|
|
267
250
|
[mIdx]: { optionIdx: oIdx, amount: existing?.amount ?? 0, parlaySlot: existing?.parlaySlot ?? null },
|
|
@@ -364,7 +347,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
|
|
|
364
347
|
config={config}
|
|
365
348
|
bets={bets}
|
|
366
349
|
onBetsChange={setBets}
|
|
367
|
-
expandedPicker={expandedPicker}
|
|
368
350
|
onOptionClick={handleOptionClick}
|
|
369
351
|
onAmountSelect={handleAmountSelect}
|
|
370
352
|
betSummary={betSummary}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @devrongx/games — games/prematch-bets/PreMatchGame.tsx
|
|
2
2
|
"use client";
|
|
3
3
|
|
|
4
|
-
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
4
|
+
import { useState, useEffect, useMemo, useCallback, useRef } from "react";
|
|
5
5
|
import Image from "next/image";
|
|
6
6
|
import { motion, AnimatePresence, useSpring, useTransform, useMotionValue } from "framer-motion";
|
|
7
7
|
import { ChevronDown, Info, X, Play, Check, Loader2 } from "lucide-react";
|
|
@@ -30,7 +30,6 @@ interface PreMatchGameProps {
|
|
|
30
30
|
config: IChallengeConfig;
|
|
31
31
|
bets: IUserBets;
|
|
32
32
|
onBetsChange?: (bets: IUserBets) => void;
|
|
33
|
-
expandedPicker: Record<number, number>; // mIdx → oIdx for open pickers
|
|
34
33
|
onOptionClick: (mIdx: number, oIdx: number) => void;
|
|
35
34
|
onAmountSelect: (mIdx: number, oIdx: number, amount: number) => void;
|
|
36
35
|
betSummary: IBetSummary;
|
|
@@ -50,7 +49,7 @@ interface PreMatchGameProps {
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
|
|
53
|
-
export const PreMatchGame = ({ config, bets, onBetsChange,
|
|
52
|
+
export const PreMatchGame = ({ config, bets, onBetsChange, onOptionClick, onAmountSelect, betSummary, leaderboardRows, marketsOnly, onSubmit, submittedBets, onViewLeaderboard, parlayEnabled = false, submitting = false }: PreMatchGameProps) => {
|
|
54
53
|
const { selectedCount, compoundMultiplier, totalEntry, compoundedReward, remainingBalance, riskPercent } = betSummary;
|
|
55
54
|
|
|
56
55
|
// Button state: fresh (no prior submit), saved (submitted, no changes), changed (submitted, user modified)
|
|
@@ -87,6 +86,16 @@ export const PreMatchGame = ({ config, bets, onBetsChange, expandedPicker, onOpt
|
|
|
87
86
|
});
|
|
88
87
|
}, []);
|
|
89
88
|
|
|
89
|
+
// One-time: when bets are restored with amounts already set, auto-collapse those markets
|
|
90
|
+
const collapseInitializedRef = useRef(false);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (collapseInitializedRef.current) return;
|
|
93
|
+
const withAmounts = Object.entries(bets).filter(([, b]) => b.amount > 0);
|
|
94
|
+
if (withAmounts.length === 0) return;
|
|
95
|
+
setCollapsedMarkets(new Set(withAmounts.map(([k]) => Number(k))));
|
|
96
|
+
collapseInitializedRef.current = true;
|
|
97
|
+
}, [bets]);
|
|
98
|
+
|
|
90
99
|
// Parlay edit mode: which slot is being edited (null = none)
|
|
91
100
|
const [editingParlay, setEditingParlay] = useState<number | null>(null);
|
|
92
101
|
// Parlay info popup: which slot's breakdown is shown (null = none)
|
|
@@ -175,7 +184,7 @@ export const PreMatchGame = ({ config, bets, onBetsChange, expandedPicker, onOpt
|
|
|
175
184
|
<div className="flex flex-col gap-3">
|
|
176
185
|
{config.markets.map((market, mIdx) => {
|
|
177
186
|
const selection = bets[mIdx];
|
|
178
|
-
const isPickerOpenForMarket = mIdx
|
|
187
|
+
const isPickerOpenForMarket = !collapsedMarkets.has(mIdx) && selection !== undefined;
|
|
179
188
|
const showCategoryHeader = categoryFirstIndices.has(mIdx);
|
|
180
189
|
|
|
181
190
|
// Available balance for picker: remaining + current bet on this market (it would be freed)
|
|
@@ -316,7 +325,7 @@ export const PreMatchGame = ({ config, bets, onBetsChange, expandedPicker, onOpt
|
|
|
316
325
|
<div className="grid grid-cols-2 gap-1.5 px-1 pt-0.5 pb-1">
|
|
317
326
|
{market.options.map((opt, j) => {
|
|
318
327
|
const isSelected = selection?.optionIdx === j;
|
|
319
|
-
const isPickerOpen = isPickerOpenForMarket &&
|
|
328
|
+
const isPickerOpen = isPickerOpenForMarket && selection?.optionIdx === j;
|
|
320
329
|
const showPickerRow = isPickerOpenForMarket;
|
|
321
330
|
const displayReward = calcDisplayReward(opt, compoundMultiplier, isSelected, selectedCount, isSelected ? selection.amount : undefined);
|
|
322
331
|
const baseReward = optionReward(opt);
|
|
@@ -407,11 +416,11 @@ export const PreMatchGame = ({ config, bets, onBetsChange, expandedPicker, onOpt
|
|
|
407
416
|
<div className="flex items-center gap-1.5 overflow-x-auto scrollbar-hide py-1 px-0.5">
|
|
408
417
|
<span className="text-[8px] text-white/60 font-semibold flex-shrink-0" style={OUTFIT}>Bet:</span>
|
|
409
418
|
{Array.from({ length: chipCount }, (_, i) => (i + 1) * config.parlayConfig.stakeIncrements).map(amt => {
|
|
410
|
-
const isChipSelected = selection?.
|
|
419
|
+
const isChipSelected = selection?.amount === amt;
|
|
411
420
|
return (
|
|
412
421
|
<div
|
|
413
422
|
key={amt}
|
|
414
|
-
onClick={() => onAmountSelect(mIdx,
|
|
423
|
+
onClick={() => onAmountSelect(mIdx, selection!.optionIdx, amt)}
|
|
415
424
|
className="flex-shrink-0 flex items-center gap-0.5 px-2 py-[3px] rounded cursor-pointer transition-colors relative overflow-hidden"
|
|
416
425
|
style={isChipSelected ? {
|
|
417
426
|
background: "linear-gradient(135deg, #22E3E8, #9945FF, #f83cc5)",
|