@orderly.network/ui-order-entry 3.0.0-beta.0 → 3.0.0-beta.10

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.js CHANGED
@@ -547,1225 +547,799 @@ var EditIcon = (props) => {
547
547
  }
548
548
  );
549
549
  };
550
- var RegularFeesUI = (props) => {
551
- const { t } = i18n.useTranslation();
552
- const { taker, maker } = props;
553
- const originalTrailingFees = /* @__PURE__ */ jsxRuntime.jsx(
554
- ui.Flex,
555
- {
556
- itemAlign: "center",
557
- justify: "between",
558
- width: "100%",
559
- gap: 1,
560
- className: "oui-orderEntry-fees",
561
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", itemAlign: "center", justify: "between", children: [
562
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-fees-label oui-truncate", size: "2xs", children: t("common.fees") }),
563
- /* @__PURE__ */ jsxRuntime.jsx(
564
- uiConnector.AuthGuard,
565
- {
566
- fallback: () => /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
567
- t("dmm.taker"),
568
- ": --% / ",
569
- t("dmm.maker"),
570
- ": --%"
571
- ] }),
572
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, className: "oui-fees-value-container", children: [
573
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
574
- t("dmm.taker"),
575
- ":"
576
- ] }),
577
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-base-contrast-80", children: taker }),
578
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: "/" }),
579
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
580
- t("dmm.maker"),
581
- ":"
582
- ] }),
583
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-base-contrast-80", children: maker })
584
- ] })
585
- }
586
- )
587
- ] })
550
+ function isBBOOrder(options2) {
551
+ const { order_type, order_type_ext } = options2;
552
+ const isBBO = [types.OrderType.ASK, types.OrderType.BID].includes(order_type_ext);
553
+ if (order_type) {
554
+ return order_type === types.OrderType.LIMIT && isBBO;
555
+ }
556
+ return isBBO;
557
+ }
558
+ function getOrderTypeByBBO(value, size) {
559
+ if ([types.BBOOrderType.COUNTERPARTY1, types.BBOOrderType.COUNTERPARTY5].includes(value)) {
560
+ return size === types.OrderSide.BUY ? types.OrderType.ASK : types.OrderType.BID;
561
+ }
562
+ if ([types.BBOOrderType.QUEUE1, types.BBOOrderType.QUEUE5].includes(value)) {
563
+ return size === types.OrderSide.BUY ? types.OrderType.BID : types.OrderType.ASK;
564
+ }
565
+ }
566
+ function getOrderLevelByBBO(value) {
567
+ if ([types.BBOOrderType.COUNTERPARTY1, types.BBOOrderType.QUEUE1].includes(value)) {
568
+ return types.OrderLevel.ONE;
569
+ }
570
+ if ([types.BBOOrderType.COUNTERPARTY5, types.BBOOrderType.QUEUE5].includes(value)) {
571
+ return types.OrderLevel.FIVE;
572
+ }
573
+ }
574
+ function getScaledPlaceOrderMessage(result) {
575
+ const rows = result?.data?.rows || [];
576
+ if (rows.length > 0) {
577
+ const totalCount = rows.length;
578
+ const successCount = rows.filter((row) => row.success).length;
579
+ if (successCount === totalCount) {
580
+ return i18n.i18n.t("orderEntry.scaledOrder.fullySuccessful", {
581
+ total: totalCount
582
+ });
588
583
  }
589
- );
590
- return originalTrailingFees;
591
- };
592
- var RegularFeesWidget = (props) => {
593
- return /* @__PURE__ */ jsxRuntime.jsx(RegularFeesUI, { ...props });
594
- };
595
- var FeesWidget = ({ symbol }) => {
596
- const { takerFee, makerFee, rwaTakerFee, rwaMakerFee } = hooks.useFeeState();
597
- const info = hooks.useRwaSymbolsInfoStore();
598
- const isRwa = info?.[symbol] !== void 0;
599
- return /* @__PURE__ */ jsxRuntime.jsx(
600
- RegularFeesWidget,
601
- {
602
- taker: isRwa ? rwaTakerFee : takerFee,
603
- maker: isRwa ? rwaMakerFee : makerFee
584
+ if (successCount === 0) {
585
+ return i18n.i18n.t("orderEntry.scaledOrder.allFailed");
604
586
  }
587
+ return i18n.i18n.t("orderEntry.scaledOrder.partiallySuccessful", {
588
+ successCount,
589
+ total: totalCount
590
+ });
591
+ }
592
+ }
593
+ var safeNumber = (val) => {
594
+ return Number.isNaN(Number(val)) ? 0 : Number(val);
595
+ };
596
+ var SymbolBadge = (props) => {
597
+ const { brokerId, brokerName, brokerNameRaw } = hooks.useBadgeBySymbol(
598
+ props.symbol
605
599
  );
600
+ const badge = brokerName ?? brokerId ?? void 0;
601
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.SymbolBadge, { badge, fullName: brokerNameRaw });
606
602
  };
607
- var options = [0.01, 0.05, 0.1];
608
- var SlippageEditor = React3.forwardRef((props, ref) => {
603
+ var OrderConfirmDialog = (props) => {
604
+ const { symbolInfo, order, onConfirm, onCancel } = props;
605
+ const { quote, quote_dp, base_dp } = symbolInfo;
606
+ const { side, order_type, order_type_ext, level, symbol } = order;
607
+ const orderMarginMode = order.margin_mode;
609
608
  const { t } = i18n.useTranslation();
610
- const [value, setValue] = React3.useState();
611
- const [customValue, setCustomValue] = React3.useState("");
612
- const [error, setError] = React3.useState(void 0);
613
- React3.useImperativeHandle(ref, () => ({
614
- getValue: () => customValue ? new utils.Decimal(customValue)?.toNumber() : value
615
- }));
616
- React3.useEffect(() => {
617
- if (props.initialValue && !options.includes(props.initialValue)) {
618
- setCustomValue(props.initialValue.toString());
619
- } else {
620
- setValue(props.initialValue);
609
+ const [{ rows: positions }] = hooks.usePositionStream(symbol);
610
+ const position = React3.useMemo(
611
+ () => orderMarginMode != null ? positions?.find(
612
+ (row) => row.symbol === symbol && row.margin_mode === orderMarginMode
613
+ ) : positions?.[0],
614
+ [positions, symbol, orderMarginMode]
615
+ );
616
+ const positionQty = position?.position_qty;
617
+ const [_, setNeedConfirm] = hooks.useLocalStorage("orderly_order_confirm", true);
618
+ const renderPositionType = () => {
619
+ if (order.position_type === types.PositionType.FULL) {
620
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.positionType.full") });
621
621
  }
622
- }, [props.initialValue, open]);
623
- const onClick = (val) => {
624
- setValue(val);
625
- setCustomValue("");
626
- setError(void 0);
622
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.positionType.partial") });
627
623
  };
628
- const onValueChange = (val) => {
629
- if (!val) {
630
- setCustomValue(val);
631
- return;
624
+ const renderPrice = () => {
625
+ if (order_type === types.OrderType.MARKET || order_type === types.OrderType.STOP_MARKET) {
626
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: t("common.marketPrice") });
632
627
  }
633
- const d = new utils.Decimal(val);
634
- setValue(void 0);
635
- if (d.gt(3)) {
636
- setCustomValue("3");
637
- setError(t("orderEntry.slippage.error.exceed"));
638
- } else {
639
- setCustomValue(val);
640
- setError(void 0);
628
+ if (isBBOOrder({ order_type, order_type_ext })) {
629
+ const bboType = utils.getBBOType({
630
+ type: order_type_ext,
631
+ side,
632
+ level
633
+ });
634
+ const label = {
635
+ [types.BBOOrderType.COUNTERPARTY1]: t("orderEntry.bbo.counterparty1"),
636
+ [types.BBOOrderType.COUNTERPARTY5]: t("orderEntry.bbo.counterparty5"),
637
+ [types.BBOOrderType.QUEUE1]: t("orderEntry.bbo.queue1"),
638
+ [types.BBOOrderType.QUEUE5]: t("orderEntry.bbo.queue5")
639
+ }[bboType];
640
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: label });
641
641
  }
642
+ return /* @__PURE__ */ jsxRuntime.jsx(
643
+ ui.Text.numeral,
644
+ {
645
+ unit: quote,
646
+ rule: "price",
647
+ className: "oui-text-base-contrast",
648
+ unitClassName: "oui-text-base-contrast-36 oui-ml-1",
649
+ dp: quote_dp,
650
+ padding: false,
651
+ children: order.order_price
652
+ }
653
+ );
642
654
  };
643
- const toolTipButton = props.isMobile ? /* @__PURE__ */ jsxRuntime.jsx(
644
- "button",
645
- {
646
- onClick: () => {
647
- ui.modal.alert({
648
- title: t("common.tips"),
649
- message: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: t("orderEntry.slippage.tips") })
650
- });
651
- },
652
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.ExclamationFillIcon, { className: "oui-text-base-contrast-54", size: 16 })
655
+ const renderTPSLPrice = ({
656
+ price,
657
+ isOrderPrice,
658
+ isEnable,
659
+ colorType
660
+ }) => {
661
+ if (!isEnable) {
662
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast-36", children: "-- USDC" });
653
663
  }
654
- ) : /* @__PURE__ */ jsxRuntime.jsx(
655
- ui.Tooltip,
656
- {
657
- content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, size: "2xs", children: t("orderEntry.slippage.tips") }),
658
- className: "oui-w-[260px] oui-bg-base-6",
659
- arrow: { className: "oui-fill-base-6" },
660
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ExclamationFillIcon, { className: "oui-text-base-contrast-54", size: 16 }) })
664
+ if (!price) {
665
+ if (isOrderPrice) {
666
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast-36", children: t("common.marketPrice") });
667
+ }
661
668
  }
662
- );
663
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-slippageEditor oui-text-2xs", children: [
664
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { mb: 2, gapX: 1, children: [
665
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xs", children: t("orderEntry.slippage") }),
666
- toolTipButton
667
- ] }),
668
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 2, children: [
669
- options.map((item) => {
670
- const isActive = value === item;
671
- return /* @__PURE__ */ jsxRuntime.jsx(
672
- SlippageItem,
673
- {
674
- value: item,
675
- isActive,
676
- onClick: () => {
677
- onClick(item);
678
- }
679
- },
680
- item
681
- );
682
- }),
669
+ return /* @__PURE__ */ jsxRuntime.jsx(
670
+ ui.Text.numeral,
671
+ {
672
+ unit: "USDC",
673
+ rule: "price",
674
+ className: ui.cn(
675
+ "oui-text-base-contrast",
676
+ colorType === "TP" ? "oui-text-trade-profit" : "oui-text-trade-loss"
677
+ ),
678
+ unitClassName: "oui-text-base-contrast-36 oui-ml-1",
679
+ dp: quote_dp,
680
+ padding: false,
681
+ children: price
682
+ }
683
+ );
684
+ };
685
+ const renderTPSLQty = () => {
686
+ if (!positionQty || !order.order_quantity) {
687
+ return null;
688
+ }
689
+ let qty = new utils.Decimal(order.order_quantity);
690
+ if (order.position_type === types.PositionType.FULL) {
691
+ qty = qty.plus(new utils.Decimal(positionQty ?? 0));
692
+ }
693
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
694
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: order.position_type === types.PositionType.FULL ? t("common.positionQty") : t("common.orderQty") }),
683
695
  /* @__PURE__ */ jsxRuntime.jsx(
684
- ui.Input,
696
+ ui.Text.numeral,
685
697
  {
686
- suffix: "%",
687
- formatters: [
688
- ui.inputFormatter.numberFormatter,
689
- ui.inputFormatter.dpFormatter(2)
690
- ],
691
- value: customValue,
692
- onValueChange,
693
- classNames: {
694
- root: ui.cn(
695
- "oui-slippageEditor-customInput",
696
- "oui-rounded-md oui-bg-base-6",
697
- "oui-h-[40px] oui-w-[74px]"
698
- ),
699
- input: "oui-text-base-contrast",
700
- additional: "oui-pl-1"
701
- }
698
+ rule: "price",
699
+ dp: base_dp,
700
+ padding: false,
701
+ className: "oui-text-base-contrast",
702
+ children: qty.toNumber()
702
703
  }
703
704
  )
704
- ] }),
705
- !!error && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { mt: 5, className: "-oui-mb-5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "danger", children: error }) })
706
- ] });
707
- });
708
- var SlippageItem = ({ value, isActive, onClick }) => {
709
- return /* @__PURE__ */ jsxRuntime.jsx(
710
- ui.Flex,
711
- {
712
- intensity: 600,
713
- justify: "center",
714
- itemAlign: "center",
715
- r: "md",
716
- width: 74,
717
- height: 40,
718
- className: ui.cn(
719
- "oui-slippageEditor-option",
720
- "oui-cursor-pointer oui-select-none",
721
- isActive ? "oui-bg-primary-light oui-text-primary-contrast/80" : "oui-text-base-contrast-80"
722
- ),
723
- onClick,
724
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "sm", children: [
725
- value,
726
- "%"
727
- ] })
728
- }
729
- );
730
- };
731
- var SlippageCell = (props) => {
732
- const { t } = i18n.useTranslation();
733
- const [open2, { setTrue: setOpen, setFalse: setClose, toggle }] = hooks.useBoolean(false);
734
- const { isMobile } = ui.useScreen();
735
- const slippageRef = React3.useRef(null);
736
- const onConfirm = () => {
737
- const val = slippageRef.current?.getValue();
738
- props.setSlippage(!val ? "1" : val.toString());
739
- setClose();
740
- return Promise.resolve(true);
705
+ ] });
741
706
  };
742
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
743
- /* @__PURE__ */ jsxRuntime.jsx(
744
- ui.SimpleDialog,
745
- {
746
- open: open2,
747
- onOpenChange: toggle,
748
- title: t("common.settings"),
749
- contentProps: { size: isMobile ? "xs" : "sm" },
750
- classNames: {
751
- footer: "oui-orderEntry-slippage-footer",
752
- body: "oui-orderEntry-slippage-body"
753
- },
754
- actions: {
755
- primary: {
756
- disabled: false,
757
- label: t("common.save"),
758
- onClick: onConfirm,
759
- className: "oui-slippage-save-btn"
760
- },
761
- secondary: {
762
- label: t("common.cancel"),
763
- onClick: () => setClose(),
764
- className: "oui-slippage-cancel-btn"
765
- }
766
- },
767
- children: /* @__PURE__ */ jsxRuntime.jsx(
768
- SlippageEditor,
707
+ const renderPriceAndTotal = () => {
708
+ if (order_type === types.OrderType.TRAILING_STOP) {
709
+ const { activated_price, callback_value, callback_rate } = order;
710
+ const callbackView = callback_rate ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
711
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.trailingRate") }),
712
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-text-base-contrast", children: [
713
+ callback_rate,
714
+ "%"
715
+ ] })
716
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
717
+ OrderItem,
718
+ {
719
+ title: t("orderEntry.trailingValue"),
720
+ value: callback_value,
721
+ unit: quote,
722
+ dp: quote_dp
723
+ }
724
+ );
725
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
726
+ activated_price && /* @__PURE__ */ jsxRuntime.jsx(
727
+ OrderItem,
769
728
  {
770
- ref: slippageRef,
771
- isMobile,
772
- initialValue: props.slippage ? Number(props.slippage) : void 0
729
+ title: t("common.triggerPrice"),
730
+ value: activated_price,
731
+ unit: quote,
732
+ dp: quote_dp
773
733
  }
774
- )
775
- }
776
- ),
777
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-orderEntry-slippage", children: [
778
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-slippage-label", size: "2xs", children: t("orderEntry.slippage") }),
734
+ ),
735
+ callbackView
736
+ ] });
737
+ }
738
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
739
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
740
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.price") }),
741
+ renderPrice()
742
+ ] }),
779
743
  /* @__PURE__ */ jsxRuntime.jsx(
780
- uiConnector.AuthGuard,
744
+ OrderItem,
781
745
  {
782
- fallback: () => /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "2xs", children: [
783
- t("orderEntry.slippage.est"),
784
- ": -% / ",
785
- t("common.max"),
786
- ": --%"
787
- ] }),
788
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, className: "oui-slippage-value-container", children: [
789
- /* @__PURE__ */ jsxRuntime.jsx(
790
- ui.Text.numeral,
791
- {
792
- size: "2xs",
793
- rule: "percentages",
794
- prefix: `${t("orderEntry.slippage.est")}: `,
795
- suffix: ` / ${t("common.max")}: `,
796
- children: props.estSlippage ?? 0
797
- }
798
- ),
799
- /* @__PURE__ */ jsxRuntime.jsx(
800
- "button",
801
- {
802
- className: "oui-slippage-edit-btn oui-text-2xs",
803
- onClick: () => setOpen(),
804
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { className: "oui-gap-0.5", as: "span", children: [
805
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-primary", children: `${props.slippage || "-"}%` }),
806
- /* @__PURE__ */ jsxRuntime.jsx(
807
- ui.EditIcon,
808
- {
809
- className: "oui-slippage-edit-icon oui-text-primary oui-hidden md:oui-block",
810
- size: 12,
811
- opacity: 1
812
- }
813
- )
814
- ] })
815
- }
816
- )
817
- ] })
746
+ title: t("common.estTotal"),
747
+ value: order.total,
748
+ unit: quote,
749
+ dp: quote_dp
818
750
  }
819
751
  )
820
- ] })
821
- ] });
822
- };
823
- var SlippageUI = (props) => {
824
- return /* @__PURE__ */ jsxRuntime.jsx(SlippageCell, { ...props });
825
- };
826
- function AssetInfo(props) {
827
- const { canTrade, disableFeatures, orderType, symbol } = props;
828
- const { t } = i18n.useTranslation();
829
- const { isMobile } = ui.useScreen();
830
- const displayEstLiqPrice = hooks.useGetEstLiqPrice({
831
- estLiqPrice: props.estLiqPrice,
832
- symbol,
833
- side: props.side
834
- });
835
- return /* @__PURE__ */ jsxRuntime.jsxs(
836
- "div",
752
+ ] });
753
+ };
754
+ const header = /* @__PURE__ */ jsxRuntime.jsxs(
755
+ ui.Flex,
837
756
  {
838
- className: "oui-orderEntry-assetInfo oui-space-y-[2px] xl:oui-space-y-1",
757
+ justify: "between",
758
+ className: "oui-orderEntry-orderConfirmDialog-header",
839
759
  children: [
840
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-orderEntry-estLiqPrice", children: [
841
- isMobile ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: t("orderEntry.estLiqPrice") }) : /* @__PURE__ */ jsxRuntime.jsx(
842
- ui.Tooltip,
843
- {
844
- content: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-min-w-[204px] oui-max-w-[280px] oui-text-2xs oui-leading-normal oui-text-base-contrast-80", children: [
845
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-text-pretty", children: t("common.liquidationPrice.tooltip") }),
846
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
847
- "a",
848
- {
849
- href: "https://orderly.network/docs/introduction/trade-on-orderly/perpetual-futures/liquidations",
850
- target: "_blank",
851
- rel: "noopener noreferrer",
852
- className: "oui-text-primary oui-underline",
853
- children: t("common.liquidationPrice.tooltip.learnMore")
854
- }
855
- ) })
856
- ] }),
857
- children: /* @__PURE__ */ jsxRuntime.jsx(
858
- ui.Text,
859
- {
860
- size: "2xs",
861
- className: "oui-estLiqPrice-label oui-cursor-pointer oui-border-b oui-border-dashed oui-border-line-12",
862
- children: t("orderEntry.estLiqPrice")
863
- }
864
- )
865
- }
866
- ),
760
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, direction: "column", itemAlign: "start", children: [
867
761
  /* @__PURE__ */ jsxRuntime.jsx(
868
- ui.Text.numeral,
762
+ ui.Text.formatted,
869
763
  {
870
- unit: props.quote,
871
- size: "2xs",
872
- dp: props.dp,
873
- className: "oui-estLiqPrice-value oui-text-base-contrast-80",
874
- unitClassName: "oui-ml-1 oui-text-base-contrast-36",
875
- children: canTrade ? displayEstLiqPrice ?? "--" : "--"
764
+ rule: "symbol",
765
+ formatString: "base",
766
+ showIcon: true,
767
+ className: "oui-orderConfirmDialog-symbol",
768
+ children: order.symbol
876
769
  }
877
- )
770
+ ),
771
+ /* @__PURE__ */ jsxRuntime.jsx(SymbolBadge, { symbol: order.symbol })
878
772
  ] }),
879
- orderType === types.OrderType.MARKET && !disableFeatures?.includes("slippageSetting") && /* @__PURE__ */ jsxRuntime.jsx(
880
- SlippageUI,
773
+ /* @__PURE__ */ jsxRuntime.jsxs(
774
+ ui.Flex,
881
775
  {
882
- slippage: props.slippage,
883
- setSlippage: props.setSlippage,
884
- estSlippage: props.estSlippage
776
+ justify: "end",
777
+ gapX: 1,
778
+ className: "oui-orderConfirmDialog-header-tags",
779
+ children: [
780
+ /* @__PURE__ */ jsxRuntime.jsx(OrderTypeTag, { type: order_type }),
781
+ side === types.OrderSide.BUY ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "buy", size: "sm", children: t("common.buy") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "sell", size: "sm", children: t("common.sell") })
782
+ ]
885
783
  }
