@sensiblestats/widget-react 0.43.1 → 0.44.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 +11 -0
- package/dist/index.cjs +197 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +123 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -279,6 +279,18 @@ function isTerminal(result) {
|
|
|
279
279
|
if (result.status === "price_changed") return result.accepted;
|
|
280
280
|
return result.status === "added" || result.status === "duplicate";
|
|
281
281
|
}
|
|
282
|
+
function slipOutcome(result) {
|
|
283
|
+
if (!result) return "added";
|
|
284
|
+
switch (result.status) {
|
|
285
|
+
case "added":
|
|
286
|
+
case "duplicate":
|
|
287
|
+
return result.status;
|
|
288
|
+
case "price_changed":
|
|
289
|
+
return result.accepted ? "added" : "price_changed";
|
|
290
|
+
case "rejected":
|
|
291
|
+
return result.reason;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
282
294
|
function resultToToast(result, shownOdds, ui) {
|
|
283
295
|
if (!result) return { kind: "success", text: ui.slipAdded };
|
|
284
296
|
switch (result.status) {
|
|
@@ -300,8 +312,28 @@ import { ENTITY_TYPE_CODES } from "@sensiblestats/widget-sdk";
|
|
|
300
312
|
function isSignalEntityType(value) {
|
|
301
313
|
return Object.prototype.hasOwnProperty.call(ENTITY_TYPE_CODES, value);
|
|
302
314
|
}
|
|
303
|
-
function
|
|
315
|
+
function toWidgetEntityType(value) {
|
|
316
|
+
switch (value.toLowerCase()) {
|
|
317
|
+
case "match":
|
|
318
|
+
return "match";
|
|
319
|
+
case "team":
|
|
320
|
+
return "team";
|
|
321
|
+
case "player":
|
|
322
|
+
return "player";
|
|
323
|
+
case "competition":
|
|
324
|
+
return "competition";
|
|
325
|
+
case "market":
|
|
326
|
+
return "market";
|
|
327
|
+
default:
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function createDashboardTapSignal(sendSignal, log) {
|
|
304
332
|
return (tile, index, layout) => {
|
|
333
|
+
const widgetEntityType = toWidgetEntityType(tile.signal.entityType);
|
|
334
|
+
if (widgetEntityType) {
|
|
335
|
+
log?.log({ name: "tile_tap", entityType: widgetEntityType, entityId: tile.signal.entityId });
|
|
336
|
+
}
|
|
305
337
|
if (!isSignalEntityType(tile.signal.entityType)) return;
|
|
306
338
|
try {
|
|
307
339
|
void sendSignal({
|
|
@@ -1373,6 +1405,13 @@ function useLiveMonitor(opts) {
|
|
|
1373
1405
|
};
|
|
1374
1406
|
}
|
|
1375
1407
|
|
|
1408
|
+
// src/eventLogContext.ts
|
|
1409
|
+
import { createContext, useContext } from "react";
|
|
1410
|
+
var EventLogContext = createContext(null);
|
|
1411
|
+
function useEventLog() {
|
|
1412
|
+
return useContext(EventLogContext);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1376
1415
|
// src/components/ChatFab.tsx
|
|
1377
1416
|
import { useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
|
|
1378
1417
|
|
|
@@ -1701,19 +1740,32 @@ function withTimeout(value) {
|
|
|
1701
1740
|
new Promise((_, reject) => setTimeout(() => reject(new Error("add-to-slip timed out")), ADD_TO_SLIP_TIMEOUT_MS))
|
|
1702
1741
|
]);
|
|
1703
1742
|
}
|
|
1704
|
-
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
1743
|
+
function SlipButton({ selection, shownOdds, marketName, marketDeveloperName, slip, ui }) {
|
|
1705
1744
|
const [pending, setPending] = useState6(false);
|
|
1706
1745
|
const [settled, setSettled] = useState6(false);
|
|
1707
1746
|
const [toast, setToast] = useState6(null);
|
|
1708
1747
|
const dismiss = useCallback3(() => setToast(null), []);
|
|
1748
|
+
const log = useEventLog();
|
|
1709
1749
|
const handler = slip.onAddToSlip;
|
|
1710
1750
|
if (!ui || !handler || !selection) return null;
|
|
1711
1751
|
const onClick = async () => {
|
|
1712
1752
|
setPending(true);
|
|
1753
|
+
if (marketDeveloperName !== void 0) {
|
|
1754
|
+
log?.log({ name: "slip_click", entityType: "market", marketDeveloperName, entityId: marketDeveloperName });
|
|
1755
|
+
}
|
|
1713
1756
|
try {
|
|
1714
1757
|
const raw = await withTimeout(Promise.resolve(handler(selection)));
|
|
1715
1758
|
if (raw != null && !isAddToSlipResult(raw)) throw new Error("malformed add-to-slip result");
|
|
1716
1759
|
const result = raw ?? void 0;
|
|
1760
|
+
if (marketDeveloperName !== void 0) {
|
|
1761
|
+
log?.log({
|
|
1762
|
+
name: "slip_result",
|
|
1763
|
+
entityType: "market",
|
|
1764
|
+
marketDeveloperName,
|
|
1765
|
+
entityId: marketDeveloperName,
|
|
1766
|
+
outcome: slipOutcome(result)
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1717
1769
|
setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui));
|
|
1718
1770
|
setSettled(isTerminal(result));
|
|
1719
1771
|
if (wasAdded(result) && slip.onMarketClicked) {
|
|
@@ -1723,6 +1775,9 @@ function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
|
1723
1775
|
}
|
|
1724
1776
|
}
|
|
1725
1777
|
} catch {
|
|
1778
|
+
if (marketDeveloperName !== void 0) {
|
|
1779
|
+
log?.log({ name: "slip_result", entityType: "market", marketDeveloperName, entityId: marketDeveloperName, outcome: "timeout" });
|
|
1780
|
+
}
|
|
1726
1781
|
setToast({ kind: "error", text: ui.slipFailed });
|
|
1727
1782
|
} finally {
|
|
1728
1783
|
setPending(false);
|
|
@@ -1744,7 +1799,17 @@ function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
|
1744
1799
|
}
|
|
1745
1800
|
function AddToSlipButton({ it, slip, ui }) {
|
|
1746
1801
|
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
1747
|
-
return /* @__PURE__ */ jsx9(
|
|
1802
|
+
return /* @__PURE__ */ jsx9(
|
|
1803
|
+
SlipButton,
|
|
1804
|
+
{
|
|
1805
|
+
selection,
|
|
1806
|
+
shownOdds: it.odds ?? "",
|
|
1807
|
+
marketName: it.market,
|
|
1808
|
+
marketDeveloperName: it.marketDeveloperName,
|
|
1809
|
+
slip,
|
|
1810
|
+
ui
|
|
1811
|
+
}
|
|
1812
|
+
);
|
|
1748
1813
|
}
|
|
1749
1814
|
|
|
1750
1815
|
// src/components/OddsMovementBadge.tsx
|
|
@@ -1794,13 +1859,21 @@ var PIN_GLYPHS = {
|
|
|
1794
1859
|
function PinToggle({ pin, monitor, ui }) {
|
|
1795
1860
|
const [toast, setToast] = useState8(null);
|
|
1796
1861
|
const dismiss = useCallback4(() => setToast(null), []);
|
|
1862
|
+
const log = useEventLog();
|
|
1797
1863
|
if (!monitor || !monitor.enabled) return null;
|
|
1798
1864
|
const key = pinKey(pin);
|
|
1799
1865
|
const pinned = monitor.isPinned(key);
|
|
1800
1866
|
const labels = pin.kind === "match" ? { pin: ui.matchPinLabel, unpin: ui.matchUnpinLabel } : { pin: ui.pinLabel, unpin: ui.unpinLabel };
|
|
1801
1867
|
const onClick = () => {
|
|
1802
1868
|
const result = monitor.togglePin({ ...pin, key });
|
|
1803
|
-
if (result === "
|
|
1869
|
+
if ((result === "added" || result === "removed") && (pin.kind === "match" || pin.marketDeveloperName !== void 0)) {
|
|
1870
|
+
log?.log({
|
|
1871
|
+
name: result === "added" ? "pin_add" : "pin_remove",
|
|
1872
|
+
entityType: pin.kind === "match" ? "match" : "market",
|
|
1873
|
+
entityId: pin.kind === "match" ? String(pin.matchId) : pin.marketDeveloperName,
|
|
1874
|
+
marketDeveloperName: pin.marketDeveloperName
|
|
1875
|
+
});
|
|
1876
|
+
} else if (result === "match_limit") {
|
|
1804
1877
|
setToast({ kind: "error", text: ui.matchLimitToast });
|
|
1805
1878
|
} else if (result === "market_limit") {
|
|
1806
1879
|
setToast({ kind: "error", text: ui.marketLimitToast });
|
|
@@ -1857,11 +1930,19 @@ function hasStatsContent(it) {
|
|
|
1857
1930
|
}
|
|
1858
1931
|
function ReasonStrip({ it, ui }) {
|
|
1859
1932
|
const [open, setOpen] = useState9(false);
|
|
1933
|
+
const log = useEventLog();
|
|
1860
1934
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1861
1935
|
const hasStats = hasStatsContent(it);
|
|
1862
1936
|
const hasText = !!it.text;
|
|
1863
1937
|
if (!hasText && !hasStats) return null;
|
|
1864
1938
|
const expandable = hasStats || (it.text?.length ?? 0) > 90;
|
|
1939
|
+
const onToggle = () => {
|
|
1940
|
+
setOpen((v) => {
|
|
1941
|
+
const next = !v;
|
|
1942
|
+
if (next) log?.log({ name: "insight_expand", entityType: "match", entityId: String(it.matchId) });
|
|
1943
|
+
return next;
|
|
1944
|
+
});
|
|
1945
|
+
};
|
|
1865
1946
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-reason", children: [
|
|
1866
1947
|
/* @__PURE__ */ jsx13("span", { className: "ss-w-bi-chart", "aria-hidden": "true" }),
|
|
1867
1948
|
/* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-reason-body", children: [
|
|
@@ -1875,7 +1956,7 @@ function ReasonStrip({ it, ui }) {
|
|
|
1875
1956
|
className: "ss-w-bi-expand",
|
|
1876
1957
|
"aria-expanded": open,
|
|
1877
1958
|
"aria-label": open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats",
|
|
1878
|
-
onClick:
|
|
1959
|
+
onClick: onToggle,
|
|
1879
1960
|
children: /* @__PURE__ */ jsx13("span", { className: `ss-w-bi-arrow${open ? " ss-w-bi-arrow-open" : ""}`, "aria-hidden": "true" })
|
|
1880
1961
|
}
|
|
1881
1962
|
) : null
|
|
@@ -1981,7 +2062,7 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
1981
2062
|
"\u2713 ",
|
|
1982
2063
|
ui.inSlipLabel
|
|
1983
2064
|
] }) : null,
|
|
1984
|
-
/* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
2065
|
+
/* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, marketDeveloperName: vm.marketDeveloperName, slip, ui })
|
|
1985
2066
|
] });
|
|
1986
2067
|
}
|
|
1987
2068
|
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
|
|
@@ -3313,6 +3394,7 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
3313
3394
|
selection,
|
|
3314
3395
|
shownOdds: typeof row.market.price === "number" ? row.market.price.toFixed(2) : "",
|
|
3315
3396
|
marketName: row.market.marketLabel,
|
|
3397
|
+
marketDeveloperName: row.market.marketDeveloperName,
|
|
3316
3398
|
slip,
|
|
3317
3399
|
ui
|
|
3318
3400
|
}
|
|
@@ -4327,6 +4409,13 @@ function StatsWidget(props) {
|
|
|
4327
4409
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
4328
4410
|
const cfg = props.config;
|
|
4329
4411
|
const built = useMemo2(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
4412
|
+
const logger = useMemo2(
|
|
4413
|
+
() => built ? built.client.createEventLogger({
|
|
4414
|
+
operatorUserId: cfg?.userContext?.operatorUserId,
|
|
4415
|
+
anonymousUserId: cfg?.userContext?.anonymousUserId
|
|
4416
|
+
}) : null,
|
|
4417
|
+
[built?.client]
|
|
4418
|
+
);
|
|
4330
4419
|
const ui = useMemo2(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
4331
4420
|
const rootRef = useRef8(null);
|
|
4332
4421
|
const introDoneRef = useRef8(false);
|
|
@@ -4365,9 +4454,33 @@ function StatsWidget(props) {
|
|
|
4365
4454
|
[props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
|
|
4366
4455
|
);
|
|
4367
4456
|
const onDashboardTap = useMemo2(
|
|
4368
|
-
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
4369
|
-
[built]
|
|
4457
|
+
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
|
|
4458
|
+
[built, logger]
|
|
4370
4459
|
);
|
|
4460
|
+
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
4461
|
+
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
4462
|
+
const conversationId = controller.state.conversationId ?? void 0;
|
|
4463
|
+
useEffect11(() => {
|
|
4464
|
+
if (!logger) return;
|
|
4465
|
+
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
4466
|
+
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
4467
|
+
useEffect11(() => {
|
|
4468
|
+
if (!logger) return;
|
|
4469
|
+
const onHide = () => {
|
|
4470
|
+
logger.flushOnHide();
|
|
4471
|
+
};
|
|
4472
|
+
const onVisibilityHide = () => {
|
|
4473
|
+
if (document.visibilityState === "hidden") logger.flushOnHide();
|
|
4474
|
+
};
|
|
4475
|
+
window.addEventListener("pagehide", onHide);
|
|
4476
|
+
document.addEventListener("visibilitychange", onVisibilityHide);
|
|
4477
|
+
return () => {
|
|
4478
|
+
window.removeEventListener("pagehide", onHide);
|
|
4479
|
+
document.removeEventListener("visibilitychange", onVisibilityHide);
|
|
4480
|
+
logger.flushOnHide();
|
|
4481
|
+
logger.dispose();
|
|
4482
|
+
};
|
|
4483
|
+
}, [logger]);
|
|
4371
4484
|
useEffect11(() => {
|
|
4372
4485
|
if (!built || !ui.injectStyles) return;
|
|
4373
4486
|
const node = rootRef.current?.getRootNode();
|
|
@@ -4375,7 +4488,7 @@ function StatsWidget(props) {
|
|
|
4375
4488
|
}, [built, ui.injectStyles]);
|
|
4376
4489
|
if (!built) return null;
|
|
4377
4490
|
const attrs = themeAttrs(ui);
|
|
4378
|
-
return /* @__PURE__ */ jsx50("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__ */ jsx50(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ jsx50(
|
|
4491
|
+
return /* @__PURE__ */ jsx50(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ jsx50("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__ */ jsx50(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ jsx50(
|
|
4379
4492
|
ChatFab,
|
|
4380
4493
|
{
|
|
4381
4494
|
label: ui.launcherLabel,
|
|
@@ -4388,7 +4501,7 @@ function StatsWidget(props) {
|
|
|
4388
4501
|
introAllowed: !introDoneRef.current,
|
|
4389
4502
|
onIntroStart: markIntroDone
|
|
4390
4503
|
}
|
|
4391
|
-
) });
|
|
4504
|
+
) }) });
|
|
4392
4505
|
}
|
|
4393
4506
|
function emptyConversation() {
|
|
4394
4507
|
return { send: () => {
|