@sensiblestats/widget-react 0.68.0 → 0.69.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 +15 -0
- package/dist/index.cjs +764 -622
- 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 +873 -731
- package/dist/index.js.map +1 -1
- package/dist/styles.css +6 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/StatsWidget.tsx
|
|
2
|
-
import { useCallback as useCallback12, useEffect as
|
|
2
|
+
import { useCallback as useCallback12, useEffect as useEffect22, useMemo as useMemo4, useRef as useRef17, useState as useState41 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -34,6 +34,12 @@ var STRINGS = {
|
|
|
34
34
|
showMore: (n) => `Show ${n} more`,
|
|
35
35
|
oddsLabel: "Odds",
|
|
36
36
|
liveLabel: "Live",
|
|
37
|
+
liveCard: {
|
|
38
|
+
stale: (time) => `Prices from ${time}`,
|
|
39
|
+
suspended: "Market suspended",
|
|
40
|
+
noPrice: "No live price available",
|
|
41
|
+
fullTime: "Full time"
|
|
42
|
+
},
|
|
37
43
|
yourMarketTag: "Your market",
|
|
38
44
|
marketFloorLabel: "Market price \xB7 not a value pick",
|
|
39
45
|
addToSlip: "Add to slip",
|
|
@@ -334,6 +340,12 @@ var STRINGS = {
|
|
|
334
340
|
showMore: (n) => `${n} tane daha g\xF6ster`,
|
|
335
341
|
oddsLabel: "Oran",
|
|
336
342
|
liveLabel: "Canl\u0131",
|
|
343
|
+
liveCard: {
|
|
344
|
+
stale: (time) => `${time} itibar\u0131yla fiyatlar`,
|
|
345
|
+
suspended: "Market ask\u0131ya al\u0131nd\u0131",
|
|
346
|
+
noPrice: "Canl\u0131 fiyat mevcut de\u011Fil",
|
|
347
|
+
fullTime: "Ma\xE7 bitti"
|
|
348
|
+
},
|
|
337
349
|
yourMarketTag: "\u0130lgilendi\u011Fin bahis",
|
|
338
350
|
marketFloorLabel: "Piyasa oran\u0131 \xB7 de\u011Fer bahsi de\u011Fil",
|
|
339
351
|
addToSlip: "Kupona ekle",
|
|
@@ -635,6 +647,7 @@ function normalizeUi(cfg) {
|
|
|
635
647
|
accent: cfg.accent,
|
|
636
648
|
logoUrl: cfg.logoUrl,
|
|
637
649
|
headerTitle: cfg.headerTitle,
|
|
650
|
+
locale: cfg.locale ?? "en",
|
|
638
651
|
rawBettingLabels: isEnglishLocale(cfg.locale),
|
|
639
652
|
cta: cfg.cta,
|
|
640
653
|
surface: cfg.surface,
|
|
@@ -741,7 +754,8 @@ function normalizeUi(cfg) {
|
|
|
741
754
|
gamePlay: strings.gamePlay,
|
|
742
755
|
gameLocked: strings.gameLocked,
|
|
743
756
|
gameVoided: strings.gameVoided,
|
|
744
|
-
games: strings.games
|
|
757
|
+
games: strings.games,
|
|
758
|
+
liveCard: strings.liveCard
|
|
745
759
|
};
|
|
746
760
|
}
|
|
747
761
|
function toClientOptions(cfg) {
|
|
@@ -753,708 +767,709 @@ function toUserContext(cfg) {
|
|
|
753
767
|
return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : void 0;
|
|
754
768
|
}
|
|
755
769
|
|
|
756
|
-
// src/
|
|
757
|
-
var
|
|
758
|
-
var
|
|
759
|
-
var
|
|
760
|
-
var
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
if (
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
770
|
+
// src/chart.ts
|
|
771
|
+
var CHART_VIEW_W = 320;
|
|
772
|
+
var CHART_VIEW_H = 140;
|
|
773
|
+
var PLOT_X0 = 40;
|
|
774
|
+
var PLOT_X1 = 312;
|
|
775
|
+
var PLOT_Y0 = 10;
|
|
776
|
+
var PLOT_Y1 = 110;
|
|
777
|
+
var MARKER_MAX_POINTS = 8;
|
|
778
|
+
var FLAT_DOMAIN_PAD = 0.05;
|
|
779
|
+
var round2 = (n) => Math.round(n * 100) / 100;
|
|
780
|
+
function projectSeries(samples) {
|
|
781
|
+
if (samples.length < 2) return null;
|
|
782
|
+
const tMin = samples[0].atMs;
|
|
783
|
+
const tMax = samples[samples.length - 1].atMs;
|
|
784
|
+
if (tMax <= tMin) return null;
|
|
785
|
+
const prices = samples.map((s) => s.price);
|
|
786
|
+
const pMin = Math.min(...prices);
|
|
787
|
+
const pMax = Math.max(...prices);
|
|
788
|
+
let yMin;
|
|
789
|
+
let yMax;
|
|
790
|
+
if (pMax === pMin) {
|
|
791
|
+
yMin = pMin - FLAT_DOMAIN_PAD;
|
|
792
|
+
yMax = pMax + FLAT_DOMAIN_PAD;
|
|
793
|
+
} else {
|
|
794
|
+
const pad = (pMax - pMin) * 0.1;
|
|
795
|
+
yMin = pMin - pad;
|
|
796
|
+
yMax = pMax + pad;
|
|
797
|
+
}
|
|
798
|
+
const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
|
|
799
|
+
const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
|
|
800
|
+
const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
|
|
801
|
+
const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
|
|
802
|
+
return {
|
|
803
|
+
path,
|
|
804
|
+
markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
|
|
805
|
+
// The real extremes, never the padded bounds: a gridline label is a price, and the padded
|
|
806
|
+
// bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
|
|
807
|
+
// two identical gridlines would collide on both React key and rendered text.
|
|
808
|
+
gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
|
|
809
|
+
{ y: y(pMax), price: pMax },
|
|
810
|
+
{ y: y(pMin), price: pMin }
|
|
811
|
+
],
|
|
812
|
+
viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
|
|
813
|
+
startMs: tMin,
|
|
814
|
+
endMs: tMax
|
|
815
|
+
};
|
|
775
816
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
return
|
|
817
|
+
|
|
818
|
+
// src/model.ts
|
|
819
|
+
function str(v) {
|
|
820
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
780
821
|
}
|
|
781
|
-
function
|
|
782
|
-
|
|
783
|
-
if (result.status === "price_changed") return result.accepted;
|
|
784
|
-
return result.status === "added" || result.status === "duplicate";
|
|
822
|
+
function num(v) {
|
|
823
|
+
return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
|
|
785
824
|
}
|
|
786
|
-
function
|
|
787
|
-
if (!
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
return result.accepted ? "added" : "price_changed";
|
|
794
|
-
case "rejected":
|
|
795
|
-
return result.reason;
|
|
825
|
+
function readStatCells(raw) {
|
|
826
|
+
if (!Array.isArray(raw)) return [];
|
|
827
|
+
const cells = [];
|
|
828
|
+
for (const entry of raw) {
|
|
829
|
+
const label = str(entry.label);
|
|
830
|
+
const value = num(entry.value) ?? str(entry.value);
|
|
831
|
+
if (label !== void 0 && value !== void 0) cells.push({ label, value });
|
|
796
832
|
}
|
|
833
|
+
return cells;
|
|
797
834
|
}
|
|
798
|
-
function
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
835
|
+
function toCardVM(card) {
|
|
836
|
+
const entityType = str(card.entityType)?.toLowerCase();
|
|
837
|
+
const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
|
|
838
|
+
const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
|
|
839
|
+
const label = str(s.label);
|
|
840
|
+
if (!label) return null;
|
|
841
|
+
return {
|
|
842
|
+
competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
|
|
843
|
+
label,
|
|
844
|
+
image: str(s.imagePath),
|
|
845
|
+
stats: readStatCells(s.stats)
|
|
846
|
+
};
|
|
847
|
+
}).filter((s) => s !== null) : [];
|
|
848
|
+
return {
|
|
849
|
+
id: String(card.entityId),
|
|
850
|
+
kind,
|
|
851
|
+
name: card.canonicalName,
|
|
852
|
+
image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
|
|
853
|
+
sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
|
|
854
|
+
season: str(card.seasonName),
|
|
855
|
+
scopes
|
|
856
|
+
};
|
|
812
857
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
// src/components/ChatHeader.tsx
|
|
821
|
-
import { useEffect, useRef, useState as useState2 } from "react";
|
|
822
|
-
|
|
823
|
-
// src/assets/logo.ts
|
|
824
|
-
var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
|
|
825
|
-
|
|
826
|
-
// src/components/Icons.tsx
|
|
827
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
828
|
-
function SsMark({ className }) {
|
|
829
|
-
return /* @__PURE__ */ jsx("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
|
|
858
|
+
function toActionVM(action) {
|
|
859
|
+
const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
|
|
860
|
+
const actionId = str(action.actionId) ?? str(action.id);
|
|
861
|
+
const actionRef = str(action.actionRef);
|
|
862
|
+
const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
|
|
863
|
+
return { label, actionId, actionRef, message };
|
|
830
864
|
}
|
|
831
|
-
function
|
|
832
|
-
|
|
865
|
+
function toChipVM(intent) {
|
|
866
|
+
const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
|
|
867
|
+
return text ? { text } : null;
|
|
833
868
|
}
|
|
834
|
-
function
|
|
835
|
-
return
|
|
869
|
+
function chipFromText(text) {
|
|
870
|
+
return { text };
|
|
836
871
|
}
|
|
837
|
-
function
|
|
838
|
-
|
|
872
|
+
function joinSelection(label, line) {
|
|
873
|
+
if (label && line && label.includes(line)) return label;
|
|
874
|
+
return [label, line].filter(Boolean).join(" ") || void 0;
|
|
839
875
|
}
|
|
840
|
-
function
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
876
|
+
function toInsightVM(insight) {
|
|
877
|
+
const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
|
|
878
|
+
const selectionLabel = str(insight.selectionLabel);
|
|
879
|
+
const selectionLine = str(insight.line);
|
|
880
|
+
const selection = joinSelection(selectionLabel, selectionLine);
|
|
881
|
+
const value = insight.odds?.value;
|
|
882
|
+
const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
|
|
883
|
+
const oddsValue = insight.odds?.value;
|
|
884
|
+
const matchOddsId = typeof insight.odds?.matchOddsId === "number" ? insight.odds.matchOddsId : void 0;
|
|
885
|
+
const home = str(insight.homeTeamName);
|
|
886
|
+
const away = str(insight.awayTeamName);
|
|
887
|
+
const fixture = home && away ? `${home} vs ${away}` : void 0;
|
|
888
|
+
const competition = str(insight.competitionName);
|
|
889
|
+
const previousValue = insight.odds?.previousValue;
|
|
890
|
+
const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
|
|
891
|
+
const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
|
|
892
|
+
return {
|
|
893
|
+
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
894
|
+
market,
|
|
895
|
+
selection,
|
|
896
|
+
odds,
|
|
897
|
+
// The wire payload carries bookmakerId (not a name); render a name only if one is present.
|
|
898
|
+
bookmaker: str(insight.odds?.bookmakerName),
|
|
899
|
+
isLive: insight.odds?.isLive === true,
|
|
900
|
+
phase: str(insight.phase),
|
|
901
|
+
fixture,
|
|
902
|
+
competition,
|
|
903
|
+
text: str(insight.text) ?? "",
|
|
904
|
+
disclaimer: str(insight.disclaimer),
|
|
905
|
+
matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
|
|
906
|
+
matchOddsId,
|
|
907
|
+
marketDeveloperName: str(insight.marketDeveloperName),
|
|
908
|
+
selectionLabel: str(insight.selectionLabel),
|
|
909
|
+
line: str(insight.line),
|
|
910
|
+
addToSlipEnabled: insight.addToSlipEnabled === true,
|
|
911
|
+
pinEnabled: insight.pinEnabled === true,
|
|
912
|
+
isMarketFloor: insight.isMarketFloor === true,
|
|
913
|
+
oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
|
|
914
|
+
quotedAtUtc: str(insight.odds?.quotedAtUtc),
|
|
915
|
+
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
916
|
+
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
|
|
917
|
+
homeTeamName: home,
|
|
918
|
+
awayTeamName: away,
|
|
919
|
+
homeCrest: str(insight.homeTeamImagePath),
|
|
920
|
+
awayCrest: str(insight.awayTeamImagePath),
|
|
921
|
+
competitionCrest: str(insight.competitionImagePath),
|
|
922
|
+
kickoffUtc: str(insight.kickoffUtc),
|
|
923
|
+
kickoffLabel: str(insight.kickoffLabel)
|
|
924
|
+
};
|
|
846
925
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
chat: "\u{1F4AC}",
|
|
859
|
-
fire: "\u{1F525}",
|
|
860
|
-
sparkle: "\u2728"
|
|
861
|
-
};
|
|
862
|
-
function DashboardIcon({ name }) {
|
|
863
|
-
const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
|
|
864
|
-
return /* @__PURE__ */ jsx("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
|
|
926
|
+
function toSlipSelection(vm, conversationId) {
|
|
927
|
+
if (vm.matchOddsId === void 0 || vm.oddsDecimal === void 0) return null;
|
|
928
|
+
const selection = {
|
|
929
|
+
matchOddsId: vm.matchOddsId,
|
|
930
|
+
matchId: vm.matchId,
|
|
931
|
+
oddsDecimal: vm.oddsDecimal
|
|
932
|
+
};
|
|
933
|
+
if (vm.quotedAtUtc !== void 0) selection.quotedAtUtc = vm.quotedAtUtc;
|
|
934
|
+
if (vm.id !== void 0) selection.insightId = vm.id;
|
|
935
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
936
|
+
return selection;
|
|
865
937
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
const [menuOpen, setMenuOpen] = useState2(false);
|
|
889
|
-
const wrapRef = useRef(null);
|
|
890
|
-
const kebabRef = useRef(null);
|
|
891
|
-
const firstItemRef = useRef(null);
|
|
892
|
-
const hasMenu = !!(canReset && onNewConversation);
|
|
893
|
-
useEffect(() => {
|
|
894
|
-
if (menuOpen) firstItemRef.current?.focus();
|
|
895
|
-
}, [menuOpen]);
|
|
896
|
-
useEffect(() => {
|
|
897
|
-
if (!menuOpen) return;
|
|
898
|
-
const onPointer = (e) => {
|
|
899
|
-
if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
|
|
900
|
-
};
|
|
901
|
-
const onKey = (e) => {
|
|
902
|
-
if (e.key === "Escape") {
|
|
903
|
-
setMenuOpen(false);
|
|
904
|
-
kebabRef.current?.focus();
|
|
905
|
-
}
|
|
906
|
-
};
|
|
907
|
-
document.addEventListener("mousedown", onPointer);
|
|
908
|
-
document.addEventListener("keydown", onKey);
|
|
909
|
-
return () => {
|
|
910
|
-
document.removeEventListener("mousedown", onPointer);
|
|
911
|
-
document.removeEventListener("keydown", onKey);
|
|
938
|
+
function toMarketOddsVM(card) {
|
|
939
|
+
const rows = Array.isArray(card.rows) ? card.rows : [];
|
|
940
|
+
const toRow = (r, i) => {
|
|
941
|
+
const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
|
|
942
|
+
const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
|
|
943
|
+
const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
|
|
944
|
+
const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
|
|
945
|
+
return {
|
|
946
|
+
key: `${selection}:${str(r.line) ?? ""}:${i}`,
|
|
947
|
+
selection,
|
|
948
|
+
selectionLabel: str(r.selectionLabel),
|
|
949
|
+
line: str(r.line),
|
|
950
|
+
odds: price !== void 0 ? price.toFixed(2) : "",
|
|
951
|
+
oddsDecimal: price,
|
|
952
|
+
matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
|
|
953
|
+
quotedAtUtc: str(r.quotedAtUtc),
|
|
954
|
+
isMain: r.isMainLine !== false,
|
|
955
|
+
// === true, not !== false: a server that has not shipped the field yet leaves it undefined,
|
|
956
|
+
// and undefined must read as open rather than hiding every price on the card.
|
|
957
|
+
isSuspended: r.isSuspended === true,
|
|
958
|
+
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
959
|
+
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
|
|
912
960
|
};
|
|
913
|
-
}, [menuOpen]);
|
|
914
|
-
const runNewConversation = () => {
|
|
915
|
-
setMenuOpen(false);
|
|
916
|
-
onNewConversation?.();
|
|
917
961
|
};
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/components/MessageList.tsx
|
|
952
|
-
import { useEffect as useEffect6, useRef as useRef4 } from "react";
|
|
953
|
-
|
|
954
|
-
// src/presets.ts
|
|
955
|
-
var CLIENT_CAPABILITIES = ["price_presets"];
|
|
956
|
-
var PRICE_TILE_PREFIX = "goal-preset-";
|
|
957
|
-
function isPriceTile(tile) {
|
|
958
|
-
const id = tile.signal?.entityId;
|
|
959
|
-
return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
|
|
960
|
-
}
|
|
961
|
-
function tileDisplayText(tile) {
|
|
962
|
-
const subtitle = tile.subtitle?.trim();
|
|
963
|
-
return isPriceTile(tile) && subtitle ? subtitle : tile.title;
|
|
962
|
+
const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
|
|
963
|
+
const home = str(card.homeTeamName);
|
|
964
|
+
const away = str(card.awayTeamName);
|
|
965
|
+
const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
|
|
966
|
+
return {
|
|
967
|
+
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
968
|
+
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
969
|
+
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
970
|
+
homeTeamName: home,
|
|
971
|
+
awayTeamName: away,
|
|
972
|
+
homeCrest: str(card.homeTeamImagePath),
|
|
973
|
+
awayCrest: str(card.awayTeamImagePath),
|
|
974
|
+
competitionCrest: str(card.competitionImagePath),
|
|
975
|
+
competition: str(card.competitionName),
|
|
976
|
+
kickoffUtc: str(card.kickoffUtc),
|
|
977
|
+
kickoffLabel: str(card.kickoffLabel),
|
|
978
|
+
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
979
|
+
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
980
|
+
isLive: rows.some((r) => r.isLive === true),
|
|
981
|
+
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
982
|
+
mainRows: vms.filter((r) => r.isMain),
|
|
983
|
+
moreRows: vms.filter((r) => !r.isMain),
|
|
984
|
+
disclaimer: str(card.disclaimer),
|
|
985
|
+
addToSlipEnabled: card.addToSlipEnabled === true,
|
|
986
|
+
marketDeveloperName: str(card.marketDeveloperName),
|
|
987
|
+
mainLine: str(card.mainLine),
|
|
988
|
+
pinEnabled: card.pinEnabled === true,
|
|
989
|
+
statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
|
|
990
|
+
tag: card.tag === "your_market" ? "your_market" : void 0,
|
|
991
|
+
live: card.live ?? null
|
|
992
|
+
};
|
|
964
993
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
if (
|
|
972
|
-
|
|
973
|
-
dashboard.tiles.forEach((tile, index) => {
|
|
974
|
-
const label = tile.subtitle?.trim();
|
|
975
|
-
if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
|
|
976
|
-
});
|
|
977
|
-
return asks;
|
|
994
|
+
function toOddsMovementVM(card) {
|
|
995
|
+
const raw = Array.isArray(card.points) ? card.points : [];
|
|
996
|
+
const samples = [];
|
|
997
|
+
for (const p of raw) {
|
|
998
|
+
const price = typeof p.price === "number" && Number.isFinite(p.price) ? p.price : void 0;
|
|
999
|
+
const atMs = typeof p.atUtc === "string" ? Date.parse(p.atUtc) : NaN;
|
|
1000
|
+
if (price === void 0 || Number.isNaN(atMs)) continue;
|
|
1001
|
+
samples.push({ atMs, price });
|
|
978
1002
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
function initials(name) {
|
|
1011
|
-
return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
|
|
1003
|
+
samples.sort((a, b) => a.atMs - b.atMs);
|
|
1004
|
+
const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
1005
|
+
const opening = asNumber(card.openingPrice);
|
|
1006
|
+
const current = asNumber(card.currentPrice);
|
|
1007
|
+
const home = str(card.homeTeamName);
|
|
1008
|
+
const away = str(card.awayTeamName);
|
|
1009
|
+
const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
|
|
1010
|
+
const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
|
|
1011
|
+
return {
|
|
1012
|
+
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
|
|
1013
|
+
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
1014
|
+
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
1015
|
+
marketDeveloperName: str(card.marketDeveloperName),
|
|
1016
|
+
selection,
|
|
1017
|
+
selectionLabel: str(card.selectionLabel),
|
|
1018
|
+
line: str(card.line),
|
|
1019
|
+
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
1020
|
+
competition: str(card.competitionName),
|
|
1021
|
+
bookmaker: str(card.bookmakerName),
|
|
1022
|
+
opening: opening !== void 0 ? opening.toFixed(2) : "",
|
|
1023
|
+
current: current !== void 0 ? current.toFixed(2) : "",
|
|
1024
|
+
direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
|
|
1025
|
+
windowHours: asNumber(card.windowHours) ?? 0,
|
|
1026
|
+
excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
|
|
1027
|
+
isSuspended: card.isSuspended === true,
|
|
1028
|
+
disclaimer: str(card.disclaimer),
|
|
1029
|
+
geometry: projectSeries(samples),
|
|
1030
|
+
observationCount: samples.length,
|
|
1031
|
+
pinEnabled: card.pinEnabled === true,
|
|
1032
|
+
matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
|
|
1033
|
+
};
|
|
1012
1034
|
}
|
|
1013
|
-
function
|
|
1014
|
-
|
|
1035
|
+
function marketOddsRowToSlipSelection(vm, row, conversationId) {
|
|
1036
|
+
if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
|
|
1037
|
+
const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
|
|
1038
|
+
if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
|
|
1039
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
1040
|
+
return selection;
|
|
1015
1041
|
}
|
|
1016
|
-
function
|
|
1017
|
-
return
|
|
1018
|
-
"span",
|
|
1019
|
-
{
|
|
1020
|
-
className: "ss-w-ecard-crest",
|
|
1021
|
-
style: { backgroundImage: `url(${image})` },
|
|
1022
|
-
...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
|
|
1023
|
-
}
|
|
1024
|
-
);
|
|
1042
|
+
function finite(v) {
|
|
1043
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
1025
1044
|
}
|
|
1026
|
-
function
|
|
1027
|
-
if (
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1045
|
+
function toComboLegVM(leg) {
|
|
1046
|
+
if (!leg || typeof leg !== "object") return null;
|
|
1047
|
+
const price = finite(leg.price);
|
|
1048
|
+
const matchOddsId = finite(leg.matchOddsId);
|
|
1049
|
+
const matchId = finite(leg.matchId);
|
|
1050
|
+
const home = str(leg.homeTeamName);
|
|
1051
|
+
const away = str(leg.awayTeamName);
|
|
1052
|
+
const selectionLabel = str(leg.selectionLabel);
|
|
1053
|
+
const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
|
|
1054
|
+
const insightId = str(insight?.insightId);
|
|
1055
|
+
const statText = str(insight?.text);
|
|
1056
|
+
if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
|
|
1057
|
+
const line = str(leg.line);
|
|
1058
|
+
return {
|
|
1059
|
+
key: `${matchOddsId}`,
|
|
1060
|
+
matchId,
|
|
1061
|
+
homeTeamName: home,
|
|
1062
|
+
awayTeamName: away,
|
|
1063
|
+
homeCrest: str(leg.homeTeamImagePath),
|
|
1064
|
+
awayCrest: str(leg.awayTeamImagePath),
|
|
1065
|
+
competition: str(leg.competitionName),
|
|
1066
|
+
kickoffUtc: str(leg.kickoffUtc),
|
|
1067
|
+
kickoffLabel: str(leg.kickoffLabel),
|
|
1068
|
+
market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
|
|
1069
|
+
marketDeveloperName: str(leg.marketDeveloperName) ?? "",
|
|
1070
|
+
selection: joinSelection(selectionLabel, line) ?? selectionLabel,
|
|
1071
|
+
selectionLabel,
|
|
1072
|
+
line,
|
|
1073
|
+
odds: price.toFixed(2),
|
|
1074
|
+
oddsDecimal: price,
|
|
1075
|
+
matchOddsId,
|
|
1076
|
+
quotedAtUtc: str(leg.quotedAtUtc),
|
|
1077
|
+
insightId,
|
|
1078
|
+
statText
|
|
1079
|
+
};
|
|
1033
1080
|
}
|
|
1034
|
-
function
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1081
|
+
function toComboCardVM(card) {
|
|
1082
|
+
const rawLegs = Array.isArray(card?.legs) ? card.legs : [];
|
|
1083
|
+
const multiplication = str(card?.multiplication);
|
|
1084
|
+
if (rawLegs.length < 2 || !multiplication) return null;
|
|
1085
|
+
const legs = [];
|
|
1086
|
+
for (const raw of rawLegs) {
|
|
1087
|
+
const vm = toComboLegVM(raw);
|
|
1088
|
+
if (!vm) return null;
|
|
1089
|
+
legs.push(vm);
|
|
1041
1090
|
}
|
|
1042
|
-
return
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1091
|
+
return {
|
|
1092
|
+
id: str(card.comboId) ?? legs.map((l) => l.matchOddsId).join("-"),
|
|
1093
|
+
legs,
|
|
1094
|
+
multiplication,
|
|
1095
|
+
replacedNote: str(card.replacedNote),
|
|
1096
|
+
addToSlipEnabled: card.addToSlipEnabled === true
|
|
1097
|
+
};
|
|
1046
1098
|
}
|
|
1047
|
-
function
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1099
|
+
function comboLegToSlipSelection(leg, conversationId) {
|
|
1100
|
+
const selection = {
|
|
1101
|
+
matchOddsId: leg.matchOddsId,
|
|
1102
|
+
matchId: leg.matchId,
|
|
1103
|
+
oddsDecimal: leg.oddsDecimal,
|
|
1104
|
+
insightId: leg.insightId
|
|
1105
|
+
};
|
|
1106
|
+
if (leg.quotedAtUtc !== void 0) selection.quotedAtUtc = leg.quotedAtUtc;
|
|
1107
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
1108
|
+
return selection;
|
|
1051
1109
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1110
|
+
|
|
1111
|
+
// src/slip.ts
|
|
1112
|
+
var ADD_TO_SLIP_TIMEOUT_MS = 1e4;
|
|
1113
|
+
var MAX_SELECTION = 64;
|
|
1114
|
+
var MAX_LINE = 32;
|
|
1115
|
+
var MAX_ODDS = 1e4;
|
|
1116
|
+
function slipPickFields(selection, label, line) {
|
|
1117
|
+
const fields = {};
|
|
1118
|
+
if (Number.isSafeInteger(selection.matchId) && selection.matchId > 0) fields.matchId = selection.matchId;
|
|
1119
|
+
if (label && label.trim() && label.length <= MAX_SELECTION) fields.selection = label;
|
|
1120
|
+
if (line && line.trim() && line.length <= MAX_LINE) fields.line = line;
|
|
1121
|
+
const odds = selection.oddsDecimal;
|
|
1122
|
+
if (Number.isFinite(odds) && odds > 1 && odds <= MAX_ODDS) fields.odds = odds;
|
|
1123
|
+
return fields;
|
|
1124
|
+
}
|
|
1125
|
+
function chipSelection(market, matchId, conversationId) {
|
|
1126
|
+
if (!market || !market.addToSlipEnabled || typeof market.matchOddsId !== "number" || typeof market.price !== "number") return null;
|
|
1127
|
+
const selection = { matchOddsId: market.matchOddsId, matchId, oddsDecimal: market.price };
|
|
1128
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
1129
|
+
return selection;
|
|
1072
1130
|
}
|
|
1073
|
-
function
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
type: "button",
|
|
1078
|
-
role: "tab",
|
|
1079
|
-
className: "ss-w-ecard-scope",
|
|
1080
|
-
"aria-selected": i === active,
|
|
1081
|
-
"aria-label": s.label,
|
|
1082
|
-
title: s.label,
|
|
1083
|
-
onClick: () => onSelect(i),
|
|
1084
|
-
children: s.image ? /* @__PURE__ */ jsx5(Crest, { image: s.image }) : s.label
|
|
1085
|
-
},
|
|
1086
|
-
String(s.competitionId ?? "all")
|
|
1087
|
-
)) });
|
|
1131
|
+
function wasAdded(result) {
|
|
1132
|
+
if (!result) return true;
|
|
1133
|
+
if (result.status === "price_changed") return result.accepted;
|
|
1134
|
+
return result.status === "added";
|
|
1088
1135
|
}
|
|
1089
|
-
function
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1136
|
+
function isTerminal(result) {
|
|
1137
|
+
if (!result) return true;
|
|
1138
|
+
if (result.status === "price_changed") return result.accepted;
|
|
1139
|
+
return result.status === "added" || result.status === "duplicate";
|
|
1140
|
+
}
|
|
1141
|
+
function slipOutcome(result) {
|
|
1142
|
+
if (!result) return "added";
|
|
1143
|
+
switch (result.status) {
|
|
1144
|
+
case "added":
|
|
1145
|
+
case "duplicate":
|
|
1146
|
+
return result.status;
|
|
1147
|
+
case "price_changed":
|
|
1148
|
+
return result.accepted ? "added" : "price_changed";
|
|
1149
|
+
case "rejected":
|
|
1150
|
+
return result.reason;
|
|
1094
1151
|
}
|
|
1095
|
-
const multi = c.scopes.length > 1;
|
|
1096
|
-
const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
|
|
1097
|
-
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
|
|
1098
|
-
/* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: !multi }),
|
|
1099
|
-
multi ? /* @__PURE__ */ jsx5(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
|
|
1100
|
-
/* @__PURE__ */ jsx5(StatStrip, { stats: scope.stats })
|
|
1101
|
-
] });
|
|
1102
1152
|
}
|
|
1103
|
-
function
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1153
|
+
function resultToToast(result, shownOdds, ui) {
|
|
1154
|
+
if (!result) return { kind: "success", text: ui.slipAdded };
|
|
1155
|
+
switch (result.status) {
|
|
1156
|
+
case "added":
|
|
1157
|
+
return { kind: "success", text: ui.slipAdded };
|
|
1158
|
+
case "duplicate":
|
|
1159
|
+
return { kind: "success", text: ui.slipDuplicate };
|
|
1160
|
+
case "price_changed":
|
|
1161
|
+
return result.accepted ? { kind: "success", text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) } : { kind: "error", text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) };
|
|
1162
|
+
case "rejected":
|
|
1163
|
+
if (result.reason === "login_required") return { kind: "error", text: ui.slipLoginRequired };
|
|
1164
|
+
if (result.reason === "suspended") return { kind: "error", text: ui.slipSuspended };
|
|
1165
|
+
return { kind: "error", text: result.message ?? ui.slipFailed };
|
|
1166
|
+
}
|
|
1112
1167
|
}
|
|
1113
1168
|
|
|
1114
|
-
// src/
|
|
1115
|
-
import { useCallback, useState as
|
|
1116
|
-
import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
|
|
1169
|
+
// src/useHostEvents.ts
|
|
1170
|
+
import { useCallback as useCallback5, useEffect as useEffect13, useMemo, useRef as useRef8, useState as useState34 } from "react";
|
|
1117
1171
|
|
|
1118
|
-
// src/
|
|
1119
|
-
|
|
1120
|
-
var CHART_VIEW_H = 140;
|
|
1121
|
-
var PLOT_X0 = 40;
|
|
1122
|
-
var PLOT_X1 = 312;
|
|
1123
|
-
var PLOT_Y0 = 10;
|
|
1124
|
-
var PLOT_Y1 = 110;
|
|
1125
|
-
var MARKER_MAX_POINTS = 8;
|
|
1126
|
-
var FLAT_DOMAIN_PAD = 0.05;
|
|
1127
|
-
var round2 = (n) => Math.round(n * 100) / 100;
|
|
1128
|
-
function projectSeries(samples) {
|
|
1129
|
-
if (samples.length < 2) return null;
|
|
1130
|
-
const tMin = samples[0].atMs;
|
|
1131
|
-
const tMax = samples[samples.length - 1].atMs;
|
|
1132
|
-
if (tMax <= tMin) return null;
|
|
1133
|
-
const prices = samples.map((s) => s.price);
|
|
1134
|
-
const pMin = Math.min(...prices);
|
|
1135
|
-
const pMax = Math.max(...prices);
|
|
1136
|
-
let yMin;
|
|
1137
|
-
let yMax;
|
|
1138
|
-
if (pMax === pMin) {
|
|
1139
|
-
yMin = pMin - FLAT_DOMAIN_PAD;
|
|
1140
|
-
yMax = pMax + FLAT_DOMAIN_PAD;
|
|
1141
|
-
} else {
|
|
1142
|
-
const pad = (pMax - pMin) * 0.1;
|
|
1143
|
-
yMin = pMin - pad;
|
|
1144
|
-
yMax = pMax + pad;
|
|
1145
|
-
}
|
|
1146
|
-
const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
|
|
1147
|
-
const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
|
|
1148
|
-
const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
|
|
1149
|
-
const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
|
|
1150
|
-
return {
|
|
1151
|
-
path,
|
|
1152
|
-
markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
|
|
1153
|
-
// The real extremes, never the padded bounds: a gridline label is a price, and the padded
|
|
1154
|
-
// bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
|
|
1155
|
-
// two identical gridlines would collide on both React key and rendered text.
|
|
1156
|
-
gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
|
|
1157
|
-
{ y: y(pMax), price: pMax },
|
|
1158
|
-
{ y: y(pMin), price: pMin }
|
|
1159
|
-
],
|
|
1160
|
-
viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
|
|
1161
|
-
startMs: tMin,
|
|
1162
|
-
endMs: tMax
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1172
|
+
// src/components/ChatPanel.tsx
|
|
1173
|
+
import { useEffect as useEffect12, useState as useState33 } from "react";
|
|
1165
1174
|
|
|
1166
|
-
// src/
|
|
1167
|
-
|
|
1168
|
-
|
|
1175
|
+
// src/components/ChatHeader.tsx
|
|
1176
|
+
import { useEffect, useRef, useState as useState2 } from "react";
|
|
1177
|
+
|
|
1178
|
+
// src/assets/logo.ts
|
|
1179
|
+
var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
|
|
1180
|
+
|
|
1181
|
+
// src/components/Icons.tsx
|
|
1182
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1183
|
+
function SsMark({ className }) {
|
|
1184
|
+
return /* @__PURE__ */ jsx("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
|
|
1169
1185
|
}
|
|
1170
|
-
function
|
|
1171
|
-
return
|
|
1186
|
+
function SendIcon() {
|
|
1187
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
|
|
1172
1188
|
}
|
|
1173
|
-
function
|
|
1174
|
-
|
|
1175
|
-
const cells = [];
|
|
1176
|
-
for (const entry of raw) {
|
|
1177
|
-
const label = str(entry.label);
|
|
1178
|
-
const value = num(entry.value) ?? str(entry.value);
|
|
1179
|
-
if (label !== void 0 && value !== void 0) cells.push({ label, value });
|
|
1180
|
-
}
|
|
1181
|
-
return cells;
|
|
1189
|
+
function CloseIcon() {
|
|
1190
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
|
|
1182
1191
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1192
|
+
function ChevronIcon() {
|
|
1193
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
1194
|
+
}
|
|
1195
|
+
function KebabIcon() {
|
|
1196
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("g", { fill: "currentColor", children: [
|
|
1197
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.6" }),
|
|
1198
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.6" }),
|
|
1199
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.6" })
|
|
1200
|
+
] }) });
|
|
1201
|
+
}
|
|
1202
|
+
var DASHBOARD_EMOJI = {
|
|
1203
|
+
football: "\u26BD",
|
|
1204
|
+
"goal-net": "\u{1F945}",
|
|
1205
|
+
btts: "\u{1F91D}",
|
|
1206
|
+
card: "\u{1F7E8}",
|
|
1207
|
+
"corner-flag": "\u{1F6A9}",
|
|
1208
|
+
player: "\u{1F464}",
|
|
1209
|
+
target: "\u{1F3AF}",
|
|
1210
|
+
trophy: "\u{1F3C6}",
|
|
1211
|
+
"chart-line": "\u{1F4C8}",
|
|
1212
|
+
"chart-bar": "\u{1F4CA}",
|
|
1213
|
+
chat: "\u{1F4AC}",
|
|
1214
|
+
fire: "\u{1F525}",
|
|
1215
|
+
sparkle: "\u2728"
|
|
1216
|
+
};
|
|
1217
|
+
function DashboardIcon({ name }) {
|
|
1218
|
+
const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
|
|
1219
|
+
return /* @__PURE__ */ jsx("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/components/BrandMark.tsx
|
|
1223
|
+
import { useState } from "react";
|
|
1224
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1225
|
+
function BrandMark({ logoUrl, className }) {
|
|
1226
|
+
const [failed, setFailed] = useState(false);
|
|
1227
|
+
if (!logoUrl || failed) return /* @__PURE__ */ jsx2(SsMark, { className });
|
|
1228
|
+
return /* @__PURE__ */ jsx2("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// src/components/ChatHeader.tsx
|
|
1232
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1233
|
+
function ChatHeader({
|
|
1234
|
+
onClose,
|
|
1235
|
+
closeLabel = "Close chat",
|
|
1236
|
+
logoUrl,
|
|
1237
|
+
headerTitle,
|
|
1238
|
+
onNewConversation,
|
|
1239
|
+
canReset,
|
|
1240
|
+
newConversationLabel = "New conversation",
|
|
1241
|
+
moreOptionsLabel = "More options"
|
|
1242
|
+
}) {
|
|
1243
|
+
const [menuOpen, setMenuOpen] = useState2(false);
|
|
1244
|
+
const wrapRef = useRef(null);
|
|
1245
|
+
const kebabRef = useRef(null);
|
|
1246
|
+
const firstItemRef = useRef(null);
|
|
1247
|
+
const hasMenu = !!(canReset && onNewConversation);
|
|
1248
|
+
useEffect(() => {
|
|
1249
|
+
if (menuOpen) firstItemRef.current?.focus();
|
|
1250
|
+
}, [menuOpen]);
|
|
1251
|
+
useEffect(() => {
|
|
1252
|
+
if (!menuOpen) return;
|
|
1253
|
+
const onPointer = (e) => {
|
|
1254
|
+
if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
|
|
1194
1255
|
};
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1256
|
+
const onKey = (e) => {
|
|
1257
|
+
if (e.key === "Escape") {
|
|
1258
|
+
setMenuOpen(false);
|
|
1259
|
+
kebabRef.current?.focus();
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
document.addEventListener("mousedown", onPointer);
|
|
1263
|
+
document.addEventListener("keydown", onKey);
|
|
1264
|
+
return () => {
|
|
1265
|
+
document.removeEventListener("mousedown", onPointer);
|
|
1266
|
+
document.removeEventListener("keydown", onKey);
|
|
1267
|
+
};
|
|
1268
|
+
}, [menuOpen]);
|
|
1269
|
+
const runNewConversation = () => {
|
|
1270
|
+
setMenuOpen(false);
|
|
1271
|
+
onNewConversation?.();
|
|
1204
1272
|
};
|
|
1273
|
+
return /* @__PURE__ */ jsxs2("header", { className: "ss-w-header", children: [
|
|
1274
|
+
/* @__PURE__ */ jsx3(BrandMark, { logoUrl, className: "ss-w-header-mark" }),
|
|
1275
|
+
/* @__PURE__ */ jsx3("span", { className: "ss-w-header-title", children: headerTitle ?? "SensibleStats" }),
|
|
1276
|
+
hasMenu ? /* @__PURE__ */ jsxs2("div", { className: "ss-w-menu-wrap", ref: wrapRef, children: [
|
|
1277
|
+
/* @__PURE__ */ jsx3(
|
|
1278
|
+
"button",
|
|
1279
|
+
{
|
|
1280
|
+
type: "button",
|
|
1281
|
+
className: "ss-w-kebab",
|
|
1282
|
+
ref: kebabRef,
|
|
1283
|
+
"aria-haspopup": "menu",
|
|
1284
|
+
"aria-expanded": menuOpen,
|
|
1285
|
+
"aria-label": moreOptionsLabel,
|
|
1286
|
+
onClick: () => setMenuOpen((open) => !open),
|
|
1287
|
+
children: /* @__PURE__ */ jsx3(KebabIcon, {})
|
|
1288
|
+
}
|
|
1289
|
+
),
|
|
1290
|
+
menuOpen ? /* @__PURE__ */ jsx3("div", { className: "ss-w-menu", role: "menu", "aria-label": moreOptionsLabel, children: /* @__PURE__ */ jsx3(
|
|
1291
|
+
"button",
|
|
1292
|
+
{
|
|
1293
|
+
type: "button",
|
|
1294
|
+
className: "ss-w-menu-item",
|
|
1295
|
+
role: "menuitem",
|
|
1296
|
+
ref: firstItemRef,
|
|
1297
|
+
onClick: runNewConversation,
|
|
1298
|
+
children: /* @__PURE__ */ jsx3("span", { children: newConversationLabel })
|
|
1299
|
+
}
|
|
1300
|
+
) }) : null
|
|
1301
|
+
] }) : null,
|
|
1302
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ jsx3(CloseIcon, {}) })
|
|
1303
|
+
] });
|
|
1205
1304
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1305
|
+
|
|
1306
|
+
// src/components/MessageList.tsx
|
|
1307
|
+
import { useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
1308
|
+
|
|
1309
|
+
// src/presets.ts
|
|
1310
|
+
var CLIENT_CAPABILITIES = ["price_presets"];
|
|
1311
|
+
var PRICE_TILE_PREFIX = "goal-preset-";
|
|
1312
|
+
function isPriceTile(tile) {
|
|
1313
|
+
const id = tile.signal?.entityId;
|
|
1314
|
+
return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
|
|
1212
1315
|
}
|
|
1213
|
-
function
|
|
1214
|
-
const
|
|
1215
|
-
return
|
|
1316
|
+
function tileDisplayText(tile) {
|
|
1317
|
+
const subtitle = tile.subtitle?.trim();
|
|
1318
|
+
return isPriceTile(tile) && subtitle ? subtitle : tile.title;
|
|
1216
1319
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1320
|
+
var MAX_BUBBLE_ASKS = 2;
|
|
1321
|
+
function bubbleAsks(messages) {
|
|
1322
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1323
|
+
const m = messages[i];
|
|
1324
|
+
if (!m || m.role !== "assistant" || !m.isGreeting) continue;
|
|
1325
|
+
const dashboard = m.greetingDashboard;
|
|
1326
|
+
if (!dashboard) return [];
|
|
1327
|
+
const asks = [];
|
|
1328
|
+
dashboard.tiles.forEach((tile, index) => {
|
|
1329
|
+
const label = tile.subtitle?.trim();
|
|
1330
|
+
if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
|
|
1331
|
+
});
|
|
1332
|
+
return asks;
|
|
1333
|
+
}
|
|
1334
|
+
return [];
|
|
1219
1335
|
}
|
|
1220
|
-
function
|
|
1221
|
-
|
|
1222
|
-
|
|
1336
|
+
function runBubbleAsk(ask, deps) {
|
|
1337
|
+
deps.log?.log({ name: "popup_ask_tap", outcome: String(ask.position) });
|
|
1338
|
+
deps.open();
|
|
1339
|
+
deps.setActiveTab("chat");
|
|
1340
|
+
const displayText = tileDisplayText(ask.tile);
|
|
1341
|
+
deps.send(ask.tile.actionValue, ask.tile.actionRef ? { actionRef: ask.tile.actionRef, displayText } : { displayText });
|
|
1342
|
+
deps.onDashboardTap?.(ask.tile, ask.index, ask.layout);
|
|
1223
1343
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
|
|
1239
|
-
const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
|
|
1240
|
-
return {
|
|
1241
|
-
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
1242
|
-
market,
|
|
1243
|
-
selection,
|
|
1244
|
-
odds,
|
|
1245
|
-
// The wire payload carries bookmakerId (not a name); render a name only if one is present.
|
|
1246
|
-
bookmaker: str(insight.odds?.bookmakerName),
|
|
1247
|
-
isLive: insight.odds?.isLive === true,
|
|
1248
|
-
phase: str(insight.phase),
|
|
1249
|
-
fixture,
|
|
1250
|
-
competition,
|
|
1251
|
-
text: str(insight.text) ?? "",
|
|
1252
|
-
disclaimer: str(insight.disclaimer),
|
|
1253
|
-
matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
|
|
1254
|
-
matchOddsId,
|
|
1255
|
-
marketDeveloperName: str(insight.marketDeveloperName),
|
|
1256
|
-
selectionLabel: str(insight.selectionLabel),
|
|
1257
|
-
line: str(insight.line),
|
|
1258
|
-
addToSlipEnabled: insight.addToSlipEnabled === true,
|
|
1259
|
-
pinEnabled: insight.pinEnabled === true,
|
|
1260
|
-
isMarketFloor: insight.isMarketFloor === true,
|
|
1261
|
-
oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
|
|
1262
|
-
quotedAtUtc: str(insight.odds?.quotedAtUtc),
|
|
1263
|
-
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
1264
|
-
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
|
|
1265
|
-
homeTeamName: home,
|
|
1266
|
-
awayTeamName: away,
|
|
1267
|
-
homeCrest: str(insight.homeTeamImagePath),
|
|
1268
|
-
awayCrest: str(insight.awayTeamImagePath),
|
|
1269
|
-
competitionCrest: str(insight.competitionImagePath),
|
|
1270
|
-
kickoffUtc: str(insight.kickoffUtc),
|
|
1271
|
-
kickoffLabel: str(insight.kickoffLabel)
|
|
1272
|
-
};
|
|
1344
|
+
|
|
1345
|
+
// src/components/Markdown.tsx
|
|
1346
|
+
import ReactMarkdown from "react-markdown";
|
|
1347
|
+
import remarkGfm from "remark-gfm";
|
|
1348
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1349
|
+
var components = {
|
|
1350
|
+
a: ({ children, href }) => /* @__PURE__ */ jsx4("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
|
|
1351
|
+
table: ({ children }) => /* @__PURE__ */ jsx4("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ jsx4("table", { className: "ss-w-md-table", children }) }),
|
|
1352
|
+
ul: ({ children }) => /* @__PURE__ */ jsx4("ul", { className: "ss-w-md-ul", children }),
|
|
1353
|
+
ol: ({ children }) => /* @__PURE__ */ jsx4("ol", { className: "ss-w-md-ol", children }),
|
|
1354
|
+
code: ({ children }) => /* @__PURE__ */ jsx4("code", { className: "ss-w-md-code", children })
|
|
1355
|
+
};
|
|
1356
|
+
function Markdown({ text }) {
|
|
1357
|
+
return /* @__PURE__ */ jsx4("div", { className: "ss-w-md", children: /* @__PURE__ */ jsx4(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children: text }) });
|
|
1273
1358
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
if (vm.id !== void 0) selection.insightId = vm.id;
|
|
1283
|
-
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
1284
|
-
return selection;
|
|
1359
|
+
|
|
1360
|
+
// src/components/EntityCardList.tsx
|
|
1361
|
+
import { useState as useState3 } from "react";
|
|
1362
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1363
|
+
var MAX_VISIBLE = 3;
|
|
1364
|
+
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
1365
|
+
function initials(name) {
|
|
1366
|
+
return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
|
|
1285
1367
|
}
|
|
1286
|
-
function
|
|
1287
|
-
|
|
1288
|
-
const toRow = (r, i) => {
|
|
1289
|
-
const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
|
|
1290
|
-
const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
|
|
1291
|
-
const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
|
|
1292
|
-
const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
|
|
1293
|
-
return {
|
|
1294
|
-
key: `${selection}:${str(r.line) ?? ""}:${i}`,
|
|
1295
|
-
selection,
|
|
1296
|
-
selectionLabel: str(r.selectionLabel),
|
|
1297
|
-
line: str(r.line),
|
|
1298
|
-
odds: price !== void 0 ? price.toFixed(2) : "",
|
|
1299
|
-
oddsDecimal: price,
|
|
1300
|
-
matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
|
|
1301
|
-
quotedAtUtc: str(r.quotedAtUtc),
|
|
1302
|
-
isMain: r.isMainLine !== false,
|
|
1303
|
-
// === true, not !== false: a server that has not shipped the field yet leaves it undefined,
|
|
1304
|
-
// and undefined must read as open rather than hiding every price on the card.
|
|
1305
|
-
isSuspended: r.isSuspended === true,
|
|
1306
|
-
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
1307
|
-
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
|
|
1308
|
-
};
|
|
1309
|
-
};
|
|
1310
|
-
const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
|
|
1311
|
-
const home = str(card.homeTeamName);
|
|
1312
|
-
const away = str(card.awayTeamName);
|
|
1313
|
-
const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
|
|
1314
|
-
return {
|
|
1315
|
-
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
1316
|
-
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
1317
|
-
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
1318
|
-
homeTeamName: home,
|
|
1319
|
-
awayTeamName: away,
|
|
1320
|
-
homeCrest: str(card.homeTeamImagePath),
|
|
1321
|
-
awayCrest: str(card.awayTeamImagePath),
|
|
1322
|
-
competitionCrest: str(card.competitionImagePath),
|
|
1323
|
-
competition: str(card.competitionName),
|
|
1324
|
-
kickoffUtc: str(card.kickoffUtc),
|
|
1325
|
-
kickoffLabel: str(card.kickoffLabel),
|
|
1326
|
-
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
1327
|
-
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
1328
|
-
isLive: rows.some((r) => r.isLive === true),
|
|
1329
|
-
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
1330
|
-
mainRows: vms.filter((r) => r.isMain),
|
|
1331
|
-
moreRows: vms.filter((r) => !r.isMain),
|
|
1332
|
-
disclaimer: str(card.disclaimer),
|
|
1333
|
-
addToSlipEnabled: card.addToSlipEnabled === true,
|
|
1334
|
-
marketDeveloperName: str(card.marketDeveloperName),
|
|
1335
|
-
mainLine: str(card.mainLine),
|
|
1336
|
-
pinEnabled: card.pinEnabled === true,
|
|
1337
|
-
statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
|
|
1338
|
-
tag: card.tag === "your_market" ? "your_market" : void 0
|
|
1339
|
-
};
|
|
1368
|
+
function shortSeason(season) {
|
|
1369
|
+
return season.replace(/\d{4}/g, (year) => year.slice(2));
|
|
1340
1370
|
}
|
|
1341
|
-
function
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
samples.sort((a, b) => a.atMs - b.atMs);
|
|
1351
|
-
const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
1352
|
-
const opening = asNumber(card.openingPrice);
|
|
1353
|
-
const current = asNumber(card.currentPrice);
|
|
1354
|
-
const home = str(card.homeTeamName);
|
|
1355
|
-
const away = str(card.awayTeamName);
|
|
1356
|
-
const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
|
|
1357
|
-
const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
|
|
1358
|
-
return {
|
|
1359
|
-
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
|
|
1360
|
-
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
1361
|
-
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
1362
|
-
marketDeveloperName: str(card.marketDeveloperName),
|
|
1363
|
-
selection,
|
|
1364
|
-
selectionLabel: str(card.selectionLabel),
|
|
1365
|
-
line: str(card.line),
|
|
1366
|
-
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
1367
|
-
competition: str(card.competitionName),
|
|
1368
|
-
bookmaker: str(card.bookmakerName),
|
|
1369
|
-
opening: opening !== void 0 ? opening.toFixed(2) : "",
|
|
1370
|
-
current: current !== void 0 ? current.toFixed(2) : "",
|
|
1371
|
-
direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
|
|
1372
|
-
windowHours: asNumber(card.windowHours) ?? 0,
|
|
1373
|
-
excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
|
|
1374
|
-
isSuspended: card.isSuspended === true,
|
|
1375
|
-
disclaimer: str(card.disclaimer),
|
|
1376
|
-
geometry: projectSeries(samples),
|
|
1377
|
-
observationCount: samples.length,
|
|
1378
|
-
pinEnabled: card.pinEnabled === true,
|
|
1379
|
-
matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
|
|
1380
|
-
};
|
|
1371
|
+
function Crest({ image, label }) {
|
|
1372
|
+
return /* @__PURE__ */ jsx5(
|
|
1373
|
+
"span",
|
|
1374
|
+
{
|
|
1375
|
+
className: "ss-w-ecard-crest",
|
|
1376
|
+
style: { backgroundImage: `url(${image})` },
|
|
1377
|
+
...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
|
|
1378
|
+
}
|
|
1379
|
+
);
|
|
1381
1380
|
}
|
|
1382
|
-
function
|
|
1383
|
-
if (
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1381
|
+
function FormBar({ w, d, l }) {
|
|
1382
|
+
if (w + d + l === 0) return null;
|
|
1383
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ss-w-form", "aria-hidden": "true", children: [
|
|
1384
|
+
w > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-w", style: { flexGrow: w } }) : null,
|
|
1385
|
+
d > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-d", style: { flexGrow: d } }) : null,
|
|
1386
|
+
l > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
|
|
1387
|
+
] });
|
|
1388
1388
|
}
|
|
1389
|
-
function
|
|
1390
|
-
|
|
1389
|
+
function StatCellView({ s }) {
|
|
1390
|
+
const m = RECORD_RE.exec(s.value);
|
|
1391
|
+
if (m) {
|
|
1392
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
|
|
1393
|
+
/* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ jsx5(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
|
|
1394
|
+
/* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.value })
|
|
1395
|
+
] });
|
|
1396
|
+
}
|
|
1397
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
|
|
1398
|
+
/* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: s.value }),
|
|
1399
|
+
/* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.label })
|
|
1400
|
+
] });
|
|
1391
1401
|
}
|
|
1392
|
-
function
|
|
1393
|
-
if (
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
const matchId = finite(leg.matchId);
|
|
1397
|
-
const home = str(leg.homeTeamName);
|
|
1398
|
-
const away = str(leg.awayTeamName);
|
|
1399
|
-
const selectionLabel = str(leg.selectionLabel);
|
|
1400
|
-
const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
|
|
1401
|
-
const insightId = str(insight?.insightId);
|
|
1402
|
-
const statText = str(insight?.text);
|
|
1403
|
-
if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
|
|
1404
|
-
const line = str(leg.line);
|
|
1405
|
-
return {
|
|
1406
|
-
key: `${matchOddsId}`,
|
|
1407
|
-
matchId,
|
|
1408
|
-
homeTeamName: home,
|
|
1409
|
-
awayTeamName: away,
|
|
1410
|
-
homeCrest: str(leg.homeTeamImagePath),
|
|
1411
|
-
awayCrest: str(leg.awayTeamImagePath),
|
|
1412
|
-
competition: str(leg.competitionName),
|
|
1413
|
-
kickoffUtc: str(leg.kickoffUtc),
|
|
1414
|
-
kickoffLabel: str(leg.kickoffLabel),
|
|
1415
|
-
market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
|
|
1416
|
-
marketDeveloperName: str(leg.marketDeveloperName) ?? "",
|
|
1417
|
-
selection: joinSelection(selectionLabel, line) ?? selectionLabel,
|
|
1418
|
-
selectionLabel,
|
|
1419
|
-
line,
|
|
1420
|
-
odds: price.toFixed(2),
|
|
1421
|
-
oddsDecimal: price,
|
|
1422
|
-
matchOddsId,
|
|
1423
|
-
quotedAtUtc: str(leg.quotedAtUtc),
|
|
1424
|
-
insightId,
|
|
1425
|
-
statText
|
|
1426
|
-
};
|
|
1402
|
+
function StatStrip({ stats }) {
|
|
1403
|
+
if (stats.length === 0) return null;
|
|
1404
|
+
const cols = Math.min(stats.length, 4);
|
|
1405
|
+
return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ jsx5(StatCellView, { s }, s.label + s.value)) });
|
|
1427
1406
|
}
|
|
1428
|
-
function
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1407
|
+
function CardHeader({ c, showScopeCrest }) {
|
|
1408
|
+
const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
|
|
1409
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-hd", children: [
|
|
1410
|
+
/* @__PURE__ */ jsx5(
|
|
1411
|
+
"span",
|
|
1412
|
+
{
|
|
1413
|
+
className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
|
|
1414
|
+
style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
|
|
1415
|
+
children: c.image ? "" : initials(c.name)
|
|
1416
|
+
}
|
|
1417
|
+
),
|
|
1418
|
+
/* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-idtext", children: [
|
|
1419
|
+
/* @__PURE__ */ jsx5("span", { className: "ss-w-nm", children: c.name }),
|
|
1420
|
+
c.sub ? /* @__PURE__ */ jsx5("span", { className: "ss-w-sub", children: c.sub }) : null
|
|
1421
|
+
] }),
|
|
1422
|
+
/* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-meta", children: [
|
|
1423
|
+
showScopeCrest && onlyScope?.image ? /* @__PURE__ */ jsx5(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
|
|
1424
|
+
c.season ? /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
|
|
1425
|
+
] })
|
|
1426
|
+
] });
|
|
1427
|
+
}
|
|
1428
|
+
function ScopeTabs({ scopes, active, onSelect }) {
|
|
1429
|
+
return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ jsx5(
|
|
1430
|
+
"button",
|
|
1431
|
+
{
|
|
1432
|
+
type: "button",
|
|
1433
|
+
role: "tab",
|
|
1434
|
+
className: "ss-w-ecard-scope",
|
|
1435
|
+
"aria-selected": i === active,
|
|
1436
|
+
"aria-label": s.label,
|
|
1437
|
+
title: s.label,
|
|
1438
|
+
onClick: () => onSelect(i),
|
|
1439
|
+
children: s.image ? /* @__PURE__ */ jsx5(Crest, { image: s.image }) : s.label
|
|
1440
|
+
},
|
|
1441
|
+
String(s.competitionId ?? "all")
|
|
1442
|
+
)) });
|
|
1443
|
+
}
|
|
1444
|
+
function EntityCardItem({ c }) {
|
|
1445
|
+
const [active, setActive] = useState3(0);
|
|
1446
|
+
const hasBody = c.scopes.length > 0;
|
|
1447
|
+
if (!hasBody) {
|
|
1448
|
+
return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: false }) });
|
|
1437
1449
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
};
|
|
1450
|
+
const multi = c.scopes.length > 1;
|
|
1451
|
+
const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
|
|
1452
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
|
|
1453
|
+
/* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: !multi }),
|
|
1454
|
+
multi ? /* @__PURE__ */ jsx5(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
|
|
1455
|
+
/* @__PURE__ */ jsx5(StatStrip, { stats: scope.stats })
|
|
1456
|
+
] });
|
|
1445
1457
|
}
|
|
1446
|
-
function
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
return selection;
|
|
1458
|
+
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1459
|
+
const [expanded, setExpanded] = useState3(false);
|
|
1460
|
+
if (cards.length === 0) return null;
|
|
1461
|
+
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1462
|
+
const overflow = cards.length - MAX_VISIBLE;
|
|
1463
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ss-w-cards", children: [
|
|
1464
|
+
visible.map((c) => /* @__PURE__ */ jsx5(EntityCardItem, { c }, c.id)),
|
|
1465
|
+
overflow > 0 ? /* @__PURE__ */ jsx5("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
|
|
1466
|
+
] });
|
|
1456
1467
|
}
|
|
1457
1468
|
|
|
1469
|
+
// src/components/AddToSlipButton.tsx
|
|
1470
|
+
import { useCallback, useState as useState4 } from "react";
|
|
1471
|
+
import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
|
|
1472
|
+
|
|
1458
1473
|
// src/eventLogContext.ts
|
|
1459
1474
|
import { createContext, useContext } from "react";
|
|
1460
1475
|
var EventLogContext = createContext(null);
|
|
@@ -2010,10 +2025,10 @@ function ComboCardList({ cards, ui, slip }) {
|
|
|
2010
2025
|
}
|
|
2011
2026
|
|
|
2012
2027
|
// src/components/MarketOddsCardList.tsx
|
|
2013
|
-
import { useState as useState8 } from "react";
|
|
2028
|
+
import { useEffect as useEffect3, useState as useState8 } from "react";
|
|
2014
2029
|
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2015
|
-
function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
|
|
2016
|
-
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
2030
|
+
function OddsRow({ vm, row, ui, slip, inSlipIds, history, suppressSlip }) {
|
|
2031
|
+
const selection = vm.addToSlipEnabled && !suppressSlip ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
2017
2032
|
const inSlip = !!inSlipIds && row.matchOddsId != null && !!inSlipIds[row.matchOddsId];
|
|
2018
2033
|
return /* @__PURE__ */ jsxs10("div", { className: "ss-w-mo-row", children: [
|
|
2019
2034
|
/* @__PURE__ */ jsx15("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
@@ -2031,17 +2046,34 @@ function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
|
|
|
2031
2046
|
"\u2713 ",
|
|
2032
2047
|
ui.inSlipLabel
|
|
2033
2048
|
] }) : null,
|
|
2034
|
-
/* @__PURE__ */ jsx15(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui })
|
|
2049
|
+
!suppressSlip ? /* @__PURE__ */ jsx15(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui }) : null
|
|
2035
2050
|
] });
|
|
2036
2051
|
}
|
|
2052
|
+
var STALE_AFTER_MS = 12e4;
|
|
2053
|
+
function fmtHhMm(iso, locale) {
|
|
2054
|
+
return new Date(iso).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
2055
|
+
}
|
|
2037
2056
|
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
|
|
2038
2057
|
const [open, setOpen] = useState8(false);
|
|
2039
2058
|
const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
2040
2059
|
const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
|
|
2041
2060
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
2042
|
-
const
|
|
2061
|
+
const live = vm.live ?? null;
|
|
2062
|
+
const closedReason = live?.closedReason ?? null;
|
|
2063
|
+
const isClosed = closedReason !== null;
|
|
2064
|
+
const asOfMs = live ? new Date(live.asOfUtc).getTime() : NaN;
|
|
2065
|
+
const isStale = live != null && !isClosed && (vm.awaitingLiveUpdate === true || Date.now() - asOfMs > STALE_AFTER_MS);
|
|
2066
|
+
const staleTime = isStale && live ? fmtHhMm(live.asOfUtc, ui?.locale ?? "en") : null;
|
|
2067
|
+
const [, setStaleTick] = useState8(0);
|
|
2068
|
+
const watchStale = live != null && !isClosed && !isStale;
|
|
2069
|
+
useEffect3(() => {
|
|
2070
|
+
if (!watchStale) return;
|
|
2071
|
+
const id = window.setTimeout(() => setStaleTick((n) => n + 1), Math.max(0, asOfMs + STALE_AFTER_MS - Date.now()) + 1);
|
|
2072
|
+
return () => window.clearTimeout(id);
|
|
2073
|
+
}, [watchStale, asOfMs]);
|
|
2074
|
+
const showPin = !!monitor && vm.pinEnabled && !live;
|
|
2043
2075
|
const history = showPin && !pinRef && !hideHeader ? monitor : void 0;
|
|
2044
|
-
const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
|
|
2076
|
+
const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin || !!live;
|
|
2045
2077
|
return /* @__PURE__ */ jsxs10("div", { className: hideHeader ? "ss-w-mocard ss-w-mocard--bare" : "ss-w-mocard", children: [
|
|
2046
2078
|
!hideHeader && /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
2047
2079
|
showHeader ? /* @__PURE__ */ jsxs10("div", { className: "ss-w-bi-header", children: [
|
|
@@ -2050,7 +2082,14 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
|
|
|
2050
2082
|
/* @__PURE__ */ jsx15("span", { className: "ss-w-bi-comp", children: vm.competition })
|
|
2051
2083
|
] }) : null }),
|
|
2052
2084
|
/* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-header-right", children: [
|
|
2053
|
-
|
|
2085
|
+
live && !isClosed ? /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
2086
|
+
/* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-score", children: [
|
|
2087
|
+
live.homeScore,
|
|
2088
|
+
"\u2013",
|
|
2089
|
+
live.awayScore
|
|
2090
|
+
] }),
|
|
2091
|
+
live.minuteLabel ? /* @__PURE__ */ jsx15("span", { className: "ss-w-bi-min", children: live.minuteLabel }) : null
|
|
2092
|
+
] }) : !live && vm.isLive ? /* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-live", children: [
|
|
2054
2093
|
/* @__PURE__ */ jsx15("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
2055
2094
|
ui?.liveLabel ?? "Live"
|
|
2056
2095
|
] }) : null,
|
|
@@ -2080,14 +2119,17 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
|
|
|
2080
2119
|
] }) : null
|
|
2081
2120
|
] }),
|
|
2082
2121
|
vm.statText && !hideHeader && !pinRef ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-stat", children: vm.statText }) : null,
|
|
2083
|
-
/* @__PURE__ */
|
|
2084
|
-
|
|
2085
|
-
|
|
2122
|
+
isClosed ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-closed", children: closedReason === "suspended" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.suspended ?? "Market suspended" }) : closedReason === "no_live_price" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.noPrice ?? "No live price available" }) : closedReason === "full_time" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.fullTime ?? "Full time" }) : null }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
2123
|
+
/* @__PURE__ */ jsxs10("div", { className: "ss-w-mo-rows", children: [
|
|
2124
|
+
vm.mainRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)),
|
|
2125
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)) : null
|
|
2126
|
+
] }),
|
|
2127
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs10("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
2128
|
+
/* @__PURE__ */ jsx15("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
2129
|
+
/* @__PURE__ */ jsx15("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
|
|
2130
|
+
] }) : null,
|
|
2131
|
+
staleTime ? /* @__PURE__ */ jsx15("p", { className: "ss-w-mo-stale", children: ui?.liveCard.stale(staleTime) ?? `Prices from ${staleTime}` }) : null
|
|
2086
2132
|
] }),
|
|
2087
|
-
vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs10("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
2088
|
-
/* @__PURE__ */ jsx15("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
2089
|
-
/* @__PURE__ */ jsx15("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
|
|
2090
|
-
] }) : null,
|
|
2091
2133
|
vm.bookmaker ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ jsx15("span", { children: vm.bookmaker }) }) : null,
|
|
2092
2134
|
vm.disclaimer ? /* @__PURE__ */ jsx15("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
2093
2135
|
] });
|
|
@@ -2098,7 +2140,7 @@ function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader, p
|
|
|
2098
2140
|
}
|
|
2099
2141
|
|
|
2100
2142
|
// src/components/CompactOddsList.tsx
|
|
2101
|
-
import { useEffect as
|
|
2143
|
+
import { useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
|
|
2102
2144
|
|
|
2103
2145
|
// src/compactList.ts
|
|
2104
2146
|
var COMPACT_MIN_CARDS = 3;
|
|
@@ -2215,7 +2257,7 @@ function CompactOddsList({ list, ui, slip, monitor }) {
|
|
|
2215
2257
|
const hidden = list.rowCount - shown;
|
|
2216
2258
|
const [focusIndex, setFocusIndex] = useState9(null);
|
|
2217
2259
|
const focusRef = useRef2(null);
|
|
2218
|
-
|
|
2260
|
+
useEffect4(() => {
|
|
2219
2261
|
if (focusIndex !== null) focusRef.current?.focus();
|
|
2220
2262
|
}, [focusIndex]);
|
|
2221
2263
|
let left = shown;
|
|
@@ -2516,7 +2558,7 @@ function FixtureCard({ card }) {
|
|
|
2516
2558
|
}
|
|
2517
2559
|
|
|
2518
2560
|
// src/components/dashboard/CountdownCard.tsx
|
|
2519
|
-
import { Fragment as Fragment6, useEffect as
|
|
2561
|
+
import { Fragment as Fragment6, useEffect as useEffect5, useState as useState10 } from "react";
|
|
2520
2562
|
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2521
2563
|
var DAY_MS = 864e5;
|
|
2522
2564
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -2540,7 +2582,7 @@ function CountdownCard({ card }) {
|
|
|
2540
2582
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
2541
2583
|
);
|
|
2542
2584
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
2543
|
-
|
|
2585
|
+
useEffect5(() => {
|
|
2544
2586
|
if (reduced) return;
|
|
2545
2587
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
2546
2588
|
return () => window.clearInterval(id);
|
|
@@ -2900,7 +2942,7 @@ function RestingFormCard({ card }) {
|
|
|
2900
2942
|
import { useRef as useRef3, useState as useState14 } from "react";
|
|
2901
2943
|
|
|
2902
2944
|
// src/useLiveClock.ts
|
|
2903
|
-
import { useEffect as
|
|
2945
|
+
import { useEffect as useEffect6, useState as useState13 } from "react";
|
|
2904
2946
|
var TICK_MS = 6e4;
|
|
2905
2947
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2906
2948
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2912,7 +2954,7 @@ function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
|
2912
2954
|
const [displayMinute, setDisplayMinute] = useState13(
|
|
2913
2955
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2914
2956
|
);
|
|
2915
|
-
|
|
2957
|
+
useEffect6(() => {
|
|
2916
2958
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2917
2959
|
if (!clockRunning) return;
|
|
2918
2960
|
const id = window.setInterval(() => {
|
|
@@ -3276,7 +3318,7 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3276
3318
|
const endRef = useRef4(null);
|
|
3277
3319
|
const pinnedRef = useRef4(true);
|
|
3278
3320
|
const anchoredTurnRef = useRef4(null);
|
|
3279
|
-
|
|
3321
|
+
useEffect7(() => {
|
|
3280
3322
|
const anchor = turnAnchor(state.messages);
|
|
3281
3323
|
const list = listRef.current;
|
|
3282
3324
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -3836,7 +3878,7 @@ function TodayPanel({ discovery, ui, monitor }) {
|
|
|
3836
3878
|
}
|
|
3837
3879
|
|
|
3838
3880
|
// src/components/GamesPanel.tsx
|
|
3839
|
-
import { useEffect as
|
|
3881
|
+
import { useEffect as useEffect11, useState as useState31 } from "react";
|
|
3840
3882
|
|
|
3841
3883
|
// src/components/GamesLoginWall.tsx
|
|
3842
3884
|
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
@@ -3845,7 +3887,7 @@ function GamesLoginWall({ ui }) {
|
|
|
3845
3887
|
}
|
|
3846
3888
|
|
|
3847
3889
|
// src/components/GamesHub.tsx
|
|
3848
|
-
import { useEffect as
|
|
3890
|
+
import { useEffect as useEffect8, useState as useState18 } from "react";
|
|
3849
3891
|
|
|
3850
3892
|
// src/components/games/ui/gameMeta.ts
|
|
3851
3893
|
function prettifyGameId(gameId) {
|
|
@@ -4031,7 +4073,7 @@ function pickHeroGame(games) {
|
|
|
4031
4073
|
var tileKey = (g) => `${g.gameId}-${g.gameDay}-${g.fixtureId}`;
|
|
4032
4074
|
function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
|
|
4033
4075
|
const [, setTick] = useState18(0);
|
|
4034
|
-
|
|
4076
|
+
useEffect8(() => {
|
|
4035
4077
|
const id = setInterval(() => setTick((t) => t + 1), 6e4);
|
|
4036
4078
|
return () => clearInterval(id);
|
|
4037
4079
|
}, []);
|
|
@@ -4091,7 +4133,7 @@ function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
|
|
|
4091
4133
|
}
|
|
4092
4134
|
|
|
4093
4135
|
// src/components/GameScreenHost.tsx
|
|
4094
|
-
import { useEffect as
|
|
4136
|
+
import { useEffect as useEffect10, useRef as useRef7, useState as useState30 } from "react";
|
|
4095
4137
|
|
|
4096
4138
|
// src/useGamePlay.ts
|
|
4097
4139
|
import { useCallback as useCallback4, useRef as useRef5, useState as useState19 } from "react";
|
|
@@ -5044,7 +5086,7 @@ function CareerPathGame({
|
|
|
5044
5086
|
}
|
|
5045
5087
|
|
|
5046
5088
|
// src/components/games/BeatTheGridGame.tsx
|
|
5047
|
-
import React, { useEffect as
|
|
5089
|
+
import React, { useEffect as useEffect9, useId as useId4, useRef as useRef6, useState as useState24 } from "react";
|
|
5048
5090
|
import { Fragment as Fragment14, jsx as jsx74, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
5049
5091
|
function criterionIconKind(label, key) {
|
|
5050
5092
|
const l = (key ?? label).toLowerCase();
|
|
@@ -5128,7 +5170,7 @@ function SearchSheet({
|
|
|
5128
5170
|
const [query, setQuery] = useState24("");
|
|
5129
5171
|
const inputId = useId4();
|
|
5130
5172
|
const inputRef = useRef6(null);
|
|
5131
|
-
|
|
5173
|
+
useEffect9(() => {
|
|
5132
5174
|
inputRef.current?.focus();
|
|
5133
5175
|
}, [row, col]);
|
|
5134
5176
|
const filtered = playerPool.filter(
|
|
@@ -6430,7 +6472,7 @@ function GameScreenHost({
|
|
|
6430
6472
|
}) {
|
|
6431
6473
|
const { gameId, fixtureId, gameDay = "", lockAtUtc = null } = selected;
|
|
6432
6474
|
const [configJson, setConfigJson] = useState30(null);
|
|
6433
|
-
|
|
6475
|
+
useEffect10(() => {
|
|
6434
6476
|
setConfigJson(null);
|
|
6435
6477
|
if (!conversation) return;
|
|
6436
6478
|
let cancelled = false;
|
|
@@ -6453,12 +6495,12 @@ function GameScreenHost({
|
|
|
6453
6495
|
fixtureId: fixtureId || void 0,
|
|
6454
6496
|
locale: ui.games.lang
|
|
6455
6497
|
});
|
|
6456
|
-
|
|
6498
|
+
useEffect10(() => {
|
|
6457
6499
|
if (conversation) hydrate();
|
|
6458
6500
|
}, [conversation, gameId]);
|
|
6459
6501
|
const hydrateRef = useRef7(hydrate);
|
|
6460
6502
|
hydrateRef.current = hydrate;
|
|
6461
|
-
|
|
6503
|
+
useEffect10(() => {
|
|
6462
6504
|
if (!FIXTURE_GAME_IDS.has(gameId)) return;
|
|
6463
6505
|
if (rawStatus !== "pending") return;
|
|
6464
6506
|
const timerId = setInterval(() => {
|
|
@@ -6594,7 +6636,7 @@ function GamesPanel({
|
|
|
6594
6636
|
refreshHub
|
|
6595
6637
|
}) {
|
|
6596
6638
|
const [selected, setSelected] = useState31(null);
|
|
6597
|
-
|
|
6639
|
+
useEffect11(() => {
|
|
6598
6640
|
ensureGamesFonts();
|
|
6599
6641
|
}, []);
|
|
6600
6642
|
if (!loggedIn) return /* @__PURE__ */ jsx83(GamesLoginWall, { ui });
|
|
@@ -6794,7 +6836,7 @@ import { jsx as jsx88, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
|
6794
6836
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
6795
6837
|
function useIsModal() {
|
|
6796
6838
|
const [modal, setModal] = useState33(false);
|
|
6797
|
-
|
|
6839
|
+
useEffect12(() => {
|
|
6798
6840
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
6799
6841
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
6800
6842
|
const sync = () => setModal(mql.matches);
|
|
@@ -6807,7 +6849,7 @@ function useIsModal() {
|
|
|
6807
6849
|
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }) {
|
|
6808
6850
|
const { state, close, stop, send, reset } = controller;
|
|
6809
6851
|
const isModal = useIsModal();
|
|
6810
|
-
|
|
6852
|
+
useEffect12(() => {
|
|
6811
6853
|
const onKey = (e) => {
|
|
6812
6854
|
if (e.key === "Escape") close();
|
|
6813
6855
|
};
|
|
@@ -6822,7 +6864,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6822
6864
|
monitor?.setActiveTab("chat");
|
|
6823
6865
|
send(text, { grounding });
|
|
6824
6866
|
};
|
|
6825
|
-
|
|
6867
|
+
useEffect12(() => {
|
|
6826
6868
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
6827
6869
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
6828
6870
|
return /* @__PURE__ */ jsxs72("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
@@ -7153,11 +7195,11 @@ function useHostEvents(opts) {
|
|
|
7153
7195
|
logger?.log(toSlipEvent(name, entry));
|
|
7154
7196
|
}
|
|
7155
7197
|
};
|
|
7156
|
-
|
|
7198
|
+
useEffect13(() => {
|
|
7157
7199
|
if (!host) return;
|
|
7158
7200
|
return attachHost(host, (command) => sinkRef.current(command));
|
|
7159
7201
|
}, [host]);
|
|
7160
|
-
|
|
7202
|
+
useEffect13(() => {
|
|
7161
7203
|
if (!isOpen || !views) return;
|
|
7162
7204
|
const held = views.markOpened();
|
|
7163
7205
|
if (held.length === 0) return;
|
|
@@ -7248,12 +7290,27 @@ function themeAttrs(ui) {
|
|
|
7248
7290
|
}
|
|
7249
7291
|
|
|
7250
7292
|
// src/useChatStream.ts
|
|
7251
|
-
import { useCallback as useCallback6, useEffect as
|
|
7293
|
+
import { useCallback as useCallback6, useEffect as useEffect15, useMemo as useMemo2, useReducer as useReducer2, useRef as useRef10 } from "react";
|
|
7252
7294
|
import { WidgetSdkError as WidgetSdkError2 } from "@sensiblestats/widget-sdk";
|
|
7253
7295
|
|
|
7254
7296
|
// src/reducer.ts
|
|
7255
7297
|
import "@sensiblestats/widget-sdk";
|
|
7256
7298
|
var POPUP_MAX = 160;
|
|
7299
|
+
function markAwaitingLiveUpdate(messages, held = []) {
|
|
7300
|
+
if (!messages.some((m) => m.role === "assistant" && m.marketOdds.some((vm) => vm.live != null))) return messages;
|
|
7301
|
+
const heldFlags = /* @__PURE__ */ new Map();
|
|
7302
|
+
for (const m of held) {
|
|
7303
|
+
if (m.role !== "assistant") continue;
|
|
7304
|
+
for (const vm of m.marketOdds) if (vm.live != null) heldFlags.set(`${m.id}|${vm.id}`, vm.awaitingLiveUpdate === true);
|
|
7305
|
+
}
|
|
7306
|
+
return messages.map((m) => {
|
|
7307
|
+
if (m.role !== "assistant" || !m.marketOdds.some((vm) => vm.live != null)) return m;
|
|
7308
|
+
return {
|
|
7309
|
+
...m,
|
|
7310
|
+
marketOdds: m.marketOdds.map((vm) => vm.live != null ? { ...vm, awaitingLiveUpdate: heldFlags.get(`${m.id}|${vm.id}`) ?? true } : vm)
|
|
7311
|
+
};
|
|
7312
|
+
});
|
|
7313
|
+
}
|
|
7257
7314
|
function initialState(starters) {
|
|
7258
7315
|
return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, configuredStarters: starters, error: null, lastUserInput: null, lastDisplayText: null, popupText: null, conversationId: null };
|
|
7259
7316
|
}
|
|
@@ -7345,7 +7402,7 @@ function reducer(state, action) {
|
|
|
7345
7402
|
case "RESTORE":
|
|
7346
7403
|
return {
|
|
7347
7404
|
...state,
|
|
7348
|
-
messages: action.messages,
|
|
7405
|
+
messages: markAwaitingLiveUpdate(action.messages, state.messages),
|
|
7349
7406
|
conversationId: action.conversationId,
|
|
7350
7407
|
isStreaming: false,
|
|
7351
7408
|
status: null,
|
|
@@ -7359,6 +7416,22 @@ function reducer(state, action) {
|
|
|
7359
7416
|
return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
7360
7417
|
case "STOP":
|
|
7361
7418
|
return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
7419
|
+
case "UPDATE_LIVE_CARD": {
|
|
7420
|
+
const { matchId, live, mainRows, moreRows, addToSlipEnabled } = action;
|
|
7421
|
+
return {
|
|
7422
|
+
...state,
|
|
7423
|
+
messages: state.messages.map((m) => {
|
|
7424
|
+
if (m.role !== "assistant") return m;
|
|
7425
|
+
if (!m.marketOdds.some((vm) => vm.matchId === matchId && vm.live != null)) return m;
|
|
7426
|
+
return {
|
|
7427
|
+
...m,
|
|
7428
|
+
marketOdds: m.marketOdds.map(
|
|
7429
|
+
(vm) => vm.matchId === matchId && vm.live != null ? { ...vm, live, mainRows, moreRows, addToSlipEnabled, awaitingLiveUpdate: false } : vm
|
|
7430
|
+
)
|
|
7431
|
+
};
|
|
7432
|
+
})
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7362
7435
|
case "LIVE_REFRESH":
|
|
7363
7436
|
return {
|
|
7364
7437
|
...state,
|
|
@@ -7377,7 +7450,7 @@ function reducer(state, action) {
|
|
|
7377
7450
|
}
|
|
7378
7451
|
|
|
7379
7452
|
// src/useLiveDashboardPoll.ts
|
|
7380
|
-
import { useEffect as
|
|
7453
|
+
import { useEffect as useEffect14, useReducer, useRef as useRef9 } from "react";
|
|
7381
7454
|
var POLL_INTERVAL_MS = 6e4;
|
|
7382
7455
|
var LEAD_MS = 12e4;
|
|
7383
7456
|
var GIVE_UP_MS = 30 * 6e4;
|
|
@@ -7425,7 +7498,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
|
7425
7498
|
anchorRef.current = anchor;
|
|
7426
7499
|
const inFlightRef = useRef9(false);
|
|
7427
7500
|
const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null;
|
|
7428
|
-
|
|
7501
|
+
useEffect14(() => {
|
|
7429
7502
|
if (!anchorKey || !anchorRef.current) return;
|
|
7430
7503
|
const tick = async () => {
|
|
7431
7504
|
if (inFlightRef.current) return;
|
|
@@ -7461,7 +7534,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
|
7461
7534
|
}, POLL_INTERVAL_MS);
|
|
7462
7535
|
return () => window.clearInterval(id);
|
|
7463
7536
|
}, [anchorKey, dispatch, getLiveDashboard]);
|
|
7464
|
-
|
|
7537
|
+
useEffect14(() => {
|
|
7465
7538
|
if (anchorKey !== null) return;
|
|
7466
7539
|
const wakeAt = findEarliestWakeupMs(messages);
|
|
7467
7540
|
if (wakeAt === null) return;
|
|
@@ -7531,7 +7604,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7531
7604
|
const restored = payload != null && payload !== "expired" && payload !== "corrupt";
|
|
7532
7605
|
const base = initialState(starterTexts.map(chipFromText));
|
|
7533
7606
|
if (restored) {
|
|
7534
|
-
return { state: { ...base, messages: payload.messages, conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
|
|
7607
|
+
return { state: { ...base, messages: markAwaitingLiveUpdate(payload.messages), conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
|
|
7535
7608
|
}
|
|
7536
7609
|
return { state: base, restored: false, stale: payload === "expired" || payload === "corrupt" };
|
|
7537
7610
|
}, []);
|
|
@@ -7624,15 +7697,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7624
7697
|
dispatch({ kind: "STOP" });
|
|
7625
7698
|
}
|
|
7626
7699
|
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
7627
|
-
|
|
7700
|
+
useEffect15(() => {
|
|
7628
7701
|
if (greetedRef.current) return;
|
|
7629
7702
|
greetedRef.current = true;
|
|
7630
7703
|
fireGreeting();
|
|
7631
7704
|
}, [fireGreeting]);
|
|
7632
|
-
|
|
7705
|
+
useEffect15(() => {
|
|
7633
7706
|
if (boot.stale && storageKey) clearConversation(storageKey);
|
|
7634
7707
|
}, []);
|
|
7635
|
-
|
|
7708
|
+
useEffect15(() => {
|
|
7636
7709
|
if (!storageKey || state.isStreaming) return;
|
|
7637
7710
|
if (hydratedRef.current) {
|
|
7638
7711
|
hydratedRef.current = false;
|
|
@@ -7649,7 +7722,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7649
7722
|
if (persistable.length === 0) return;
|
|
7650
7723
|
writeConversation(storageKey, state.conversationId, persistable, Date.now());
|
|
7651
7724
|
}, [storageKey, state.isStreaming, state.messages, state.conversationId]);
|
|
7652
|
-
|
|
7725
|
+
useEffect15(() => {
|
|
7653
7726
|
if (!storageKey) return;
|
|
7654
7727
|
const onStorage = (e) => {
|
|
7655
7728
|
if (e.key !== storageKey || e.storageArea !== window.localStorage) return;
|
|
@@ -7704,11 +7777,11 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7704
7777
|
}, [storageKey, conversation, clearFallbackTimer, fireGreeting]);
|
|
7705
7778
|
const getLiveDashboard = useCallback6(() => conversation.getLiveDashboard(), [conversation]);
|
|
7706
7779
|
useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard });
|
|
7707
|
-
return { state, open, close, stop, toggle, send, retry, dismissPopup, reset };
|
|
7780
|
+
return { state, open, close, stop, toggle, send, retry, dismissPopup, reset, _dispatch: dispatch };
|
|
7708
7781
|
}
|
|
7709
7782
|
|
|
7710
7783
|
// src/useLiveMonitor.ts
|
|
7711
|
-
import { useCallback as useCallback7, useEffect as
|
|
7784
|
+
import { useCallback as useCallback7, useEffect as useEffect16, useRef as useRef11, useState as useState36 } from "react";
|
|
7712
7785
|
|
|
7713
7786
|
// src/useTabs.ts
|
|
7714
7787
|
import { useState as useState35 } from "react";
|
|
@@ -7721,6 +7794,7 @@ function useTabs(initial = "chat") {
|
|
|
7721
7794
|
var GOAL_OR_RED = /* @__PURE__ */ new Set(["goal", "red"]);
|
|
7722
7795
|
var MIN_POLL_MS = 5e3;
|
|
7723
7796
|
var DEFAULT_POLL_MS = 6e4;
|
|
7797
|
+
var LIVE_WATCH_POLL_MS = 12e3;
|
|
7724
7798
|
function eventIdentity(e) {
|
|
7725
7799
|
return `${e.type}:${e.side}:${e.minuteLabel}:${e.player ?? ""}`;
|
|
7726
7800
|
}
|
|
@@ -7752,6 +7826,8 @@ function useLiveMonitor(opts) {
|
|
|
7752
7826
|
const [marketOdds, setMarketOdds] = useState36({});
|
|
7753
7827
|
const pinsRef = useRef11(pins);
|
|
7754
7828
|
pinsRef.current = pins;
|
|
7829
|
+
const watchesRef = useRef11(opts.watches ?? []);
|
|
7830
|
+
watchesRef.current = opts.watches ?? [];
|
|
7755
7831
|
const activeTabRef = useRef11(activeTab);
|
|
7756
7832
|
activeTabRef.current = activeTab;
|
|
7757
7833
|
const snapshotRef = useRef11(snapshot);
|
|
@@ -7869,10 +7945,11 @@ function useLiveMonitor(opts) {
|
|
|
7869
7945
|
const getLiveMonitorRef = useRef11(opts.getLiveMonitor);
|
|
7870
7946
|
getLiveMonitorRef.current = opts.getLiveMonitor;
|
|
7871
7947
|
const tick = useCallback7(async () => {
|
|
7872
|
-
|
|
7948
|
+
const allPins = [...pinsRef.current, ...watchesRef.current];
|
|
7949
|
+
if (inFlightRef.current || disabledRef.current || allPins.length === 0) return;
|
|
7873
7950
|
inFlightRef.current = true;
|
|
7874
7951
|
try {
|
|
7875
|
-
const snap = await getLiveMonitorRef.current(
|
|
7952
|
+
const snap = await getLiveMonitorRef.current(allPins);
|
|
7876
7953
|
if (!mountedRef.current) return;
|
|
7877
7954
|
if (snap === null) {
|
|
7878
7955
|
disabledRef.current = true;
|
|
@@ -7895,27 +7972,36 @@ function useLiveMonitor(opts) {
|
|
|
7895
7972
|
});
|
|
7896
7973
|
scheduleRef.current = () => {
|
|
7897
7974
|
window.clearTimeout(timerRef.current);
|
|
7898
|
-
|
|
7899
|
-
|
|
7975
|
+
const hasWork = pinsRef.current.length > 0 || watchesRef.current.length > 0;
|
|
7976
|
+
if (!mountedRef.current || disabledRef.current || !hasWork || document.visibilityState === "hidden") return;
|
|
7977
|
+
const fallbackMs = watchesRef.current.length > 0 ? LIVE_WATCH_POLL_MS : DEFAULT_POLL_MS;
|
|
7978
|
+
const hinted = snapshotRef.current ? snapshotRef.current.nextPollSeconds * 1e3 : fallbackMs;
|
|
7900
7979
|
timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted));
|
|
7901
7980
|
};
|
|
7902
|
-
|
|
7981
|
+
useEffect16(() => {
|
|
7903
7982
|
mountedRef.current = true;
|
|
7904
7983
|
return () => {
|
|
7905
7984
|
mountedRef.current = false;
|
|
7906
7985
|
};
|
|
7907
7986
|
}, []);
|
|
7908
7987
|
const prevPinsLengthRef = useRef11(0);
|
|
7909
|
-
|
|
7910
|
-
const wasEmpty = prevPinsLengthRef.current === 0;
|
|
7988
|
+
useEffect16(() => {
|
|
7989
|
+
const wasEmpty = prevPinsLengthRef.current === 0 && watchesRef.current.length === 0;
|
|
7911
7990
|
prevPinsLengthRef.current = pins.length;
|
|
7912
|
-
if (pins.length === 0) {
|
|
7991
|
+
if (pins.length === 0 && watchesRef.current.length === 0) {
|
|
7913
7992
|
window.clearTimeout(timerRef.current);
|
|
7914
7993
|
return;
|
|
7915
7994
|
}
|
|
7916
7995
|
if (wasEmpty) void tick();
|
|
7917
7996
|
}, [pins.length, tick]);
|
|
7918
|
-
|
|
7997
|
+
const prevWatchesLengthRef = useRef11(0);
|
|
7998
|
+
const watchesLength = opts.watches?.length ?? 0;
|
|
7999
|
+
useEffect16(() => {
|
|
8000
|
+
const wasEmpty = prevWatchesLengthRef.current === 0 && pinsRef.current.length === 0;
|
|
8001
|
+
prevWatchesLengthRef.current = watchesLength;
|
|
8002
|
+
if (wasEmpty && watchesLength > 0) void tick();
|
|
8003
|
+
}, [watchesLength, tick]);
|
|
8004
|
+
useEffect16(() => {
|
|
7919
8005
|
const matchPins = pins.filter((p) => p.kind === "match").length;
|
|
7920
8006
|
const marketPins = pins.length - matchPins;
|
|
7921
8007
|
if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
@@ -7923,12 +8009,12 @@ function useLiveMonitor(opts) {
|
|
|
7923
8009
|
if (activeTab === "today" && !hasToday) setActiveTabState("chat");
|
|
7924
8010
|
}, [pins, activeTab, hasToday]);
|
|
7925
8011
|
const prevIsOpenRef = useRef11(false);
|
|
7926
|
-
|
|
8012
|
+
useEffect16(() => {
|
|
7927
8013
|
const wasClosed = !prevIsOpenRef.current;
|
|
7928
8014
|
prevIsOpenRef.current = opts.isOpen;
|
|
7929
8015
|
if (wasClosed && opts.isOpen) void tick();
|
|
7930
8016
|
}, [opts.isOpen, tick]);
|
|
7931
|
-
|
|
8017
|
+
useEffect16(() => {
|
|
7932
8018
|
const onVisibility = () => {
|
|
7933
8019
|
if (document.visibilityState === "hidden") window.clearTimeout(timerRef.current);
|
|
7934
8020
|
else void tick();
|
|
@@ -7994,7 +8080,7 @@ function useLiveMonitor(opts) {
|
|
|
7994
8080
|
}
|
|
7995
8081
|
|
|
7996
8082
|
// src/useMatchDiscovery.ts
|
|
7997
|
-
import { useCallback as useCallback8, useEffect as
|
|
8083
|
+
import { useCallback as useCallback8, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef12, useState as useState37 } from "react";
|
|
7998
8084
|
|
|
7999
8085
|
// src/scheduleCache.ts
|
|
8000
8086
|
var PREFIX = "ss-w-schedule:";
|
|
@@ -8095,14 +8181,14 @@ function useMatchDiscovery(opts) {
|
|
|
8095
8181
|
getStatesRef.current = opts.getStates;
|
|
8096
8182
|
const pinnedKey = opts.pinnedMatchIds.join(",");
|
|
8097
8183
|
const [localDate, setLocalDate] = useState37(() => localDateOf(/* @__PURE__ */ new Date()));
|
|
8098
|
-
|
|
8184
|
+
useEffect17(() => {
|
|
8099
8185
|
const id = setInterval(() => {
|
|
8100
8186
|
const next = localDateOf(/* @__PURE__ */ new Date());
|
|
8101
8187
|
setLocalDate((prev) => prev === next ? prev : next);
|
|
8102
8188
|
}, ROLLOVER_CHECK_MS);
|
|
8103
8189
|
return () => clearInterval(id);
|
|
8104
8190
|
}, []);
|
|
8105
|
-
|
|
8191
|
+
useEffect17(() => {
|
|
8106
8192
|
let cancelled = false;
|
|
8107
8193
|
const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
8108
8194
|
const cached = readSchedule(opts.operatorId, localDate, Date.now());
|
|
@@ -8127,7 +8213,7 @@ function useMatchDiscovery(opts) {
|
|
|
8127
8213
|
cancelled = true;
|
|
8128
8214
|
};
|
|
8129
8215
|
}, [opts.operatorId, localDate]);
|
|
8130
|
-
|
|
8216
|
+
useEffect17(() => {
|
|
8131
8217
|
setExpanded((prev) => {
|
|
8132
8218
|
const next = {};
|
|
8133
8219
|
for (const group of groups) {
|
|
@@ -8154,7 +8240,7 @@ function useMatchDiscovery(opts) {
|
|
|
8154
8240
|
setFailures((n) => n + 1);
|
|
8155
8241
|
}
|
|
8156
8242
|
}, []);
|
|
8157
|
-
|
|
8243
|
+
useEffect17(() => {
|
|
8158
8244
|
if (!opts.isOpen) return;
|
|
8159
8245
|
void tick();
|
|
8160
8246
|
const id = setInterval(() => {
|
|
@@ -8175,7 +8261,7 @@ function useMatchDiscovery(opts) {
|
|
|
8175
8261
|
}
|
|
8176
8262
|
|
|
8177
8263
|
// src/useGames.ts
|
|
8178
|
-
import { useCallback as useCallback9, useEffect as
|
|
8264
|
+
import { useCallback as useCallback9, useEffect as useEffect18, useRef as useRef13, useState as useState38 } from "react";
|
|
8179
8265
|
var GAMES_POLL_MS = 6e4;
|
|
8180
8266
|
var DEFAULT_TZ = "Europe/London";
|
|
8181
8267
|
function computeGameDay(timezone) {
|
|
@@ -8193,7 +8279,7 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
|
|
|
8193
8279
|
const tzRef = useRef13(operatorTimezone ?? DEFAULT_TZ);
|
|
8194
8280
|
tzRef.current = operatorTimezone ?? DEFAULT_TZ;
|
|
8195
8281
|
const ready = conversation != null;
|
|
8196
|
-
|
|
8282
|
+
useEffect18(() => {
|
|
8197
8283
|
if (hardOffRef.current) return;
|
|
8198
8284
|
let active = true;
|
|
8199
8285
|
const doFetch = async () => {
|
|
@@ -8243,7 +8329,7 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
|
|
|
8243
8329
|
}
|
|
8244
8330
|
|
|
8245
8331
|
// src/useLeaderboard.ts
|
|
8246
|
-
import { useCallback as useCallback10, useEffect as
|
|
8332
|
+
import { useCallback as useCallback10, useEffect as useEffect19, useRef as useRef14, useState as useState39 } from "react";
|
|
8247
8333
|
function useLeaderboard(conversation, { activeTab }) {
|
|
8248
8334
|
const [data, setData] = useState39(null);
|
|
8249
8335
|
const [loading, setLoading] = useState39(false);
|
|
@@ -8251,7 +8337,7 @@ function useLeaderboard(conversation, { activeTab }) {
|
|
|
8251
8337
|
const inFlightRef = useRef14(false);
|
|
8252
8338
|
const conversationRef = useRef14(conversation);
|
|
8253
8339
|
conversationRef.current = conversation;
|
|
8254
|
-
|
|
8340
|
+
useEffect19(() => {
|
|
8255
8341
|
if (activeTab !== "leaderboard" && activeTab !== "games") return;
|
|
8256
8342
|
let active = true;
|
|
8257
8343
|
const doFetch = async () => {
|
|
@@ -8281,11 +8367,11 @@ function useLeaderboard(conversation, { activeTab }) {
|
|
|
8281
8367
|
}
|
|
8282
8368
|
|
|
8283
8369
|
// src/popupTelemetry.ts
|
|
8284
|
-
import { useCallback as useCallback11, useEffect as
|
|
8370
|
+
import { useCallback as useCallback11, useEffect as useEffect20, useRef as useRef15 } from "react";
|
|
8285
8371
|
function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
|
|
8286
8372
|
const shownRef = useRef15(/* @__PURE__ */ new Set());
|
|
8287
8373
|
const closedTextRef = useRef15(null);
|
|
8288
|
-
|
|
8374
|
+
useEffect20(() => {
|
|
8289
8375
|
if (isOpen) {
|
|
8290
8376
|
if (closedTextRef.current) log?.log({ name: "popup_opened" });
|
|
8291
8377
|
closedTextRef.current = null;
|
|
@@ -8304,7 +8390,7 @@ function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
|
|
|
8304
8390
|
}
|
|
8305
8391
|
|
|
8306
8392
|
// src/components/ChatFab.tsx
|
|
8307
|
-
import { useEffect as
|
|
8393
|
+
import { useEffect as useEffect21, useRef as useRef16, useState as useState40 } from "react";
|
|
8308
8394
|
|
|
8309
8395
|
// src/components/GreetingBubble.tsx
|
|
8310
8396
|
import { jsx as jsx89, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
@@ -8339,7 +8425,7 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
|
|
|
8339
8425
|
const bubble = popupText ?? greeting;
|
|
8340
8426
|
const [intro, setIntro] = useState40(false);
|
|
8341
8427
|
const armedRef = useRef16(introAllowed);
|
|
8342
|
-
|
|
8428
|
+
useEffect21(() => {
|
|
8343
8429
|
if (armedRef.current && bubble) {
|
|
8344
8430
|
armedRef.current = false;
|
|
8345
8431
|
setIntro(true);
|
|
@@ -8751,6 +8837,12 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
8751
8837
|
.ss-w-mo-more-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }
|
|
8752
8838
|
.ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }
|
|
8753
8839
|
.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
8840
|
+
/* Stage 4: live card score+minute in header (R18). */
|
|
8841
|
+
.ss-w-bi-score { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); white-space: nowrap; }
|
|
8842
|
+
.ss-w-bi-min { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; }
|
|
8843
|
+
/* D12: closed state message row; D13: stale-price notice. */
|
|
8844
|
+
.ss-w-mo-closed { padding: 6px 0; font-size: 12.5px; color: var(--ss-w-faint); }
|
|
8845
|
+
.ss-w-mo-stale { margin: 0; font-size: 11px; color: var(--ss-w-faint); }
|
|
8754
8846
|
/* The card's stat, in the Live tab accordion's insight style. No row below it is marked (R17). */
|
|
8755
8847
|
.ss-w-mo-stat { 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; }
|
|
8756
8848
|
.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
|
|
@@ -9953,12 +10045,27 @@ function StatsWidget(props) {
|
|
|
9953
10045
|
const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
|
|
9954
10046
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
|
|
9955
10047
|
const [hasToday, setHasToday] = useState41(false);
|
|
10048
|
+
const liveCardWatches = useMemo4(() => {
|
|
10049
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10050
|
+
const out = [];
|
|
10051
|
+
for (const msg of controller.state.messages) {
|
|
10052
|
+
if (msg.role !== "assistant") continue;
|
|
10053
|
+
for (const vm of msg.marketOdds) {
|
|
10054
|
+
if (vm.live == null || seen.has(vm.matchId)) continue;
|
|
10055
|
+
seen.add(vm.matchId);
|
|
10056
|
+
out.push({ key: `live:card:${vm.matchId}`, kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName ?? "FULLTIME_RESULT" });
|
|
10057
|
+
}
|
|
10058
|
+
}
|
|
10059
|
+
return out;
|
|
10060
|
+
}, [controller.state.messages]);
|
|
10061
|
+
const locale = cfg?.locale;
|
|
9956
10062
|
const monitor = useLiveMonitor({
|
|
9957
|
-
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
10063
|
+
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins, locale) : Promise.resolve(null),
|
|
9958
10064
|
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
9959
10065
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
9960
10066
|
isOpen: controller.state.isOpen,
|
|
9961
|
-
hasToday
|
|
10067
|
+
hasToday,
|
|
10068
|
+
watches: liveCardWatches
|
|
9962
10069
|
});
|
|
9963
10070
|
const getSchedule = useCallback12(
|
|
9964
10071
|
(localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
|
|
@@ -9980,14 +10087,49 @@ function StatsWidget(props) {
|
|
|
9980
10087
|
pinnedMatchIds
|
|
9981
10088
|
});
|
|
9982
10089
|
const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
|
|
9983
|
-
|
|
10090
|
+
useEffect22(() => {
|
|
9984
10091
|
setHasToday(todayHasContent);
|
|
9985
10092
|
}, [todayHasContent]);
|
|
10093
|
+
const prevLiveSnapshotRef = useRef17(monitor.snapshot);
|
|
10094
|
+
useEffect22(() => {
|
|
10095
|
+
const snap = monitor.snapshot;
|
|
10096
|
+
if (!snap || snap === prevLiveSnapshotRef.current) return;
|
|
10097
|
+
prevLiveSnapshotRef.current = snap;
|
|
10098
|
+
for (const market of snap.markets) {
|
|
10099
|
+
if (!market.key.startsWith("live:card:")) continue;
|
|
10100
|
+
const matchId = parseInt(market.key.slice("live:card:".length), 10);
|
|
10101
|
+
if (!Number.isFinite(matchId)) continue;
|
|
10102
|
+
let mainRows = [];
|
|
10103
|
+
let moreRows = [];
|
|
10104
|
+
let addToSlipEnabled = false;
|
|
10105
|
+
if (market.card) {
|
|
10106
|
+
const updated = toMarketOddsVM(market.card);
|
|
10107
|
+
mainRows = updated.mainRows;
|
|
10108
|
+
moreRows = updated.moreRows;
|
|
10109
|
+
addToSlipEnabled = updated.addToSlipEnabled;
|
|
10110
|
+
}
|
|
10111
|
+
let closedReason = null;
|
|
10112
|
+
if (market.phase === "fullTime" || market.phase === "postponed") closedReason = "full_time";
|
|
10113
|
+
else if (market.isSuspended) closedReason = "suspended";
|
|
10114
|
+
else if (!market.card) closedReason = "no_live_price";
|
|
10115
|
+
const live = {
|
|
10116
|
+
phase: market.phase,
|
|
10117
|
+
homeScore: market.homeScore ?? null,
|
|
10118
|
+
awayScore: market.awayScore ?? null,
|
|
10119
|
+
minuteLabel: market.minuteLabel ?? null,
|
|
10120
|
+
isSuspended: market.isSuspended,
|
|
10121
|
+
isSettled: market.isSettled,
|
|
10122
|
+
asOfUtc: market.asOfUtc,
|
|
10123
|
+
closedReason
|
|
10124
|
+
};
|
|
10125
|
+
controller._dispatch?.({ kind: "UPDATE_LIVE_CARD", matchId, live, mainRows, moreRows, addToSlipEnabled });
|
|
10126
|
+
}
|
|
10127
|
+
}, [monitor.snapshot]);
|
|
9986
10128
|
const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
|
|
9987
10129
|
const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
|
|
9988
10130
|
const markTodayActivity = monitor.markTodayActivity;
|
|
9989
10131
|
const prevLiveCountRef = useRef17(0);
|
|
9990
|
-
|
|
10132
|
+
useEffect22(() => {
|
|
9991
10133
|
const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
|
|
9992
10134
|
prevLiveCountRef.current = discovery.liveCount;
|
|
9993
10135
|
if (rose) markTodayActivity();
|
|
@@ -10040,11 +10182,11 @@ function StatsWidget(props) {
|
|
|
10040
10182
|
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
10041
10183
|
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
10042
10184
|
const conversationId = controller.state.conversationId ?? void 0;
|
|
10043
|
-
|
|
10185
|
+
useEffect22(() => {
|
|
10044
10186
|
if (!logger) return;
|
|
10045
10187
|
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
10046
10188
|
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
10047
|
-
|
|
10189
|
+
useEffect22(() => {
|
|
10048
10190
|
if (!logger) return;
|
|
10049
10191
|
logger.resume();
|
|
10050
10192
|
const onHide = () => {
|
|
@@ -10062,7 +10204,7 @@ function StatsWidget(props) {
|
|
|
10062
10204
|
logger.dispose();
|
|
10063
10205
|
};
|
|
10064
10206
|
}, [logger]);
|
|
10065
|
-
|
|
10207
|
+
useEffect22(() => {
|
|
10066
10208
|
if (!built || !ui.injectStyles) return;
|
|
10067
10209
|
const node = rootRef.current?.getRootNode();
|
|
10068
10210
|
if (node) injectStyles(node);
|