886
- ),
887
- !disableFeatures?.includes("feesInfo") && /* @__PURE__ */ jsxRuntime.jsx(FeesWidget, { symbol: props.symbol })
784
+ )
888
785
  ]
889
786
  }
890
787
  );
891
- }
892
- var calculateLTVColor = (val) => {
893
- if (val >= 0 && val < 50) {
894
- return "oui-text-success";
895
- } else if (val >= 50 && val < 80) {
896
- return "oui-text-warning";
897
- } else if (val >= 80) {
898
- return "oui-text-danger";
899
- } else {
900
- return "";
901
- }
902
- };
903
- var LTVRiskTooltipUI = (props) => {
904
- const { t } = i18n.useTranslation();
905
- const {
906
- ltv_threshold,
907
- negative_usdc_threshold,
908
- isThresholdLoading,
909
- holdingData = [],
910
- currentLtv,
911
- onConvert,
912
- marginMode
913
- } = props;
914
- return /* @__PURE__ */ jsxRuntime.jsxs(
915
- ui.Flex,
788
+ const quantityItem = /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
789
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.orderQty") }),
790
+ /* @__PURE__ */ jsxRuntime.jsx(
791
+ ui.Text.numeral,
792
+ {
793
+ rule: "price",
794
+ dp: base_dp,
795
+ padding: false,
796
+ className: "oui-text-base-contrast",
797
+ children: order.order_quantity
798
+ }
799
+ )
800
+ ] });
801
+ const triggerPriceItem = (order_type === types.OrderType.STOP_LIMIT || order_type === types.OrderType.STOP_MARKET && order.trigger_price) && /* @__PURE__ */ jsxRuntime.jsx(
802
+ OrderItem,
916
803
  {
917
- gap: 1,
918
- className: "oui-orderEntry-ltvRiskTooltip oui-w-72 oui-max-w-72",
919
- direction: "column",
920
- itemAlign: "start",
921
- children: [
922
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", justify: "between", itemAlign: "center", children: [
923
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("common.assets") }),
924
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("transfer.deposit.collateralContribution") })
925
- ] }),
926
- holdingData.map((asset, index) => {
927
- return /* @__PURE__ */ jsxRuntime.jsxs(
804
+ title: t("common.trigger"),
805
+ value: order.trigger_price,
806
+ unit: quote,
807
+ dp: quote_dp
808
+ }
809
+ );
810
+ const tpslTriggerPrice = (order.tp_trigger_price || order.sl_trigger_price) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
811
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-my-4" }),
812
+ /* @__PURE__ */ jsxRuntime.jsxs(
813
+ "div",
814
+ {
815
+ className: ui.textVariants({
816
+ size: "sm",
817
+ intensity: 54,
818
+ className: "oui-space-y-1 oui-w-full oui-flex oui-flex-col oui-gap-3"
819
+ }),
820
+ children: [
821
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast", children: renderPositionType() }),
822
+ renderTPSLQty(),
823
+ /* @__PURE__ */ jsxRuntime.jsxs(
928
824
  ui.Flex,
929
825
  {
930
- width: "100%",
826
+ direction: "column",
931
827
  justify: "between",
932
- itemAlign: "center",
828
+ itemAlign: "start",
829
+ gap: 1,
830
+ className: "oui-w-full",
933
831
  children: [
934
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, size: "xs", children: asset.token }),
935
- /* @__PURE__ */ jsxRuntime.jsx(
936
- ui.Text,
937
- {
938
- size: "xs",
939
- intensity: 80,
940
- className: ui.cn(
941
- Number(asset.collateralContribution) < 0 && "oui-text-warning"
942
- ),
943
- children: utils.removeTrailingZeros(asset.collateralContribution)
944
- }
945
- )
832
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
833
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.tpTriggerPrice") }),
834
+ renderTPSLPrice({
835
+ price: order.tp_trigger_price ?? "",
836
+ isOrderPrice: false,
837
+ isEnable: !!order.tp_trigger_price,
838
+ colorType: "TP"
839
+ })
840
+ ] }),
841
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
842
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.tpOrderPrice") }),
843
+ renderTPSLPrice({
844
+ price: order.tp_order_price ?? "",
845
+ isOrderPrice: true,
846
+ isEnable: !!order.tp_trigger_price,
847
+ colorType: "TP"
848
+ })
849
+ ] })
946
850
  ]
947
- },
948
- `item-${index}`
949
- );
950
- }),
951
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-w-full" }),
952
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", justify: "between", itemAlign: "center", children: [
953
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("transfer.LTV.currentLTV") }),
851
+ }
852
+ ),
954
853
  /* @__PURE__ */ jsxRuntime.jsxs(
955
- ui.Text,
854
+ ui.Flex,
956
855
  {
957
- size: "xs",
958
- intensity: 36,
959
- className: ui.cn("oui-select-none", calculateLTVColor(currentLtv)),
856
+ direction: "column",
857
+ justify: "between",
858
+ itemAlign: "start",
859
+ gap: 1,
860
+ className: "oui-w-full",
960
861
  children: [
961
- currentLtv,
962
- "%"
862
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
863
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.slTriggerPrice") }),
864
+ renderTPSLPrice({
865
+ price: order.sl_trigger_price ?? "",
866
+ isOrderPrice: false,
867
+ isEnable: !!order.sl_trigger_price,
868
+ colorType: "SL"
869
+ })
870
+ ] }),
871
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
872
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.slOrderPrice") }),
873
+ renderTPSLPrice({
874
+ price: order.sl_order_price ?? "",
875
+ isOrderPrice: true,
876
+ isEnable: !!order.sl_trigger_price,
877
+ colorType: "SL"
878
+ })
879
+ ] })
963
880
  ]
964
881
  }
965
882
  )
966
- ] }),
967
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-py-2", intensity: 54, size: "2xs", children: t("transfer.LTV.tooltip", {
968
- threshold: isThresholdLoading ? "-" : ltv_threshold,
969
- usdcThreshold: isThresholdLoading ? "-" : negative_usdc_threshold
970
- }) }),
883
+ ]
884
+ }
885
+ )
886
+ ] });
887
+ const orderConfirmCheckbox = /* @__PURE__ */ jsxRuntime.jsxs(
888
+ ui.Flex,
889
+ {
890
+ gapX: 1,
891
+ pt: 4,
892
+ pb: 5,
893
+ className: "oui-orderEntry-orderConfirmDialog-disableConfirm",
894
+ children: [
895
+ /* @__PURE__ */ jsxRuntime.jsx(
896
+ ui.Checkbox,
897
+ {
898
+ id: "orderConfirm",
899
+ color: "white",
900
+ className: "oui-orderConfirmDialog-disableConfirm-checkbox",
901
+ onCheckedChange: (checked) => {
902
+ setNeedConfirm(!!!checked);
903
+ }
904
+ }
905
+ ),
906
+ /* @__PURE__ */ jsxRuntime.jsx(
907
+ "label",
908
+ {
909
+ htmlFor: "orderConfirm",
910
+ className: ui.textVariants({
911
+ size: "xs",
912
+ intensity: 54
913
+ }),
914
+ children: t("orderEntry.disableOrderConfirm")
915
+ }
916
+ )
917
+ ]
918
+ }
919
+ );
920
+ const buttons = /* @__PURE__ */ jsxRuntime.jsxs(
921
+ ui.Grid,
922
+ {
923
+ cols: 2,
924
+ gapX: 3,
925
+ className: "oui-orderEntry-orderConfirmDialog-actions",
926
+ children: [
971
927
  /* @__PURE__ */ jsxRuntime.jsx(
972
928
  ui.Button,
973
929
  {
974
- fullWidth: true,
975
- size: "md",
976
- variant: "outlined",
977
930
  color: "secondary",
978
- className: "oui-ltvRiskTooltip-convert-btn",
979
- onClick: onConvert,
980
- children: t("transfer.convert.convertAssets")
931
+ size: "md",
932
+ className: "oui-cancel-btn",
933
+ onClick: () => onCancel(),
934
+ children: t("common.cancel")
935
+ }
936
+ ),
937
+ /* @__PURE__ */ jsxRuntime.jsx(
938
+ ui.Button,
939
+ {
940
+ size: "md",
941
+ className: "oui-confirm-btn",
942
+ onClick: () => onConfirm(),
943
+ children: t("common.confirm")
981
944
  }
982
945
  )
983
946
  ]
984
947
  }
985
948
  );
949
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
950
+ header,
951
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-my-4" }),
952
+ /* @__PURE__ */ jsxRuntime.jsxs(
953
+ "div",
954
+ {
955
+ className: ui.textVariants({
956
+ size: "sm",
957
+ intensity: 54,
958
+ className: "oui-orderEntry-orderConfirmDialog-content oui-space-y-1"
959
+ }),
960
+ children: [
961
+ quantityItem,
962
+ triggerPriceItem,
963
+ renderPriceAndTotal()
964
+ ]
965
+ }
966
+ ),
967
+ tpslTriggerPrice,
968
+ orderConfirmCheckbox,
969
+ buttons
970
+ ] });
986
971
  };
987
- var useConvertThreshold = () => {
988
- const { data, error, isLoading } = hooks.useQuery(
989
- "/v1/public/auto_convert_threshold",
990
- { errorRetryCount: 3 }
991
- );
992
- return {
993
- ltv_threshold: new utils.Decimal(data?.ltv_threshold ?? 0).mul(100).toNumber(),
994
- negative_usdc_threshold: data?.negative_usdc_threshold,
995
- isLoading,
996
- error
997
- };
972
+ var OrderItem = (props) => {
973
+ const { title, value, unit, dp } = props;
974
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
975
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: title }),
976
+ /* @__PURE__ */ jsxRuntime.jsx(
977
+ ui.Text.numeral,
978
+ {
979
+ unit,
980
+ rule: "price",
981
+ dp,
982
+ padding: false,
983
+ className: "oui-text-base-contrast",
984
+ unitClassName: "oui-text-base-contrast-36 oui-ml-1",
985
+ children: value
986
+ }
987
+ )
988
+ ] });
998
989
  };
999
- var useLTVTooltipScript = (marginMode) => {
1000
- const { data: holdingList = [], isLoading: isHoldingLoading } = hooks.useHoldingStream();
1001
- const {
1002
- ltv_threshold,
1003
- negative_usdc_threshold,
1004
- isLoading: isThresholdLoading
1005
- } = useConvertThreshold();
1006
- const tokensInfo = hooks.useAppStore((state) => state.tokensInfo);
1007
- const { getIndexPrice } = hooks.useIndexPricesStream();
1008
- const holdingData = holdingList.map((item) => {
1009
- const tokenInfo = tokensInfo?.find(({ token }) => token === item.token);
1010
- const indexPrice = getIndexPrice(item.token);
1011
- const collateralRatio = tokenInfo ? perp.account.collateralRatio({
1012
- baseWeight: tokenInfo.base_weight ?? 0,
1013
- discountFactor: tokenInfo.discount_factor ?? 0,
1014
- collateralQty: item.holding,
1015
- collateralCap: tokenInfo?.user_max_qty ?? item.holding,
1016
- indexPrice
1017
- }) : utils.zero;
1018
- const collateralContribution = perp.account.collateralContribution({
1019
- collateralQty: item.holding,
1020
- collateralCap: tokenInfo?.user_max_qty ?? item.holding,
1021
- collateralRatio: collateralRatio.toNumber(),
1022
- indexPrice
1023
- });
1024
- return {
1025
- ...item,
1026
- collateralContribution
1027
- };
1028
- });
1029
- const currentLtv = hooks.useComputedLTV();
1030
- const onConvert = React3.useCallback(async () => {
1031
- return ui.modal.show("ConvertDialogId");
1032
- }, []);
1033
- return {
1034
- holdingData,
1035
- isHoldingLoading,
1036
- ltv_threshold,
1037
- negative_usdc_threshold,
1038
- isThresholdLoading,
1039
- currentLtv,
1040
- onConvert,
1041
- marginMode
1042
- };
990
+ OrderConfirmDialog.displayName = "OrderConfirmDialog";
991
+ var OrderTypeTag = (props) => {
992
+ const { t } = i18n.useTranslation();
993
+ const typeStr = React3.useMemo(() => {
994
+ switch (props.type) {
995
+ case types.OrderType.LIMIT:
996
+ return t("orderEntry.orderType.limit");
997
+ case types.OrderType.MARKET:
998
+ return t("common.marketPrice");
999
+ case types.OrderType.STOP_LIMIT:
1000
+ return t("orderEntry.orderType.stopLimit");
1001
+ case types.OrderType.STOP_MARKET:
1002
+ return t("orderEntry.orderType.stopMarket");
1003
+ case types.OrderType.TRAILING_STOP:
1004
+ return t("orderEntry.orderType.trailingStop");
1005
+ default:
1006
+ return "";
1007
+ }
1008
+ }, [props.type]);
1009
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "neutral", size: "sm", children: typeStr });
1043
1010
  };
1044
- var LTVRiskTooltipWidget = ({
1045
- marginMode
1046
- }) => {
1047
- const state = useLTVTooltipScript(marginMode);
1048
- return /* @__PURE__ */ jsxRuntime.jsx(LTVRiskTooltipUI, { ...state });
1011
+ var Dialog = (props) => {
1012
+ const { close, resolve, reject, ...rest } = props;
1013
+ return /* @__PURE__ */ jsxRuntime.jsx(
1014
+ OrderConfirmDialog,
1015
+ {
1016
+ ...rest,
1017
+ onCancel: () => {
1018
+ reject();
1019
+ close();
1020
+ },
1021
+ onConfirm: () => {
1022
+ resolve();
1023
+ close();
1024
+ }
1025
+ }
1026
+ );
1049
1027
  };
1050
- var Available = (props) => {
1051
- const { canTrade, currentLtv, quote, freeCollateral, marginMode } = props;
1028
+ var orderConfirmDialogId = "orderConfirm";
1029
+ ui.registerSimpleDialog(orderConfirmDialogId, Dialog, {
1030
+ size: "sm",
1031
+ title: () => i18n.i18n.t("orderEntry.orderConfirm")
1032
+ });
1033
+ var MaxQtyConfirm = React3.memo((props) => {
1052
1034
  const { t } = i18n.useTranslation();
1053
- const { isMobile } = ui.useScreen();
1054
- const showLTV = React3.useMemo(() => {
1055
- return typeof currentLtv === "number" && !Number.isNaN(currentLtv) && currentLtv > 0;
1056
- }, [currentLtv]);
1057
- return /* @__PURE__ */ jsxRuntime.jsxs(
1035
+ return /* @__PURE__ */ jsxRuntime.jsx(
1036
+ ui.SimpleDialog,
1037
+ {
1038
+ open: props.open,
1039
+ title: t("orderEntry.orderConfirm"),
1040
+ closable: true,
1041
+ onOpenChange: props.onOpenChange,
1042
+ size: "sm",
1043
+ classNames: {
1044
+ footer: "oui-maxQtyConfirm-footer",
1045
+ body: "oui-maxQtyConfirm-body"
1046
+ },
1047
+ actions: {
1048
+ primary: {
1049
+ label: t("orderEntry.placeOrderNow"),
1050
+ className: "oui-primary-btn oui-text-sm oui-font-semibold oui-w-[100%] oui-h-8",
1051
+ onClick: () => {
1052
+ props.onConfirm();
1053
+ return Promise.resolve();
1054
+ }
1055
+ },
1056
+ secondary: {
1057
+ label: t("common.cancel"),
1058
+ className: "oui-secondary-btn oui-text-sm oui-font-semibold oui-w-[100%] oui-h-8",
1059
+ onClick: () => {
1060
+ props.onOpenChange(false);
1061
+ return Promise.resolve();
1062
+ }
1063
+ }
1064
+ },
1065
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-maxQtyConfirm-content oui-text-2xs lg:oui-text-sm", children: t("orderEntry.maxQty.reminder.content", {
1066
+ maxQty: `${props.maxQty} ${props.base}`
1067
+ }) })
1068
+ }
1069
+ );
1070
+ });
1071
+ var PermissionlessMarketNoticeDialog = (props) => {
1072
+ const { onConfirm, onCancel } = props;
1073
+ const { t } = i18n.useTranslation();
1074
+ const [checked, setChecked] = React3.useState(false);
1075
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(
1058
1076
  ui.Flex,
1059
1077
  {
1060
- itemAlign: "center",
1061
- justify: "between",
1062
- className: "oui-orderEntry-available",
1078
+ direction: "column",
1079
+ gap: 3,
1080
+ itemAlign: "start",
1081
+ className: "oui-permissionlessNotice-content",
1063
1082
  children: [
1064
- marginMode === types.MarginMode.ISOLATED ? /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: t("transfer.LTV.isolatedModeUsdcOnly"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-available-label oui-cursor-pointer", size: "2xs", children: t("common.available") }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-available-label", size: "2xs", children: t("common.available") }),
1065
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { itemAlign: "center", justify: "center", gap: 1, children: [
1066
- showLTV && /* @__PURE__ */ jsxRuntime.jsx(
1067
- ui.Tooltip,
1068
- {
1069
- className: "oui-available-ltvRisk-tooltip oui-bg-base-6 oui-p-2",
1070
- content: /* @__PURE__ */ jsxRuntime.jsx(LTVRiskTooltipWidget, { marginMode }),
1071
- children: /* @__PURE__ */ jsxRuntime.jsx(
1072
- ui.InfoCircleIcon,
1073
- {
1074
- className: "oui-cursor-pointer oui-text-warning oui-opacity-80"
1075
- }
1076
- )
1077
- }
1078
- ),
1079
- /* @__PURE__ */ jsxRuntime.jsx(
1080
- ui.Text.numeral,
1081
- {
1082
- unit: quote,
1083
- size: "2xs",
1084
- className: "oui-available-value oui-text-base-contrast-80",
1085
- unitClassName: "oui-ml-1 oui-text-base-contrast-54",
1086
- dp: 2,
1087
- padding: false,
1088
- children: canTrade ? freeCollateral : 0
1089
- }
1090
- ),
1091
- /* @__PURE__ */ jsxRuntime.jsx(
1092
- ui.Button,
1093
- {
1094
- variant: "text",
1083
+ /* @__PURE__ */ jsxRuntime.jsx(
1084
+ ui.Text,
1085
+ {
1086
+ className: ui.textVariants({
1087
+ size: "sm",
1088
+ intensity: 54
1089
+ }),
1090
+ children: t("orderEntry.permissionlessNotice.content1")
1091
+ }
1092
+ ),
1093
+ /* @__PURE__ */ jsxRuntime.jsx(
1094
+ ui.Text,
1095
+ {
1096
+ className: ui.textVariants({
1097
+ size: "sm",
1098
+ intensity: 54
1099
+ }),
1100
+ children: t("orderEntry.permissionlessNotice.content2")
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ jsxRuntime.jsx(
1104
+ ui.Text,
1105
+ {
1106
+ className: ui.textVariants({
1107
+ size: "sm",
1108
+ intensity: 54
1109
+ }),
1110
+ children: t("orderEntry.permissionlessNotice.content3")
1111
+ }
1112
+ )
1113
+ ]
1114
+ }
1115
+ );
1116
+ const checkboxSection = /* @__PURE__ */ jsxRuntime.jsxs(
1117
+ ui.Flex,
1118
+ {
1119
+ gapX: 1,
1120
+ pt: 4,
1121
+ pb: 5,
1122
+ itemAlign: "start",
1123
+ className: "oui-permissionlessNotice-checkbox oui-orderEntry-orderConfirmDialog-disableConfirm oui-cursor-pointer",
1124
+ children: [
1125
+ /* @__PURE__ */ jsxRuntime.jsx(
1126
+ ui.Checkbox,
1127
+ {
1128
+ id: "permissionlessNotice",
1129
+ color: "white",
1130
+ className: "oui-permissionlessNotice-checkbox-input oui-mt-1",
1131
+ checked,
1132
+ onCheckedChange: (value) => setChecked(!!value)
1133
+ }
1134
+ ),
1135
+ /* @__PURE__ */ jsxRuntime.jsx(
1136
+ "label",
1137
+ {
1138
+ htmlFor: "permissionlessNotice",
1139
+ className: ui.textVariants({
1095
1140
  size: "xs",
1096
- color: "secondary",
1097
- className: "oui-available-deposit-icon oui-p-0 hover:oui-text-base-contrast-80",
1098
- onClick: () => {
1099
- const handleDomId = isMobile ? "DepositAndWithdrawWithSheetId" : "DepositAndWithdrawWithDialogId";
1100
- ui.modal.show(handleDomId, {
1101
- activeTab: "deposit"
1102
- });
1103
- },
1104
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.AddCircleIcon, { opacity: 1 })
1105
- }
1106
- )
1107
- ] })
1141
+ intensity: 54,
1142
+ className: "oui-cursor-pointer"
1143
+ }),
1144
+ children: t("orderEntry.permissionlessNotice.checkbox")
1145
+ }
1146
+ )
1108
1147
  ]
1109
1148
  }
1110
1149
  );
1150
+ const confirmButton = /* @__PURE__ */ jsxRuntime.jsx(
1151
+ ui.Flex,
1152
+ {
1153
+ className: "oui-permissionlessNotice-confirm-button oui-w-full",
1154
+ justify: "center",
1155
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1156
+ ui.Button,
1157
+ {
1158
+ fullWidth: true,
1159
+ size: "md",
1160
+ className: "oui-permissionlessNotice-confirm oui-confirm-btn oui-max-w-[244px]",
1161
+ disabled: !checked,
1162
+ onClick: () => onConfirm(),
1163
+ children: t("common.confirm")
1164
+ }
1165
+ )
1166
+ }
1167
+ );
1168
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1169
+ content,
1170
+ checkboxSection,
1171
+ confirmButton
1172
+ ] });
1111
1173
  };
