@agg-build/ui 4.18.2 → 4.19.1

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 (61) hide show
  1. package/README.md +1 -0
  2. package/dist/chunk-CKHECAKV.mjs +2724 -0
  3. package/dist/{chunk-NSQQ62QK.mjs → chunk-DONMO42Q.mjs} +1 -1
  4. package/dist/{chunk-RFMA5ABT.mjs → chunk-KRYMEFPL.mjs} +505 -44
  5. package/dist/{chunk-5YHKIJ23.mjs → chunk-NV6WT3TN.mjs} +481 -826
  6. package/dist/{chunk-47CCGQH6.mjs → chunk-UXLC3FFY.mjs} +451 -1349
  7. package/dist/{event-market-2BAMDM5I.mjs → event-market-UREM3ZE7.mjs} +3 -3
  8. package/dist/index.js +21879 -21136
  9. package/dist/index.mjs +16 -8
  10. package/dist/modals.js +898 -335
  11. package/dist/modals.mjs +5 -5
  12. package/dist/pages.js +3270 -1629
  13. package/dist/pages.mjs +12 -4
  14. package/dist/styles.css +1 -1
  15. package/dist/tailwind.css +1 -1
  16. package/dist/trading.js +1746 -643
  17. package/dist/trading.mjs +2 -2
  18. package/dist/types/pages/index.d.mts +1 -0
  19. package/dist/types/pages/index.d.ts +1 -0
  20. package/dist/types/pages/leaderboard/components/leaderboard-header-row.d.mts +7 -0
  21. package/dist/types/pages/leaderboard/components/leaderboard-header-row.d.ts +7 -0
  22. package/dist/types/pages/leaderboard/components/leaderboard-row.d.mts +7 -0
  23. package/dist/types/pages/leaderboard/components/leaderboard-row.d.ts +7 -0
  24. package/dist/types/pages/leaderboard/components/leaderboard-skeleton.d.mts +3 -0
  25. package/dist/types/pages/leaderboard/components/leaderboard-skeleton.d.ts +3 -0
  26. package/dist/types/pages/leaderboard/components/segmented-control.d.mts +18 -0
  27. package/dist/types/pages/leaderboard/components/segmented-control.d.ts +18 -0
  28. package/dist/types/pages/leaderboard/index.d.mts +28 -0
  29. package/dist/types/pages/leaderboard/index.d.ts +28 -0
  30. package/dist/types/pages/leaderboard/leaderboard.constants.d.mts +8 -0
  31. package/dist/types/pages/leaderboard/leaderboard.constants.d.ts +8 -0
  32. package/dist/types/pages/leaderboard/leaderboard.types.d.mts +11 -0
  33. package/dist/types/pages/leaderboard/leaderboard.types.d.ts +11 -0
  34. package/dist/types/pages/user-profile/components/available-balance-card.d.mts +2 -1
  35. package/dist/types/pages/user-profile/components/available-balance-card.d.ts +2 -1
  36. package/dist/types/pages/user-profile/components/betdex-account-card.d.mts +3 -1
  37. package/dist/types/pages/user-profile/components/betdex-account-card.d.ts +3 -1
  38. package/dist/types/pages/user-profile/components/betdex-account-transfers.d.mts +2 -1
  39. package/dist/types/pages/user-profile/components/betdex-account-transfers.d.ts +2 -1
  40. package/dist/types/pages/user-profile/components/betdex-wallet-deposit.d.mts +6 -0
  41. package/dist/types/pages/user-profile/components/betdex-wallet-deposit.d.ts +6 -0
  42. package/dist/types/pages/user-profile/position-view-model.d.mts +2 -4
  43. package/dist/types/pages/user-profile/position-view-model.d.ts +2 -4
  44. package/dist/types/profile/tabs/trading-access-tab.d.mts +2 -1
  45. package/dist/types/profile/tabs/trading-access-tab.d.ts +2 -1
  46. package/dist/types/shared/pnl-format.d.mts +20 -0
  47. package/dist/types/shared/pnl-format.d.ts +20 -0
  48. package/dist/types/trading/manage-betdex-account-modal.d.mts +2 -1
  49. package/dist/types/trading/manage-betdex-account-modal.d.ts +2 -1
  50. package/dist/types/trading/place-order/index.place-order.types.d.mts +1 -0
  51. package/dist/types/trading/place-order/index.place-order.types.d.ts +1 -0
  52. package/dist/types/trading/place-order/index.place-order.utils.d.mts +2 -2
  53. package/dist/types/trading/place-order/index.place-order.utils.d.ts +2 -2
  54. package/dist/types/withdraw/steps/withdraw-amount.d.mts +3 -1
  55. package/dist/types/withdraw/steps/withdraw-amount.d.ts +3 -1
  56. package/dist/types/withdraw/withdraw-modal.types.d.mts +8 -0
  57. package/dist/types/withdraw/withdraw-modal.types.d.ts +8 -0
  58. package/package.json +3 -3
  59. package/dist/chunk-ROA5K67W.mjs +0 -1237
  60. /package/dist/types/{pages/user-profile/components → shared}/default-avatar.d.mts +0 -0
  61. /package/dist/types/{pages/user-profile/components → shared}/default-avatar.d.ts +0 -0
