@orderly.network/ui-order-entry 2.11.3-rc.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import React3, { forwardRef, useState, useImperativeHandle, useEffect, memo, createContext, useMemo, useRef, useCallback, useContext, useId } from 'react';
2
- import { useLocalStorage, utils, usePositionStream, useMarkets, MarketsType, useMarginModes, useMarginModeBySymbol, useEventEmitter, useDebouncedCallback, useFeeState, useRwaSymbolsInfoStore, useOrderlyContext, useMemoizedFn, ERROR_MSG_CODES, useOrderEntry, useMarginRatio, useComputedLTV, useTpslPriceChecker, useHoldingStream, useAppStore, useIndexPricesStream, useGetEstLiqPrice, useTrack, useQuery, useFeatureFlag, FlagKeys, useBoolean } from '@orderly.network/hooks';
2
+ import { useLocalStorage, utils, usePositionStream, useMarkets, MarketsType, useMarginModes, useMarginModeBySymbol, useBadgeBySymbol, useEventEmitter, useDebouncedCallback, useFeeState, useRwaSymbolsInfoStore, useOrderlyContext, useMemoizedFn, ERROR_MSG_CODES, useAccount, useOrderEntry, useMarginRatio, useComputedLTV, useTpslPriceChecker, useHoldingStream, useAppStore, useIndexPricesStream, useGetEstLiqPrice, useTrack, useQuery, useFeatureFlag, FlagKeys, useBoolean } from '@orderly.network/hooks';
3
3
  import { useTranslation, i18n } from '@orderly.network/i18n';
4
4
  import { useOrderEntryFormErrorMsg, useCanTrade } from '@orderly.network/react-app';
5
5
  import { EMPTY_LIST, DistributionType, TrailingCallbackType, OrderSide, OrderType, MarginMode, PositionType, BBOOrderType, ORDER_ENTRY_EST_LIQ_PRICE_CHANGE, OrderLevel, TrackerEventName } from '@orderly.network/types';
6
- import { ExclamationFillIcon, modal, Text, Tooltip, TooltipTrigger, Flex, Input, cn, inputFormatter, Box, registerSimpleDialog, SimpleDialog, registerSimpleSheet, Select, Grid, Checkbox, Slider, textVariants, SettingFillIcon, useModal, Badge, Divider, Button, TokenIcon, DataTable, useScreen, toast, IconButton, CloseIcon, CloseCircleFillIcon, ChevronRightIcon, SimpleDropdownMenu, CaretDownIcon, Switch, ThrottledButton, SimpleSheet, InfoCircleIcon, AddCircleIcon, PopoverRoot, PopoverTrigger, PopoverContent, DotStatus, EditIcon as EditIcon$1 } from '@orderly.network/ui';
6
+ import { ExclamationFillIcon, modal, Text, Tooltip, TooltipTrigger, Flex, Input, cn, inputFormatter, Box, registerSimpleDialog, SimpleDialog, registerSimpleSheet, Select, Grid, Checkbox, Slider, textVariants, SettingFillIcon, useModal, Badge, Divider, Button, TokenIcon, DataTable, useScreen, toast, IconButton, CloseIcon, CloseCircleFillIcon, ChevronRightIcon, SymbolBadge as SymbolBadge$1, SimpleDropdownMenu, CaretDownIcon, Switch, ThrottledButton, SimpleSheet, InfoCircleIcon, AddCircleIcon, PopoverRoot, PopoverTrigger, PopoverContent, DotStatus, EditIcon as EditIcon$1 } from '@orderly.network/ui';
7
7
  import { TPSLPositionTypeWidget, TPSLAdvancedWidget } from '@orderly.network/ui-tpsl';
