@agg-build/ui 4.17.3 → 4.18.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.
Files changed (103) hide show
  1. package/dist/{chunk-7E4UXCEX.mjs → chunk-2OBJ7DYT.mjs} +1227 -534
  2. package/dist/{chunk-RZLM3M5R.mjs → chunk-2UPO6G3S.mjs} +1251 -2578
  3. package/dist/{chunk-DSQSQ4RG.mjs → chunk-FTWJRLJQ.mjs} +726 -3825
  4. package/dist/chunk-HFL3CEWG.mjs +3482 -0
  5. package/dist/{chunk-TK62UB5F.mjs → chunk-JJ3VVCEP.mjs} +6 -13
  6. package/dist/{chunk-B5ALKYD5.mjs → chunk-NRPS2D3Q.mjs} +176 -17
  7. package/dist/{chunk-BBDFSTIA.mjs → chunk-WIGSRHUG.mjs} +1532 -741
  8. package/dist/chunk-WSZYDOZN.mjs +2040 -0
  9. package/dist/{chunk-JI5KV4QI.mjs → chunk-ZNOAKSPT.mjs} +8 -10
  10. package/dist/event-market-GX24AP2H.mjs +21 -0
  11. package/dist/events.js +2960 -1523
  12. package/dist/events.mjs +6 -4
  13. package/dist/index.js +36141 -30748
  14. package/dist/index.mjs +34 -22
  15. package/dist/modals.js +1763 -1456
  16. package/dist/modals.mjs +5 -3
  17. package/dist/pages.js +34107 -28284
  18. package/dist/pages.mjs +17 -8
  19. package/dist/primitives.js +1552 -786
  20. package/dist/primitives.mjs +1 -1
  21. package/dist/styles.css +1 -1
  22. package/dist/tailwind.css +1 -1
  23. package/dist/trading.js +2559 -1499
  24. package/dist/trading.mjs +4 -4
  25. package/dist/types/events/item-details/event-chart-window.d.mts +9 -0
  26. package/dist/types/events/item-details/event-chart-window.d.ts +9 -0
  27. package/dist/types/events/item-details/event-list-item-details.types.d.mts +7 -0
  28. package/dist/types/events/item-details/event-list-item-details.types.d.ts +7 -0
  29. package/dist/types/events/item-details/event-markets-chart.d.mts +12 -0
  30. package/dist/types/events/item-details/event-markets-chart.d.ts +12 -0
  31. package/dist/types/events/item-details/event-markets-chart.utils.d.mts +23 -0
  32. package/dist/types/events/item-details/event-markets-chart.utils.d.ts +23 -0
  33. package/dist/types/events/list/event-list.constants.d.mts +2 -0
  34. package/dist/types/events/list/event-list.constants.d.ts +2 -0
  35. package/dist/types/events/market-details/use-visible-market-streams.d.mts +7 -0
  36. package/dist/types/events/market-details/use-visible-market-streams.d.ts +7 -0
  37. package/dist/types/events/shared/chart-source-caption.d.mts +4 -0
  38. package/dist/types/events/shared/chart-source-caption.d.ts +4 -0
  39. package/dist/types/events/shared/chart-venue-selection.d.mts +11 -0
  40. package/dist/types/events/shared/chart-venue-selection.d.ts +11 -0
  41. package/dist/types/events/shared/use-chart-orderbook.d.mts +23 -0
  42. package/dist/types/events/shared/use-chart-orderbook.d.ts +23 -0
  43. package/dist/types/onboarding/index.d.mts +1 -0
  44. package/dist/types/onboarding/index.d.ts +1 -0
  45. package/dist/types/onboarding/steps/connect-prophetx-modal.d.mts +12 -0
  46. package/dist/types/onboarding/steps/connect-prophetx-modal.d.ts +12 -0
  47. package/dist/types/pages/event-market/event-market.types.d.mts +5 -0
  48. package/dist/types/pages/event-market/event-market.types.d.ts +5 -0
  49. package/dist/types/pages/event-market/event-open-orders.d.mts +50 -0
  50. package/dist/types/pages/event-market/event-open-orders.d.ts +50 -0
  51. package/dist/types/pages/event-market/index.d.mts +3 -0
  52. package/dist/types/pages/event-market/index.d.ts +3 -0
  53. package/dist/types/pages/event-market/sports-event-market-page.d.mts +1 -1
  54. package/dist/types/pages/event-market/sports-event-market-page.d.ts +1 -1
  55. package/dist/types/pages/event-market/use-event-open-orders.d.mts +27 -0
  56. package/dist/types/pages/event-market/use-event-open-orders.d.ts +27 -0
  57. package/dist/types/pages/user-profile/components/available-balance-card.d.mts +2 -0
  58. package/dist/types/pages/user-profile/components/available-balance-card.d.ts +2 -0
  59. package/dist/types/pages/user-profile/components/betdex-account-activity.d.mts +4 -0
  60. package/dist/types/pages/user-profile/components/betdex-account-activity.d.ts +4 -0
  61. package/dist/types/pages/user-profile/components/betdex-account-card.d.mts +2 -0
  62. package/dist/types/pages/user-profile/components/betdex-account-card.d.ts +2 -0
  63. package/dist/types/pages/user-profile/components/betdex-account-transfers.d.mts +7 -0
  64. package/dist/types/pages/user-profile/components/betdex-account-transfers.d.ts +7 -0
  65. package/dist/types/pages/user-profile/components/open-order-row.d.mts +8 -1
  66. package/dist/types/pages/user-profile/components/open-order-row.d.ts +8 -1
  67. package/dist/types/pages/user-profile/user-profile.types.d.mts +5 -0
  68. package/dist/types/pages/user-profile/user-profile.types.d.ts +5 -0
  69. package/dist/types/primitives/chart/chart.constants.d.mts +7 -0
  70. package/dist/types/primitives/chart/chart.constants.d.ts +7 -0
  71. package/dist/types/primitives/chart/chart.types.d.mts +24 -2
  72. package/dist/types/primitives/chart/chart.types.d.ts +24 -2
  73. package/dist/types/primitives/chart/index.d.mts +2 -2
  74. package/dist/types/primitives/chart/index.d.ts +2 -2
  75. package/dist/types/primitives/chart/probability-chart.d.mts +22 -0
  76. package/dist/types/primitives/chart/probability-chart.d.ts +22 -0
  77. package/dist/types/primitives/chart/probability-chart.utils.d.mts +12 -0
  78. package/dist/types/primitives/chart/probability-chart.utils.d.ts +12 -0
  79. package/dist/types/primitives/chart/probability-live-tail.d.mts +16 -0
  80. package/dist/types/primitives/chart/probability-live-tail.d.ts +16 -0
  81. package/dist/types/primitives/remote-image/index.d.mts +1 -1
  82. package/dist/types/primitives/remote-image/index.d.ts +1 -1
  83. package/dist/types/primitives/remote-image/remote-image.types.d.mts +6 -0
  84. package/dist/types/primitives/remote-image/remote-image.types.d.ts +6 -0
  85. package/dist/types/primitives/skeleton/views/event-list-item-skeleton-view.d.mts +6 -0
  86. package/dist/types/primitives/skeleton/views/event-list-item-skeleton-view.d.ts +6 -0
  87. package/dist/types/primitives/venue-logo/svg/logo-betdex.d.mts +12 -0
  88. package/dist/types/primitives/venue-logo/svg/logo-betdex.d.ts +12 -0
  89. package/dist/types/primitives/venue-logo/svg/logo-tiprun.d.mts +7 -0
  90. package/dist/types/primitives/venue-logo/svg/logo-tiprun.d.ts +7 -0
  91. package/dist/types/shared/open-orders.d.mts +63 -0
  92. package/dist/types/shared/open-orders.d.ts +63 -0
  93. package/dist/types/shared/use-open-order-cancellation.d.mts +18 -0
  94. package/dist/types/shared/use-open-order-cancellation.d.ts +18 -0
  95. package/dist/types/trading/manage-betdex-account-modal.d.mts +5 -0
  96. package/dist/types/trading/manage-betdex-account-modal.d.ts +5 -0
  97. package/dist/types/trading/place-order/index.place-order.execution-steps.d.mts +2 -0
  98. package/dist/types/trading/place-order/index.place-order.execution-steps.d.ts +2 -0
  99. package/dist/types/trading/place-order/index.place-order.types.d.mts +5 -0
  100. package/dist/types/trading/place-order/index.place-order.types.d.ts +5 -0
  101. package/dist/types/trading/place-order/index.place-order.utils.d.mts +6 -1
  102. package/dist/types/trading/place-order/index.place-order.utils.d.ts +6 -1
  103. package/package.json +3 -3