1112
- function isBBOOrder(options2) {
1113
- const { order_type, order_type_ext } = options2;
1114
- const isBBO = [types.OrderType.ASK, types.OrderType.BID].includes(order_type_ext);
1115
- if (order_type) {
1116
- return order_type === types.OrderType.LIMIT && isBBO;
1117
- }
1118
- return isBBO;
1119
- }
1120
- function getOrderTypeByBBO(value, size) {
1121
- if ([types.BBOOrderType.COUNTERPARTY1, types.BBOOrderType.COUNTERPARTY5].includes(value)) {
1122
- return size === types.OrderSide.BUY ? types.OrderType.ASK : types.OrderType.BID;
1123
- }
1124
- if ([types.BBOOrderType.QUEUE1, types.BBOOrderType.QUEUE5].includes(value)) {
1125
- return size === types.OrderSide.BUY ? types.OrderType.BID : types.OrderType.ASK;
1126
- }
1127
- }
1128
- function getOrderLevelByBBO(value) {
1129
- if ([types.BBOOrderType.COUNTERPARTY1, types.BBOOrderType.QUEUE1].includes(value)) {
1130
- return types.OrderLevel.ONE;
1131
- }
1132
- if ([types.BBOOrderType.COUNTERPARTY5, types.BBOOrderType.QUEUE5].includes(value)) {
1133
- return types.OrderLevel.FIVE;
1134
- }
1135
- }
1136
- function getScaledPlaceOrderMessage(result) {
1137
- const rows = result?.data?.rows || [];
1138
- if (rows.length > 0) {
1139
- const totalCount = rows.length;
1140
- const successCount = rows.filter((row) => row.success).length;
1141
- if (successCount === totalCount) {
1142
- return i18n.i18n.t("orderEntry.scaledOrder.fullySuccessful", {
1143
- total: totalCount
1144
- });
1145
- }
1146
- if (successCount === 0) {
1147
- return i18n.i18n.t("orderEntry.scaledOrder.allFailed");
1174
+ PermissionlessMarketNoticeDialog.displayName = "PermissionlessMarketNoticeDialog";
1175
+ var Dialog2 = (props) => {
1176
+ const { close, resolve, reject } = props;
1177
+ return /* @__PURE__ */ jsxRuntime.jsx(
1178
+ PermissionlessMarketNoticeDialog,
1179
+ {
1180
+ onCancel: () => {
1181
+ reject();
1182
+ close();
1183
+ },
1184
+ onConfirm: () => {
1185
+ resolve();
1186
+ close();
1187
+ }
1148
1188
  }
1149
- return i18n.i18n.t("orderEntry.scaledOrder.partiallySuccessful", {
1150
- successCount,
1151
- total: totalCount
1152
- });
1153
- }
1154
- }
1155
- var safeNumber = (val) => {
1156
- return Number.isNaN(Number(val)) ? 0 : Number(val);
1189
+ );
1157
1190
  };
1158
- var OrderConfirmDialog = (props) => {
1159
- const { symbolInfo, order, onConfirm, onCancel } = props;
1160
- const { quote, quote_dp, base_dp } = symbolInfo;
1161
- const { side, order_type, order_type_ext, level, symbol } = order;
1162
- const orderMarginMode = order.margin_mode;
1191
+ var permissionlessMarketNoticeDialogId = "permissionlessMarketNotice";
1192
+ var permissionlessMarketNoticeDesktopDialogId = "permissionlessMarketNoticeDesktop";
1193
+ ui.registerSimpleDialog(permissionlessMarketNoticeDialogId, Dialog2, {
1194
+ size: "sm",
1195
+ title: () => i18n.i18n.t("orderEntry.permissionlessNotice.title")
1196
+ });
1197
+ ui.registerSimpleDialog(permissionlessMarketNoticeDesktopDialogId, Dialog2, {
1198
+ size: "xl",
1199
+ title: () => i18n.i18n.t("orderEntry.permissionlessNotice.title")
1200
+ });
1201
+ var ScaledOrderConfirm = (props) => {
1202
+ const { order, symbolInfo, dataSource, national, askAndBid, totalQuantity } = props;
1203
+ const { base, quote, base_dp, quote_dp } = symbolInfo;
1163
1204
  const { t } = i18n.useTranslation();
1164
- const [{ rows: positions }] = hooks.usePositionStream(symbol);
1165
- const position = React3.useMemo(
1166
- () => orderMarginMode != null ? positions?.find(
1167
- (row) => row.symbol === symbol && row.margin_mode === orderMarginMode
1168
- ) : positions?.[0],
1169
- [positions, symbol, orderMarginMode]
1170
- );
1171
- const positionQty = position?.position_qty;
1172
- const [_, setNeedConfirm] = hooks.useLocalStorage("orderly_order_confirm", true);
1173
- const renderPositionType = () => {
1174
- if (order.position_type === types.PositionType.FULL) {
1175
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.positionType.full") });
1176
- }
1177
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.positionType.partial") });
1205
+ const onCancel = () => {
1206
+ props.reject();
1207
+ props.close?.();
1178
1208
  };
1179
- const renderPrice = () => {
1180
- if (order_type === types.OrderType.MARKET || order_type === types.OrderType.STOP_MARKET) {
1181
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: t("common.marketPrice") });
1182
- }
1183
- if (isBBOOrder({ order_type, order_type_ext })) {
1184
- const bboType = utils.getBBOType({
1185
- type: order_type_ext,
1186
- side,
1187
- level
1188
- });
1189
- const label = {
1190
- [types.BBOOrderType.COUNTERPARTY1]: t("orderEntry.bbo.counterparty1"),
1191
- [types.BBOOrderType.COUNTERPARTY5]: t("orderEntry.bbo.counterparty5"),
1192
- [types.BBOOrderType.QUEUE1]: t("orderEntry.bbo.queue1"),
1193
- [types.BBOOrderType.QUEUE5]: t("orderEntry.bbo.queue5")
1194
- }[bboType];
1195
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: label });
1196
- }
1197
- return /* @__PURE__ */ jsxRuntime.jsx(
1198
- ui.Text.numeral,
1199
- {
1200
- unit: quote,
1201
- rule: "price",
1202
- className: "oui-text-base-contrast",
1203
- unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1204
- dp: quote_dp,
1205
- padding: false,
1206
- children: order.order_price
1207
- }
1208
- );
1209
+ const onConfirm = () => {
1210
+ props.resolve();
1211
+ props.close?.();
1209
1212
  };
1210
- const renderTPSLPrice = ({
1211
- price,
1212
- isOrderPrice,
1213
- isEnable,
1214
- colorType
1215
- }) => {
1216
- if (!isEnable) {
1217
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast-36", children: "-- USDC" });
1218
- }
1219
- if (!price) {
1220
- if (isOrderPrice) {
1221
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast-36", children: t("common.marketPrice") });
1222
- }
1223
- }
1224
- return /* @__PURE__ */ jsxRuntime.jsx(
1225
- ui.Text.numeral,
1213
+ const columns = React3.useMemo(() => {
1214
+ return [
1226
1215
  {
1227
- unit: "USDC",
1228
- rule: "price",
1229
- className: ui.cn(
1230
- "oui-text-base-contrast",
1231
- colorType === "TP" ? "oui-text-trade-profit" : "oui-text-trade-loss"
1232
- ),
1233
- unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1234
- dp: quote_dp,
1235
- padding: false,
1236
- children: price
1237
- }
1238
- );
1239
- };
1240
- const renderTPSLQty = () => {
1241
- if (!positionQty || !order.order_quantity) {
1242
- return null;
1243
- }
1244
- let qty = new utils.Decimal(order.order_quantity);
1245
- if (order.position_type === types.PositionType.FULL) {
1246
- qty = qty.plus(new utils.Decimal(positionQty ?? 0));
1247
- }
1248
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1249
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: order.position_type === types.PositionType.FULL ? t("common.positionQty") : t("common.orderQty") }),
1250
- /* @__PURE__ */ jsxRuntime.jsx(
1251
- ui.Text.numeral,
1252
- {
1253
- rule: "price",
1254
- dp: base_dp,
1255
- padding: false,
1256
- className: "oui-text-base-contrast",
1257
- children: qty.toNumber()
1216
+ title: t("common.symbol"),
1217
+ dataIndex: "symbol",
1218
+ width: 125,
1219
+ render: (value, record) => {
1220
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, children: [
1221
+ /* @__PURE__ */ jsxRuntime.jsx(
1222
+ "div",
1223
+ {
1224
+ className: ui.cn(
1225
+ "oui-h-[42px] oui-w-1 oui-shrink-0 oui-rounded-[1px]",
1226
+ record.side === types.OrderSide.BUY ? "oui-bg-trade-profit" : "oui-bg-trade-loss"
1227
+ )
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", itemAlign: "start", children: [
1231
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 1, children: [
1232
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TokenIcon, { symbol: value, className: "oui-size-3" }),
1233
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text.formatted, { rule: "symbol", size: "xs", formatString: "base", children: value })
1234
+ ] }),
1235
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, children: [
1236
+ /* @__PURE__ */ jsxRuntime.jsx(SymbolBadge, { symbol: value }),
1237
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "neutral", size: "xs", children: t("orderEntry.orderType.limit") })
1238
+ ] })
1239
+ ] })
1240
+ ] });
1258
1241
  }
1259
- )
1260
- ] });
1261
- };
1262
- const renderPriceAndTotal = () => {
1263
- if (order_type === types.OrderType.TRAILING_STOP) {
1264
- const { activated_price, callback_value, callback_rate } = order;
1265
- const callbackView = callback_rate ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1266
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.trailingRate") }),
1267
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-text-base-contrast", children: [
1268
- callback_rate,
1269
- "%"
1270
- ] })
1271
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
1272
- OrderItem,
1273
- {
1274
- title: t("orderEntry.trailingValue"),
1275
- value: callback_value,
1276
- unit: quote,
1277
- dp: quote_dp
1242
+ },
1243
+ {
1244
+ title: t("common.quantity"),
1245
+ dataIndex: "order_quantity",
1246
+ width: 100,
1247
+ render: (value, record) => {
1248
+ return /* @__PURE__ */ jsxRuntime.jsx(
1249
+ ui.Text.numeral,
1250
+ {
1251
+ rule: "price",
1252
+ dp: base_dp,
1253
+ padding: false,
1254
+ color: record.side === types.OrderSide.BUY ? "buy" : "sell",
1255
+ children: value
1256
+ }
1257
+ );
1278
1258
  }
1279
- );
1280
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1281
- activated_price && /* @__PURE__ */ jsxRuntime.jsx(
1282
- OrderItem,
1283
- {
1284
- title: t("common.triggerPrice"),
1285
- value: activated_price,
1286
- unit: quote,
1287
- dp: quote_dp
1288
- }
1289
- ),
1290
- callbackView
1291
- ] });
1292
- }
1293
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1294
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1295
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.price") }),
1296
- renderPrice()
1297
- ] }),
1298
- /* @__PURE__ */ jsxRuntime.jsx(
1299
- OrderItem,
1300
- {
1301
- title: t("common.estTotal"),
1302
- value: order.total,
1303
- unit: quote,
1304
- dp: quote_dp
1259
+ },
1260
+ {
1261
+ title: t("common.orderPrice"),
1262
+ dataIndex: "order_price",
1263
+ width: 100,
1264
+ render: (value, record) => {
1265
+ const showWarning = !!(record.side === types.OrderSide.BUY ? askAndBid?.[0] && Number(value) >= askAndBid?.[0] : askAndBid?.[1] && Number(value) <= askAndBid?.[1]);
1266
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 1, children: [
1267
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text.numeral, { rule: "price", dp: quote_dp, children: value }),
1268
+ showWarning && /* @__PURE__ */ jsxRuntime.jsx(
1269
+ ui.Tooltip,
1270
+ {
1271
+ content: t(
1272
+ "orderEntry.confirmScaledOrder.orderPrice.warning"
1273
+ ),
1274
+ className: "oui-w-[240px] oui-text-2xs oui-font-semibold oui-text-base-contrast-80",
1275
+ children: /* @__PURE__ */ jsxRuntime.jsx(TooltipIcon, { className: "oui-text-warning-darken" })
1276
+ }
1277
+ )
1278
+ ] });
1305
1279
  }
1306
- )
1307
- ] });
1308
- };
1309
- const header = /* @__PURE__ */ jsxRuntime.jsxs(
1310
- ui.Flex,
1311
- {
1312
- justify: "between",
1313
- className: "oui-orderEntry-orderConfirmDialog-header",
1314
- children: [
1315
- /* @__PURE__ */ jsxRuntime.jsx(
1316
- ui.Text.formatted,
1317
- {
1318
- rule: "symbol",
1319
- showIcon: true,
1320
- className: "oui-orderConfirmDialog-symbol",
1321
- children: order.symbol
1322
- }
1323
- ),
1324
- /* @__PURE__ */ jsxRuntime.jsxs(
1325
- ui.Flex,
1326
- {
1327
- justify: "end",
1328
- gapX: 1,
1329
- className: "oui-orderConfirmDialog-header-tags",
1330
- children: [
1331
- /* @__PURE__ */ jsxRuntime.jsx(OrderTypeTag, { type: order_type }),
1332
- side === types.OrderSide.BUY ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "buy", size: "sm", children: t("common.buy") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "sell", size: "sm", children: t("common.sell") })
1333
- ]
1334
- }
1335
- )
1336
- ]
1337
- }
1338
- );
1339
- const quantityItem = /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1340
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.orderQty") }),
1341
- /* @__PURE__ */ jsxRuntime.jsx(
1342
- ui.Text.numeral,
1343
- {
1344
- rule: "price",
1345
- dp: base_dp,
1346
- padding: false,
1347
- className: "oui-text-base-contrast",
1348
- children: order.order_quantity
1349
1280
  }
1350
- )
1351
- ] });
1352
- const triggerPriceItem = (order_type === types.OrderType.STOP_LIMIT || order_type === types.OrderType.STOP_MARKET && order.trigger_price) && /* @__PURE__ */ jsxRuntime.jsx(
1353
- OrderItem,
1354
- {
1355
- title: t("common.trigger"),
1356
- value: order.trigger_price,
1357
- unit: quote,
1358
- dp: quote_dp
1359
- }
1360
- );
1361
- const tpslTriggerPrice = (order.tp_trigger_price || order.sl_trigger_price) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1362
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-my-4" }),
1363
- /* @__PURE__ */ jsxRuntime.jsxs(
1364
- "div",
1281
+ ];
1282
+ }, [t, symbolInfo, askAndBid, base_dp, quote_dp]);
1283
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-scaledOrderConfirm oui-font-semibold", children: [
1284
+ /* @__PURE__ */ jsxRuntime.jsx(
1285
+ ui.DataTable,
1365
1286
  {
1366
- className: ui.textVariants({
1367
- size: "sm",
1368
- intensity: 54,
1369
- className: "oui-space-y-1 oui-w-full oui-flex oui-flex-col oui-gap-3"
1370
- }),
1371
- children: [
1372
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-base-contrast", children: renderPositionType() }),
1373
- renderTPSLQty(),
1374
- /* @__PURE__ */ jsxRuntime.jsxs(
1375
- ui.Flex,
1376
- {
1377
- direction: "column",
1378
- justify: "between",
1379
- itemAlign: "start",
1380
- gap: 1,
1381
- className: "oui-w-full",
1382
- children: [
1383
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
1384
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.tpTriggerPrice") }),
1385
- renderTPSLPrice({
1386
- price: order.tp_trigger_price ?? "",
1387
- isOrderPrice: false,
1388
- isEnable: !!order.tp_trigger_price,
1389
- colorType: "TP"
1390
- })
1391
- ] }),
1392
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
1393
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.tpOrderPrice") }),
1394
- renderTPSLPrice({
1395
- price: order.tp_order_price ?? "",
1396
- isOrderPrice: true,
1397
- isEnable: !!order.tp_trigger_price,
1398
- colorType: "TP"
1399
- })
1400
- ] })
1401
- ]
1402
- }
1287
+ classNames: {
1288
+ root: ui.cn(
1289
+ "oui-scaledOrderConfirm-table",
1290
+ "oui-bg-base-7",
1291
+ "oui-rounded-lg",
1292
+ // need to set overflow hidden because table header will avoid the border radius
1293
+ "oui-overflow-hidden",
1294
+ // "oui-text-2xs lg:oui-text-xs",
1295
+ // if orders is greater than 6, set the height to 320px to show scroll bar
1296
+ order.orders?.length >= 6 && "oui-h-[320px]"
1403
1297
  ),
1404
- /* @__PURE__ */ jsxRuntime.jsxs(
1405
- ui.Flex,
1406
- {
1407
- direction: "column",
1408
- justify: "between",
1409
- itemAlign: "start",
1410
- gap: 1,
1411
- className: "oui-w-full",
1412
- children: [
1413
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
1414
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.slTriggerPrice") }),
1415
- renderTPSLPrice({
1416
- price: order.sl_trigger_price ?? "",
1417
- isOrderPrice: false,
1418
- isEnable: !!order.sl_trigger_price,
1419
- colorType: "SL"
1420
- })
1421
- ] }),
1422
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-w-full", children: [
1423
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("tpsl.slOrderPrice") }),
1424
- renderTPSLPrice({
1425
- price: order.sl_order_price ?? "",
1426
- isOrderPrice: true,
1427
- isEnable: !!order.sl_trigger_price,
1428
- colorType: "SL"
1429
- })
1430
- ] })
1431
- ]
1432
- }
1433
- )
1434
- ]
1298
+ // set the min height of the table to show 2 rows
1299
+ scroll: "!oui-min-h-[130px]"
1300
+ },
1301
+ dataSource,
1302
+ columns,
1303
+ bordered: true,
1304
+ onRow: () => {
1305
+ return {
1306
+ className: ui.cn("oui-h-[50px]")
1307
+ };
1308
+ }
1435
1309
  }
1436
- )
1437
- ] });
1438
- const orderConfirmCheckbox = /* @__PURE__ */ jsxRuntime.jsxs(
1439
- ui.Flex,
1440
- {
1441
- gapX: 1,
1442
- pt: 4,
1443
- pb: 5,
1444
- className: "oui-orderEntry-orderConfirmDialog-disableConfirm",
1445
- children: [
1446
- /* @__PURE__ */ jsxRuntime.jsx(
1447
- ui.Checkbox,
1448
- {
1449
- id: "orderConfirm",
1450
- color: "white",
1451
- className: "oui-orderConfirmDialog-disableConfirm-checkbox",
1452
- onCheckedChange: (checked) => {
1453
- setNeedConfirm(!!!checked);
1454
- }
1455
- }
1456
- ),
1310
+ ),
1311
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-scaledOrderConfirm-content oui-mb-5 oui-mt-4 oui-text-2xs", children: [
1312
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1313
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.totalOrders") }),
1314
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: order.orders?.length })
1315
+ ] }),
1316
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", mt: 2, children: [
1317
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.totalQuantity") }),
1457
1318
  /* @__PURE__ */ jsxRuntime.jsx(
1458
- "label",
1319
+ ui.Text.numeral,
1459
1320
  {
1460
- htmlFor: "orderConfirm",
1461
- className: ui.textVariants({
1462
- size: "xs",
1463
- intensity: 54
1464
- }),
1465
- children: t("orderEntry.disableOrderConfirm")
1321
+ rule: "price",
1322
+ unit: base,
1323
+ dp: base_dp,
1324
+ padding: false,
1325
+ intensity: 80,
1326
+ unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1327
+ children: totalQuantity
1466
1328
  }
1467
1329
  )
