@sensiblestats/widget-react 0.60.0 → 0.60.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.60.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Games hub refreshes today's points, tile status, streak and rank as soon as a fan returns from a game, instead of waiting for the 60-second poll or a tab switch.
8
+
9
+ ## 0.60.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Localize game display names for Turkish operators; rename mystery-tiger display name to Mystery Player
14
+
3
15
  ## 0.60.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -175,6 +175,18 @@ var STRINGS = {
175
175
  alreadyPlayedTitle: "Played today",
176
176
  guess: "Guess",
177
177
  formatDayTime: (iso) => new Intl.DateTimeFormat("en-GB", { weekday: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(iso)),
178
+ titles: {
179
+ "mystery-tiger": "Mystery Player",
180
+ "daily-quiz": "Daily Quiz",
181
+ "career-path": "Career Path",
182
+ "beat-the-grid": "Beat the Grid",
183
+ "guess-the-xi": "Guess the XI",
184
+ "higher-or-lower": "Higher or Lower",
185
+ "matchday-predictor": "Matchday Predictor",
186
+ "starting-xi": "Starting XI",
187
+ "stat-ladder": "Stat Ladder",
188
+ "fan-motm": "Fan MOTM"
189
+ },
178
190
  taglines: {
179
191
  "mystery-tiger": "One player. Six guesses.",
180
192
  "higher-or-lower": "Who had more?",
@@ -458,6 +470,18 @@ var STRINGS = {
458
470
  alreadyPlayedTitle: "Bug\xFCn oynad\u0131n",
459
471
  guess: "Tahmin",
460
472
  formatDayTime: (iso) => new Intl.DateTimeFormat("tr-TR", { weekday: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(iso)),
473
+ titles: {
474
+ "mystery-tiger": "Gizemli Oyuncu",
475
+ "daily-quiz": "G\xFCn\xFCn Testi",
476
+ "career-path": "Kariyer Yolu",
477
+ "beat-the-grid": "Tabloyu Tamamla",
478
+ "guess-the-xi": "Bu 11 Kimin?",
479
+ "higher-or-lower": "Fazla m\u0131, Az m\u0131?",
480
+ "matchday-predictor": "Skor Tahmini",
481
+ "starting-xi": "\u0130lk 11 Tahmini",
482
+ "stat-ladder": "\u0130statistik Merdiveni",
483
+ "fan-motm": "Ma\xE7\u0131n Oyuncusu"
484
+ },
461
485
  taglines: {
462
486
  "mystery-tiger": "Bir oyuncu. Alt\u0131 tahmin.",
463
487
  "higher-or-lower": "Kimin daha fazlas\u0131 var?",
@@ -2187,6 +2211,7 @@ function useLeaderboard(conversation, { activeTab }) {
2187
2211
  void doFetch();
2188
2212
  return () => {
2189
2213
  active = false;
2214
+ inFlightRef.current = false;
2190
2215
  };
2191
2216
  }, [activeTab, refreshCount]);
2192
2217
  const refresh = (0, import_react7.useCallback)(() => {
@@ -4422,23 +4447,11 @@ function GamesLoginWall({ ui }) {
4422
4447
  var import_react28 = require("react");
4423
4448
 
4424
4449
  // src/components/games/ui/gameMeta.ts
4425
- var GAME_TITLES = {
4426
- "mystery-tiger": "Mystery Tiger",
4427
- "daily-quiz": "Daily Quiz",
4428
- "career-path": "Career Path",
4429
- "beat-the-grid": "Beat the Grid",
4430
- "guess-the-xi": "Guess the XI",
4431
- "higher-or-lower": "Higher or Lower",
4432
- "matchday-predictor": "Matchday Predictor",
4433
- "starting-xi": "Starting XI",
4434
- "stat-ladder": "Stat Ladder",
4435
- "fan-motm": "Fan MOTM"
4436
- };
4437
4450
  function prettifyGameId(gameId) {
4438
4451
  return gameId.split("-").map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
4439
4452
  }
4440
- function gameTitle(g) {
4441
- return g.title ?? GAME_TITLES[g.gameId] ?? prettifyGameId(g.gameId);
4453
+ function gameTitle(g, titles) {
4454
+ return g.title ?? titles[g.gameId] ?? prettifyGameId(g.gameId);
4442
4455
  }
4443
4456
  function splitName(full) {
4444
4457
  const parts = full.trim().split(/\s+/).filter(Boolean);
@@ -4571,7 +4584,7 @@ var DISABLED = /* @__PURE__ */ new Set(["locked", "voided"]);
4571
4584
  function GameTile({ game, onOpen, ui, variant = "tile" }) {
4572
4585
  const status = tileStatus(game, ui);
4573
4586
  const disabled = DISABLED.has(game.status);
4574
- const title = gameTitle(game);
4587
+ const title = gameTitle(game, ui.games.titles);
4575
4588
  const body = variant === "hero" ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
4576
4589
  /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "ss-g-hero-text", children: [
4577
4590
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-g-hero-eyebrow", children: ui.games.dailyChallenge }),
@@ -5106,7 +5119,7 @@ function MysteryTigerGame({
5106
5119
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
5107
5120
  GameHeader,
5108
5121
  {
5109
- title: gameTitle({ gameId: "mystery-tiger" }),
5122
+ title: gameTitle({ gameId: "mystery-tiger" }, ui.games.titles),
5110
5123
  eyebrow: t.eyebrow,
5111
5124
  right: headerRight,
5112
5125
  onBack,
@@ -5278,7 +5291,7 @@ function HigherOrLowerGame({
5278
5291
  /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5279
5292
  GameHeader,
5280
5293
  {
5281
- title: gameTitle({ gameId: "higher-or-lower" }),
5294
+ title: gameTitle({ gameId: "higher-or-lower" }, ui.games.titles),
5282
5295
  eyebrow: t.eyebrow(POINTS_PER_CORRECT),
5283
5296
  right: config ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatStack, { value: runLength, label: t.streak }) : void 0,
5284
5297
  onBack,
@@ -5379,7 +5392,7 @@ function CareerPathGame({
5379
5392
  ui
5380
5393
  }) {
5381
5394
  const s = ui.games.careerPath;
5382
- const title = gameTitle({ gameId: "career-path" });
5395
+ const title = gameTitle({ gameId: "career-path" }, ui.games.titles);
5383
5396
  const [query, setQuery] = (0, import_react33.useState)("");
5384
5397
  const inputId = (0, import_react33.useId)();
5385
5398
  const clientState = parseClientState3(result?.clientStateJson);
@@ -5629,7 +5642,7 @@ function BeatTheGridGame({
5629
5642
  playerPool
5630
5643
  }) {
5631
5644
  const s = ui.games.beatTheGrid;
5632
- const title = gameTitle({ gameId: "beat-the-grid" });
5645
+ const title = gameTitle({ gameId: "beat-the-grid" }, ui.games.titles);
5633
5646
  const [activeCell, setActiveCell] = (0, import_react34.useState)(null);
5634
5647
  const clientState = parseClientState4(result?.clientStateJson);
5635
5648
  const filledCells = clientState?.cells ?? [];
@@ -5883,7 +5896,7 @@ function GuessTheXiGame({
5883
5896
  /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
5884
5897
  GameHeader,
5885
5898
  {
5886
- title: gameTitle({ gameId: "guess-the-xi" }),
5899
+ title: gameTitle({ gameId: "guess-the-xi" }, ui.games.titles),
5887
5900
  eyebrow: config?.poolLabel,
5888
5901
  right: formation ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(Chip, { variant: "accent", children: formation }) : void 0,
5889
5902
  onBack,
@@ -6004,7 +6017,7 @@ function DailyQuizGame({
6004
6017
  ui
6005
6018
  }) {
6006
6019
  const s = ui.games.dailyQuiz;
6007
- const title = gameTitle({ gameId: "daily-quiz" });
6020
+ const title = gameTitle({ gameId: "daily-quiz" }, ui.games.titles);
6008
6021
  const [selections, setSelections] = (0, import_react36.useState)(/* @__PURE__ */ new Map());
6009
6022
  const [page, setPage] = (0, import_react36.useState)(0);
6010
6023
  const clientState = parseClientState6(result?.clientStateJson);
@@ -6220,7 +6233,7 @@ function MatchdayPredictorGame({
6220
6233
  const header = /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
6221
6234
  GameHeader,
6222
6235
  {
6223
- title: gameTitle({ gameId: "matchday-predictor" }),
6236
+ title: gameTitle({ gameId: "matchday-predictor" }, ui.games.titles),
6224
6237
  eyebrow: config ? t.eyebrow(config.homeTeam.name, config.awayTeam.name) : void 0,
6225
6238
  right: config ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(Chip, { icon: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(IconLock, {}), children: ui.games.formatDayTime(config.kickoffUtc) }) : void 0,
6226
6239
  onBack,
@@ -6434,7 +6447,7 @@ function StartingXiGame({
6434
6447
  const header = /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
6435
6448
  GameHeader,
6436
6449
  {
6437
- title: gameTitle({ gameId: "starting-xi" }),
6450
+ title: gameTitle({ gameId: "starting-xi" }, ui.games.titles),
6438
6451
  eyebrow: t.eyebrow,
6439
6452
  right: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Chip, { variant: "accent", children: t.perStarter(POINTS_PER_STARTER) }),
6440
6453
  onBack,
@@ -6609,7 +6622,7 @@ function StatLadderGame({
6609
6622
  const searchId = (0, import_react39.useId)();
6610
6623
  const clientState = parseClientState9(result?.clientStateJson);
6611
6624
  const revealed = clientState != null;
6612
- const header = /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(GameHeader, { title: gameTitle({ gameId: "stat-ladder" }), eyebrow: t.eyebrow, onBack, backLabel: ui.back });
6625
+ const header = /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(GameHeader, { title: gameTitle({ gameId: "stat-ladder" }, ui.games.titles), eyebrow: t.eyebrow, onBack, backLabel: ui.back });
6613
6626
  if (!config) {
6614
6627
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "ss-g-screen", "data-testid": "game-screen-stat-ladder", children: [
6615
6628
  header,
@@ -6806,6 +6819,7 @@ function safeParseConfig(json) {
6806
6819
  function GameScreenHost({
6807
6820
  selected,
6808
6821
  onBack,
6822
+ onPlayed,
6809
6823
  conversation,
6810
6824
  ui
6811
6825
  }) {
@@ -6849,7 +6863,11 @@ function GameScreenHost({
6849
6863
  const sharedProps = {
6850
6864
  result,
6851
6865
  submitting,
6852
- onSubmit: submit,
6866
+ // Refresh only after the play is saved: a fan can tap Back while a submit is still in flight,
6867
+ // and a refetch fired from Back alone would read the hub's pre-play state.
6868
+ onSubmit: (answerJson) => {
6869
+ void submit(answerJson).then(() => onPlayed?.());
6870
+ },
6853
6871
  ui,
6854
6872
  onBack,
6855
6873
  lockAtUtc
@@ -6940,7 +6958,7 @@ function GameScreenHost({
6940
6958
  }
6941
6959
  );
6942
6960
  default:
6943
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "ss-g-screen", "data-testid": `game-screen-${gameId}`, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(GameHeader, { title: gameTitle({ gameId }), onBack, backLabel: ui.back }) });
6961
+ return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "ss-g-screen", "data-testid": `game-screen-${gameId}`, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(GameHeader, { title: gameTitle({ gameId }, ui.games.titles), onBack, backLabel: ui.back }) });
6944
6962
  }
6945
6963
  }
6946
6964
  return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "ss-w-gscreen", "data-testid": "gscreen", "data-lock-at": lockAtUtc ?? void 0, children: renderScreen() });
@@ -6966,7 +6984,8 @@ function GamesPanel({
6966
6984
  games,
6967
6985
  ui,
6968
6986
  conversation,
6969
- leaderboard
6987
+ leaderboard,
6988
+ refreshHub
6970
6989
  }) {
6971
6990
  const [selected, setSelected] = (0, import_react41.useState)(null);
6972
6991
  (0, import_react41.useEffect)(() => {
@@ -6978,7 +6997,11 @@ function GamesPanel({
6978
6997
  GameScreenHost,
6979
6998
  {
6980
6999
  selected,
6981
- onBack: () => setSelected(null),
7000
+ onBack: () => {
7001
+ setSelected(null);
7002
+ refreshHub?.();
7003
+ },
7004
+ onPlayed: refreshHub,
6982
7005
  conversation: conversation ?? null,
6983
7006
  ui
6984
7007
  }
@@ -7228,7 +7251,20 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
7228
7251
  monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(TodayPanel, { discovery, ui, monitor }),
7229
7252
  monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(MatchesPanel, { monitor, ui, slip }),
7230
7253
  monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(OddsPanel, { monitor, ui, slip }),
7231
- monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(GamesPanel, { loggedIn: !!loggedIn, games: gamesResult.games, ui, conversation, leaderboard: leaderboardResult?.data ?? null }),
7254
+ monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
7255
+ GamesPanel,
7256
+ {
7257
+ loggedIn: !!loggedIn,
7258
+ games: gamesResult.games,
7259
+ ui,
7260
+ conversation,
7261
+ leaderboard: leaderboardResult?.data ?? null,
7262
+ refreshHub: () => {
7263
+ gamesResult.refresh();
7264
+ leaderboardResult?.refresh();
7265
+ }
7266
+ }
7267
+ ),
7232
7268
  monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
7233
7269
  LeaderboardPanel,
7234
7270
  {