8
8
  import { Decimal, zero, formatSymbol, todpIfNeed, getBBOType, removeTrailingZeros } from '@orderly.network/utils';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1149,6 +1149,13 @@ function getScaledPlaceOrderMessage(result) {
1149
1149
  var safeNumber = (val) => {
1150
1150
  return Number.isNaN(Number(val)) ? 0 : Number(val);
1151
1151
  };
1152
+ var SymbolBadge = (props) => {
1153
+ const { brokerId, brokerName, brokerNameRaw } = useBadgeBySymbol(
1154
+ props.symbol
1155
+ );
1156
+ const badge = brokerName ?? brokerId ?? void 0;
1157
+ return /* @__PURE__ */ jsx(SymbolBadge$1, { badge, fullName: brokerNameRaw });
1158
+ };
1152
1159
  var OrderConfirmDialog = (props) => {
1153
1160
  const { symbolInfo, order, onConfirm, onCancel } = props;
1154
1161
  const { quote, quote_dp, base_dp } = symbolInfo;
@@ -1306,15 +1313,19 @@ var OrderConfirmDialog = (props) => {
1306
1313
  justify: "between",
1307
1314
  className: "oui-orderEntry-orderConfirmDialog-header",
1308
1315
  children: [
1309
- /* @__PURE__ */ jsx(
1310
- Text.formatted,
1311
- {
1312
- rule: "symbol",
1313
- showIcon: true,
1314
- className: "oui-orderConfirmDialog-symbol",
1315
- children: order.symbol
1316
- }
1317
- ),
1316
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, direction: "column", itemAlign: "start", children: [
1317
+ /* @__PURE__ */ jsx(
1318
+ Text.formatted,
1319
+ {
1320
+ rule: "symbol",
1321
+ formatString: "base",
1322
+ showIcon: true,
1323
+ className: "oui-orderConfirmDialog-symbol",
1324
+ children: order.symbol
1325
+ }
1326
+ ),
1327
+ /* @__PURE__ */ jsx(SymbolBadge, { symbol: order.symbol })
1328
+ ] }),
1318
1329
  /* @__PURE__ */ jsxs(
1319
1330
  Flex,
1320
1331
  {
@@ -1613,6 +1624,136 @@ var MaxQtyConfirm = memo((props) => {
1613
1624
  }
1614
1625
  );
1615
1626
  });
1627
+ var PermissionlessMarketNoticeDialog = (props) => {
1628
+ const { onConfirm, onCancel } = props;
1629
+ const { t } = useTranslation();
1630
+ const [checked, setChecked] = useState(false);
1631
+ const content = /* @__PURE__ */ jsxs(
1632
+ Flex,
1633
+ {
1634
+ direction: "column",
1635
+ gap: 3,
1636
+ itemAlign: "start",
1637
+ className: "oui-permissionlessNotice-content",
1638
+ children: [
1639
+ /* @__PURE__ */ jsx(
1640
+ Text,
1641
+ {
1642
+ className: textVariants({
1643
+ size: "sm",
1644
+ intensity: 54
1645
+ }),
1646
+ children: t("orderEntry.permissionlessNotice.content1")
1647
+ }
1648
+ ),
1649
+ /* @__PURE__ */ jsx(
1650
+ Text,
1651
+ {
1652
+ className: textVariants({
1653
+ size: "sm",
1654
+ intensity: 54
1655
+ }),
1656
+ children: t("orderEntry.permissionlessNotice.content2")
1657
+ }
1658
+ ),
1659
+ /* @__PURE__ */ jsx(
1660
+ Text,
1661
+ {
1662
+ className: textVariants({
1663
+ size: "sm",
1664
+ intensity: 54
1665
+ }),
1666
+ children: t("orderEntry.permissionlessNotice.content3")
1667
+ }
1668
+ )
1669
+ ]
1670
+ }
1671
+ );
1672
+ const checkboxSection = /* @__PURE__ */ jsxs(
1673
+ Flex,
1674
+ {
1675
+ gapX: 1,
1676
+ pt: 4,
1677
+ pb: 5,
1678
+ itemAlign: "start",
1679
+ className: "oui-permissionlessNotice-checkbox oui-orderEntry-orderConfirmDialog-disableConfirm oui-cursor-pointer",
1680
+ children: [
1681
+ /* @__PURE__ */ jsx(
1682
+ Checkbox,
1683
+ {
1684
+ id: "permissionlessNotice",
1685
+ color: "white",
1686
+ className: "oui-permissionlessNotice-checkbox-input oui-mt-1",
1687
+ checked,
1688
+ onCheckedChange: (value) => setChecked(!!value)
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsx(
1692
+ "label",
1693
+ {
1694
+ htmlFor: "permissionlessNotice",
1695
+ className: textVariants({
1696
+ size: "xs",
1697
+ intensity: 54,
1698
+ className: "oui-cursor-pointer"
1699
+ }),
1700
+ children: t("orderEntry.permissionlessNotice.checkbox")
1701
+ }
1702
+ )
1703
+ ]
1704
+ }
1705
+ );
1706
+ const confirmButton = /* @__PURE__ */ jsx(
1707
+ Flex,
1708
+ {
1709
+ className: "oui-permissionlessNotice-confirm-button oui-w-full",
1710
+ justify: "center",
1711
+ children: /* @__PURE__ */ jsx(
1712
+ Button,
1713
+ {
1714
+ fullWidth: true,
1715
+ size: "md",
1716
+ className: "oui-permissionlessNotice-confirm oui-confirm-btn oui-max-w-[244px]",
1717
+ disabled: !checked,
1718
+ onClick: () => onConfirm(),
1719
+ children: t("common.confirm")
1720
+ }
1721
+ )
1722
+ }
1723
+ );
1724
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1725
+ content,
1726
+ checkboxSection,
1727
+ confirmButton
1728
+ ] });
1729
+ };
1730
+ PermissionlessMarketNoticeDialog.displayName = "PermissionlessMarketNoticeDialog";
1731
+ var Dialog2 = (props) => {
1732
+ const { close, resolve, reject } = props;
1733
+ return /* @__PURE__ */ jsx(
1734
+ PermissionlessMarketNoticeDialog,
1735
+ {
1736
+ onCancel: () => {
1737
+ reject();
1738
+ close();
1739
+ },
1740
+ onConfirm: () => {
1741
+ resolve();
1742
+ close();
1743
+ }
1744
+ }
1745
+ );
1746
+ };
1747
+ var permissionlessMarketNoticeDialogId = "permissionlessMarketNotice";
1748
+ var permissionlessMarketNoticeDesktopDialogId = "permissionlessMarketNoticeDesktop";
1749
+ registerSimpleDialog(permissionlessMarketNoticeDialogId, Dialog2, {
1750
+ size: "sm",
1751
+ title: () => i18n.t("orderEntry.permissionlessNotice.title")
1752
+ });
1753
+ registerSimpleDialog(permissionlessMarketNoticeDesktopDialogId, Dialog2, {
1754
+ size: "xl",
1755
+ title: () => i18n.t("orderEntry.permissionlessNotice.title")
1756
+ });
1616
1757
  var ScaledOrderConfirm = (props) => {
1617
1758
  const { order, symbolInfo, dataSource, national, askAndBid, totalQuantity } = props;
1618
1759
  const { base, quote, base_dp, quote_dp } = symbolInfo;
@@ -1637,7 +1778,7 @@ var ScaledOrderConfirm = (props) => {
1637
1778
  "div",
1638
1779
  {
1639
1780
  className: cn(
1640
- "oui-h-[38px] oui-w-1 oui-shrink-0 oui-rounded-[1px]",
1781
+ "oui-h-[42px] oui-w-1 oui-shrink-0 oui-rounded-[1px]",
1641
1782
  record.side === OrderSide.BUY ? "oui-bg-trade-profit" : "oui-bg-trade-loss"
1642
1783
  )
1643
1784
  }
@@ -1645,17 +1786,12 @@ var ScaledOrderConfirm = (props) => {
1645
1786
  /* @__PURE__ */ jsxs(Flex, { direction: "column", itemAlign: "start", children: [
1646
1787
  /* @__PURE__ */ jsxs(Flex, { gapX: 1, children: [
1647
1788
  /* @__PURE__ */ jsx(TokenIcon, { symbol: value, className: "oui-size-3" }),
1648
- /* @__PURE__ */ jsx(
1649
- Text.formatted,
1650
- {
1651
- rule: "symbol",
1652
- size: "xs",
1653
- formatString: "base-type",
1654
- children: value
1655
- }
1656
- )
1789
+ /* @__PURE__ */ jsx(Text.formatted, { rule: "symbol", size: "xs", formatString: "base", children: value })
1657
1790
  ] }),
1658
- /* @__PURE__ */ jsx(Badge, { color: "neutral", size: "xs", children: t("orderEntry.orderType.limit") })
1791
+ /* @__PURE__ */ jsxs(Flex, { gap: 1, children: [
1792
+ /* @__PURE__ */ jsx(SymbolBadge, { symbol: value }),
1793
+ /* @__PURE__ */ jsx(Badge, { color: "neutral", size: "xs", children: t("orderEntry.orderType.limit") })
1794
+ ] })
1659
1795
  ] })
1660
1796
  ] });
1661
1797
  }
