@agg-build/ui 4.7.1 → 4.7.3

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.
@@ -9,12 +9,12 @@ import {
9
9
  getTradingVenueLabel,
10
10
  prepareSettlementDifferences,
11
11
  resolveOrderEligibilityMessage
12
- } from "./chunk-WYCSTAN7.mjs";
12
+ } from "./chunk-MAQ52KM5.mjs";
13
13
  import {
14
14
  ConnectKalshiModal,
15
15
  GeoBlockBanner,
16
16
  subscribeAggDepositNotification
17
- } from "./chunk-XN2NB2NP.mjs";
17
+ } from "./chunk-XR6C3MZX.mjs";
18
18
  import {
19
19
  AGG_TERMS_OF_SERVICE_URL,
20
20
  Button,
@@ -47,7 +47,7 @@ import {
47
47
  resolveResolvedOutcomeLabel,
48
48
  skeletonViews,
49
49
  useOptionalToast
50
- } from "./chunk-RDBMHBR2.mjs";
50
+ } from "./chunk-UQ7XJIAZ.mjs";
51
51
 
52
52
  // src/trading/types.ts
53
53
  import { Venue, enumGuard, isFiniteNonNeg, safeParse } from "@agg-build/sdk";
@@ -993,6 +993,37 @@ var findMatchingVenueOutcome = (market, selectedOutcome) => {
993
993
  return normalizedLabel !== "" && selectedNames.has(normalizedLabel);
994
994
  })) != null ? _b : null;
995
995
  };