1468
- ]
1469
- }
1470
- );
1471
- const buttons = /* @__PURE__ */ jsxRuntime.jsxs(
1472
- ui.Grid,
1473
- {
1474
- cols: 2,
1475
- gapX: 3,
1476
- className: "oui-orderEntry-orderConfirmDialog-actions",
1477
- children: [
1478
- /* @__PURE__ */ jsxRuntime.jsx(
1479
- ui.Button,
1480
- {
1481
- color: "secondary",
1482
- size: "md",
1483
- className: "oui-cancel-btn",
1484
- onClick: () => onCancel(),
1485
- children: t("common.cancel")
1486
- }
1487
- ),
1330
+ ] }),
1331
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", mt: 2, children: [
1332
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.notional") }),
1488
1333
  /* @__PURE__ */ jsxRuntime.jsx(
1489
- ui.Button,
1334
+ ui.Text.numeral,
1490
1335
  {
1491
- size: "md",
1492
- className: "oui-confirm-btn",
1493
- onClick: () => onConfirm(),
1494
- children: t("common.confirm")
1495
- }
1496
- )
1497
- ]
1498
- }
1499
- );
1500
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1501
- header,
1502
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-my-4" }),
1503
- /* @__PURE__ */ jsxRuntime.jsxs(
1504
- "div",
1505
- {
1506
- className: ui.textVariants({
1507
- size: "sm",
1508
- intensity: 54,
1509
- className: "oui-orderEntry-orderConfirmDialog-content oui-space-y-1"
1510
- }),
1511
- children: [
1512
- quantityItem,
1513
- triggerPriceItem,
1514
- renderPriceAndTotal()
1515
- ]
1516
- }
1517
- ),
1518
- tpslTriggerPrice,
1519
- orderConfirmCheckbox,
1520
- buttons
1521
- ] });
1522
- };
1523
- var OrderItem = (props) => {
1524
- const { title, value, unit, dp } = props;
1525
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1526
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: title }),
1527
- /* @__PURE__ */ jsxRuntime.jsx(
1528
- ui.Text.numeral,
1529
- {
1530
- unit,
1531
- rule: "price",
1532
- dp,
1533
- padding: false,
1534
- className: "oui-text-base-contrast",
1535
- unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1536
- children: value
1537
- }
1538
- )
1539
- ] });
1540
- };
1541
- OrderConfirmDialog.displayName = "OrderConfirmDialog";
1542
- var OrderTypeTag = (props) => {
1543
- const { t } = i18n.useTranslation();
1544
- const typeStr = React3.useMemo(() => {
1545
- switch (props.type) {
1546
- case types.OrderType.LIMIT:
1547
- return t("orderEntry.orderType.limit");
1548
- case types.OrderType.MARKET:
1549
- return t("common.marketPrice");
1550
- case types.OrderType.STOP_LIMIT:
1551
- return t("orderEntry.orderType.stopLimit");
1552
- case types.OrderType.STOP_MARKET:
1553
- return t("orderEntry.orderType.stopMarket");
1554
- case types.OrderType.TRAILING_STOP:
1555
- return t("orderEntry.orderType.trailingStop");
1556
- default:
1557
- return "";
1558
- }
1559
- }, [props.type]);
1560
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "neutral", size: "sm", children: typeStr });
1561
- };
1562
- var Dialog = (props) => {
1563
- const { close, resolve, reject, ...rest } = props;
1564
- return /* @__PURE__ */ jsxRuntime.jsx(
1565
- OrderConfirmDialog,
1566
- {
1567
- ...rest,
1568
- onCancel: () => {
1569
- reject();
1570
- close();
1571
- },
1572
- onConfirm: () => {
1573
- resolve();
1574
- close();
1575
- }
1576
- }
1577
- );
1578
- };
1579
- var orderConfirmDialogId = "orderConfirm";
1580
- ui.registerSimpleDialog(orderConfirmDialogId, Dialog, {
1581
- size: "sm",
1582
- title: () => i18n.i18n.t("orderEntry.orderConfirm")
1583
- });
1584
- var MaxQtyConfirm = React3.memo((props) => {
1585
- const { t } = i18n.useTranslation();
1586
- return /* @__PURE__ */ jsxRuntime.jsx(
1587
- ui.SimpleDialog,
1588
- {
1589
- open: props.open,
1590
- title: t("orderEntry.orderConfirm"),
1591
- closable: true,
1592
- onOpenChange: props.onOpenChange,
1593
- size: "sm",
1594
- classNames: {
1595
- footer: "oui-maxQtyConfirm-footer",
1596
- body: "oui-maxQtyConfirm-body"
1597
- },
1598
- actions: {
1599
- primary: {
1600
- label: t("orderEntry.placeOrderNow"),
1601
- className: "oui-primary-btn oui-text-sm oui-font-semibold oui-w-[100%] oui-h-8",
1602
- onClick: () => {
1603
- props.onConfirm();
1604
- return Promise.resolve();
1605
- }
1606
- },
1607
- secondary: {
1608
- label: t("common.cancel"),
1609
- className: "oui-secondary-btn oui-text-sm oui-font-semibold oui-w-[100%] oui-h-8",
1610
- onClick: () => {
1611
- props.onOpenChange(false);
1612
- return Promise.resolve();
1613
- }
1614
- }
1615
- },
1616
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-maxQtyConfirm-content oui-text-2xs lg:oui-text-sm", children: t("orderEntry.maxQty.reminder.content", {
1617
- maxQty: `${props.maxQty} ${props.base}`
1618
- }) })
1619
- }
1620
- );
1621
- });
1622
- var ScaledOrderConfirm = (props) => {
1623
- const { order, symbolInfo, dataSource, national, askAndBid, totalQuantity } = props;
1624
- const { base, quote, base_dp, quote_dp } = symbolInfo;
1625
- const { t } = i18n.useTranslation();
1626
- const onCancel = () => {
1627
- props.reject();
1628
- props.close?.();
1629
- };
1630
- const onConfirm = () => {
1631
- props.resolve();
1632
- props.close?.();
1633
- };
1634
- const columns = React3.useMemo(() => {
1635
- return [
1636
- {
1637
- title: t("common.symbol"),
1638
- dataIndex: "symbol",
1639
- width: 125,
1640
- render: (value, record) => {
1641
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, children: [
1642
- /* @__PURE__ */ jsxRuntime.jsx(
1643
- "div",
1644
- {
1645
- className: ui.cn(
1646
- "oui-h-[38px] oui-w-1 oui-shrink-0 oui-rounded-[1px]",
1647
- record.side === types.OrderSide.BUY ? "oui-bg-trade-profit" : "oui-bg-trade-loss"
1648
- )
1649
- }
1650
- ),
1651
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", itemAlign: "start", children: [
1652
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 1, children: [
1653
- /* @__PURE__ */ jsxRuntime.jsx(ui.TokenIcon, { symbol: value, className: "oui-size-3" }),
1654
- /* @__PURE__ */ jsxRuntime.jsx(
1655
- ui.Text.formatted,
1656
- {
1657
- rule: "symbol",
1658
- size: "xs",
1659
- formatString: "base-type",
1660
- children: value
1661
- }
1662
- )
1663
- ] }),
1664
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "neutral", size: "xs", children: t("orderEntry.orderType.limit") })
1665
- ] })
1666
- ] });
1667
- }
1668
- },
1669
- {
1670
- title: t("common.quantity"),
1671
- dataIndex: "order_quantity",
1672
- width: 100,
1673
- render: (value, record) => {
1674
- return /* @__PURE__ */ jsxRuntime.jsx(
1675
- ui.Text.numeral,
1676
- {
1677
- rule: "price",
1678
- dp: base_dp,
1679
- padding: false,
1680
- color: record.side === types.OrderSide.BUY ? "buy" : "sell",
1681
- children: value
1682
- }
1683
- );
1684
- }
1685
- },
1686
- {
1687
- title: t("common.orderPrice"),
1688
- dataIndex: "order_price",
1689
- width: 100,
1690
- render: (value, record) => {
1691
- const showWarning = !!(record.side === types.OrderSide.BUY ? askAndBid?.[0] && Number(value) >= askAndBid?.[0] : askAndBid?.[1] && Number(value) <= askAndBid?.[1]);
1692
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 1, children: [
1693
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text.numeral, { rule: "price", dp: quote_dp, children: value }),
1694
- showWarning && /* @__PURE__ */ jsxRuntime.jsx(
1695
- ui.Tooltip,
1696
- {
1697
- content: t(
1698
- "orderEntry.confirmScaledOrder.orderPrice.warning"
1699
- ),
1700
- className: "oui-w-[240px] oui-text-2xs oui-font-semibold oui-text-base-contrast-80",
1701
- children: /* @__PURE__ */ jsxRuntime.jsx(TooltipIcon, { className: "oui-text-warning-darken" })
1702
- }
1703
- )
1704
- ] });
1705
- }
1706
- }
1707
- ];
1708
- }, [t, symbolInfo, askAndBid, base_dp, quote_dp]);
1709
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-scaledOrderConfirm oui-font-semibold", children: [
1710
- /* @__PURE__ */ jsxRuntime.jsx(
1711
- ui.DataTable,
1712
- {
1713
- classNames: {
1714
- root: ui.cn(
1715
- "oui-scaledOrderConfirm-table",
1716
- "oui-bg-base-7",
1717
- "oui-rounded-lg",
1718
- // need to set overflow hidden because table header will avoid the border radius
1719
- "oui-overflow-hidden",
1720
- // "oui-text-2xs lg:oui-text-xs",
1721
- // if orders is greater than 6, set the height to 320px to show scroll bar
1722
- order.orders?.length >= 6 && "oui-h-[320px]"
1723
- ),
1724
- // set the min height of the table to show 2 rows
1725
- scroll: "!oui-min-h-[130px]"
1726
- },
1727
- dataSource,
1728
- columns,
1729
- bordered: true,
1730
- onRow: () => {
1731
- return {
1732
- className: ui.cn("oui-h-[50px]")
1733
- };
1734
- }
1735
- }
1736
- ),
1737
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-scaledOrderConfirm-content oui-mb-5 oui-mt-4 oui-text-2xs", children: [
1738
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", children: [
1739
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.totalOrders") }),
1740
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, children: order.orders?.length })
1741
- ] }),
1742
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", mt: 2, children: [
1743
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("orderEntry.totalQuantity") }),
1744
- /* @__PURE__ */ jsxRuntime.jsx(
1745
- ui.Text.numeral,
1746
- {
1747
- rule: "price",
1748
- unit: base,
1749
- dp: base_dp,
1750
- padding: false,
1751
- intensity: 80,
1752
- unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1753
- children: totalQuantity
1754
- }
1755
- )
1756
- ] }),
1757
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", mt: 2, children: [
1758
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: t("common.notional") }),
1759
- /* @__PURE__ */ jsxRuntime.jsx(
1760
- ui.Text.numeral,
1761
- {
1762
- rule: "price",
1763
- unit: quote,
1764
- dp: quote_dp,
1765
- padding: false,
1766
- intensity: 80,
1767
- unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1768
- children: national
1336
+ rule: "price",
1337
+ unit: quote,
1338
+ dp: quote_dp,
1339
+ padding: false,
1340
+ intensity: 80,
1341
+ unitClassName: "oui-text-base-contrast-36 oui-ml-1",
1342
+ children: national
1769
1343
  }
1770
1344
  )
1771
1345
  ] })
@@ -1851,17 +1425,580 @@ var ScaledOrderConfirmWidget = (props) => {
1851
1425
  const state = useScaledOrderConfirmScript(props);
1852
1426
  return /* @__PURE__ */ jsxRuntime.jsx(ScaledOrderConfirm, { ...props, ...state });
1853
1427
  };