@@ -1856,6 +1992,7 @@ registerSimpleDialog(scaledOrderConfirmDialogId, ScaledOrderConfirmWidget, {
1856
1992
  var OrderTypeSelect = (props) => {
1857
1993
  const { t } = useTranslation();
1858
1994
  const { isMobile } = useScreen();
1995
+ const { marketOrderDisabled = false, marketOrderDisabledTooltip } = props;
1859
1996
  const allOptions = useMemo(() => {
1860
1997
  return [
1861
1998
  { label: t("orderEntry.orderType.limitOrder"), value: OrderType.LIMIT },
@@ -1936,7 +2073,24 @@ var OrderTypeSelect = (props) => {
1936
2073
  children: /* @__PURE__ */ jsx(Text, { size: "xs", children: t("orderEntry.orderType.limit") })
1937
2074
  }
1938
2075
  ),
1939
- /* @__PURE__ */ jsx(
2076
+ marketOrderDisabled && marketOrderDisabledTooltip ? /* @__PURE__ */ jsx(
2077
+ Tooltip,
2078
+ {
2079
+ content: marketOrderDisabledTooltip,
2080
+ className: "oui-max-w-[275px]",
2081
+ children: /* @__PURE__ */ jsx("span", { className: "oui-inline-flex oui-flex-1", children: /* @__PURE__ */ jsx(
2082
+ "button",
2083
+ {
2084
+ type: "button",
2085
+ className: unselectedButtonClassName,
2086
+ "aria-pressed": false,
2087
+ disabled: true,
2088
+ "data-testid": "oui-testid-orderEntry-orderType-market",
2089
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", children: t("orderEntry.orderType.market") })
2090
+ }
2091
+ ) })
2092
+ }
2093
+ ) : /* @__PURE__ */ jsx(
1940
2094
  "button",
1941
2095
  {
1942
2096
  type: "button",
@@ -1986,14 +2140,25 @@ var OrderTypeSelect = (props) => {
1986
2140
  }
1987
2141
  );
1988
2142
  }
2143
+ const mobileOptions = useMemo(() => allOptions, [allOptions]);
2144
+ const handleMobileValueChange = (value) => {
2145
+ if (marketOrderDisabled && value === OrderType.MARKET && marketOrderDisabledTooltip) {
2146
+ modal.alert({
2147
+ title: t("common.tips"),
2148
+ message: marketOrderDisabledTooltip
2149
+ });
2150
+ return;
2151
+ }
2152
+ props.onChange(value);
2153
+ };
1989
2154
  return /* @__PURE__ */ jsx(
1990
2155
  Select.options,
1991
2156
  {
1992
2157
  testid: "oui-testid-orderEntry-orderType-button",
1993
2158
  currentValue: props.type,
1994
2159
  value: props.type,
1995
- options: allOptions,
1996
- onValueChange: props.onChange,
2160
+ options: mobileOptions,
2161
+ onValueChange: handleMobileValueChange,
1997
2162
  contentProps: {
1998
2163
  className: cn(
1999
2164
  "oui-orderEntry-orderTypeSelect-content",
@@ -2096,10 +2261,11 @@ var MarginModeSwitch = (props) => {
2096
2261
  {
2097
2262
  className: "oui-tracking-[0.03em]",
2098
2263
  rule: "symbol",
2099
- formatString: "base-type",
2264
+ formatString: "base",
2100
2265
  size: "base",
2101
2266
  weight: "semibold",
2102
2267
  intensity: 98,
2268
+ suffix: /* @__PURE__ */ jsx(SymbolBadge, { symbol: props.symbol }),
2103
2269
  children: props.symbol
2104
2270
  }
2105
2271
  )
@@ -2111,7 +2277,8 @@ var MarginModeSwitch = (props) => {
2111
2277
  mode: MarginMode.CROSS,
2112
2278
  selected: props.selectedMarginMode === MarginMode.CROSS,
2113
2279
  isCurrent: props.currentMarginMode === MarginMode.CROSS,
2114
- onClick: () => handleSelect(MarginMode.CROSS)
2280
+ onClick: () => handleSelect(MarginMode.CROSS),
2281
+ disabled: props.isPermissionlessListing
2115
2282
  }
2116
2283
  ),
2117
2284
  /* @__PURE__ */ jsx(
@@ -2174,9 +2341,11 @@ var OptionCard = (props) => {
2174
2341
  "oui-relative oui-w-full oui-rounded-md oui-p-2",
2175
2342
  "oui-bg-base-6",
2176
2343
  "oui-text-left",
2177
- props.selected ? "oui-border oui-border-[#38e2fe]" : "oui-border oui-border-transparent hover:oui-border-line-12"
2344
+ props.disabled ? "oui-cursor-not-allowed oui-opacity-50 oui-border oui-border-transparent" : props.selected ? "oui-border oui-border-[#38e2fe]" : "oui-border oui-border-transparent hover:oui-border-line-12"
2178
2345
  ),
2179
- onClick: props.onClick,
2346
+ onClick: props.disabled ? void 0 : props.onClick,
2347
+ disabled: props.disabled,
2348
+ "aria-disabled": props.disabled,
2180
2349
  "data-testid": `oui-testid-marginModeSwitch-option-${props.mode}`,
2181
2350
  children: [
2182
2351
  /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, itemAlign: "start", className: "oui-w-full", children: [
@@ -2209,7 +2378,11 @@ var useMarginModeSwitchScript = (options2) => {
2209
2378
  const { symbol, close } = options2;
2210
2379
  const { isMobile } = useScreen();
2211
2380
  const { t } = useTranslation();
2212
- const { marginMode: currentMarginMode, update } = useMarginModeBySymbol(symbol);
2381
+ const {
2382
+ marginMode: currentMarginMode,
2383
+ update,
2384
+ isPermissionlessListing
2385
+ } = useMarginModeBySymbol(symbol);
2213
2386
  const [selectedMarginMode, setSelectedMarginMode] = useState(currentMarginMode);
2214
2387
  useEffect(() => {
2215
2388
  setSelectedMarginMode(currentMarginMode);
@@ -2247,11 +2420,13 @@ var useMarginModeSwitchScript = (options2) => {
2247
2420
  setSelectedMarginMode,
2248
2421
  applyMarginMode,
2249
2422
  close,
2250
- onSelect
2423
+ onSelect,
2424
+ isPermissionlessListing
2251
2425
  };
2252
2426
  };
2253
2427
  var useMarginModeSettingsScript = (options2) => {
2254
2428
  const { isMobile } = useScreen();
2429
+ const { t } = useTranslation();
2255
2430
  const [markets] = useMarkets(MarketsType.ALL);
2256
2431
  const items = useMemo(() => {
2257
2432
  if (!markets || markets.length === 0) {
@@ -2260,10 +2435,20 @@ var useMarginModeSettingsScript = (options2) => {
2260
2435
  return markets.map((market) => ({
2261
2436
  key: market.symbol,
2262
2437
  // Original symbol: "PERP_BTC_USDC"
2263
- symbol: formatSymbol(market.symbol, "base-type")
2438
+ symbol: formatSymbol(market.symbol, "base"),
2264
2439
  // Formatted: "BTC-PERP"
2440
+ brokerId: market.broker_id
2265
2441
  }));
2266
2442
  }, [markets]);
2443
+ const brokerLockedKeys = useMemo(() => {
2444
+ const locked = /* @__PURE__ */ new Set();
2445
+ for (const item of items) {
2446
+ if (item.brokerId) {
2447
+ locked.add(item.key);
2448
+ }
2449
+ }
2450
+ return locked;
2451
+ }, [items]);
2267
2452
  const [searchKeyword, setSearchKeyword] = useState("");
2268
2453
  const [selectedKeys, setSelectedKeys] = useState(
2269
2454
  () => /* @__PURE__ */ new Set()
@@ -2284,11 +2469,15 @@ var useMarginModeSettingsScript = (options2) => {
2284
2469
  const itemMarginModes = useMemo(() => {
2285
2470
  const result = {};
2286
2471
  for (const item of items) {
2472
+ if (brokerLockedKeys.has(item.key)) {
2473
+ result[item.key] = MarginMode.ISOLATED;
2474
+ continue;
2475
+ }
2287
2476
  const marginMode = marginModes[item.key];
2288
2477
  result[item.key] = marginMode ?? MarginMode.CROSS;
2289
2478
  }
2290
2479
  return result;
2291
- }, [items, marginModes]);
2480
+ }, [brokerLockedKeys, items, marginModes]);
2292
2481
  const filteredItems = useMemo(() => {
2293
2482
  const keyword = searchKeyword.trim().toLowerCase();
2294
2483
  if (!keyword) return items;
@@ -2324,17 +2513,21 @@ var useMarginModeSettingsScript = (options2) => {
2324
2513
  const onSearchChange = useCallback((keyword) => {
2325
2514
  setSearchKeyword(keyword);
2326
2515
  }, []);
2327
- const onToggleItem = useCallback((key) => {
2328
- setSelectedKeys((prev) => {
2329
- const next = new Set(prev);
2330
- if (next.has(key)) {
2331
- next.delete(key);
2332
- } else {
2333
- next.add(key);
2334
- }
2335
- return next;
2336
- });
2337
- }, []);
2516
+ const onToggleItem = useCallback(
2517
+ (key) => {
2518
+ if (brokerLockedKeys.has(key)) return;
2519
+ setSelectedKeys((prev) => {
2520
+ const next = new Set(prev);
2521
+ if (next.has(key)) {
2522
+ next.delete(key);
2523
+ } else {
2524
+ next.add(key);
2525
+ }
2526
+ return next;
2527
+ });
2528
+ },
2529
+ [brokerLockedKeys]
2530
+ );
2338
2531
  const onToggleSelectAll = useCallback(() => {
2339
2532
  setSelectedKeys((prev) => {
2340
2533
  const next = new Set(prev);
@@ -2345,31 +2538,39 @@ var useMarginModeSettingsScript = (options2) => {
2345
2538
  return next;
2346
2539
  }
2347
2540
  for (const item of filteredItems) {
2541
+ if (brokerLockedKeys.has(item.key)) continue;
2348
2542
  next.add(item.key);
2349
2543
  }
2350
2544
  return next;
2351
2545
  });
2352
- }, [filteredItems, isSelectAll]);
2546
+ }, [brokerLockedKeys, filteredItems, isSelectAll]);
2353
2547
  const onSetMarginMode = useCallback(
2354
2548
  async (mode) => {
2355
2549
  if (selectedKeys.size === 0) return;
2550
+ const editableSymbolList = Array.from(selectedKeys).filter(
2551
+ (key) => !brokerLockedKeys.has(key)
2552
+ );
2553
+ if (editableSymbolList.length === 0) {
2554
+ toast.error(t("marginMode.noEditableSymbolsSelected"));
2555
+ return;
2556
+ }
2356
2557
  setIsOperationLoading(true);
2357
2558
  try {
2358
2559
  const payload = {
2359
- symbol_list: Array.from(selectedKeys),
2560
+ symbol_list: editableSymbolList,
2360
2561
  default_margin_mode: mode
2361
2562
  };
2362
2563
  await updateMarginMode(payload);
2363
- toast.success("Updated successfully");
2564
+ toast.success(t("marginMode.updatedSuccessfully"));
2364
2565
  } catch (error) {
2365
2566
  toast.error(
2366
- error instanceof Error ? error.message : "Failed to update margin mode"
2567
+ error instanceof Error ? error.message : t("marginMode.failedToUpdateMarginMode")
2367
2568
  );
2368
2569
  } finally {
2369
2570
  setIsOperationLoading(false);
2370
2571
  }
2371
2572
  },
2372
- [selectedKeys, updateMarginMode]
2573
+ [brokerLockedKeys, selectedKeys, updateMarginMode]
2373
2574
  );
2374
2575
  const isLoading = isDataLoading || isMarginModesLoading || isOperationLoading || isSettingMarginMode;
2375
2576
  return {
@@ -2517,7 +2718,8 @@ var MarginModeSettings = (props) => {
2517
2718
  item,
2518
2719
  checked: props.selectedKeys.has(item.key),
2519
2720
  marginMode: props.itemMarginModes[item.key] ?? MarginMode.CROSS,
2520
- onToggle: props.onToggleItem
2721
+ onToggle: props.onToggleItem,
2722
+ disabled: !!item.brokerId
2521
2723
  },
2522
2724
  item.key
2523
2725
  ))
@@ -2620,13 +2822,15 @@ var MarginModeSettings = (props) => {
2620
2822
  var SymbolRow = (props) => {
2621
2823
  const { t } = useTranslation();
2622
2824
  const handleCheckedChange = useCallback(() => {
2825
+ if (props.disabled) return;
2623
2826
  props.onToggle(props.item.key);
2624
2827
  }, [props]);
2625
- return /* @__PURE__ */ jsx(Flex, { itemAlign: "center", className: "oui-w-full", children: /* @__PURE__ */ jsxs(
2828
+ const row = /* @__PURE__ */ jsx(Flex, { itemAlign: "center", className: "oui-w-full", children: /* @__PURE__ */ jsxs(
2626
2829
  "label",
2627
2830
  {
2628
2831
  className: cn(
2629
- "oui-flex oui-items-center oui-gap-2 oui-flex-1 oui-cursor-pointer oui-select-none oui-w-full"
2832
+ "oui-flex oui-items-center oui-gap-2 oui-flex-1 oui-cursor-pointer oui-select-none oui-w-full",
2833
+ props.disabled ? "oui-cursor-not-allowed oui-opacity-50" : ""
2630
2834
  ),
2631
2835
  "data-testid": `oui-testid-marginModeSettings-item-${props.item.key}`,
2632
2836
  children: [
@@ -2636,10 +2840,12 @@ var SymbolRow = (props) => {
2636
2840
  color: "white",
2637
2841
  checked: props.checked,
2638
2842
  onCheckedChange: handleCheckedChange,
2639
- "aria-label": props.item.symbol
2843
+ "aria-label": props.item.symbol,
2844
+ disabled: props.disabled
2640
2845
  }
2641
2846
  ),
2642
2847
  /* @__PURE__ */ jsx(Text, { className: "oui-text-sm oui-font-semibold oui-text-base-contrast-80", children: props.item.symbol }),
2848
+ /* @__PURE__ */ jsx(SymbolBadge, { symbol: props.item.key }),
2643
2849
  /* @__PURE__ */ jsx(
2644
2850
  "span",
2645
2851
  {
@@ -2655,6 +2861,17 @@ var SymbolRow = (props) => {
2655
2861
  ]
2656
2862
  }
2657
2863
  ) });
2864
+ if (props.disabled) {
2865
+ return /* @__PURE__ */ jsx(
2866
+ Tooltip,
2867
+ {
2868
+ content: t("marginMode.disabledSymbolTooltip"),
2869
+ className: "oui-max-w-[280px] oui-text-2xs oui-text-base-contrast-80",
2870
+ children: row
2871
+ }
2872
+ );
2873
+ }
2874
+ return row;
2658
2875
  };
2659
2876
  var SearchGlyph = (props) => {
2660
2877
  return /* @__PURE__ */ jsx(
@@ -2846,7 +3063,9 @@ function OrderEntryHeader(props) {
2846
3063
  canTrade,
2847
3064
  onChange: (type) => {
2848
3065
  setOrderValue("order_type", type);
2849
- }
3066
+ },
3067
+ marketOrderDisabled: props.marketOrderDisabled,
3068
+ marketOrderDisabledTooltip: props.marketOrderDisabledTooltip
2850
3069
  }
2851
3070
  ) }),
2852
3071
  /* @__PURE__ */ jsxs(
@@ -4617,12 +4836,15 @@ var usePNLInputBuilder = (props) => {
4617
4836
  }
4618
4837
  if (value === "" || value === "-") return "";
4619
4838
  if (mode === "Offset%" /* PERCENTAGE */) {
4620
- return `${new Decimal(
4621
- value.replace(
4622
- new RegExp(percentageSuffix.current.replace(".", "\\.") + "$"),
4623
- ""
4624
- )
4625
- ).mul(100).todp(2, 4).toString()}${percentageSuffix.current}`;
4839
+ let normalized = value.replace(
4840
+ new RegExp(percentageSuffix.current.replace(".", "\\.") + "$"),
4841
+ ""
4842
+ ).replace(/,/g, "");
4843
+ normalized = normalized.replace(/\.$/, "");
4844
+ if (isNaN(Number(normalized)) || normalized === "" || normalized === "-") {
4845
+ return value;
4846
+ }
4847
+ return `${new Decimal(normalized).mul(100).todp(2, 4).toString()}${percentageSuffix.current}`;
4626
4848
  } else if (mode === "Offset" /* OFFSET */) {
4627
4849
  value = todpIfNeed(value, dp);
4628
4850
  } else ;
@@ -4641,6 +4863,9 @@ var usePNLInputBuilder = (props) => {
4641
4863
  } else {
4642
4864
  percentageSuffix.current = "";
4643
4865
  }
4866
+ if (isNaN(Number(value))) {
4867
+ return value;
4868
+ }
4644
4869
  value = new Decimal(value).div(100).toString();
4645
4870
  value = `${value}${percentageSuffix.current}`;
4646
4871
  }
@@ -5176,6 +5401,7 @@ var OrderEntry = (props) => {
5176
5401
  setOrderValue,
5177
5402
  manualSetOrderValue,
5178
5403
  setOrderValues,
5404
+ setOrderValuesRaw,
5179
5405
  symbolInfo,
5180
5406
  maxQty,
5181
5407
  freeCollateral,
@@ -5191,9 +5417,13 @@ var OrderEntry = (props) => {
5191
5417
  fillMiddleValue,
5192
5418
  soundAlert,
5193
5419
  setSoundAlert,
5194
- currentFocusInput
5420
+ currentFocusInput,
5421
+ walletAddress,
5422
+ isPermissionlessListing,
5423
+ symbol
5195
5424
  } = props;
5196
5425
  const [maxQtyConfirmOpen, setMaxQtyConfirmOpen] = useState(false);
5426
+ const [permissionlessAcknowledgedKeys, setPermissionlessAcknowledgedKeys] = useLocalStorage("orderly-permissionless-market-notice", []);
5197
5427
  const { t } = useTranslation();
5198
5428
  const { isMobile } = useScreen();
5199
5429
  const [hasAdvancedTPSLResult, setHasAdvancedTPSLResult] = useState(false);
@@ -5263,22 +5493,7 @@ var OrderEntry = (props) => {
5263
5493
  helper.validate(isSlPriceError ? props.slPriceError : void 0).then(
5264
5494
  // validate success, it return the order
5265
5495
  // TODO: get order from other function
5266
- (order) => {
5267
- if (isScaledOrder) {
5268
- return modal.show(scaledOrderConfirmDialogId, {
5269
- order,
5270
- symbolInfo,
5271
- size: isMobile ? "sm" : "md"
5272
- });
5273
- }
5274
- if (needConfirm) {
5275
- return modal.show(orderConfirmDialogId, {
5276
- order: formattedOrder,
5277
- symbolInfo
5278
- });
5279
- }
5280
- return true;
5281
- },
5496
+ (order) => order,
5282
5497
  // should catch validate error first, then submit
5283
5498
  (errors2) => {
5284
5499
  if (errors2.slippage) {
@@ -5287,7 +5502,38 @@ var OrderEntry = (props) => {
5287
5502
  setErrorMsgVisible(true);
5288
5503
  return Promise.reject();
5289
5504
  }
5290
- ).then(() => {
5505
+ ).then((order) => {
5506
+ const shouldShowPermissionlessNotice = isPermissionlessListing && walletAddress && !(permissionlessAcknowledgedKeys ?? []).includes(
5507
+ `${walletAddress}_${symbol}`
5508
+ );
5509
+ if (shouldShowPermissionlessNotice) {
5510
+ return modal.show(
5511
+ isMobile ? permissionlessMarketNoticeDialogId : permissionlessMarketNoticeDesktopDialogId
5512
+ ).then(() => {
5513
+ setPermissionlessAcknowledgedKeys([
5514
+ ...Array.isArray(permissionlessAcknowledgedKeys) ? permissionlessAcknowledgedKeys : [],
5515
+ `${walletAddress}_${symbol}`
5516
+ ]);
5517
+ return order;
5518
+ });
5519
+ }
5520
+ return Promise.resolve(order);
5521
+ }).then((order) => {
5522
+ if (isScaledOrder) {
5523
+ return modal.show(scaledOrderConfirmDialogId, {
5524
+ order,
5525
+ symbolInfo,
5526
+ size: isMobile ? "sm" : "md"
5527
+ });
5528
+ }
5529
+ if (needConfirm) {
5530
+ return modal.show(orderConfirmDialogId, {
5531
+ order: formattedOrder,
5532
+ symbolInfo
5533
+ });
5534
+ }
5535
+ return true;
5536
+ }).then(() => {
5291
5537
  return submit({ resetOnSuccess: false }).then((result) => {
5292
5538
  if (!result.success && result.message) {
5293
5539
  toast.error(result.message);
@@ -5355,7 +5601,7 @@ var OrderEntry = (props) => {
5355
5601
  if (order.side !== formattedOrder.side) {
5356
5602
  manualSetOrderValue("side", order.side);
5357
5603
  }
5358
- setOrderValues({
5604
+ setOrderValuesRaw({
5359
5605
  position_type: order.position_type,
5360
5606
  tp_order_type: order.tp_order_type,
5361
5607
  tp_pnl: order.tp_pnl,
@@ -5454,7 +5700,11 @@ var OrderEntry = (props) => {
5454
5700
  order_type: formattedOrder.order_type,
5455
5701
  setOrderValue: manualSetOrderValue,
5456
5702
  symbolLeverage: props.symbolLeverage,
5457
- marginMode: props.marginMode
5703
+ marginMode: props.marginMode,
5704
+ marketOrderDisabled: props.isSymbolPostOnly,
5705
+ marketOrderDisabledTooltip: t(
5706
+ "orderEntry.orderType.symbolPostOnly.tooltip"
5707
+ )
5458
5708
  }
5459
5709
  ),
5460
5710
  /* @__PURE__ */ jsx(
@@ -5852,11 +6102,14 @@ var useOrderEntryScript = (inputs) => {
5852
6102
  defaultSoundValue ?? null
5853
6103
  );
5854
6104
  const canTrade = useCanTrade();
5855
- const { marginMode } = useMarginModeBySymbol(symbol);
6105
+ const { state: accountState } = useAccount();
6106
+ const { marginMode, isPermissionlessListing } = useMarginModeBySymbol(symbol);
6107
+ const walletAddress = accountState?.address;
5856
6108
  const {
5857
6109
  formattedOrder,
5858
6110
  setValue,
5859
6111
  setValues: setOrderValues,
6112
+ setValuesRaw: setOrderValuesRaw,
5860
6113
  symbolInfo,
5861
6114
  symbolLeverage,
5862
6115
  ...state
@@ -6052,6 +6305,16 @@ var useOrderEntryScript = (inputs) => {
6052
6305
  setValue("distribution_type", DistributionType.FLAT);
6053
6306
  }
6054
6307
  }, [formattedOrder.order_type, formattedOrder.distribution_type]);
6308
+ const isSymbolPostOnly = symbolInfo?.status === "POST_ONLY";
6309
+ useEffect(() => {
6310
+ if (isSymbolPostOnly && (formattedOrder.order_type === OrderType.MARKET || formattedOrder.order_type === OrderType.STOP_MARKET)) {
6311
+ setLocalOrderType(OrderType.LIMIT);
6312
+ setOrderValues({
6313
+ order_type: OrderType.LIMIT,
6314
+ order_type_ext: void 0
6315
+ });
6316
+ }
6317
+ }, [isSymbolPostOnly, formattedOrder.order_type, setOrderValues]);
6055
6318
  const currentLtv = useComputedLTV();
6056
6319
  const askAndBid = useAskAndBid();
6057
6320
  const fillMiddleValue = () => {
@@ -6115,6 +6378,7 @@ var useOrderEntryScript = (inputs) => {
6115
6378
  setOrderValue,
6116
6379
  manualSetOrderValue,
6117
6380
  setOrderValues,
6381
+ setOrderValuesRaw,
6118
6382
  // account-level leverage (for other consumers)
6119
6383
  currentLeverage,
6120
6384
  // symbol-level leverage & margin mode for this order entry
@@ -6143,7 +6407,10 @@ var useOrderEntryScript = (inputs) => {
6143
6407
  symbol,
6144
6408
  soundAlert,
6145
6409
  setSoundAlert,
6146
- currentFocusInput
6410
+ currentFocusInput,
6411
+ walletAddress,
6412
+ isPermissionlessListing,
6413
+ isSymbolPostOnly
6147
6414
  };
6148
6415
  };
6149
6416
  var OrderEntryWidget = (props) => {
@@ -6158,6 +6425,6 @@ var OrderEntryWidget = (props) => {
6158
6425
  );
6159
6426
  };
6160
6427
 
6161
- export { AdditionalInfo, FeesWidget, LTVRiskTooltipWidget, OrderConfirmDialog, OrderEntry, OrderEntryWidget, useOrderEntryScript };
6428
+ export { AdditionalInfo, FeesWidget, LTVRiskTooltipWidget, OrderConfirmDialog, OrderEntry, OrderEntryWidget, SymbolBadge, useOrderEntryScript };
6162
6429
  //# sourceMappingURL=index.mjs.map
6163
6430
  //# sourceMappingURL=index.mjs.map