@@ -0,0 +1,3482 @@
1
+ "use client";
2
+ import {
3
+ EventListItemDetails,
4
+ MarketDetails,
5
+ MarketDetailsList,
6
+ isErrorWithStatus
7
+ } from "./chunk-2UPO6G3S.mjs";
8
+ import {
9
+ PlaceOrder,
10
+ SettlementDetails,
11
+ useResolvedMarketClaim
12
+ } from "./chunk-2OBJ7DYT.mjs";
13
+ import {
14
+ getDisplayOutcomePrice,
15
+ resolveHeaderOutcomeItems,
16
+ resolveMarketFromVenueMarkets
17
+ } from "./chunk-JJ3VVCEP.mjs";
18
+ import {
19
+ AggErrorBoundary,
20
+ Button,
21
+ CloseIcon,
22
+ Icon,
23
+ LoadingIcon,
24
+ Modal,
25
+ RemoteImage,
26
+ SearchEmptyIcon,
27
+ Skeleton,
28
+ StateMessage,
29
+ VenueLogo,
30
+ __async,
31
+ __objRest,
32
+ __restKey,
33
+ __spreadProps,
34
+ __spreadValues,
35
+ cn,
36
+ formatRecurringMarketPillTimeEt,
37
+ formatRecurringMarketWindowTimeEt,
38
+ normalizeVenueMarketCluster,
39
+ skeletonViews,
40
+ useOptionalToast
41
+ } from "./chunk-WIGSRHUG.mjs";
42
+
43
+ // src/pages/event-market/index.tsx
44
+ import {
45
+ resolveRecurringCryptoTimeline,
46
+ resolveEventTradingState as resolveEventTradingState3,
47
+ TradeSide as TradeSide2,
48
+ useEnrichedVenueEvent,
49
+ useEventTradingContext as useEventTradingContext4,
50
+ useLabels as useLabels8,
51
+ useMidpoints as useMidpoints2,
52
+ useRecurringCryptoMarkets,
53
+ useSdkUiConfig as useSdkUiConfig3,
54
+ useResolvedExecutionMode as useResolvedExecutionMode2
55
+ } from "@agg-build/hooks";
56
+ import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef5, useState as useState7 } from "react";
57
+
58
+ // src/pages/event-market/event-open-orders.tsx
59
+ import { useAggAuthState, useLabels as useLabels4, useSdkUiConfig } from "@agg-build/hooks";
60
+ import { useCallback as useCallback2 } from "react";
61
+
62
+ // src/pages/user-profile/components/open-order-row.tsx
63
+ import { optimizedImageUrl, retinaImageUrl, useLabels } from "@agg-build/hooks";
64
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
65
+ var shouldUseNativeLinkNavigation = (event) => {
66
+ return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button === 1;
67
+ };
68
+ var CANCELLABLE_LIMIT_ORDER_STATUSES = /* @__PURE__ */ new Set([
69
+ "submitted",
70
+ "open",
71
+ "partially_filled_open",
72
+ "cancel_pending"
73
+ ]);
74
+ var canCancelOpenOrder = (order) => {
75
+ const status = order.status.trim().toLowerCase();
76
+ const isLimitOrder = order.orderType === "limit" || order.limitPriceLabel != null;
77
+ if (!isLimitOrder) return false;
78
+ if (status === "pending" && !order.dagRunId) return true;
79
+ return CANCELLABLE_LIMIT_ORDER_STATUSES.has(status);
80
+ };
81
+ var PENDING_LIMIT_ORDER_STATUSES = /* @__PURE__ */ new Set([
82
+ "pending",
83
+ "signing",
84
+ "pending_bridge",
85
+ "submitting"
86
+ ]);
87
+ var isPendingOpenOrder = (order) => {
88
+ const isLimitOrder = order.orderType === "limit" || order.limitPriceLabel != null;
89
+ return isLimitOrder && PENDING_LIMIT_ORDER_STATUSES.has(order.status.trim().toLowerCase()) && !canCancelOpenOrder(order);
90
+ };
91
+ var OpenOrderRow = ({
92
+ order,
93
+ variant = "profile",
94
+ href,
95
+ onClick,
96
+ onCancel,
97
+ isCancelling = false,
98
+ cancelLabel,
99
+ cancelAriaLabel,
100
+ limitPriceHeader,
101
+ filledHeader,
102
+ totalHeader,
103
+ expirationHeader
104
+ }) => {
105
+ var _a, _b, _c, _d;
106
+ const allLabels = useLabels();
107
+ const labels = allLabels.userProfile.openOrders;
108
+ const isEventVariant = variant === "event";
109
+ const resolvedCancelLabel = cancelLabel != null ? cancelLabel : labels.cancel;
110
+ const resolvedCancelAriaLabel = cancelAriaLabel != null ? cancelAriaLabel : labels.cancelOrderAria(order.id);
111
+ const resolvedLimitPriceHeader = limitPriceHeader != null ? limitPriceHeader : labels.limitPriceHeader;
112
+ const resolvedFilledHeader = filledHeader != null ? filledHeader : labels.filledHeader;
113
+ const resolvedTotalHeader = totalHeader != null ? totalHeader : labels.totalHeader;
114
+ const resolvedExpirationHeader = expirationHeader != null ? expirationHeader : labels.expirationHeader;
115
+ const handleDivClick = () => {
116
+ onClick == null ? void 0 : onClick(order);
117
+ };
118
+ const handleAnchorClick = (event) => {
119
+ if (shouldUseNativeLinkNavigation(event)) return;
120
+ if (!onClick) return;
121
+ event.preventDefault();
122
+ onClick(order);
123
+ };
124
+ const handleCancelClick = (event) => {
125
+ event.preventDefault();
126
+ event.stopPropagation();
127
+ onCancel == null ? void 0 : onCancel(order);
128
+ };
129
+ const canCancel = canCancelOpenOrder(order);
130
+ const isPending = isPendingOpenOrder(order);
131
+ const sideLabel = order.side === "buy" ? labels.buy : order.side === "sell" ? labels.sell : void 0;
132
+ const outcomePillLabel = sideLabel ? `${sideLabel} ${order.outcomeLabel}` : order.outcomeLabel;
133
+ const currentPriceLabel = order.currentPriceLabel ? `${labels.nowPrefix} ${order.currentPriceLabel}` : void 0;
134
+ const outcomePill = /* @__PURE__ */ jsx("span", { className: "agg-open-order-outcome inline-flex w-fit shrink-0 items-center justify-center rounded-full bg-agg-secondary-hover px-4 py-[6px]", children: /* @__PURE__ */ jsx("span", { className: "font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground whitespace-nowrap", children: outcomePillLabel }) });
135
+ const sharesLabel = isEventVariant && order.sizeShares != null ? allLabels.trading.shares(order.sizeShares) : void 0;
136
+ const mobileStats = [
137
+ __spreadValues({
138
+ label: resolvedLimitPriceHeader,
139
+ value: (_a = order.limitPriceLabel) != null ? _a : "\u2014"
140
+ }, currentPriceLabel ? { subValue: currentPriceLabel } : {}),
141
+ { label: resolvedFilledHeader, value: order.filledLabel },
142
+ { label: resolvedTotalHeader, value: order.valueLabel },
143
+ { label: resolvedExpirationHeader, value: (_b = order.expirationLabel) != null ? _b : "\u2014" }
144
+ ];
145
+ const isInteractive = Boolean(href || onClick);
146
+ const Wrapper = href ? "a" : "div";
147
+ const wrapperProps = href ? {
148
+ href,
149
+ onClick: handleAnchorClick
150
+ } : onClick ? {
151
+ role: "button",
152
+ tabIndex: 0,
153
+ onClick: handleDivClick,
154
+ onKeyDown: (event) => {
155
+ if (event.target !== event.currentTarget) return;
156
+ if (event.key !== "Enter" && event.key !== " ") return;
157
+ event.preventDefault();
158
+ handleDivClick();
159
+ }
160
+ } : {};
161
+ return /* @__PURE__ */ jsx(
162
+ Wrapper,
163
+ __spreadProps(__spreadValues({
164
+ "aria-label": order.title,
165
+ className: cn(
166
+ "agg-open-order-row relative block focus-visible:outline-none",
167
+ isInteractive && "cursor-pointer",
168
+ isInteractive && "before:absolute before:-top-2 before:-left-2 before:-bottom-2 before:-right-2 before:z-0",
169
+ isInteractive && "before:rounded-agg-xl before:bg-agg-secondary-hover before:opacity-0 before:transition-all before:duration-300",
170
+ isInteractive && "hover:before:opacity-100 focus-visible:before:opacity-100"
171
+ )
172
+ }, wrapperProps), {
173
+ children: /* @__PURE__ */ jsxs("div", { className: "agg-open-order-row-content relative z-10 flex w-full flex-col gap-3 rounded-agg-xl px-3 py-2.5 text-left lg:flex-row lg:items-center lg:gap-6 lg:px-0 lg:py-0", children: [
174
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3 lg:gap-4", children: [
175
+ !isEventVariant ? /* @__PURE__ */ jsx("div", { className: "agg-open-order-image flex h-10 w-10 shrink-0 items-center justify-center lg:h-15 lg:w-15", children: /* @__PURE__ */ jsx(
176
+ RemoteImage,
177
+ {
178
+ src: optimizedImageUrl(order.thumbnailSrc, 60),
179
+ retinaSrc: retinaImageUrl(order.thumbnailSrc, 60),
180
+ alt: "",
181
+ className: "h-full w-full rounded-agg-sm object-cover"
182
+ }
183
+ ) }) : null,
184
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-2", children: [
185
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
186
+ /* @__PURE__ */ jsx("p", { className: "agg-open-order-market min-w-0 flex-1 overflow-hidden font-agg-sans text-agg-sm leading-agg-5 font-agg-bold text-agg-foreground [display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical] lg:text-agg-base lg:leading-agg-6 lg:whitespace-nowrap lg:text-ellipsis lg:[-webkit-line-clamp:1] lg:[display:block]", children: order.title }),
187
+ isEventVariant ? /* @__PURE__ */ jsx("span", { className: "lg:hidden", children: outcomePill }) : null
188
+ ] }),
189
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "hidden lg:inline-flex", children: outcomePill }),
191
+ sharesLabel ? /* @__PURE__ */ jsxs("span", { className: "agg-open-order-shares flex min-w-0 items-center gap-1", children: [
192
+ /* @__PURE__ */ jsx(VenueLogo, { venue: order.venue, size: "small", className: "size-4 shrink-0" }),
193
+ /* @__PURE__ */ jsx("span", { className: "truncate whitespace-nowrap font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground", children: sharesLabel })
194
+ ] }) : null
195
+ ] })
196
+ ] })
197
+ ] }),
198
+ /* @__PURE__ */ jsxs(
199
+ "div",
200
+ {
201
+ className: cn(
202
+ // Wraps in both variants: the values are `whitespace-nowrap`, so a
203
+ // long expiration ("Good 'til canceled") beside a wide fill count
204
+ // overflows the card — and takes the page's horizontal scroll with
205
+ // it — on a narrow phone if the row is pinned to one line.
206
+ "flex w-full flex-wrap items-center lg:hidden",
207
+ isEventVariant ? "justify-between gap-x-3 gap-y-2" : "gap-x-4 gap-y-2"
208
+ ),
209
+ children: [
210
+ !isEventVariant ? /* @__PURE__ */ jsx(Fragment, { children: outcomePill }) : null,
211
+ mobileStats.map(({ label, value, subValue }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
212
+ /* @__PURE__ */ jsxs(
213
+ "div",
214
+ {
215
+ className: cn(
216
+ "flex whitespace-nowrap",
217
+ isEventVariant ? "flex-col gap-1.5" : "items-baseline gap-1.5"
218
+ ),
219
+ children: [
220
+ /* @__PURE__ */ jsx(
221
+ "span",
222
+ {
223
+ className: cn(
224
+ "font-agg-sans text-agg-foreground",
225
+ isEventVariant ? "text-agg-sm leading-agg-5 font-agg-bold" : "text-agg-lg leading-agg-7 font-agg-normal"
226
+ ),
227
+ children: value
228
+ }
229
+ ),
230
+ /* @__PURE__ */ jsx("span", { className: "font-agg-sans text-[10px] leading-[14px] font-agg-bold uppercase text-agg-muted-foreground", children: label })
231
+ ]
232
+ }
233
+ ),
234
+ subValue ? /* @__PURE__ */ jsx("span", { className: "agg-open-order-current-price font-agg-sans text-agg-sm leading-agg-5 font-agg-normal whitespace-nowrap text-agg-foreground", children: subValue }) : null
235
+ ] }, label))
236
+ ]
237
+ }
238
+ ),
239
+ /* @__PURE__ */ jsxs("div", { className: "agg-open-order-limit-price hidden w-[120px] shrink-0 flex-col justify-center gap-0.5 lg:flex", children: [
240
+ /* @__PURE__ */ jsx("p", { className: "agg-type-body-strong text-agg-foreground", children: (_c = order.limitPriceLabel) != null ? _c : "\u2014" }),
241
+ currentPriceLabel ? /* @__PURE__ */ jsx("p", { className: "agg-open-order-current-price font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground", children: currentPriceLabel }) : null
242
+ ] }),
243
+ /* @__PURE__ */ jsx("p", { className: "agg-open-order-filled hidden w-[120px] shrink-0 agg-type-body-strong text-agg-foreground lg:block", children: order.filledLabel }),
244
+ /* @__PURE__ */ jsx("p", { className: "agg-open-order-value hidden w-[120px] shrink-0 agg-type-body-strong text-agg-foreground lg:block", children: order.valueLabel }),
245
+ /* @__PURE__ */ jsx("p", { className: "agg-open-order-expiration hidden w-[140px] shrink-0 agg-type-label text-agg-foreground lg:block", children: (_d = order.expirationLabel) != null ? _d : "\u2014" }),
246
+ /* @__PURE__ */ jsx(
247
+ "div",
248
+ {
249
+ className: cn(
250
+ "shrink-0 justify-end",
251
+ canCancel || isPending ? "flex w-full lg:w-[80px]" : "hidden lg:flex lg:w-[80px]"
252
+ ),
253
+ children: canCancel ? /* @__PURE__ */ jsx(
254
+ Button,
255
+ {
256
+ variant: "secondary",
257
+ size: "small",
258
+ isLoading: isCancelling,
259
+ disabled: isCancelling,
260
+ onClick: handleCancelClick,
261
+ "aria-label": resolvedCancelAriaLabel,
262
+ className: "w-full lg:w-auto !text-agg-error font-agg-bold",
263
+ children: resolvedCancelLabel
264
+ }
265
+ ) : isPending ? /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-center gap-2 agg-type-label text-agg-foreground", children: [
266
+ /* @__PURE__ */ jsx(LoadingIcon, { size: "small", ariaLabel: labels.pending, className: "text-agg-primary" }),
267
+ /* @__PURE__ */ jsx("span", { children: labels.pending })
268
+ ] }) : null
269
+ }
270
+ )
271
+ ] })
272
+ })
273
+ );
274
+ };
275
+ OpenOrderRow.displayName = "OpenOrderRow";
276
+
277
+ // src/shared/use-open-order-cancellation.ts
278
+ import { useCancelManagedOrder, useLabels as useLabels2 } from "@agg-build/hooks";
279
+ import { useCallback, useState } from "react";
280
+ var useOpenOrderCancellation = ({
281
+ onCancelOrder
282
+ } = {}) => {
283
+ const cancelOrderMutation = useCancelManagedOrder();
284
+ const toastContext = useOptionalToast();
285
+ const labels = useLabels2();
286
+ const [cancellingOrderIds, setCancellingOrderIds] = useState({});
287
+ const cancelOrder = useCallback(
288
+ (order) => __async(null, null, function* () {
289
+ if (onCancelOrder) {
290
+ onCancelOrder(order);
291
+ return;
292
+ }
293
+ setCancellingOrderIds((prev) => __spreadProps(__spreadValues({}, prev), { [order.id]: true }));
294
+ try {
295
+ const cancellationResult = yield cancelOrderMutation.mutateAsync(order.id);
296
+ const isCancellationPending = cancellationResult.status === "cancel_pending";
297
+ toastContext == null ? void 0 : toastContext.toast(
298
+ isCancellationPending ? labels.notifications.order.cancelPendingMessage : labels.notifications.order.cancelledMessage,
299
+ {
300
+ title: isCancellationPending ? labels.notifications.order.cancelPendingTitle : labels.notifications.order.cancelledTitle,
301
+ tone: "success"
302
+ }
303
+ );
304
+ } catch (error) {
305
+ const errorReason = error instanceof Error ? error.message : void 0;
306
+ toastContext == null ? void 0 : toastContext.toast(labels.notifications.order.cancelFailedMessage(errorReason), {
307
+ title: labels.notifications.order.cancelFailedTitle,
308
+ tone: "error"
309
+ });
310
+ } finally {
311
+ setCancellingOrderIds((prev) => {
312
+ var _a;
313
+ const _b = prev, { [_a = order.id]: _removed } = _b, rest = __objRest(_b, [__restKey(_a)]);
314
+ return rest;
315
+ });
316
+ }
317
+ }),
318
+ [cancelOrderMutation, labels.notifications.order, onCancelOrder, toastContext]
319
+ );
320
+ return { cancellingOrderIds, cancelOrder };
321
+ };
322
+
323
+ // src/pages/event-market/use-event-open-orders.ts
324
+ import { useExecutionOrdersForMarkets, useLabels as useLabels3, useVenueMarketMidpoints } from "@agg-build/hooks";
325
+ import { useMemo } from "react";
326
+
327
+ // src/shared/open-orders.ts
328
+ import dayjs from "dayjs";
329
+ var MICRO_UNITS_SCALE = 1e6;
330
+ var twoDecimalNumberFormatter = new Intl.NumberFormat("en-US", {
331
+ minimumFractionDigits: 2,
332
+ maximumFractionDigits: 2
333
+ });
334
+ var twoDecimalUsdFormatter = new Intl.NumberFormat("en-US", {
335
+ style: "currency",
336
+ currency: "USD",
337
+ minimumFractionDigits: 2,
338
+ maximumFractionDigits: 2
339
+ });
340
+ var limitPriceCentsFormatter = new Intl.NumberFormat("en-US", {
341
+ maximumFractionDigits: 1
342
+ });
343
+ var parseRawMicroValue = (value) => {
344
+ if (!value) return null;
345
+ if (value.startsWith("0x") || value.startsWith("0X")) {
346
+ try {
347
+ return Number(BigInt(value)) / MICRO_UNITS_SCALE;
348
+ } catch (e) {
349
+ return null;
350
+ }
351
+ }
352
+ const parsed = Number(value);
353
+ if (!Number.isFinite(parsed)) return null;
354
+ return value.includes(".") ? parsed : parsed / MICRO_UNITS_SCALE;
355
+ };
356
+ var formatScaledNumberTwoDecimals = (value) => {
357
+ const parsed = parseRawMicroValue(value);
358
+ if (parsed == null) return "0.00";
359
+ return twoDecimalNumberFormatter.format(parsed);
360
+ };
361
+ var formatFilledUsdTwoDecimals = (filledAmountRaw) => {
362
+ var _a;
363
+ return twoDecimalUsdFormatter.format((_a = parseRawMicroValue(filledAmountRaw)) != null ? _a : 0);
364
+ };
365
+ var formatPriceCentsLabel = (value) => `${limitPriceCentsFormatter.format(value * 100)}\xA2`;
366
+ var formatLimitPriceLabel = (value) => {
367
+ const parsed = parseRawMicroValue(value);
368
+ if (parsed == null) return void 0;
369
+ return formatPriceCentsLabel(parsed);
370
+ };
371
+ var formatOpenOrderExpirationLabel = ({
372
+ timeInForce,
373
+ expiresAt,
374
+ goodTilCanceledLabel,
375
+ expiredLabel
376
+ }) => {
377
+ if (timeInForce === "GTC") return goodTilCanceledLabel;
378
+ if (!expiresAt) return void 0;
379
+ const expiration = dayjs(expiresAt);
380
+ if (!expiration.isValid()) return void 0;
381
+ const now = dayjs();
382
+ const remainingMinutes = expiration.diff(now, "minute", true);
383
+ if (remainingMinutes <= 0) return expiredLabel;
384
+ if (remainingMinutes < 60) return `${Math.ceil(remainingMinutes)}m`;
385
+ const remainingHours = expiration.diff(now, "hour", true);
386
+ if (remainingHours < 24) return `${Math.ceil(remainingHours)}h`;
387
+ return `${Math.ceil(expiration.diff(now, "day", true))}d`;
388
+ };
389
+ var OPEN_ORDER_STATUSES = /* @__PURE__ */ new Set([
390
+ "pending",
391
+ "signing",
392
+ "pending_bridge",
393
+ "submitting",
394
+ "submitted",
395
+ "open",
396
+ "partially_filled_open",
397
+ "cancel_pending"
398
+ ]);
399
+ var OPEN_ORDER_QUERY_STATUSES = [
400
+ "pending",
401
+ "signing",
402
+ "pending_bridge",
403
+ "submitting",
404
+ "submitted",
405
+ "open",
406
+ "partially_filled_open",
407
+ "cancel_pending"
408
+ ];
409
+ var isOpenOrderStatus = (status) => OPEN_ORDER_STATUSES.has(status.toLowerCase());
410
+ var isExecutionLimitOrder = (order) => order.orderType === "limit" || order.orderType == null && order.limitSizeRaw != null;
411
+ var selectOpenLimitOrders = (orderLists, options = {}) => {
412
+ const { venueEventId, venueMarketIds } = options;
413
+ const venueMarketIdSet = venueMarketIds ? new Set(venueMarketIds) : void 0;
414
+ const ordersById = /* @__PURE__ */ new Map();
415
+ for (const orders of orderLists) {
416
+ for (const order of orders) {
417
+ ordersById.set(order.id, order);
418
+ }
419
+ }
420
+ return Array.from(ordersById.values()).filter((order) => isOpenOrderStatus(order.status) && isExecutionLimitOrder(order)).filter((order) => {
421
+ var _a;
422
+ return !venueEventId || ((_a = order.venueMarket) == null ? void 0 : _a.venueEventId) === venueEventId;
423
+ }).filter((order) => {
424
+ var _a;
425
+ if (!venueMarketIdSet) return true;
426
+ const venueMarketId = (_a = order.venueMarket) == null ? void 0 : _a.id;
427
+ return !!venueMarketId && venueMarketIdSet.has(venueMarketId);
428
+ }).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
429
+ };
430
+ var normalizeOutcomeMatchLabel = (value) => typeof value === "string" ? value.trim().toLowerCase() : "";
431
+ var buildOpenOrderCurrentPriceLabels = (orders, midpointRows) => {
432
+ var _a, _b, _c, _d;
433
+ const midpointRowsByVenueMarketId = new Map(midpointRows.map((row) => [row.venueMarketId, row]));
434
+ const labelsByOrderId = /* @__PURE__ */ new Map();
435
+ for (const order of orders) {
436
+ const venueMarketId = (_a = order.venueMarket) == null ? void 0 : _a.id;
437
+ if (!venueMarketId) continue;
438
+ const midpointRow = midpointRowsByVenueMarketId.get(venueMarketId);
439
+ if (!midpointRow) continue;
440
+ const orderOutcomeLabels = [
441
+ normalizeOutcomeMatchLabel((_b = order.venueMarketOutcome) == null ? void 0 : _b.label),
442
+ normalizeOutcomeMatchLabel((_c = order.venueMarketOutcome) == null ? void 0 : _c.title)
443
+ ].filter(Boolean);
444
+ if (orderOutcomeLabels.length === 0) continue;
445
+ const outcomeMidpoint = (_d = midpointRow.outcomes) == null ? void 0 : _d.find(
446
+ (outcome) => orderOutcomeLabels.includes(normalizeOutcomeMatchLabel(outcome.label))
447
+ );
448
+ if ((outcomeMidpoint == null ? void 0 : outcomeMidpoint.midpoint) == null) continue;
449
+ labelsByOrderId.set(order.id, formatPriceCentsLabel(outcomeMidpoint.midpoint));
450
+ }
451
+ return labelsByOrderId;
452
+ };
453
+ var OPEN_ORDER_FALLBACK_THUMBNAIL_SRC = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"><rect width="100%" height="100%" fill="%23f4f4f7"/></svg>';
454
+ var mapExecutionOrderToOpenOrder = (order, {
455
+ goodTilCanceledLabel,
456
+ expiredLabel,
457
+ currentPriceLabel,
458
+ fallbackThumbnailSrc = OPEN_ORDER_FALLBACK_THUMBNAIL_SRC
459
+ }) => {
460
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
461
+ const isLimitOrder = isExecutionLimitOrder(order);
462
+ const filledRaw = isLimitOrder ? order.filledSizeRaw : order.filledAmountRaw;
463
+ const totalRaw = isLimitOrder ? order.limitSizeRaw : order.amountRaw;
464
+ const totalCostRaw = isLimitOrder ? (_a = order.reservedCostRaw) != null ? _a : order.amountRaw : order.amountRaw;
465
+ const limitPriceLabel = formatLimitPriceLabel(order.limitPriceRaw);
466
+ const expirationLabel = formatOpenOrderExpirationLabel({
467
+ timeInForce: order.timeInForce,
468
+ expiresAt: order.expiresAt,
469
+ goodTilCanceledLabel,
470
+ expiredLabel
471
+ });
472
+ const sizeShares = parseRawMicroValue(totalRaw);
473
+ return __spreadProps(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadProps(__spreadValues({
474
+ id: order.id,
475
+ eventId: (_c = (_b = order.venueMarket) == null ? void 0 : _b.venueEventId) != null ? _c : void 0,
476
+ marketId: (_e = (_d = order.venueMarket) == null ? void 0 : _d.id) != null ? _e : void 0,
477
+ thumbnailSrc: (_g = (_f = order.venueMarket) == null ? void 0 : _f.image) != null ? _g : fallbackThumbnailSrc,
478
+ title: ((_h = order.venueMarket) == null ? void 0 : _h.question) || "Market",
479
+ outcomeLabel: ((_i = order.venueMarketOutcome) == null ? void 0 : _i.title) || ((_j = order.venueMarketOutcome) == null ? void 0 : _j.label) || "Outcome"
480
+ }, order.side === "sell" || order.side === "buy" ? { side: order.side } : {}), {
481
+ venue: order.venue
482
+ }), limitPriceLabel ? { limitPriceLabel } : {}), currentPriceLabel ? { currentPriceLabel } : {}), {
483
+ filledLabel: `${formatScaledNumberTwoDecimals(filledRaw != null ? filledRaw : "0")}/${formatScaledNumberTwoDecimals(totalRaw)}`,
484
+ valueLabel: formatFilledUsdTwoDecimals(totalCostRaw)
485
+ }), expirationLabel ? { expirationLabel } : {}), sizeShares != null ? { sizeShares } : {}), {
486
+ status: order.status,
487
+ orderType: isLimitOrder ? "limit" : "market",
488
+ dagRunId: (_k = order.dagRunId) != null ? _k : null
489
+ });
490
+ };
491
+
492
+ // src/pages/event-market/use-event-open-orders.ts
493
+ var useEventOpenOrders = ({
494
+ venueMarketIds: pageVenueMarketIds,
495
+ enabled = true,
496
+ executionMode
497
+ }) => {
498
+ const labels = useLabels3();
499
+ const isEnabled = enabled && pageVenueMarketIds.length > 0;
500
+ const ordersQuery = useExecutionOrdersForMarkets(__spreadProps(__spreadValues({
501
+ venueMarketIds: pageVenueMarketIds,
502
+ orderType: "limit"
503
+ }, executionMode === "paper" ? { mode: "paper" } : {}), {
504
+ enabled: isEnabled
505
+ }));
506
+ const pageVenueMarketIdKey = pageVenueMarketIds.join("\0");
507
+ const orderRows = useMemo(
508
+ () => selectOpenLimitOrders([ordersQuery.orders], {
509
+ // Already scoped by the API; kept so an API deploy that predates the
510
+ // `venueMarketIds` filter (and returns everything) can't leak other
511
+ // events' orders onto this page.
512
+ venueMarketIds: pageVenueMarketIdKey ? pageVenueMarketIdKey.split("\0") : []
513
+ }),
514
+ [ordersQuery.orders, pageVenueMarketIdKey]
515
+ );
516
+ const venueMarketIds = useMemo(
517
+ () => orderRows.map((order) => {
518
+ var _a;
519
+ return (_a = order.venueMarket) == null ? void 0 : _a.id;
520
+ }).filter((venueMarketId) => Boolean(venueMarketId)),
521
+ [orderRows]
522
+ );
523
+ const midpointsQuery = useVenueMarketMidpoints({
524
+ venueMarketIds,
525
+ enabled: isEnabled && venueMarketIds.length > 0
526
+ });
527
+ const midpointRows = midpointsQuery.midpointRows;
528
+ const currentPriceLabels = useMemo(
529
+ () => buildOpenOrderCurrentPriceLabels(orderRows, midpointRows),
530
+ [midpointRows, orderRows]
531
+ );
532
+ const orders = useMemo(
533
+ () => orderRows.map(
534
+ (order) => mapExecutionOrderToOpenOrder(order, __spreadValues({
535
+ goodTilCanceledLabel: labels.userProfile.openOrders.goodTilCanceled,
536
+ expiredLabel: labels.userProfile.openOrders.expired
537
+ }, currentPriceLabels.has(order.id) ? { currentPriceLabel: currentPriceLabels.get(order.id) } : {}))
538
+ ),
539
+ [currentPriceLabels, labels, orderRows]
540
+ );
541
+ return { orders, isLoading: ordersQuery.isLoading, hasError: !!ordersQuery.error };
542
+ };
543
+
544
+ // src/pages/event-market/event-open-orders.tsx
545
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
546
+ var EventOpenOrdersCard = ({
547
+ orders,
548
+ hasError = false,
549
+ onCancelOrder,
550
+ cancellingOrderIds,
551
+ className
552
+ }) => {
553
+ const allLabels = useLabels4();
554
+ const labels = allLabels.eventMarketPage.openOrders;
555
+ const errorLabels = allLabels.userProfile.openOrders;
556
+ if (orders.length === 0 && hasError) {
557
+ return /* @__PURE__ */ jsxs2(
558
+ "section",
559
+ {
560
+ className: cn(
561
+ "agg-event-open-orders agg-event-open-orders-error flex w-full flex-col gap-1 rounded-agg-xl border border-agg-separator bg-agg-secondary p-4 lg:p-5",
562
+ className
563
+ ),
564
+ "aria-label": labels.title,
565
+ role: "status",
566
+ children: [
567
+ /* @__PURE__ */ jsx2("p", { className: "font-agg-sans text-agg-sm leading-agg-5 font-agg-bold text-agg-foreground", children: errorLabels.errorTitle }),
568
+ /* @__PURE__ */ jsx2("p", { className: "font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-muted-foreground", children: errorLabels.errorDescription })
569
+ ]
570
+ }
571
+ );
572
+ }
573
+ if (orders.length === 0) return null;
574
+ const columnHeaderClassName = "font-agg-sans text-agg-xs leading-agg-4 font-agg-bold uppercase text-agg-muted-foreground";
575
+ return /* @__PURE__ */ jsxs2(
576
+ "section",
577
+ {
578
+ className: cn(
579
+ "agg-event-open-orders flex w-full flex-col gap-4 rounded-agg-xl border border-agg-separator bg-agg-secondary p-4 lg:gap-4 lg:p-5",
580
+ className
581
+ ),
582
+ "aria-label": labels.title,
583
+ children: [
584
+ /* @__PURE__ */ jsxs2("div", { className: "flex w-full items-center gap-6", children: [
585
+ /* @__PURE__ */ jsx2("p", { className: cn("agg-event-open-orders-title min-w-0 flex-1", columnHeaderClassName), children: labels.title }),
586
+ /* @__PURE__ */ jsx2("p", { className: cn("hidden w-[120px] shrink-0 lg:block", columnHeaderClassName), children: labels.limitPriceHeader }),
587
+ /* @__PURE__ */ jsx2("p", { className: cn("hidden w-[120px] shrink-0 lg:block", columnHeaderClassName), children: labels.filledHeader }),
588
+ /* @__PURE__ */ jsx2("p", { className: cn("hidden w-[120px] shrink-0 lg:block", columnHeaderClassName), children: labels.totalHeader }),
589
+ /* @__PURE__ */ jsx2("p", { className: cn("hidden w-[140px] shrink-0 lg:block", columnHeaderClassName), children: labels.expirationHeader }),
590
+ /* @__PURE__ */ jsx2("span", { className: "hidden w-[80px] shrink-0 lg:block", "aria-hidden": true })
591
+ ] }),
592
+ /* @__PURE__ */ jsx2("div", { className: "flex w-full flex-col gap-4", children: orders.map((order) => {
593
+ var _a;
594
+ return /* @__PURE__ */ jsx2(
595
+ OpenOrderRow,
596
+ __spreadProps(__spreadValues({
597
+ order,
598
+ variant: "event"
599
+ }, onCancelOrder ? { onCancel: onCancelOrder } : {}), {
600
+ isCancelling: (_a = cancellingOrderIds == null ? void 0 : cancellingOrderIds[order.id]) != null ? _a : false,
601
+ limitPriceHeader: labels.limitShort,
602
+ filledHeader: labels.filledShort,
603
+ totalHeader: labels.totalShort,
604
+ expirationHeader: labels.expirationShort
605
+ }),
606
+ order.id
607
+ );
608
+ }) })
609
+ ]
610
+ }
611
+ );
612
+ };
613
+ EventOpenOrdersCard.displayName = "EventOpenOrdersCard";
614
+ var EventOpenOrders = ({
615
+ venueMarketIds,
616
+ executionMode,
617
+ className
618
+ }) => {
619
+ const { isAuthenticated } = useAggAuthState();
620
+ const {
621
+ features: { showLimitOrders }
622
+ } = useSdkUiConfig();
623
+ const isPaperMode = executionMode === "paper";
624
+ const isEnabled = isAuthenticated && showLimitOrders && !isPaperMode;
625
+ const { orders, hasError } = useEventOpenOrders(__spreadValues({
626
+ venueMarketIds,
627
+ enabled: isEnabled
628
+ }, executionMode ? { executionMode } : {}));
629
+ const { cancellingOrderIds, cancelOrder } = useOpenOrderCancellation();
630
+ const handleCancelOrder = useCallback2(
631
+ (order) => {
632
+ void cancelOrder(order);
633
+ },
634
+ [cancelOrder]
635
+ );
636
+ if (!isEnabled) return null;
637
+ return /* @__PURE__ */ jsx2(
638
+ EventOpenOrdersCard,
639
+ __spreadValues({
640
+ orders,
641
+ hasError,
642
+ onCancelOrder: handleCancelOrder,
643
+ cancellingOrderIds
644
+ }, className ? { className } : {})
645
+ );
646
+ };
647
+ EventOpenOrders.displayName = "EventOpenOrders";
648
+
649
+ // src/pages/event-market/event-market.utils.ts
650
+ var EVENT_MARKET_PAGE_STICKY_HEADER_OFFSET_PX = 48;
651
+ var EVENT_MARKET_PAGE_STICKY_SPACING_PX = 32;
652
+ var EVENT_MARKET_PAGE_STICKY_TOP_PX = EVENT_MARKET_PAGE_STICKY_HEADER_OFFSET_PX + EVENT_MARKET_PAGE_STICKY_SPACING_PX;
653
+ var EVENT_MARKET_PAGE_STICKY_TOP_CSS_VAR = "--agg-event-market-sidebar-top";
654
+ var EVENT_MARKET_PAGE_STICKY_SPACING_CSS_VAR = "--agg-event-market-sidebar-spacing";
655
+ var toCssLength = (value, fallback) => {
656
+ if (typeof value === "number") {
657
+ return `${value}px`;
658
+ }
659
+ return value != null ? value : `${fallback}px`;
660
+ };
661
+ var deriveSpacingFromTop = (top) => {
662
+ if (typeof top !== "number") {
663
+ return void 0;
664
+ }
665
+ return Math.max(top - EVENT_MARKET_PAGE_STICKY_HEADER_OFFSET_PX, 0);
666
+ };
667
+ var resolveEventMarketPageStickyState = ({
668
+ stickyOrderPanel
669
+ }) => {
670
+ var _a, _b;
671
+ const isEnabled = (_a = stickyOrderPanel == null ? void 0 : stickyOrderPanel.enabled) != null ? _a : Boolean(stickyOrderPanel);
672
+ if (!isEnabled) {
673
+ return {
674
+ contentClassName: cn(),
675
+ sidebarClassName: cn("pt-4 sm:pt-6 md:pt-8 pb-10"),
676
+ placeOrder: cn("mb-10"),
677
+ mainClassName: cn("pt-4 sm:pt-6 md:pt-8"),
678
+ style: {}
679
+ };
680
+ }
681
+ return {
682
+ contentClassName: cn("lg:items-stretch!"),
683
+ sidebarClassName: cn(
684
+ "pt-4 sm:pt-6 md:pt-8 pb-10",
685
+ "lg:self-start lg:sticky lg:top-[var(--agg-event-market-sidebar-top)] lg:max-h-[calc(100vh-var(--agg-event-market-sidebar-top))] lg:overflow-y-auto lg:overscroll-contain",
686
+ stickyOrderPanel == null ? void 0 : stickyOrderPanel.className
687
+ ),
688
+ placeOrder: cn("mb-10"),
689
+ mainClassName: cn("pt-4 sm:pt-6 md:pt-8"),
690
+ style: {
691
+ [EVENT_MARKET_PAGE_STICKY_TOP_CSS_VAR]: toCssLength(
692
+ stickyOrderPanel == null ? void 0 : stickyOrderPanel.top,
693
+ EVENT_MARKET_PAGE_STICKY_TOP_PX
694
+ ),
695
+ [EVENT_MARKET_PAGE_STICKY_SPACING_CSS_VAR]: toCssLength(
696
+ (_b = stickyOrderPanel == null ? void 0 : stickyOrderPanel.spacing) != null ? _b : deriveSpacingFromTop(stickyOrderPanel == null ? void 0 : stickyOrderPanel.top),
697
+ EVENT_MARKET_PAGE_STICKY_SPACING_PX
698
+ )
699
+ }
700
+ };
701
+ };
702
+
703
+ // src/pages/event-market/event-market.shared.tsx
704
+ import { useLabels as useLabels5 } from "@agg-build/hooks";
705
+ import * as Dialog from "@radix-ui/react-dialog";
706
+ import { useEffect, useState as useState2 } from "react";
707
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
708
+ var MOBILE_EVENT_MARKET_MEDIA_QUERY = "(max-width: 1023px)";
709
+ var SPORTS_EVENT_MARKET_MEDIA_QUERY = "(max-width: 1279px)";
710
+ var getIsMobileEventMarketViewport = (mediaQuery = MOBILE_EVENT_MARKET_MEDIA_QUERY) => {
711
+ if (typeof window === "undefined") return false;
712
+ if (typeof window.matchMedia !== "function") return false;
713
+ return window.matchMedia(mediaQuery).matches;
714
+ };
715
+ var useIsMobileEventMarketViewport = (mediaQuery = MOBILE_EVENT_MARKET_MEDIA_QUERY) => {
716
+ const [isMobileViewport, setIsMobileViewport] = useState2(
717
+ () => getIsMobileEventMarketViewport(mediaQuery)
718
+ );
719
+ useEffect(() => {
720
+ if (typeof window === "undefined") return;
721
+ if (typeof window.matchMedia !== "function") return;
722
+ const mediaQueryList = window.matchMedia(mediaQuery);
723
+ const handleChange = () => {
724
+ setIsMobileViewport(mediaQueryList.matches);
725
+ };
726
+ handleChange();
727
+ mediaQueryList.addEventListener("change", handleChange);
728
+ return () => {
729
+ mediaQueryList.removeEventListener("change", handleChange);
730
+ };
731
+ }, [mediaQuery]);
732
+ return isMobileViewport;
733
+ };
734
+ var resolveDesktopTradePlaceOrderClassNames = (classNames) => {
735
+ const resolvedClassNames = {
736
+ body: classNames == null ? void 0 : classNames.tradeBody,
737
+ content: classNames == null ? void 0 : classNames.tradeContent,
738
+ footer: classNames == null ? void 0 : classNames.tradeFooter,
739
+ header: classNames == null ? void 0 : classNames.tradeHeader
740
+ };
741
+ if (!Object.values(resolvedClassNames).some(Boolean)) {
742
+ return void 0;
743
+ }
744
+ return resolvedClassNames;
745
+ };
746
+ var resolveMobileTradePlaceOrderClassNames = (classNames) => {
747
+ return {
748
+ root: "rounded-t-agg-2xl rounded-b-none md:rounded-agg-2xl md:rounded-b-agg-2xl",
749
+ body: cn("flex h-full min-h-0 flex-col", classNames == null ? void 0 : classNames.tradeBody, classNames == null ? void 0 : classNames.mobileTradeBody),
750
+ content: cn(
751
+ "min-h-0 flex-1 overflow-y-auto overflow-x-hidden overscroll-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
752
+ classNames == null ? void 0 : classNames.tradeContent,
753
+ classNames == null ? void 0 : classNames.mobileTradeContent
754
+ ),
755
+ footer: cn(classNames == null ? void 0 : classNames.tradeFooter, classNames == null ? void 0 : classNames.mobileTradeFooter),
756
+ header: cn(
757
+ "sticky top-0 z-10 bg-agg-secondary",
758
+ classNames == null ? void 0 : classNames.tradeHeader,
759
+ classNames == null ? void 0 : classNames.mobileTradeHeader
760
+ )
761
+ };
762
+ };
763
+ var EventMarketPageMobileTrade = ({
764
+ classNames,
765
+ eventTradingState,
766
+ executionMode,
767
+ showPlaceOrder = true,
768
+ isOpen,
769
+ onOpenChange,
770
+ midpointsResult,
771
+ onBeforePrimaryAction,
772
+ sharedKyc
773
+ }) => {
774
+ const labels = useLabels5();
775
+ if (!showPlaceOrder) return null;
776
+ const handleOpenChange = (nextOpen) => {
777
+ onOpenChange(nextOpen);
778
+ };
779
+ const handleClose = () => {
780
+ onOpenChange(false);
781
+ };
782
+ return /* @__PURE__ */ jsx3(Fragment2, { children: /* @__PURE__ */ jsx3(Modal, { open: isOpen, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs3(
783
+ Modal.Container,
784
+ {
785
+ classNames: {
786
+ content: "items-end p-0 sm:items-center sm:p-4",
787
+ container: cn(
788
+ "agg-mobile-trade-modal",
789
+ "w-full border-0 bg-transparent shadow-none",
790
+ classNames == null ? void 0 : classNames.mobileTradeModal
791
+ )
792
+ },
793
+ children: [
794
+ /* @__PURE__ */ jsx3(Dialog.Title, { className: "sr-only", children: labels.trading.confirmOrder }),
795
+ /* @__PURE__ */ jsx3(Dialog.Description, { className: "sr-only", children: labels.trading.disclaimer }),
796
+ /* @__PURE__ */ jsx3("div", { className: "agg-mobile-trade-handle relative flex w-full flex-col items-center sm:hidden", children: /* @__PURE__ */ jsx3(
797
+ "button",
798
+ {
799
+ type: "button",
800
+ className: "absolute right-3 top-4 z-100 flex cursor-pointer items-center justify-center rounded-full p-1 text-agg-muted-foreground hover:text-agg-foreground",
801
+ "aria-label": labels.common.close,
802
+ onClick: handleClose,
803
+ children: /* @__PURE__ */ jsx3(CloseIcon, { className: "h-5 w-5" })
804
+ }
805
+ ) }),
806
+ /* @__PURE__ */ jsx3(
807
+ PlaceOrder,
808
+ {
809
+ eventTradingState,
810
+ executionMode,
811
+ isQuotePanelActive: isOpen,
812
+ midpointsResult,
813
+ onBeforePrimaryAction,
814
+ sharedKyc,
815
+ className: cn(
816
+ "agg-mobile-trade-panel w-full overflow-hidden rounded-t-agg-2xl sm:rounded-agg-xl",
817
+ classNames == null ? void 0 : classNames.mobileTrade
818
+ ),
819
+ classNames: resolveMobileTradePlaceOrderClassNames(classNames),
820
+ onClose: handleClose
821
+ }
822
+ )
823
+ ]
824
+ }
825
+ ) }) });
826
+ };
827
+ var EventMarketPageUnavailableState = ({
828
+ ariaLabel: _ariaLabel
829
+ }) => {
830
+ const labels = useLabels5();
831
+ return /* @__PURE__ */ jsx3(
832
+ StateMessage,
833
+ {
834
+ title: labels.eventMarketPage.unavailableTitle,
835
+ description: labels.eventMarketPage.unavailableDescription,
836
+ icon: /* @__PURE__ */ jsx3(Icon, { name: "quotes-warning", className: "h-12 w-12" }),
837
+ classNames: {
838
+ root: "min-h-[calc(100vh-5rem)]!"
839
+ }
840
+ }
841
+ );
842
+ };
843
+ var EventMarketPageNotFoundState = ({
844
+ ariaLabel: _ariaLabel
845
+ }) => {
846
+ const labels = useLabels5();
847
+ return /* @__PURE__ */ jsx3(
848
+ StateMessage,
849
+ {
850
+ title: labels.eventItemDetails.notFoundTitle,
851
+ description: labels.eventItemDetails.notFoundDescription,
852
+ icon: /* @__PURE__ */ jsx3(SearchEmptyIcon, {}),
853
+ classNames: { root: "min-h-[320px] md:min-h-[360px]" }
854
+ }
855
+ );
856
+ };
857
+ var EventMarketPageLoadingState = ({
858
+ classNames,
859
+ stickyOrderPanel
860
+ }) => {
861
+ const stickyOrderPanelState = resolveEventMarketPageStickyState({
862
+ stickyOrderPanel
863
+ });
864
+ return /* @__PURE__ */ jsx3(
865
+ "section",
866
+ {
867
+ className: cn(
868
+ "agg-event-market-page",
869
+ "w-full mx-auto max-w-[1440px] px-6 lg:px-10 pb-10",
870
+ classNames == null ? void 0 : classNames.root
871
+ ),
872
+ children: /* @__PURE__ */ jsxs3(
873
+ "div",
874
+ {
875
+ className: cn(
876
+ "agg-page-content",
877
+ "flex w-full flex-col gap-6 lg:flex-row lg:items-start lg:gap-8",
878
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.contentClassName,
879
+ classNames == null ? void 0 : classNames.content
880
+ ),
881
+ style: stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.style,
882
+ children: [
883
+ /* @__PURE__ */ jsxs3(
884
+ "div",
885
+ {
886
+ className: cn(
887
+ "agg-page-main flex min-w-0 flex-1 flex-col gap-6 mb-10",
888
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.mainClassName,
889
+ classNames == null ? void 0 : classNames.main
890
+ ),
891
+ children: [
892
+ /* @__PURE__ */ jsx3(
893
+ EventListItemDetails,
894
+ {
895
+ isLoading: true,
896
+ classNames: {
897
+ root: cn("agg-event-hero", classNames == null ? void 0 : classNames.hero)
898
+ }
899
+ }
900
+ ),
901
+ /* @__PURE__ */ jsxs3("div", { className: cn("agg-market-list flex flex-col gap-3", classNames == null ? void 0 : classNames.markets), children: [
902
+ /* @__PURE__ */ jsx3(MarketDetails, { isLoading: true, isOpened: true, classNames: { root: "w-full" } }),
903
+ /* @__PURE__ */ jsx3(MarketDetails, { isLoading: true, isOpened: false, classNames: { root: "w-full" } }),
904
+ /* @__PURE__ */ jsx3(MarketDetails, { isLoading: true, isOpened: false, classNames: { root: "w-full" } })
905
+ ] }),
906
+ /* @__PURE__ */ jsx3(
907
+ Skeleton,
908
+ {
909
+ view: skeletonViews.settlement,
910
+ className: cn("agg-settlement-list-item", classNames == null ? void 0 : classNames.settlement)
911
+ }
912
+ )
913
+ ]
914
+ }
915
+ ),
916
+ /* @__PURE__ */ jsx3(
917
+ "aside",
918
+ {
919
+ className: cn(
920
+ "agg-sidebar",
921
+ "hidden w-full shrink-0 lg:block lg:w-[342px] lg:shrink-0",
922
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.sidebarClassName,
923
+ classNames == null ? void 0 : classNames.sidebar
924
+ ),
925
+ children: /* @__PURE__ */ jsx3(
926
+ PlaceOrder,
927
+ {
928
+ isLoading: true,
929
+ className: cn(stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.placeOrder, classNames == null ? void 0 : classNames.trade),
930
+ classNames: resolveDesktopTradePlaceOrderClassNames(classNames)
931
+ }
932
+ )
933
+ }
934
+ )
935
+ ]
936
+ }
937
+ )
938
+ }
939
+ );
940
+ };
941
+
942
+ // src/pages/event-market/sports-event-market-page.tsx
943
+ import {
944
+ resolveEventTradingState as resolveEventTradingState2,
945
+ TradeSide,
946
+ useEventTradingContext as useEventTradingContext3,
947
+ useMidpoints,
948
+ useResolvedExecutionMode,
949
+ useSportsLive
950
+ } from "@agg-build/hooks";
951
+ import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef4, useState as useState6 } from "react";
952
+
953
+ // src/pages/event-market/sports-markets.tsx
954
+ import {
955
+ MarketStatus as MarketStatus2,
956
+ resolveMarketTradingState as resolveMarketTradingState2,
957
+ useEventTradingContext as useEventTradingContext2,
958
+ useLabels as useLabels7,
959
+ useVenueMarkets
960
+ } from "@agg-build/hooks";
961
+ import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState5 } from "react";
962
+
963
+ // src/pages/event-market/sports-event-market.utils.ts
964
+ var SPORTS_MARKET_TYPE_KEYS = [
965
+ "to_advance",
966
+ "moneyline",
967
+ "spread",
968
+ "total",
969
+ "prop",
970
+ "completion",
971
+ "other"
972
+ ];
973
+ var SPORTS_PERIOD_KEYS = [
974
+ "full",
975
+ "1h",
976
+ "2h",
977
+ "q1",
978
+ "q2",
979
+ "q3",
980
+ "q4",
981
+ "ot",
982
+ "first_inning",
983
+ "second_inning",
984
+ "third_inning",
985
+ "first_5_innings",
986
+ "other"
987
+ ];
988
+ var SPORTS_PERIOD_GRAMMAR_PATTERN = /^(?:(set|map|game|period|inning)_(\d{1,2})|first_(\d{1,2})_innings)$/;
989
+ var SPORTS_MARKET_CATEGORY_KEYS = [
990
+ "game_lines",
991
+ "exact_score",
992
+ "corners",
993
+ "goals",
994
+ "assists",
995
+ "shots",
996
+ "other"
997
+ ];
998
+ var SPORTS_MARKET_GROUP_KEYS = [
999
+ "game_lines",
1000
+ "spreads",
1001
+ "totals",
1002
+ "period_lines",
1003
+ "exact_score",
1004
+ "team_props",
1005
+ "player_props",
1006
+ "specials",
1007
+ "completion",
1008
+ "other"
1009
+ ];
1010
+ var SPORTS_PERIOD_KEY_SET = new Set(SPORTS_PERIOD_KEYS);
1011
+ var SPORTS_MARKET_TYPE_KEY_SET = new Set(SPORTS_MARKET_TYPE_KEYS);
1012
+ var SPORTS_MARKET_CATEGORY_KEY_SET = new Set(SPORTS_MARKET_CATEGORY_KEYS);
1013
+ var SPORTS_MARKET_GROUP_KEY_SET = new Set(SPORTS_MARKET_GROUP_KEYS);
1014
+ var SPORTS_LEGACY_PROP_CATEGORY_KEY_SET = /* @__PURE__ */ new Set([
1015
+ "corners",
1016
+ "goals",
1017
+ "assists",
1018
+ "shots"
1019
+ ]);
1020
+ var SPORTS_GAME_LINE_GROUPS = [
1021
+ "game_lines",
1022
+ "spreads",
1023
+ "totals",
1024
+ "team_props",
1025
+ "specials",
1026
+ "completion"
1027
+ ];
1028
+ var SPORTS_GENERIC_STAT = "player_props";
1029
+ var ESPORTS_CATEGORY_TOKENS = /* @__PURE__ */ new Set([
1030
+ "esports",
1031
+ "video games",
1032
+ "video game",
1033
+ "computer games",
1034
+ "computer game",
1035
+ "gaming"
1036
+ ]);
1037
+ var ESPORTS_TITLE_PATTERN = /\b(?:esports?|valorant|counter-strike|cs2|league of legends|lol|dota|rocket league|overwatch|rainbow six|starcraft|call of duty)\b/i;
1038
+ var SERIES_SCOPE_PATTERN = /\b(?:bo[1-9]|best of \d+|map \d+|game \d+)\b/i;
1039
+ var SPORTS_PERIOD_ORDER = [
1040
+ "full",
1041
+ "1h",
1042
+ "2h",
1043
+ "q1",
1044
+ "q2",
1045
+ "q3",
1046
+ "q4",
1047
+ "ot",
1048
+ "first_inning",
1049
+ "second_inning",
1050
+ "third_inning",
1051
+ "other"
1052
+ ];
1053
+ var FIRST_N_INNINGS_PATTERN = /^first_(\d{1,2})_innings$/;
1054
+ var SPORTS_MARKET_TYPE_ORDER = [
1055
+ "to_advance",
1056
+ "moneyline",
1057
+ "spread",
1058
+ "total",
1059
+ "prop",
1060
+ "completion",
1061
+ "other"
1062
+ ];
1063
+ var YES_NO_LABELS = /* @__PURE__ */ new Set(["yes", "no"]);
1064
+ var LINE_MARKET_TYPES = /* @__PURE__ */ new Set(["spread", "total"]);
1065
+ var PLAYER_PROP_COUNT_PATTERN = /\+\s|\bo\/u\b|\bover\/under\b/i;
1066
+ var REG_TIME_TITLE_PATTERN = /^reg(?:ular)?\s*time\s*:/i;
1067
+ var toTrimmedString = (value) => {
1068
+ return typeof value === "string" ? value.trim() : "";
1069
+ };
1070
+ var resolveSportsMarketAggKey = (market) => {
1071
+ const typedMarket = market;
1072
+ return toTrimmedString(typedMarket.aggKey);
1073
+ };
1074
+ var sanitizeFamilyValue = (value) => {
1075
+ return value.toLowerCase().replace(/[-+]?\d+(?:\.\d+)?/g, "").replace(/[¢$]/g, "").replace(/\s+/g, " ").replace(/[|:()[\]{}]/g, "").trim();
1076
+ };
1077
+ var stripLineValueFromQuestion = (question) => {
1078
+ const strippedQuestion = sanitizeFamilyValue(question);
1079
+ return strippedQuestion ? question.replace(/\(\s*[+-]?\d+(?:\.\d+)?\s*\)\s*$/g, "").replace(/\s+[+-]?\d+(?:\.\d+)?\s*$/g, "").replace(/\s+/g, " ").trim() : question.trim();
1080
+ };
1081
+ var SPORTS_PERIOD_FAMILY_ORDER = ["period", "inning", "set", "map", "game"];
1082
+ var getSportsPeriodOrderIndex = (period) => {
1083
+ var _a, _b;
1084
+ const inningsMatch = FIRST_N_INNINGS_PATTERN.exec(period);
1085
+ if (inningsMatch) {
1086
+ return SPORTS_PERIOD_ORDER.indexOf("third_inning") + 1 + Number(inningsMatch[1]) / 100;
1087
+ }
1088
+ const periodIndex = SPORTS_PERIOD_ORDER.indexOf(period);
1089
+ if (periodIndex >= 0) {
1090
+ return period === "other" ? Number.MAX_SAFE_INTEGER : periodIndex;
1091
+ }
1092
+ const grammarMatch = SPORTS_PERIOD_GRAMMAR_PATTERN.exec(period);
1093
+ if (grammarMatch) {
1094
+ const familyIndex = grammarMatch[1] ? SPORTS_PERIOD_FAMILY_ORDER.indexOf(
1095
+ grammarMatch[1]
1096
+ ) : SPORTS_PERIOD_FAMILY_ORDER.length;
1097
+ const scopeNumber = Number((_b = (_a = grammarMatch[2]) != null ? _a : grammarMatch[3]) != null ? _b : 0);
1098
+ return SPORTS_PERIOD_ORDER.length + familyIndex * 100 + scopeNumber;
1099
+ }
1100
+ return Number.MAX_SAFE_INTEGER - 1;
1101
+ };
1102
+ var getSportsMarketTypeOrderIndex = (sportsMarketType) => {
1103
+ if (!sportsMarketType) return SPORTS_MARKET_TYPE_ORDER.length;
1104
+ const marketTypeIndex = SPORTS_MARKET_TYPE_ORDER.indexOf(sportsMarketType);
1105
+ return marketTypeIndex >= 0 ? marketTypeIndex : SPORTS_MARKET_TYPE_ORDER.length;
1106
+ };
1107
+ var resolveSportsPeriodFamily = (period) => {
1108
+ if (period === "1h" || period === "2h") return "halves";
1109
+ if (period === "q1" || period === "q2" || period === "q3" || period === "q4") return "quarters";
1110
+ if (/^inning_\d{1,2}$/.test(period)) return "innings";
1111
+ if (/^set_\d{1,2}$/.test(period)) return "sets";
1112
+ if (/^(?:map|game)_\d{1,2}$/.test(period)) return "maps";
1113
+ return period;
1114
+ };
1115
+ var normalizeSportsPeriod = (value) => {
1116
+ const resolvedValue = toTrimmedString(value).toLowerCase();
1117
+ if (!resolvedValue) return "full";
1118
+ if (resolvedValue === "match") return "full";
1119
+ if (SPORTS_PERIOD_KEY_SET.has(resolvedValue)) return resolvedValue;
1120
+ if (SPORTS_PERIOD_GRAMMAR_PATTERN.test(resolvedValue)) return resolvedValue;
1121
+ return "other";
1122
+ };
1123
+ var normalizeSportsMarketType = (value) => {
1124
+ const resolvedValue = toTrimmedString(value).toLowerCase();
1125
+ if (!resolvedValue) return null;
1126
+ return SPORTS_MARKET_TYPE_KEY_SET.has(resolvedValue) ? resolvedValue : "other";
1127
+ };
1128
+ var normalizeSportsMarketCategory = (value) => {
1129
+ const resolvedValue = toTrimmedString(value).toLowerCase();
1130
+ if (!resolvedValue) return null;
1131
+ return SPORTS_MARKET_CATEGORY_KEY_SET.has(resolvedValue) ? resolvedValue : "other";
1132
+ };
1133
+ var normalizeSportsMarketGroup = (value) => {
1134
+ const resolvedValue = toTrimmedString(value).toLowerCase();
1135
+ if (!resolvedValue) return null;
1136
+ return SPORTS_MARKET_GROUP_KEY_SET.has(resolvedValue) ? resolvedValue : "other";
1137
+ };
1138
+ var resolveFallbackSportsMarketCategory = (market) => {
1139
+ const marketSubtype = toTrimmedString(market.marketSubtype).toLowerCase();
1140
+ const question = toTrimmedString(market.question).toLowerCase();
1141
+ if (marketSubtype.includes("exact_score") || marketSubtype.includes("correct_score") || question.includes("exact score") || question.includes("correct score")) {
1142
+ return "exact_score";
1143
+ }
1144
+ if (marketSubtype.includes("corner") || question.includes("corner")) {
1145
+ return "corners";
1146
+ }
1147
+ if (marketSubtype.includes("shot")) return "shots";
1148
+ if (marketSubtype.includes("assist")) return "assists";
1149
+ if (marketSubtype.includes("goal")) return "goals";
1150
+ if (!PLAYER_PROP_COUNT_PATTERN.test(question) || !question.includes(":") || question.includes(" vs ") || question.includes(" vs. ")) {
1151
+ return null;
1152
+ }
1153
+ if (question.includes("shot")) return "shots";
1154
+ if (question.includes("assist")) return "assists";
1155
+ if (question.includes("goal")) return "goals";
1156
+ return null;
1157
+ };
1158
+ var resolveSportsStatToken = (market) => {
1159
+ const subtype = toTrimmedString(market.marketSubtype).toLowerCase();
1160
+ const playerMatch = /_player_(.+)$/.exec(subtype);
1161
+ if (playerMatch) return playerMatch[1];
1162
+ const category = normalizeSportsMarketCategory(market.marketCategory);
1163
+ if (category && SPORTS_LEGACY_PROP_CATEGORY_KEY_SET.has(category)) return category;
1164
+ return null;
1165
+ };
1166
+ var resolveMarketSectionTabKey = (market) => {
1167
+ var _a;
1168
+ if (normalizeSportsMarketType(market.sportsMarketType) === "to_advance") {
1169
+ return "game_lines";
1170
+ }
1171
+ const normalizedCategory = normalizeSportsMarketCategory(market.marketCategory);
1172
+ const fallbackCategory = !normalizedCategory || normalizedCategory === "other" ? resolveFallbackSportsMarketCategory(market) : null;
1173
+ const category = fallbackCategory != null ? fallbackCategory : normalizedCategory;
1174
+ if (category && SPORTS_LEGACY_PROP_CATEGORY_KEY_SET.has(category)) return `stat:${category}`;
1175
+ if (category === "exact_score") return "exact_score";
1176
+ const group = normalizeSportsMarketGroup(market.marketGroup);
1177
+ if (group === "exact_score") return "exact_score";
1178
+ if (group === "player_props") {
1179
+ return `stat:${(_a = resolveSportsStatToken(market)) != null ? _a : SPORTS_GENERIC_STAT}`;
1180
+ }
1181
+ if (group === "period_lines") {
1182
+ return `period:${resolveSportsPeriodFamily(normalizeSportsPeriod(market.period))}`;
1183
+ }
1184
+ if (group === "other") return "other";
1185
+ if (group) return "game_lines";
1186
+ if (category === "game_lines") return "game_lines";
1187
+ if (category === "other") return "other";
1188
+ return null;
1189
+ };
1190
+ var SPORTS_PERIOD_FAMILY_ALLOWED_SPORTS = {
1191
+ halves: /* @__PURE__ */ new Set(["soccer", "basketball", "american_football", "rugby", "aussie_rules"]),
1192
+ quarters: /* @__PURE__ */ new Set(["basketball", "american_football", "lacrosse", "aussie_rules"]),
1193
+ innings: /* @__PURE__ */ new Set(["baseball"]),
1194
+ sets: /* @__PURE__ */ new Set(["tennis", "table_tennis", "volleyball"]),
1195
+ maps: /* @__PURE__ */ new Set(["esports"]),
1196
+ ot: /* @__PURE__ */ new Set(["basketball", "american_football", "hockey", "soccer"])
1197
+ };
1198
+ var PERIOD_N_FAMILY_PATTERN = /^period_\d{1,2}$/;
1199
+ var isPeriodFamilyAllowedForSport = (family, sport) => {
1200
+ if (!sport || sport === "other_sport") return true;
1201
+ if (PERIOD_N_FAMILY_PATTERN.test(family)) return sport === "hockey";
1202
+ const normalizedFamily = FIRST_N_INNINGS_PATTERN.test(family) ? "innings" : family;
1203
+ const allowedSports = SPORTS_PERIOD_FAMILY_ALLOWED_SPORTS[normalizedFamily];
1204
+ return !allowedSports || allowedSports.has(sport);
1205
+ };
1206
+ var resolveEffectiveMarketSectionTabKey = (market, sport) => {
1207
+ const key = resolveMarketSectionTabKey(market);
1208
+ if (!key || !key.startsWith("period:")) return key;
1209
+ const family = key.slice("period:".length);
1210
+ return isPeriodFamilyAllowedForSport(family, sport) ? key : "other";
1211
+ };
1212
+ var resolveVisibleSportsSectionTabs = (event) => {
1213
+ var _a, _b, _c;
1214
+ const periodsByFamily = /* @__PURE__ */ new Map();
1215
+ const statVolume = /* @__PURE__ */ new Map();
1216
+ let hasGameLines = false;
1217
+ let hasExactScore = false;
1218
+ let hasOther = false;
1219
+ for (const market of event.venueMarkets) {
1220
+ const key = resolveEffectiveMarketSectionTabKey(market, event.sport);
1221
+ if (!key) continue;
1222
+ if (key === "game_lines") hasGameLines = true;
1223
+ else if (key === "exact_score") hasExactScore = true;
1224
+ else if (key === "other") hasOther = true;
1225
+ else if (key.startsWith("period:")) {
1226
+ const family = key.slice("period:".length);
1227
+ const periods = (_a = periodsByFamily.get(family)) != null ? _a : /* @__PURE__ */ new Set();
1228
+ periods.add(normalizeSportsPeriod(market.period));
1229
+ periodsByFamily.set(family, periods);
1230
+ } else if (key.startsWith("stat:")) {
1231
+ const stat = key.slice("stat:".length);
1232
+ statVolume.set(stat, ((_b = statVolume.get(stat)) != null ? _b : 0) + ((_c = market.volume) != null ? _c : 0));
1233
+ }
1234
+ }
1235
+ const tabs = [];
1236
+ if (hasGameLines) tabs.push({ key: "game_lines", kind: "game_lines" });
1237
+ const periodTabs = Array.from(periodsByFamily.entries()).map(([periodFamily, periods]) => ({
1238
+ key: `period:${periodFamily}`,
1239
+ kind: "period",
1240
+ periodFamily,
1241
+ periods: Array.from(periods).sort(
1242
+ (left, right) => getSportsPeriodOrderIndex(left) - getSportsPeriodOrderIndex(right)
1243
+ )
1244
+ })).sort(
1245
+ (left, right) => getSportsPeriodOrderIndex(left.periods[0]) - getSportsPeriodOrderIndex(right.periods[0])
1246
+ );
1247
+ tabs.push(...periodTabs);
1248
+ const statTabs = Array.from(statVolume.entries()).sort((left, right) => {
1249
+ if (left[0] === SPORTS_GENERIC_STAT !== (right[0] === SPORTS_GENERIC_STAT)) {
1250
+ return left[0] === SPORTS_GENERIC_STAT ? 1 : -1;
1251
+ }
1252
+ return right[1] - left[1];
1253
+ }).map(([stat]) => ({ key: `stat:${stat}`, kind: "stat", stat }));
1254
+ tabs.push(...statTabs);
1255
+ if (hasExactScore) tabs.push({ key: "exact_score", kind: "exact_score" });
1256
+ if (hasOther) tabs.push({ key: "other", kind: "other" });
1257
+ if (isNonStandardSportsLikeEvent(event)) {
1258
+ return tabs.filter((tab) => tab.kind === "game_lines" || tab.kind === "other");
1259
+ }
1260
+ return tabs;
1261
+ };
1262
+ var resolveSportsSectionFilters = (tab) => {
1263
+ if (tab.kind === "period") {
1264
+ return {
1265
+ marketGroup: ["period_lines"],
1266
+ marketCategory: void 0,
1267
+ sportsMarketType: void 0,
1268
+ period: tab.periods ? [...tab.periods] : void 0
1269
+ };
1270
+ }
1271
+ if (tab.kind === "stat") {
1272
+ const legacyCategory = SPORTS_LEGACY_PROP_CATEGORY_KEY_SET.has(
1273
+ tab.stat
1274
+ ) ? tab.stat : null;
1275
+ return legacyCategory ? {
1276
+ marketGroup: void 0,
1277
+ marketCategory: [legacyCategory],
1278
+ sportsMarketType: void 0,
1279
+ period: void 0
1280
+ } : {
1281
+ marketGroup: ["player_props"],
1282
+ marketCategory: void 0,
1283
+ sportsMarketType: void 0,
1284
+ period: void 0
1285
+ };
1286
+ }
1287
+ if (tab.kind === "exact_score") {
1288
+ return {
1289
+ marketGroup: ["exact_score"],
1290
+ marketCategory: void 0,
1291
+ sportsMarketType: void 0,
1292
+ period: void 0
1293
+ };
1294
+ }
1295
+ if (tab.kind === "other") {
1296
+ return {
1297
+ marketGroup: ["other"],
1298
+ marketCategory: void 0,
1299
+ sportsMarketType: void 0,
1300
+ period: void 0
1301
+ };
1302
+ }
1303
+ return {
1304
+ marketGroup: [...SPORTS_GAME_LINE_GROUPS],
1305
+ marketCategory: void 0,
1306
+ sportsMarketType: void 0,
1307
+ period: void 0
1308
+ };
1309
+ };
1310
+ var hasTeamTitledOutcomes = (market) => {
1311
+ var _a;
1312
+ const titles = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1313
+ (outcome) => toTrimmedString(outcome.title)
1314
+ );
1315
+ return titles.length > 1 && titles.every((title) => title && !YES_NO_LABELS.has(title.toLowerCase())) && new Set(titles).size === titles.length;
1316
+ };
1317
+ var isClusterRelation = (left, right) => {
1318
+ var _a, _b;
1319
+ return ((_a = left.matchedVenueMarkets) != null ? _a : []).some((market) => market.id === right.id) || ((_b = right.matchedVenueMarkets) != null ? _b : []).some((market) => market.id === left.id);
1320
+ };
1321
+ var isDecomposedLeg = (market) => {
1322
+ var _a;
1323
+ const labels = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1324
+ (outcome) => toTrimmedString(outcome.label).toLowerCase()
1325
+ );
1326
+ return labels.length === 2 && labels.every((label) => YES_NO_LABELS.has(label)) && !hasTeamTitledOutcomes(market);
1327
+ };
1328
+ var singleEnumeratesLegs = (single, legs) => {
1329
+ var _a;
1330
+ const titles = new Set(
1331
+ ((_a = single.venueMarketOutcomes) != null ? _a : []).map((outcome) => toTrimmedString(outcome.title).toLowerCase()).filter(Boolean)
1332
+ );
1333
+ if (titles.size === 0) return false;
1334
+ return legs.every((leg) => {
1335
+ const label = resolveCombinedMoneylineLegLabel(leg).toLowerCase();
1336
+ return label.length > 0 && titles.has(label);
1337
+ });
1338
+ };
1339
+ var dropDecomposedLegsMergedIntoSingle = (markets) => {
1340
+ const legs = markets.filter((market) => isDecomposedLeg(market));
1341
+ if (legs.length === 0) return markets;
1342
+ const hasMergedSingle = markets.some(
1343
+ (market) => {
1344
+ var _a, _b;
1345
+ return hasTeamTitledOutcomes(market) && ((_b = (_a = market.venueMarketOutcomes) == null ? void 0 : _a.length) != null ? _b : 0) >= legs.length && (markets.some((other) => other !== market && isClusterRelation(market, other)) || singleEnumeratesLegs(market, legs));
1346
+ }
1347
+ );
1348
+ return hasMergedSingle ? markets.filter((market) => !isDecomposedLeg(market)) : markets;
1349
+ };
1350
+ var resolveSportsSectionMarkets = ({
1351
+ tab,
1352
+ eventMarkets,
1353
+ sectionMarkets,
1354
+ sport
1355
+ }) => {
1356
+ const effectiveSectionMarkets = sectionMarkets.length > 0 ? sectionMarkets : eventMarkets.filter(
1357
+ (market) => resolveEffectiveMarketSectionTabKey(market, sport) === tab.key
1358
+ );
1359
+ const filteredSectionMarkets = effectiveSectionMarkets.filter(
1360
+ (market) => resolveEffectiveMarketSectionTabKey(market, sport) === tab.key
1361
+ );
1362
+ if (tab.key === "other" || tab.key === `stat:${SPORTS_GENERIC_STAT}`) {
1363
+ const seenIds = new Set(filteredSectionMarkets.map((market) => market.id));
1364
+ const strayMarkets = eventMarkets.filter(
1365
+ (market) => !seenIds.has(market.id) && resolveEffectiveMarketSectionTabKey(market, sport) === tab.key
1366
+ );
1367
+ return [...filteredSectionMarkets, ...strayMarkets];
1368
+ }
1369
+ if (tab.kind !== "game_lines") return filteredSectionMarkets;
1370
+ const dedupeEventMarketsOfType = (type) => {
1371
+ const dedupedMarkets = [];
1372
+ const keptIndexByKey = /* @__PURE__ */ new Map();
1373
+ for (const market of eventMarkets) {
1374
+ if (normalizeSportsMarketType(market.sportsMarketType) !== type || resolveMarketSectionTabKey(market) !== "game_lines") {
1375
+ continue;
1376
+ }
1377
+ const key = resolveSportsMarketAggKey(market) || market.id;
1378
+ const keptIndex = keptIndexByKey.get(key);
1379
+ if (keptIndex !== void 0) {
1380
+ const kept = dedupedMarkets[keptIndex];
1381
+ if (!hasTeamTitledOutcomes(kept) && hasTeamTitledOutcomes(market)) {
1382
+ dedupedMarkets[keptIndex] = market;
1383
+ }
1384
+ continue;
1385
+ }
1386
+ keptIndexByKey.set(key, dedupedMarkets.length);
1387
+ dedupedMarkets.push(market);
1388
+ }
1389
+ return dropDecomposedLegsMergedIntoSingle(dedupedMarkets);
1390
+ };
1391
+ const eventMoneylineMarkets = dedupeEventMarketsOfType("moneyline");
1392
+ const eventToAdvanceMarkets = dedupeEventMarketsOfType("to_advance");
1393
+ const sectionWithoutAdvance = filteredSectionMarkets.filter(
1394
+ (market) => normalizeSportsMarketType(market.sportsMarketType) !== "to_advance"
1395
+ );
1396
+ if (eventMoneylineMarkets.length === 0) {
1397
+ return [...eventToAdvanceMarkets, ...sectionWithoutAdvance];
1398
+ }
1399
+ const lineSectionMarkets = sectionWithoutAdvance.filter(
1400
+ (market) => normalizeSportsMarketType(market.sportsMarketType) !== "moneyline" && resolveMarketSectionTabKey(market) === "game_lines"
1401
+ );
1402
+ return [...eventToAdvanceMarkets, ...eventMoneylineMarkets, ...lineSectionMarkets];
1403
+ };
1404
+ var resolveSportsMarketCardVariant = (market) => {
1405
+ var _a;
1406
+ const normalizedOutcomeLabels = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1407
+ (outcome) => toTrimmedString(outcome.label).toLowerCase()
1408
+ );
1409
+ const sportsMarketType = normalizeSportsMarketType(market.sportsMarketType);
1410
+ if (sportsMarketType && LINE_MARKET_TYPES.has(sportsMarketType)) {
1411
+ return "line";
1412
+ }
1413
+ if (market.lineValue != null) {
1414
+ return "line";
1415
+ }
1416
+ if (normalizedOutcomeLabels.length === 2 && normalizedOutcomeLabels.every((label) => YES_NO_LABELS.has(label))) {
1417
+ return "yes_no";
1418
+ }
1419
+ return "outcome";
1420
+ };
1421
+ var isBinarySportsMoneylineMarket = (market) => {
1422
+ var _a;
1423
+ const normalizedOutcomeLabels = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1424
+ (outcome) => toTrimmedString(outcome.label).toLowerCase()
1425
+ );
1426
+ const marketSubtype = toTrimmedString(market.marketSubtype).toLowerCase();
1427
+ const marketGroup = normalizeSportsMarketGroup(market.marketGroup);
1428
+ const sportsMarketType = normalizeSportsMarketType(market.sportsMarketType);
1429
+ const question = toTrimmedString(market.question);
1430
+ const aggKey = resolveSportsMarketAggKey(market);
1431
+ return sportsMarketType === "moneyline" && marketGroup === "game_lines" && normalizeSportsPeriod(market.period) === "full" && normalizedOutcomeLabels.length === 2 && normalizedOutcomeLabels.every((label) => YES_NO_LABELS.has(label)) && (marketSubtype === "moneyline" || REG_TIME_TITLE_PATTERN.test(question) || aggKey.includes("_ml_"));
1432
+ };
1433
+ var AGGKEY_LINE_TOKEN_PATTERN = /_\d{1,3}(?:p\d+)?(?=_|$)/g;
1434
+ var resolveSportsLineFamilyKey = (market) => {
1435
+ const aggKey = resolveSportsMarketAggKey(market);
1436
+ return aggKey ? aggKey.replace(AGGKEY_LINE_TOKEN_PATTERN, "") : "";
1437
+ };
1438
+ var resolveSpreadFamilyKey = (market) => {
1439
+ const aggKey = resolveSportsMarketAggKey(market);
1440
+ return aggKey ? aggKey.replace(/_sp_.+$/i, "_sp") : "";
1441
+ };
1442
+ var SPREAD_KEY_LEG_PATTERN = /_sp_([a-z0-9]+?)_([mp]?)(\d{1,3})(?:p(\d+))?(?:_|$)/i;
1443
+ var resolveSpreadKeyLeg = (market) => {
1444
+ const match = SPREAD_KEY_LEG_PATTERN.exec(resolveSportsMarketAggKey(market));
1445
+ if (!match) return null;
1446
+ const [, team, leg, whole, fraction] = match;
1447
+ return {
1448
+ team: team.toLowerCase(),
1449
+ isFavorite: (leg == null ? void 0 : leg.toLowerCase()) !== "p",
1450
+ line: Number(fraction ? `${whole}.${fraction}` : whole)
1451
+ };
1452
+ };
1453
+ var isSpreadUnderdogLeg = (market) => {
1454
+ var _a;
1455
+ return ((_a = resolveSpreadKeyLeg(market)) == null ? void 0 : _a.isFavorite) === false;
1456
+ };
1457
+ var resolveSpreadAnchorToken = (markets) => {
1458
+ var _a;
1459
+ const tokens = /* @__PURE__ */ new Set();
1460
+ let prefix = "";
1461
+ for (const market of markets) {
1462
+ const leg = resolveSpreadKeyLeg(market);
1463
+ if (leg) tokens.add(leg.team);
1464
+ if (!prefix) prefix = (_a = resolveSportsMarketAggKey(market).split("_sp_")[0]) != null ? _a : "";
1465
+ }
1466
+ if (tokens.size === 0 || !prefix) return null;
1467
+ return Array.from(tokens).sort((left, right) => prefix.indexOf(left) - prefix.indexOf(right))[0];
1468
+ };
1469
+ var SPREAD_NON_TEAM_TITLE_PATTERN = /\b(?:yes|no|over|under|wins?\s+by|reg\.?\s*time|goal\s*diff|more\s+than|less\s+than|halftime|1st\s+half|2nd\s+half|goals?)\b/i;
1470
+ var isSpreadTeamTitle = (title) => {
1471
+ const trimmed = toTrimmedString(title);
1472
+ if (!trimmed || trimmed.length > 24) return false;
1473
+ const normalized = trimmed.toLowerCase();
1474
+ if (normalized === "yes" || normalized === "no") return false;
1475
+ return !SPREAD_NON_TEAM_TITLE_PATTERN.test(trimmed);
1476
+ };
1477
+ var resolveSpreadOutcomeTeamNames = (activeMarket, groupMarkets) => {
1478
+ const aggKey = resolveSportsMarketAggKey(activeMarket);
1479
+ const twins = aggKey ? groupMarkets.filter((market) => resolveSportsMarketAggKey(market) === aggKey) : [activeMarket];
1480
+ const pickName = (index) => {
1481
+ const cleanTitles = twins.map((market) => {
1482
+ var _a, _b;
1483
+ return toTrimmedString((_b = (_a = market.venueMarketOutcomes) == null ? void 0 : _a[index]) == null ? void 0 : _b.title);
1484
+ }).filter((title) => isSpreadTeamTitle(title));
1485
+ if (cleanTitles.length === 0) return null;
1486
+ return cleanTitles.reduce(
1487
+ (longest, title) => title.length > longest.length ? title : longest
1488
+ );
1489
+ };
1490
+ const named = pickName(0);
1491
+ const opponent = pickName(1);
1492
+ return isSpreadUnderdogLeg(activeMarket) ? { favored: opponent, dog: named } : { favored: named, dog: opponent };
1493
+ };
1494
+ var resolveCombinedMoneylineLegLabel = (market) => {
1495
+ const typedMarket = market;
1496
+ return toTrimmedString(typedMarket.shortTitle) || toTrimmedString(market.question);
1497
+ };
1498
+ var normalizeSportsSubtypeToken = (subtype, sport) => {
1499
+ const token = toTrimmedString(subtype).toLowerCase().replace(/^sports_/, "");
1500
+ const sportToken = toTrimmedString(sport).toLowerCase();
1501
+ return sportToken && token.startsWith(`${sportToken}_`) ? token.slice(sportToken.length + 1) : token;
1502
+ };
1503
+ var SPORTS_LEG_GROUPABLE_GROUPS = /* @__PURE__ */ new Set([
1504
+ "game_lines",
1505
+ "period_lines",
1506
+ "team_props",
1507
+ "specials",
1508
+ "completion"
1509
+ ]);
1510
+ var resolveDisplayGroupFamilyKey = (market, sport) => {
1511
+ var _a, _b, _c;
1512
+ const normalizedQuestion = sanitizeFamilyValue(toTrimmedString(market.question));
1513
+ const outcomeKey = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1514
+ (outcome) => sanitizeFamilyValue(toTrimmedString(outcome.title) || toTrimmedString(outcome.label))
1515
+ ).filter(Boolean).sort((left, right) => left.localeCompare(right)).join("|");
1516
+ const sportsMarketType = (_b = normalizeSportsMarketType(market.sportsMarketType)) != null ? _b : "other";
1517
+ const period = normalizeSportsPeriod(market.period);
1518
+ const marketCategory = (_c = normalizeSportsMarketCategory(market.marketCategory)) != null ? _c : "other";
1519
+ if (isBinarySportsMoneylineMarket(market)) {
1520
+ return `${period}|moneyline|${marketCategory}`;
1521
+ }
1522
+ if (sportsMarketType === "to_advance") {
1523
+ return `${period}|to_advance`;
1524
+ }
1525
+ const lineFamily = resolveSportsLineFamilyKey(market);
1526
+ if (sportsMarketType === "spread") {
1527
+ const spreadFamily = resolveSpreadFamilyKey(market);
1528
+ return spreadFamily ? `${period}|spread|${spreadFamily}` : `${period}|spread|${marketCategory}`;
1529
+ }
1530
+ if (market.lineValue != null || LINE_MARKET_TYPES.has(sportsMarketType)) {
1531
+ return lineFamily ? `${period}|${sportsMarketType}|${lineFamily}` : `${period}|${sportsMarketType}|${marketCategory}|${normalizedQuestion}|${outcomeKey}`;
1532
+ }
1533
+ const marketGroup = normalizeSportsMarketGroup(market.marketGroup);
1534
+ const legToken = marketGroup && SPORTS_LEG_GROUPABLE_GROUPS.has(marketGroup) && isDecomposedLeg(market) ? normalizeSportsSubtypeToken(market.marketSubtype, sport) : "";
1535
+ if (legToken) {
1536
+ return `${period}|leg|${marketGroup}|${legToken}`;
1537
+ }
1538
+ return resolveMarketOwnCardKey(market);
1539
+ };
1540
+ var resolveMarketOwnCardKey = (market) => {
1541
+ var _a, _b, _c;
1542
+ const outcomeKey = ((_a = market.venueMarketOutcomes) != null ? _a : []).map(
1543
+ (outcome) => sanitizeFamilyValue(toTrimmedString(outcome.title) || toTrimmedString(outcome.label))
1544
+ ).filter(Boolean).sort((left, right) => left.localeCompare(right)).join("|");
1545
+ const sportsMarketType = (_b = normalizeSportsMarketType(market.sportsMarketType)) != null ? _b : "other";
1546
+ const period = normalizeSportsPeriod(market.period);
1547
+ const marketCategory = (_c = normalizeSportsMarketCategory(market.marketCategory)) != null ? _c : "other";
1548
+ return `${period}|${sportsMarketType}|${marketCategory}|${toTrimmedString(market.question)}|${outcomeKey}|${market.id}`;
1549
+ };
1550
+ var LEG_GROUP_KEY_MARKER = "|leg|";
1551
+ var TOTAL_STAT_UNITS = [
1552
+ [/\bcorners?\b/i, "Corners"],
1553
+ [/\bcards?\b|\bbookings?\b/i, "Cards"],
1554
+ [/\bgoals?\b/i, "Goals"],
1555
+ [/\bpoints?\b/i, "Points"],
1556
+ [/\bruns?\b/i, "Runs"],
1557
+ [/\brounds?\b/i, "Rounds"],
1558
+ [/\bgames?\b/i, "Games"],
1559
+ [/\bsets?\b/i, "Sets"],
1560
+ [/\bmaps?\b/i, "Maps"]
1561
+ ];
1562
+ var resolveTotalStatUnit = (markets, marketCategory) => {
1563
+ if (marketCategory === "corners") return "Corners";
1564
+ for (const market of markets) {
1565
+ const question = toTrimmedString(market.question);
1566
+ for (const [pattern, unit] of TOTAL_STAT_UNITS) {
1567
+ if (pattern.test(question)) return unit;
1568
+ }
1569
+ }
1570
+ return null;
1571
+ };
1572
+ var SPORTS_LEG_TITLE_OVERRIDES = { nrfi: "NRFI" };
1573
+ var SPORTS_LEG_TITLE_SMALL_WORDS = /* @__PURE__ */ new Set(["to", "the", "of", "in", "at", "a", "and", "or"]);
1574
+ var formatSportsLegTitle = (token) => {
1575
+ var _a;
1576
+ return (_a = SPORTS_LEG_TITLE_OVERRIDES[token]) != null ? _a : token.split("_").filter(Boolean).map(
1577
+ (word, index) => index > 0 && SPORTS_LEG_TITLE_SMALL_WORDS.has(word) ? word : word.charAt(0).toUpperCase() + word.slice(1)
1578
+ ).join(" ");
1579
+ };
1580
+ var resolveDisplayGroupTitle = (market, groupMarkets = [market], sport, isCombinedLegGroup = false) => {
1581
+ const sportsMarketType = normalizeSportsMarketType(market.sportsMarketType);
1582
+ const question = toTrimmedString(market.question);
1583
+ if (isBinarySportsMoneylineMarket(market)) return "Moneyline";
1584
+ if (sportsMarketType === "to_advance") return "Team to Advance";
1585
+ if (sportsMarketType === "spread") return "Spreads";
1586
+ if (isCombinedLegGroup) {
1587
+ const legToken = normalizeSportsSubtypeToken(market.marketSubtype, sport);
1588
+ if (legToken) return formatSportsLegTitle(legToken);
1589
+ }
1590
+ if (!question) {
1591
+ return sportsMarketType != null ? sportsMarketType : market.id;
1592
+ }
1593
+ if (sportsMarketType === "total") {
1594
+ const lineFamily = resolveSportsLineFamilyKey(market);
1595
+ const marketCategory = normalizeSportsMarketCategory(market.marketCategory);
1596
+ if (/_tot(_corners)?(_\dh)?$/i.test(lineFamily)) {
1597
+ const unit = resolveTotalStatUnit(groupMarkets, marketCategory);
1598
+ return unit ? `Total ${unit}` : "Totals";
1599
+ }
1600
+ const base = stripLineValueFromQuestion(question).replace(/o\s*\/\s*u/gi, " ").replace(/\btotals?\b/gi, " ").replace(/\s+/g, " ").trim();
1601
+ return base ? `${base} Totals` : "Totals";
1602
+ }
1603
+ if (market.lineValue != null) {
1604
+ const strippedQuestion = stripLineValueFromQuestion(question);
1605
+ return strippedQuestion || question;
1606
+ }
1607
+ return question;
1608
+ };
1609
+ var sortMarketsByLineValue = (markets) => {
1610
+ return [...markets].sort((leftMarket, rightMarket) => {
1611
+ var _a, _b;
1612
+ const leftLineValue = (_a = leftMarket.lineValue) != null ? _a : Number.NEGATIVE_INFINITY;
1613
+ const rightLineValue = (_b = rightMarket.lineValue) != null ? _b : Number.NEGATIVE_INFINITY;
1614
+ if (leftLineValue !== rightLineValue) {
1615
+ return leftLineValue - rightLineValue;
1616
+ }
1617
+ return leftMarket.question.localeCompare(rightMarket.question);
1618
+ });
1619
+ };
1620
+ var buildSportsMarketDisplayGroups = (markets, sport) => {
1621
+ var _a, _b, _c, _d, _e;
1622
+ const groupsByKey = /* @__PURE__ */ new Map();
1623
+ for (const market of markets) {
1624
+ const groupKey = resolveDisplayGroupFamilyKey(market, sport);
1625
+ const currentMarkets = (_a = groupsByKey.get(groupKey)) != null ? _a : [];
1626
+ currentMarkets.push(market);
1627
+ groupsByKey.set(groupKey, currentMarkets);
1628
+ }
1629
+ const VENUE_SPLIT_MARKER = "|venue:";
1630
+ const pending = Array.from(groupsByKey.keys());
1631
+ while (pending.length > 0) {
1632
+ const groupKey = pending.pop();
1633
+ if (groupKey == null) continue;
1634
+ const groupMarkets = groupsByKey.get(groupKey);
1635
+ if (!groupMarkets || groupMarkets.length === 0) continue;
1636
+ const isLegBucket = groupKey.includes(LEG_GROUP_KEY_MARKER);
1637
+ const combinable = groupMarkets.length > 1 ? resolveSportsCombinedLegs({
1638
+ markets: groupMarkets,
1639
+ sportsMarketType: normalizeSportsMarketType((_b = groupMarkets[0]) == null ? void 0 : _b.sportsMarketType)
1640
+ }) : null;
1641
+ if (groupMarkets.length > 1) {
1642
+ if (groupMarkets.some((market) => market.lineValue != null)) continue;
1643
+ if (!combinable && groupMarkets.some((market) => hasTeamTitledOutcomes(market))) continue;
1644
+ const marketsPerVenue = /* @__PURE__ */ new Map();
1645
+ for (const market of groupMarkets) {
1646
+ marketsPerVenue.set(market.venue, [...(_c = marketsPerVenue.get(market.venue)) != null ? _c : [], market]);
1647
+ }
1648
+ const mostFromOneVenue = Math.max(...Array.from(marketsPerVenue.values(), (m) => m.length));
1649
+ if (combinable && combinable.length <= mostFromOneVenue) continue;
1650
+ if (marketsPerVenue.size > 1) {
1651
+ groupsByKey.delete(groupKey);
1652
+ for (const [venue, venueMarkets] of marketsPerVenue) {
1653
+ const venueKey = `${groupKey}${VENUE_SPLIT_MARKER}${venue}`;
1654
+ groupsByKey.set(venueKey, [...(_d = groupsByKey.get(venueKey)) != null ? _d : [], ...venueMarkets]);
1655
+ pending.push(venueKey);
1656
+ }
1657
+ continue;
1658
+ }
1659
+ }
1660
+ if (isLegBucket && !combinable) {
1661
+ groupsByKey.delete(groupKey);
1662
+ for (const market of groupMarkets) {
1663
+ const ownKey = resolveMarketOwnCardKey(market);
1664
+ groupsByKey.set(ownKey, [...(_e = groupsByKey.get(ownKey)) != null ? _e : [], market]);
1665
+ }
1666
+ }
1667
+ }
1668
+ const groups = Array.from(groupsByKey.entries()).map(([id, groupMarkets]) => {
1669
+ var _a2;
1670
+ const isToAdvanceGroup = groupMarkets.some(
1671
+ (market) => normalizeSportsMarketType(market.sportsMarketType) === "to_advance"
1672
+ );
1673
+ const orderedMarkets = isToAdvanceGroup ? [...groupMarkets].sort((left, right) => {
1674
+ var _a3, _b2;
1675
+ const leftSingle = resolveSportsMarketAggKey(left).endsWith("_adv") ? 0 : 1;
1676
+ const rightSingle = resolveSportsMarketAggKey(right).endsWith("_adv") ? 0 : 1;
1677
+ if (leftSingle !== rightSingle) return leftSingle - rightSingle;
1678
+ return ((_a3 = right.volume) != null ? _a3 : 0) - ((_b2 = left.volume) != null ? _b2 : 0);
1679
+ }) : sortMarketsByLineValue(groupMarkets);
1680
+ const firstMarket = orderedMarkets[0];
1681
+ const sportsMarketType = normalizeSportsMarketType(firstMarket == null ? void 0 : firstMarket.sportsMarketType);
1682
+ const marketCategory = normalizeSportsMarketCategory(firstMarket == null ? void 0 : firstMarket.marketCategory);
1683
+ const period = normalizeSportsPeriod(firstMarket == null ? void 0 : firstMarket.period);
1684
+ const sectionRank = (_a2 = firstMarket == null ? void 0 : firstMarket.sectionRank) != null ? _a2 : Number.MAX_SAFE_INTEGER;
1685
+ return {
1686
+ id,
1687
+ title: resolveDisplayGroupTitle(
1688
+ firstMarket,
1689
+ orderedMarkets,
1690
+ id.includes(LEG_GROUP_KEY_MARKER) ? sport : void 0,
1691
+ id.includes(LEG_GROUP_KEY_MARKER)
1692
+ ),
1693
+ questionKey: sanitizeFamilyValue(toTrimmedString(firstMarket == null ? void 0 : firstMarket.question)),
1694
+ sportsMarketType,
1695
+ marketCategory,
1696
+ period,
1697
+ sectionRank,
1698
+ markets: orderedMarkets,
1699
+ hasLineVariants: orderedMarkets.some((market) => market.lineValue != null)
1700
+ };
1701
+ });
1702
+ return groups.sort((leftGroup, rightGroup) => {
1703
+ var _a2, _b2, _c2, _d2;
1704
+ if (leftGroup.sectionRank !== rightGroup.sectionRank) {
1705
+ return leftGroup.sectionRank - rightGroup.sectionRank;
1706
+ }
1707
+ const leftMarketTypeOrder = getSportsMarketTypeOrderIndex(leftGroup.sportsMarketType);
1708
+ const rightMarketTypeOrder = getSportsMarketTypeOrderIndex(rightGroup.sportsMarketType);
1709
+ if (leftMarketTypeOrder !== rightMarketTypeOrder) {
1710
+ return leftMarketTypeOrder - rightMarketTypeOrder;
1711
+ }
1712
+ const leftLineValue = (_b2 = (_a2 = leftGroup.markets[0]) == null ? void 0 : _a2.lineValue) != null ? _b2 : Number.NEGATIVE_INFINITY;
1713
+ const rightLineValue = (_d2 = (_c2 = rightGroup.markets[0]) == null ? void 0 : _c2.lineValue) != null ? _d2 : Number.NEGATIVE_INFINITY;
1714
+ if (leftLineValue !== rightLineValue) {
1715
+ return leftLineValue - rightLineValue;
1716
+ }
1717
+ return leftGroup.title.localeCompare(rightGroup.title);
1718
+ });
1719
+ };
1720
+ var groupSportsMarketsByPeriod = (markets, sport) => {
1721
+ var _a;
1722
+ const periodGroups = /* @__PURE__ */ new Map();
1723
+ for (const market of markets) {
1724
+ const period = normalizeSportsPeriod(market.period);
1725
+ const currentMarkets = (_a = periodGroups.get(period)) != null ? _a : [];
1726
+ currentMarkets.push(market);
1727
+ periodGroups.set(period, currentMarkets);
1728
+ }
1729
+ return Array.from(periodGroups.entries()).map(([key, groupedMarkets]) => ({
1730
+ key,
1731
+ markets: groupedMarkets,
1732
+ groups: buildSportsMarketDisplayGroups(groupedMarkets, sport)
1733
+ })).sort((leftGroup, rightGroup) => {
1734
+ return getSportsPeriodOrderIndex(leftGroup.key) - getSportsPeriodOrderIndex(rightGroup.key);
1735
+ });
1736
+ };
1737
+ var resolveSelectedSportsLineValue = (lineValue) => {
1738
+ if (lineValue == null) return "0";
1739
+ return Number.isInteger(lineValue) ? String(lineValue) : lineValue.toFixed(1);
1740
+ };
1741
+ var collectVenueNames = (market) => {
1742
+ var _a;
1743
+ const venues = /* @__PURE__ */ new Set([market.venue]);
1744
+ for (const matchedVenueMarket of (_a = market.matchedVenueMarkets) != null ? _a : []) {
1745
+ venues.add(matchedVenueMarket.venue);
1746
+ }
1747
+ return Array.from(venues);
1748
+ };
1749
+ var resolveTotalGroupVolume = (markets) => {
1750
+ return markets.reduce((totalVolume, market) => {
1751
+ var _a;
1752
+ return totalVolume + ((_a = market.volume) != null ? _a : 0);
1753
+ }, 0);
1754
+ };
1755
+ var resolveSportsExpandedMarkets = (markets) => {
1756
+ var _a;
1757
+ const expandedMarkets = [];
1758
+ const seenMarketIds = /* @__PURE__ */ new Set();
1759
+ for (const market of markets) {
1760
+ if (!seenMarketIds.has(market.id)) {
1761
+ seenMarketIds.add(market.id);
1762
+ expandedMarkets.push(market);
1763
+ }
1764
+ for (const matchedVenueMarket of (_a = market.matchedVenueMarkets) != null ? _a : []) {
1765
+ if (seenMarketIds.has(matchedVenueMarket.id)) continue;
1766
+ seenMarketIds.add(matchedVenueMarket.id);
1767
+ expandedMarkets.push(matchedVenueMarket);
1768
+ }
1769
+ }
1770
+ return expandedMarkets;
1771
+ };
1772
+ var resolveSportsExpandedMarketsVolume = (markets) => {
1773
+ return resolveSportsExpandedMarkets(markets).reduce((totalVolume, market) => {
1774
+ var _a;
1775
+ return totalVolume + ((_a = market.volume) != null ? _a : 0);
1776
+ }, 0);
1777
+ };
1778
+ var resolveHighestVolumeIndex = (markets) => {
1779
+ let bestIndex = 0;
1780
+ let bestVolume = Number.NEGATIVE_INFINITY;
1781
+ markets.forEach((market, index) => {
1782
+ var _a;
1783
+ const volume = (_a = market.volume) != null ? _a : 0;
1784
+ if (volume > bestVolume) {
1785
+ bestVolume = volume;
1786
+ bestIndex = index;
1787
+ }
1788
+ });
1789
+ return bestIndex;
1790
+ };
1791
+ var resolveSportsCombinedLegs = (group) => {
1792
+ var _a;
1793
+ if (group.markets.some((market) => market.lineValue != null)) return null;
1794
+ const isMoneylineGroup = group.sportsMarketType === "moneyline" && group.markets.every((market) => isBinarySportsMoneylineMarket(market));
1795
+ const legs = group.markets.filter(
1796
+ (market) => isMoneylineGroup ? isBinarySportsMoneylineMarket(market) : isDecomposedLeg(market)
1797
+ );
1798
+ if (legs.length < 2 || legs.length !== group.markets.length) return null;
1799
+ if (!isMoneylineGroup) {
1800
+ const legsPerVenue = /* @__PURE__ */ new Map();
1801
+ for (const leg of legs) {
1802
+ legsPerVenue.set(leg.venue, ((_a = legsPerVenue.get(leg.venue)) != null ? _a : 0) + 1);
1803
+ }
1804
+ const isDecomposition = Array.from(legsPerVenue.values()).some((count) => count > 1);
1805
+ if (!isDecomposition) return null;
1806
+ }
1807
+ const twinSets = [];
1808
+ for (const leg of legs) {
1809
+ const legQuestion = sanitizeFamilyValue(toTrimmedString(leg.question));
1810
+ const twins = twinSets.find(
1811
+ (candidates) => candidates.some(
1812
+ (candidate) => (
1813
+ // CROSS-VENUE only. A venue never lists one leg twice, so two legs
1814
+ // from the SAME venue are always different bets — and they routinely
1815
+ // reference each other through their absent merged anchor, so the
1816
+ // cluster test alone would fold a 2-way decomposition down to one
1817
+ // pill and drop a team off the card.
1818
+ candidate.venue !== leg.venue && (isClusterRelation(candidate, leg) || legQuestion.length > 0 && sanitizeFamilyValue(toTrimmedString(candidate.question)) === legQuestion)
1819
+ )
1820
+ )
1821
+ );
1822
+ if (twins) twins.push(leg);
1823
+ else twinSets.push([leg]);
1824
+ }
1825
+ const pills = twinSets.map((twins) => {
1826
+ var _a2;
1827
+ const market = (_a2 = twins[resolveHighestVolumeIndex(twins)]) != null ? _a2 : twins[0];
1828
+ const label = twins.map((twin) => resolveCombinedMoneylineLegLabel(twin)).reduce(
1829
+ (longest, candidate) => candidate.length > longest.length ? candidate : longest,
1830
+ ""
1831
+ );
1832
+ const venues = /* @__PURE__ */ new Set();
1833
+ for (const twin of twins) {
1834
+ for (const venue of collectVenueNames(twin)) venues.add(venue);
1835
+ }
1836
+ return { label, market, venues: Array.from(venues) };
1837
+ });
1838
+ const labels = pills.map((pill) => pill.label.toLowerCase());
1839
+ if (pills.length < 2 || labels.some((label) => !label)) return null;
1840
+ return new Set(labels).size === labels.length ? pills : null;
1841
+ };
1842
+ var resolveSlideKind = (group) => {
1843
+ if (group.sportsMarketType === "to_advance") return "to_advance";
1844
+ if (group.sportsMarketType === "moneyline") return "moneyline";
1845
+ if (group.sportsMarketType === "spread") return "spread";
1846
+ if (group.sportsMarketType === "total") return "total";
1847
+ return "other";
1848
+ };
1849
+ var aggregateSportsLineStops = (markets, isSpread = false) => {
1850
+ var _a;
1851
+ const anchorToken = isSpread ? resolveSpreadAnchorToken(markets) : null;
1852
+ const axisOf = (market) => {
1853
+ var _a2;
1854
+ if (anchorToken) {
1855
+ const leg = resolveSpreadKeyLeg(market);
1856
+ if (leg) {
1857
+ const anchorGivesPoints = leg.team === anchorToken ? leg.isFavorite : !leg.isFavorite;
1858
+ return anchorGivesPoints ? -leg.line : leg.line;
1859
+ }
1860
+ }
1861
+ return (_a2 = market.lineValue) != null ? _a2 : Number.NEGATIVE_INFINITY;
1862
+ };
1863
+ const displayOf = (market) => {
1864
+ var _a2;
1865
+ if (!anchorToken) return resolveSelectedSportsLineValue(market.lineValue);
1866
+ const leg = resolveSpreadKeyLeg(market);
1867
+ return resolveSelectedSportsLineValue(leg ? leg.line : Math.abs((_a2 = market.lineValue) != null ? _a2 : 0));
1868
+ };
1869
+ const marketsByAxis = /* @__PURE__ */ new Map();
1870
+ for (const market of markets) {
1871
+ const axis = axisOf(market);
1872
+ const lineMarkets = (_a = marketsByAxis.get(axis)) != null ? _a : [];
1873
+ lineMarkets.push(market);
1874
+ marketsByAxis.set(axis, lineMarkets);
1875
+ }
1876
+ return Array.from(marketsByAxis.entries()).map(([axis, lineMarkets]) => {
1877
+ var _a2;
1878
+ const representative = (_a2 = lineMarkets[resolveHighestVolumeIndex(lineMarkets)]) != null ? _a2 : lineMarkets[0];
1879
+ const venues = /* @__PURE__ */ new Set();
1880
+ for (const lineMarket of lineMarkets) {
1881
+ for (const venue of collectVenueNames(lineMarket)) {
1882
+ venues.add(venue);
1883
+ }
1884
+ }
1885
+ return {
1886
+ value: displayOf(representative),
1887
+ representative,
1888
+ venues: Array.from(venues),
1889
+ volume: resolveTotalGroupVolume(lineMarkets),
1890
+ lineValue: axis
1891
+ };
1892
+ }).sort(
1893
+ (left, right) => left.lineValue !== right.lineValue ? left.lineValue - right.lineValue : left.value.localeCompare(right.value)
1894
+ );
1895
+ };
1896
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1897
+ var resolveSportsLadderTitle = (group, selectedLineDisplay) => {
1898
+ var _a;
1899
+ const anchorLineValue = (_a = group.markets[0]) == null ? void 0 : _a.lineValue;
1900
+ if (anchorLineValue == null || !selectedLineDisplay) return group.title;
1901
+ const anchorDisplay = resolveSelectedSportsLineValue(anchorLineValue);
1902
+ if (anchorDisplay === selectedLineDisplay) return group.title;
1903
+ const pattern = new RegExp(`(^|[^\\d.])${escapeRegExp(anchorDisplay)}(?![\\d.])`);
1904
+ return pattern.test(group.title) ? group.title.replace(pattern, (_match, prefix) => `${prefix}${selectedLineDisplay}`) : group.title;
1905
+ };
1906
+ var buildSportsSlideFromGroup = (group) => {
1907
+ const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets, group.sportsMarketType === "spread") : [];
1908
+ const hasLadder = lineStops.length > 1;
1909
+ const stops = hasLadder ? lineStops.map((lineStop) => ({
1910
+ value: lineStop.value,
1911
+ venues: lineStop.venues,
1912
+ market: lineStop.representative
1913
+ })) : [];
1914
+ const defaultStopIndex = hasLadder ? lineStops.reduce(
1915
+ (bestIndex, lineStop, index) => lineStop.volume > lineStops[bestIndex].volume ? index : bestIndex,
1916
+ 0
1917
+ ) : 0;
1918
+ return {
1919
+ id: group.id,
1920
+ kind: resolveSlideKind(group),
1921
+ group,
1922
+ hasLadder,
1923
+ stops,
1924
+ defaultStopIndex
1925
+ };
1926
+ };
1927
+ var formatSportsPeriodGrammarLabel = (period) => {
1928
+ const grammarMatch = SPORTS_PERIOD_GRAMMAR_PATTERN.exec(period);
1929
+ if (!grammarMatch) return null;
1930
+ if (grammarMatch[1]) {
1931
+ const family = grammarMatch[1].charAt(0).toUpperCase() + grammarMatch[1].slice(1);
1932
+ return `${family} ${Number(grammarMatch[2])}`;
1933
+ }
1934
+ return `First ${Number(grammarMatch[3])} Innings`;
1935
+ };
1936
+ var resolveSportsCategoryTokens = (event) => {
1937
+ return new Set(
1938
+ event.categories.flatMap((entry) => {
1939
+ const categoryName = toTrimmedString(entry.category.name).toLowerCase();
1940
+ const categoryDisplayName = toTrimmedString(entry.category.displayName).toLowerCase();
1941
+ return [categoryName, categoryDisplayName].filter(Boolean);
1942
+ })
1943
+ );
1944
+ };
1945
+ var isNonStandardSportsLikeEvent = (event) => {
1946
+ const categoryTokens = resolveSportsCategoryTokens(event);
1947
+ if ([...categoryTokens].some((token) => ESPORTS_CATEGORY_TOKENS.has(token))) {
1948
+ return true;
1949
+ }
1950
+ if (ESPORTS_TITLE_PATTERN.test(event.title) || SERIES_SCOPE_PATTERN.test(event.title)) {
1951
+ return true;
1952
+ }
1953
+ return event.venueMarkets.some((market) => {
1954
+ const question = toTrimmedString(market.question);
1955
+ return ESPORTS_TITLE_PATTERN.test(question) || SERIES_SCOPE_PATTERN.test(question);
1956
+ });
1957
+ };
1958
+ var mergeSportsSectionMarketsIntoEvent = ({
1959
+ event,
1960
+ sectionMarketsByKey
1961
+ }) => {
1962
+ const orderedVenueMarkets = [...event.venueMarkets];
1963
+ const seenMarketIds = new Set(orderedVenueMarkets.map((market) => market.id));
1964
+ for (const markets of Object.values(sectionMarketsByKey)) {
1965
+ for (const market of markets != null ? markets : []) {
1966
+ if (seenMarketIds.has(market.id)) continue;
1967
+ seenMarketIds.add(market.id);
1968
+ orderedVenueMarkets.push(market);
1969
+ }
1970
+ }
1971
+ return __spreadProps(__spreadValues({}, event), { venueMarkets: orderedVenueMarkets });
1972
+ };
1973
+
1974
+ // src/pages/event-market/sports-market-card.tsx
1975
+ import {
1976
+ MarketStatus,
1977
+ resolveMarketTradingState,
1978
+ useEventTradingContext,
1979
+ useLabels as useLabels6,
1980
+ useSdkUiConfig as useSdkUiConfig2
1981
+ } from "@agg-build/hooks";
1982
+ import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState4 } from "react";
1983
+
1984
+ // src/pages/event-market/sports-line-rail.tsx
1985
+ import * as React from "react";
1986
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1987
+ function VenueRow({ venues, active }) {
1988
+ if (!venues || venues.length === 0) return /* @__PURE__ */ jsx4("span", { className: "h-4" });
1989
+ const shown = venues.length > 3 ? venues.slice(0, 2) : venues;
1990
+ const extra = venues.length - shown.length;
1991
+ return /* @__PURE__ */ jsxs4(
1992
+ "span",
1993
+ {
1994
+ className: cn(
1995
+ "flex h-4 items-center justify-center gap-1",
1996
+ !active && "text-agg-muted-foreground"
1997
+ ),
1998
+ children: [
1999
+ shown.map((venue, index) => /* @__PURE__ */ jsx4(
2000
+ VenueLogo,
2001
+ {
2002
+ venue,
2003
+ isMonochromatic: !active,
2004
+ size: "small",
2005
+ className: "size-3! shrink-0"
2006
+ },
2007
+ `${venue}-${index}`
2008
+ )),
2009
+ extra > 0 && /* @__PURE__ */ jsxs4("span", { className: "text-[10px] font-agg-bold uppercase leading-[14px] text-agg-muted-foreground", children: [
2010
+ "+",
2011
+ extra
2012
+ ] })
2013
+ ]
2014
+ }
2015
+ );
2016
+ }
2017
+ function SportsLineRail({
2018
+ stops,
2019
+ selectedIndex,
2020
+ onSelect,
2021
+ ariaLabel,
2022
+ previousAriaLabel,
2023
+ nextAriaLabel,
2024
+ className
2025
+ }) {
2026
+ const scrollRef = React.useRef(null);
2027
+ const itemRefs = React.useRef([]);
2028
+ const didInit = React.useRef(false);
2029
+ const programmatic = React.useRef(false);
2030
+ const progTimer = React.useRef(void 0);
2031
+ const skipCenterForIndex = React.useRef(null);
2032
+ const pendingScrollIndex = React.useRef(null);
2033
+ const scrollSettleTimer = React.useRef(void 0);
2034
+ const stopCount = stops.length;
2035
+ const [pad, setPad] = React.useState({ left: 0, right: 0 });
2036
+ const [mask, setMask] = React.useState({ left: false, right: false });
2037
+ const updateMask = React.useCallback(() => {
2038
+ const c = scrollRef.current;
2039
+ if (!c || !c.clientWidth) return;
2040
+ setMask({
2041
+ left: c.scrollLeft > 1,
2042
+ right: c.scrollLeft + c.clientWidth < c.scrollWidth - 1
2043
+ });
2044
+ }, []);
2045
+ const resolveNearestIndexToViewportCenter = React.useCallback(() => {
2046
+ const container = scrollRef.current;
2047
+ if (!container || !container.clientWidth) return null;
2048
+ const viewportCenter = container.scrollLeft + container.clientWidth / 2;
2049
+ let nearestIndex = null;
2050
+ let nearestDistance = Number.POSITIVE_INFINITY;
2051
+ itemRefs.current.forEach((item, index) => {
2052
+ if (!item) return;
2053
+ const itemCenter = item.offsetLeft + item.offsetWidth / 2;
2054
+ const distance = Math.abs(itemCenter - viewportCenter);
2055
+ if (distance < nearestDistance) {
2056
+ nearestDistance = distance;
2057
+ nearestIndex = index;
2058
+ }
2059
+ });
2060
+ return nearestIndex;
2061
+ }, []);
2062
+ React.useLayoutEffect(() => {
2063
+ const c = scrollRef.current;
2064
+ if (!c) return;
2065
+ const measure = () => {
2066
+ var _a, _b, _c, _d;
2067
+ const w = c.clientWidth;
2068
+ if (!w) return;
2069
+ const firstW = (_b = (_a = itemRefs.current[0]) == null ? void 0 : _a.offsetWidth) != null ? _b : 0;
2070
+ const lastW = (_d = (_c = itemRefs.current[stopCount - 1]) == null ? void 0 : _c.offsetWidth) != null ? _d : 0;
2071
+ const nextPad = {
2072
+ left: Math.max(0, w / 2 - firstW / 2),
2073
+ right: Math.max(0, w / 2 - lastW / 2)
2074
+ };
2075
+ setPad((currentPad) => {
2076
+ if (currentPad.left === nextPad.left && currentPad.right === nextPad.right) {
2077
+ return currentPad;
2078
+ }
2079
+ return nextPad;
2080
+ });
2081
+ updateMask();
2082
+ };
2083
+ const onScroll = () => {
2084
+ if (!programmatic.current) {
2085
+ const nearestIndex = resolveNearestIndexToViewportCenter();
2086
+ if (nearestIndex != null && nearestIndex !== selectedIndex) {
2087
+ pendingScrollIndex.current = nearestIndex;
2088
+ clearTimeout(scrollSettleTimer.current);
2089
+ scrollSettleTimer.current = setTimeout(() => {
2090
+ const nextIndex = pendingScrollIndex.current;
2091
+ if (nextIndex == null || nextIndex === selectedIndex) return;
2092
+ skipCenterForIndex.current = nextIndex;
2093
+ onSelect(nextIndex);
2094
+ }, 120);
2095
+ }
2096
+ }
2097
+ updateMask();
2098
+ };
2099
+ measure();
2100
+ const ro = new ResizeObserver(measure);
2101
+ ro.observe(c);
2102
+ c.addEventListener("scroll", onScroll, { passive: true });
2103
+ return () => {
2104
+ ro.disconnect();
2105
+ c.removeEventListener("scroll", onScroll);
2106
+ clearTimeout(scrollSettleTimer.current);
2107
+ };
2108
+ }, [onSelect, resolveNearestIndexToViewportCenter, selectedIndex, stopCount, updateMask]);
2109
+ React.useEffect(() => {
2110
+ pendingScrollIndex.current = selectedIndex;
2111
+ }, [selectedIndex]);
2112
+ React.useEffect(() => {
2113
+ const c = scrollRef.current;
2114
+ const el = itemRefs.current[selectedIndex];
2115
+ if (!c || !el || !c.clientWidth) return;
2116
+ if (skipCenterForIndex.current === selectedIndex) {
2117
+ skipCenterForIndex.current = null;
2118
+ updateMask();
2119
+ return;
2120
+ }
2121
+ skipCenterForIndex.current = null;
2122
+ const max = c.scrollWidth - c.clientWidth;
2123
+ const target = el.offsetLeft - c.clientWidth / 2 + el.clientWidth / 2;
2124
+ programmatic.current = true;
2125
+ c.scrollTo({
2126
+ left: Math.max(0, Math.min(max, target)),
2127
+ behavior: didInit.current ? "smooth" : "auto"
2128
+ });
2129
+ if (pad.left > 0 || pad.right > 0) didInit.current = true;
2130
+ clearTimeout(progTimer.current);
2131
+ progTimer.current = setTimeout(() => {
2132
+ programmatic.current = false;
2133
+ }, 500);
2134
+ updateMask();
2135
+ }, [selectedIndex, stopCount, pad, updateMask]);
2136
+ const clampStopIndex = (index) => Math.min(stops.length - 1, Math.max(0, index));
2137
+ const handleStopClick = (index) => {
2138
+ const next = clampStopIndex(index);
2139
+ if (next !== selectedIndex) {
2140
+ skipCenterForIndex.current = next;
2141
+ }
2142
+ onSelect(next);
2143
+ };
2144
+ const handleStep = (delta) => {
2145
+ const next = clampStopIndex(selectedIndex + delta);
2146
+ if (next !== selectedIndex) onSelect(next);
2147
+ };
2148
+ if (stopCount === 0) return null;
2149
+ return /* @__PURE__ */ jsxs4(
2150
+ "div",
2151
+ {
2152
+ className: cn("flex items-center justify-center gap-3 px-3 py-3 sm:gap-4 sm:px-5", className),
2153
+ "aria-label": ariaLabel,
2154
+ children: [
2155
+ /* @__PURE__ */ jsx4(
2156
+ "button",
2157
+ {
2158
+ type: "button",
2159
+ onClick: () => handleStep(-1),
2160
+ disabled: selectedIndex === 0,
2161
+ "aria-label": previousAriaLabel != null ? previousAriaLabel : "Previous line",
2162
+ className: "flex size-5! shrink-0 cursor-pointer items-center justify-center text-agg-muted-foreground transition-colors hover:text-agg-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary disabled:cursor-not-allowed disabled:opacity-30",
2163
+ children: /* @__PURE__ */ jsx4(Icon, { name: "chevron-left", className: "size-4" })
2164
+ }
2165
+ ),
2166
+ /* @__PURE__ */ jsxs4("div", { className: "relative min-w-0 flex-1", children: [
2167
+ /* @__PURE__ */ jsx4(
2168
+ "div",
2169
+ {
2170
+ ref: scrollRef,
2171
+ style: { paddingLeft: pad.left, paddingRight: pad.right },
2172
+ className: "flex items-end gap-1 overflow-x-hidden py-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
2173
+ children: stops.map((stop, index) => {
2174
+ const active = index === selectedIndex;
2175
+ return /* @__PURE__ */ jsxs4(
2176
+ "button",
2177
+ {
2178
+ type: "button",
2179
+ ref: (el) => {
2180
+ itemRefs.current[index] = el;
2181
+ },
2182
+ onClick: () => handleStopClick(index),
2183
+ disabled: stop.disabled,
2184
+ "aria-pressed": active,
2185
+ className: "flex shrink-0 cursor-pointer flex-col items-center gap-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-40",
2186
+ children: [
2187
+ /* @__PURE__ */ jsx4(
2188
+ "span",
2189
+ {
2190
+ className: cn(
2191
+ "flex h-8 min-w-[60px] items-center justify-center rounded-agg-full border px-3 text-agg-sm leading-agg-5 tabular-nums transition-colors",
2192
+ active ? "border-agg-primary bg-agg-secondary font-agg-bold text-agg-foreground" : "border-transparent bg-agg-secondary text-agg-muted-foreground hover:bg-agg-secondary-hover hover:text-agg-foreground"
2193
+ ),
2194
+ children: stop.value
2195
+ }
2196
+ ),
2197
+ /* @__PURE__ */ jsx4(VenueRow, { venues: stop.venues, active })
2198
+ ]
2199
+ },
2200
+ index
2201
+ );
2202
+ })
2203
+ }
2204
+ ),
2205
+ /* @__PURE__ */ jsx4(
2206
+ "span",
2207
+ {
2208
+ className: cn(
2209
+ "pointer-events-none absolute inset-y-0 left-0 w-8 bg-gradient-to-r from-agg-secondary to-transparent transition-opacity duration-200",
2210
+ mask.left ? "opacity-100" : "opacity-0"
2211
+ )
2212
+ }
2213
+ ),
2214
+ /* @__PURE__ */ jsx4(
2215
+ "span",
2216
+ {
2217
+ className: cn(
2218
+ "pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-agg-secondary to-transparent transition-opacity duration-200",
2219
+ mask.right ? "opacity-100" : "opacity-0"
2220
+ )
2221
+ }
2222
+ )
2223
+ ] }),
2224
+ /* @__PURE__ */ jsx4(
2225
+ "button",
2226
+ {
2227
+ type: "button",
2228
+ onClick: () => handleStep(1),
2229
+ disabled: selectedIndex === stopCount - 1,
2230
+ "aria-label": nextAriaLabel != null ? nextAriaLabel : "Next line",
2231
+ className: "flex size-5! shrink-0 cursor-pointer items-center justify-center text-agg-muted-foreground transition-colors hover:text-agg-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary disabled:cursor-not-allowed disabled:opacity-30",
2232
+ children: /* @__PURE__ */ jsx4(Icon, { name: "chevron-right", className: "size-4" })
2233
+ }
2234
+ )
2235
+ ]
2236
+ }
2237
+ );
2238
+ }
2239
+
2240
+ // src/pages/event-market/sports-market-card.tsx
2241
+ import { jsx as jsx5 } from "react/jsx-runtime";
2242
+ var resolveSpreadHeaderOutcomeItems = ({
2243
+ market,
2244
+ groupMarkets,
2245
+ midpointsResult
2246
+ }) => {
2247
+ var _a;
2248
+ const outcomes = (_a = market.venueMarketOutcomes) != null ? _a : [];
2249
+ const lineValue = market.lineValue;
2250
+ if (outcomes.length < 2 || lineValue == null) return void 0;
2251
+ const { favored, dog } = resolveSpreadOutcomeTeamNames(market, groupMarkets);
2252
+ if (!favored && !dog) return void 0;
2253
+ const magnitude = Math.abs(lineValue);
2254
+ const formatLine = (value) => `${value > 0 ? "+" : "\u2212"}${Number.isInteger(magnitude) ? String(magnitude) : magnitude.toFixed(1)}`;
2255
+ const isDogLeg = isSpreadUnderdogLeg(market);
2256
+ return [
2257
+ { index: isDogLeg ? 1 : 0, name: favored, signedLine: -magnitude, tone: "positive" },
2258
+ { index: isDogLeg ? 0 : 1, name: dog, signedLine: magnitude, tone: "negative" }
2259
+ ].flatMap(({ index, name, signedLine, tone }) => {
2260
+ var _a2;
2261
+ const outcome = outcomes[index];
2262
+ if (!outcome) return [];
2263
+ const label = name != null ? name : outcome.label.trim();
2264
+ const probability = midpointsResult == null ? void 0 : getDisplayOutcomePrice({
2265
+ outcomeId: outcome.id,
2266
+ outcomeLabel: outcome.label,
2267
+ bestMidpointsByOutcomeId: (_a2 = midpointsResult.bestMidpointsByOutcomeId) != null ? _a2 : midpointsResult.prices
2268
+ });
2269
+ return [
2270
+ {
2271
+ id: outcome.id,
2272
+ label,
2273
+ title: label,
2274
+ lineLabel: formatLine(signedLine),
2275
+ probability,
2276
+ isPriceLoading: (midpointsResult == null ? void 0 : midpointsResult.isLoading) === true && probability == null,
2277
+ tone,
2278
+ variant: "line",
2279
+ venue: market.venue
2280
+ }
2281
+ ];
2282
+ });
2283
+ };
2284
+ var resolveDisplayedOutcomes = ({
2285
+ market,
2286
+ venueMarkets,
2287
+ groupMarkets,
2288
+ useSpreadOverride
2289
+ }) => {
2290
+ var _a;
2291
+ const spreadHeaderOutcomeItems = useSpreadOverride ? resolveSpreadHeaderOutcomeItems({ market, groupMarkets }) : void 0;
2292
+ const resolvedMarket = resolveMarketFromVenueMarkets(venueMarkets, market.id);
2293
+ const headerOutcomeItems = spreadHeaderOutcomeItems != null ? spreadHeaderOutcomeItems : resolveHeaderOutcomeItems(
2294
+ (_a = resolvedMarket == null ? void 0 : resolvedMarket.venueMarkets) != null ? _a : [market],
2295
+ market,
2296
+ resolveSportsMarketCardVariant(market)
2297
+ );
2298
+ return headerOutcomeItems.flatMap((item) => {
2299
+ const outcome = market.venueMarketOutcomes.find((candidate) => candidate.id === item.id);
2300
+ return outcome ? [outcome] : [];
2301
+ });
2302
+ };
2303
+ var resolveSelectedOutcomeSide = ({
2304
+ displayedOutcomes,
2305
+ selectedOutcomeId
2306
+ }) => {
2307
+ const selectedOutcomeIndex = displayedOutcomes.findIndex(
2308
+ (outcome) => outcome.id === selectedOutcomeId
2309
+ );
2310
+ if (selectedOutcomeIndex === 0) return "left";
2311
+ if (selectedOutcomeIndex === 1) return "right";
2312
+ return null;
2313
+ };
2314
+ var resolveOutcomeBySide = (displayedOutcomes, side) => {
2315
+ var _a;
2316
+ return (_a = displayedOutcomes[side === "right" ? 1 : 0]) != null ? _a : displayedOutcomes[0];
2317
+ };
2318
+ var SportsMarketCard = ({
2319
+ group,
2320
+ venueMarkets,
2321
+ isExpanded,
2322
+ onToggle,
2323
+ onOutcomeSelect,
2324
+ live,
2325
+ midpointsFallback,
2326
+ midpointsFallbackVenues,
2327
+ midpointsResult
2328
+ }) => {
2329
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2330
+ const labels = useLabels6();
2331
+ const {
2332
+ formatting: { formatCompactCurrency }
2333
+ } = useSdkUiConfig2();
2334
+ const tradingContext = useEventTradingContext();
2335
+ const slide = useMemo2(() => buildSportsSlideFromGroup(group), [group]);
2336
+ const [selectedLineIndex, setSelectedLineIndex] = useState4(slide.defaultStopIndex);
2337
+ const combinedLegs = useMemo2(() => resolveSportsCombinedLegs(group), [group]);
2338
+ const isCombinedLegGroup = combinedLegs != null;
2339
+ const combinedLegMarkets = useMemo2(
2340
+ () => {
2341
+ var _a2;
2342
+ return (_a2 = combinedLegs == null ? void 0 : combinedLegs.map((leg) => leg.market)) != null ? _a2 : [];
2343
+ },
2344
+ [combinedLegs]
2345
+ );
2346
+ const preferredResolvedLegMarket = useMemo2(() => {
2347
+ var _a2, _b2;
2348
+ const resolvedYesWinnerMarket = (_a2 = combinedLegMarkets.find(
2349
+ (market) => market.venueMarketOutcomes.some(
2350
+ (outcome) => outcome.winner === true && outcome.label.trim().toLowerCase() === "yes"
2351
+ )
2352
+ )) != null ? _a2 : null;
2353
+ if (resolvedYesWinnerMarket) return resolvedYesWinnerMarket;
2354
+ return (_b2 = combinedLegMarkets.find(
2355
+ (market) => market.venueMarketOutcomes.some((outcome) => outcome.winner === true)
2356
+ )) != null ? _b2 : null;
2357
+ }, [combinedLegMarkets]);
2358
+ useEffect3(() => {
2359
+ if (!slide.hasLadder) return;
2360
+ const tradingMarketId = tradingContext == null ? void 0 : tradingContext.selectedMarketId;
2361
+ if (!tradingMarketId) return;
2362
+ const matchedIndex = slide.stops.findIndex((stop) => stop.market.id === tradingMarketId);
2363
+ if (matchedIndex >= 0) setSelectedLineIndex(matchedIndex);
2364
+ }, [slide.hasLadder, slide.stops, tradingContext == null ? void 0 : tradingContext.selectedMarketId]);
2365
+ const activeLegMarket = isCombinedLegGroup ? preferredResolvedLegMarket != null ? preferredResolvedLegMarket : (tradingContext == null ? void 0 : tradingContext.selectedMarketId) ? (_a = group.markets.find((market) => market.id === tradingContext.selectedMarketId)) != null ? _a : null : null : null;
2366
+ const activeMarket = slide.hasLadder ? (_d = (_c = (_b = slide.stops[selectedLineIndex]) == null ? void 0 : _b.market) != null ? _c : group.markets[0]) != null ? _d : null : (_f = (_e = activeLegMarket != null ? activeLegMarket : combinedLegMarkets[0]) != null ? _e : group.markets[0]) != null ? _f : null;
2367
+ const activeDefaultOutcome = isCombinedLegGroup && activeMarket ? (_g = activeMarket.venueMarketOutcomes.find(
2368
+ (outcome) => outcome.label.trim().toLowerCase() === "yes"
2369
+ )) != null ? _g : activeMarket.venueMarketOutcomes[0] : activeMarket == null ? void 0 : activeMarket.venueMarketOutcomes[0];
2370
+ const wasExpandedRef = useRef2(isExpanded);
2371
+ useEffect3(() => {
2372
+ const justOpened = isExpanded && !wasExpandedRef.current;
2373
+ wasExpandedRef.current = isExpanded;
2374
+ if (!justOpened || !activeMarket) return;
2375
+ if (resolveMarketTradingState(activeMarket).isTradingDisabled) return;
2376
+ const selectedOutcomeId = tradingContext == null ? void 0 : tradingContext.selectedOutcomeId;
2377
+ const hasInScopeOutcome = selectedOutcomeId != null && activeMarket.venueMarketOutcomes.some((outcome) => outcome.id === selectedOutcomeId);
2378
+ if (hasInScopeOutcome) return;
2379
+ const firstOutcome = activeDefaultOutcome;
2380
+ if (firstOutcome) {
2381
+ tradingContext == null ? void 0 : tradingContext.selectMarketAndOutcome(activeMarket.id, firstOutcome.id);
2382
+ }
2383
+ }, [activeDefaultOutcome, isExpanded, activeMarket, tradingContext]);
2384
+ const combinedLegHeaderOutcomeItems = useMemo2(() => {
2385
+ if (!combinedLegs) return void 0;
2386
+ return combinedLegs.flatMap(({ label, market }, index) => {
2387
+ var _a2;
2388
+ const yesOutcome = market.venueMarketOutcomes.find(
2389
+ (outcome) => outcome.label.trim().toLowerCase() === "yes"
2390
+ );
2391
+ if (!yesOutcome) return [];
2392
+ const probability = midpointsResult == null ? void 0 : getDisplayOutcomePrice({
2393
+ outcomeId: yesOutcome.id,
2394
+ outcomeLabel: yesOutcome.label,
2395
+ bestMidpointsByOutcomeId: (_a2 = midpointsResult.bestMidpointsByOutcomeId) != null ? _a2 : midpointsResult.prices
2396
+ });
2397
+ return [
2398
+ {
2399
+ id: yesOutcome.id,
2400
+ label,
2401
+ title: label,
2402
+ probability,
2403
+ isPriceLoading: (midpointsResult == null ? void 0 : midpointsResult.isLoading) === true && probability == null,
2404
+ tone: index === 0 ? "positive" : "negative",
2405
+ variant: "outcome",
2406
+ venue: market.venue
2407
+ }
2408
+ ];
2409
+ });
2410
+ }, [combinedLegs, midpointsResult]);
2411
+ const spreadHeaderOutcomeItems = useMemo2(() => {
2412
+ if (slide.kind !== "spread" || !activeMarket) return void 0;
2413
+ return resolveSpreadHeaderOutcomeItems({
2414
+ market: activeMarket,
2415
+ groupMarkets: group.markets,
2416
+ midpointsResult
2417
+ });
2418
+ }, [slide.kind, activeMarket, group.markets, midpointsResult]);
2419
+ if (!activeMarket) return null;
2420
+ const selectedStop = slide.hasLadder ? slide.stops[selectedLineIndex] : void 0;
2421
+ const cardTitle = selectedStop ? resolveSportsLadderTitle(group, selectedStop.value) : group.title;
2422
+ const activeOutcome = (_h = activeMarket.venueMarketOutcomes.find(
2423
+ (outcome) => outcome.id === (tradingContext == null ? void 0 : tradingContext.selectedOutcomeId)
2424
+ )) != null ? _h : activeDefaultOutcome;
2425
+ const activeOutcomeVenueCount = (() => {
2426
+ var _a2, _b2;
2427
+ if (!activeOutcome) return collectVenueNames(activeMarket).length;
2428
+ const venueNames = /* @__PURE__ */ new Set([activeMarket.venue]);
2429
+ for (const matchedOutcome of (_a2 = activeOutcome.matchedVenueMarketOutcomes) != null ? _a2 : []) {
2430
+ const matchedVenueMarket = (_b2 = activeMarket.matchedVenueMarkets) == null ? void 0 : _b2.find(
2431
+ (market) => market.id === matchedOutcome.venueMarketId
2432
+ );
2433
+ if (matchedVenueMarket == null ? void 0 : matchedVenueMarket.venue) {
2434
+ venueNames.add(matchedVenueMarket.venue);
2435
+ }
2436
+ }
2437
+ return venueNames.size > 0 ? venueNames.size : collectVenueNames(activeMarket).length;
2438
+ })();
2439
+ const activeMarketVolume = resolveSportsExpandedMarketsVolume([activeMarket]);
2440
+ const totalGroupVolume = resolveSportsExpandedMarketsVolume(group.markets);
2441
+ const compactSubtitle = `${activeOutcomeVenueCount} ${activeOutcomeVenueCount === 1 ? labels.marketDetails.meta.venueSingular : labels.marketDetails.meta.venuePlural} \xB7 ${formatCompactCurrency(activeMarketVolume || resolveTotalGroupVolume([activeMarket]))} ${labels.eventMarketPage.sports.volumeShort} \xB7 ${formatCompactCurrency(totalGroupVolume || resolveTotalGroupVolume(group.markets))} ${labels.eventMarketPage.sports.totalVolumeShort}`;
2442
+ const headerOutcomeItemsOverride = combinedLegHeaderOutcomeItems != null ? combinedLegHeaderOutcomeItems : spreadHeaderOutcomeItems;
2443
+ const headerOutcomeVariant = isCombinedLegGroup ? "outcome" : resolveSportsMarketCardVariant(activeMarket);
2444
+ const handleLineSelect = (index) => {
2445
+ var _a2, _b2, _c2;
2446
+ const targetMarket = (_a2 = slide.stops[index]) == null ? void 0 : _a2.market;
2447
+ if (!targetMarket) return;
2448
+ const selectedMarket = (_c2 = (_b2 = tradingContext == null ? void 0 : tradingContext.selectedMarket) != null ? _b2 : venueMarkets.find((market) => market.id === (tradingContext == null ? void 0 : tradingContext.selectedMarketId))) != null ? _c2 : null;
2449
+ const selectedMarketIsInGroup = selectedMarket != null && group.markets.some((market) => market.id === selectedMarket.id);
2450
+ const selectedSide = selectedMarket ? resolveSelectedOutcomeSide({
2451
+ displayedOutcomes: resolveDisplayedOutcomes({
2452
+ market: selectedMarket,
2453
+ venueMarkets,
2454
+ groupMarkets: group.markets,
2455
+ useSpreadOverride: slide.kind === "spread" && selectedMarketIsInGroup
2456
+ }),
2457
+ selectedOutcomeId: tradingContext == null ? void 0 : tradingContext.selectedOutcomeId
2458
+ }) : null;
2459
+ const targetDisplayedOutcomes = resolveDisplayedOutcomes({
2460
+ market: targetMarket,
2461
+ venueMarkets,
2462
+ groupMarkets: group.markets,
2463
+ useSpreadOverride: slide.kind === "spread"
2464
+ });
2465
+ const nextOutcome = resolveOutcomeBySide(targetDisplayedOutcomes, selectedSide != null ? selectedSide : "left");
2466
+ setSelectedLineIndex(index);
2467
+ if (nextOutcome) {
2468
+ tradingContext == null ? void 0 : tradingContext.selectMarketAndOutcome(targetMarket.id, nextOutcome.id);
2469
+ onOutcomeSelect == null ? void 0 : onOutcomeSelect(group.id, {
2470
+ marketId: targetMarket.id,
2471
+ outcomeId: nextOutcome.id
2472
+ });
2473
+ } else {
2474
+ tradingContext == null ? void 0 : tradingContext.selectMarket(targetMarket.id, targetMarket);
2475
+ }
2476
+ };
2477
+ return /* @__PURE__ */ jsx5(
2478
+ MarketDetails,
2479
+ {
2480
+ marketId: activeMarket.id,
2481
+ venueMarkets,
2482
+ title: cardTitle,
2483
+ compactHeader: true,
2484
+ subtitleOverride: compactSubtitle,
2485
+ headerOutcomeVariant,
2486
+ headerOutcomeItemsOverride,
2487
+ isOpened: isExpanded,
2488
+ suppressOutcomeFallbackSelection: activeMarket.id !== (tradingContext == null ? void 0 : tradingContext.selectedMarketId),
2489
+ onOpenChange: () => onToggle(group.id, activeMarket),
2490
+ onOutcomeSelect: (selection) => onOutcomeSelect == null ? void 0 : onOutcomeSelect(group.id, selection),
2491
+ headerAccessory: slide.hasLadder ? /* @__PURE__ */ jsx5(
2492
+ SportsLineRail,
2493
+ {
2494
+ stops: slide.stops.map((stop) => ({
2495
+ value: stop.value,
2496
+ venues: stop.venues,
2497
+ disabled: stop.market.status !== MarketStatus.open
2498
+ })),
2499
+ selectedIndex: selectedLineIndex,
2500
+ onSelect: handleLineSelect,
2501
+ ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(cardTitle),
2502
+ previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(cardTitle),
2503
+ nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(cardTitle)
2504
+ }
2505
+ ) : void 0,
2506
+ classNames: { root: "agg-market-list-item agg-sports-market-card" },
2507
+ live,
2508
+ midpointsFallback,
2509
+ midpointsFallbackVenues,
2510
+ midpointsResult
2511
+ }
2512
+ );
2513
+ };
2514
+ SportsMarketCard.displayName = "SportsMarketCard";
2515
+
2516
+ // src/pages/event-market/sports-markets.tsx
2517
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
2518
+ var STAT_LABEL_OVERRIDES = {
2519
+ rbis: "RBIs",
2520
+ hits_runs_rbis: "Hits + Runs + RBIs",
2521
+ ot: "OT"
2522
+ };
2523
+ var formatStatLabel = (stat) => {
2524
+ var _a;
2525
+ return (_a = STAT_LABEL_OVERRIDES[stat]) != null ? _a : stat.split("_").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
2526
+ };
2527
+ var LEGACY_STAT_LABEL_KEYS = {
2528
+ corners: "cornersTab",
2529
+ goals: "goalsTab",
2530
+ assists: "assistsTab",
2531
+ shots: "shotsTab"
2532
+ };
2533
+ var SPORTS_PERIOD_LABEL_KEYS = {
2534
+ full: "fullPeriod",
2535
+ "1h": "firstHalfPeriod",
2536
+ "2h": "secondHalfPeriod",
2537
+ q1: "quarterOnePeriod",
2538
+ q2: "quarterTwoPeriod",
2539
+ q3: "quarterThreePeriod",
2540
+ q4: "quarterFourPeriod",
2541
+ ot: "overtimePeriod"
2542
+ };
2543
+ var resolveSportsPeriodLabel = (labels, period) => {
2544
+ var _a;
2545
+ const sports = labels.eventMarketPage.sports;
2546
+ const labelKey = SPORTS_PERIOD_LABEL_KEYS[period];
2547
+ if (labelKey && typeof sports[labelKey] === "string") return sports[labelKey];
2548
+ return (_a = formatSportsPeriodGrammarLabel(period)) != null ? _a : formatStatLabel(period);
2549
+ };
2550
+ var resolveSportsSectionLabel = (labels, tab) => {
2551
+ var _a, _b, _c, _d, _e;
2552
+ const sports = labels.eventMarketPage.sports;
2553
+ switch (tab.kind) {
2554
+ case "game_lines":
2555
+ return sports.gameLinesTab;
2556
+ case "exact_score":
2557
+ return sports.exactScoreTab;
2558
+ case "other":
2559
+ return sports.otherTab;
2560
+ case "stat": {
2561
+ if (tab.stat === "player_props") return sports.playerPropsTab;
2562
+ const legacyLabelKey = tab.stat ? LEGACY_STAT_LABEL_KEYS[tab.stat] : void 0;
2563
+ return legacyLabelKey ? sports[legacyLabelKey] : formatStatLabel((_a = tab.stat) != null ? _a : "");
2564
+ }
2565
+ case "period": {
2566
+ switch (tab.periodFamily) {
2567
+ case "halves":
2568
+ return sports.halvesTab;
2569
+ case "quarters":
2570
+ return sports.quartersTab;
2571
+ case "sets":
2572
+ return sports.setsTab;
2573
+ default:
2574
+ return (_e = (_c = formatSportsPeriodGrammarLabel((_b = tab.periodFamily) != null ? _b : "")) == null ? void 0 : _c.replace(/^First /, "")) != null ? _e : formatStatLabel((_d = tab.periodFamily) != null ? _d : "");
2575
+ }
2576
+ }
2577
+ }
2578
+ };
2579
+ var SportsTabButton = ({
2580
+ isActive,
2581
+ label,
2582
+ onClick
2583
+ }) => {
2584
+ return /* @__PURE__ */ jsx6(
2585
+ "button",
2586
+ {
2587
+ type: "button",
2588
+ role: "tab",
2589
+ "aria-selected": isActive,
2590
+ "data-testid": "sports-section-tab",
2591
+ className: cn(
2592
+ "inline-flex h-9 shrink-0 cursor-pointer items-center justify-center rounded-agg-full border px-4 text-agg-sm leading-agg-5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary focus-visible:ring-offset-2 focus-visible:ring-offset-agg-secondary",
2593
+ isActive ? "border-agg-primary bg-agg-secondary font-agg-bold text-agg-foreground" : "border-transparent bg-agg-secondary-hover font-agg-normal text-agg-foreground hover:bg-agg-tertiary"
2594
+ ),
2595
+ onClick,
2596
+ children: label
2597
+ }
2598
+ );
2599
+ };
2600
+ var SportsMarketsLoadingState = () => {
2601
+ const labels = useLabels7();
2602
+ return /* @__PURE__ */ jsxs5(
2603
+ "div",
2604
+ {
2605
+ className: "flex flex-col gap-3",
2606
+ role: "status",
2607
+ "aria-label": labels.eventMarketPage.sports.loadingTitle,
2608
+ children: [
2609
+ /* @__PURE__ */ jsx6("span", { className: "sr-only", children: labels.eventMarketPage.sports.loadingDescription }),
2610
+ Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxs5(
2611
+ "div",
2612
+ {
2613
+ className: "flex min-h-[76px] animate-pulse flex-col gap-3 rounded-agg-2xl border border-agg-separator bg-agg-secondary px-5 py-3 sm:flex-row sm:items-center sm:justify-between",
2614
+ children: [
2615
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
2616
+ /* @__PURE__ */ jsx6("div", { className: "h-5 w-32 rounded-agg-sm bg-agg-secondary-hover" }),
2617
+ /* @__PURE__ */ jsx6("div", { className: "h-4 w-40 rounded-agg-sm bg-agg-secondary-hover" })
2618
+ ] }),
2619
+ /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
2620
+ /* @__PURE__ */ jsx6("div", { className: "h-9 w-32 rounded-agg-full bg-agg-secondary-hover" }),
2621
+ /* @__PURE__ */ jsx6("div", { className: "hidden h-9 w-32 rounded-agg-full bg-agg-secondary-hover sm:block" })
2622
+ ] })
2623
+ ]
2624
+ },
2625
+ `sports-card-skeleton-${index}`
2626
+ ))
2627
+ ]
2628
+ }
2629
+ );
2630
+ };
2631
+ var SportsMarkets = ({
2632
+ event,
2633
+ onSectionMarketsChange,
2634
+ onOutcomeSelect,
2635
+ live,
2636
+ midpointsResult
2637
+ }) => {
2638
+ var _a, _b;
2639
+ const labels = useLabels7();
2640
+ const tradingContext = useEventTradingContext2();
2641
+ const hasAggKey = Boolean(event.aggKey);
2642
+ const gameMarketsQuery = useVenueMarkets({
2643
+ aggKey: event.aggKey ? [event.aggKey] : void 0,
2644
+ limit: 100,
2645
+ status: MarketStatus2.open,
2646
+ enabled: hasAggKey
2647
+ });
2648
+ const {
2649
+ markets: gameMarkets,
2650
+ hasNextPage: hasNextGameMarketsPage,
2651
+ isFetchingNextPage: isFetchingNextGameMarketsPage,
2652
+ fetchNextPage: fetchNextGameMarketsPage
2653
+ } = gameMarketsQuery;
2654
+ const tabSourceMarkets = useMemo3(() => {
2655
+ const seen = /* @__PURE__ */ new Set();
2656
+ const merged = [];
2657
+ for (const market of [...event.venueMarkets, ...gameMarkets]) {
2658
+ if (seen.has(market.id)) continue;
2659
+ seen.add(market.id);
2660
+ merged.push(market);
2661
+ }
2662
+ return merged;
2663
+ }, [event.venueMarkets, gameMarkets]);
2664
+ const visibleTabs = useMemo3(
2665
+ () => resolveVisibleSportsSectionTabs(__spreadProps(__spreadValues({}, event), { venueMarkets: tabSourceMarkets })),
2666
+ [event, tabSourceMarkets]
2667
+ );
2668
+ const shouldRenderTabs = visibleTabs.length > 1 && tabSourceMarkets.length > 1;
2669
+ const [activeTabKey, setActiveTabKey] = useState5((_b = (_a = visibleTabs[0]) == null ? void 0 : _a.key) != null ? _b : "game_lines");
2670
+ const activeTab = useMemo3(
2671
+ () => {
2672
+ var _a2, _b2;
2673
+ return (_b2 = (_a2 = visibleTabs.find((tab) => tab.key === activeTabKey)) != null ? _a2 : visibleTabs[0]) != null ? _b2 : { key: "game_lines", kind: "game_lines" };
2674
+ },
2675
+ [visibleTabs, activeTabKey]
2676
+ );
2677
+ const [expandedGroupId, setExpandedGroupId] = useState5(null);
2678
+ const [stableMarketsByTab, setStableMarketsByTab] = useState5({});
2679
+ const activeTabLabel = resolveSportsSectionLabel(labels, activeTab);
2680
+ const sectionFilters = resolveSportsSectionFilters(activeTab);
2681
+ const sectionMarketsQuery = useVenueMarkets({
2682
+ aggKey: event.aggKey ? [event.aggKey] : void 0,
2683
+ sportsMarketType: sectionFilters.sportsMarketType,
2684
+ period: sectionFilters.period,
2685
+ marketCategory: sectionFilters.marketCategory,
2686
+ marketGroup: sectionFilters.marketGroup,
2687
+ // The per-tab section fetch paginates; a large page (schema max) collapses a
2688
+ // heavy tab (e.g. "Other" spans other/team_props/player_props/specials/
2689
+ // completion — hundreds of markets on prop-rich events) from ~15 calls to 1-3.
2690
+ limit: 100,
2691
+ status: MarketStatus2.open,
2692
+ enabled: hasAggKey
2693
+ });
2694
+ const {
2695
+ markets: sectionMarkets,
2696
+ isLoading: isSectionLoading,
2697
+ hasNextPage,
2698
+ isFetchingNextPage,
2699
+ fetchNextPage
2700
+ } = sectionMarketsQuery;
2701
+ const resolvedSectionMarkets = useMemo3(
2702
+ () => resolveSportsSectionMarkets({
2703
+ tab: activeTab,
2704
+ eventMarkets: tabSourceMarkets,
2705
+ sectionMarkets,
2706
+ sport: event.sport
2707
+ }),
2708
+ [activeTab, tabSourceMarkets, sectionMarkets, event.sport]
2709
+ );
2710
+ const isSectionSettled = !isSectionLoading && !hasNextPage && !isFetchingNextPage;
2711
+ const stableSectionMarkets = stableMarketsByTab[activeTabKey];
2712
+ const displayedSectionMarkets = useMemo3(
2713
+ () => stableSectionMarkets != null ? stableSectionMarkets : isSectionSettled ? resolvedSectionMarkets : [],
2714
+ [stableSectionMarkets, isSectionSettled, resolvedSectionMarkets]
2715
+ );
2716
+ const periodGroups = useMemo3(
2717
+ () => groupSportsMarketsByPeriod(displayedSectionMarkets, event.sport),
2718
+ [displayedSectionMarkets, event.sport]
2719
+ );
2720
+ const allGroups = useMemo3(
2721
+ () => periodGroups.flatMap((periodGroup) => periodGroup.groups),
2722
+ [periodGroups]
2723
+ );
2724
+ useEffect4(() => {
2725
+ if (hasNextPage && !isFetchingNextPage) {
2726
+ void fetchNextPage();
2727
+ }
2728
+ }, [hasNextPage, isFetchingNextPage, fetchNextPage]);
2729
+ useEffect4(() => {
2730
+ if (hasNextGameMarketsPage && !isFetchingNextGameMarketsPage) {
2731
+ void fetchNextGameMarketsPage();
2732
+ }
2733
+ }, [hasNextGameMarketsPage, isFetchingNextGameMarketsPage, fetchNextGameMarketsPage]);
2734
+ useEffect4(() => {
2735
+ if (!isSectionSettled) return;
2736
+ setStableMarketsByTab((currentStableMarketsByTab) => {
2737
+ var _a2;
2738
+ const currentMarkets = (_a2 = currentStableMarketsByTab[activeTabKey]) != null ? _a2 : [];
2739
+ if (currentMarkets.length === resolvedSectionMarkets.length && currentMarkets.every((market, index) => {
2740
+ var _a3;
2741
+ return market.id === ((_a3 = resolvedSectionMarkets[index]) == null ? void 0 : _a3.id);
2742
+ })) {
2743
+ return currentStableMarketsByTab;
2744
+ }
2745
+ return __spreadProps(__spreadValues({}, currentStableMarketsByTab), {
2746
+ [activeTabKey]: resolvedSectionMarkets
2747
+ });
2748
+ });
2749
+ }, [activeTabKey, isSectionSettled, resolvedSectionMarkets]);
2750
+ useEffect4(() => {
2751
+ if (!hasAggKey) return;
2752
+ onSectionMarketsChange(activeTabKey, displayedSectionMarkets);
2753
+ }, [activeTabKey, displayedSectionMarkets, hasAggKey, onSectionMarketsChange]);
2754
+ useEffect4(() => {
2755
+ var _a2, _b2;
2756
+ if (visibleTabs.some((tab) => tab.key === activeTabKey)) return;
2757
+ setActiveTabKey((_b2 = (_a2 = visibleTabs[0]) == null ? void 0 : _a2.key) != null ? _b2 : "game_lines");
2758
+ }, [activeTabKey, visibleTabs]);
2759
+ const lastActiveTabRef = useRef3(null);
2760
+ useEffect4(() => {
2761
+ if (allGroups.length === 0) return;
2762
+ if (lastActiveTabRef.current !== activeTabKey) {
2763
+ lastActiveTabRef.current = activeTabKey;
2764
+ setExpandedGroupId(null);
2765
+ return;
2766
+ }
2767
+ if (expandedGroupId && !allGroups.some((group) => group.id === expandedGroupId)) {
2768
+ setExpandedGroupId(null);
2769
+ }
2770
+ }, [activeTabKey, allGroups, expandedGroupId]);
2771
+ const handleToggleGroup = (groupId, market) => {
2772
+ if (groupId === expandedGroupId) {
2773
+ setExpandedGroupId(null);
2774
+ return;
2775
+ }
2776
+ setExpandedGroupId(groupId);
2777
+ if (resolveMarketTradingState2(market).isTradingDisabled) return;
2778
+ if (market.id !== (tradingContext == null ? void 0 : tradingContext.selectedMarketId)) {
2779
+ tradingContext == null ? void 0 : tradingContext.selectMarket(market.id, market);
2780
+ }
2781
+ };
2782
+ const handleGroupOutcomeSelect = (groupId) => {
2783
+ setExpandedGroupId(groupId);
2784
+ onOutcomeSelect == null ? void 0 : onOutcomeSelect();
2785
+ };
2786
+ if (!hasAggKey && event.venueMarkets.length === 0) {
2787
+ return /* @__PURE__ */ jsx6(
2788
+ StateMessage,
2789
+ {
2790
+ title: labels.eventMarketPage.sports.emptyTitle,
2791
+ description: labels.eventMarketPage.unavailableDescription,
2792
+ icon: /* @__PURE__ */ jsx6(Icon, { name: "warning", className: "h-10 w-10 text-agg-warning" }),
2793
+ classNames: { root: "min-h-[220px]" }
2794
+ }
2795
+ );
2796
+ }
2797
+ const shouldShowLoadingState = stableSectionMarkets == null && !isSectionSettled;
2798
+ return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3", "data-testid": "sports-markets", children: [
2799
+ shouldRenderTabs ? /* @__PURE__ */ jsx6(
2800
+ "div",
2801
+ {
2802
+ role: "tablist",
2803
+ "aria-label": labels.eventMarketPage.sports.sectionTabsAria,
2804
+ className: "flex flex-nowrap items-center gap-2 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
2805
+ children: visibleTabs.map((tab) => /* @__PURE__ */ jsx6(
2806
+ SportsTabButton,
2807
+ {
2808
+ isActive: tab.key === activeTabKey,
2809
+ label: resolveSportsSectionLabel(labels, tab),
2810
+ onClick: () => setActiveTabKey(tab.key)
2811
+ },
2812
+ tab.key
2813
+ ))
2814
+ }
2815
+ ) : null,
2816
+ shouldShowLoadingState ? /* @__PURE__ */ jsx6(SportsMarketsLoadingState, {}) : null,
2817
+ !shouldShowLoadingState && allGroups.length === 0 ? /* @__PURE__ */ jsx6(
2818
+ StateMessage,
2819
+ {
2820
+ title: labels.eventMarketPage.sports.emptyTitle,
2821
+ description: labels.eventMarketPage.sports.emptyDescription(activeTabLabel),
2822
+ icon: /* @__PURE__ */ jsx6(Icon, { name: "search", className: "h-10 w-10 text-agg-muted-foreground" }),
2823
+ classNames: { root: "min-h-[220px]" }
2824
+ }
2825
+ ) : null,
2826
+ periodGroups.map((periodGroup) => {
2827
+ return /* @__PURE__ */ jsxs5(
2828
+ "section",
2829
+ {
2830
+ className: "flex flex-col gap-3",
2831
+ "data-period-key": periodGroup.key,
2832
+ children: [
2833
+ periodGroups.length > 1 ? /* @__PURE__ */ jsx6(
2834
+ "h3",
2835
+ {
2836
+ "data-testid": "sports-period-heading",
2837
+ className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-muted-foreground",
2838
+ children: resolveSportsPeriodLabel(labels, periodGroup.key)
2839
+ }
2840
+ ) : null,
2841
+ periodGroup.groups.map((group) => /* @__PURE__ */ jsx6(
2842
+ SportsMarketCard,
2843
+ {
2844
+ group,
2845
+ venueMarkets: displayedSectionMarkets,
2846
+ isExpanded: expandedGroupId === group.id,
2847
+ onToggle: handleToggleGroup,
2848
+ onOutcomeSelect: (_groupId, _selection) => handleGroupOutcomeSelect(group.id),
2849
+ live,
2850
+ midpointsResult
2851
+ },
2852
+ group.id
2853
+ ))
2854
+ ]
2855
+ },
2856
+ `${activeTabKey}-${periodGroup.key}`
2857
+ );
2858
+ })
2859
+ ] });
2860
+ };
2861
+ SportsMarkets.displayName = "SportsMarkets";
2862
+
2863
+ // src/pages/event-market/sports-event-market-page.tsx
2864
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2865
+ var areSportsSectionMarketsEqual = (leftMarkets, rightMarkets) => {
2866
+ if (leftMarkets.length !== rightMarkets.length) return false;
2867
+ return leftMarkets.every((market, index) => {
2868
+ var _a;
2869
+ return market.id === ((_a = rightMarkets[index]) == null ? void 0 : _a.id);
2870
+ });
2871
+ };
2872
+ var SportsEventMarketPage = ({
2873
+ event,
2874
+ defaultMarketId,
2875
+ defaultOutcomeId,
2876
+ defaultTradeSide,
2877
+ defaultChartView,
2878
+ classNames,
2879
+ ariaLabel,
2880
+ showPlaceOrder,
2881
+ executionMode,
2882
+ stickyOrderPanel,
2883
+ resolvedClaim,
2884
+ onBeforePrimaryAction,
2885
+ sharedKyc
2886
+ }) => {
2887
+ const [sectionMarketsByKey, setSectionMarketsByKey] = useState6({});
2888
+ const composedEvent = useMemo4(() => {
2889
+ return mergeSportsSectionMarketsIntoEvent({
2890
+ event,
2891
+ sectionMarketsByKey
2892
+ });
2893
+ }, [event, sectionMarketsByKey]);
2894
+ const eventTradingState = useMemo4(() => resolveEventTradingState2(composedEvent), [composedEvent]);
2895
+ const hasSportsSections = useMemo4(
2896
+ () => resolveVisibleSportsSectionTabs(event).length > 0,
2897
+ [event]
2898
+ );
2899
+ const stickyOrderPanelState = resolveEventMarketPageStickyState({
2900
+ stickyOrderPanel
2901
+ });
2902
+ const { executionMode: resolvedExecutionMode } = useResolvedExecutionMode(executionMode);
2903
+ const [isMobileTradeOpen, setIsMobileTradeOpen] = useState6(false);
2904
+ const isMobileViewport = useIsMobileEventMarketViewport(SPORTS_EVENT_MARKET_MEDIA_QUERY);
2905
+ const tradingContext = useEventTradingContext3();
2906
+ const { stateByEventId: sportsLiveStateByEventId } = useSportsLive([event.id]);
2907
+ const midpointsResult = useMidpoints(composedEvent.venueMarkets);
2908
+ const internalResolvedClaim = useResolvedMarketClaim({
2909
+ market: eventTradingState.primaryMarket,
2910
+ enabled: eventTradingState.kind === "resolved",
2911
+ executionMode: resolvedExecutionMode
2912
+ });
2913
+ const effectiveResolvedClaim = resolvedClaim != null ? resolvedClaim : internalResolvedClaim;
2914
+ const setTradeSideRef = useRef4(tradingContext == null ? void 0 : tradingContext.setTradeSide);
2915
+ setTradeSideRef.current = tradingContext == null ? void 0 : tradingContext.setTradeSide;
2916
+ useEffect5(() => {
2917
+ return () => {
2918
+ var _a;
2919
+ (_a = setTradeSideRef.current) == null ? void 0 : _a.call(setTradeSideRef, TradeSide.Buy);
2920
+ };
2921
+ }, []);
2922
+ const handleSectionMarketsChange = useCallback4(
2923
+ (tabKey, markets) => {
2924
+ setSectionMarketsByKey((currentSectionMarketsByKey) => {
2925
+ var _a;
2926
+ const currentMarkets = (_a = currentSectionMarketsByKey[tabKey]) != null ? _a : [];
2927
+ if (areSportsSectionMarketsEqual(currentMarkets, markets)) {
2928
+ return currentSectionMarketsByKey;
2929
+ }
2930
+ return __spreadProps(__spreadValues({}, currentSectionMarketsByKey), {
2931
+ [tabKey]: markets
2932
+ });
2933
+ });
2934
+ },
2935
+ []
2936
+ );
2937
+ if (!composedEvent.venueMarkets.length) {
2938
+ return /* @__PURE__ */ jsx7(EventMarketPageUnavailableState, { ariaLabel });
2939
+ }
2940
+ return /* @__PURE__ */ jsxs6(
2941
+ "section",
2942
+ {
2943
+ className: cn(
2944
+ "agg-event-market-page",
2945
+ "mx-auto w-full max-w-[1440px] px-4 pb-10 pt-4 sm:px-6 sm:pt-6 xl:px-9 xl:pt-8",
2946
+ classNames == null ? void 0 : classNames.root
2947
+ ),
2948
+ "aria-label": ariaLabel != null ? ariaLabel : composedEvent.title,
2949
+ children: [
2950
+ /* @__PURE__ */ jsxs6(
2951
+ "div",
2952
+ {
2953
+ className: cn(
2954
+ "agg-page-content",
2955
+ "flex w-full flex-col gap-6 xl:flex-row xl:items-start xl:gap-[60px]",
2956
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.contentClassName,
2957
+ classNames == null ? void 0 : classNames.content
2958
+ ),
2959
+ style: stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.style,
2960
+ children: [
2961
+ /* @__PURE__ */ jsxs6(
2962
+ "div",
2963
+ {
2964
+ className: cn(
2965
+ "agg-page-main mb-10 flex min-w-0 flex-1 flex-col gap-10",
2966
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.mainClassName,
2967
+ classNames == null ? void 0 : classNames.main
2968
+ ),
2969
+ children: [
2970
+ /* @__PURE__ */ jsx7(
2971
+ EventListItemDetails,
2972
+ {
2973
+ event: composedEvent,
2974
+ defaultMarketId,
2975
+ defaultOutcomeId,
2976
+ defaultTradeSide,
2977
+ defaultChartView,
2978
+ eventTradingState,
2979
+ midpointsResult,
2980
+ sportsLiveState: sportsLiveStateByEventId.get(event.id),
2981
+ classNames: {
2982
+ root: cn("agg-event-hero", classNames == null ? void 0 : classNames.hero),
2983
+ // The sports tabs + market cards own market navigation, so hide the
2984
+ // hero's per-market selector pills (one per line market would be noise).
2985
+ headerPills: "hidden"
2986
+ }
2987
+ }
2988
+ ),
2989
+ hasSportsSections ? /* @__PURE__ */ jsx7(
2990
+ SportsMarkets,
2991
+ {
2992
+ event,
2993
+ onSectionMarketsChange: handleSectionMarketsChange,
2994
+ midpointsResult,
2995
+ onOutcomeSelect: isMobileViewport ? () => {
2996
+ setIsMobileTradeOpen(true);
2997
+ } : void 0
2998
+ }
2999
+ ) : /* @__PURE__ */ jsx7(
3000
+ MarketDetailsList,
3001
+ {
3002
+ eventId: composedEvent.id,
3003
+ markets: eventTradingState.displayMarkets,
3004
+ eventTradingState,
3005
+ live: true,
3006
+ expandSelectedMarketOnChange: !isMobileViewport,
3007
+ autoExpandFallbackMarket: !isMobileViewport,
3008
+ autoSelectFallbackMarket: !isMobileViewport,
3009
+ onOutcomeSelect: () => {
3010
+ if (!isMobileViewport) return;
3011
+ setIsMobileTradeOpen(true);
3012
+ },
3013
+ classNames: { root: "agg-market-list", item: "agg-market-list-item" },
3014
+ midpointsResult
3015
+ }
3016
+ ),
3017
+ showPlaceOrder !== false && eventTradingState.isTradingDisabled ? /* @__PURE__ */ jsx7("div", { className: "xl:hidden", children: /* @__PURE__ */ jsx7(
3018
+ PlaceOrder,
3019
+ {
3020
+ eventTradingState,
3021
+ executionMode: resolvedExecutionMode,
3022
+ resolvedClaim: effectiveResolvedClaim,
3023
+ midpointsResult,
3024
+ onBeforePrimaryAction,
3025
+ sharedKyc,
3026
+ className: cn(
3027
+ "agg-mobile-trade-panel w-full overflow-hidden",
3028
+ classNames == null ? void 0 : classNames.mobileTrade
3029
+ ),
3030
+ classNames: resolveMobileTradePlaceOrderClassNames(classNames)
3031
+ }
3032
+ ) }) : null,
3033
+ /* @__PURE__ */ jsx7(SettlementDetails, { eventId: event.id, className: classNames == null ? void 0 : classNames.settlement })
3034
+ ]
3035
+ }
3036
+ ),
3037
+ /* @__PURE__ */ jsx7(
3038
+ "aside",
3039
+ {
3040
+ className: cn(
3041
+ "agg-sidebar hidden w-full xl:block xl:max-w-[343px] xl:shrink-0",
3042
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.sidebarClassName,
3043
+ classNames == null ? void 0 : classNames.sidebar
3044
+ ),
3045
+ children: showPlaceOrder !== false ? /* @__PURE__ */ jsx7(
3046
+ PlaceOrder,
3047
+ {
3048
+ eventTradingState,
3049
+ executionMode: resolvedExecutionMode,
3050
+ resolvedClaim: effectiveResolvedClaim,
3051
+ midpointsResult,
3052
+ onBeforePrimaryAction,
3053
+ sharedKyc,
3054
+ className: cn(stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.placeOrder, classNames == null ? void 0 : classNames.trade),
3055
+ classNames: resolveDesktopTradePlaceOrderClassNames(classNames)
3056
+ }
3057
+ ) : null
3058
+ }
3059
+ )
3060
+ ]
3061
+ }
3062
+ ),
3063
+ !eventTradingState.isTradingDisabled ? /* @__PURE__ */ jsx7(
3064
+ EventMarketPageMobileTrade,
3065
+ {
3066
+ classNames,
3067
+ eventTradingState,
3068
+ executionMode: resolvedExecutionMode,
3069
+ showPlaceOrder,
3070
+ isOpen: isMobileTradeOpen,
3071
+ onOpenChange: setIsMobileTradeOpen,
3072
+ midpointsResult,
3073
+ onBeforePrimaryAction,
3074
+ sharedKyc
3075
+ }
3076
+ ) : null
3077
+ ]
3078
+ }
3079
+ );
3080
+ };
3081
+ SportsEventMarketPage.displayName = "SportsEventMarketPage";
3082
+
3083
+ // src/pages/event-market/index.tsx
3084
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
3085
+ var CLOCK_INTERVAL_MS = 1e3;
3086
+ var formatRecurringCountdown = (remainingMs) => {
3087
+ if (!Number.isFinite(remainingMs) || remainingMs <= 0) return null;
3088
+ const totalSeconds = Math.ceil(remainingMs / 1e3);
3089
+ const hours = Math.floor(totalSeconds / 3600);
3090
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
3091
+ const seconds = totalSeconds % 60;
3092
+ const minuteSecondLabel = `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
3093
+ return hours > 0 ? `${hours}:${minuteSecondLabel}` : minuteSecondLabel;
3094
+ };
3095
+ var useCurrentTimestamp = (enabled) => {
3096
+ const [currentTimestamp, setCurrentTimestamp] = useState7(null);
3097
+ useEffect6(() => {
3098
+ if (!enabled) {
3099
+ setCurrentTimestamp(null);
3100
+ return;
3101
+ }
3102
+ const updateCurrentTimestamp = () => {
3103
+ setCurrentTimestamp(Date.now());
3104
+ };
3105
+ updateCurrentTimestamp();
3106
+ const intervalId = window.setInterval(updateCurrentTimestamp, CLOCK_INTERVAL_MS);
3107
+ document.addEventListener("visibilitychange", updateCurrentTimestamp);
3108
+ return () => {
3109
+ window.clearInterval(intervalId);
3110
+ document.removeEventListener("visibilitychange", updateCurrentTimestamp);
3111
+ };
3112
+ }, [enabled]);
3113
+ return currentTimestamp;
3114
+ };
3115
+ var EventMarketPageContent = ({
3116
+ event,
3117
+ defaultMarketId,
3118
+ defaultOutcomeId,
3119
+ defaultTradeSide,
3120
+ defaultChartView,
3121
+ classNames,
3122
+ ariaLabel,
3123
+ showPlaceOrder,
3124
+ executionMode,
3125
+ stickyOrderPanel,
3126
+ resolvedClaim,
3127
+ onBeforePrimaryAction,
3128
+ sharedKyc,
3129
+ onRecurringMarketNavigate
3130
+ }) => {
3131
+ var _a;
3132
+ const eventTradingState = useMemo5(() => resolveEventTradingState3(event), [event]);
3133
+ const stickyOrderPanelState = resolveEventMarketPageStickyState({
3134
+ stickyOrderPanel
3135
+ });
3136
+ const { executionMode: resolvedExecutionMode } = useResolvedExecutionMode2(executionMode);
3137
+ const [isMobileTradeOpen, setIsMobileTradeOpen] = useState7(false);
3138
+ const isMobileViewport = useIsMobileEventMarketViewport();
3139
+ const tradingContext = useEventTradingContext4();
3140
+ const labels = useLabels8();
3141
+ const recurringQuery = useRecurringCryptoMarkets({ event });
3142
+ const currentTimestamp = useCurrentTimestamp(recurringQuery.isRecurringCryptoMarket);
3143
+ const recurringTimeline = useMemo5(
3144
+ () => currentTimestamp == null ? null : resolveRecurringCryptoTimeline(recurringQuery.windows, event, currentTimestamp),
3145
+ [currentTimestamp, event, recurringQuery.windows]
3146
+ );
3147
+ const isRecurringCryptoMarket = (recurringTimeline == null ? void 0 : recurringTimeline.viewed) != null;
3148
+ const recurringViewedEndTimestamp = (recurringTimeline == null ? void 0 : recurringTimeline.viewed) ? Date.parse(recurringTimeline.viewed.windowEnd) : Number.NaN;
3149
+ const hasViewedMarketEnded = currentTimestamp != null && Number.isFinite(recurringViewedEndTimestamp) && currentTimestamp >= recurringViewedEndTimestamp;
3150
+ const isRecurringResolvingMarket = recurringQuery.isRecurringCryptoMarket && eventTradingState.kind === "closed";
3151
+ const lastBoundaryRefetchRef = useRef5(null);
3152
+ useEffect6(() => {
3153
+ lastBoundaryRefetchRef.current = null;
3154
+ }, [event.id]);
3155
+ useEffect6(() => {
3156
+ if (!isRecurringCryptoMarket || !hasViewedMarketEnded || !(recurringTimeline == null ? void 0 : recurringTimeline.viewed)) return;
3157
+ const refetchKey = `${event.id}:${recurringTimeline.viewed.windowEnd}`;
3158
+ if (lastBoundaryRefetchRef.current === refetchKey) return;
3159
+ lastBoundaryRefetchRef.current = refetchKey;
3160
+ void recurringQuery.refetch();
3161
+ }, [
3162
+ event.id,
3163
+ hasViewedMarketEnded,
3164
+ isRecurringCryptoMarket,
3165
+ recurringQuery,
3166
+ recurringTimeline == null ? void 0 : recurringTimeline.viewed
3167
+ ]);
3168
+ const handleRecurringMarketSelect = useCallback5(
3169
+ (eventId) => {
3170
+ if (!onRecurringMarketNavigate || eventId === event.id) return;
3171
+ onRecurringMarketNavigate(eventId, { replace: false });
3172
+ },
3173
+ [event.id, onRecurringMarketNavigate]
3174
+ );
3175
+ const handleGoToLive = useCallback5(() => {
3176
+ var _a2;
3177
+ const liveEventId = (_a2 = recurringTimeline == null ? void 0 : recurringTimeline.live) == null ? void 0 : _a2.venueEventId;
3178
+ if (!onRecurringMarketNavigate || !liveEventId || liveEventId === event.id) return;
3179
+ onRecurringMarketNavigate(liveEventId, { replace: false });
3180
+ }, [event.id, onRecurringMarketNavigate, (_a = recurringTimeline == null ? void 0 : recurringTimeline.live) == null ? void 0 : _a.venueEventId]);
3181
+ const recurringMarketsPresentation = useMemo5(() => {
3182
+ var _a2, _b;
3183
+ if (!isRecurringCryptoMarket || !(recurringTimeline == null ? void 0 : recurringTimeline.viewed)) return void 0;
3184
+ const toOption = (market) => {
3185
+ var _a3;
3186
+ return {
3187
+ value: market.venueEventId,
3188
+ label: (_a3 = formatRecurringMarketPillTimeEt(market.windowStart)) != null ? _a3 : market.windowStart
3189
+ };
3190
+ };
3191
+ const countdownLabel = ((_a2 = recurringTimeline.live) == null ? void 0 : _a2.venueEventId) === event.id ? formatRecurringCountdown(recurringViewedEndTimestamp - currentTimestamp) : null;
3192
+ return {
3193
+ visibleOptions: recurringTimeline.visible.map(toOption),
3194
+ browseOptions: recurringTimeline.all.map(toOption),
3195
+ selectedValue: event.id,
3196
+ liveValue: (_b = recurringTimeline.live) == null ? void 0 : _b.venueEventId,
3197
+ duration: recurringTimeline.viewed.duration,
3198
+ windowLabel: formatRecurringMarketWindowTimeEt(
3199
+ recurringTimeline.viewed.windowStart,
3200
+ recurringTimeline.viewed.windowEnd
3201
+ ),
3202
+ countdownLabel,
3203
+ countdownAriaLabel: countdownLabel ? labels.eventMarketPage.recurringCountdownAria(countdownLabel) : null,
3204
+ isResolving: hasViewedMarketEnded,
3205
+ canGoToLive: recurringTimeline.live != null && recurringTimeline.live.venueEventId !== event.id,
3206
+ onSelect: handleRecurringMarketSelect,
3207
+ onGoToLive: handleGoToLive
3208
+ };
3209
+ }, [
3210
+ currentTimestamp,
3211
+ event.id,
3212
+ handleGoToLive,
3213
+ handleRecurringMarketSelect,
3214
+ hasViewedMarketEnded,
3215
+ isRecurringCryptoMarket,
3216
+ labels.eventMarketPage,
3217
+ recurringTimeline,
3218
+ recurringViewedEndTimestamp
3219
+ ]);
3220
+ const eventDetailVenueMarkets = useMemo5(
3221
+ () => normalizeVenueMarketCluster(event.venueMarkets),
3222
+ [event.venueMarkets]
3223
+ );
3224
+ const eventDetailVenueMarketIds = useMemo5(
3225
+ () => eventDetailVenueMarkets.map((venueMarket) => venueMarket.id),
3226
+ [eventDetailVenueMarkets]
3227
+ );
3228
+ const midpointsResult = useMidpoints2(
3229
+ recurringQuery.isRecurringCryptoMarket && eventTradingState.kind !== "open" ? [] : eventDetailVenueMarkets
3230
+ );
3231
+ const internalResolvedClaim = useResolvedMarketClaim({
3232
+ market: eventTradingState.primaryMarket,
3233
+ enabled: eventTradingState.kind === "resolved",
3234
+ executionMode: resolvedExecutionMode
3235
+ });
3236
+ const effectiveResolvedClaim = resolvedClaim != null ? resolvedClaim : internalResolvedClaim;
3237
+ const setTradeSideRef = useRef5(tradingContext == null ? void 0 : tradingContext.setTradeSide);
3238
+ setTradeSideRef.current = tradingContext == null ? void 0 : tradingContext.setTradeSide;
3239
+ useEffect6(() => {
3240
+ return () => {
3241
+ var _a2;
3242
+ (_a2 = setTradeSideRef.current) == null ? void 0 : _a2.call(setTradeSideRef, TradeSide2.Buy);
3243
+ };
3244
+ }, []);
3245
+ if (!event.venueMarkets.length) {
3246
+ return /* @__PURE__ */ jsx8(EventMarketPageUnavailableState, { ariaLabel });
3247
+ }
3248
+ return /* @__PURE__ */ jsxs7(
3249
+ "section",
3250
+ {
3251
+ className: cn(
3252
+ "agg-event-market-page",
3253
+ "w-full mx-auto max-w-[1440px] px-6 lg:px-10 pb-10",
3254
+ classNames == null ? void 0 : classNames.root
3255
+ ),
3256
+ "aria-label": ariaLabel != null ? ariaLabel : event.title,
3257
+ children: [
3258
+ /* @__PURE__ */ jsxs7(
3259
+ "div",
3260
+ {
3261
+ className: cn(
3262
+ "agg-page-content",
3263
+ "flex w-full flex-col gap-6 lg:flex-row lg:items-start lg:gap-8",
3264
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.contentClassName,
3265
+ classNames == null ? void 0 : classNames.content
3266
+ ),
3267
+ style: stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.style,
3268
+ children: [
3269
+ /* @__PURE__ */ jsxs7(
3270
+ "div",
3271
+ {
3272
+ className: cn(
3273
+ "agg-page-main flex min-w-0 flex-1 flex-col gap-6 mb-10",
3274
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.mainClassName,
3275
+ classNames == null ? void 0 : classNames.main
3276
+ ),
3277
+ children: [
3278
+ /* @__PURE__ */ jsx8(
3279
+ EventListItemDetails,
3280
+ {
3281
+ event,
3282
+ defaultMarketId,
3283
+ defaultOutcomeId,
3284
+ defaultTradeSide,
3285
+ defaultChartView,
3286
+ eventTradingState,
3287
+ midpointsResult,
3288
+ recurringMarkets: recurringMarketsPresentation,
3289
+ classNames: {
3290
+ root: cn("agg-event-hero", classNames == null ? void 0 : classNames.hero)
3291
+ }
3292
+ }
3293
+ ),
3294
+ /* @__PURE__ */ jsx8(
3295
+ EventOpenOrders,
3296
+ __spreadValues({
3297
+ venueMarketIds: eventDetailVenueMarketIds,
3298
+ executionMode: resolvedExecutionMode
3299
+ }, (classNames == null ? void 0 : classNames.openOrders) ? { className: classNames.openOrders } : {})
3300
+ ),
3301
+ /* @__PURE__ */ jsx8(
3302
+ MarketDetailsList,
3303
+ {
3304
+ eventId: event.id,
3305
+ markets: eventTradingState.displayMarkets,
3306
+ eventTradingState,
3307
+ live: true,
3308
+ showResolvingState: isRecurringResolvingMarket,
3309
+ expandSelectedMarketOnChange: !isMobileViewport,
3310
+ autoExpandFallbackMarket: !isMobileViewport,
3311
+ autoSelectFallbackMarket: !isMobileViewport,
3312
+ onOutcomeSelect: () => {
3313
+ if (!isMobileViewport) return;
3314
+ setIsMobileTradeOpen(true);
3315
+ },
3316
+ classNames: { root: "agg-market-list", item: "agg-market-list-item" },
3317
+ midpointsResult
3318
+ }
3319
+ ),
3320
+ showPlaceOrder !== false && eventTradingState.isTradingDisabled ? /* @__PURE__ */ jsx8("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx8(
3321
+ PlaceOrder,
3322
+ {
3323
+ eventTradingState,
3324
+ executionMode: resolvedExecutionMode,
3325
+ isQuotePanelActive: isMobileViewport,
3326
+ resolvedClaim: effectiveResolvedClaim,
3327
+ showResolvingState: isRecurringResolvingMarket,
3328
+ midpointsResult,
3329
+ onBeforePrimaryAction,
3330
+ sharedKyc,
3331
+ className: cn(
3332
+ "agg-mobile-trade-panel w-full overflow-hidden",
3333
+ classNames == null ? void 0 : classNames.mobileTrade
3334
+ ),
3335
+ classNames: resolveMobileTradePlaceOrderClassNames(classNames)
3336
+ }
3337
+ ) }) : null,
3338
+ /* @__PURE__ */ jsx8(SettlementDetails, { eventId: event.id, className: classNames == null ? void 0 : classNames.settlement })
3339
+ ]
3340
+ }
3341
+ ),
3342
+ /* @__PURE__ */ jsx8(
3343
+ "aside",
3344
+ {
3345
+ className: cn(
3346
+ "agg-sidebar hidden w-full lg:block lg:max-w-[342px] lg:shrink-0",
3347
+ stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.sidebarClassName,
3348
+ classNames == null ? void 0 : classNames.sidebar
3349
+ ),
3350
+ children: showPlaceOrder !== false ? /* @__PURE__ */ jsx8(
3351
+ PlaceOrder,
3352
+ {
3353
+ eventTradingState,
3354
+ executionMode: resolvedExecutionMode,
3355
+ isQuotePanelActive: !isMobileViewport,
3356
+ resolvedClaim: effectiveResolvedClaim,
3357
+ showResolvingState: isRecurringResolvingMarket,
3358
+ midpointsResult,
3359
+ onBeforePrimaryAction,
3360
+ sharedKyc,
3361
+ className: cn(stickyOrderPanelState == null ? void 0 : stickyOrderPanelState.placeOrder, classNames == null ? void 0 : classNames.trade),
3362
+ classNames: resolveDesktopTradePlaceOrderClassNames(classNames)
3363
+ }
3364
+ ) : null
3365
+ }
3366
+ )
3367
+ ]
3368
+ }
3369
+ ),
3370
+ !eventTradingState.isTradingDisabled ? /* @__PURE__ */ jsx8(
3371
+ EventMarketPageMobileTrade,
3372
+ {
3373
+ classNames,
3374
+ eventTradingState,
3375
+ executionMode: resolvedExecutionMode,
3376
+ showPlaceOrder,
3377
+ isOpen: isMobileTradeOpen,
3378
+ onOpenChange: setIsMobileTradeOpen,
3379
+ midpointsResult,
3380
+ onBeforePrimaryAction,
3381
+ sharedKyc
3382
+ }
3383
+ ) : null
3384
+ ]
3385
+ }
3386
+ );
3387
+ };
3388
+ var EventMarketPage = (props) => {
3389
+ var _a;
3390
+ const {
3391
+ features: { showSportsMarkets }
3392
+ } = useSdkUiConfig3();
3393
+ const labels = useLabels8();
3394
+ const hasEventProp = "event" in props && !!props.event;
3395
+ const {
3396
+ event: fetchedEvent,
3397
+ error: eventError,
3398
+ isLoading: isFetchingEvent,
3399
+ isEnriching,
3400
+ hasMoreMarkets,
3401
+ loadMoreMarkets,
3402
+ isLoadingMoreMarkets
3403
+ } = useEnrichedVenueEvent({
3404
+ progressive: props.progressiveMarkets,
3405
+ eventId: hasEventProp ? "" : (_a = props.eventId) != null ? _a : "",
3406
+ enabled: !props.isLoading && !hasEventProp && !!props.eventId
3407
+ });
3408
+ const renderEventContent = (event) => {
3409
+ const contentProps = __spreadProps(__spreadValues({}, props), {
3410
+ event,
3411
+ isLoading: false
3412
+ });
3413
+ const hasKnownSport = !!event.sport && event.sport !== "other_sport";
3414
+ if (showSportsMarkets === true && event.structureType === "sport" && hasKnownSport) {
3415
+ return /* @__PURE__ */ jsx8(SportsEventMarketPage, __spreadValues({}, contentProps));
3416
+ }
3417
+ return /* @__PURE__ */ jsx8(EventMarketPageContent, __spreadValues({}, contentProps));
3418
+ };
3419
+ const content = (() => {
3420
+ if (props.isLoading) {
3421
+ return /* @__PURE__ */ jsx8(
3422
+ EventMarketPageLoadingState,
3423
+ {
3424
+ classNames: props.classNames,
3425
+ stickyOrderPanel: props.stickyOrderPanel
3426
+ }
3427
+ );
3428
+ }
3429
+ if ("event" in props && props.event) {
3430
+ return renderEventContent(props.event);
3431
+ }
3432
+ if (isFetchingEvent || fetchedEvent && !fetchedEvent.venueMarkets.length && isEnriching) {
3433
+ return /* @__PURE__ */ jsx8(
3434
+ EventMarketPageLoadingState,
3435
+ {
3436
+ classNames: props.classNames,
3437
+ stickyOrderPanel: props.stickyOrderPanel
3438
+ }
3439
+ );
3440
+ }
3441
+ if (!fetchedEvent) {
3442
+ if (isErrorWithStatus(eventError, 404)) {
3443
+ return /* @__PURE__ */ jsx8(EventMarketPageNotFoundState, { ariaLabel: props.ariaLabel });
3444
+ }
3445
+ return /* @__PURE__ */ jsx8(EventMarketPageUnavailableState, { ariaLabel: props.ariaLabel });
3446
+ }
3447
+ return renderEventContent(fetchedEvent);
3448
+ })();
3449
+ return /* @__PURE__ */ jsxs7(AggErrorBoundary, { onError: props.onError, children: [
3450
+ content,
3451
+ props.progressiveMarkets && !hasEventProp && hasMoreMarkets ? /* @__PURE__ */ jsx8("div", { className: "mx-auto flex max-w-[1440px] justify-center px-6 pb-8", children: /* @__PURE__ */ jsx8(
3452
+ Button,
3453
+ {
3454
+ disabled: isLoadingMoreMarkets,
3455
+ onClick: () => {
3456
+ void (loadMoreMarkets == null ? void 0 : loadMoreMarkets());
3457
+ },
3458
+ children: isLoadingMoreMarkets ? labels.eventMarketPage.loadingMoreMarkets : labels.eventMarketPage.loadMoreMarkets
3459
+ }
3460
+ ) }) : null
3461
+ ] });
3462
+ };
3463
+ EventMarketPage.displayName = "EventMarketPage";
3464
+
3465
+ export {
3466
+ OpenOrderRow,
3467
+ useOpenOrderCancellation,
3468
+ parseRawMicroValue,
3469
+ formatScaledNumberTwoDecimals,
3470
+ formatFilledUsdTwoDecimals,
3471
+ OPEN_ORDER_QUERY_STATUSES,
3472
+ isOpenOrderStatus,
3473
+ selectOpenLimitOrders,
3474
+ buildOpenOrderCurrentPriceLabels,
3475
+ OPEN_ORDER_FALLBACK_THUMBNAIL_SRC,
3476
+ mapExecutionOrderToOpenOrder,
3477
+ useEventOpenOrders,
3478
+ EventOpenOrdersCard,
3479
+ EventOpenOrders,
3480
+ formatRecurringCountdown,
3481
+ EventMarketPage
3482
+ };