@sensiblestats/widget-react 0.43.1 → 0.45.0
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/CHANGELOG.md +24 -0
- package/dist/index.cjs +585 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +582 -121
- package/dist/index.js.map +1 -1
- package/dist/styles.css +34 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/StatsWidget.tsx
|
|
2
|
-
import { useCallback as
|
|
2
|
+
import { useCallback as useCallback6, useEffect as useEffect12, useMemo as useMemo3, useRef as useRef9, useState as useState20 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -69,7 +69,7 @@ var STRINGS = {
|
|
|
69
69
|
tomorrow: "Tomorrow",
|
|
70
70
|
bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.en, "en", now),
|
|
71
71
|
tabChat: "Chat",
|
|
72
|
-
|
|
72
|
+
tabFollowing: "Following",
|
|
73
73
|
tabOdds: "Odds",
|
|
74
74
|
pinLabel: "Track odds",
|
|
75
75
|
unpinLabel: "Stop tracking odds",
|
|
@@ -88,7 +88,10 @@ var STRINGS = {
|
|
|
88
88
|
momentumLabel: "Momentum",
|
|
89
89
|
accordionValueLabel: "Value",
|
|
90
90
|
accordionRetry: "Couldn't load odds \u2014 tap to retry",
|
|
91
|
-
accordionSuspended: "Suspended"
|
|
91
|
+
accordionSuspended: "Suspended",
|
|
92
|
+
tabToday: "Today",
|
|
93
|
+
sectionLive: "Live",
|
|
94
|
+
staleStates: "Live scores can't be updated \u2014 showing the last known state."
|
|
92
95
|
},
|
|
93
96
|
tr: {
|
|
94
97
|
launcherLabel: "SensibleStats ile sohbet et",
|
|
@@ -143,7 +146,7 @@ var STRINGS = {
|
|
|
143
146
|
tomorrow: "Yar\u0131n",
|
|
144
147
|
bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.tr, "tr", now),
|
|
145
148
|
tabChat: "Sohbet",
|
|
146
|
-
|
|
149
|
+
tabFollowing: "Takip",
|
|
147
150
|
tabOdds: "Oranlar",
|
|
148
151
|
pinLabel: "Oran\u0131 takip et",
|
|
149
152
|
unpinLabel: "Oran takibini b\u0131rak",
|
|
@@ -162,7 +165,10 @@ var STRINGS = {
|
|
|
162
165
|
momentumLabel: "Momentum",
|
|
163
166
|
accordionValueLabel: "De\u011Fer",
|
|
164
167
|
accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
|
|
165
|
-
accordionSuspended: "Ask\u0131da"
|
|
168
|
+
accordionSuspended: "Ask\u0131da",
|
|
169
|
+
tabToday: "Bug\xFCn",
|
|
170
|
+
sectionLive: "Canl\u0131",
|
|
171
|
+
staleStates: "Canl\u0131 skorlar g\xFCncellenemiyor \u2014 son bilinen durum g\xF6steriliyor."
|
|
166
172
|
}
|
|
167
173
|
};
|
|
168
174
|
function resolveLocaleStrings(locale) {
|
|
@@ -236,8 +242,11 @@ function normalizeUi(cfg) {
|
|
|
236
242
|
tomorrow: strings.tomorrow,
|
|
237
243
|
bettingKickoff: strings.bettingKickoff,
|
|
238
244
|
tabChat: strings.tabChat,
|
|
239
|
-
|
|
245
|
+
tabFollowing: strings.tabFollowing,
|
|
240
246
|
tabOdds: strings.tabOdds,
|
|
247
|
+
tabToday: strings.tabToday,
|
|
248
|
+
sectionLive: strings.sectionLive,
|
|
249
|
+
staleStates: strings.staleStates,
|
|
241
250
|
pinLabel: strings.pinLabel,
|
|
242
251
|
unpinLabel: strings.unpinLabel,
|
|
243
252
|
matchPinLabel: strings.matchPinLabel,
|
|
@@ -279,6 +288,18 @@ function isTerminal(result) {
|
|
|
279
288
|
if (result.status === "price_changed") return result.accepted;
|
|
280
289
|
return result.status === "added" || result.status === "duplicate";
|
|
281
290
|
}
|
|
291
|
+
function slipOutcome(result) {
|
|
292
|
+
if (!result) return "added";
|
|
293
|
+
switch (result.status) {
|
|
294
|
+
case "added":
|
|
295
|
+
case "duplicate":
|
|
296
|
+
return result.status;
|
|
297
|
+
case "price_changed":
|
|
298
|
+
return result.accepted ? "added" : "price_changed";
|
|
299
|
+
case "rejected":
|
|
300
|
+
return result.reason;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
282
303
|
function resultToToast(result, shownOdds, ui) {
|
|
283
304
|
if (!result) return { kind: "success", text: ui.slipAdded };
|
|
284
305
|
switch (result.status) {
|
|
@@ -300,8 +321,28 @@ import { ENTITY_TYPE_CODES } from "@sensiblestats/widget-sdk";
|
|
|
300
321
|
function isSignalEntityType(value) {
|
|
301
322
|
return Object.prototype.hasOwnProperty.call(ENTITY_TYPE_CODES, value);
|
|
302
323
|
}
|
|
303
|
-
function
|
|
324
|
+
function toWidgetEntityType(value) {
|
|
325
|
+
switch (value.toLowerCase()) {
|
|
326
|
+
case "match":
|
|
327
|
+
return "match";
|
|
328
|
+
case "team":
|
|
329
|
+
return "team";
|
|
330
|
+
case "player":
|
|
331
|
+
return "player";
|
|
332
|
+
case "competition":
|
|
333
|
+
return "competition";
|
|
334
|
+
case "market":
|
|
335
|
+
return "market";
|
|
336
|
+
default:
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function createDashboardTapSignal(sendSignal, log) {
|
|
304
341
|
return (tile, index, layout) => {
|
|
342
|
+
const widgetEntityType = toWidgetEntityType(tile.signal.entityType);
|
|
343
|
+
if (widgetEntityType) {
|
|
344
|
+
log?.log({ name: "tile_tap", entityType: widgetEntityType, entityId: tile.signal.entityId });
|
|
345
|
+
}
|
|
305
346
|
if (!isSignalEntityType(tile.signal.entityType)) return;
|
|
306
347
|
try {
|
|
307
348
|
void sendSignal({
|
|
@@ -1146,6 +1187,7 @@ function useLiveMonitor(opts) {
|
|
|
1146
1187
|
const [chatDot, setChatDot] = useState(false);
|
|
1147
1188
|
const [matchesDot, setMatchesDot] = useState(false);
|
|
1148
1189
|
const [oddsDot, setOddsDot] = useState(false);
|
|
1190
|
+
const [todayDot, setTodayDot] = useState(false);
|
|
1149
1191
|
const [lastViewedPrices, setLastViewedPrices] = useState({});
|
|
1150
1192
|
const [inSlip, setInSlip] = useState({});
|
|
1151
1193
|
const [openMarket, setOpenMarket] = useState({});
|
|
@@ -1162,6 +1204,7 @@ function useLiveMonitor(opts) {
|
|
|
1162
1204
|
openMarketRef.current = openMarket;
|
|
1163
1205
|
const marketOddsRef = useRef3(marketOdds);
|
|
1164
1206
|
marketOddsRef.current = marketOdds;
|
|
1207
|
+
const hasToday = opts.hasToday ?? false;
|
|
1165
1208
|
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
1166
1209
|
const getMarketOddsRef = useRef3(opts.getMarketOdds);
|
|
1167
1210
|
getMarketOddsRef.current = opts.getMarketOdds;
|
|
@@ -1216,7 +1259,7 @@ function useLiveMonitor(opts) {
|
|
|
1216
1259
|
break;
|
|
1217
1260
|
}
|
|
1218
1261
|
}
|
|
1219
|
-
if (sawNewGoalOrRed && activeTabRef.current !== "
|
|
1262
|
+
if (sawNewGoalOrRed && activeTabRef.current !== "following") setMatchesDot(true);
|
|
1220
1263
|
for (const m of next.matches) {
|
|
1221
1264
|
if (!pinnedMatchIds.has(m.matchId)) continue;
|
|
1222
1265
|
const first = m.availableMarkets?.[0];
|
|
@@ -1302,11 +1345,17 @@ function useLiveMonitor(opts) {
|
|
|
1302
1345
|
prevPinsLengthRef.current = pins.length;
|
|
1303
1346
|
if (pins.length === 0) {
|
|
1304
1347
|
window.clearTimeout(timerRef.current);
|
|
1305
|
-
setActiveTabState("chat");
|
|
1306
1348
|
return;
|
|
1307
1349
|
}
|
|
1308
1350
|
if (wasEmpty) void tick();
|
|
1309
1351
|
}, [pins.length, tick]);
|
|
1352
|
+
useEffect3(() => {
|
|
1353
|
+
const matchPins = pins.filter((p) => p.kind === "match").length;
|
|
1354
|
+
const marketPins = pins.length - matchPins;
|
|
1355
|
+
if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
1356
|
+
if (activeTab === "odds" && marketPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
1357
|
+
if (activeTab === "today" && !hasToday) setActiveTabState("chat");
|
|
1358
|
+
}, [pins, activeTab, hasToday]);
|
|
1310
1359
|
const prevIsOpenRef = useRef3(false);
|
|
1311
1360
|
useEffect3(() => {
|
|
1312
1361
|
const wasClosed = !prevIsOpenRef.current;
|
|
@@ -1327,7 +1376,8 @@ function useLiveMonitor(opts) {
|
|
|
1327
1376
|
const setActiveTab = useCallback2((tab) => {
|
|
1328
1377
|
setActiveTabState(tab);
|
|
1329
1378
|
if (tab === "chat") setChatDot(false);
|
|
1330
|
-
if (tab === "
|
|
1379
|
+
if (tab === "today") setTodayDot(false);
|
|
1380
|
+
if (tab === "following") {
|
|
1331
1381
|
setMatchesDot(false);
|
|
1332
1382
|
void tick();
|
|
1333
1383
|
}
|
|
@@ -1347,6 +1397,9 @@ function useLiveMonitor(opts) {
|
|
|
1347
1397
|
const togglePin = useCallback2((pin) => store.toggle(pin), [store]);
|
|
1348
1398
|
const isPinned = useCallback2((key) => pinsRef.current.some((p) => p.key === key), []);
|
|
1349
1399
|
const markChatActivity = useCallback2(() => setChatDot(true), []);
|
|
1400
|
+
const markTodayActivity = useCallback2(() => {
|
|
1401
|
+
if (activeTabRef.current !== "today") setTodayDot(true);
|
|
1402
|
+
}, []);
|
|
1350
1403
|
const markInSlip = useCallback2((matchOddsId) => {
|
|
1351
1404
|
setInSlip((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
|
|
1352
1405
|
}, []);
|
|
@@ -1362,6 +1415,8 @@ function useLiveMonitor(opts) {
|
|
|
1362
1415
|
markChatActivity,
|
|
1363
1416
|
matchesDot,
|
|
1364
1417
|
oddsDot,
|
|
1418
|
+
todayDot,
|
|
1419
|
+
markTodayActivity,
|
|
1365
1420
|
lastViewedPrices,
|
|
1366
1421
|
inSlip,
|
|
1367
1422
|
markInSlip,
|
|
@@ -1373,11 +1428,198 @@ function useLiveMonitor(opts) {
|
|
|
1373
1428
|
};
|
|
1374
1429
|
}
|
|
1375
1430
|
|
|
1431
|
+
// src/useMatchDiscovery.ts
|
|
1432
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState2 } from "react";
|
|
1433
|
+
|
|
1434
|
+
// src/scheduleCache.ts
|
|
1435
|
+
var PREFIX = "ss-w-schedule:";
|
|
1436
|
+
var SCHEMA_VERSION = 1;
|
|
1437
|
+
var TTL_MS2 = 6 * 36e5;
|
|
1438
|
+
function scheduleCacheKey(operatorId, localDate) {
|
|
1439
|
+
return `${PREFIX}${operatorId}:${localDate}`;
|
|
1440
|
+
}
|
|
1441
|
+
function read(operatorId, localDate) {
|
|
1442
|
+
try {
|
|
1443
|
+
const raw = localStorage.getItem(scheduleCacheKey(operatorId, localDate));
|
|
1444
|
+
if (!raw) return null;
|
|
1445
|
+
const entry = JSON.parse(raw);
|
|
1446
|
+
if (entry.v !== SCHEMA_VERSION || !entry.payload) return null;
|
|
1447
|
+
return entry;
|
|
1448
|
+
} catch {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
function readSchedule(operatorId, localDate, nowMs) {
|
|
1453
|
+
const entry = read(operatorId, localDate);
|
|
1454
|
+
if (!entry) return null;
|
|
1455
|
+
return nowMs - entry.at > TTL_MS2 ? null : entry.payload;
|
|
1456
|
+
}
|
|
1457
|
+
function readScheduleIgnoringTtl(operatorId, localDate) {
|
|
1458
|
+
return read(operatorId, localDate)?.payload ?? null;
|
|
1459
|
+
}
|
|
1460
|
+
function skeletonOnly(payload) {
|
|
1461
|
+
return {
|
|
1462
|
+
localDate: payload.localDate,
|
|
1463
|
+
groups: payload.groups.map((g) => ({
|
|
1464
|
+
competitionId: g.competitionId,
|
|
1465
|
+
competitionName: g.competitionName,
|
|
1466
|
+
competitionImagePath: g.competitionImagePath ?? null,
|
|
1467
|
+
rank: g.rank,
|
|
1468
|
+
expandedByDefault: g.expandedByDefault,
|
|
1469
|
+
matches: g.matches.map((m) => ({
|
|
1470
|
+
matchId: m.matchId,
|
|
1471
|
+
homeTeamName: m.homeTeamName,
|
|
1472
|
+
awayTeamName: m.awayTeamName,
|
|
1473
|
+
homeTeamImagePath: m.homeTeamImagePath ?? null,
|
|
1474
|
+
awayTeamImagePath: m.awayTeamImagePath ?? null,
|
|
1475
|
+
kickoffUnix: m.kickoffUnix
|
|
1476
|
+
}))
|
|
1477
|
+
}))
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
function writeSchedule(operatorId, localDate, payload, nowMs) {
|
|
1481
|
+
const keep = scheduleCacheKey(operatorId, localDate);
|
|
1482
|
+
const mine = `${PREFIX}${operatorId}:`;
|
|
1483
|
+
try {
|
|
1484
|
+
for (let i = localStorage.length - 1; i >= 0; i--) {
|
|
1485
|
+
const key = localStorage.key(i);
|
|
1486
|
+
if (key && key.startsWith(mine) && key !== keep) localStorage.removeItem(key);
|
|
1487
|
+
}
|
|
1488
|
+
const entry = { v: SCHEMA_VERSION, at: nowMs, payload: skeletonOnly(payload) };
|
|
1489
|
+
localStorage.setItem(keep, JSON.stringify(entry));
|
|
1490
|
+
} catch {
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// src/dueSet.ts
|
|
1495
|
+
var WINDOW_MS = 3.5 * 36e5;
|
|
1496
|
+
function dueMatchIds(groups, states, nowMs) {
|
|
1497
|
+
const due = /* @__PURE__ */ new Set();
|
|
1498
|
+
for (const group of groups) {
|
|
1499
|
+
for (const match of group.matches) {
|
|
1500
|
+
const sinceKickoff = nowMs - match.kickoffUnix * 1e3;
|
|
1501
|
+
if (sinceKickoff >= 0 && sinceKickoff <= WINDOW_MS) due.add(match.matchId);
|
|
1502
|
+
if (states[match.matchId]?.phase === "live") due.add(match.matchId);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return [...due];
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// src/useMatchDiscovery.ts
|
|
1509
|
+
var POLL_MS = 6e4;
|
|
1510
|
+
var ROLLOVER_CHECK_MS = 6e4;
|
|
1511
|
+
var STALE_AFTER_FAILURES = 2;
|
|
1512
|
+
function localDateOf(now) {
|
|
1513
|
+
const y = now.getFullYear();
|
|
1514
|
+
const m = `${now.getMonth() + 1}`.padStart(2, "0");
|
|
1515
|
+
const d = `${now.getDate()}`.padStart(2, "0");
|
|
1516
|
+
return `${y}-${m}-${d}`;
|
|
1517
|
+
}
|
|
1518
|
+
function useMatchDiscovery(opts) {
|
|
1519
|
+
const [groups, setGroups] = useState2([]);
|
|
1520
|
+
const [states, setStates] = useState2({});
|
|
1521
|
+
const [failures, setFailures] = useState2(0);
|
|
1522
|
+
const [expanded, setExpanded] = useState2({});
|
|
1523
|
+
const [touched, setTouched] = useState2({});
|
|
1524
|
+
const groupsRef = useRef4(groups);
|
|
1525
|
+
groupsRef.current = groups;
|
|
1526
|
+
const statesRef = useRef4(states);
|
|
1527
|
+
statesRef.current = states;
|
|
1528
|
+
const getStatesRef = useRef4(opts.getStates);
|
|
1529
|
+
getStatesRef.current = opts.getStates;
|
|
1530
|
+
const pinnedKey = opts.pinnedMatchIds.join(",");
|
|
1531
|
+
const [localDate, setLocalDate] = useState2(() => localDateOf(/* @__PURE__ */ new Date()));
|
|
1532
|
+
useEffect4(() => {
|
|
1533
|
+
const id = setInterval(() => {
|
|
1534
|
+
const next = localDateOf(/* @__PURE__ */ new Date());
|
|
1535
|
+
setLocalDate((prev) => prev === next ? prev : next);
|
|
1536
|
+
}, ROLLOVER_CHECK_MS);
|
|
1537
|
+
return () => clearInterval(id);
|
|
1538
|
+
}, []);
|
|
1539
|
+
useEffect4(() => {
|
|
1540
|
+
let cancelled = false;
|
|
1541
|
+
const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
1542
|
+
const cached = readSchedule(opts.operatorId, localDate, Date.now());
|
|
1543
|
+
if (cached) {
|
|
1544
|
+
if (!cancelled) setGroups(cached.groups);
|
|
1545
|
+
return () => {
|
|
1546
|
+
cancelled = true;
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
void (async () => {
|
|
1550
|
+
try {
|
|
1551
|
+
const payload = await opts.getSchedule(localDate, utcOffsetMinutes);
|
|
1552
|
+
if (cancelled || !payload) return;
|
|
1553
|
+
writeSchedule(opts.operatorId, localDate, payload, Date.now());
|
|
1554
|
+
setGroups(payload.groups);
|
|
1555
|
+
} catch {
|
|
1556
|
+
const fallback = readScheduleIgnoringTtl(opts.operatorId, localDate);
|
|
1557
|
+
if (!cancelled && fallback) setGroups(fallback.groups);
|
|
1558
|
+
}
|
|
1559
|
+
})();
|
|
1560
|
+
return () => {
|
|
1561
|
+
cancelled = true;
|
|
1562
|
+
};
|
|
1563
|
+
}, [opts.operatorId, localDate]);
|
|
1564
|
+
useEffect4(() => {
|
|
1565
|
+
setExpanded((prev) => {
|
|
1566
|
+
const next = {};
|
|
1567
|
+
for (const group of groups) {
|
|
1568
|
+
const hasPin = group.matches.some((m) => opts.pinnedMatchIds.includes(m.matchId));
|
|
1569
|
+
const seeded = group.expandedByDefault || hasPin;
|
|
1570
|
+
next[group.competitionId] = touched[group.competitionId] ? prev[group.competitionId] ?? seeded : seeded;
|
|
1571
|
+
}
|
|
1572
|
+
return next;
|
|
1573
|
+
});
|
|
1574
|
+
}, [groups, pinnedKey, touched]);
|
|
1575
|
+
const tick = useCallback3(async () => {
|
|
1576
|
+
const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now());
|
|
1577
|
+
if (ids.length === 0) return;
|
|
1578
|
+
try {
|
|
1579
|
+
const payload = await getStatesRef.current(ids);
|
|
1580
|
+
if (!payload) return;
|
|
1581
|
+
setStates((prev) => {
|
|
1582
|
+
const next = { ...prev };
|
|
1583
|
+
for (const state of payload.states) next[state.matchId] = state;
|
|
1584
|
+
return next;
|
|
1585
|
+
});
|
|
1586
|
+
setFailures(0);
|
|
1587
|
+
} catch {
|
|
1588
|
+
setFailures((n) => n + 1);
|
|
1589
|
+
}
|
|
1590
|
+
}, []);
|
|
1591
|
+
useEffect4(() => {
|
|
1592
|
+
if (!opts.isOpen) return;
|
|
1593
|
+
void tick();
|
|
1594
|
+
const id = setInterval(() => {
|
|
1595
|
+
void tick();
|
|
1596
|
+
}, POLL_MS);
|
|
1597
|
+
return () => clearInterval(id);
|
|
1598
|
+
}, [opts.isOpen, tick, groups]);
|
|
1599
|
+
const stale = failures >= STALE_AFTER_FAILURES;
|
|
1600
|
+
const liveCount = useMemo2(
|
|
1601
|
+
() => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
|
|
1602
|
+
[states, stale]
|
|
1603
|
+
);
|
|
1604
|
+
const toggleGroup = useCallback3((competitionId) => {
|
|
1605
|
+
setTouched((prev) => ({ ...prev, [competitionId]: true }));
|
|
1606
|
+
setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
|
|
1607
|
+
}, []);
|
|
1608
|
+
return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick };
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
// src/eventLogContext.ts
|
|
1612
|
+
import { createContext, useContext } from "react";
|
|
1613
|
+
var EventLogContext = createContext(null);
|
|
1614
|
+
function useEventLog() {
|
|
1615
|
+
return useContext(EventLogContext);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1376
1618
|
// src/components/ChatFab.tsx
|
|
1377
|
-
import { useEffect as
|
|
1619
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
|
|
1378
1620
|
|
|
1379
1621
|
// src/components/BrandMark.tsx
|
|
1380
|
-
import { useState as
|
|
1622
|
+
import { useState as useState3 } from "react";
|
|
1381
1623
|
|
|
1382
1624
|
// src/assets/logo.ts
|
|
1383
1625
|
var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
|
|
@@ -1426,7 +1668,7 @@ function DashboardIcon({ name }) {
|
|
|
1426
1668
|
// src/components/BrandMark.tsx
|
|
1427
1669
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1428
1670
|
function BrandMark({ logoUrl, className }) {
|
|
1429
|
-
const [failed, setFailed] =
|
|
1671
|
+
const [failed, setFailed] = useState3(false);
|
|
1430
1672
|
if (!logoUrl || failed) return /* @__PURE__ */ jsx2(SsMark, { className });
|
|
1431
1673
|
return /* @__PURE__ */ jsx2("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1432
1674
|
}
|
|
@@ -1451,9 +1693,9 @@ function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
|
|
|
1451
1693
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1452
1694
|
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
|
|
1453
1695
|
const bubble = popupText ?? greeting;
|
|
1454
|
-
const [intro, setIntro] =
|
|
1455
|
-
const armedRef =
|
|
1456
|
-
|
|
1696
|
+
const [intro, setIntro] = useState4(false);
|
|
1697
|
+
const armedRef = useRef5(introAllowed);
|
|
1698
|
+
useEffect5(() => {
|
|
1457
1699
|
if (armedRef.current && bubble) {
|
|
1458
1700
|
armedRef.current = false;
|
|
1459
1701
|
setIntro(true);
|
|
@@ -1467,10 +1709,10 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
|
|
|
1467
1709
|
}
|
|
1468
1710
|
|
|
1469
1711
|
// src/components/ChatPanel.tsx
|
|
1470
|
-
import { useEffect as
|
|
1712
|
+
import { useEffect as useEffect11, useState as useState19 } from "react";
|
|
1471
1713
|
|
|
1472
1714
|
// src/components/ChatHeader.tsx
|
|
1473
|
-
import { useEffect as
|
|
1715
|
+
import { useEffect as useEffect6, useRef as useRef6, useState as useState5 } from "react";
|
|
1474
1716
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1475
1717
|
function ChatHeader({
|
|
1476
1718
|
onClose,
|
|
@@ -1482,15 +1724,15 @@ function ChatHeader({
|
|
|
1482
1724
|
newConversationLabel = "New conversation",
|
|
1483
1725
|
moreOptionsLabel = "More options"
|
|
1484
1726
|
}) {
|
|
1485
|
-
const [menuOpen, setMenuOpen] =
|
|
1486
|
-
const wrapRef =
|
|
1487
|
-
const kebabRef =
|
|
1488
|
-
const firstItemRef =
|
|
1727
|
+
const [menuOpen, setMenuOpen] = useState5(false);
|
|
1728
|
+
const wrapRef = useRef6(null);
|
|
1729
|
+
const kebabRef = useRef6(null);
|
|
1730
|
+
const firstItemRef = useRef6(null);
|
|
1489
1731
|
const hasMenu = !!(canReset && onNewConversation);
|
|
1490
|
-
|
|
1732
|
+
useEffect6(() => {
|
|
1491
1733
|
if (menuOpen) firstItemRef.current?.focus();
|
|
1492
1734
|
}, [menuOpen]);
|
|
1493
|
-
|
|
1735
|
+
useEffect6(() => {
|
|
1494
1736
|
if (!menuOpen) return;
|
|
1495
1737
|
const onPointer = (e) => {
|
|
1496
1738
|
if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
|
|
@@ -1546,7 +1788,7 @@ function ChatHeader({
|
|
|
1546
1788
|
}
|
|
1547
1789
|
|
|
1548
1790
|
// src/components/MessageList.tsx
|
|
1549
|
-
import { useEffect as
|
|
1791
|
+
import { useEffect as useEffect10, useRef as useRef8 } from "react";
|
|
1550
1792
|
|
|
1551
1793
|
// src/components/Markdown.tsx
|
|
1552
1794
|
import ReactMarkdown from "react-markdown";
|
|
@@ -1564,7 +1806,7 @@ function Markdown({ text }) {
|
|
|
1564
1806
|
}
|
|
1565
1807
|
|
|
1566
1808
|
// src/components/EntityCardList.tsx
|
|
1567
|
-
import { useState as
|
|
1809
|
+
import { useState as useState6 } from "react";
|
|
1568
1810
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1569
1811
|
var MAX_VISIBLE = 3;
|
|
1570
1812
|
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
@@ -1648,7 +1890,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
|
|
|
1648
1890
|
)) });
|
|
1649
1891
|
}
|
|
1650
1892
|
function EntityCardItem({ c }) {
|
|
1651
|
-
const [active, setActive] =
|
|
1893
|
+
const [active, setActive] = useState6(0);
|
|
1652
1894
|
const hasBody = c.scopes.length > 0;
|
|
1653
1895
|
if (!hasBody) {
|
|
1654
1896
|
return /* @__PURE__ */ jsx7("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx7(CardHeader, { c, showScopeCrest: false }) });
|
|
@@ -1662,7 +1904,7 @@ function EntityCardItem({ c }) {
|
|
|
1662
1904
|
] });
|
|
1663
1905
|
}
|
|
1664
1906
|
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1665
|
-
const [expanded, setExpanded] =
|
|
1907
|
+
const [expanded, setExpanded] = useState6(false);
|
|
1666
1908
|
if (cards.length === 0) return null;
|
|
1667
1909
|
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1668
1910
|
const overflow = cards.length - MAX_VISIBLE;
|
|
@@ -1673,18 +1915,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
1673
1915
|
}
|
|
1674
1916
|
|
|
1675
1917
|
// src/components/BettingInsightList.tsx
|
|
1676
|
-
import { useState as
|
|
1918
|
+
import { useState as useState10 } from "react";
|
|
1677
1919
|
|
|
1678
1920
|
// src/components/AddToSlipButton.tsx
|
|
1679
|
-
import { useCallback as
|
|
1921
|
+
import { useCallback as useCallback4, useState as useState7 } from "react";
|
|
1680
1922
|
import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
|
|
1681
1923
|
|
|
1682
1924
|
// src/components/Toast.tsx
|
|
1683
|
-
import { useEffect as
|
|
1925
|
+
import { useEffect as useEffect7 } from "react";
|
|
1684
1926
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1685
1927
|
var DISMISS_MS = 4e3;
|
|
1686
1928
|
function Toast({ toast, onDismiss }) {
|
|
1687
|
-
|
|
1929
|
+
useEffect7(() => {
|
|
1688
1930
|
if (!toast) return;
|
|
1689
1931
|
const timer = setTimeout(onDismiss, DISMISS_MS);
|
|
1690
1932
|
return () => clearTimeout(timer);
|
|
@@ -1701,19 +1943,32 @@ function withTimeout(value) {
|
|
|
1701
1943
|
new Promise((_, reject) => setTimeout(() => reject(new Error("add-to-slip timed out")), ADD_TO_SLIP_TIMEOUT_MS))
|
|
1702
1944
|
]);
|
|
1703
1945
|
}
|
|
1704
|
-
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
1705
|
-
const [pending, setPending] =
|
|
1706
|
-
const [settled, setSettled] =
|
|
1707
|
-
const [toast, setToast] =
|
|
1708
|
-
const dismiss =
|
|
1946
|
+
function SlipButton({ selection, shownOdds, marketName, marketDeveloperName, slip, ui }) {
|
|
1947
|
+
const [pending, setPending] = useState7(false);
|
|
1948
|
+
const [settled, setSettled] = useState7(false);
|
|
1949
|
+
const [toast, setToast] = useState7(null);
|
|
1950
|
+
const dismiss = useCallback4(() => setToast(null), []);
|
|
1951
|
+
const log = useEventLog();
|
|
1709
1952
|
const handler = slip.onAddToSlip;
|
|
1710
1953
|
if (!ui || !handler || !selection) return null;
|
|
1711
1954
|
const onClick = async () => {
|
|
1712
1955
|
setPending(true);
|
|
1956
|
+
if (marketDeveloperName !== void 0) {
|
|
1957
|
+
log?.log({ name: "slip_click", entityType: "market", marketDeveloperName, entityId: marketDeveloperName });
|
|
1958
|
+
}
|
|
1713
1959
|
try {
|
|
1714
1960
|
const raw = await withTimeout(Promise.resolve(handler(selection)));
|
|
1715
1961
|
if (raw != null && !isAddToSlipResult(raw)) throw new Error("malformed add-to-slip result");
|
|
1716
1962
|
const result = raw ?? void 0;
|
|
1963
|
+
if (marketDeveloperName !== void 0) {
|
|
1964
|
+
log?.log({
|
|
1965
|
+
name: "slip_result",
|
|
1966
|
+
entityType: "market",
|
|
1967
|
+
marketDeveloperName,
|
|
1968
|
+
entityId: marketDeveloperName,
|
|
1969
|
+
outcome: slipOutcome(result)
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1717
1972
|
setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui));
|
|
1718
1973
|
setSettled(isTerminal(result));
|
|
1719
1974
|
if (wasAdded(result) && slip.onMarketClicked) {
|
|
@@ -1723,6 +1978,9 @@ function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
|
1723
1978
|
}
|
|
1724
1979
|
}
|
|
1725
1980
|
} catch {
|
|
1981
|
+
if (marketDeveloperName !== void 0) {
|
|
1982
|
+
log?.log({ name: "slip_result", entityType: "market", marketDeveloperName, entityId: marketDeveloperName, outcome: "timeout" });
|
|
1983
|
+
}
|
|
1726
1984
|
setToast({ kind: "error", text: ui.slipFailed });
|
|
1727
1985
|
} finally {
|
|
1728
1986
|
setPending(false);
|
|
@@ -1744,7 +2002,17 @@ function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
|
1744
2002
|
}
|
|
1745
2003
|
function AddToSlipButton({ it, slip, ui }) {
|
|
1746
2004
|
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
1747
|
-
return /* @__PURE__ */ jsx9(
|
|
2005
|
+
return /* @__PURE__ */ jsx9(
|
|
2006
|
+
SlipButton,
|
|
2007
|
+
{
|
|
2008
|
+
selection,
|
|
2009
|
+
shownOdds: it.odds ?? "",
|
|
2010
|
+
marketName: it.market,
|
|
2011
|
+
marketDeveloperName: it.marketDeveloperName,
|
|
2012
|
+
slip,
|
|
2013
|
+
ui
|
|
2014
|
+
}
|
|
2015
|
+
);
|
|
1748
2016
|
}
|
|
1749
2017
|
|
|
1750
2018
|
// src/components/OddsMovementBadge.tsx
|
|
@@ -1769,14 +2037,14 @@ function OddsMovementBadge({
|
|
|
1769
2037
|
}
|
|
1770
2038
|
|
|
1771
2039
|
// src/components/Crest.tsx
|
|
1772
|
-
import { useState as
|
|
2040
|
+
import { useState as useState8 } from "react";
|
|
1773
2041
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1774
2042
|
function initials2(name) {
|
|
1775
2043
|
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1776
2044
|
}
|
|
1777
2045
|
function Crest2({ url, name, kind }) {
|
|
1778
2046
|
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1779
|
-
const [failed, setFailed] =
|
|
2047
|
+
const [failed, setFailed] = useState8(false);
|
|
1780
2048
|
if (url && !failed) {
|
|
1781
2049
|
return /* @__PURE__ */ jsx11("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1782
2050
|
}
|
|
@@ -1784,7 +2052,7 @@ function Crest2({ url, name, kind }) {
|
|
|
1784
2052
|
}
|
|
1785
2053
|
|
|
1786
2054
|
// src/components/PinToggle.tsx
|
|
1787
|
-
import { useCallback as
|
|
2055
|
+
import { useCallback as useCallback5, useState as useState9 } from "react";
|
|
1788
2056
|
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1789
2057
|
var PIN_GLYPHS = {
|
|
1790
2058
|
pin: { viewBox: "0 0 24 24", strokeWidth: 1.4, transform: "scale(1.5)", d: "M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z" },
|
|
@@ -1792,15 +2060,23 @@ var PIN_GLYPHS = {
|
|
|
1792
2060
|
bookmark: { viewBox: "0 0 24 24", strokeWidth: 2, d: "M7 3h10a1.5 1.5 0 0 1 1.5 1.5V21l-6.5-3.6L5.5 21V4.5A1.5 1.5 0 0 1 7 3z" }
|
|
1793
2061
|
};
|
|
1794
2062
|
function PinToggle({ pin, monitor, ui }) {
|
|
1795
|
-
const [toast, setToast] =
|
|
1796
|
-
const dismiss =
|
|
2063
|
+
const [toast, setToast] = useState9(null);
|
|
2064
|
+
const dismiss = useCallback5(() => setToast(null), []);
|
|
2065
|
+
const log = useEventLog();
|
|
1797
2066
|
if (!monitor || !monitor.enabled) return null;
|
|
1798
2067
|
const key = pinKey(pin);
|
|
1799
2068
|
const pinned = monitor.isPinned(key);
|
|
1800
2069
|
const labels = pin.kind === "match" ? { pin: ui.matchPinLabel, unpin: ui.matchUnpinLabel } : { pin: ui.pinLabel, unpin: ui.unpinLabel };
|
|
1801
2070
|
const onClick = () => {
|
|
1802
2071
|
const result = monitor.togglePin({ ...pin, key });
|
|
1803
|
-
if (result === "
|
|
2072
|
+
if ((result === "added" || result === "removed") && (pin.kind === "match" || pin.marketDeveloperName !== void 0)) {
|
|
2073
|
+
log?.log({
|
|
2074
|
+
name: result === "added" ? "pin_add" : "pin_remove",
|
|
2075
|
+
entityType: pin.kind === "match" ? "match" : "market",
|
|
2076
|
+
entityId: pin.kind === "match" ? String(pin.matchId) : pin.marketDeveloperName,
|
|
2077
|
+
marketDeveloperName: pin.marketDeveloperName
|
|
2078
|
+
});
|
|
2079
|
+
} else if (result === "match_limit") {
|
|
1804
2080
|
setToast({ kind: "error", text: ui.matchLimitToast });
|
|
1805
2081
|
} else if (result === "market_limit") {
|
|
1806
2082
|
setToast({ kind: "error", text: ui.marketLimitToast });
|
|
@@ -1845,7 +2121,7 @@ function StatRows({ stats }) {
|
|
|
1845
2121
|
] }, `${s.label}:${s.value}`)) });
|
|
1846
2122
|
}
|
|
1847
2123
|
function ScopedStats({ scopes }) {
|
|
1848
|
-
const [active, setActive] =
|
|
2124
|
+
const [active, setActive] = useState10(0);
|
|
1849
2125
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1850
2126
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-scoped", children: [
|
|
1851
2127
|
/* @__PURE__ */ jsx13("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx13("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
@@ -1856,12 +2132,20 @@ function hasStatsContent(it) {
|
|
|
1856
2132
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1857
2133
|
}
|
|
1858
2134
|
function ReasonStrip({ it, ui }) {
|
|
1859
|
-
const [open, setOpen] =
|
|
2135
|
+
const [open, setOpen] = useState10(false);
|
|
2136
|
+
const log = useEventLog();
|
|
1860
2137
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1861
2138
|
const hasStats = hasStatsContent(it);
|
|
1862
2139
|
const hasText = !!it.text;
|
|
1863
2140
|
if (!hasText && !hasStats) return null;
|
|
1864
2141
|
const expandable = hasStats || (it.text?.length ?? 0) > 90;
|
|
2142
|
+
const onToggle = () => {
|
|
2143
|
+
setOpen((v) => {
|
|
2144
|
+
const next = !v;
|
|
2145
|
+
if (next) log?.log({ name: "insight_expand", entityType: "match", entityId: String(it.matchId) });
|
|
2146
|
+
return next;
|
|
2147
|
+
});
|
|
2148
|
+
};
|
|
1865
2149
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-reason", children: [
|
|
1866
2150
|
/* @__PURE__ */ jsx13("span", { className: "ss-w-bi-chart", "aria-hidden": "true" }),
|
|
1867
2151
|
/* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-reason-body", children: [
|
|
@@ -1875,7 +2159,7 @@ function ReasonStrip({ it, ui }) {
|
|
|
1875
2159
|
className: "ss-w-bi-expand",
|
|
1876
2160
|
"aria-expanded": open,
|
|
1877
2161
|
"aria-label": open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats",
|
|
1878
|
-
onClick:
|
|
2162
|
+
onClick: onToggle,
|
|
1879
2163
|
children: /* @__PURE__ */ jsx13("span", { className: `ss-w-bi-arrow${open ? " ss-w-bi-arrow-open" : ""}`, "aria-hidden": "true" })
|
|
1880
2164
|
}
|
|
1881
2165
|
) : null
|
|
@@ -1968,7 +2252,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
1968
2252
|
}
|
|
1969
2253
|
|
|
1970
2254
|
// src/components/MarketOddsCardList.tsx
|
|
1971
|
-
import { useState as
|
|
2255
|
+
import { useState as useState11 } from "react";
|
|
1972
2256
|
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1973
2257
|
function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
1974
2258
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
@@ -1981,11 +2265,11 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
1981
2265
|
"\u2713 ",
|
|
1982
2266
|
ui.inSlipLabel
|
|
1983
2267
|
] }) : null,
|
|
1984
|
-
/* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
2268
|
+
/* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, marketDeveloperName: vm.marketDeveloperName, slip, ui })
|
|
1985
2269
|
] });
|
|
1986
2270
|
}
|
|
1987
2271
|
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
|
|
1988
|
-
const [open, setOpen] =
|
|
2272
|
+
const [open, setOpen] = useState11(false);
|
|
1989
2273
|
const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
1990
2274
|
const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
|
|
1991
2275
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
@@ -2288,7 +2572,7 @@ function FixtureCard({ card }) {
|
|
|
2288
2572
|
}
|
|
2289
2573
|
|
|
2290
2574
|
// src/components/dashboard/CountdownCard.tsx
|
|
2291
|
-
import { Fragment as Fragment6, useEffect as
|
|
2575
|
+
import { Fragment as Fragment6, useEffect as useEffect8, useState as useState12 } from "react";
|
|
2292
2576
|
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2293
2577
|
var DAY_MS = 864e5;
|
|
2294
2578
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -2307,12 +2591,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
|
2307
2591
|
function CountdownCard({ card }) {
|
|
2308
2592
|
const { data } = card;
|
|
2309
2593
|
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
2310
|
-
const [nowMs, setNowMs] =
|
|
2311
|
-
const [reduced] =
|
|
2594
|
+
const [nowMs, setNowMs] = useState12(() => Date.now());
|
|
2595
|
+
const [reduced] = useState12(
|
|
2312
2596
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
2313
2597
|
);
|
|
2314
2598
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
2315
|
-
|
|
2599
|
+
useEffect8(() => {
|
|
2316
2600
|
if (reduced) return;
|
|
2317
2601
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
2318
2602
|
return () => window.clearInterval(id);
|
|
@@ -2331,7 +2615,7 @@ function CountdownCard({ card }) {
|
|
|
2331
2615
|
}
|
|
2332
2616
|
|
|
2333
2617
|
// src/components/dashboard/InjuriesCard.tsx
|
|
2334
|
-
import { useState as
|
|
2618
|
+
import { useState as useState13 } from "react";
|
|
2335
2619
|
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2336
2620
|
var SHOWN = 3;
|
|
2337
2621
|
function ColHead({ name, crestUrl }) {
|
|
@@ -2354,7 +2638,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
|
|
|
2354
2638
|
}
|
|
2355
2639
|
function InjuriesCard({ card, ui }) {
|
|
2356
2640
|
const { data } = card;
|
|
2357
|
-
const [expanded, setExpanded] =
|
|
2641
|
+
const [expanded, setExpanded] = useState13(false);
|
|
2358
2642
|
const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
|
|
2359
2643
|
const limit = expanded ? void 0 : SHOWN;
|
|
2360
2644
|
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
@@ -2458,7 +2742,7 @@ function LinksCard({ card }) {
|
|
|
2458
2742
|
}
|
|
2459
2743
|
|
|
2460
2744
|
// src/components/dashboard/PostMatchResultCard.tsx
|
|
2461
|
-
import { useState as
|
|
2745
|
+
import { useState as useState14 } from "react";
|
|
2462
2746
|
import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2463
2747
|
function initials3(name) {
|
|
2464
2748
|
return name.trim().slice(0, 3).toUpperCase();
|
|
@@ -2468,7 +2752,7 @@ function PostMatchCrest({
|
|
|
2468
2752
|
name,
|
|
2469
2753
|
side
|
|
2470
2754
|
}) {
|
|
2471
|
-
const [failed, setFailed] =
|
|
2755
|
+
const [failed, setFailed] = useState14(false);
|
|
2472
2756
|
const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
|
|
2473
2757
|
if (url && !failed) {
|
|
2474
2758
|
return /* @__PURE__ */ jsx27("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2667,10 +2951,10 @@ function RestingFormCard({ card }) {
|
|
|
2667
2951
|
}
|
|
2668
2952
|
|
|
2669
2953
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
2670
|
-
import { useRef as
|
|
2954
|
+
import { useRef as useRef7, useState as useState16 } from "react";
|
|
2671
2955
|
|
|
2672
2956
|
// src/useLiveClock.ts
|
|
2673
|
-
import { useEffect as
|
|
2957
|
+
import { useEffect as useEffect9, useState as useState15 } from "react";
|
|
2674
2958
|
var TICK_MS = 6e4;
|
|
2675
2959
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2676
2960
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2679,10 +2963,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2679
2963
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2680
2964
|
}
|
|
2681
2965
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2682
|
-
const [displayMinute, setDisplayMinute] =
|
|
2966
|
+
const [displayMinute, setDisplayMinute] = useState15(
|
|
2683
2967
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2684
2968
|
);
|
|
2685
|
-
|
|
2969
|
+
useEffect9(() => {
|
|
2686
2970
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2687
2971
|
if (!clockRunning) return;
|
|
2688
2972
|
const id = window.setInterval(() => {
|
|
@@ -2699,7 +2983,7 @@ function initials5(name) {
|
|
|
2699
2983
|
return name.trim().slice(0, 3).toUpperCase();
|
|
2700
2984
|
}
|
|
2701
2985
|
function LiveCrest({ url, name, side }) {
|
|
2702
|
-
const [failed, setFailed] =
|
|
2986
|
+
const [failed, setFailed] = useState16(false);
|
|
2703
2987
|
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
2704
2988
|
if (url && !failed) {
|
|
2705
2989
|
return /* @__PURE__ */ jsx36("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2718,7 +3002,7 @@ function LiveScoreCard({
|
|
|
2718
3002
|
}) {
|
|
2719
3003
|
const { data } = card;
|
|
2720
3004
|
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
2721
|
-
const seedRef =
|
|
3005
|
+
const seedRef = useRef7(null);
|
|
2722
3006
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
2723
3007
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
2724
3008
|
}
|
|
@@ -2758,7 +3042,7 @@ function LiveScoreCard({
|
|
|
2758
3042
|
}
|
|
2759
3043
|
|
|
2760
3044
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
2761
|
-
import { useState as
|
|
3045
|
+
import { useState as useState17 } from "react";
|
|
2762
3046
|
import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2763
3047
|
var SHOWN2 = 3;
|
|
2764
3048
|
function EventIcon({ type }) {
|
|
@@ -2800,7 +3084,7 @@ function EventRow({ e }) {
|
|
|
2800
3084
|
] });
|
|
2801
3085
|
}
|
|
2802
3086
|
function LiveTimelineCard({ card, ui }) {
|
|
2803
|
-
const [expanded, setExpanded] =
|
|
3087
|
+
const [expanded, setExpanded] = useState17(false);
|
|
2804
3088
|
const events = card.data.events;
|
|
2805
3089
|
if (!events || events.length === 0) return null;
|
|
2806
3090
|
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
@@ -3040,11 +3324,11 @@ function turnAnchor(messages) {
|
|
|
3040
3324
|
}
|
|
3041
3325
|
function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3042
3326
|
const { state, send } = controller;
|
|
3043
|
-
const listRef =
|
|
3044
|
-
const endRef =
|
|
3045
|
-
const pinnedRef =
|
|
3046
|
-
const anchoredTurnRef =
|
|
3047
|
-
|
|
3327
|
+
const listRef = useRef8(null);
|
|
3328
|
+
const endRef = useRef8(null);
|
|
3329
|
+
const pinnedRef = useRef8(true);
|
|
3330
|
+
const anchoredTurnRef = useRef8(null);
|
|
3331
|
+
useEffect10(() => {
|
|
3048
3332
|
const anchor = turnAnchor(state.messages);
|
|
3049
3333
|
const list = listRef.current;
|
|
3050
3334
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -3100,10 +3384,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3100
3384
|
}
|
|
3101
3385
|
|
|
3102
3386
|
// src/components/ChatInput.tsx
|
|
3103
|
-
import { useState as
|
|
3387
|
+
import { useState as useState18 } from "react";
|
|
3104
3388
|
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3105
3389
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
3106
|
-
const [value, setValue] =
|
|
3390
|
+
const [value, setValue] = useState18("");
|
|
3107
3391
|
const submit = () => {
|
|
3108
3392
|
const t = value.trim();
|
|
3109
3393
|
if (!t) return;
|
|
@@ -3124,22 +3408,16 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
3124
3408
|
|
|
3125
3409
|
// src/components/TabBar.tsx
|
|
3126
3410
|
import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
]
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
chat: monitor.chatDot && monitor.activeTab !== "chat",
|
|
3137
|
-
matches: monitor.matchesDot && monitor.activeTab !== "matches",
|
|
3138
|
-
odds: monitor.oddsDot && monitor.activeTab !== "odds"
|
|
3139
|
-
};
|
|
3140
|
-
return /* @__PURE__ */ jsx45("div", { className: "ss-w-tabs", role: "tablist", children: TABS.map(({ tab, labelKey }) => {
|
|
3411
|
+
function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday }) {
|
|
3412
|
+
const tabs = [
|
|
3413
|
+
{ tab: "chat", label: ui.tabChat, count: 0, dot: monitor.chatDot },
|
|
3414
|
+
...hasToday ? [{ tab: "today", label: ui.tabToday, count: todayCount, dot: monitor.todayDot }] : [],
|
|
3415
|
+
...matchCount > 0 ? [{ tab: "following", label: ui.tabFollowing, count: matchCount, dot: monitor.matchesDot }] : [],
|
|
3416
|
+
...oddsCount > 0 ? [{ tab: "odds", label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : []
|
|
3417
|
+
];
|
|
3418
|
+
if (tabs.length < 2) return null;
|
|
3419
|
+
return /* @__PURE__ */ jsx45("div", { className: "ss-w-tabs", role: "tablist", children: tabs.map(({ tab, label, count, dot }) => {
|
|
3141
3420
|
const active = monitor.activeTab === tab;
|
|
3142
|
-
const count = counts[tab];
|
|
3143
3421
|
return /* @__PURE__ */ jsxs40(
|
|
3144
3422
|
"button",
|
|
3145
3423
|
{
|
|
@@ -3150,9 +3428,9 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
|
|
|
3150
3428
|
className: "ss-w-tab",
|
|
3151
3429
|
onClick: () => monitor.setActiveTab(tab),
|
|
3152
3430
|
children: [
|
|
3153
|
-
|
|
3431
|
+
label,
|
|
3154
3432
|
count > 0 && /* @__PURE__ */ jsx45("span", { className: "ss-w-tab-count", children: count }),
|
|
3155
|
-
|
|
3433
|
+
dot && !active && /* @__PURE__ */ jsx45("span", { className: "ss-w-tab-dot", "aria-hidden": "true" })
|
|
3156
3434
|
]
|
|
3157
3435
|
},
|
|
3158
3436
|
tab
|
|
@@ -3313,6 +3591,7 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
3313
3591
|
selection,
|
|
3314
3592
|
shownOdds: typeof row.market.price === "number" ? row.market.price.toFixed(2) : "",
|
|
3315
3593
|
marketName: row.market.marketLabel,
|
|
3594
|
+
marketDeveloperName: row.market.marketDeveloperName,
|
|
3316
3595
|
slip,
|
|
3317
3596
|
ui
|
|
3318
3597
|
}
|
|
@@ -3407,12 +3686,96 @@ function OddsPanel({ monitor, ui, slip }) {
|
|
|
3407
3686
|
}) });
|
|
3408
3687
|
}
|
|
3409
3688
|
|
|
3410
|
-
// src/components/
|
|
3689
|
+
// src/components/FixtureRow.tsx
|
|
3411
3690
|
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3691
|
+
function kickoffLabel(kickoffUnix) {
|
|
3692
|
+
const d = new Date(kickoffUnix * 1e3);
|
|
3693
|
+
return `${`${d.getHours()}`.padStart(2, "0")}:${`${d.getMinutes()}`.padStart(2, "0")}`;
|
|
3694
|
+
}
|
|
3695
|
+
function Side({ name, crest }) {
|
|
3696
|
+
return /* @__PURE__ */ jsxs44("span", { className: "ss-w-drow-side", children: [
|
|
3697
|
+
crest ? /* @__PURE__ */ jsx49("img", { className: "ss-w-drow-crest", src: crest, alt: "" }) : null,
|
|
3698
|
+
/* @__PURE__ */ jsx49("span", { className: "ss-w-drow-nm", children: name })
|
|
3699
|
+
] });
|
|
3700
|
+
}
|
|
3701
|
+
function FixtureRow({ match, state, stale, ui, monitor }) {
|
|
3702
|
+
const isLive = state?.phase === "live" && !stale;
|
|
3703
|
+
const hasScore = (state?.phase === "live" || state?.phase === "fullTime") && typeof state.homeScore === "number" && typeof state.awayScore === "number";
|
|
3704
|
+
const when = stale && state?.phase === "live" ? "\u2014" : isLive ? state?.minuteLabel ?? "\u2014" : kickoffLabel(match.kickoffUnix);
|
|
3705
|
+
return /* @__PURE__ */ jsxs44("div", { className: isLive ? "ss-w-drow ss-w-drow--live" : "ss-w-drow", children: [
|
|
3706
|
+
/* @__PURE__ */ jsx49("span", { className: isLive ? "ss-w-drow-when ss-w-drow-when--live" : "ss-w-drow-when", children: when }),
|
|
3707
|
+
/* @__PURE__ */ jsxs44("span", { className: "ss-w-drow-fx", children: [
|
|
3708
|
+
/* @__PURE__ */ jsx49(Side, { name: match.homeTeamName, crest: match.homeTeamImagePath }),
|
|
3709
|
+
/* @__PURE__ */ jsx49("span", { className: "ss-w-drow-dash", children: "\u2013" }),
|
|
3710
|
+
/* @__PURE__ */ jsx49(Side, { name: match.awayTeamName, crest: match.awayTeamImagePath })
|
|
3711
|
+
] }),
|
|
3712
|
+
/* @__PURE__ */ jsx49("span", { className: hasScore ? "ss-w-drow-sc" : "ss-w-drow-sc ss-w-drow-sc--idle", children: hasScore ? `${state.homeScore}\u2013${state.awayScore}` : "\u2013" }),
|
|
3713
|
+
/* @__PURE__ */ jsx49(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
|
|
3714
|
+
] });
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
// src/components/CompetitionGroup.tsx
|
|
3718
|
+
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3719
|
+
function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor }) {
|
|
3720
|
+
const own = group.matches.filter((m) => states[m.matchId]?.phase !== "live" || stale);
|
|
3721
|
+
const hasLive = own.length !== group.matches.length;
|
|
3722
|
+
return /* @__PURE__ */ jsxs45("div", { className: "ss-w-grp", children: [
|
|
3723
|
+
/* @__PURE__ */ jsxs45("button", { type: "button", className: "ss-w-grp-head", "aria-expanded": open, onClick: onToggle, children: [
|
|
3724
|
+
/* @__PURE__ */ jsx50("span", { className: "ss-w-grp-chev", children: open ? "\u25BE" : "\u25B8" }),
|
|
3725
|
+
hasLive && /* @__PURE__ */ jsx50("span", { className: "ss-w-sec-dot", "aria-hidden": "true" }),
|
|
3726
|
+
/* @__PURE__ */ jsx50("span", { className: "ss-w-grp-name", children: group.competitionName }),
|
|
3727
|
+
/* @__PURE__ */ jsx50("span", { className: "ss-w-grp-count", children: own.length })
|
|
3728
|
+
] }),
|
|
3729
|
+
open && /* @__PURE__ */ jsx50("div", { className: "ss-w-grp-body", children: own.map((m) => /* @__PURE__ */ jsx50(FixtureRow, { match: m, state: states[m.matchId], stale, ui, monitor }, m.matchId)) })
|
|
3730
|
+
] });
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3733
|
+
// src/components/TodayPanel.tsx
|
|
3734
|
+
import { Fragment as Fragment7, jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3735
|
+
function TodayPanel({ discovery, ui, monitor }) {
|
|
3736
|
+
const { groups, states, stale, expanded, toggleGroup } = discovery;
|
|
3737
|
+
const liveRows = stale ? [] : groups.flatMap((group) => group.matches.filter((m) => states[m.matchId]?.phase === "live").map((match) => ({ match, rank: group.rank }))).sort((a, b) => a.rank - b.rank);
|
|
3738
|
+
return /* @__PURE__ */ jsxs46("div", { className: "ss-w-mon-list", children: [
|
|
3739
|
+
stale && /* @__PURE__ */ jsx51("div", { className: "ss-w-stale", children: ui.staleStates }),
|
|
3740
|
+
liveRows.length > 0 && /* @__PURE__ */ jsxs46(Fragment7, { children: [
|
|
3741
|
+
/* @__PURE__ */ jsxs46("div", { className: "ss-w-sec-head", children: [
|
|
3742
|
+
/* @__PURE__ */ jsx51("span", { className: "ss-w-sec-dot", "aria-hidden": "true" }),
|
|
3743
|
+
ui.sectionLive
|
|
3744
|
+
] }),
|
|
3745
|
+
/* @__PURE__ */ jsx51("div", { className: "ss-w-today-live", children: liveRows.map(({ match }) => /* @__PURE__ */ jsx51(
|
|
3746
|
+
FixtureRow,
|
|
3747
|
+
{
|
|
3748
|
+
match,
|
|
3749
|
+
state: states[match.matchId],
|
|
3750
|
+
stale,
|
|
3751
|
+
ui,
|
|
3752
|
+
monitor
|
|
3753
|
+
},
|
|
3754
|
+
match.matchId
|
|
3755
|
+
)) })
|
|
3756
|
+
] }),
|
|
3757
|
+
groups.map((group) => /* @__PURE__ */ jsx51(
|
|
3758
|
+
CompetitionGroup,
|
|
3759
|
+
{
|
|
3760
|
+
group,
|
|
3761
|
+
open: expanded[group.competitionId] ?? group.expandedByDefault,
|
|
3762
|
+
onToggle: () => toggleGroup(group.competitionId),
|
|
3763
|
+
states,
|
|
3764
|
+
stale,
|
|
3765
|
+
ui,
|
|
3766
|
+
monitor
|
|
3767
|
+
},
|
|
3768
|
+
group.competitionId
|
|
3769
|
+
))
|
|
3770
|
+
] });
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
// src/components/ChatPanel.tsx
|
|
3774
|
+
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3412
3775
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
3413
3776
|
function useIsModal() {
|
|
3414
|
-
const [modal, setModal] =
|
|
3415
|
-
|
|
3777
|
+
const [modal, setModal] = useState19(false);
|
|
3778
|
+
useEffect11(() => {
|
|
3416
3779
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
3417
3780
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
3418
3781
|
const sync = () => setModal(mql.matches);
|
|
@@ -3422,10 +3785,10 @@ function useIsModal() {
|
|
|
3422
3785
|
}, []);
|
|
3423
3786
|
return modal;
|
|
3424
3787
|
}
|
|
3425
|
-
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3788
|
+
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery }) {
|
|
3426
3789
|
const { state, close, stop, send, reset } = controller;
|
|
3427
3790
|
const isModal = useIsModal();
|
|
3428
|
-
|
|
3791
|
+
useEffect11(() => {
|
|
3429
3792
|
const onKey = (e) => {
|
|
3430
3793
|
if (e.key === "Escape") close();
|
|
3431
3794
|
};
|
|
@@ -3436,11 +3799,11 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3436
3799
|
monitor?.setActiveTab("chat");
|
|
3437
3800
|
send(text);
|
|
3438
3801
|
};
|
|
3439
|
-
|
|
3802
|
+
useEffect11(() => {
|
|
3440
3803
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
3441
3804
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
3442
|
-
return /* @__PURE__ */
|
|
3443
|
-
/* @__PURE__ */
|
|
3805
|
+
return /* @__PURE__ */ jsxs47("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
3806
|
+
/* @__PURE__ */ jsx52(
|
|
3444
3807
|
ChatHeader,
|
|
3445
3808
|
{
|
|
3446
3809
|
onClose: close,
|
|
@@ -3453,25 +3816,28 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3453
3816
|
moreOptionsLabel: ui.moreOptions
|
|
3454
3817
|
}
|
|
3455
3818
|
),
|
|
3456
|
-
monitor && /* @__PURE__ */
|
|
3819
|
+
monitor && /* @__PURE__ */ jsx52(
|
|
3457
3820
|
TabBar,
|
|
3458
3821
|
{
|
|
3459
3822
|
monitor,
|
|
3460
3823
|
ui,
|
|
3461
3824
|
matchCount: monitor.pins.filter((p) => p.kind === "match").length,
|
|
3462
|
-
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
|
|
3825
|
+
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length,
|
|
3826
|
+
todayCount: discovery?.liveCount ?? 0,
|
|
3827
|
+
hasToday: (discovery?.groups.length ?? 0) > 0
|
|
3463
3828
|
}
|
|
3464
3829
|
),
|
|
3465
|
-
/* @__PURE__ */
|
|
3830
|
+
/* @__PURE__ */ jsx52(
|
|
3466
3831
|
"div",
|
|
3467
3832
|
{
|
|
3468
3833
|
style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
|
|
3469
|
-
children: /* @__PURE__ */
|
|
3834
|
+
children: /* @__PURE__ */ jsx52(MessageList, { controller, ui, slip, onDashboardTap, monitor })
|
|
3470
3835
|
}
|
|
3471
3836
|
),
|
|
3472
|
-
monitor && monitor.activeTab === "
|
|
3473
|
-
monitor && monitor.activeTab === "
|
|
3474
|
-
/* @__PURE__ */
|
|
3837
|
+
monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ jsx52(TodayPanel, { discovery, ui, monitor }),
|
|
3838
|
+
monitor && monitor.activeTab === "following" && /* @__PURE__ */ jsx52(MatchesPanel, { monitor, ui, slip }),
|
|
3839
|
+
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ jsx52(OddsPanel, { monitor, ui, slip }),
|
|
3840
|
+
/* @__PURE__ */ jsx52(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
3475
3841
|
] });
|
|
3476
3842
|
}
|
|
3477
3843
|
|
|
@@ -4208,8 +4574,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4208
4574
|
.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }
|
|
4209
4575
|
|
|
4210
4576
|
/* live monitor tab bar: underline pattern mirrors .ss-w-ecard-scope; the unread dot uses --ss-w-neg */
|
|
4211
|
-
.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); }
|
|
4212
|
-
.ss-w-
|
|
4577
|
+
.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); overflow-x: auto; scrollbar-width: none; }
|
|
4578
|
+
.ss-w-tabs::-webkit-scrollbar { display: none; }
|
|
4579
|
+
.ss-w-tab { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 9px 12px; margin-bottom: -1px; border-bottom: 2px solid transparent; flex: none; white-space: nowrap; }
|
|
4213
4580
|
.ss-w-tab[data-on] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }
|
|
4214
4581
|
.ss-w-tab-count { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 999px; padding: 1px 6px; }
|
|
4215
4582
|
.ss-w-tab[data-on] .ss-w-tab-count { color: var(--ss-w-accent); }
|
|
@@ -4298,10 +4665,41 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4298
4665
|
.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
|
|
4299
4666
|
.ss-w-acc-insight { font-size: 12px; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 7px 9px; }
|
|
4300
4667
|
.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
|
|
4668
|
+
|
|
4669
|
+
/* ---- Today tab (u355) ---- */
|
|
4670
|
+
.ss-w-sec-head { display: flex; align-items: center; gap: 7px; padding: 2px 2px 0; font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
4671
|
+
.ss-w-sec-head::after { content: ""; flex: 1; height: 1px; background: var(--ss-w-line); }
|
|
4672
|
+
.ss-w-sec-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }
|
|
4673
|
+
.ss-w-today-live { display: flex; flex-direction: column; gap: 2px; }
|
|
4674
|
+
|
|
4675
|
+
.ss-w-grp { border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; }
|
|
4676
|
+
.ss-w-grp-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 11px; background: var(--ss-w-bubble); border: none; font: inherit; color: var(--ss-w-ink); cursor: pointer; text-align: left; }
|
|
4677
|
+
.ss-w-grp-head:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: -2px; }
|
|
4678
|
+
.ss-w-grp-chev { color: var(--ss-w-faint); font-size: 10px; flex: none; }
|
|
4679
|
+
.ss-w-grp-name { font-size: 12px; font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
4680
|
+
.ss-w-grp-count { margin-left: auto; flex: none; font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 999px; padding: 1px 7px; font-variant-numeric: tabular-nums; }
|
|
4681
|
+
.ss-w-grp-body { display: flex; flex-direction: column; padding: 2px 11px 6px; }
|
|
4682
|
+
|
|
4683
|
+
.ss-w-drow { display: grid; grid-template-columns: 42px minmax(0,1fr) auto 22px; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--ss-w-line); }
|
|
4684
|
+
.ss-w-drow:last-child { border-bottom: none; }
|
|
4685
|
+
.ss-w-drow-when { font-size: 11px; font-weight: 700; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
|
|
4686
|
+
.ss-w-drow-when--live { color: var(--ss-w-neg); }
|
|
4687
|
+
/* Each side ellipsises independently: a single joined string truncates the away team off the end,
|
|
4688
|
+
which is the u350 betting-card truncation one layer down. */
|
|
4689
|
+
.ss-w-drow-fx { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
4690
|
+
.ss-w-drow-side { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1 1 0; }
|
|
4691
|
+
.ss-w-drow-nm { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
4692
|
+
.ss-w-drow-dash { flex: none; color: var(--ss-w-faint); font-size: 11px; }
|
|
4693
|
+
.ss-w-drow-sc { font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
|
|
4694
|
+
.ss-w-drow-sc--idle { color: var(--ss-w-faint); font-weight: 600; }
|
|
4695
|
+
.ss-w-drow--live { background: color-mix(in srgb, var(--ss-w-neg) 5%, transparent); border-radius: 8px; padding: 7px 6px; margin: 0 -6px; border-bottom: none; }
|
|
4696
|
+
.ss-w-drow-crest { width: 16px; height: 16px; flex: none; border-radius: 50%; object-fit: contain; background: var(--ss-w-bubble); }
|
|
4697
|
+
|
|
4698
|
+
.ss-w-stale { font-size: 11px; font-weight: 600; color: var(--ss-w-cta); background: color-mix(in srgb, var(--ss-w-cta) 12%, var(--ss-w-panel)); border-radius: 8px; padding: 6px 9px; }
|
|
4301
4699
|
`;
|
|
4302
4700
|
|
|
4303
4701
|
// src/StatsWidget.tsx
|
|
4304
|
-
import { jsx as
|
|
4702
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
4305
4703
|
function buildClient(props) {
|
|
4306
4704
|
try {
|
|
4307
4705
|
if ("client" in props && props.client) {
|
|
@@ -4326,22 +4724,61 @@ function injectStyles(root) {
|
|
|
4326
4724
|
function StatsWidget(props) {
|
|
4327
4725
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
4328
4726
|
const cfg = props.config;
|
|
4329
|
-
const built =
|
|
4330
|
-
const
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4727
|
+
const built = useMemo3(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
4728
|
+
const logger = useMemo3(
|
|
4729
|
+
() => built ? built.client.createEventLogger({
|
|
4730
|
+
operatorUserId: cfg?.userContext?.operatorUserId,
|
|
4731
|
+
anonymousUserId: cfg?.userContext?.anonymousUserId
|
|
4732
|
+
}) : null,
|
|
4733
|
+
[built?.client]
|
|
4734
|
+
);
|
|
4735
|
+
const ui = useMemo3(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
4736
|
+
const rootRef = useRef9(null);
|
|
4737
|
+
const introDoneRef = useRef9(false);
|
|
4738
|
+
const markIntroDone = useCallback6(() => {
|
|
4334
4739
|
introDoneRef.current = true;
|
|
4335
4740
|
}, []);
|
|
4336
4741
|
const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
|
|
4337
4742
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
|
|
4743
|
+
const [hasToday, setHasToday] = useState20(false);
|
|
4338
4744
|
const monitor = useLiveMonitor({
|
|
4339
4745
|
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
4340
4746
|
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
4341
4747
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
4342
|
-
isOpen: controller.state.isOpen
|
|
4748
|
+
isOpen: controller.state.isOpen,
|
|
4749
|
+
hasToday
|
|
4343
4750
|
});
|
|
4344
|
-
const
|
|
4751
|
+
const getSchedule = useCallback6(
|
|
4752
|
+
(localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
|
|
4753
|
+
[built]
|
|
4754
|
+
);
|
|
4755
|
+
const getStates = useCallback6(
|
|
4756
|
+
(matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
|
|
4757
|
+
[built]
|
|
4758
|
+
);
|
|
4759
|
+
const pinnedMatchIds = useMemo3(
|
|
4760
|
+
() => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
|
|
4761
|
+
[monitor.pins]
|
|
4762
|
+
);
|
|
4763
|
+
const discovery = useMatchDiscovery({
|
|
4764
|
+
getSchedule,
|
|
4765
|
+
getStates,
|
|
4766
|
+
operatorId: cfg?.operatorId ?? "",
|
|
4767
|
+
isOpen: controller.state.isOpen,
|
|
4768
|
+
pinnedMatchIds
|
|
4769
|
+
});
|
|
4770
|
+
const todayHasContent = discovery.groups.length > 0;
|
|
4771
|
+
useEffect12(() => {
|
|
4772
|
+
setHasToday(todayHasContent);
|
|
4773
|
+
}, [todayHasContent]);
|
|
4774
|
+
const markTodayActivity = monitor.markTodayActivity;
|
|
4775
|
+
const prevLiveCountRef = useRef9(0);
|
|
4776
|
+
useEffect12(() => {
|
|
4777
|
+
const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
|
|
4778
|
+
prevLiveCountRef.current = discovery.liveCount;
|
|
4779
|
+
if (rose) markTodayActivity();
|
|
4780
|
+
}, [discovery.liveCount, markTodayActivity]);
|
|
4781
|
+
const slip = useMemo3(
|
|
4345
4782
|
() => {
|
|
4346
4783
|
const handler = props.config?.onAddToSlip;
|
|
4347
4784
|
return {
|
|
@@ -4364,18 +4801,42 @@ function StatsWidget(props) {
|
|
|
4364
4801
|
},
|
|
4365
4802
|
[props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
|
|
4366
4803
|
);
|
|
4367
|
-
const onDashboardTap =
|
|
4368
|
-
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
4369
|
-
[built]
|
|
4804
|
+
const onDashboardTap = useMemo3(
|
|
4805
|
+
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
|
|
4806
|
+
[built, logger]
|
|
4370
4807
|
);
|
|
4371
|
-
|
|
4808
|
+
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
4809
|
+
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
4810
|
+
const conversationId = controller.state.conversationId ?? void 0;
|
|
4811
|
+
useEffect12(() => {
|
|
4812
|
+
if (!logger) return;
|
|
4813
|
+
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
4814
|
+
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
4815
|
+
useEffect12(() => {
|
|
4816
|
+
if (!logger) return;
|
|
4817
|
+
const onHide = () => {
|
|
4818
|
+
logger.flushOnHide();
|
|
4819
|
+
};
|
|
4820
|
+
const onVisibilityHide = () => {
|
|
4821
|
+
if (document.visibilityState === "hidden") logger.flushOnHide();
|
|
4822
|
+
};
|
|
4823
|
+
window.addEventListener("pagehide", onHide);
|
|
4824
|
+
document.addEventListener("visibilitychange", onVisibilityHide);
|
|
4825
|
+
return () => {
|
|
4826
|
+
window.removeEventListener("pagehide", onHide);
|
|
4827
|
+
document.removeEventListener("visibilitychange", onVisibilityHide);
|
|
4828
|
+
logger.flushOnHide();
|
|
4829
|
+
logger.dispose();
|
|
4830
|
+
};
|
|
4831
|
+
}, [logger]);
|
|
4832
|
+
useEffect12(() => {
|
|
4372
4833
|
if (!built || !ui.injectStyles) return;
|
|
4373
4834
|
const node = rootRef.current?.getRootNode();
|
|
4374
4835
|
if (node) injectStyles(node);
|
|
4375
4836
|
}, [built, ui.injectStyles]);
|
|
4376
4837
|
if (!built) return null;
|
|
4377
4838
|
const attrs = themeAttrs(ui);
|
|
4378
|
-
return /* @__PURE__ */
|
|
4839
|
+
return /* @__PURE__ */ jsx53(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ jsx53("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ jsx53(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0, discovery }) : /* @__PURE__ */ jsx53(
|
|
4379
4840
|
ChatFab,
|
|
4380
4841
|
{
|
|
4381
4842
|
label: ui.launcherLabel,
|
|
@@ -4388,7 +4849,7 @@ function StatsWidget(props) {
|
|
|
4388
4849
|
introAllowed: !introDoneRef.current,
|
|
4389
4850
|
onIntroStart: markIntroDone
|
|
4390
4851
|
}
|
|
4391
|
-
) });
|
|
4852
|
+
) }) });
|
|
4392
4853
|
}
|
|
4393
4854
|
function emptyConversation() {
|
|
4394
4855
|
return { send: () => {
|