1854
- var scaledOrderConfirmDialogId = "scaledOrderConfirm";
1855
- ui.registerSimpleDialog(scaledOrderConfirmDialogId, ScaledOrderConfirmWidget, {
1856
- size: "md",
1857
- title: () => i18n.i18n.t("orderEntry.confirmScaledOrder"),
1858
- contentProps: {
1859
- // className: "oui-p-0",
1860
- }
1861
- });
1428
+ var scaledOrderConfirmDialogId = "scaledOrderConfirm";
1429
+ ui.registerSimpleDialog(scaledOrderConfirmDialogId, ScaledOrderConfirmWidget, {
1430
+ size: "md",
1431
+ title: () => i18n.i18n.t("orderEntry.confirmScaledOrder"),
1432
+ contentProps: {
1433
+ // className: "oui-p-0",
1434
+ }
1435
+ });
1436
+ var RegularFeesUI = (props) => {
1437
+ const { t } = i18n.useTranslation();
1438
+ const { taker, maker } = props;
1439
+ const originalTrailingFees = /* @__PURE__ */ jsxRuntime.jsx(
1440
+ ui.Flex,
1441
+ {
1442
+ itemAlign: "center",
1443
+ justify: "between",
1444
+ width: "100%",
1445
+ gap: 1,
1446
+ className: "oui-orderEntry-fees",
1447
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", itemAlign: "center", justify: "between", children: [
1448
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-fees-label oui-truncate", size: "2xs", children: t("common.fees") }),
1449
+ /* @__PURE__ */ jsxRuntime.jsx(
1450
+ uiConnector.AuthGuard,
1451
+ {
1452
+ fallback: () => /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
1453
+ t("dmm.taker"),
1454
+ ": --% / ",
1455
+ t("dmm.maker"),
1456
+ ": --%"
1457
+ ] }),
1458
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, className: "oui-fees-value-container", children: [
1459
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
1460
+ t("dmm.taker"),
1461
+ ":"
1462
+ ] }),
1463
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-base-contrast-80", children: taker }),
1464
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: "/" }),
1465
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "oui-truncate", size: "2xs", children: [
1466
+ t("dmm.maker"),
1467
+ ":"
1468
+ ] }),
1469
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-base-contrast-80", children: maker })
1470
+ ] })
1471
+ }
1472
+ )
1473
+ ] })
1474
+ }
1475
+ );
1476
+ return originalTrailingFees;
1477
+ };
1478
+ var RegularFeesWidget = (props) => {
1479
+ return /* @__PURE__ */ jsxRuntime.jsx(RegularFeesUI, { ...props });
1480
+ };
1481
+ var FeesWidget = ({ symbol }) => {
1482
+ const { takerFee, makerFee, rwaTakerFee, rwaMakerFee } = hooks.useFeeState();
1483
+ const info = hooks.useRwaSymbolsInfoStore();
1484
+ const isRwa = info?.[symbol] !== void 0;
1485
+ return /* @__PURE__ */ jsxRuntime.jsx(
1486
+ RegularFeesWidget,
1487
+ {
1488
+ taker: isRwa ? rwaTakerFee : takerFee,
1489
+ maker: isRwa ? rwaMakerFee : makerFee
1490
+ }
1491
+ );
1492
+ };
1493
+ var options = [0.01, 0.05, 0.1];
1494
+ var SlippageEditor = React3.forwardRef((props, ref) => {
1495
+ const { t } = i18n.useTranslation();
1496
+ const [value, setValue] = React3.useState();
1497
+ const [customValue, setCustomValue] = React3.useState("");
1498
+ const [error, setError] = React3.useState(void 0);
1499
+ React3.useImperativeHandle(ref, () => ({
1500
+ getValue: () => customValue ? new utils.Decimal(customValue)?.toNumber() : value
1501
+ }));
1502
+ React3.useEffect(() => {
1503
+ if (props.initialValue && !options.includes(props.initialValue)) {
1504
+ setCustomValue(props.initialValue.toString());
1505
+ } else {
1506
+ setValue(props.initialValue);
1507
+ }
1508
+ }, [props.initialValue, open]);
1509
+ const onClick = (val) => {
1510
+ setValue(val);
1511
+ setCustomValue("");
1512
+ setError(void 0);
1513
+ };
1514
+ const onValueChange = (val) => {
1515
+ if (!val) {
1516
+ setCustomValue(val);
1517
+ return;
1518
+ }
1519
+ const d = new utils.Decimal(val);
1520
+ setValue(void 0);
1521
+ if (d.gt(3)) {
1522
+ setCustomValue("3");
1523
+ setError(t("orderEntry.slippage.error.exceed"));
1524
+ } else {
1525
+ setCustomValue(val);
1526
+ setError(void 0);
1527
+ }
1528
+ };
1529
+ const toolTipButton = props.isMobile ? /* @__PURE__ */ jsxRuntime.jsx(
1530
+ "button",
1531
+ {
1532
+ onClick: () => {
1533
+ ui.modal.alert({
1534
+ title: t("common.tips"),
1535
+ message: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: t("orderEntry.slippage.tips") })
1536
+ });
1537
+ },
1538
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.ExclamationFillIcon, { className: "oui-text-base-contrast-54", size: 16 })
1539
+ }
1540
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1541
+ ui.Tooltip,
1542
+ {
1543
+ content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, size: "2xs", children: t("orderEntry.slippage.tips") }),
1544
+ className: "oui-w-[260px] oui-bg-base-6",
1545
+ arrow: { className: "oui-fill-base-6" },
1546
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.ExclamationFillIcon, { className: "oui-text-base-contrast-54", size: 16 }) })
1547
+ }
1548
+ );
1549
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-slippageEditor oui-text-2xs", children: [
1550
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { mb: 2, gapX: 1, children: [
1551
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xs", children: t("orderEntry.slippage") }),
1552
+ toolTipButton
1553
+ ] }),
1554
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gapX: 2, children: [
1555
+ options.map((item) => {
1556
+ const isActive = value === item;
1557
+ return /* @__PURE__ */ jsxRuntime.jsx(
1558
+ SlippageItem,
1559
+ {
1560
+ value: item,
1561
+ isActive,
1562
+ onClick: () => {
1563
+ onClick(item);
1564
+ }
1565
+ },
1566
+ item
1567
+ );
1568
+ }),
1569
+ /* @__PURE__ */ jsxRuntime.jsx(
1570
+ ui.Input,
1571
+ {
1572
+ suffix: "%",
1573
+ formatters: [
1574
+ ui.inputFormatter.numberFormatter,
1575
+ ui.inputFormatter.dpFormatter(2)
1576
+ ],
1577
+ value: customValue,
1578
+ onValueChange,
1579
+ classNames: {
1580
+ root: ui.cn(
1581
+ "oui-slippageEditor-customInput",
1582
+ "oui-rounded-md oui-bg-base-6",
1583
+ "oui-h-[40px] oui-w-[74px]"
1584
+ ),
1585
+ input: "oui-text-base-contrast",
1586
+ additional: "oui-pl-1"
1587
+ }
1588
+ }
1589
+ )
1590
+ ] }),
1591
+ !!error && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { mt: 5, className: "-oui-mb-5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "danger", children: error }) })
1592
+ ] });
1593
+ });
1594
+ var SlippageItem = ({ value, isActive, onClick }) => {
1595
+ return /* @__PURE__ */ jsxRuntime.jsx(
1596
+ ui.Flex,
1597
+ {
1598
+ intensity: 600,
1599
+ justify: "center",
1600
+ itemAlign: "center",
1601
+ r: "md",
1602
+ width: 74,
1603
+ height: 40,
1604
+ className: ui.cn(
1605
+ "oui-slippageEditor-option",
1606
+ "oui-cursor-pointer oui-select-none",
1607
+ isActive ? "oui-bg-primary-light oui-text-primary-contrast/80" : "oui-text-base-contrast-80"
1608
+ ),
1609
+ onClick,
1610
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "sm", children: [
1611
+ value,
1612
+ "%"
1613
+ ] })
1614
+ }
1615
+ );
1616
+ };
1617
+ var SlippageCell = (props) => {
1618
+ const { t } = i18n.useTranslation();
1619
+ const [open2, { setTrue: setOpen, setFalse: setClose, toggle }] = hooks.useBoolean(false);
1620
+ const { isMobile } = ui.useScreen();
1621
+ const slippageRef = React3.useRef(null);
1622
+ const onConfirm = () => {
1623
+ const val = slippageRef.current?.getValue();
1624
+ props.setSlippage(!val ? "1" : val.toString());
1625
+ setClose();
1626
+ return Promise.resolve(true);
1627
+ };
1628
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1629
+ /* @__PURE__ */ jsxRuntime.jsx(
1630
+ ui.SimpleDialog,
1631
+ {
1632
+ open: open2,
1633
+ onOpenChange: toggle,
1634
+ title: t("common.settings"),
1635
+ contentProps: { size: isMobile ? "xs" : "sm" },
1636
+ classNames: {
1637
+ footer: "oui-orderEntry-slippage-footer",
1638
+ body: "oui-orderEntry-slippage-body"
1639
+ },
1640
+ actions: {
1641
+ primary: {
1642
+ disabled: false,
1643
+ label: t("common.save"),
1644
+ onClick: onConfirm,
1645
+ className: "oui-slippage-save-btn"
1646
+ },
1647
+ secondary: {
1648
+ label: t("common.cancel"),
1649
+ onClick: () => setClose(),
1650
+ className: "oui-slippage-cancel-btn"
1651
+ }
1652
+ },
1653
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1654
+ SlippageEditor,
1655
+ {
1656
+ ref: slippageRef,
1657
+ isMobile,
1658
+ initialValue: props.slippage ? Number(props.slippage) : void 0
1659
+ }
1660
+ )
1661
+ }
1662
+ ),
1663
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-orderEntry-slippage", children: [
1664
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-slippage-label", size: "2xs", children: t("orderEntry.slippage") }),
1665
+ /* @__PURE__ */ jsxRuntime.jsx(
1666
+ uiConnector.AuthGuard,
1667
+ {
1668
+ fallback: () => /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "2xs", children: [
1669
+ t("orderEntry.slippage.est"),
1670
+ ": -% / ",
1671
+ t("common.max"),
1672
+ ": --%"
1673
+ ] }),
1674
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, className: "oui-slippage-value-container", children: [
1675
+ /* @__PURE__ */ jsxRuntime.jsx(
1676
+ ui.Text.numeral,
1677
+ {
1678
+ size: "2xs",
1679
+ rule: "percentages",
1680
+ prefix: `${t("orderEntry.slippage.est")}: `,
1681
+ suffix: ` / ${t("common.max")}: `,
1682
+ children: props.estSlippage ?? 0
1683
+ }
1684
+ ),
1685
+ /* @__PURE__ */ jsxRuntime.jsx(
1686
+ "button",
1687
+ {
1688
+ className: "oui-slippage-edit-btn oui-text-2xs",
1689
+ onClick: () => setOpen(),
1690
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { className: "oui-gap-0.5", as: "span", children: [
1691
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", className: "oui-text-primary", children: `${props.slippage || "-"}%` }),
1692
+ /* @__PURE__ */ jsxRuntime.jsx(
1693
+ ui.EditIcon,
1694
+ {
1695
+ className: "oui-slippage-edit-icon oui-text-primary oui-hidden md:oui-block",
1696
+ size: 12,
1697
+ opacity: 1
1698
+ }
1699
+ )
1700
+ ] })
1701
+ }
1702
+ )
1703
+ ] })
1704
+ }
1705
+ )
1706
+ ] })
1707
+ ] });
1708
+ };
1709
+ var SlippageUI = (props) => {
1710
+ return /* @__PURE__ */ jsxRuntime.jsx(SlippageCell, { ...props });
1711
+ };
1712
+ function AssetInfo(props) {
1713
+ const { canTrade, disableFeatures, orderType, symbol } = props;
1714
+ const { t } = i18n.useTranslation();
1715
+ const { isMobile } = ui.useScreen();
1716
+ const displayEstLiqPrice = hooks.useGetEstLiqPrice({
1717
+ estLiqPrice: props.estLiqPrice,
1718
+ symbol,
1719
+ side: props.side
1720
+ });
1721
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1722
+ "div",
1723
+ {
1724
+ className: "oui-orderEntry-assetInfo oui-space-y-[2px] xl:oui-space-y-1",
1725
+ children: [
1726
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "between", className: "oui-orderEntry-estLiqPrice", children: [
1727
+ isMobile ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", children: t("orderEntry.estLiqPrice") }) : /* @__PURE__ */ jsxRuntime.jsx(
1728
+ ui.Tooltip,
1729
+ {
1730
+ content: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-min-w-[204px] oui-max-w-[280px] oui-text-2xs oui-leading-normal oui-text-base-contrast-80", children: [
1731
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-text-pretty", children: t("common.liquidationPrice.tooltip") }),
1732
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
1733
+ "a",
1734
+ {
1735
+ href: "https://orderly.network/docs/introduction/trade-on-orderly/perpetual-futures/liquidations",
1736
+ target: "_blank",
1737
+ rel: "noopener noreferrer",
1738
+ className: "oui-text-primary oui-underline",
1739
+ children: t("common.liquidationPrice.tooltip.learnMore")
1740
+ }
1741
+ ) })
1742
+ ] }),
1743
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1744
+ ui.Text,
1745
+ {
1746
+ size: "2xs",
1747
+ className: "oui-estLiqPrice-label oui-cursor-pointer oui-border-b oui-border-dashed oui-border-line-12",
1748
+ children: t("orderEntry.estLiqPrice")
1749
+ }
1750
+ )
1751
+ }
1752
+ ),
1753
+ /* @__PURE__ */ jsxRuntime.jsx(
1754
+ ui.Text.numeral,
1755
+ {
1756
+ unit: props.quote,
1757
+ size: "2xs",
1758
+ dp: props.dp,
1759
+ className: "oui-estLiqPrice-value oui-text-base-contrast-80",
1760
+ unitClassName: "oui-ml-1 oui-text-base-contrast-36",
1761
+ children: canTrade ? displayEstLiqPrice ?? "--" : "--"
1762
+ }
1763
+ )
1764
+ ] }),
1765
+ orderType === types.OrderType.MARKET && !disableFeatures?.includes("slippageSetting") && /* @__PURE__ */ jsxRuntime.jsx(
1766
+ SlippageUI,
1767
+ {
1768
+ slippage: props.slippage,
1769
+ setSlippage: props.setSlippage,
1770
+ estSlippage: props.estSlippage
1771
+ }
1772
+ ),
1773
+ !disableFeatures?.includes("feesInfo") && /* @__PURE__ */ jsxRuntime.jsx(FeesWidget, { symbol: props.symbol })
1774
+ ]
1775
+ }
1776
+ );
1777
+ }
1778
+ var calculateLTVColor = (val) => {
1779
+ if (val >= 0 && val < 50) {
1780
+ return "oui-text-success";
1781
+ } else if (val >= 50 && val < 80) {
1782
+ return "oui-text-warning";
1783
+ } else if (val >= 80) {
1784
+ return "oui-text-danger";
1785
+ } else {
1786
+ return "";
1787
+ }
1788
+ };
1789
+ var LTVRiskTooltipUI = (props) => {
1790
+ const { t } = i18n.useTranslation();
1791
+ const {
1792
+ ltv_threshold,
1793
+ negative_usdc_threshold,
1794
+ isThresholdLoading,
1795
+ holdingData = [],
1796
+ currentLtv,
1797
+ onConvert,
1798
+ marginMode
1799
+ } = props;
1800
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1801
+ ui.Flex,
1802
+ {
1803
+ gap: 1,
1804
+ className: "oui-orderEntry-ltvRiskTooltip oui-w-72 oui-max-w-72",
1805
+ direction: "column",
1806
+ itemAlign: "start",
1807
+ children: [
1808
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", justify: "between", itemAlign: "center", children: [
1809
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("common.assets") }),
1810
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("transfer.deposit.collateralContribution") })
1811
+ ] }),
1812
+ holdingData.map((asset, index) => {
1813
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1814
+ ui.Flex,
1815
+ {
1816
+ width: "100%",
1817
+ justify: "between",
1818
+ itemAlign: "center",
1819
+ children: [
1820
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 80, size: "xs", children: asset.token }),
1821
+ /* @__PURE__ */ jsxRuntime.jsx(
1822
+ ui.Text,
1823
+ {
1824
+ size: "xs",
1825
+ intensity: 80,
1826
+ className: ui.cn(
1827
+ Number(asset.collateralContribution) < 0 && "oui-text-warning"
1828
+ ),
1829
+ children: utils.removeTrailingZeros(asset.collateralContribution)
1830
+ }
1831
+ )
1832
+ ]
1833
+ },
1834
+ `item-${index}`
1835
+ );
1836
+ }),
1837
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-w-full" }),
1838
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { width: "100%", justify: "between", itemAlign: "center", children: [
1839
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { intensity: 36, size: "xs", children: t("transfer.LTV.currentLTV") }),
1840
+ /* @__PURE__ */ jsxRuntime.jsxs(
1841
+ ui.Text,
1842
+ {
1843
+ size: "xs",
1844
+ intensity: 36,
1845
+ className: ui.cn("oui-select-none", calculateLTVColor(currentLtv)),
1846
+ children: [
1847
+ currentLtv,
1848
+ "%"
1849
+ ]
1850
+ }
1851
+ )
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-py-2", intensity: 54, size: "2xs", children: t("transfer.LTV.tooltip", {
1854
+ threshold: isThresholdLoading ? "-" : ltv_threshold,
1855
+ usdcThreshold: isThresholdLoading ? "-" : negative_usdc_threshold
1856
+ }) }),
1857
+ /* @__PURE__ */ jsxRuntime.jsx(
1858
+ ui.Button,
1859
+ {
1860
+ fullWidth: true,
1861
+ size: "md",
1862
+ variant: "outlined",
1863
+ color: "secondary",
1864
+ className: "oui-ltvRiskTooltip-convert-btn",
1865
+ onClick: onConvert,
1866
+ children: t("transfer.convert.convertAssets")
1867
+ }
1868
+ )
1869
+ ]
1870
+ }
1871
+ );
1872
+ };
1873
+ var useConvertThreshold = () => {
1874
+ const { data, error, isLoading } = hooks.useQuery(
1875
+ "/v1/public/auto_convert_threshold",
1876
+ { errorRetryCount: 3 }
1877
+ );
1878
+ return {
1879
+ ltv_threshold: new utils.Decimal(data?.ltv_threshold ?? 0).mul(100).toNumber(),
1880
+ negative_usdc_threshold: data?.negative_usdc_threshold,
1881
+ isLoading,
1882
+ error
1883
+ };
1884
+ };
1885
+ var useLTVTooltipScript = (marginMode) => {
1886
+ const { data: holdingList = [], isLoading: isHoldingLoading } = hooks.useHoldingStream();
1887
+ const {
1888
+ ltv_threshold,
1889
+ negative_usdc_threshold,
1890
+ isLoading: isThresholdLoading
1891
+ } = useConvertThreshold();
1892
+ const tokensInfo = hooks.useAppStore((state) => state.tokensInfo);
1893
+ const { getIndexPrice } = hooks.useIndexPricesStream();
1894
+ const holdingData = holdingList.map((item) => {
1895
+ const tokenInfo = tokensInfo?.find(({ token }) => token === item.token);
1896
+ const indexPrice = getIndexPrice(item.token);
1897
+ const collateralRatio = tokenInfo ? perp.account.collateralRatio({
1898
+ baseWeight: tokenInfo.base_weight ?? 0,
1899
+ discountFactor: tokenInfo.discount_factor ?? 0,
1900
+ collateralQty: item.holding,
1901
+ collateralCap: tokenInfo?.user_max_qty ?? item.holding,
1902
+ indexPrice
1903
+ }) : utils.zero;
1904
+ const collateralContribution = perp.account.collateralContribution({
1905
+ collateralQty: item.holding,
1906
+ collateralCap: tokenInfo?.user_max_qty ?? item.holding,
1907
+ collateralRatio: collateralRatio.toNumber(),
1908
+ indexPrice
1909
+ });
1910
+ return {
1911
+ ...item,
1912
+ collateralContribution
1913
+ };
1914
+ });
1915
+ const currentLtv = hooks.useComputedLTV();
1916
+ const onConvert = React3.useCallback(async () => {
1917
+ return ui.modal.show("ConvertDialogId");
1918
+ }, []);
1919
+ return {
1920
+ holdingData,
1921
+ isHoldingLoading,
1922
+ ltv_threshold,
1923
+ negative_usdc_threshold,
1924
+ isThresholdLoading,
1925
+ currentLtv,
1926
+ onConvert,
1927
+ marginMode
1928
+ };
1929
+ };
1930
+ var LTVRiskTooltipWidget = ({
1931
+ marginMode
1932
+ }) => {
1933
+ const state = useLTVTooltipScript(marginMode);
1934
+ return /* @__PURE__ */ jsxRuntime.jsx(LTVRiskTooltipUI, { ...state });
1935
+ };
1936
+ var Available = (props) => {
1937
+ const { canTrade, currentLtv, quote, freeCollateral, marginMode } = props;
1938
+ const { t } = i18n.useTranslation();
1939
+ const { isMobile } = ui.useScreen();
1940
+ const showLTV = React3.useMemo(() => {
1941
+ return typeof currentLtv === "number" && !Number.isNaN(currentLtv) && currentLtv > 0;
1942
+ }, [currentLtv]);
1943
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1944
+ ui.Flex,
1945
+ {
1946
+ itemAlign: "center",
1947
+ justify: "between",
1948
+ className: "oui-orderEntry-available",
1949
+ children: [
1950
+ marginMode === types.MarginMode.ISOLATED ? /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: t("transfer.LTV.isolatedModeUsdcOnly"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-available-label oui-cursor-pointer", size: "2xs", children: t("common.available") }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-available-label", size: "2xs", children: t("common.available") }),
1951
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { itemAlign: "center", justify: "center", gap: 1, children: [
1952
+ showLTV && /* @__PURE__ */ jsxRuntime.jsx(
1953
+ ui.Tooltip,
1954
+ {
1955
+ className: "oui-available-ltvRisk-tooltip oui-bg-base-6 oui-p-2",
1956
+ content: /* @__PURE__ */ jsxRuntime.jsx(LTVRiskTooltipWidget, { marginMode }),
1957
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1958
+ ui.InfoCircleIcon,
1959
+ {
1960
+ className: "oui-cursor-pointer oui-text-warning oui-opacity-80"
1961
+ }
1962
+ )
1963
+ }
1964
+ ),
1965
+ /* @__PURE__ */ jsxRuntime.jsx(
1966
+ ui.Text.numeral,
1967
+ {
1968
+ unit: quote,
1969
+ size: "2xs",
1970
+ className: "oui-available-value oui-text-base-contrast-80",
1971
+ unitClassName: "oui-ml-1 oui-text-base-contrast-54",
1972
+ dp: 2,
1973
+ padding: false,
1974
+ children: canTrade ? freeCollateral : 0
1975
+ }
1976
+ ),
1977
+ /* @__PURE__ */ jsxRuntime.jsx(
1978
+ ui.Button,
1979
+ {
1980
+ variant: "text",
1981
+ size: "xs",
1982
+ color: "secondary",
1983
+ className: "oui-available-deposit-icon oui-p-0 hover:oui-text-base-contrast-80",
1984
+ onClick: () => {
1985
+ const handleDomId = isMobile ? "DepositAndWithdrawWithSheetId" : "DepositAndWithdrawWithDialogId";
1986
+ ui.modal.show(handleDomId, {
1987
+ activeTab: "deposit"
1988
+ });
1989
+ },
1990
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.AddCircleIcon, { opacity: 1 })
1991
+ }
1992
+ )
1993
+ ] })
1994
+ ]
1995
+ }
1996
+ );
1997
+ };
1862
1998
  var OrderTypeSelect = (props) => {
1863
1999
  const { t } = i18n.useTranslation();
1864
2000
  const { isMobile } = ui.useScreen();
2001
+ const { marketOrderDisabled = false, marketOrderDisabledTooltip } = props;
1865
2002
  const allOptions = React3.useMemo(() => {
1866
2003
  return [
1867
2004
  { label: t("orderEntry.orderType.limitOrder"), value: types.OrderType.LIMIT },
@@ -1911,6 +2048,7 @@ var OrderTypeSelect = (props) => {
1911
2048
  [types.OrderType.TRAILING_STOP]: t("orderEntry.orderType.trailingStop")
1912
2049
  };
1913
2050
  }, [t]);
2051
+ const mobileOptions = React3.useMemo(() => allOptions, [allOptions]);
1914
2052
  if (!isMobile) {
1915
2053
  const baseButtonClassName = "oui-flex oui-flex-1 oui-items-center oui-justify-center oui-gap-x-1 oui-rounded oui-px-3 oui-py-0.5 oui-text-xs oui-font-semibold oui-h-8";
1916
2054
  const selectedButtonClassName = ui.cn(
@@ -1942,7 +2080,24 @@ var OrderTypeSelect = (props) => {
1942
2080
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xs", children: t("orderEntry.orderType.limit") })
1943
2081
  }
1944
2082
  ),
1945
- /* @__PURE__ */ jsxRuntime.jsx(
2083
+ marketOrderDisabled && marketOrderDisabledTooltip ? /* @__PURE__ */ jsxRuntime.jsx(
2084
+ ui.Tooltip,
2085
+ {
2086
+ content: marketOrderDisabledTooltip,
2087
+ className: "oui-max-w-[275px]",
2088
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oui-inline-flex oui-flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
2089
+ "button",
2090
+ {
2091
+ type: "button",
2092
+ className: unselectedButtonClassName,
2093
+ "aria-pressed": false,
2094
+ disabled: true,
2095
+ "data-testid": "oui-testid-orderEntry-orderType-market",
2096
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xs", children: t("orderEntry.orderType.market") })
2097
+ }
2098
+ ) })
2099
+ }
2100
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1946
2101
  "button",
1947
2102
  {
1948
2103
  type: "button",
@@ -1992,14 +2147,24 @@ var OrderTypeSelect = (props) => {
1992
2147
  }
1993
2148
  );
1994
2149
  }
2150
+ const handleMobileValueChange = (value) => {
2151
+ if (marketOrderDisabled && value === types.OrderType.MARKET && marketOrderDisabledTooltip) {
2152
+ ui.modal.alert({
2153
+ title: t("common.tips"),
2154
+ message: marketOrderDisabledTooltip
2155
+ });
2156
+ return;
2157
+ }
2158
+ props.onChange(value);
2159
+ };
1995
2160
  return /* @__PURE__ */ jsxRuntime.jsx(
1996
2161
  ui.Select.options,
1997
2162
  {
1998
2163
  testid: "oui-testid-orderEntry-orderType-button",
1999
2164
  currentValue: props.type,
2000
2165
  value: props.type,
2001
- options: allOptions,
2002
- onValueChange: props.onChange,
2166
+ options: mobileOptions,
2167
+ onValueChange: handleMobileValueChange,
2003
2168
  contentProps: {
2004
2169
  className: ui.cn(
2005
2170
  "oui-orderEntry-orderTypeSelect-content",
@@ -2024,6 +2189,274 @@ var OrderTypeSelect = (props) => {
2024
2189
  }
2025
2190
  );
2026
2191
  };
2192
+ var OrderEntryContext = React3.createContext(
2193
+ {}
2194
+ );
2195
+ var useOrderEntryContext = () => {
2196
+ return React3.useContext(OrderEntryContext);
2197
+ };
2198
+ var SLIDER_MIN = 0;
2199
+ var SLIDER_MAX = 100;
2200
+ var QuantitySlider = React3.memo((props) => {
2201
+ const { canTrade, side, order_quantity, maxQty } = props;
2202
+ const [sliderValue, setSliderValue] = React3.useState(0);
2203
+ const {
2204
+ setOrderValue,
2205
+ manualSetOrderValue,
2206
+ symbolInfo,
2207
+ lastQuantityInputType
2208
+ } = useOrderEntryContext();
2209
+ const { base_dp, base_tick } = symbolInfo;
2210
+ const { t } = i18n.useTranslation();
2211
+ const color = React3.useMemo(
2212
+ () => canTrade ? side === types.OrderSide.BUY ? "buy" : "sell" : void 0,
2213
+ [side, canTrade]
2214
+ );
2215
+ const maxLabel = React3.useMemo(() => {
2216
+ return side === types.OrderSide.BUY ? t("orderEntry.maxBuy") : t("orderEntry.maxSell");
2217
+ }, [side, t]);
2218
+ const onSliderValueChange = (value) => {
2219
+ lastQuantityInputType.current = 4 /* QUANTITY_SLIDER */;
2220
+ setSliderValue(value);
2221
+ sliderToQuantity(value, true);
2222
+ };
2223
+ const sliderToQuantity = (value, isManual = false) => {
2224
+ const newQty = new utils.Decimal(value).div(SLIDER_MAX).mul(maxQty).toFixed(base_dp, utils.Decimal.ROUND_DOWN);
2225
+ if (isManual) {
2226
+ manualSetOrderValue?.(
2227
+ "order_quantity",
2228
+ hooks.utils.formatNumber(newQty, base_tick)
2229
+ );
2230
+ } else {
2231
+ setOrderValue("order_quantity", hooks.utils.formatNumber(newQty, base_tick));
2232
+ }
2233
+ };
2234
+ const onMax = () => {
2235
+ onSliderValueChange(SLIDER_MAX);
2236
+ if (sliderValue === SLIDER_MAX) {
2237
+ sliderToQuantity(SLIDER_MAX, true);
2238
+ }
2239
+ };
2240
+ React3.useEffect(() => {
2241
+ if (lastQuantityInputType.current === 4 /* QUANTITY_SLIDER */) {
2242
+ sliderToQuantity(sliderValue);
2243
+ }
2244
+ }, [maxQty]);
2245
+ React3.useEffect(() => {
2246
+ const quantityToSlider = () => {
2247
+ if (order_quantity && Number(order_quantity) !== 0 && maxQty !== 0) {
2248
+ return new utils.Decimal(Math.min(Number(order_quantity), maxQty)).div(maxQty).mul(SLIDER_MAX).todp(2, utils.Decimal.ROUND_DOWN).toNumber();
2249
+ }
2250
+ return 0;
2251
+ };
2252
+ if (lastQuantityInputType.current !== 4 /* QUANTITY_SLIDER */) {
2253
+ setSliderValue(quantityToSlider());
2254
+ }
2255
+ }, [order_quantity, maxQty]);
2256
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-quantitySlider", children: [
2257
+ /* @__PURE__ */ jsxRuntime.jsx(
2258
+ ui.Slider,
2259
+ {
2260
+ disabled: maxQty === 0 || !canTrade,
2261
+ value: [sliderValue],
2262
+ color,
2263
+ markCount: 4,
2264
+ showTip: true,
2265
+ onValueChange: (e) => {
2266
+ onSliderValueChange(e[0]);
2267
+ },
2268
+ min: SLIDER_MIN,
2269
+ max: SLIDER_MAX
2270
+ }
2271
+ ),
2272
+ /* @__PURE__ */ jsxRuntime.jsxs(
2273
+ ui.Flex,
2274
+ {
2275
+ justify: "between",
2276
+ className: "oui-quantitySlider-footer oui-pt-1 xl:oui-pt-2",
2277
+ children: [
2278
+ /* @__PURE__ */ jsxRuntime.jsx(
2279
+ ui.Text.numeral,
2280
+ {
2281
+ size: "2xs",
2282
+ color,
2283
+ dp: 2,
2284
+ padding: false,
2285
+ suffix: "%",
2286
+ children: canTrade ? sliderValue : 0
2287
+ }
2288
+ ),
2289
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { children: [
2290
+ /* @__PURE__ */ jsxRuntime.jsx(
2291
+ "button",
2292
+ {
2293
+ className: ui.textVariants({
2294
+ size: "2xs",
2295
+ className: "oui-quantitySlider-maxQty-btn oui-mr-1"
2296
+ }),
2297
+ onClick: onMax,
2298
+ "data-testid": "oui-testid-orderEntry-maxQty-value-button",
2299
+ children: maxLabel
2300
+ }
2301
+ ),
2302
+ /* @__PURE__ */ jsxRuntime.jsx(
2303
+ ui.Text.numeral,
2304
+ {
2305
+ size: "2xs",
2306
+ color,
2307
+ dp: base_dp,
2308
+ padding: false,
2309
+ className: "oui-quantitySlider-maxQty-value",
2310
+ "data-testid": "oui-testid-orderEntry-maxQty-value",
2311
+ children: canTrade ? maxQty : 0
2312
+ }
2313
+ )
2314
+ ] })
2315
+ ]
2316
+ }
2317
+ )
2318
+ ] });
2319
+ });
2320
+ QuantitySlider.displayName = "QuantitySlider";
2321
+ var OrderEntryTypeTabsInjectabled = ui.injectable(
2322
+ (props) => {
2323
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2324
+ OrderTypeSelect,
2325
+ {
2326
+ type: props.type,
2327
+ side: props.side,
2328
+ canTrade: props.canTrade,
2329
+ onChange: props.onChange,
2330
+ marketOrderDisabled: props.marketOrderDisabled,
2331
+ marketOrderDisabledTooltip: props.marketOrderDisabledTooltip
2332
+ }
2333
+ ) });
2334
+ },
2335
+ "Trading.OrderEntry.TypeTabs"
2336
+ );
2337
+ var OrderEntryBuySellSwitchInjectabled = ui.injectable(
2338
+ (props) => {
2339
+ const { t } = i18n.useTranslation();
2340
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2341
+ "div",
2342
+ {
2343
+ className: ui.cn(
2344
+ "oui-orderEntry-side",
2345
+ "oui-grid oui-w-full oui-flex-1 oui-gap-x-2 lg:oui-flex lg:oui-gap-x-[6px]",
2346
+ "oui-grid-cols-2"
2347
+ ),
2348
+ children: [
2349
+ /* @__PURE__ */ jsxRuntime.jsx(
2350
+ ui.Button,
2351
+ {
2352
+ onClick: () => {
2353
+ props.onSideChange(types.OrderSide.BUY);
2354
+ },
2355
+ size: "md",
2356
+ fullWidth: true,
2357
+ "data-type": types.OrderSide.BUY,
2358
+ className: ui.cn(
2359
+ "oui-orderEntry-side-buy-btn",
2360
+ props.side === types.OrderSide.BUY && props.canTrade ? "oui-bg-success-darken hover:oui-bg-success-darken/80 active:oui-bg-success-darken/80" : "oui-bg-base-7 oui-text-base-contrast-36 hover:oui-bg-base-6 active:oui-bg-base-6"
2361
+ ),
2362
+ "data-testid": "oui-testid-orderEntry-side-buy-button",
2363
+ children: t("common.buy")
2364
+ }
2365
+ ),
2366
+ /* @__PURE__ */ jsxRuntime.jsx(
2367
+ ui.Button,
2368
+ {
2369
+ onClick: () => {
2370
+ props.onSideChange(types.OrderSide.SELL);
2371
+ },
2372
+ "data-type": types.OrderSide.SELL,
2373
+ fullWidth: true,
2374
+ size: "md",
2375
+ className: ui.cn(
2376
+ "oui-orderEntry-side-sell-btn",
2377
+ props.side === types.OrderSide.SELL && props.canTrade ? "oui-bg-danger-darken hover:oui-bg-danger-darken/80 active:oui-bg-danger-darken/80" : "oui-bg-base-7 oui-text-base-contrast-36 hover:oui-bg-base-6 active:oui-bg-base-6"
2378
+ ),
2379
+ "data-testid": "oui-testid-orderEntry-side-sell-button",
2380
+ children: t("common.sell")
2381
+ }
2382
+ )
2383
+ ]
2384
+ }
2385
+ );
2386
+ },
2387
+ "Trading.OrderEntry.BuySellSwitch"
2388
+ );
2389
+ var OrderEntryAvailableInjectabled = ui.injectable(
2390
+ (props) => {
2391
+ return /* @__PURE__ */ jsxRuntime.jsx(
2392
+ Available,
2393
+ {
2394
+ currentLtv: props.currentLtv,
2395
+ canTrade: props.canTrade,
2396
+ quote: props.quote,
2397
+ freeCollateral: props.freeCollateral,
2398
+ marginMode: props.marginMode
2399
+ }
2400
+ );
2401
+ },
2402
+ "Trading.OrderEntry.Available"
2403
+ );
2404
+ var OrderEntryQuantitySliderInjectabled = ui.injectable(
2405
+ (props) => {
2406
+ return /* @__PURE__ */ jsxRuntime.jsx(
2407
+ QuantitySlider,
2408
+ {
2409
+ canTrade: props.canTrade,
2410
+ side: props.side,
2411
+ order_quantity: props.order_quantity,
2412
+ maxQty: props.maxQty
2413
+ }
2414
+ );
2415
+ },
2416
+ "Trading.OrderEntry.QuantitySlider"
2417
+ );
2418
+ var OrderEntrySubmitSectionInjectabled = ui.injectable(
2419
+ (props) => {
2420
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2421
+ /* @__PURE__ */ jsxRuntime.jsx(
2422
+ ui.ThrottledButton,
2423
+ {
2424
+ fullWidth: true,
2425
+ id: "order-entry-submit-button",
2426
+ "data-type": types.OrderSide.BUY,
2427
+ className: ui.cn(
2428
+ "oui-orderEntry-submit-btn",
2429
+ props.side === types.OrderSide.BUY ? "orderly-order-entry-submit-button-buy oui-bg-success-darken hover:oui-bg-success-darken/80 active:oui-bg-success-darken/80" : "orderly-order-entry-submit-button-sell oui-bg-danger-darken hover:oui-bg-danger-darken/80 active:oui-bg-danger-darken/80"
2430
+ ),
2431
+ onClick: props.onSubmit,
2432
+ loading: props.isMutating,
2433
+ disabled: !props.canTrade,
2434
+ children: props.buttonLabel
2435
+ }
2436
+ ),
2437
+ /* @__PURE__ */ jsxRuntime.jsx(
2438
+ AssetInfo,
2439
+ {
2440
+ canTrade: props.assetInfo.canTrade,
2441
+ quote: props.assetInfo.quote,
2442
+ estLiqPrice: props.assetInfo.estLiqPrice,
2443
+ estLiqPriceDistance: props.assetInfo.estLiqPriceDistance,
2444
+ estLeverage: props.assetInfo.estLeverage,
2445
+ currentLeverage: props.assetInfo.currentLeverage,
2446
+ slippage: props.assetInfo.slippage,
2447
+ dp: props.assetInfo.dp,
2448
+ setSlippage: props.assetInfo.setSlippage,
2449
+ estSlippage: props.assetInfo.estSlippage,
2450
+ orderType: props.assetInfo.orderType,
2451
+ disableFeatures: props.assetInfo.disableFeatures,
2452
+ symbol: props.assetInfo.symbol,
2453
+ side: props.assetInfo.side
2454
+ }
2455
+ )
2456
+ ] });
2457
+ },
2458
+ "Trading.OrderEntry.SubmitSection"
2459
+ );
2027
2460
  var MarginModeSwitch = (props) => {
2028
2461
  const { t } = i18n.useTranslation();
2029
2462
  const handleSelect = (mode) => {
@@ -2102,10 +2535,11 @@ var MarginModeSwitch = (props) => {
2102
2535
  {
2103
2536
  className: "oui-tracking-[0.03em]",
2104
2537
  rule: "symbol",
2105
- formatString: "base-type",
2538
+ formatString: "base",
2106
2539
  size: "base",
2107
2540
  weight: "semibold",
2108
2541
  intensity: 98,
2542
+ suffix: /* @__PURE__ */ jsxRuntime.jsx(SymbolBadge, { symbol: props.symbol }),
2109
2543
  children: props.symbol
2110
2544
  }
2111
2545
  )
@@ -2117,7 +2551,8 @@ var MarginModeSwitch = (props) => {
2117
2551
  mode: types.MarginMode.CROSS,
2118
2552
  selected: props.selectedMarginMode === types.MarginMode.CROSS,
2119
2553
  isCurrent: props.currentMarginMode === types.MarginMode.CROSS,
2120
- onClick: () => handleSelect(types.MarginMode.CROSS)
2554
+ onClick: () => handleSelect(types.MarginMode.CROSS),
2555
+ disabled: props.isPermissionlessListing
2121
2556
  }
2122
2557
  ),
2123
2558
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2180,9 +2615,11 @@ var OptionCard = (props) => {
2180
2615
  "oui-relative oui-w-full oui-rounded-md oui-p-2",
2181
2616
  "oui-bg-base-6",
2182
2617
  "oui-text-left",
2183
- props.selected ? "oui-border oui-border-[#38e2fe]" : "oui-border oui-border-transparent hover:oui-border-line-12"
2618
+ 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"
2184
2619
  ),
2185
- onClick: props.onClick,
2620
+ onClick: props.disabled ? void 0 : props.onClick,
2621
+ disabled: props.disabled,
2622
+ "aria-disabled": props.disabled,
2186
2623
  "data-testid": `oui-testid-marginModeSwitch-option-${props.mode}`,
2187
2624
  children: [
2188
2625
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", gap: 2, itemAlign: "start", className: "oui-w-full", children: [
@@ -2215,7 +2652,11 @@ var useMarginModeSwitchScript = (options2) => {
2215
2652
  const { symbol, close } = options2;
2216
2653
  const { isMobile } = ui.useScreen();
2217
2654
  const { t } = i18n.useTranslation();
2218
- const { marginMode: currentMarginMode, update } = hooks.useMarginModeBySymbol(symbol);
2655
+ const {
2656
+ marginMode: currentMarginMode,
2657
+ update,
2658
+ isPermissionlessListing
2659
+ } = hooks.useMarginModeBySymbol(symbol);
2219
2660
  const [selectedMarginMode, setSelectedMarginMode] = React3.useState(currentMarginMode);
2220
2661
  React3.useEffect(() => {
2221
2662
  setSelectedMarginMode(currentMarginMode);
@@ -2253,11 +2694,13 @@ var useMarginModeSwitchScript = (options2) => {
2253
2694
  setSelectedMarginMode,
2254
2695
  applyMarginMode,
2255
2696
  close,
2256
- onSelect
2697
+ onSelect,
2698
+ isPermissionlessListing
2257
2699
  };
2258
2700
  };
2259
2701
  var useMarginModeSettingsScript = (options2) => {
2260
2702
  const { isMobile } = ui.useScreen();
2703
+ const { t } = i18n.useTranslation();
2261
2704
  const [markets] = hooks.useMarkets(hooks.MarketsType.ALL);
2262
2705
  const items = React3.useMemo(() => {
2263
2706
  if (!markets || markets.length === 0) {
@@ -2266,10 +2709,20 @@ var useMarginModeSettingsScript = (options2) => {
2266
2709
  return markets.map((market) => ({
2267
2710
  key: market.symbol,
2268
2711
  // Original symbol: "PERP_BTC_USDC"
2269
- symbol: utils.formatSymbol(market.symbol, "base-type")
2712
+ symbol: utils.formatSymbol(market.symbol, "base"),
2270
2713
  // Formatted: "BTC-PERP"
2714
+ brokerId: market.broker_id
2271
2715
  }));
2272
2716
  }, [markets]);
2717
+ const brokerLockedKeys = React3.useMemo(() => {
2718
+ const locked = /* @__PURE__ */ new Set();
2719
+ for (const item of items) {
2720
+ if (item.brokerId) {
2721
+ locked.add(item.key);
2722
+ }
2723
+ }
2724
+ return locked;
2725
+ }, [items]);
2273
2726
  const [searchKeyword, setSearchKeyword] = React3.useState("");
2274
2727
  const [selectedKeys, setSelectedKeys] = React3.useState(
2275
2728
  () => /* @__PURE__ */ new Set()
@@ -2290,11 +2743,15 @@ var useMarginModeSettingsScript = (options2) => {
2290
2743
  const itemMarginModes = React3.useMemo(() => {
2291
2744
  const result = {};
2292
2745
  for (const item of items) {
2746
+ if (brokerLockedKeys.has(item.key)) {
2747
+ result[item.key] = types.MarginMode.ISOLATED;
2748
+ continue;
2749
+ }
2293
2750
  const marginMode = marginModes[item.key];
2294
2751
  result[item.key] = marginMode ?? types.MarginMode.CROSS;
2295
2752
  }
2296
2753
  return result;
2297
- }, [items, marginModes]);
2754
+ }, [brokerLockedKeys, items, marginModes]);
2298
2755
  const filteredItems = React3.useMemo(() => {
2299
2756
  const keyword = searchKeyword.trim().toLowerCase();
2300
2757
  if (!keyword) return items;
@@ -2330,17 +2787,21 @@ var useMarginModeSettingsScript = (options2) => {
2330
2787
  const onSearchChange = React3.useCallback((keyword) => {
2331
2788
  setSearchKeyword(keyword);
2332
2789
  }, []);
2333
- const onToggleItem = React3.useCallback((key) => {
2334
- setSelectedKeys((prev) => {
2335
- const next = new Set(prev);
2336
- if (next.has(key)) {
2337
- next.delete(key);
2338
- } else {
2339
- next.add(key);
2340
- }
2341
- return next;
2342
- });
2343
- }, []);
2790
+ const onToggleItem = React3.useCallback(
2791
+ (key) => {
2792
+ if (brokerLockedKeys.has(key)) return;
2793
+ setSelectedKeys((prev) => {
2794
+ const next = new Set(prev);
2795
+ if (next.has(key)) {
2796
+ next.delete(key);
2797
+ } else {
2798
+ next.add(key);
2799
+ }
2800
+ return next;
2801
+ });
2802
+ },
2803
+ [brokerLockedKeys]
2804
+ );
2344
2805
  const onToggleSelectAll = React3.useCallback(() => {
2345
2806
  setSelectedKeys((prev) => {
2346
2807
  const next = new Set(prev);
@@ -2351,31 +2812,39 @@ var useMarginModeSettingsScript = (options2) => {
2351
2812
  return next;
2352
2813
  }
2353
2814
  for (const item of filteredItems) {
2815
+ if (brokerLockedKeys.has(item.key)) continue;
2354
2816
  next.add(item.key);
2355
2817
  }
2356
2818
  return next;
2357
2819
  });
2358
- }, [filteredItems, isSelectAll]);
2820
+ }, [brokerLockedKeys, filteredItems, isSelectAll]);
2359
2821
  const onSetMarginMode = React3.useCallback(
2360
2822
  async (mode) => {
2361
2823
  if (selectedKeys.size === 0) return;
2824
+ const editableSymbolList = Array.from(selectedKeys).filter(
2825
+ (key) => !brokerLockedKeys.has(key)
2826
+ );
2827
+ if (editableSymbolList.length === 0) {
2828
+ ui.toast.error(t("marginMode.noEditableSymbolsSelected"));
2829
+ return;
2830
+ }
2362
2831
  setIsOperationLoading(true);
2363
2832
  try {
2364
2833
  const payload = {
2365
- symbol_list: Array.from(selectedKeys),
2834
+ symbol_list: editableSymbolList,
2366
2835
  default_margin_mode: mode
2367
2836
  };
2368
2837
  await updateMarginMode(payload);
2369
- ui.toast.success("Updated successfully");
2838
+ ui.toast.success(t("marginMode.updatedSuccessfully"));
2370
2839
  } catch (error) {
2371
2840
  ui.toast.error(
2372
- error instanceof Error ? error.message : "Failed to update margin mode"
2841
+ error instanceof Error ? error.message : t("marginMode.failedToUpdateMarginMode")
2373
2842
  );
2374
2843
  } finally {
2375
2844
  setIsOperationLoading(false);
2376
2845
  }
2377
2846
  },
2378
- [selectedKeys, updateMarginMode]
2847
+ [brokerLockedKeys, selectedKeys, updateMarginMode]
2379
2848
  );
2380
2849
  const isLoading = isDataLoading || isMarginModesLoading || isOperationLoading || isSettingMarginMode;
2381
2850
  return {
@@ -2523,7 +2992,8 @@ var MarginModeSettings = (props) => {
2523
2992
  item,
2524
2993
  checked: props.selectedKeys.has(item.key),
2525
2994
  marginMode: props.itemMarginModes[item.key] ?? types.MarginMode.CROSS,
2526
- onToggle: props.onToggleItem
2995
+ onToggle: props.onToggleItem,
2996
+ disabled: !!item.brokerId
2527
2997
  },
2528
2998
  item.key
2529
2999
  ))
@@ -2626,13 +3096,15 @@ var MarginModeSettings = (props) => {
2626
3096
  var SymbolRow = (props) => {
2627
3097
  const { t } = i18n.useTranslation();
2628
3098
  const handleCheckedChange = React3.useCallback(() => {
3099
+ if (props.disabled) return;
2629
3100
  props.onToggle(props.item.key);
2630
3101
  }, [props]);
2631
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { itemAlign: "center", className: "oui-w-full", children: /* @__PURE__ */ jsxRuntime.jsxs(
3102
+ const row = /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { itemAlign: "center", className: "oui-w-full", children: /* @__PURE__ */ jsxRuntime.jsxs(
2632
3103
  "label",
2633
3104
  {
2634
3105
  className: ui.cn(
2635
- "oui-flex oui-items-center oui-gap-2 oui-flex-1 oui-cursor-pointer oui-select-none oui-w-full"
3106
+ "oui-flex oui-items-center oui-gap-2 oui-flex-1 oui-cursor-pointer oui-select-none oui-w-full",
3107
+ props.disabled ? "oui-cursor-not-allowed oui-opacity-50" : ""
2636
3108
  ),
2637
3109
  "data-testid": `oui-testid-marginModeSettings-item-${props.item.key}`,
2638
3110
  children: [
@@ -2642,10 +3114,12 @@ var SymbolRow = (props) => {
2642
3114
  color: "white",
2643
3115
  checked: props.checked,
2644
3116
  onCheckedChange: handleCheckedChange,
2645
- "aria-label": props.item.symbol
3117
+ "aria-label": props.item.symbol,
3118
+ disabled: props.disabled
2646
3119
  }
2647
3120
  ),
2648
3121
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "oui-text-sm oui-font-semibold oui-text-base-contrast-80", children: props.item.symbol }),
3122
+ /* @__PURE__ */ jsxRuntime.jsx(SymbolBadge, { symbol: props.item.key }),
2649
3123
  /* @__PURE__ */ jsxRuntime.jsx(
2650
3124
  "span",
2651
3125
  {
@@ -2661,6 +3135,17 @@ var SymbolRow = (props) => {
2661
3135
  ]
2662
3136
  }
2663
3137
  ) });
3138
+ if (props.disabled) {
3139
+ return /* @__PURE__ */ jsxRuntime.jsx(
3140
+ ui.Tooltip,
3141
+ {
3142
+ content: t("marginMode.disabledSymbolTooltip"),
3143
+ className: "oui-max-w-[280px] oui-text-2xs oui-text-base-contrast-80",
3144
+ children: row
3145
+ }
3146
+ );
3147
+ }
3148
+ return row;
2664
3149
  };
2665
3150
  var SearchGlyph = (props) => {
2666
3151
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2832,7 +3317,6 @@ var LeverageBadge = (props) => {
2832
3317
  };
2833
3318
  function OrderEntryHeader(props) {
2834
3319
  const { canTrade, side, order_type, setOrderValue } = props;
2835
- const { t } = i18n.useTranslation();
2836
3320
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2837
3321
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2838
3322
  LeverageBadge,
@@ -2844,71 +3328,31 @@ function OrderEntryHeader(props) {
2844
3328
  disabled: !props.canTrade
2845
3329
  }
2846
3330
  ) }),
2847
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2848
- OrderTypeSelect,
3331
+ /* @__PURE__ */ jsxRuntime.jsx(
3332
+ OrderEntryTypeTabsInjectabled,
2849
3333
  {
2850
3334
  type: order_type,
2851
3335
  side,
2852
3336
  canTrade,
2853
3337
  onChange: (type) => {
2854
3338
  setOrderValue("order_type", type);
2855
- }
3339
+ },
3340
+ marketOrderDisabled: props.marketOrderDisabled,
3341
+ marketOrderDisabledTooltip: props.marketOrderDisabledTooltip
2856
3342
  }
2857
- ) }),
2858
- /* @__PURE__ */ jsxRuntime.jsxs(
2859
- "div",
3343
+ ),
3344
+ /* @__PURE__ */ jsxRuntime.jsx(
3345
+ OrderEntryBuySellSwitchInjectabled,
2860
3346
  {
2861
- className: ui.cn(
2862
- "oui-orderEntry-side",
2863
- "oui-grid oui-w-full oui-flex-1 oui-gap-x-2 lg:oui-flex lg:oui-gap-x-[6px]",
2864
- "oui-grid-cols-2"
2865
- ),
2866
- children: [
2867
- /* @__PURE__ */ jsxRuntime.jsx(
2868
- ui.Button,
2869
- {
2870
- onClick: () => {
2871
- props.setOrderValue("side", types.OrderSide.BUY);
2872
- },
2873
- size: "md",
2874
- fullWidth: true,
2875
- "data-type": types.OrderSide.BUY,
2876
- className: ui.cn(
2877
- "oui-orderEntry-side-buy-btn",
2878
- side === types.OrderSide.BUY && canTrade ? "oui-bg-success-darken hover:oui-bg-success-darken/80 active:oui-bg-success-darken/80" : "oui-bg-base-7 oui-text-base-contrast-36 hover:oui-bg-base-6 active:oui-bg-base-6"
2879
- ),
2880
- "data-testid": "oui-testid-orderEntry-side-buy-button",
2881
- children: t("common.buy")
2882
- }
2883
- ),
2884
- /* @__PURE__ */ jsxRuntime.jsx(
2885
- ui.Button,
2886
- {
2887
- onClick: () => {
2888
- props.setOrderValue("side", types.OrderSide.SELL);
2889
- },
2890
- "data-type": types.OrderSide.SELL,
2891
- fullWidth: true,
2892
- size: "md",
2893
- className: ui.cn(
2894
- "oui-orderEntry-side-sell-btn",
2895
- side === types.OrderSide.SELL && props.canTrade ? "oui-bg-danger-darken hover:oui-bg-danger-darken/80 active:oui-bg-danger-darken/80" : "oui-bg-base-7 oui-text-base-contrast-36 hover:oui-bg-base-6 active:oui-bg-base-6"
2896
- ),
2897
- "data-testid": "oui-testid-orderEntry-side-sell-button",
2898
- children: t("common.sell")
2899
- }
2900
- )
2901
- ]
3347
+ side,
3348
+ canTrade,
3349
+ onSideChange: (nextSide) => {
3350
+ props.setOrderValue("side", nextSide);
3351
+ }
2902
3352
  }
2903
3353
  )
2904
3354
  ] });
2905
3355
  }
2906
- var OrderEntryContext = React3.createContext(
2907
- {}
2908
- );
2909
- var useOrderEntryContext = () => {
2910
- return React3.useContext(OrderEntryContext);
2911
- };
2912
3356
  var OrderEntryProvider = (props) => {
2913
3357
  const {
2914
3358
  errorMsgVisible,
@@ -2917,6 +3361,7 @@ var OrderEntryProvider = (props) => {
2917
3361
  onBlur,
2918
3362
  getErrorMsg,
2919
3363
  setOrderValue,
3364
+ manualSetOrderValue,
2920
3365
  setOrderValues,
2921
3366
  currentFocusInput,
2922
3367
  errors,
@@ -2935,6 +3380,7 @@ var OrderEntryProvider = (props) => {
2935
3380
  onBlur,
2936
3381
  getErrorMsg,
2937
3382
  setOrderValue,
3383
+ manualSetOrderValue,
2938
3384
  setOrderValues,
2939
3385
  currentFocusInput,
2940
3386
  errors,
@@ -2953,6 +3399,7 @@ var OrderEntryProvider = (props) => {
2953
3399
  onBlur,
2954
3400
  getErrorMsg,
2955
3401
  setOrderValue,
3402
+ manualSetOrderValue,
2956
3403
  setOrderValues,
2957
3404
  currentFocusInput,
2958
3405
  errors,
@@ -4376,116 +4823,6 @@ function OrderInput(props) {
4376
4823
  )
4377
4824
  ] });
4378
4825
  }
4379
- var SLIDER_MIN = 0;
4380
- var SLIDER_MAX = 100;
4381
- var QuantitySlider = React3.memo((props) => {
4382
- const { canTrade, side, order_quantity, maxQty } = props;
4383
- const [sliderValue, setSliderValue] = React3.useState(0);
4384
- const { setOrderValue, symbolInfo, lastQuantityInputType } = useOrderEntryContext();
4385
- const { base_dp, base_tick } = symbolInfo;
4386
- const { t } = i18n.useTranslation();
4387
- const color = React3.useMemo(
4388
- () => canTrade ? side === types.OrderSide.BUY ? "buy" : "sell" : void 0,
4389
- [side, canTrade]
4390
- );
4391
- const maxLabel = React3.useMemo(() => {
4392
- return side === types.OrderSide.BUY ? t("orderEntry.maxBuy") : t("orderEntry.maxSell");
4393
- }, [side, t]);
4394
- const onSliderValueChange = (value) => {
4395
- lastQuantityInputType.current = 4 /* QUANTITY_SLIDER */;
4396
- setSliderValue(value);
4397
- };
4398
- const sliderToQuantity = (value) => {
4399
- const newQty = new utils.Decimal(value).div(SLIDER_MAX).mul(maxQty).toFixed(base_dp, utils.Decimal.ROUND_DOWN);
4400
- setOrderValue("order_quantity", hooks.utils.formatNumber(newQty, base_tick));
4401
- };
4402
- const onMax = () => {
4403
- onSliderValueChange(SLIDER_MAX);
4404
- if (sliderValue === SLIDER_MAX) {
4405
- sliderToQuantity(SLIDER_MAX);
4406
- }
4407
- };
4408
- React3.useEffect(() => {
4409
- if (lastQuantityInputType.current === 4 /* QUANTITY_SLIDER */) {
4410
- sliderToQuantity(sliderValue);
4411
- }
4412
- }, [sliderValue, maxQty]);
4413
- React3.useEffect(() => {
4414
- const quantityToSlider = () => {
4415
- if (order_quantity && Number(order_quantity) !== 0 && maxQty !== 0) {
4416
- return new utils.Decimal(Math.min(Number(order_quantity), maxQty)).div(maxQty).mul(SLIDER_MAX).todp(2, utils.Decimal.ROUND_DOWN).toNumber();
4417
- }
4418
- return 0;
4419
- };
4420
- if (lastQuantityInputType.current !== 4 /* QUANTITY_SLIDER */) {
4421
- setSliderValue(quantityToSlider());
4422
- }
4423
- }, [order_quantity, maxQty]);
4424
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-orderEntry-quantitySlider", children: [
4425
- /* @__PURE__ */ jsxRuntime.jsx(
4426
- ui.Slider,
4427
- {
4428
- disabled: maxQty === 0 || !canTrade,
4429
- value: [sliderValue],
4430
- color,
4431
- markCount: 4,
4432
- showTip: true,
4433
- onValueChange: (e) => {
4434
- onSliderValueChange(e[0]);
4435
- },
4436
- min: SLIDER_MIN,
4437
- max: SLIDER_MAX
4438
- }
4439
- ),
4440
- /* @__PURE__ */ jsxRuntime.jsxs(
4441
- ui.Flex,
4442
- {
4443
- justify: "between",
4444
- className: "oui-quantitySlider-footer oui-pt-1 xl:oui-pt-2",
4445
- children: [
4446
- /* @__PURE__ */ jsxRuntime.jsx(
4447
- ui.Text.numeral,
4448
- {
4449
- size: "2xs",
4450
- color,
4451
- dp: 2,
4452
- padding: false,
4453
- suffix: "%",
4454
- children: canTrade ? sliderValue : 0
4455
- }
4456
- ),
4457
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { children: [
4458
- /* @__PURE__ */ jsxRuntime.jsx(
4459
- "button",
4460
- {
4461
- className: ui.textVariants({
4462
- size: "2xs",
4463
- className: "oui-quantitySlider-maxQty-btn oui-mr-1"
4464
- }),
4465
- onClick: onMax,
4466
- "data-testid": "oui-testid-orderEntry-maxQty-value-button",
4467
- children: maxLabel
4468
- }
4469
- ),
4470
- /* @__PURE__ */ jsxRuntime.jsx(
4471
- ui.Text.numeral,
4472
- {
4473
- size: "2xs",
4474
- color,
4475
- dp: base_dp,
4476
- padding: false,
4477
- className: "oui-quantitySlider-maxQty-value",
4478
- "data-testid": "oui-testid-orderEntry-maxQty-value",
4479
- children: canTrade ? maxQty : 0
4480
- }
4481
- )
4482
- ] })
4483
- ]
4484
- }
4485
- )
4486
- ] });
4487
- });
4488
- QuantitySlider.displayName = "QuantitySlider";
4489
4826
  var ReduceOnlySwitch = ({
4490
4827
  checked,
4491
4828
  onCheckedChange,
@@ -4529,10 +4866,19 @@ var usePnlInputContext = () => {
4529
4866
  };
4530
4867
 
4531
4868
  // src/components/pnlInput/useBuilder.script.ts
4869
+ function normalizeSlPnlForStore(raw) {
4870
+ const v = `${raw}`.replace(/,/g, "").trim();
4871
+ if (v === "" || v === "-") return v;
4872
+ const withoutTrailingDot = v.replace(/\.$/, "");
4873
+ const num = Number(withoutTrailingDot);
4874
+ if (!isNaN(num) && num === 0) return "0";
4875
+ if (v.startsWith("-")) return v;
4876
+ return `-${v}`;
4877
+ }
4532
4878
  var usePNLInputBuilder = (props) => {
4533
4879
  const { type, values, quote_dp } = props;
4534
4880
  const { t } = i18n.useTranslation();
4535
- const [focus, setFocus] = React3.useState(true);
4881
+ const [, setFocus] = React3.useState(true);
4536
4882
  const { mode, setMode, tipsEle } = usePnlInputContext();
4537
4883
  const [tipVisible, setTipVisible] = React3.useState(false);
4538
4884
  const [isFocused, setIsFocused] = React3.useState(false);
@@ -4542,10 +4888,14 @@ var usePNLInputBuilder = (props) => {
4542
4888
  return `${type.toLowerCase()}_offset`;
4543
4889
  case "Offset%" /* PERCENTAGE */:
4544
4890
  return `${type.toLowerCase()}_offset_percentage`;
4891
+ case "OffsetFromMark" /* OFFSET_FROM_MARK */:
4892
+ return `${type.toLowerCase()}_offset_from_mark`;
4893
+ case "PercentageFromMark" /* PERCENTAGE_FROM_MARK */:
4894
+ return `${type.toLowerCase()}_offset_percentage_from_mark`;
4545
4895
  default:
4546
4896
  return `${type.toLowerCase()}_pnl`;
4547
4897
  }
4548
- }, [mode]);
4898
+ }, [mode, type]);
4549
4899
  const [innerValue, setInnerValue] = React3.useState(
4550
4900
  values[mode]
4551
4901
  );