@@ -21,14 +21,13 @@ import {
21
21
  parseRawMicroValue,
22
22
  selectOpenLimitOrders,
23
23
  useOpenOrderCancellation
24
- } from "./chunk-NSQQ62QK.mjs";
24
+ } from "./chunk-DONMO42Q.mjs";
25
25
  import {
26
- BetdexAccountCard,
27
26
  DEPOSIT_MODAL_OPEN_EVENT,
28
27
  WITHDRAW_MODAL_OPEN_EVENT,
29
28
  formatChainIdLabel,
30
29
  useClaimWinnings
31
- } from "./chunk-5YHKIJ23.mjs";
30
+ } from "./chunk-NV6WT3TN.mjs";
32
31
  import {
33
32
  AggErrorBoundary,
34
33
  Button,
@@ -267,7 +266,7 @@ var useHomePageModals = () => {
267
266
  // src/pages/home/index.tsx
268
267
  import { jsx, jsxs } from "react/jsx-runtime";
269
268
  var DeferredEventMarketPage = lazy(
270
- () => import("./event-market-2BAMDM5I.mjs").then((module) => ({ default: module.EventMarketPage }))
269
+ () => import("./event-market-UREM3ZE7.mjs").then((module) => ({ default: module.EventMarketPage }))
271
270
  );
272
271
  var MIN_SEARCH_LENGTH = 3;
273
272
  var SEARCH_DEBOUNCE_MS = 300;
@@ -1071,6 +1070,7 @@ var AvailableBalanceCard = ({
1071
1070
  valueLabel,
1072
1071
  reservedValueLabel,
1073
1072
  kalshiValueLabel,
1073
+ betdexValueLabel,
1074
1074
  chains,
1075
1075
  isLoading = false,
1076
1076
  className,
@@ -1230,6 +1230,13 @@ var AvailableBalanceCard = ({
1230
1230
  /* @__PURE__ */ jsx2("span", { className: "font-agg-sans text-agg-xs leading-agg-4 font-agg-normal text-agg-muted-foreground", children: labels.venues.kalshi })
1231
1231
  ] })
1232
1232
  ] }) : null,
1233
+ betdexValueLabel !== void 0 ? /* @__PURE__ */ jsxs2("div", { className: "agg-balance-betdex flex items-center justify-between gap-3", children: [
1234
+ /* @__PURE__ */ jsx2("div", { className: "font-agg-sans text-agg-base leading-6 font-agg-bold text-agg-foreground", children: isLoading ? /* @__PURE__ */ jsx2("div", { role: "status", "aria-label": `${labels.venues.betdex}: ${labels.common.loading}`, children: /* @__PURE__ */ jsx2(SkeletonBlock, { className: "h-6 w-16 rounded-agg-sm" }) }) : betdexValueLabel }),
1235
+ /* @__PURE__ */ jsxs2("span", { className: "flex h-5 shrink-0 items-center gap-1 rounded-[4px] bg-agg-secondary-hover px-1.5", children: [
1236
+ /* @__PURE__ */ jsx2(VenueLogo, { venue: "betdex", size: "small", className: "size-3" }),
1237
+ /* @__PURE__ */ jsx2("span", { className: "font-agg-sans text-agg-xs leading-agg-4 font-agg-normal text-agg-muted-foreground", children: labels.venues.betdex })
1238
+ ] })
1239
+ ] }) : null,
1233
1240
  !isLoading && reservedValueLabel ? /* @__PURE__ */ jsx2("p", { className: "font-agg-sans text-agg-xs leading-agg-4 text-agg-muted-foreground", children: balanceLabels.reservedForOpenOrders(reservedValueLabel) }) : null
1234
1241
  ]
1235
1242
  }
@@ -2101,24 +2108,58 @@ var USER_PROFILE_POSITION_FILTERS = [
2101
2108
  { value: "closed", label: "Closed" }
2102
2109
  ];
2103
2110
 
2104
- // src/pages/user-profile/position-view-model.ts
2105
- var defaultLabels = {
2106
- avgPrefix: "avg",
2107
- nowPrefix: "now",
2108
- finalPrefix: "final"
2109
- };
2110
- var missingLabel = "\u2014";
2111
+ // src/shared/pnl-format.ts
2112
+ var MISSING_VALUE_LABEL = "\u2014";
2111
2113
  var usdFormatter = new Intl.NumberFormat("en-US", {
2112
2114
  style: "currency",
2113
2115
  currency: "USD",
2114
2116
  minimumFractionDigits: 2,
2115
2117
  maximumFractionDigits: 2
2116
2118
  });
2119
+ var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
2120
+ var formatCurrency = (value, formatCurrencyOverride) => {
2121
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
2122
+ if (formatCurrencyOverride) return formatCurrencyOverride(value);
2123
+ return usdFormatter.format(value);
2124
+ };
2125
+ var NEGLIGIBLE_CURRENCY_THRESHOLD = 5e-3;
2126
+ var formatSignedCurrency = (value, formatCurrencyOverride, options = {}) => {
2127
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
2128
+ if (value === 0) return formatCurrency(0, formatCurrencyOverride);
2129
+ const sign = value > 0 ? "+" : "-";
2130
+ const magnitude = Math.abs(value);
2131
+ if (options.markNegligible && magnitude < NEGLIGIBLE_CURRENCY_THRESHOLD) {
2132
+ return `${sign}<${formatCurrency(0.01, formatCurrencyOverride)}`;
2133
+ }
2134
+ return `${sign}${formatCurrency(magnitude, formatCurrencyOverride)}`;
2135
+ };
2136
+ var formatCurrencyMarkingNegligible = (value, formatCurrencyOverride) => {
2137
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
2138
+ if (value !== 0 && Math.abs(value) < NEGLIGIBLE_CURRENCY_THRESHOLD) {
2139
+ return `<${formatCurrency(0.01, formatCurrencyOverride)}`;
2140
+ }
2141
+ return formatCurrency(value, formatCurrencyOverride);
2142
+ };
2143
+ var getPositionTone = (value) => {
2144
+ if (!isFiniteNumber(value) || value === 0) return "neutral";
2145
+ return value > 0 ? "positive" : "negative";
2146
+ };
2147
+ var toneClassName = (tone) => {
2148
+ if (tone === "positive") return "text-agg-success";
2149
+ if (tone === "negative") return "text-agg-error";
2150
+ return "text-agg-muted-foreground";
2151
+ };
2152
+
2153
+ // src/pages/user-profile/position-view-model.ts
2154
+ var defaultLabels = {
2155
+ avgPrefix: "avg",
2156
+ nowPrefix: "now",
2157
+ finalPrefix: "final"
2158
+ };
2117
2159
  var percentFormatter = new Intl.NumberFormat("en-US", {
2118
2160
  minimumFractionDigits: 0,
2119
2161
  maximumFractionDigits: 1
2120
2162
  });
