@devrongx/games 0.4.0 → 0.4.2
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
|
@@ -25,6 +25,7 @@ import { useTDMatches } from "../../matches/useTDMatches";
|
|
|
25
25
|
import { buildPMBConfig } from "../../pools/mapper";
|
|
26
26
|
import { joinTDPool, placeTDBets } from "../../pools/actions";
|
|
27
27
|
import type { ITDLeaderboardEntry } from "../../pools/types";
|
|
28
|
+
import { TDPoolStatus } from "../../pools/types";
|
|
28
29
|
import { calcRankPayout } from "./config";
|
|
29
30
|
|
|
30
31
|
const GAME_ID = "pre-match";
|
|
@@ -35,13 +36,13 @@ type UserFlowState = "intro" | "questions" | "game";
|
|
|
35
36
|
type ActiveView = UserFlowState | "submitted" | "live" | "results";
|
|
36
37
|
|
|
37
38
|
function getActiveView(
|
|
38
|
-
poolStatus:
|
|
39
|
+
poolStatus: number | undefined,
|
|
39
40
|
hasEntry: boolean,
|
|
40
41
|
userFlowState: UserFlowState,
|
|
41
42
|
): ActiveView {
|
|
42
|
-
if (
|
|
43
|
-
if (poolStatus ===
|
|
44
|
-
if (poolStatus ===
|
|
43
|
+
if (poolStatus === undefined) return userFlowState;
|
|
44
|
+
if (poolStatus === TDPoolStatus.COMPLETE || poolStatus === TDPoolStatus.CANCELLED) return "results";
|
|
45
|
+
if (poolStatus === TDPoolStatus.CLOSED || poolStatus === TDPoolStatus.RESOLVING) return hasEntry ? "live" : "results";
|
|
45
46
|
// Pool is open
|
|
46
47
|
if (hasEntry) return "submitted";
|
|
47
48
|
return userFlowState;
|
|
@@ -121,7 +122,7 @@ export const PreMatchBetsPopup = ({ poolId, matchId }: PreMatchBetsPopupProps) =
|
|
|
121
122
|
const [submitError, setSubmitError] = useState<string | null>(null);
|
|
122
123
|
|
|
123
124
|
const betSummary = useMemo(
|
|
124
|
-
() => config ? calcBetSummary(bets, config) : { selectedCount: 0, compoundMultiplier: 0, totalEntry: 0, compoundedReward: 0, remainingBalance: 0, riskPercent: 0, potentialBalance: 0
|
|
125
|
+
() => config ? calcBetSummary(bets, config) : { selectedCount: 0, compoundMultiplier: 0, totalEntry: 0, baseReward: 0, compoundedReward: 0, remainingBalance: 0, riskPercent: 0, potentialBalance: 0 },
|
|
125
126
|
[bets, config],
|
|
126
127
|
);
|
|
127
128
|
|
|
@@ -9,6 +9,7 @@ import { IChallengeConfig } from "./config";
|
|
|
9
9
|
import { LeaderboardRow } from "./LeaderboardRow";
|
|
10
10
|
import { OUTFIT, MARKET_ICONS } from "./constants";
|
|
11
11
|
import type { ITDPoolDetail, ITDMyEntryResponse, ITDLeaderboardEntry } from "../../pools/types";
|
|
12
|
+
import { TDChallengeStatus, TDBetStatus } from "../../pools/types";
|
|
12
13
|
|
|
13
14
|
interface PreMatchLiveProps {
|
|
14
15
|
config: IChallengeConfig;
|
|
@@ -50,7 +51,7 @@ export function PreMatchLive({
|
|
|
50
51
|
resolved_at: null as string | null,
|
|
51
52
|
}));
|
|
52
53
|
|
|
53
|
-
const resolvedCount = challenges.filter((c) => c.status ===
|
|
54
|
+
const resolvedCount = challenges.filter((c) => c.status === TDChallengeStatus.RESOLVED).length;
|
|
54
55
|
const totalCount = challenges.length;
|
|
55
56
|
const progressPct = totalCount > 0 ? Math.round((resolvedCount / totalCount) * 100) : 0;
|
|
56
57
|
|
|
@@ -105,9 +106,9 @@ export function PreMatchLive({
|
|
|
105
106
|
{challenges.map((c) => {
|
|
106
107
|
const Icon = MARKET_ICONS[c.icon] ?? MARKET_ICONS.coin;
|
|
107
108
|
const myBet = myBets.find((b) => b.challenge_id === c.id);
|
|
108
|
-
const isResolved = c.status ===
|
|
109
|
-
const won = isResolved && myBet?.status ===
|
|
110
|
-
const lost = isResolved && myBet?.status ===
|
|
109
|
+
const isResolved = c.status === TDChallengeStatus.RESOLVED;
|
|
110
|
+
const won = isResolved && myBet?.status === TDBetStatus.WON;
|
|
111
|
+
const lost = isResolved && myBet?.status === TDBetStatus.LOST;
|
|
111
112
|
|
|
112
113
|
return (
|
|
113
114
|
<div
|
|
@@ -8,6 +8,7 @@ import { IChallengeConfig } from "./config";
|
|
|
8
8
|
import { LeaderboardRow } from "./LeaderboardRow";
|
|
9
9
|
import { OUTFIT, MARKET_ICONS } from "./constants";
|
|
10
10
|
import type { ITDPoolDetail, ITDMyEntryResponse, ITDLeaderboardEntry } from "../../pools/types";
|
|
11
|
+
import { TDBetStatus } from "../../pools/types";
|
|
11
12
|
|
|
12
13
|
// USDC icon inline
|
|
13
14
|
const UsdcIcon = ({ size = 12 }: { size?: number }) => (
|
|
@@ -42,8 +43,8 @@ export function PreMatchResults({
|
|
|
42
43
|
|
|
43
44
|
const stats = useMemo(() => {
|
|
44
45
|
const individualBets = myBets.filter((b) => b.parlay_id === null);
|
|
45
|
-
const won = individualBets.filter((b) => b.status ===
|
|
46
|
-
const lost = individualBets.filter((b) => b.status ===
|
|
46
|
+
const won = individualBets.filter((b) => b.status === TDBetStatus.WON).length;
|
|
47
|
+
const lost = individualBets.filter((b) => b.status === TDBetStatus.LOST).length;
|
|
47
48
|
const totalSpent = individualBets.reduce((s, b) => s + b.coin_amount, 0);
|
|
48
49
|
const totalEarned = entry?.final_coins ?? 0;
|
|
49
50
|
return {
|
|
@@ -116,8 +117,8 @@ export function PreMatchResults({
|
|
|
116
117
|
{myBets.filter((b) => b.parlay_id === null).map((bet) => {
|
|
117
118
|
const market = config.markets.find((m) => m.backendChallengeId === bet.challenge_id);
|
|
118
119
|
const Icon = MARKET_ICONS[market?.icon ?? "coin"];
|
|
119
|
-
const won = bet.status ===
|
|
120
|
-
const lost = bet.status ===
|
|
120
|
+
const won = bet.status === TDBetStatus.WON;
|
|
121
|
+
const lost = bet.status === TDBetStatus.LOST;
|
|
121
122
|
|
|
122
123
|
return (
|
|
123
124
|
<div
|
|
@@ -7,6 +7,7 @@ import { Calendar, MapPin, Loader2, Trophy, Zap, Target, Users } from "lucide-re
|
|
|
7
7
|
import { useTDMatches } from "./useTDMatches";
|
|
8
8
|
import { useTDPools } from "../pools/hooks";
|
|
9
9
|
import type { ITDPool } from "../pools/types";
|
|
10
|
+
import { TDGameType, TDPoolStatus } from "../pools/types";
|
|
10
11
|
import type { ITDMatch } from "./types";
|
|
11
12
|
|
|
12
13
|
// TD match status enum values
|
|
@@ -105,15 +106,16 @@ function groupByDate(matches: ITDMatch[]): IMatchDay[] {
|
|
|
105
106
|
|
|
106
107
|
/* ── Pool pills for a match ── */
|
|
107
108
|
|
|
108
|
-
const GAME_TYPE_STYLE: Record<
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
const GAME_TYPE_STYLE: Record<number, { icon: typeof Target; color: string; bg: string; label: string }> = {
|
|
110
|
+
[TDGameType.PRE_MATCH_BETS]: { icon: Target, color: "#22E3E8", bg: "rgba(34,227,232,0.06)", label: "Pre-Match Bets" },
|
|
111
|
+
[TDGameType.FANTASY_11]: { icon: Users, color: "#9945FF", bg: "rgba(153,69,255,0.06)", label: "Fantasy 11" },
|
|
112
|
+
[TDGameType.BALL_SEQUENCE]: { icon: Zap, color: "#FF9945", bg: "rgba(255,153,69,0.06)", label: "Ball Sequence" },
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
function PoolPill({ pool, onPress }: { pool: ITDPool; onPress: (pool: ITDPool) => void }) {
|
|
114
116
|
const style = GAME_TYPE_STYLE[pool.game_type] ?? { icon: Target, color: "#22E3E8", bg: "rgba(34,227,232,0.06)" };
|
|
115
117
|
const Icon = style.icon;
|
|
116
|
-
const isClosed = pool.status ===
|
|
118
|
+
const isClosed = pool.status === TDPoolStatus.CLOSED || pool.status === TDPoolStatus.RESOLVING || pool.status === TDPoolStatus.COMPLETE;
|
|
117
119
|
|
|
118
120
|
return (
|
|
119
121
|
<button
|
|
@@ -150,13 +152,15 @@ function MatchGameSection({
|
|
|
150
152
|
|
|
151
153
|
if (isCompleted || loading || pools.length === 0) return null;
|
|
152
154
|
|
|
153
|
-
// Group by game_type
|
|
154
|
-
const grouped: Record<
|
|
155
|
+
// Group by game_type (integer)
|
|
156
|
+
const grouped: Record<number, ITDPool[]> = {};
|
|
155
157
|
for (const p of pools) {
|
|
156
158
|
(grouped[p.game_type] ??= []).push(p);
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
const gameTypes = Object.keys(grouped)
|
|
161
|
+
const gameTypes = (Object.keys(grouped) as unknown as number[])
|
|
162
|
+
.map(Number)
|
|
163
|
+
.filter((gt) => gt in GAME_TYPE_STYLE);
|
|
160
164
|
if (gameTypes.length === 0) return null;
|
|
161
165
|
|
|
162
166
|
return (
|
|
@@ -169,7 +173,7 @@ function MatchGameSection({
|
|
|
169
173
|
<div className="flex items-center gap-1 px-1">
|
|
170
174
|
<Icon size={8} style={{ color: style.color }} />
|
|
171
175
|
<span className="text-[7px] barlowcondensedBold tracking-wide text-white/60">
|
|
172
|
-
{
|
|
176
|
+
{style.label}
|
|
173
177
|
</span>
|
|
174
178
|
</div>
|
|
175
179
|
<div className="flex gap-1 flex-wrap">
|
package/src/pools/types.ts
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
// @devrongx/games — pools/types.ts
|
|
2
2
|
// Types matching TD backend pool API responses (pool.repo.ts).
|
|
3
|
+
// Status and game_type fields are integers matching DBEnum values in the TD backend.
|
|
4
|
+
|
|
5
|
+
// ─── Game type constants (mirrors DBEnumGameType in TD backend) ────────────────
|
|
6
|
+
export const TDGameType = {
|
|
7
|
+
PRE_MATCH_BETS: 1,
|
|
8
|
+
FANTASY_11: 2,
|
|
9
|
+
BALL_SEQUENCE: 3,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
// ─── Pool status constants (mirrors DBEnumPoolStatus) ─────────────────────────
|
|
13
|
+
export const TDPoolStatus = {
|
|
14
|
+
DRAFT: 1,
|
|
15
|
+
OPEN: 2,
|
|
16
|
+
CLOSED: 3,
|
|
17
|
+
RESOLVING: 4,
|
|
18
|
+
COMPLETE: 5,
|
|
19
|
+
CANCELLED: 6,
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
// ─── Challenge status constants (mirrors DBEnumChallengeStatus) ────────────────
|
|
23
|
+
export const TDChallengeStatus = {
|
|
24
|
+
DRAFT: 1,
|
|
25
|
+
OPEN: 2,
|
|
26
|
+
CLOSED: 3,
|
|
27
|
+
RESOLVED: 4,
|
|
28
|
+
CANCELLED: 5,
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
// ─── Bet status constants (mirrors DBEnumBetStatus) ───────────────────────────
|
|
32
|
+
export const TDBetStatus = {
|
|
33
|
+
PENDING: 1,
|
|
34
|
+
WON: 2,
|
|
35
|
+
LOST: 3,
|
|
36
|
+
CANCELLED: 4,
|
|
37
|
+
} as const;
|
|
3
38
|
|
|
4
39
|
// ─── Currency ───────────────────────────────────────────────────────────────
|
|
5
40
|
|
|
@@ -15,13 +50,13 @@ export interface ITDCurrency {
|
|
|
15
50
|
export interface ITDPool {
|
|
16
51
|
id: number;
|
|
17
52
|
match_id: number;
|
|
18
|
-
game_type:
|
|
53
|
+
game_type: number; // TDGameType: 1=PRE_MATCH_BETS, 2=FANTASY_11, 3=BALL_SEQUENCE
|
|
19
54
|
name: string;
|
|
20
55
|
machine_name: string | null;
|
|
21
56
|
display_price: string; // "Free" | "$1" | "$5"
|
|
22
57
|
entry_fee: number;
|
|
23
58
|
starting_coins: number;
|
|
24
|
-
status:
|
|
59
|
+
status: number; // TDPoolStatus: 1=DRAFT, 2=OPEN, 3=CLOSED, 4=RESOLVING, 5=COMPLETE, 6=CANCELLED
|
|
25
60
|
entry_count: number;
|
|
26
61
|
challenge_count: number;
|
|
27
62
|
currency: ITDCurrency;
|
|
@@ -47,7 +82,7 @@ export interface ITDChallenge {
|
|
|
47
82
|
accent_color: string;
|
|
48
83
|
sort_order: number;
|
|
49
84
|
options: ITDChallengeOption[];
|
|
50
|
-
status:
|
|
85
|
+
status: number; // TDChallengeStatus: 1=DRAFT, 2=OPEN, 3=CLOSED, 4=RESOLVED, 5=CANCELLED
|
|
51
86
|
correct_option: string | null;
|
|
52
87
|
resolved_at: string | null;
|
|
53
88
|
}
|
|
@@ -155,7 +190,7 @@ export interface ITDPoolBet {
|
|
|
155
190
|
odds_at_bet: number;
|
|
156
191
|
potential_return: number;
|
|
157
192
|
actual_return: number | null;
|
|
158
|
-
status:
|
|
193
|
+
status: number; // TDBetStatus: 1=PENDING, 2=WON, 3=LOST, 4=CANCELLED
|
|
159
194
|
parlay_id: number | null;
|
|
160
195
|
created_at: string;
|
|
161
196
|
}
|
|
@@ -167,14 +202,14 @@ export interface ITDPoolParlay {
|
|
|
167
202
|
combined_multiplier: number;
|
|
168
203
|
potential_return: number;
|
|
169
204
|
actual_return: number | null;
|
|
170
|
-
status:
|
|
205
|
+
status: number; // TDBetStatus: 1=PENDING, 2=WON, 3=LOST, 4=CANCELLED
|
|
171
206
|
bets: {
|
|
172
207
|
id: number;
|
|
173
208
|
challenge_id: number;
|
|
174
209
|
selected_option: string;
|
|
175
210
|
coin_amount: number;
|
|
176
211
|
odds_at_bet: number;
|
|
177
|
-
status:
|
|
212
|
+
status: number; // TDBetStatus
|
|
178
213
|
}[];
|
|
179
214
|
created_at: string;
|
|
180
215
|
}
|