@@ -4568,23 +4918,39 @@ var usePNLInputBuilder = (props) => {
4568
4918
  testId: `${"Offset" /* OFFSET */}_mneu_item`
4569
4919
  },
4570
4920
  {
4571
- label: `${t("tpsl.offset")}%`,
4921
+ label: t("tpsl.offsetPercent"),
4572
4922
  value: "Offset%" /* PERCENTAGE */,
4573
4923
  testId: `${"Offset%" /* PERCENTAGE */}_menu_item`
4924
+ },
4925
+ {
4926
+ // @ts-ignore
4927
+ label: t("tpsl.offsetMark"),
4928
+ value: "OffsetFromMark" /* OFFSET_FROM_MARK */,
4929
+ testId: `${"OffsetFromMark" /* OFFSET_FROM_MARK */}_menu_item`
4930
+ },
4931
+ {
4932
+ // @ts-ignore
4933
+ label: t("tpsl.offsetPercentMark"),
4934
+ value: "PercentageFromMark" /* PERCENTAGE_FROM_MARK */,
4935
+ testId: `${"PercentageFromMark" /* PERCENTAGE_FROM_MARK */}_menu_item`
4574
4936
  }
4575
4937
  ];
4576
4938
  }, [t]);
4577
4939
  const modeLabelMap = React3.useMemo(() => {
4578
4940
  return {
4579
4941
  ["PnL" /* PnL */]: t("tpsl.pnl"),
4580
- ["Offset" /* OFFSET */]: t("tpsl.offset"),
4581
- ["Offset%" /* PERCENTAGE */]: `${t("tpsl.offset")}%`
4942
+ ["Offset" /* OFFSET */]: t("tpsl.offsetHolder"),
4943
+ ["Offset%" /* PERCENTAGE */]: `${t("tpsl.offsetHolder")}`,
4944
+ // Extend locale keys; not yet in LocaleMessages typings
4945
+ ["OffsetFromMark" /* OFFSET_FROM_MARK */]: t("tpsl.offsetHolder"),
4946
+ ["PercentageFromMark" /* PERCENTAGE_FROM_MARK */]: t("tpsl.offsetHolder")
4582
4947
  };
4583
4948
  }, [t]);