2121
- var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
2122
2163
  var parseCurrencyLabel = (label) => {
2123
2164
  if (!label) return null;
2124
2165
  const normalized = label.replace(/[$,\s]/g, "");
@@ -2139,23 +2180,13 @@ var parsePercentLabel = (label) => {
2139
2180
  const parsed = Number(match[1].replace(/,/g, ""));
2140
2181
  return Number.isFinite(parsed) ? parsed : null;
2141
2182
  };
2142
- var formatCurrency = (value, formatCurrencyOverride) => {
2143
- if (!isFiniteNumber(value)) return missingLabel;
2144
- if (formatCurrencyOverride) return formatCurrencyOverride(value);
2145
- return usdFormatter.format(value);
2146
- };
2147
- var formatSignedCurrency = (value, formatCurrencyOverride) => {
2148
- if (!isFiniteNumber(value)) return missingLabel;
2149
- if (value === 0) return formatCurrency(0, formatCurrencyOverride);
2150
- return `${value > 0 ? "+" : "-"}${formatCurrency(Math.abs(value), formatCurrencyOverride)}`;
2151
- };
2152
2183
  var formatPriceCents = (value, formatPrice) => {
2153
- if (!isFiniteNumber(value)) return missingLabel;
2184
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
2154
2185
  if (formatPrice) return formatPrice(value);
2155
2186
  return `${Math.round(value * 100)}\xA2`;
2156
2187
  };
2157
2188
  var formatSignedPercent = (value) => {
2158
- if (!isFiniteNumber(value)) return missingLabel;
2189
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
2159
2190
  if (value === 0) return "0%";
2160
2191
  return `${value > 0 ? "+" : "-"}${percentFormatter.format(Math.abs(value))}%`;
2161
2192
  };
@@ -2243,10 +2274,6 @@ var getFinalPnlPercent = (position, pnlValue) => {
2243
2274
  }
2244
2275
  return null;
2245
2276
  };
