@sensiblestats/widget-react 0.44.0 → 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 +13 -0
- package/dist/index.cjs +469 -121
- 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 +463 -115
- 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,
|
|
@@ -1178,6 +1187,7 @@ function useLiveMonitor(opts) {
|
|
|
1178
1187
|
const [chatDot, setChatDot] = useState(false);
|
|
1179
1188
|
const [matchesDot, setMatchesDot] = useState(false);
|
|
1180
1189
|
const [oddsDot, setOddsDot] = useState(false);
|
|
1190
|
+
const [todayDot, setTodayDot] = useState(false);
|
|
1181
1191
|
const [lastViewedPrices, setLastViewedPrices] = useState({});
|
|
1182
1192
|
const [inSlip, setInSlip] = useState({});
|
|
1183
1193
|
const [openMarket, setOpenMarket] = useState({});
|
|
@@ -1194,6 +1204,7 @@ function useLiveMonitor(opts) {
|
|
|
1194
1204
|
openMarketRef.current = openMarket;
|
|
1195
1205
|
const marketOddsRef = useRef3(marketOdds);
|
|
1196
1206
|
marketOddsRef.current = marketOdds;
|
|
1207
|
+
const hasToday = opts.hasToday ?? false;
|
|
1197
1208
|
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
1198
1209
|
const getMarketOddsRef = useRef3(opts.getMarketOdds);
|
|
1199
1210
|
getMarketOddsRef.current = opts.getMarketOdds;
|
|
@@ -1248,7 +1259,7 @@ function useLiveMonitor(opts) {
|
|
|
1248
1259
|
break;
|
|
1249
1260
|
}
|
|
1250
1261
|
}
|
|
1251
|
-
if (sawNewGoalOrRed && activeTabRef.current !== "
|
|
1262
|
+
if (sawNewGoalOrRed && activeTabRef.current !== "following") setMatchesDot(true);
|
|
1252
1263
|
for (const m of next.matches) {
|
|
1253
1264
|
if (!pinnedMatchIds.has(m.matchId)) continue;
|
|
1254
1265
|
const first = m.availableMarkets?.[0];
|
|
@@ -1334,11 +1345,17 @@ function useLiveMonitor(opts) {
|
|
|
1334
1345
|
prevPinsLengthRef.current = pins.length;
|
|
1335
1346
|
if (pins.length === 0) {
|
|
1336
1347
|
window.clearTimeout(timerRef.current);
|
|
1337
|
-
setActiveTabState("chat");
|
|
1338
1348
|
return;
|
|
1339
1349
|
}
|
|
1340
1350
|
if (wasEmpty) void tick();
|
|
1341
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]);
|
|
1342
1359
|
const prevIsOpenRef = useRef3(false);
|
|
1343
1360
|
useEffect3(() => {
|
|
1344
1361
|
const wasClosed = !prevIsOpenRef.current;
|
|
@@ -1359,7 +1376,8 @@ function useLiveMonitor(opts) {
|
|
|
1359
1376
|
const setActiveTab = useCallback2((tab) => {
|
|
1360
1377
|
setActiveTabState(tab);
|
|
1361
1378
|
if (tab === "chat") setChatDot(false);
|
|
1362
|
-
if (tab === "
|
|
1379
|
+
if (tab === "today") setTodayDot(false);
|
|
1380
|
+
if (tab === "following") {
|
|
1363
1381
|
setMatchesDot(false);
|
|
1364
1382
|
void tick();
|
|
1365
1383
|
}
|
|
@@ -1379,6 +1397,9 @@ function useLiveMonitor(opts) {
|
|
|
1379
1397
|
const togglePin = useCallback2((pin) => store.toggle(pin), [store]);
|
|
1380
1398
|
const isPinned = useCallback2((key) => pinsRef.current.some((p) => p.key === key), []);
|
|
1381
1399
|
const markChatActivity = useCallback2(() => setChatDot(true), []);
|
|
1400
|
+
const markTodayActivity = useCallback2(() => {
|
|
1401
|
+
if (activeTabRef.current !== "today") setTodayDot(true);
|
|
1402
|
+
}, []);
|
|
1382
1403
|
const markInSlip = useCallback2((matchOddsId) => {
|
|
1383
1404
|
setInSlip((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
|
|
1384
1405
|
}, []);
|
|
@@ -1394,6 +1415,8 @@ function useLiveMonitor(opts) {
|
|
|
1394
1415
|
markChatActivity,
|
|
1395
1416
|
matchesDot,
|
|
1396
1417
|
oddsDot,
|
|
1418
|
+
todayDot,
|
|
1419
|
+
markTodayActivity,
|
|
1397
1420
|
lastViewedPrices,
|
|
1398
1421
|
inSlip,
|
|
1399
1422
|
markInSlip,
|
|
@@ -1405,6 +1428,186 @@ function useLiveMonitor(opts) {
|
|
|
1405
1428
|
};
|
|
1406
1429
|
}
|
|
1407
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
|
+
|
|
1408
1611
|
// src/eventLogContext.ts
|
|
1409
1612
|
import { createContext, useContext } from "react";
|
|
1410
1613
|
var EventLogContext = createContext(null);
|
|
@@ -1413,10 +1616,10 @@ function useEventLog() {
|
|
|
1413
1616
|
}
|
|
1414
1617
|
|
|
1415
1618
|
// src/components/ChatFab.tsx
|
|
1416
|
-
import { useEffect as
|
|
1619
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
|
|
1417
1620
|
|
|
1418
1621
|
// src/components/BrandMark.tsx
|
|
1419
|
-
import { useState as
|
|
1622
|
+
import { useState as useState3 } from "react";
|
|
1420
1623
|
|
|
1421
1624
|
// src/assets/logo.ts
|
|
1422
1625
|
var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
|
|
@@ -1465,7 +1668,7 @@ function DashboardIcon({ name }) {
|
|
|
1465
1668
|
// src/components/BrandMark.tsx
|
|
1466
1669
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1467
1670
|
function BrandMark({ logoUrl, className }) {
|
|
1468
|
-
const [failed, setFailed] =
|
|
1671
|
+
const [failed, setFailed] = useState3(false);
|
|
1469
1672
|
if (!logoUrl || failed) return /* @__PURE__ */ jsx2(SsMark, { className });
|
|
1470
1673
|
return /* @__PURE__ */ jsx2("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1471
1674
|
}
|
|
@@ -1490,9 +1693,9 @@ function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
|
|
|
1490
1693
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1491
1694
|
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
|
|
1492
1695
|
const bubble = popupText ?? greeting;
|
|
1493
|
-
const [intro, setIntro] =
|
|
1494
|
-
const armedRef =
|
|
1495
|
-
|
|
1696
|
+
const [intro, setIntro] = useState4(false);
|
|
1697
|
+
const armedRef = useRef5(introAllowed);
|
|
1698
|
+
useEffect5(() => {
|
|
1496
1699
|
if (armedRef.current && bubble) {
|
|
1497
1700
|
armedRef.current = false;
|
|
1498
1701
|
setIntro(true);
|
|
@@ -1506,10 +1709,10 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
|
|
|
1506
1709
|
}
|
|
1507
1710
|
|
|
1508
1711
|
// src/components/ChatPanel.tsx
|
|
1509
|
-
import { useEffect as
|
|
1712
|
+
import { useEffect as useEffect11, useState as useState19 } from "react";
|
|
1510
1713
|
|
|
1511
1714
|
// src/components/ChatHeader.tsx
|
|
1512
|
-
import { useEffect as
|
|
1715
|
+
import { useEffect as useEffect6, useRef as useRef6, useState as useState5 } from "react";
|
|
1513
1716
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1514
1717
|
function ChatHeader({
|
|
1515
1718
|
onClose,
|
|
@@ -1521,15 +1724,15 @@ function ChatHeader({
|
|
|
1521
1724
|
newConversationLabel = "New conversation",
|
|
1522
1725
|
moreOptionsLabel = "More options"
|
|
1523
1726
|
}) {
|
|
1524
|
-
const [menuOpen, setMenuOpen] =
|
|
1525
|
-
const wrapRef =
|
|
1526
|
-
const kebabRef =
|
|
1527
|
-
const firstItemRef =
|
|
1727
|
+
const [menuOpen, setMenuOpen] = useState5(false);
|
|
1728
|
+
const wrapRef = useRef6(null);
|
|
1729
|
+
const kebabRef = useRef6(null);
|
|
1730
|
+
const firstItemRef = useRef6(null);
|
|
1528
1731
|
const hasMenu = !!(canReset && onNewConversation);
|
|
1529
|
-
|
|
1732
|
+
useEffect6(() => {
|
|
1530
1733
|
if (menuOpen) firstItemRef.current?.focus();
|
|
1531
1734
|
}, [menuOpen]);
|
|
1532
|
-
|
|
1735
|
+
useEffect6(() => {
|
|
1533
1736
|
if (!menuOpen) return;
|
|
1534
1737
|
const onPointer = (e) => {
|
|
1535
1738
|
if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
|
|
@@ -1585,7 +1788,7 @@ function ChatHeader({
|
|
|
1585
1788
|
}
|
|
1586
1789
|
|
|
1587
1790
|
// src/components/MessageList.tsx
|
|
1588
|
-
import { useEffect as
|
|
1791
|
+
import { useEffect as useEffect10, useRef as useRef8 } from "react";
|
|
1589
1792
|
|
|
1590
1793
|
// src/components/Markdown.tsx
|
|
1591
1794
|
import ReactMarkdown from "react-markdown";
|
|
@@ -1603,7 +1806,7 @@ function Markdown({ text }) {
|
|
|
1603
1806
|
}
|
|
1604
1807
|
|
|
1605
1808
|
// src/components/EntityCardList.tsx
|
|
1606
|
-
import { useState as
|
|
1809
|
+
import { useState as useState6 } from "react";
|
|
1607
1810
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1608
1811
|
var MAX_VISIBLE = 3;
|
|
1609
1812
|
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
@@ -1687,7 +1890,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
|
|
|
1687
1890
|
)) });
|
|
1688
1891
|
}
|
|
1689
1892
|
function EntityCardItem({ c }) {
|
|
1690
|
-
const [active, setActive] =
|
|
1893
|
+
const [active, setActive] = useState6(0);
|
|
1691
1894
|
const hasBody = c.scopes.length > 0;
|
|
1692
1895
|
if (!hasBody) {
|
|
1693
1896
|
return /* @__PURE__ */ jsx7("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx7(CardHeader, { c, showScopeCrest: false }) });
|
|
@@ -1701,7 +1904,7 @@ function EntityCardItem({ c }) {
|
|
|
1701
1904
|
] });
|
|
1702
1905
|
}
|
|
1703
1906
|
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1704
|
-
const [expanded, setExpanded] =
|
|
1907
|
+
const [expanded, setExpanded] = useState6(false);
|
|
1705
1908
|
if (cards.length === 0) return null;
|
|
1706
1909
|
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1707
1910
|
const overflow = cards.length - MAX_VISIBLE;
|
|
@@ -1712,18 +1915,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
1712
1915
|
}
|
|
1713
1916
|
|
|
1714
1917
|
// src/components/BettingInsightList.tsx
|
|
1715
|
-
import { useState as
|
|
1918
|
+
import { useState as useState10 } from "react";
|
|
1716
1919
|
|
|
1717
1920
|
// src/components/AddToSlipButton.tsx
|
|
1718
|
-
import { useCallback as
|
|
1921
|
+
import { useCallback as useCallback4, useState as useState7 } from "react";
|
|
1719
1922
|
import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
|
|
1720
1923
|
|
|
1721
1924
|
// src/components/Toast.tsx
|
|
1722
|
-
import { useEffect as
|
|
1925
|
+
import { useEffect as useEffect7 } from "react";
|
|
1723
1926
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1724
1927
|
var DISMISS_MS = 4e3;
|
|
1725
1928
|
function Toast({ toast, onDismiss }) {
|
|
1726
|
-
|
|
1929
|
+
useEffect7(() => {
|
|
1727
1930
|
if (!toast) return;
|
|
1728
1931
|
const timer = setTimeout(onDismiss, DISMISS_MS);
|
|
1729
1932
|
return () => clearTimeout(timer);
|
|
@@ -1741,10 +1944,10 @@ function withTimeout(value) {
|
|
|
1741
1944
|
]);
|
|
1742
1945
|
}
|
|
1743
1946
|
function SlipButton({ selection, shownOdds, marketName, marketDeveloperName, slip, ui }) {
|
|
1744
|
-
const [pending, setPending] =
|
|
1745
|
-
const [settled, setSettled] =
|
|
1746
|
-
const [toast, setToast] =
|
|
1747
|
-
const dismiss =
|
|
1947
|
+
const [pending, setPending] = useState7(false);
|
|
1948
|
+
const [settled, setSettled] = useState7(false);
|
|
1949
|
+
const [toast, setToast] = useState7(null);
|
|
1950
|
+
const dismiss = useCallback4(() => setToast(null), []);
|
|
1748
1951
|
const log = useEventLog();
|
|
1749
1952
|
const handler = slip.onAddToSlip;
|
|
1750
1953
|
if (!ui || !handler || !selection) return null;
|
|
@@ -1834,14 +2037,14 @@ function OddsMovementBadge({
|
|
|
1834
2037
|
}
|
|
1835
2038
|
|
|
1836
2039
|
// src/components/Crest.tsx
|
|
1837
|
-
import { useState as
|
|
2040
|
+
import { useState as useState8 } from "react";
|
|
1838
2041
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1839
2042
|
function initials2(name) {
|
|
1840
2043
|
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1841
2044
|
}
|
|
1842
2045
|
function Crest2({ url, name, kind }) {
|
|
1843
2046
|
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1844
|
-
const [failed, setFailed] =
|
|
2047
|
+
const [failed, setFailed] = useState8(false);
|
|
1845
2048
|
if (url && !failed) {
|
|
1846
2049
|
return /* @__PURE__ */ jsx11("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1847
2050
|
}
|
|
@@ -1849,7 +2052,7 @@ function Crest2({ url, name, kind }) {
|
|
|
1849
2052
|
}
|
|
1850
2053
|
|
|
1851
2054
|
// src/components/PinToggle.tsx
|
|
1852
|
-
import { useCallback as
|
|
2055
|
+
import { useCallback as useCallback5, useState as useState9 } from "react";
|
|
1853
2056
|
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1854
2057
|
var PIN_GLYPHS = {
|
|
1855
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" },
|
|
@@ -1857,8 +2060,8 @@ var PIN_GLYPHS = {
|
|
|
1857
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" }
|
|
1858
2061
|
};
|
|
1859
2062
|
function PinToggle({ pin, monitor, ui }) {
|
|
1860
|
-
const [toast, setToast] =
|
|
1861
|
-
const dismiss =
|
|
2063
|
+
const [toast, setToast] = useState9(null);
|
|
2064
|
+
const dismiss = useCallback5(() => setToast(null), []);
|
|
1862
2065
|
const log = useEventLog();
|
|
1863
2066
|
if (!monitor || !monitor.enabled) return null;
|
|
1864
2067
|
const key = pinKey(pin);
|
|
@@ -1918,7 +2121,7 @@ function StatRows({ stats }) {
|
|
|
1918
2121
|
] }, `${s.label}:${s.value}`)) });
|
|
1919
2122
|
}
|
|
1920
2123
|
function ScopedStats({ scopes }) {
|
|
1921
|
-
const [active, setActive] =
|
|
2124
|
+
const [active, setActive] = useState10(0);
|
|
1922
2125
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1923
2126
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-scoped", children: [
|
|
1924
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)) }),
|
|
@@ -1929,7 +2132,7 @@ function hasStatsContent(it) {
|
|
|
1929
2132
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1930
2133
|
}
|
|
1931
2134
|
function ReasonStrip({ it, ui }) {
|
|
1932
|
-
const [open, setOpen] =
|
|
2135
|
+
const [open, setOpen] = useState10(false);
|
|
1933
2136
|
const log = useEventLog();
|
|
1934
2137
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1935
2138
|
const hasStats = hasStatsContent(it);
|
|
@@ -2049,7 +2252,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
2049
2252
|
}
|
|
2050
2253
|
|
|
2051
2254
|
// src/components/MarketOddsCardList.tsx
|
|
2052
|
-
import { useState as
|
|
2255
|
+
import { useState as useState11 } from "react";
|
|
2053
2256
|
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2054
2257
|
function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
2055
2258
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
@@ -2066,7 +2269,7 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
2066
2269
|
] });
|
|
2067
2270
|
}
|
|
2068
2271
|
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
|
|
2069
|
-
const [open, setOpen] =
|
|
2272
|
+
const [open, setOpen] = useState11(false);
|
|
2070
2273
|
const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
2071
2274
|
const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
|
|
2072
2275
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
@@ -2369,7 +2572,7 @@ function FixtureCard({ card }) {
|
|
|
2369
2572
|
}
|
|
2370
2573
|
|
|
2371
2574
|
// src/components/dashboard/CountdownCard.tsx
|
|
2372
|
-
import { Fragment as Fragment6, useEffect as
|
|
2575
|
+
import { Fragment as Fragment6, useEffect as useEffect8, useState as useState12 } from "react";
|
|
2373
2576
|
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2374
2577
|
var DAY_MS = 864e5;
|
|
2375
2578
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -2388,12 +2591,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
|
2388
2591
|
function CountdownCard({ card }) {
|
|
2389
2592
|
const { data } = card;
|
|
2390
2593
|
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
2391
|
-
const [nowMs, setNowMs] =
|
|
2392
|
-
const [reduced] =
|
|
2594
|
+
const [nowMs, setNowMs] = useState12(() => Date.now());
|
|
2595
|
+
const [reduced] = useState12(
|
|
2393
2596
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
2394
2597
|
);
|
|
2395
2598
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
2396
|
-
|
|
2599
|
+
useEffect8(() => {
|
|
2397
2600
|
if (reduced) return;
|
|
2398
2601
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
2399
2602
|
return () => window.clearInterval(id);
|
|
@@ -2412,7 +2615,7 @@ function CountdownCard({ card }) {
|
|
|
2412
2615
|
}
|
|
2413
2616
|
|
|
2414
2617
|
// src/components/dashboard/InjuriesCard.tsx
|
|
2415
|
-
import { useState as
|
|
2618
|
+
import { useState as useState13 } from "react";
|
|
2416
2619
|
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2417
2620
|
var SHOWN = 3;
|
|
2418
2621
|
function ColHead({ name, crestUrl }) {
|
|
@@ -2435,7 +2638,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
|
|
|
2435
2638
|
}
|
|
2436
2639
|
function InjuriesCard({ card, ui }) {
|
|
2437
2640
|
const { data } = card;
|
|
2438
|
-
const [expanded, setExpanded] =
|
|
2641
|
+
const [expanded, setExpanded] = useState13(false);
|
|
2439
2642
|
const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
|
|
2440
2643
|
const limit = expanded ? void 0 : SHOWN;
|
|
2441
2644
|
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
@@ -2539,7 +2742,7 @@ function LinksCard({ card }) {
|
|
|
2539
2742
|
}
|
|
2540
2743
|
|
|
2541
2744
|
// src/components/dashboard/PostMatchResultCard.tsx
|
|
2542
|
-
import { useState as
|
|
2745
|
+
import { useState as useState14 } from "react";
|
|
2543
2746
|
import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2544
2747
|
function initials3(name) {
|
|
2545
2748
|
return name.trim().slice(0, 3).toUpperCase();
|
|
@@ -2549,7 +2752,7 @@ function PostMatchCrest({
|
|
|
2549
2752
|
name,
|
|
2550
2753
|
side
|
|
2551
2754
|
}) {
|
|
2552
|
-
const [failed, setFailed] =
|
|
2755
|
+
const [failed, setFailed] = useState14(false);
|
|
2553
2756
|
const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
|
|
2554
2757
|
if (url && !failed) {
|
|
2555
2758
|
return /* @__PURE__ */ jsx27("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2748,10 +2951,10 @@ function RestingFormCard({ card }) {
|
|
|
2748
2951
|
}
|
|
2749
2952
|
|
|
2750
2953
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
2751
|
-
import { useRef as
|
|
2954
|
+
import { useRef as useRef7, useState as useState16 } from "react";
|
|
2752
2955
|
|
|
2753
2956
|
// src/useLiveClock.ts
|
|
2754
|
-
import { useEffect as
|
|
2957
|
+
import { useEffect as useEffect9, useState as useState15 } from "react";
|
|
2755
2958
|
var TICK_MS = 6e4;
|
|
2756
2959
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2757
2960
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2760,10 +2963,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2760
2963
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2761
2964
|
}
|
|
2762
2965
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2763
|
-
const [displayMinute, setDisplayMinute] =
|
|
2966
|
+
const [displayMinute, setDisplayMinute] = useState15(
|
|
2764
2967
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2765
2968
|
);
|
|
2766
|
-
|
|
2969
|
+
useEffect9(() => {
|
|
2767
2970
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2768
2971
|
if (!clockRunning) return;
|
|
2769
2972
|
const id = window.setInterval(() => {
|
|
@@ -2780,7 +2983,7 @@ function initials5(name) {
|
|
|
2780
2983
|
return name.trim().slice(0, 3).toUpperCase();
|
|
2781
2984
|
}
|
|
2782
2985
|
function LiveCrest({ url, name, side }) {
|
|
2783
|
-
const [failed, setFailed] =
|
|
2986
|
+
const [failed, setFailed] = useState16(false);
|
|
2784
2987
|
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
2785
2988
|
if (url && !failed) {
|
|
2786
2989
|
return /* @__PURE__ */ jsx36("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2799,7 +3002,7 @@ function LiveScoreCard({
|
|
|
2799
3002
|
}) {
|
|
2800
3003
|
const { data } = card;
|
|
2801
3004
|
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
2802
|
-
const seedRef =
|
|
3005
|
+
const seedRef = useRef7(null);
|
|
2803
3006
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
2804
3007
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
2805
3008
|
}
|
|
@@ -2839,7 +3042,7 @@ function LiveScoreCard({
|
|
|
2839
3042
|
}
|
|
2840
3043
|
|
|
2841
3044
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
2842
|
-
import { useState as
|
|
3045
|
+
import { useState as useState17 } from "react";
|
|
2843
3046
|
import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2844
3047
|
var SHOWN2 = 3;
|
|
2845
3048
|
function EventIcon({ type }) {
|
|
@@ -2881,7 +3084,7 @@ function EventRow({ e }) {
|
|
|
2881
3084
|
] });
|
|
2882
3085
|
}
|
|
2883
3086
|
function LiveTimelineCard({ card, ui }) {
|
|
2884
|
-
const [expanded, setExpanded] =
|
|
3087
|
+
const [expanded, setExpanded] = useState17(false);
|
|
2885
3088
|
const events = card.data.events;
|
|
2886
3089
|
if (!events || events.length === 0) return null;
|
|
2887
3090
|
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
@@ -3121,11 +3324,11 @@ function turnAnchor(messages) {
|
|
|
3121
3324
|
}
|
|
3122
3325
|
function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3123
3326
|
const { state, send } = controller;
|
|
3124
|
-
const listRef =
|
|
3125
|
-
const endRef =
|
|
3126
|
-
const pinnedRef =
|
|
3127
|
-
const anchoredTurnRef =
|
|
3128
|
-
|
|
3327
|
+
const listRef = useRef8(null);
|
|
3328
|
+
const endRef = useRef8(null);
|
|
3329
|
+
const pinnedRef = useRef8(true);
|
|
3330
|
+
const anchoredTurnRef = useRef8(null);
|
|
3331
|
+
useEffect10(() => {
|
|
3129
3332
|
const anchor = turnAnchor(state.messages);
|
|
3130
3333
|
const list = listRef.current;
|
|
3131
3334
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -3181,10 +3384,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3181
3384
|
}
|
|
3182
3385
|
|
|
3183
3386
|
// src/components/ChatInput.tsx
|
|
3184
|
-
import { useState as
|
|
3387
|
+
import { useState as useState18 } from "react";
|
|
3185
3388
|
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3186
3389
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
3187
|
-
const [value, setValue] =
|
|
3390
|
+
const [value, setValue] = useState18("");
|
|
3188
3391
|
const submit = () => {
|
|
3189
3392
|
const t = value.trim();
|
|
3190
3393
|
if (!t) return;
|
|
@@ -3205,22 +3408,16 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
3205
3408
|
|
|
3206
3409
|
// src/components/TabBar.tsx
|
|
3207
3410
|
import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
]
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
chat: monitor.chatDot && monitor.activeTab !== "chat",
|
|
3218
|
-
matches: monitor.matchesDot && monitor.activeTab !== "matches",
|
|
3219
|
-
odds: monitor.oddsDot && monitor.activeTab !== "odds"
|
|
3220
|
-
};
|
|
3221
|
-
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 }) => {
|
|
3222
3420
|
const active = monitor.activeTab === tab;
|
|
3223
|
-
const count = counts[tab];
|
|
3224
3421
|
return /* @__PURE__ */ jsxs40(
|
|
3225
3422
|
"button",
|
|
3226
3423
|
{
|
|
@@ -3231,9 +3428,9 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
|
|
|
3231
3428
|
className: "ss-w-tab",
|
|
3232
3429
|
onClick: () => monitor.setActiveTab(tab),
|
|
3233
3430
|
children: [
|
|
3234
|
-
|
|
3431
|
+
label,
|
|
3235
3432
|
count > 0 && /* @__PURE__ */ jsx45("span", { className: "ss-w-tab-count", children: count }),
|
|
3236
|
-
|
|
3433
|
+
dot && !active && /* @__PURE__ */ jsx45("span", { className: "ss-w-tab-dot", "aria-hidden": "true" })
|
|
3237
3434
|
]
|
|
3238
3435
|
},
|
|
3239
3436
|
tab
|
|
@@ -3489,12 +3686,96 @@ function OddsPanel({ monitor, ui, slip }) {
|
|
|
3489
3686
|
}) });
|
|
3490
3687
|
}
|
|
3491
3688
|
|
|
3492
|
-
// src/components/
|
|
3689
|
+
// src/components/FixtureRow.tsx
|
|
3493
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";
|
|
3494
3775
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
3495
3776
|
function useIsModal() {
|
|
3496
|
-
const [modal, setModal] =
|
|
3497
|
-
|
|
3777
|
+
const [modal, setModal] = useState19(false);
|
|
3778
|
+
useEffect11(() => {
|
|
3498
3779
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
3499
3780
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
3500
3781
|
const sync = () => setModal(mql.matches);
|
|
@@ -3504,10 +3785,10 @@ function useIsModal() {
|
|
|
3504
3785
|
}, []);
|
|
3505
3786
|
return modal;
|
|
3506
3787
|
}
|
|
3507
|
-
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3788
|
+
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery }) {
|
|
3508
3789
|
const { state, close, stop, send, reset } = controller;
|
|
3509
3790
|
const isModal = useIsModal();
|
|
3510
|
-
|
|
3791
|
+
useEffect11(() => {
|
|
3511
3792
|
const onKey = (e) => {
|
|
3512
3793
|
if (e.key === "Escape") close();
|
|
3513
3794
|
};
|
|
@@ -3518,11 +3799,11 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3518
3799
|
monitor?.setActiveTab("chat");
|
|
3519
3800
|
send(text);
|
|
3520
3801
|
};
|
|
3521
|
-
|
|
3802
|
+
useEffect11(() => {
|
|
3522
3803
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
3523
3804
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
3524
|
-
return /* @__PURE__ */
|
|
3525
|
-
/* @__PURE__ */
|
|
3805
|
+
return /* @__PURE__ */ jsxs47("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
3806
|
+
/* @__PURE__ */ jsx52(
|
|
3526
3807
|
ChatHeader,
|
|
3527
3808
|
{
|
|
3528
3809
|
onClose: close,
|
|
@@ -3535,25 +3816,28 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3535
3816
|
moreOptionsLabel: ui.moreOptions
|
|
3536
3817
|
}
|
|
3537
3818
|
),
|
|
3538
|
-
monitor && /* @__PURE__ */
|
|
3819
|
+
monitor && /* @__PURE__ */ jsx52(
|
|
3539
3820
|
TabBar,
|
|
3540
3821
|
{
|
|
3541
3822
|
monitor,
|
|
3542
3823
|
ui,
|
|
3543
3824
|
matchCount: monitor.pins.filter((p) => p.kind === "match").length,
|
|
3544
|
-
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
|
|
3545
3828
|
}
|
|
3546
3829
|
),
|
|
3547
|
-
/* @__PURE__ */
|
|
3830
|
+
/* @__PURE__ */ jsx52(
|
|
3548
3831
|
"div",
|
|
3549
3832
|
{
|
|
3550
3833
|
style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
|
|
3551
|
-
children: /* @__PURE__ */
|
|
3834
|
+
children: /* @__PURE__ */ jsx52(MessageList, { controller, ui, slip, onDashboardTap, monitor })
|
|
3552
3835
|
}
|
|
3553
3836
|
),
|
|
3554
|
-
monitor && monitor.activeTab === "
|
|
3555
|
-
monitor && monitor.activeTab === "
|
|
3556
|
-
/* @__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 })
|
|
3557
3841
|
] });
|
|
3558
3842
|
}
|
|
3559
3843
|
|
|
@@ -4290,8 +4574,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4290
4574
|
.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }
|
|
4291
4575
|
|
|
4292
4576
|
/* live monitor tab bar: underline pattern mirrors .ss-w-ecard-scope; the unread dot uses --ss-w-neg */
|
|
4293
|
-
.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); }
|
|
4294
|
-
.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; }
|
|
4295
4580
|
.ss-w-tab[data-on] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }
|
|
4296
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; }
|
|
4297
4582
|
.ss-w-tab[data-on] .ss-w-tab-count { color: var(--ss-w-accent); }
|
|
@@ -4380,10 +4665,41 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4380
4665
|
.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
|
|
4381
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; }
|
|
4382
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; }
|
|
4383
4699
|
`;
|
|
4384
4700
|
|
|
4385
4701
|
// src/StatsWidget.tsx
|
|
4386
|
-
import { jsx as
|
|
4702
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
4387
4703
|
function buildClient(props) {
|
|
4388
4704
|
try {
|
|
4389
4705
|
if ("client" in props && props.client) {
|
|
@@ -4408,29 +4724,61 @@ function injectStyles(root) {
|
|
|
4408
4724
|
function StatsWidget(props) {
|
|
4409
4725
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
4410
4726
|
const cfg = props.config;
|
|
4411
|
-
const built =
|
|
4412
|
-
const logger =
|
|
4727
|
+
const built = useMemo3(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
4728
|
+
const logger = useMemo3(
|
|
4413
4729
|
() => built ? built.client.createEventLogger({
|
|
4414
4730
|
operatorUserId: cfg?.userContext?.operatorUserId,
|
|
4415
4731
|
anonymousUserId: cfg?.userContext?.anonymousUserId
|
|
4416
4732
|
}) : null,
|
|
4417
4733
|
[built?.client]
|
|
4418
4734
|
);
|
|
4419
|
-
const ui =
|
|
4420
|
-
const rootRef =
|
|
4421
|
-
const introDoneRef =
|
|
4422
|
-
const markIntroDone =
|
|
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(() => {
|
|
4423
4739
|
introDoneRef.current = true;
|
|
4424
4740
|
}, []);
|
|
4425
4741
|
const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
|
|
4426
4742
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
|
|
4743
|
+
const [hasToday, setHasToday] = useState20(false);
|
|
4427
4744
|
const monitor = useLiveMonitor({
|
|
4428
4745
|
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
4429
4746
|
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
4430
4747
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
4431
|
-
isOpen: controller.state.isOpen
|
|
4748
|
+
isOpen: controller.state.isOpen,
|
|
4749
|
+
hasToday
|
|
4432
4750
|
});
|
|
4433
|
-
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(
|
|
4434
4782
|
() => {
|
|
4435
4783
|
const handler = props.config?.onAddToSlip;
|
|
4436
4784
|
return {
|
|
@@ -4453,18 +4801,18 @@ function StatsWidget(props) {
|
|
|
4453
4801
|
},
|
|
4454
4802
|
[props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
|
|
4455
4803
|
);
|
|
4456
|
-
const onDashboardTap =
|
|
4804
|
+
const onDashboardTap = useMemo3(
|
|
4457
4805
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
|
|
4458
4806
|
[built, logger]
|
|
4459
4807
|
);
|
|
4460
4808
|
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
4461
4809
|
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
4462
4810
|
const conversationId = controller.state.conversationId ?? void 0;
|
|
4463
|
-
|
|
4811
|
+
useEffect12(() => {
|
|
4464
4812
|
if (!logger) return;
|
|
4465
4813
|
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
4466
4814
|
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
4467
|
-
|
|
4815
|
+
useEffect12(() => {
|
|
4468
4816
|
if (!logger) return;
|
|
4469
4817
|
const onHide = () => {
|
|
4470
4818
|
logger.flushOnHide();
|
|
@@ -4481,14 +4829,14 @@ function StatsWidget(props) {
|
|
|
4481
4829
|
logger.dispose();
|
|
4482
4830
|
};
|
|
4483
4831
|
}, [logger]);
|
|
4484
|
-
|
|
4832
|
+
useEffect12(() => {
|
|
4485
4833
|
if (!built || !ui.injectStyles) return;
|
|
4486
4834
|
const node = rootRef.current?.getRootNode();
|
|
4487
4835
|
if (node) injectStyles(node);
|
|
4488
4836
|
}, [built, ui.injectStyles]);
|
|
4489
4837
|
if (!built) return null;
|
|
4490
4838
|
const attrs = themeAttrs(ui);
|
|
4491
|
-
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(
|
|
4492
4840
|
ChatFab,
|
|
4493
4841
|
{
|
|
4494
4842
|
label: ui.launcherLabel,
|