996
+ var resolveSellableSharesByVenue = ({
997
+ positions,
998
+ market,
999
+ selectedOutcome
1000
+ }) => {
1001
+ var _a, _b, _c, _d, _e, _f, _g;
1002
+ const sharesByVenue = /* @__PURE__ */ new Map();
1003
+ if (!market || !selectedOutcome) return sharesByVenue;
1004
+ const normalizedSelectedOutcomeLabel = normalizeOutcomeName(selectedOutcome.label);
1005
+ const selectedMarketIdSet = new Set(
1006
+ [
1007
+ market.id,
1008
+ (_a = market.marketId) != null ? _a : void 0,
1009
+ (_b = market.externalIdentifier) != null ? _b : void 0,
1010
+ ...((_c = market.matchedVenueMarkets) != null ? _c : []).map((matched) => matched.id)
1011
+ ].filter((value) => Boolean(value))
1012
+ );
1013
+ for (const group of positions) {
1014
+ for (const outcome of (_e = (_d = group.venueMarket) == null ? void 0 : _d.venueMarketOutcomes) != null ? _e : []) {
1015
+ if (normalizeOutcomeName(outcome.label) !== normalizedSelectedOutcomeLabel) continue;
1016
+ for (const breakdown of (_f = outcome.venueBreakdown) != null ? _f : []) {
1017
+ const matchesMarketId = selectedMarketIdSet.size === 0 || selectedMarketIdSet.has(group.targetMarketId) || selectedMarketIdSet.has(breakdown.venueMarketId);
1018
+ if (!matchesMarketId) continue;
1019
+ const size = Number.isFinite(breakdown.size) ? breakdown.size : 0;
1020
+ if (size <= 0) continue;
1021
+ sharesByVenue.set(breakdown.venue, ((_g = sharesByVenue.get(breakdown.venue)) != null ? _g : 0) + size);
1022
+ }
1023
+ }
1024
+ }
1025
+ return sharesByVenue;
1026
+ };
996
1027
  var buildLimitOrderVenueOptions = ({
997
1028
  currentPrices,
998
1029
  livePrices,
@@ -4255,6 +4286,14 @@ var PlaceOrder = ({
4255
4286
  enabled: Boolean(isAuthenticated && isSell),
4256
4287
  mode: isPaperMode ? "paper" : void 0
4257
4288
  });
4289
+ const sellableSharesByVenue = useMemo(
4290
+ () => isSell ? resolveSellableSharesByVenue({
4291
+ positions: executionPositions,
4292
+ market: scopedSelectedMarket,
4293
+ selectedOutcome: scopedSelectedOutcome
4294
+ }) : /* @__PURE__ */ new Map(),
4295
+ [executionPositions, isSell, scopedSelectedMarket, scopedSelectedOutcome]
4296
+ );
4258
4297
  const isSmartRouteEnabled = !isLimitOrder && isQuotePanelActive && !isEndedWithoutKnownWinner && !submissionProgressState && !isBeforeActionPending && !executeManaged.isPending && debouncedAmount > 0 && orderEligibility.canPlaceOrder && // On the sell tab, hold the quote until the amount has been initialized
4259
4298
  // from the user's position for THIS outcome AND the debounced value has
4260
4299
  // caught up to it. The amount input is shared with the buy tab, so right
@@ -4305,13 +4344,26 @@ var PlaceOrder = ({
4305
4344
  }, [limitVenueQuotes.quotes]);
4306
4345
  const availableLimitVenueOptions = useMemo(() => {
4307
4346
  return visibleLimitVenueOptions.filter((option) => {
4308
- return !geoBlockedLimitVenues.has(option.venue) && getVenueAvailabilityState({
4347
+ var _a2;
4348
+ return !geoBlockedLimitVenues.has(option.venue) && // A limit SELL rests against shares held at that specific venue, so a
4349
+ // venue the user has no position on is a guaranteed 409 from the
4350
+ // server's reservation check — and the automatic pick, which sorts on
4351
+ // price alone, would happily choose one. Only narrow once we know
4352
+ // where the shares are; an empty map means positions haven't resolved.
4353
+ (!isSell || sellableSharesByVenue.size === 0 || ((_a2 = sellableSharesByVenue.get(option.venue)) != null ? _a2 : 0) > 0) && getVenueAvailabilityState({
4309
4354
  venueId: option.venue,
4310
4355
  disabledVenues,
4311
4356
  isConfigLoading: isAppConfigLoading
4312
4357
  }) === "available";
4313
4358
  });
4314
- }, [disabledVenues, geoBlockedLimitVenues, isAppConfigLoading, visibleLimitVenueOptions]);
4359
+ }, [
4360
+ disabledVenues,
4361
+ geoBlockedLimitVenues,
4362
+ isAppConfigLoading,
4363
+ isSell,
4364
+ sellableSharesByVenue,
4365
+ visibleLimitVenueOptions
4366
+ ]);
4315
4367
  const automaticLimitVenueOption = useMemo(
4316
4368
  () => resolveAutomaticLimitOrderVenueOption(availableLimitVenueOptions, internalTab),
4317
4369
  [availableLimitVenueOptions, internalTab]
@@ -4413,39 +4465,15 @@ var PlaceOrder = ({
4413
4465
  refreshContext: smartRouteRefreshContext
4414
4466
  });
4415
4467
  const currentSellableShares = useMemo(() => {
4416
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2;
4468
+ var _a2, _b2;
4417
4469
  const sharesFromQuote = (_b2 = (_a2 = smartRoute.data) == null ? void 0 : _a2.positionAvailability) == null ? void 0 : _b2.totalSellableShares;
4418
4470
  if (typeof sharesFromQuote === "number" && Number.isFinite(sharesFromQuote)) {
4419
4471
  return Math.max(0, sharesFromQuote);
4420
4472
  }
4421
- if (!isSell || !scopedSelectedOutcome || !scopedSelectedMarket) return 0;
4422
- const normalizedSelectedOutcomeLabel = scopedSelectedOutcome.label.trim().toLowerCase();
4423
- const selectedMarketIds = [
4424
- scopedSelectedMarket.id,
4425
- (_c2 = scopedSelectedMarket.marketId) != null ? _c2 : void 0,
4426
- (_d2 = scopedSelectedMarket.externalIdentifier) != null ? _d2 : void 0
4427
- ].filter((value) => Boolean(value));
4428
- const selectedMarketIdSet = new Set(selectedMarketIds);
4429
4473
  let resolvedShares = 0;
4430
- for (const group of executionPositions) {
4431
- const groupOutcomes = (_f2 = (_e2 = group.venueMarket) == null ? void 0 : _e2.venueMarketOutcomes) != null ? _f2 : [];
4432
- for (const outcome of groupOutcomes) {
4433
- if (outcome.label.trim().toLowerCase() !== normalizedSelectedOutcomeLabel) continue;
4434
- for (const breakdown of (_g2 = outcome.venueBreakdown) != null ? _g2 : []) {
4435
- const matchesMarketId = selectedMarketIdSet.size === 0 || selectedMarketIdSet.has(group.targetMarketId) || selectedMarketIdSet.has(breakdown.venueMarketId);
4436
- if (!matchesMarketId) continue;
4437
- resolvedShares += Number.isFinite(breakdown.size) ? breakdown.size : 0;
4438
- }
4439
- }
4440
- }
4474
+ for (const size of sellableSharesByVenue.values()) resolvedShares += size;
4441
4475
  return Math.max(0, resolvedShares);
4442
- }, [
4443
- executionPositions,
4444
- isSell,
4445
- scopedSelectedMarket,
4446
- scopedSelectedOutcome,
4447
- (_q = (_p = smartRoute.data) == null ? void 0 : _p.positionAvailability) == null ? void 0 : _q.totalSellableShares
4448
- ]);
4476
+ }, [sellableSharesByVenue, (_q = (_p = smartRoute.data) == null ? void 0 : _p.positionAvailability) == null ? void 0 : _q.totalSellableShares]);
4449
4477
  const maxSellableShares = useMemo(
4450
4478
  () => floorToDecimals(currentSellableShares, SELL_SHARE_INPUT_DECIMALS),
4451
4479
  [currentSellableShares]