2246
- var getPositionTone = (value) => {
2247
- if (!isFiniteNumber(value) || value === 0) return "neutral";
2248
- return value > 0 ? "positive" : "negative";
2249
- };
2250
2277
  var toPositionRowViewModel = (position, labels = defaultLabels, formatters = {}) => {
2251
2278
  const { formatCurrency: currency, formatPrice: price } = formatters;
2252
2279
  const positionStatus = resolvePositionStatus(position);
@@ -2260,10 +2287,10 @@ var toPositionRowViewModel = (position, labels = defaultLabels, formatters = {})
2260
2287
  position,
2261
2288
  positionStatus,
2262
2289
  bucket: resolvePositionBucket(position),
2263
- title: position.title || missingLabel,
2290
+ title: position.title || MISSING_VALUE_LABEL,
2264
2291
  thumbnailSrc: position.thumbnailSrc,
2265
- selectedOutcomeLabel: position.outcomeLabel || missingLabel,
2266
- resolutionLabel: position.resolutionLabel || position.outcomeLabel || missingLabel,
2292
+ selectedOutcomeLabel: position.outcomeLabel || MISSING_VALUE_LABEL,
2293
+ resolutionLabel: position.resolutionLabel || position.outcomeLabel || MISSING_VALUE_LABEL,
2267
2294
  venueShareBreakdown: position.venueShareBreakdown,
2268
2295
  totalTraded: {
2269
2296
  primaryLabel: formatCurrency(getTotalTradedValue(position), currency),
@@ -2886,11 +2913,6 @@ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-run
2886
2913
  var shouldUseNativeLinkNavigation2 = (event) => {
2887
2914
  return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button === 1;
2888
2915
  };
2889
- var toneTextClassName = (tone) => {
2890
- if (tone === "positive") return "text-agg-success";
2891
- if (tone === "negative") return "text-agg-error";
2892
- return "text-agg-muted-foreground";
2893
- };
2894
2916
  var OutcomePill = ({ label }) => /* @__PURE__ */ jsx7("span", { className: "agg-position-outcome max-w-[120px] inline-flex items-center justify-center rounded-full bg-agg-secondary-hover px-4 py-[6px]", children: /* @__PURE__ */ jsx7("span", { className: "whitespace-nowrap font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground truncate", children: label }) });
2895
2917
  var ResolutionPill = ({ label }) => /* @__PURE__ */ jsx7("span", { className: "agg-position-resolution-pill inline-flex w-full items-center justify-center overflow-hidden rounded-full bg-agg-secondary-hover px-4 py-[6px] md:w-auto", children: /* @__PURE__ */ jsx7("span", { className: "truncate whitespace-nowrap font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground", children: label }) });
2896
2918
  var VenueShares = ({
@@ -2989,7 +3011,7 @@ var PositionValueCell = ({
2989
3011
  {
2990
3012
  className: cn(
2991
3013
  "font-agg-sans text-agg-sm leading-agg-5 font-agg-normal",
2992
- toneTextClassName(value.tone)
3014
+ toneClassName(value.tone)
2993
3015
  ),
2994
3016
  children: value.deltaLabel
2995
3017
  }
@@ -3002,7 +3024,7 @@ var PositionValueCell = ({
3002
3024
  {
3003
3025
  className: cn(
3004
3026
  "font-agg-sans text-agg-xs leading-agg-4 font-agg-normal",
3005
- toneTextClassName(value.tone)
3027
+ toneClassName(value.tone)
3006
3028
  ),
3007
3029
  children: value.percentLabel
3008
3030
  }
@@ -3918,7 +3940,7 @@ var ConditionalWrapper = ({
3918
3940
  }) => condition ? wrapper(children) : children;
3919
3941
  ConditionalWrapper.displayName = "ConditionalWrapper";
3920
3942
 
3921
- // src/pages/user-profile/components/default-avatar.tsx
3943
+ // src/shared/default-avatar.tsx
3922
3944
  import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
3923
3945
  var DefaultAvatar = ({ className }) => {
3924
3946
  return /* @__PURE__ */ jsxs10(
@@ -4817,7 +4839,6 @@ var UserProfilePage = ({
4817
4839
  disabledVenues,
4818
4840
  isConfigLoading: isAppConfigLoading
4819
4841
  }) === "available";
4820
- const showBetdexAccount = shouldUseHookData && isAuthenticated && !isPaperMode && !isAppConfigLoading && (getVenueAvailabilityState({ venueId: Venue3.betdex, disabledVenues }) === "available" || ((_b = currentUser == null ? void 0 : currentUser.venueAccounts) == null ? void 0 : _b.some((account) => account.venue === Venue3.betdex)));
4821
4842
  const isPositionsValueLoading = !(balance == null ? void 0 : balance.totalLabel) && balanceState.isLoading;
4822
4843
  const isAvailableBalanceLoading = balanceState.isLoading;
4823
4844
  const resolvedActivities = useMemo4(() => {
@@ -5173,7 +5194,6 @@ var UserProfilePage = ({
5173
5194
  compact: isPaperMode
5174
5195
  }
5175
5196
  ),
5176
- showBetdexAccount ? /* @__PURE__ */ jsx12(BetdexAccountCard, {}) : null,
5177
5197
  isPaperMode ? (
5178
5198
  // Paper apps have no withdrawable balance and no network
5179
5199
  // breakdown — simulated cash lives nowhere. Swap the whole
@@ -5220,14 +5240,17 @@ var UserProfilePage = ({
5220
5240
  {
5221
5241
  valueLabel: availableBalanceLabel,
5222
5242
  isLoading: isAvailableBalanceLoading,
5223
- chains: ((_c = balanceChainsOverride != null ? balanceChainsOverride : balanceState.availableBalanceBreakdown) != null ? _c : balanceState.balanceBreakdown).map((b) => ({
5243
+ chains: ((_b = balanceChainsOverride != null ? balanceChainsOverride : balanceState.availableBalanceBreakdown) != null ? _b : balanceState.balanceBreakdown).map((b) => ({
5224
5244
  key: b.key,
5225
5245
  label: b.label,
5226
5246
  balance: b.balance,
5227
5247
  accountCount: b.accountCount,
5228
5248
  venues: b.venues
5229
5249
  })),
5230
- kalshiValueLabel: isKalshiAvailable ? formatUsd2((_d = balanceState.kalshiBalance) != null ? _d : 0) : void 0,
5250
+ kalshiValueLabel: isKalshiAvailable ? formatUsd2((_c = balanceState.kalshiBalance) != null ? _c : 0) : void 0,
5251
+ betdexValueLabel: shouldUseHookData && isAuthenticated && (((_d = currentUser == null ? void 0 : currentUser.venueAccounts) == null ? void 0 : _d.some(
5252
+ (account) => account.venue === Venue3.betdex
5253
+ )) || balanceState.betdexAvailableBalance != null) ? balanceState.betdexAvailableBalance == null ? labels.userProfile.balance.balanceUnavailable : formatUsd2(balanceState.betdexAvailableBalance) : void 0,
5231
5254
  manageButtonRef: manageBalancesButtonRef,
5232
5255
  onManage: () => handleManageBalancesOpenChange(true)
5233
5256
  }
@@ -5316,6 +5339,440 @@ var UserProfilePage = ({
5316
5339
  };
5317
5340
  UserProfilePage.displayName = "UserProfilePage";
5318
5341
 
5342
+ // src/pages/leaderboard/index.tsx
5343
+ import { useAggAuthState as useAggAuthState2, useLabels as useLabels12, useLeaderboard, LEADERBOARD_PERIODS } from "@agg-build/hooks";
5344
+ import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useState as useState7 } from "react";
5345
+
5346
+ // src/pages/leaderboard/components/leaderboard-header-row.tsx
5347
+ import { useLabels as useLabels9 } from "@agg-build/hooks";
5348
+
5349
+ // src/pages/leaderboard/leaderboard.constants.ts
5350
+ var LEADERBOARD_DEFAULT_PERIOD = "30d";
5351
+ var LEADERBOARD_DEFAULT_METRIC = "realizedPnl";
5352
+ var LEADERBOARD_METRICS = ["realizedPnl", "volume"];
5353
+ var LEADERBOARD_TOP_RANKS = 3;
5354
+ var LEADERBOARD_GRID_CLASS = "grid grid-cols-[36px_minmax(0,1fr)] grid-rows-[auto_auto] gap-x-3 gap-y-2 sm:grid-cols-[48px_minmax(0,1fr)_88px_128px_128px] sm:grid-rows-1 sm:gap-x-3 sm:gap-y-0";
5355
+
5356
+ // src/pages/leaderboard/components/leaderboard-header-row.tsx
5357
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
5358
+ var SORT_CARET = /* @__PURE__ */ jsx13("svg", { viewBox: "0 0 10 10", className: "size-2.5", "aria-hidden": "true", children: /* @__PURE__ */ jsx13("path", { d: "M5 8 1 3h8z", fill: "currentColor" }) });
5359
+ function LeaderboardHeaderRow({
5360
+ metric,
5361
+ onMetricChange
5362
+ }) {
5363
+ const labels = useLabels9().leaderboard;
5364
+ const sortable = (key, text) => {
5365
+ const active = metric === key;
5366
+ return /* @__PURE__ */ jsx13(
5367
+ "span",
5368
+ {
5369
+ role: "columnheader",
5370
+ "aria-sort": active ? "descending" : void 0,
5371
+ className: "text-right",
5372
+ children: /* @__PURE__ */ jsxs13(
5373
+ "button",
5374
+ {
5375
+ type: "button",
5376
+ onClick: () => onMetricChange(key),
5377
+ className: cn(
5378
+ "inline-flex cursor-pointer items-center justify-end gap-1 uppercase tracking-wide outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-agg-primary-hover",
5379
+ active ? "font-agg-bold text-agg-foreground" : "hover:text-agg-foreground"
5380
+ ),
5381
+ children: [
5382
+ text,
5383
+ active ? SORT_CARET : null
5384
+ ]
5385
+ }
5386
+ )
5387
+ }
5388
+ );
5389
+ };
5390
+ return /* @__PURE__ */ jsxs13(
5391
+ "div",
5392
+ {
5393
+ role: "row",
5394
+ className: cn(
5395
+ LEADERBOARD_GRID_CLASS,
5396
+ "agg-leaderboard-header hidden h-10 items-center border-b border-agg-separator bg-agg-secondary-hover px-5 text-agg-xs leading-agg-4 uppercase tracking-wide text-agg-muted-foreground sm:grid"
5397
+ ),
5398
+ children: [
5399
+ /* @__PURE__ */ jsx13("span", { role: "columnheader", children: labels.columns.rank }),
5400
+ /* @__PURE__ */ jsx13("span", { role: "columnheader", children: labels.columns.trader }),
5401
+ /* @__PURE__ */ jsx13("span", { role: "columnheader", className: "text-right", children: labels.columns.orders }),
5402
+ sortable("volume", labels.columns.volume),
5403
+ sortable("realizedPnl", labels.columns.realizedPnl)
5404
+ ]
5405
+ }
5406
+ );
5407
+ }
5408
+
5409
+ // src/pages/leaderboard/components/leaderboard-row.tsx
5410
+ import { optimizedImageUrl as optimizedImageUrl4, useAggUiConfig as useAggUiConfig3, useLabels as useLabels10 } from "@agg-build/hooks";
5411
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
5412
+ var integer = new Intl.NumberFormat("en-US");
5413
+ function LeaderboardRowView({
5414
+ row,
5415
+ isCurrentUser,
5416
+ className
5417
+ }) {
5418
+ var _a, _b, _c;
5419
+ const labels = useLabels10().leaderboard;
5420
+ const { formatCurrency: formatCurrency2 } = useAggUiConfig3().formatting;
5421
+ const tone = getPositionTone(row.realizedPnl);
5422
+ const shortWallet = shortenAddress(row.walletAddress);
5423
+ const identity = (_b = (_a = row.username) != null ? _a : shortWallet) != null ? _b : labels.anonymousTrader;
5424
+ const identityKind = row.username ? "username" : shortWallet ? "wallet" : "anonymous";
5425
+ const isTop = row.rank != null && row.rank <= LEADERBOARD_TOP_RANKS;
5426
+ const hasOrders = Number.isFinite(row.orders);
5427
+ const cell = (caption, value, extra) => /* @__PURE__ */ jsxs14("span", { role: "cell", className: "flex flex-col text-left tabular-nums sm:block sm:text-right", children: [
5428
+ /* @__PURE__ */ jsx14("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground sm:hidden", children: caption }),
5429
+ /* @__PURE__ */ jsx14("span", { className: cn("text-agg-sm leading-agg-5", extra), children: value })
5430
+ ] });
5431
+ return /* @__PURE__ */ jsxs14(
5432
+ "div",
5433
+ {
5434
+ role: "row",
5435
+ "aria-current": isCurrentUser ? "true" : void 0,
5436
+ className: cn(
5437
+ LEADERBOARD_GRID_CLASS,
5438
+ "agg-leaderboard-row items-center px-4 py-3 sm:min-h-16 sm:px-5",
5439
+ isCurrentUser ? "bg-agg-trade-highlight-surface shadow-[inset_3px_0_0_var(--agg-color-primary)]" : "hover:bg-agg-secondary-hover/60",
5440
+ className
5441
+ ),
5442
+ children: [
5443
+ /* @__PURE__ */ jsx14(
5444
+ "span",
5445
+ {
5446
+ role: "cell",
5447
+ "data-testid": "agg-leaderboard-rank",
5448
+ className: cn(
5449
+ "agg-leaderboard-rank row-span-2 inline-flex size-7 items-center justify-center rounded-agg-full text-agg-sm tabular-nums sm:row-span-1",
5450
+ // cn() is a plain join: colour classes must be mutually exclusive.
5451
+ row.rank === 1 ? "border border-agg-primary bg-agg-secondary-hover font-agg-bold text-agg-primary" : isTop ? "border border-agg-separator bg-agg-secondary-hover font-agg-bold text-agg-foreground" : "text-agg-muted-foreground"
5452
+ ),
5453
+ children: (_c = row.rank) != null ? _c : "\u2013"
5454
+ }
5455
+ ),
5456
+ /* @__PURE__ */ jsxs14("div", { role: "cell", className: "agg-leaderboard-identity flex min-w-0 items-center gap-3", children: [
5457
+ row.avatarUrl ? /* @__PURE__ */ jsx14(
5458
+ RemoteImage,
5459
+ {
5460
+ src: optimizedImageUrl4(row.avatarUrl, 80),
5461
+ alt: "",
5462
+ className: "size-10 shrink-0 rounded-agg-full object-cover"
5463
+ }
5464
+ ) : /* @__PURE__ */ jsx14(DefaultAvatar, { className: "size-10 rounded-agg-full" }),
5465
+ /* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 flex-col", children: [
5466
+ /* @__PURE__ */ jsxs14("span", { className: "flex items-center gap-2", children: [
5467
+ /* @__PURE__ */ jsx14(
5468
+ "span",
5469
+ {
5470
+ className: cn(
5471
+ "truncate text-agg-sm leading-agg-5",
5472
+ identityKind === "username" && "font-agg-bold text-agg-foreground",
5473
+ identityKind === "wallet" && "font-mono font-agg-medium text-agg-foreground",
5474
+ identityKind === "anonymous" && "font-agg-medium text-agg-muted-foreground"
5475
+ ),
5476
+ children: identity
5477
+ }
5478
+ ),
5479
+ isCurrentUser ? /* @__PURE__ */ jsx14("span", { className: "rounded-agg-full bg-agg-primary px-1.5 text-agg-2xs font-agg-bold uppercase leading-agg-4 tracking-wide text-agg-on-primary", children: labels.you }) : null
5480
+ ] }),
5481
+ /* @__PURE__ */ jsx14("span", { className: "text-agg-xs leading-agg-4 text-agg-muted-foreground", children: hasOrders ? labels.tradesCount(row.orders) : MISSING_VALUE_LABEL })
5482
+ ] })
5483
+ ] }),
5484
+ /* @__PURE__ */ jsxs14("div", { className: "col-start-2 grid grid-cols-3 gap-2 sm:contents", children: [
5485
+ cell(labels.columns.orders, hasOrders ? integer.format(row.orders) : MISSING_VALUE_LABEL),
5486
+ cell(labels.columns.volume, formatCurrencyMarkingNegligible(row.volume, formatCurrency2)),
5487
+ cell(
5488
+ labels.columns.realizedPnl,
5489
+ formatSignedCurrency(row.realizedPnl, formatCurrency2, { markNegligible: true }),
5490
+ cn("font-agg-bold", toneClassName(tone))
5491
+ )
5492
+ ] })
5493
+ ]
5494
+ }
5495
+ );
5496
+ }
5497
+
5498
+ // src/pages/leaderboard/components/leaderboard-skeleton.tsx
5499
+ import { useLabels as useLabels11 } from "@agg-build/hooks";
5500
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
5501
+ function LeaderboardSkeleton({ rows = 4 }) {
5502
+ const labels = useLabels11().leaderboard;
5503
+ return /* @__PURE__ */ jsx15("div", { role: "status", "aria-label": labels.loadingAria, className: "agg-leaderboard-skeleton", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs15(
5504
+ "div",
5505
+ {
5506
+ className: cn(
5507
+ LEADERBOARD_GRID_CLASS,
5508
+ "items-center border-b border-agg-separator px-4 py-3 last:border-b-0 sm:min-h-16 sm:px-5"
5509
+ ),
5510
+ children: [
5511
+ /* @__PURE__ */ jsx15("span", { className: "size-7 rounded-agg-full bg-agg-secondary-hover/80" }),
5512
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-3", children: [
5513
+ /* @__PURE__ */ jsx15("span", { className: "size-10 rounded-agg-full bg-agg-secondary-hover/80" }),
5514
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-1 flex-col gap-2", children: [
5515
+ /* @__PURE__ */ jsx15("span", { className: "h-3 w-2/5 rounded-agg-sm bg-agg-secondary-hover/80" }),
5516
+ /* @__PURE__ */ jsx15("span", { className: "h-3 w-1/5 rounded-agg-sm bg-agg-secondary-hover/80" })
5517
+ ] })
5518
+ ] }),
5519
+ /* @__PURE__ */ jsx15("span", { className: "hidden h-3 w-10 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" }),
5520
+ /* @__PURE__ */ jsx15("span", { className: "hidden h-3 w-16 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" }),
5521
+ /* @__PURE__ */ jsx15("span", { className: "hidden h-3 w-14 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" })
5522
+ ]
5523
+ },
5524
+ i
5525
+ )) });
5526
+ }
5527
+
5528
+ // src/pages/leaderboard/components/segmented-control.tsx
5529
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
5530
+ function SegmentedControl({
5531
+ label,
5532
+ value,
5533
+ onChange,
5534
+ items,
5535
+ className,
5536
+ itemClassName
5537
+ }) {
5538
+ return /* @__PURE__ */ jsx16(
5539
+ "div",
5540
+ {
5541
+ role: "group",
5542
+ "aria-label": label,
5543
+ className: cn(
5544
+ "agg-segmented flex h-10 w-full items-stretch overflow-clip rounded-agg-sm border border-agg-separator sm:w-auto",
5545
+ className
5546
+ ),
5547
+ children: items.map((item, idx) => {
5548
+ const isActive = item.value === value;
5549
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-1 items-stretch sm:flex-none", children: [
5550
+ idx > 0 ? /* @__PURE__ */ jsx16("div", { className: "w-px bg-agg-separator", "aria-hidden": true }) : null,
5551
+ /* @__PURE__ */ jsx16(
5552
+ "button",
5553
+ {
5554
+ type: "button",
5555
+ "aria-pressed": isActive,
5556
+ onClick: () => onChange(item.value),
5557
+ className: cn(
5558
+ "agg-segmented-trigger flex flex-1 cursor-pointer items-center justify-center px-3 font-agg-sans text-agg-sm leading-agg-5 whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-agg-primary-hover sm:px-4",
5559
+ isActive ? "bg-agg-secondary-hover font-agg-bold text-agg-foreground" : "bg-agg-secondary font-agg-normal text-agg-muted-foreground hover:bg-agg-secondary-hover hover:text-agg-foreground",
5560
+ itemClassName
5561
+ ),
5562
+ children: item.label
5563
+ }
5564
+ )
5565
+ ] }, item.value);
5566
+ })
5567
+ }
5568
+ );
5569
+ }
5570
+
5571
+ // src/pages/leaderboard/index.tsx
5572
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
5573
+ function LeaderboardPage(props) {
5574
+ return /* @__PURE__ */ jsx17(AggErrorBoundary, { onError: props.onError, children: /* @__PURE__ */ jsx17(LeaderboardPageInner, __spreadValues({}, props)) });
5575
+ }
5576
+ function LeaderboardPageInner({
5577
+ rows: rowsProp,
5578
+ isLoading: isLoadingProp,
5579
+ error: errorProp,
5580
+ hasNextPage: hasNextPageProp,
5581
+ isLoadingMore: isLoadingMoreProp,
5582
+ onLoadMore: onLoadMoreProp,
5583
+ period: periodProp,
5584
+ onPeriodChange,
5585
+ metric: metricProp,
5586
+ onMetricChange,
5587
+ currentUserId: currentUserIdProp,
5588
+ appName,
5589
+ className,
5590
+ classNames
5591
+ }) {
5592
+ const allLabels = useLabels12();
5593
+ const labels = allLabels.leaderboard;
5594
+ const { user } = useAggAuthState2();
5595
+ const [periodState, setPeriodState] = useState7(LEADERBOARD_DEFAULT_PERIOD);
5596
+ const [metricState, setMetricState] = useState7(LEADERBOARD_DEFAULT_METRIC);
5597
+ const period = periodProp != null ? periodProp : periodState;
5598
+ const metric = metricProp != null ? metricProp : metricState;
5599
+ const handlePeriodChange = useCallback5(
5600
+ (next) => {
5601
+ if (periodProp === void 0) setPeriodState(next);
5602
+ onPeriodChange == null ? void 0 : onPeriodChange(next);
5603
+ },
5604
+ [onPeriodChange, periodProp]
5605
+ );
5606
+ const handleMetricChange = useCallback5(
5607
+ (next) => {
5608
+ if (metricProp === void 0) setMetricState(next);
5609
+ onMetricChange == null ? void 0 : onMetricChange(next);
5610
+ },
5611
+ [metricProp, onMetricChange]
5612
+ );
5613
+ const shouldUseHookData = !rowsProp;
5614
+ const query = useLeaderboard({ period, metric, enabled: shouldUseHookData });
5615
+ const rows = rowsProp != null ? rowsProp : query.rows;
5616
+ const isLoading = isLoadingProp != null ? isLoadingProp : shouldUseHookData && query.isLoading;
5617
+ const error = errorProp != null ? errorProp : shouldUseHookData ? query.error : null;
5618
+ const hasNextPage = hasNextPageProp != null ? hasNextPageProp : shouldUseHookData && query.hasNextPage;
5619
+ const isLoadingMore = isLoadingMoreProp != null ? isLoadingMoreProp : shouldUseHookData && query.isFetchingNextPage;
5620
+ const fetchNextPage = query.fetchNextPage;
5621
+ const onLoadMore = useMemo5(
5622
+ () => onLoadMoreProp != null ? onLoadMoreProp : shouldUseHookData ? () => void fetchNextPage() : void 0,
5623
+ [onLoadMoreProp, shouldUseHookData, fetchNextPage]
5624
+ );
5625
+ const retry = shouldUseHookData ? () => void query.refetch() : void 0;
5626
+ const currentUserId = currentUserIdProp != null ? currentUserIdProp : user == null ? void 0 : user.id;
5627
+ const [sentinel, setSentinel] = useState7(null);
5628
+ useEffect6(() => {
5629
+ const target = sentinel;
5630
+ if (!target || !hasNextPage || !onLoadMore || typeof IntersectionObserver === "undefined")
5631
+ return;
5632
+ const observer = new IntersectionObserver(
5633
+ (entries) => {
5634
+ var _a;
5635
+ if (!((_a = entries[0]) == null ? void 0 : _a.isIntersecting) || isLoading || isLoadingMore) return;
5636
+ onLoadMore();
5637
+ },
5638
+ { rootMargin: "60px 0px" }
5639
+ );
5640
+ observer.observe(target);
5641
+ return () => observer.disconnect();
5642
+ }, [sentinel, hasNextPage, isLoading, isLoadingMore, onLoadMore]);
5643
+ const hasRows = rows.length > 0;
5644
+ const showInlineError = Boolean(error) && hasRows;
5645
+ const periodItems = LEADERBOARD_PERIODS.map((value) => ({ value, label: labels.periods[value] }));
5646
+ const metricItems = LEADERBOARD_METRICS.map((value) => ({ value, label: labels.metrics[value] }));
5647
+ return /* @__PURE__ */ jsxs17(
5648
+ "div",
5649
+ {
5650
+ className: cn(
5651
+ "agg-leaderboard mx-auto flex w-full max-w-[960px] flex-col px-4 py-6 sm:px-6 gap-5 font-agg-sans text-agg-foreground",
5652
+ className,
5653
+ classNames == null ? void 0 : classNames.root
5654
+ ),
5655
+ children: [
5656
+ /* @__PURE__ */ jsxs17("header", { className: cn("agg-leaderboard-title flex flex-col gap-1", classNames == null ? void 0 : classNames.header), children: [
5657
+ /* @__PURE__ */ jsx17("h1", { className: "agg-type-heading m-0", children: labels.title }),
5658
+ /* @__PURE__ */ jsx17("p", { className: "m-0 text-agg-sm leading-agg-5 text-agg-muted-foreground", children: labels.subtitle(appName, labels.periods[period]) })
5659
+ ] }),
5660
+ /* @__PURE__ */ jsxs17(
5661
+ "div",
5662
+ {
5663
+ className: cn(
5664
+ "agg-leaderboard-toolbar flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between",
5665
+ classNames == null ? void 0 : classNames.toolbar
5666
+ ),
5667
+ children: [
5668
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3", children: [
5669
+ /* @__PURE__ */ jsx17("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground", children: labels.periodLabel }),
5670
+ /* @__PURE__ */ jsx17(
5671
+ SegmentedControl,
5672
+ {
5673
+ label: labels.periodLabel,
5674
+ value: period,
5675
+ onChange: handlePeriodChange,
5676
+ items: periodItems
5677
+ }
5678
+ )
5679
+ ] }),
5680
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3", children: [
5681
+ /* @__PURE__ */ jsx17("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground", children: labels.rankByLabel }),
5682
+ /* @__PURE__ */ jsx17(
5683
+ SegmentedControl,
5684
+ {
5685
+ label: labels.rankByLabel,
5686
+ value: metric,
5687
+ onChange: handleMetricChange,
5688
+ items: metricItems
5689
+ }
5690
+ )
5691
+ ] })
5692
+ ]
5693
+ }
5694
+ ),
5695
+ /* @__PURE__ */ jsxs17(
5696
+ "section",
5697
+ {
5698
+ "aria-label": labels.title,
5699
+ className: cn(
5700
+ "agg-leaderboard-list overflow-clip rounded-agg-xl border border-agg-separator bg-agg-secondary shadow-agg-card",
5701
+ classNames == null ? void 0 : classNames.list
5702
+ ),
5703
+ children: [
5704
+ /* @__PURE__ */ jsxs17("div", { role: "table", "aria-label": labels.title, className: "agg-leaderboard-table", children: [
5705
+ /* @__PURE__ */ jsx17(LeaderboardHeaderRow, { metric, onMetricChange: handleMetricChange }),
5706
+ !isLoading && hasRows ? /* @__PURE__ */ jsx17("div", { className: "divide-y divide-agg-separator", children: rows.map((row) => /* @__PURE__ */ jsx17(
5707
+ LeaderboardRowView,
5708
+ {
5709
+ row,
5710
+ isCurrentUser: currentUserId !== void 0 && row.userId === currentUserId,
5711
+ className: classNames == null ? void 0 : classNames.row
5712
+ },
5713
+ row.userId
5714
+ )) }) : null
5715
+ ] }),
5716
+ isLoading ? /* @__PURE__ */ jsx17(LeaderboardSkeleton, {}) : error && !hasRows ? /* @__PURE__ */ jsx17("div", { className: "py-10", children: /* @__PURE__ */ jsx17(
5717
+ StateMessage,
5718
+ {
5719
+ title: labels.errorTitle,
5720
+ description: labels.errorDescription,
5721
+ icon: /* @__PURE__ */ jsx17(Icon, { name: "warning" }),
5722
+ onAction: retry
5723
+ }
5724
+ ) }) : rows.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "py-10", children: /* @__PURE__ */ jsx17(
5725
+ StateMessage,
5726
+ {
5727
+ title: labels.emptyTitle,
5728
+ description: labels.emptyDescription,
5729
+ icon: /* @__PURE__ */ jsx17(Icon, { name: "search-empty" })
5730
+ }
5731
+ ) }) : null,
5732
+ (hasNextPage || showInlineError) && !isLoading ? /* @__PURE__ */ jsx17(
5733
+ "div",
5734
+ {
5735
+ className: cn(
5736
+ "agg-leaderboard-footer relative flex items-center justify-center gap-3 border-t border-agg-separator p-3.5",
5737
+ classNames == null ? void 0 : classNames.footer
5738
+ ),
5739
+ children: showInlineError ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
5740
+ /* @__PURE__ */ jsx17("span", { role: "alert", className: "text-agg-sm leading-agg-5 text-agg-error", children: labels.errorTitle }),
5741
+ /* @__PURE__ */ jsx17(Button, { variant: "tertiary", size: "small", onClick: retry != null ? retry : onLoadMore, children: allLabels.common.retry })
5742
+ ] }) : /* @__PURE__ */ jsxs17(Fragment5, { children: [
5743
+ /* @__PURE__ */ jsx17(
5744
+ "div",
5745
+ {
5746
+ ref: setSentinel,
5747
+ className: "agg-leaderboard-sentinel absolute inset-x-0 top-0 h-px",
5748
+ "aria-hidden": true
5749
+ }
5750
+ ),
5751
+ /* @__PURE__ */ jsx17(
5752
+ Button,
5753
+ {
5754
+ variant: "tertiary",
5755
+ size: "small",
5756
+ onClick: onLoadMore,
5757
+ disabled: isLoadingMore,
5758
+ isLoading: isLoadingMore,
5759
+ "aria-label": labels.showMore,
5760
+ children: labels.showMore
5761
+ }
5762
+ )
5763
+ ] })
5764
+ }
5765
+ ) : null
5766
+ ]
5767
+ }
5768
+ ),
5769
+ /* @__PURE__ */ jsx17("p", { className: "m-0 text-agg-xs leading-agg-4 text-agg-muted-foreground", children: labels.pnlFootnote })
5770
+ ]
5771
+ }
5772
+ );
5773
+ }
5774
+ LeaderboardPage.displayName = "LeaderboardPage";
5775
+
5319
5776
  export {
5320
5777
  DefaultAvatar,
5321
5778
  ConditionalWrapper,
@@ -5327,5 +5784,9 @@ export {
5327
5784
  USER_PROFILE_TAB_ACTIVITY,
5328
5785
  buildAggTxExplorerHref,
5329
5786
  formatShareAmount,
5330
- UserProfilePage
5787
+ UserProfilePage,
5788
+ LEADERBOARD_DEFAULT_PERIOD,
5789
+ LEADERBOARD_DEFAULT_METRIC,
5790
+ LEADERBOARD_METRICS,
5791
+ LeaderboardPage
5331
5792
  };