@devrongx/games 0.4.10 → 0.4.12

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrongx/games",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Game UI components for sports prediction markets",
5
5
  "license": "MIT",
6
6
  "main": "./src/index.ts",
@@ -16,7 +16,6 @@ import { GamePopupShell } from "../../core/GamePopupShell";
16
16
  import { PreMatchIntro } from "./PreMatchIntro";
17
17
  import { PreMatchQuestions } from "./PreMatchQuestions";
18
18
  import { PreMatchGame } from "./PreMatchGame";
19
- import { PreMatchSubmitted } from "./PreMatchSubmitted";
20
19
  import { PreMatchLive } from "./PreMatchLive";
21
20
  import { PreMatchResults } from "./PreMatchResults";
22
21
  import { FullLeaderboard } from "./FullLeaderboard";
@@ -34,7 +33,7 @@ const GAME_ID = "pre-match";
34
33
  // ─── View logic ────────────────────────────────────────────────────────────────
35
34
 
36
35
  type UserFlowState = "intro" | "questions" | "game";
37
- type ActiveView = UserFlowState | "submitted" | "live" | "results";
36
+ type ActiveView = UserFlowState | "live" | "results";
38
37
 
39
38
  function getActiveView(
40
39
  poolStatus: number | undefined,
@@ -44,8 +43,7 @@ function getActiveView(
44
43
  if (poolStatus === undefined) return userFlowState;
45
44
  if (poolStatus === TDPoolStatus.COMPLETE || poolStatus === TDPoolStatus.CANCELLED) return "results";
46
45
  if (poolStatus === TDPoolStatus.CLOSED || poolStatus === TDPoolStatus.RESOLVING) return hasEntry ? "live" : "results";
47
- // Pool is open
48
- if (hasEntry) return "submitted";
46
+ // Pool is open — user can keep editing regardless
49
47
  return userFlowState;
50
48
  }
51
49
 
@@ -123,6 +121,31 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
123
121
  const [submitting, setSubmitting] = useState(false);
124
122
  const [submitError, setSubmitError] = useState<string | null>(null);
125
123
 
124
+ // ── Real bets restore: when user has submitted bets, load them into game state ─
125
+ const realBetsRestoredRef = useRef(false);
126
+ useEffect(() => {
127
+ if (!poolId || !config || !entryData || realBetsRestoredRef.current) return;
128
+ if (entryData.bets.length === 0) return;
129
+ const loaded: IUserBets = {};
130
+ const pickers: Record<number, number> = {};
131
+ for (const bet of entryData.bets) {
132
+ if (bet.parlay_id !== null) continue;
133
+ const mIdx = config.markets.findIndex((m) => m.backendChallengeId === bet.challenge_id);
134
+ if (mIdx < 0) continue;
135
+ const oIdx = config.markets[mIdx].options.findIndex(
136
+ (o) => o.label.toLowerCase().replace(/\s+/g, "_") === bet.selected_option,
137
+ );
138
+ if (oIdx < 0) continue;
139
+ loaded[mIdx] = { optionIdx: oIdx, amount: bet.coin_amount, parlaySlot: null };
140
+ pickers[mIdx] = oIdx;
141
+ }
142
+ if (Object.keys(loaded).length === 0) return;
143
+ setBets(loaded);
144
+ setExpandedPicker(pickers);
145
+ setUserFlowState("game");
146
+ realBetsRestoredRef.current = true;
147
+ }, [poolId, config, entryData]);
148
+
126
149
  // ── Draft restore: when entry + config load, seed bets from draft_selections ─
127
150
  const draftRestoredRef = useRef(false);
128
151
  const [restoredSelections, setRestoredSelections] = useState<IUserBets | undefined>(undefined);
@@ -144,10 +167,9 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
144
167
  }
145
168
  const answeredCount = Object.keys(restored).length;
146
169
  if (answeredCount === 0) return;
147
- const allAnswered = answeredCount === config.markets.length;
148
170
  setBets(restored);
149
- if (allAnswered) {
150
- // All questions donego straight to game screen
171
+ if (answeredCount >= 5) {
172
+ // 5+ questions answeredskip straight to game screen
151
173
  setUserFlowState("game");
152
174
  } else {
153
175
  // Partial — restore into questions at the first unanswered question
@@ -277,24 +299,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
277
299
  }
278
300
  }, [poolId, config, bets, hasEntry, refetchEntry, refetchLB, refetchPool]);
279
301
 
280
- const handleAdjust = useCallback(async () => {
281
- // Load server bets back into local state
282
- if (entryData?.bets && config) {
283
- const loaded: IUserBets = {};
284
- for (const bet of entryData.bets) {
285
- if (bet.parlay_id !== null) continue; // skip parlays for now
286
- const mIdx = config.markets.findIndex((m) => m.backendChallengeId === bet.challenge_id);
287
- if (mIdx >= 0) {
288
- // Find option by matching the stored key to a label approximation
289
- // (we store selected_option as the label key from the pool option)
290
- const oIdx = config.markets[mIdx].options.findIndex((_, i) => i === 0); // fallback: first option
291
- loaded[mIdx] = { optionIdx: oIdx, amount: bet.coin_amount, parlaySlot: null };
292
- }
293
- }
294
- setBets(loaded);
295
- }
296
- setUserFlowState("game");
297
- }, [entryData, config]);
298
302
 
299
303
  // ── Loading ────────────────────────────────────────────────────────────────
300
304
  if (poolId && (poolLoading || (!config && !poolLoading))) {
@@ -354,17 +358,6 @@ export const PreMatchBetsPopup = ({ poolId, matchId: _matchId, match: matchProp
354
358
  />
355
359
  )}
356
360
 
357
- {activeView === "submitted" && (
358
- <PreMatchSubmitted
359
- config={config}
360
- poolId={poolId!}
361
- entryData={entryData}
362
- rankings={rankings}
363
- onAdjust={handleAdjust}
364
- onViewLeaderboard={() => setShowFullLeaderboard(true)}
365
- />
366
- )}
367
-
368
361
  {activeView === "live" && (
369
362
  <PreMatchLive
370
363
  config={config}