4584
4949
  const percentageSuffix = React3.useRef("");
4585
4950
  const onValueChange = (value) => {
4586
4951
  setInnerValue(value);
4587
- props.onChange(key, value);
4952
+ const outgoing = key === "sl_pnl" ? normalizeSlPnlForStore(value) : value;
4953
+ props.onChange(key, outgoing);
4588
4954
  };
4589
4955
  const onFocus = () => {
4590
4956
  setTipVisible(true);
@@ -4593,27 +4959,29 @@ var usePNLInputBuilder = (props) => {
4593
4959
  const onBlur = () => {
4594
4960
  setTipVisible(false);
4595
4961
  setIsFocused(false);
4596
- props.onChange(key, innerValue);
4962
+ const outgoing = key === "sl_pnl" ? normalizeSlPnlForStore(innerValue) : innerValue;
4963
+ props.onChange(key, outgoing);
4597
4964
  };
4598
4965
  const formatter = (options2) => {
4599
4966
  const { dp = 2 } = options2;
4600
4967
  return {
4601
4968
  onRenderBefore: (value, options3) => {
4602
4969
  value = `${value}`;
4603
- if (focus) {
4604
- if (type === "SL" && mode === "PnL" /* PnL */) {
4605
- value = value.startsWith("-") ? value : "-" + value;
4606
- }
4970
+ if (type === "SL" && mode === "PnL" /* PnL */) {
4971
+ value = value.startsWith("-") ? value : "-" + value;
4607
4972
  }
4608
4973
  if (value === "" || value === "-") return "";
4609
- if (mode === "Offset%" /* PERCENTAGE */) {
4610
- return `${new utils.Decimal(
4611
- value.replace(
4612
- new RegExp(percentageSuffix.current.replace(".", "\\.") + "$"),
4613
- ""
4614
- )
4615
- ).mul(100).todp(2, 4).toString()}${percentageSuffix.current}`;
4616
- } else if (mode === "Offset" /* OFFSET */) {
4974
+ if (mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */) {
4975
+ let normalized = value.replace(
4976
+ new RegExp(percentageSuffix.current.replace(".", "\\.") + "$"),
4977
+ ""
4978
+ ).replace(/,/g, "");
4979
+ normalized = normalized.replace(/\.$/, "");
4980
+ if (isNaN(Number(normalized)) || normalized === "" || normalized === "-") {
4981
+ return value;
4982
+ }
4983
+ return `${new utils.Decimal(normalized).mul(100).todp(2, 4).toString()}${percentageSuffix.current}`;
4984
+ } else if (mode === "Offset" /* OFFSET */ || mode === "OffsetFromMark" /* OFFSET_FROM_MARK */) {
4617
4985
  value = utils.todpIfNeed(value, dp);
4618
4986
  } else ;
4619
4987
  return `${value}`;
@@ -4622,7 +4990,7 @@ var usePNLInputBuilder = (props) => {
4622
4990
  if (/^\-?0{2,}$/.test(value)) {
4623
4991
  return "0";
4624
4992
  }
4625
- if (mode === "Offset%" /* PERCENTAGE */) {
4993
+ if (mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */) {
4626
4994
  if (value !== "") {
4627
4995
  value = utils.todpIfNeed(value, 2);
4628
4996
  const endStr = value.match(/\.0{0,2}$/);
@@ -4631,10 +4999,13 @@ var usePNLInputBuilder = (props) => {
4631
4999
  } else {
4632
5000
  percentageSuffix.current = "";
4633
5001
  }
5002
+ if (isNaN(Number(value))) {
5003
+ return value;
5004
+ }
4634
5005
  value = new utils.Decimal(value).div(100).toString();
4635
5006
  value = `${value}${percentageSuffix.current}`;
4636
5007
  }
4637
- } else if (mode === "PnL" /* PnL */ && type === "SL" && focus) {
5008
+ } else if (mode === "PnL" /* PnL */ && type === "SL") {
4638
5009
  value = value.startsWith("-") ? value : "-" + value;
4639
5010
  } else {
4640
5011
  value = utils.todpIfNeed(value, dp);
@@ -4678,21 +5049,28 @@ var PNLInput = (props) => {
4678
5049
  setFocus
4679
5050
  } = props;
4680
5051
  const [prefix, setPrefix] = React3.useState(mode);
5052
+ const isPercentageMode = mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */;
4681
5053
  const [placeholder, setPlaceholder] = React3.useState(
4682
- mode === "Offset%" /* PERCENTAGE */ ? "%" : quote
5054
+ isPercentageMode ? "%" : quote
4683
5055
  );
4684
5056
  React3.useEffect(() => {
4685
5057
  setPrefix(mode);
4686
- setPlaceholder(mode === "Offset%" /* PERCENTAGE */ ? "%" : quote);
4687
- }, [mode]);
5058
+ setPlaceholder(isPercentageMode ? "%" : quote);
5059
+ }, [mode, isPercentageMode, quote]);
4688
5060
  React3.useEffect(() => {
4689
5061
  setPrefix(!!value ? "" : mode);
4690
5062
  }, [value]);
4691
- const id = React3.useMemo(() => `${type.toLowerCase()}_${mode.toLowerCase()}`, []);
5063
+ const id = React3.useMemo(
5064
+ () => `${type.toLowerCase()}_${mode.toLowerCase()}`,
5065
+ [type, mode]
5066
+ );
5067
+ const prefixLabel = prefix === "" ? "" : String(
5068
+ modeLabelMap[prefix] ?? prefix ?? ""
5069
+ );
4692
5070
  return /* @__PURE__ */ jsxRuntime.jsx(
4693
5071
  ui.Input.tooltip,
4694
5072
  {
4695
- prefix: modeLabelMap[prefix] || prefix,
5073
+ prefix: prefixLabel,
4696
5074
  size: "md",
4697
5075
  placeholder,
4698
5076
  id,
@@ -4729,11 +5107,11 @@ var PNLInput = (props) => {
4729
5107
  },
4730
5108
  onBlur: () => {
4731
5109
  setPrefix(!!value ? "" : mode);
4732
- setPlaceholder(mode === "Offset%" /* PERCENTAGE */ ? "%" : quote);
5110
+ setPlaceholder(isPercentageMode ? "%" : quote);
4733
5111
  onBlur();
4734
5112
  },
4735
5113
  suffix: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4736
- mode === "Offset%" /* PERCENTAGE */ && !!value && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "inherit", className: "oui-ml-[2px]", children: "%" }),
5114
+ isPercentageMode && !!value && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "inherit", className: "oui-ml-[2px]", children: "%" }),
4737
5115
  /* @__PURE__ */ jsxRuntime.jsx(
4738
5116
  PNLMenus,
4739
5117
  {
@@ -4878,8 +5256,8 @@ var OrderTPSL = (props) => {
4878
5256
  {
4879
5257
  className: ui.cn(
4880
5258
  "oui-orderEntry-tpsl-body",
4881
- "oui-max-h-0 oui-overflow-hidden oui-transition-all",
4882
- props.switchState && "oui-max-h-[120px]"
5259
+ "oui-overflow-hidden oui-transition-all",
5260
+ props.switchState ? "oui-max-h-[120px]" : "oui-max-h-0"
4883
5261
  ),
4884
5262
  onTransitionEnd: () => {
4885
5263
  tpslFormRef.current?.style.setProperty(
@@ -5153,6 +5531,8 @@ var TPSLInputRow = (props) => {
5153
5531
  PnL: props.values.PnL,
5154
5532
  Offset: props.values.Offset,
5155
5533
  "Offset%": props.values["Offset%"],
5534
+ OffsetFromMark: props.values.OffsetFromMark,
5535
+ PercentageFromMark: props.values.PercentageFromMark,
5156
5536
  ROI: props.values.ROI
5157
5537
  }
5158
5538
  }
@@ -5164,7 +5544,9 @@ var OrderEntry = (props) => {
5164
5544
  side,
5165
5545
  formattedOrder,
5166
5546
  setOrderValue,
5547
+ manualSetOrderValue,
5167
5548
  setOrderValues,
5549
+ setOrderValuesRaw,
5168
5550
  symbolInfo,
5169
5551
  maxQty,
5170
5552
  freeCollateral,
@@ -5180,9 +5562,13 @@ var OrderEntry = (props) => {
5180
5562
  fillMiddleValue,
5181
5563
  soundAlert,
5182
5564
  setSoundAlert,
5183
- currentFocusInput
5565
+ currentFocusInput,
5566
+ walletAddress,
5567
+ isPermissionlessListing,
5568
+ symbol
5184
5569
  } = props;
5185
5570
  const [maxQtyConfirmOpen, setMaxQtyConfirmOpen] = React3.useState(false);
5571
+ const [permissionlessAcknowledgedKeys, setPermissionlessAcknowledgedKeys] = hooks.useLocalStorage("orderly-permissionless-market-notice", []);
5186
5572
  const { t } = i18n.useTranslation();
5187
5573
  const { isMobile } = ui.useScreen();
5188
5574
  const [hasAdvancedTPSLResult, setHasAdvancedTPSLResult] = React3.useState(false);
@@ -5219,11 +5605,11 @@ var OrderEntry = (props) => {
5219
5605
  return;
5220
5606
  }
5221
5607
  if (slippage) {
5222
- setOrderValue("slippage", Number(slippage));
5608
+ manualSetOrderValue("slippage", Number(slippage));
5223
5609
  } else {
5224
- setOrderValue("slippage", void 0);
5610
+ manualSetOrderValue("slippage", void 0);
5225
5611
  }
5226
- }, [slippage, disableFeatures]);
5612
+ }, [slippage, disableFeatures, manualSetOrderValue]);
5227
5613
  React3.useEffect(() => {
5228
5614
  const clickHandler = (event) => {
5229
5615
  const target = event.target;
@@ -5252,22 +5638,7 @@ var OrderEntry = (props) => {
5252
5638
  helper.validate(isSlPriceError ? props.slPriceError : void 0).then(
5253
5639
  // validate success, it return the order
5254
5640
  // TODO: get order from other function
5255
- (order) => {
5256
- if (isScaledOrder) {
5257
- return ui.modal.show(scaledOrderConfirmDialogId, {
5258
- order,
5259
- symbolInfo,
5260
- size: isMobile ? "sm" : "md"
5261
- });
5262
- }
5263
- if (needConfirm) {
5264
- return ui.modal.show(orderConfirmDialogId, {
5265
- order: formattedOrder,
5266
- symbolInfo
5267
- });
5268
- }
5269
- return true;
5270
- },
5641
+ (order) => order,
5271
5642
  // should catch validate error first, then submit
5272
5643
  (errors2) => {
5273
5644
  if (errors2.slippage) {
@@ -5276,7 +5647,38 @@ var OrderEntry = (props) => {
5276
5647
  setErrorMsgVisible(true);
5277
5648
  return Promise.reject();
5278
5649
  }
5279
- ).then(() => {
5650
+ ).then((order) => {
5651
+ const shouldShowPermissionlessNotice = isPermissionlessListing && walletAddress && !(permissionlessAcknowledgedKeys ?? []).includes(
5652
+ `${walletAddress}_${symbol}`
5653
+ );
5654
+ if (shouldShowPermissionlessNotice) {
5655
+ return ui.modal.show(
5656
+ isMobile ? permissionlessMarketNoticeDialogId : permissionlessMarketNoticeDesktopDialogId
5657
+ ).then(() => {
5658
+ setPermissionlessAcknowledgedKeys([
5659
+ ...Array.isArray(permissionlessAcknowledgedKeys) ? permissionlessAcknowledgedKeys : [],
5660
+ `${walletAddress}_${symbol}`
5661
+ ]);
5662
+ return order;
5663
+ });
5664
+ }
5665
+ return Promise.resolve(order);
5666
+ }).then((order) => {
5667
+ if (isScaledOrder) {
5668
+ return ui.modal.show(scaledOrderConfirmDialogId, {
5669
+ order,
5670
+ symbolInfo,
5671
+ size: isMobile ? "sm" : "md"
5672
+ });
5673
+ }
5674
+ if (needConfirm) {
5675
+ return ui.modal.show(orderConfirmDialogId, {
5676
+ order: formattedOrder,
5677
+ symbolInfo
5678
+ });
5679
+ }
5680
+ return true;
5681
+ }).then(() => {
5280
5682
  return submit({ resetOnSuccess: false }).then((result) => {
5281
5683
  if (!result.success && result.message) {
5282
5684
  ui.toast.error(result.message);
@@ -5297,12 +5699,12 @@ var OrderEntry = (props) => {
5297
5699
  return new utils.Decimal(maxQty).todp(symbolInfo.base_dp, utils.Decimal.ROUND_DOWN).toString();
5298
5700
  }, [maxQty, symbolInfo.base_dp]);
5299
5701
  const onMaxQtyConfirm = React3.useCallback(() => {
5300
- setOrderValue("order_quantity", formattedMaxQty);
5702
+ manualSetOrderValue("order_quantity", formattedMaxQty);
5301
5703
  requestAnimationFrame(() => {
5302
5704
  onSubmit();
5303
5705
  });
5304
5706
  setMaxQtyConfirmOpen(false);
5305
- }, [setOrderValue, formattedMaxQty]);
5707
+ }, [manualSetOrderValue, formattedMaxQty, onSubmit]);
5306
5708
  const validateSubmit = async () => {
5307
5709
  if (formattedOrder.reduce_only && maxQty === 0) {
5308
5710
  return ui.modal.confirm({
@@ -5310,7 +5712,7 @@ var OrderEntry = (props) => {
5310
5712
  content: t("orderEntry.reduceOnly.reminder.content"),
5311
5713
  okLabel: t("orderEntry.placeOrderNow"),
5312
5714
  onOk: async () => {
5313
- setOrderValue("reduce_only", false);
5715
+ manualSetOrderValue("reduce_only", false);
5314
5716
  requestAnimationFrame(() => {
5315
5717
  props.resetMetaState();
5316
5718
  onSubmit();
@@ -5342,14 +5744,16 @@ var OrderEntry = (props) => {
5342
5744
  };
5343
5745
  const onSubmitAdvancedTPSL = (order) => {
5344
5746
  if (order.side !== formattedOrder.side) {
5345
- setOrderValue("side", order.side);
5747
+ manualSetOrderValue("side", order.side);
5346
5748
  }
5347
- setOrderValues({
5749
+ setOrderValuesRaw({
5348
5750
  position_type: order.position_type,
5349
5751
  tp_order_type: order.tp_order_type,
5350
5752
  tp_pnl: order.tp_pnl,
5351
5753
  tp_offset: order.tp_offset,
5352
5754
  tp_offset_percentage: order.tp_offset_percentage,
5755
+ tp_offset_from_mark: order.tp_offset_from_mark,
5756
+ tp_offset_percentage_from_mark: order.tp_offset_percentage_from_mark,
5353
5757
  tp_ROI: order.tp_ROI,
5354
5758
  tp_trigger_price: order.tp_trigger_price,
5355
5759
  tp_order_price: order.tp_order_price,
@@ -5359,6 +5763,8 @@ var OrderEntry = (props) => {
5359
5763
  sl_pnl: order.sl_pnl,
5360
5764
  sl_offset: order.sl_offset,
5361
5765
  sl_offset_percentage: order.sl_offset_percentage,
5766
+ sl_offset_from_mark: order.sl_offset_from_mark,
5767
+ sl_offset_percentage_from_mark: order.sl_offset_percentage_from_mark,
5362
5768
  sl_ROI: order.sl_ROI
5363
5769
  });
5364
5770
  setShowTPSLAdvanced(false);
@@ -5375,6 +5781,14 @@ var OrderEntry = (props) => {
5375
5781
  sl_order_type: types.OrderType.MARKET,
5376
5782
  tp_pnl: void 0,
5377
5783
  sl_pnl: void 0,
5784
+ tp_offset: void 0,
5785
+ tp_offset_percentage: void 0,
5786
+ tp_offset_from_mark: void 0,
5787
+ tp_offset_percentage_from_mark: void 0,
5788
+ sl_offset: void 0,
5789
+ sl_offset_percentage: void 0,
5790
+ sl_offset_from_mark: void 0,
5791
+ sl_offset_percentage_from_mark: void 0,
5378
5792
  position_type: types.PositionType.FULL
5379
5793
  });
5380
5794
  };
@@ -5390,7 +5804,7 @@ var OrderEntry = (props) => {
5390
5804
  setNeedConfirm,
5391
5805
  hidden,
5392
5806
  setHidden,
5393
- onValueChange: setOrderValue,
5807
+ onValueChange: manualSetOrderValue,
5394
5808
  orderTypeExtra: formattedOrder["order_type_ext"],
5395
5809
  showExtra: formattedOrder["order_type"] === types.OrderType.LIMIT && !props.tpslSwitch
5396
5810
  };
@@ -5405,6 +5819,7 @@ var OrderEntry = (props) => {
5405
5819
  onBlur: props.onBlur,
5406
5820
  getErrorMsg,
5407
5821
  setOrderValue,
5822
+ manualSetOrderValue,
5408
5823
  setOrderValues,
5409
5824
  currentFocusInput: currentFocusInput.current,
5410
5825
  priceInputRef: props.priceInputRef,
@@ -5440,13 +5855,17 @@ var OrderEntry = (props) => {
5440
5855
  canTrade: props.canTrade,
5441
5856
  side,
5442
5857
  order_type: formattedOrder.order_type,
5443
- setOrderValue,
5858
+ setOrderValue: manualSetOrderValue,
5444
5859
  symbolLeverage: props.symbolLeverage,
5445
- marginMode: props.marginMode
5860
+ marginMode: props.marginMode,
5861
+ marketOrderDisabled: props.isSymbolPostOnly,
5862
+ marketOrderDisabledTooltip: t(
5863
+ "orderEntry.orderType.symbolPostOnly.tooltip"
5864
+ )
5446
5865
  }
5447
5866
  ),
5448
5867
  /* @__PURE__ */ jsxRuntime.jsx(
5449
- Available,
5868
+ OrderEntryAvailableInjectabled,
5450
5869
  {
5451
5870
  currentLtv,
5452
5871
  canTrade: props.canTrade,
@@ -5470,7 +5889,7 @@ var OrderEntry = (props) => {
5470
5889
  }
5471
5890
  ),
5472
5891
  /* @__PURE__ */ jsxRuntime.jsx(
5473
- QuantitySlider,
5892
+ OrderEntryQuantitySliderInjectabled,
5474
5893
  {
5475
5894
  canTrade: props.canTrade,
5476
5895
  side: props.side,
@@ -5479,38 +5898,29 @@ var OrderEntry = (props) => {
5479
5898
  }
5480
5899
  ),
5481
5900
  /* @__PURE__ */ jsxRuntime.jsx(
5482
- ui.ThrottledButton,
5483
- {
5484
- fullWidth: true,
5485
- id: "order-entry-submit-button",
5486
- "data-type": types.OrderSide.BUY,
5487
- className: ui.cn(
5488
- "oui-orderEntry-submit-btn",
5489
- side === types.OrderSide.BUY ? "orderly-order-entry-submit-button-buy oui-bg-success-darken hover:oui-bg-success-darken/80 active:oui-bg-success-darken/80" : "orderly-order-entry-submit-button-sell oui-bg-danger-darken hover:oui-bg-danger-darken/80 active:oui-bg-danger-darken/80"
5490
- ),
5491
- onClick: validateSubmit,
5492
- loading: props.isMutating,
5493
- disabled: !props.canTrade,
5494
- children: buttonLabel
5495
- }
5496
- ),
5497
- /* @__PURE__ */ jsxRuntime.jsx(
5498
- AssetInfo,
5901
+ OrderEntrySubmitSectionInjectabled,
5499
5902
  {
5903
+ buttonLabel,
5904
+ side,
5500
5905
  canTrade: props.canTrade,
5501
- quote: symbolInfo.quote,
5502
- estLiqPrice: props.estLiqPrice,
5503
- estLiqPriceDistance: props.estLiqPriceDistance,
5504
- estLeverage: props.estLeverage,
5505
- currentLeverage: props.currentLeverage,
5506
- slippage,
5507
- dp: symbolInfo.quote_dp,
5508
- setSlippage,
5509
- estSlippage: props.estSlippage,
5510
- orderType: formattedOrder.order_type,
5511
- disableFeatures,
5512
- symbol: props.symbol,
5513
- side
5906
+ isMutating: props.isMutating,
5907
+ onSubmit: validateSubmit,
5908
+ assetInfo: {
5909
+ canTrade: props.canTrade,
5910
+ quote: symbolInfo.quote,
5911
+ estLiqPrice: props.estLiqPrice,
5912
+ estLiqPriceDistance: props.estLiqPriceDistance,
5913
+ estLeverage: props.estLeverage,
5914
+ currentLeverage: props.currentLeverage,
5915
+ slippage,
5916
+ dp: symbolInfo.quote_dp,
5917
+ setSlippage,
5918
+ estSlippage: props.estSlippage,
5919
+ orderType: formattedOrder.order_type,
5920
+ disableFeatures,
5921
+ symbol: props.symbol,
5922
+ side
5923
+ }
5514
5924
  }
5515
5925
  ),
5516
5926
  /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-w-full" }),
@@ -5535,10 +5945,10 @@ var OrderEntry = (props) => {
5535
5945
  onSwitchChanged: props.setTpslSwitch,
5536
5946
  orderType: formattedOrder.order_type,
5537
5947
  errors: validated || props.slPriceError !== void 0 ? { ...errors, ...props.slPriceError } : null,
5538
- setOrderValue,
5948
+ setOrderValue: manualSetOrderValue,
5539
5949
  reduceOnlyChecked: formattedOrder.reduce_only ?? false,
5540
5950
  onReduceOnlyChange: (checked) => {
5541
- setOrderValue("reduce_only", checked);
5951
+ manualSetOrderValue("reduce_only", checked);
5542
5952
  },
5543
5953
  values: {
5544
5954
  position_type: formattedOrder.position_type ?? types.PositionType.PARTIAL,
@@ -5547,6 +5957,8 @@ var OrderEntry = (props) => {
5547
5957
  PnL: formattedOrder.tp_pnl ?? "",
5548
5958
  Offset: formattedOrder.tp_offset ?? "",
5549
5959
  "Offset%": formattedOrder.tp_offset_percentage ?? "",
5960
+ OffsetFromMark: formattedOrder.tp_offset_from_mark ?? "",
5961
+ PercentageFromMark: formattedOrder.tp_offset_percentage_from_mark ?? "",
5550
5962
  ROI: formattedOrder.tp_ROI ?? ""
5551
5963
  },
5552
5964
  sl: {
@@ -5554,6 +5966,8 @@ var OrderEntry = (props) => {
5554
5966
  PnL: formattedOrder.sl_pnl ?? "",
5555
5967
  Offset: formattedOrder.sl_offset ?? "",
5556
5968
  "Offset%": formattedOrder.sl_offset_percentage ?? "",
5969
+ OffsetFromMark: formattedOrder.sl_offset_from_mark ?? "",
5970
+ PercentageFromMark: formattedOrder.sl_offset_percentage_from_mark ?? "",
5557
5971
  ROI: formattedOrder.sl_ROI ?? ""
5558
5972
  }
5559
5973
  },
@@ -5575,7 +5989,7 @@ var OrderEntry = (props) => {
5575
5989
  {
5576
5990
  checked: formattedOrder.reduce_only ?? false,
5577
5991
  onCheckedChange: (checked) => {
5578
- setOrderValue("reduce_only", checked);
5992
+ manualSetOrderValue("reduce_only", checked);
5579
5993
  }
5580
5994
  }
5581
5995
  ),
@@ -5664,7 +6078,7 @@ var OrderEntry = (props) => {
5664
6078
  children: showTPSLAdvanced && /* @__PURE__ */ jsxRuntime.jsx(
5665
6079
  uiTpsl.TPSLAdvancedWidget,
5666
6080
  {
5667
- setOrderValue,
6081
+ setOrderValue: manualSetOrderValue,
5668
6082
  order: formattedOrder,
5669
6083
  onSubmit: onSubmitAdvancedTPSL,
5670
6084
  onClose: () => {
@@ -5840,11 +6254,14 @@ var useOrderEntryScript = (inputs) => {
5840
6254
  defaultSoundValue ?? null
5841
6255
  );
5842
6256
  const canTrade = reactApp.useCanTrade();
5843
- const { marginMode } = hooks.useMarginModeBySymbol(symbol);
6257
+ const { state: accountState } = hooks.useAccount();
6258
+ const { marginMode, isPermissionlessListing } = hooks.useMarginModeBySymbol(symbol);
6259
+ const walletAddress = accountState?.address;
5844
6260
  const {
5845
6261
  formattedOrder,
5846
6262
  setValue,
5847
6263
  setValues: setOrderValues,
6264
+ setValuesRaw: setOrderValuesRaw,
5848
6265
  symbolInfo,
5849
6266
  symbolLeverage,
5850
6267
  ...state
@@ -5943,6 +6360,12 @@ var useOrderEntryScript = (inputs) => {
5943
6360
  );
5944
6361
  }
5945
6362
  );
6363
+ const manualSetOrderValue = hooks.useMemoizedFn(
6364
+ (key, value, options2) => {
6365
+ lastUserActiveTimeRef.current = Date.now();
6366
+ setOrderValue(key, value, options2);
6367
+ }
6368
+ );
5946
6369
  const onTPSLSwitchChanged = (state2) => {
5947
6370
  setTpslSwitch(state2);
5948
6371
  if (state2) {
@@ -6034,6 +6457,16 @@ var useOrderEntryScript = (inputs) => {
6034
6457
  setValue("distribution_type", types.DistributionType.FLAT);
6035
6458
  }
6036
6459
  }, [formattedOrder.order_type, formattedOrder.distribution_type]);
6460
+ const isSymbolPostOnly = symbolInfo?.status === "POST_ONLY";
6461
+ React3.useEffect(() => {
6462
+ if (isSymbolPostOnly && (formattedOrder.order_type === types.OrderType.MARKET || formattedOrder.order_type === types.OrderType.STOP_MARKET)) {
6463
+ setLocalOrderType(types.OrderType.LIMIT);
6464
+ setOrderValues({
6465
+ order_type: types.OrderType.LIMIT,
6466
+ order_type_ext: void 0
6467
+ });
6468
+ }
6469
+ }, [isSymbolPostOnly, formattedOrder.order_type, setOrderValues]);
6037
6470
  const currentLtv = hooks.useComputedLTV();
6038
6471
  const askAndBid = useAskAndBid();
6039
6472
  const fillMiddleValue = () => {
@@ -6051,10 +6484,24 @@ var useOrderEntryScript = (inputs) => {
6051
6484
  const { priceInputContainerRef, priceInputContainerWidth } = usePriceInputContainer({
6052
6485
  order_type_ext: formattedOrder.order_type_ext
6053
6486
  });
6487
+ const effectiveEstLiqPriceForSlCheck = React3.useMemo(() => {
6488
+ const estLiqPrice = state.estLiqPrice;
6489
+ if (estLiqPrice == null || formattedOrder.side == null || state.markPrice == null) {
6490
+ return null;
6491
+ }
6492
+ if (formattedOrder.side === types.OrderSide.BUY && estLiqPrice > state.markPrice || formattedOrder.side === types.OrderSide.SELL && estLiqPrice < state.markPrice) {
6493
+ return null;
6494
+ }
6495
+ if (!Number.isFinite(estLiqPrice) || estLiqPrice <= 0) {
6496
+ return null;
6497
+ }
6498
+ return estLiqPrice;
6499
+ }, [state.estLiqPrice, state.markPrice, formattedOrder.side]);
6054
6500
  const slPriceError = hooks.useTpslPriceChecker({
6055
6501
  slPrice: formattedOrder.sl_trigger_price,
6056
- liqPrice: state.estLiqPrice,
6502
+ liqPrice: effectiveEstLiqPriceForSlCheck,
6057
6503
  side: formattedOrder.side,
6504
+ markPrice: state.markPrice,
6058
6505
  currentPosition: state.currentPosition,
6059
6506
  orderQuantity: Number(formattedOrder.order_quantity)
6060
6507
  });
@@ -6069,22 +6516,16 @@ var useOrderEntryScript = (inputs) => {
6069
6516
  }
6070
6517
  }, [tpslSwitch]);
6071
6518
  React3.useEffect(() => {
6072
- lastUserActiveTimeRef.current = Date.now();
6073
- }, [
6074
- formattedOrder.order_price,
6075
- formattedOrder.order_quantity,
6076
- formattedOrder.side
6077
- ]);
6078
- React3.useEffect(() => {
6519
+ const estLiqPrice = effectiveEstLiqPriceForSlCheck;
6079
6520
  const lastActive = lastUserActiveTimeRef.current;
6080
6521
  const now = Date.now();
6081
6522
  const isUserActive = now - lastActive <= ORDER_ENTRY_EST_LIQ_ACTIVE_WINDOW_MS;
6082
6523
  ee.emit(types.ORDER_ENTRY_EST_LIQ_PRICE_CHANGE, {
6083
6524
  symbol,
6084
- estLiqPrice: state.estLiqPrice ?? null,
6525
+ estLiqPrice,
6085
6526
  isUserActive
6086
6527
  });
6087
- }, [ee, symbol, state.estLiqPrice]);
6528
+ }, [ee, symbol, effectiveEstLiqPriceForSlCheck]);
6088
6529
  React3.useEffect(() => {
6089
6530
  setOrderValue("margin_mode", marginMode);
6090
6531
  }, [marginMode]);
@@ -6096,7 +6537,9 @@ var useOrderEntryScript = (inputs) => {
6096
6537
  level: formattedOrder.level,
6097
6538
  formattedOrder,
6098
6539
  setOrderValue,
6540
+ manualSetOrderValue,
6099
6541
  setOrderValues,
6542
+ setOrderValuesRaw,
6100
6543
  // account-level leverage (for other consumers)
6101
6544
  currentLeverage,
6102
6545
  // symbol-level leverage & margin mode for this order entry
@@ -6125,7 +6568,10 @@ var useOrderEntryScript = (inputs) => {
6125
6568
  symbol,
6126
6569
  soundAlert,
6127
6570
  setSoundAlert,
6128
- currentFocusInput
6571
+ currentFocusInput,
6572
+ walletAddress,
6573
+ isPermissionlessListing,
6574
+ isSymbolPostOnly
6129
6575
  };
6130
6576
  };
6131
6577
  var InjectableOrderEntry = ui.injectable(
@@ -6150,6 +6596,7 @@ exports.LTVRiskTooltipWidget = LTVRiskTooltipWidget;
6150
6596
  exports.OrderConfirmDialog = OrderConfirmDialog;
6151
6597
  exports.OrderEntry = OrderEntry;
6152
6598
  exports.OrderEntryWidget = OrderEntryWidget;
6599
+ exports.SymbolBadge = SymbolBadge;
6153
6600
  exports.useOrderEntryScript = useOrderEntryScript;
6154
6601
  //# sourceMappingURL=index.js.map
6155
6602
  //# sourceMappingURL=index.js.map