From 9e771748a4991d89a37e6ae781a949bd5eb8113d Mon Sep 17 00:00:00 2001
From: deep-path <476044723@qq.com>
Date: Wed, 20 Nov 2024 12:13:14 +0800
Subject: [PATCH] feat: add modal
---
.../ModalWithClosePosition.tsx | 96 +++++++++++++++++++
components/HashResultModal/index.tsx | 21 ++++
screens/Trading/index.tsx | 82 ++--------------
services/transaction.ts | 76 +++++++++++++++
4 files changed, 200 insertions(+), 75 deletions(-)
create mode 100644 components/HashResultModal/ModalWithClosePosition.tsx
create mode 100644 services/transaction.ts
diff --git a/components/HashResultModal/ModalWithClosePosition.tsx b/components/HashResultModal/ModalWithClosePosition.tsx
new file mode 100644
index 00000000..28f37452
--- /dev/null
+++ b/components/HashResultModal/ModalWithClosePosition.tsx
@@ -0,0 +1,96 @@
+import React, { useState, useEffect } from "react";
+import { NearIconMini } from "../../screens/MarginTrading/components/Icon";
+import { CloseIcon } from "../Icons/Icons";
+
+interface FailureModalProps {
+ show: boolean;
+ onClose: () => void;
+ title?: string;
+ errorMessage?: string;
+ type?: "Long" | "Short";
+}
+
+const ModalWithFailure = ({
+ show,
+ onClose,
+ title = "Close Position",
+ errorMessage = "Operation failed, please try again later",
+ type = "Long",
+}: FailureModalProps) => {
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [countdown, setCountdown] = useState(10);
+ const [progress, setProgress] = useState(100);
+ let countdownTimer;
+
+ useEffect(() => {
+ if (show) {
+ setIsModalVisible(true);
+ startCountdown();
+ } else {
+ setIsModalVisible(false);
+ clearTimeoutOrInterval(countdownTimer);
+ }
+ return () => clearTimeoutOrInterval(countdownTimer);
+ }, [show]);
+
+ const clearTimeoutOrInterval = (timerId) => {
+ if (timerId) {
+ clearInterval(timerId);
+ countdownTimer = null;
+ }
+ };
+
+ const hideModal = () => {
+ setIsModalVisible(false);
+ onClose();
+ clearTimeout(countdownTimer);
+ };
+
+ const startCountdown = () => {
+ setCountdown(10);
+ setProgress(100);
+
+ const timerInterval = 1000;
+ countdownTimer = setInterval(() => {
+ setCountdown((prevCountdown) => {
+ if (prevCountdown <= 1) {
+ hideModal();
+ clearTimeoutOrInterval(countdownTimer);
+ return 0;
+ }
+ return prevCountdown - 1;
+ });
+ setProgress((prevProgress) => Math.max(prevProgress - 10, 0));
+ }, timerInterval);
+ };
+
+ return (
+
+ {isModalVisible && (
+
+ )}
+
+ );
+};
+
+export default ModalWithFailure;
diff --git a/components/HashResultModal/index.tsx b/components/HashResultModal/index.tsx
index caaf4c65..56e2bdea 100644
--- a/components/HashResultModal/index.tsx
+++ b/components/HashResultModal/index.tsx
@@ -2,6 +2,7 @@ import React from "react";
import { createRoot } from "react-dom/client";
import ModalWithCountdown from "./ModalWithCountdown";
import ModalWithFailure from "./ModalWithFailure";
+import ModalWithClosePosition from "./ModalWithClosePosition";
interface ShowPositionResultParams {
title?: string;
@@ -82,3 +83,23 @@ export const showPositionFailure = (params: {
root?.render();
};
+
+export const showPositionClose = (params: { title?: string; type?: "Long" | "Short" }) => {
+ if (!container) {
+ container = document.createElement("div");
+ container.id = "position-result-container";
+ document.body.appendChild(container);
+ root = createRoot(container);
+ }
+ const handleClose = () => {
+ if (root) {
+ root.unmount();
+ }
+ if (container) {
+ container.remove();
+ container = null;
+ root = null;
+ }
+ };
+ root?.render();
+};
diff --git a/screens/Trading/index.tsx b/screens/Trading/index.tsx
index fb1c3c56..6494b387 100644
--- a/screens/Trading/index.tsx
+++ b/screens/Trading/index.tsx
@@ -23,7 +23,12 @@ import { setCategoryAssets1, setCategoryAssets2 } from "../../redux/marginTradin
import { useMarginAccount } from "../../hooks/useMarginAccount";
import { useAccountId, usePortfolioAssets } from "../../hooks/hooks";
import { useRouterQuery, getTransactionResult, parsedArgs } from "../../utils/txhashContract";
-import { showPositionResult, showPositionFailure } from "../../components/HashResultModal";
+import {
+ showPositionResult,
+ showPositionFailure,
+ showPositionClose,
+} from "../../components/HashResultModal";
+import { handleTransactionResults } from "../../services/transaction";
init_env("dev");
@@ -138,82 +143,9 @@ const Trading = () => {
};
useEffect(() => {
- handleTransactions();
+ handleTransactionResults(query?.transactionHashes, query?.errorMessage);
}, [query?.transactionHashes, query?.errorMessage]);
- const handleTransactions = async () => {
- if (query?.transactionHashes) {
- try {
- const txhash = Array.isArray(query?.transactionHashes)
- ? query?.transactionHashes
- : (query?.transactionHashes as string).split(",");
- const results = await Promise.all(
- txhash.map(async (txHash: string) => {
- const result: any = await getTransactionResult(txHash);
- const hasStorageDeposit = result.transaction.actions.some(
- (action: any) => action?.FunctionCall?.method_name === "margin_execute_with_pyth",
- );
- return { txHash, result, hasStorageDeposit };
- }),
- );
- results.forEach(({ txHash, result, hasStorageDeposit }: any) => {
- if (hasStorageDeposit) {
- // handleClaimTokenMobile({ level, count });
- console.log(result);
-
- const args = parsedArgs(result?.transaction?.actions?.[0]?.FunctionCall?.args || "");
- const { actions } = JSON.parse(args || "");
-
- // const ft_on_transfer_id = result?.receipts?.findIndex((r: any) =>
- // r?.receipt?.Action?.actions?.some(
- // (a: any) => a?.FunctionCall?.method_name === "margin_execute_with_pyth",
- // ),
- // );
-
- // const ft_on_transfer_logs =
- // result?.receipts_outcome?.[ft_on_transfer_id]?.outcome?.logs || "";
- // const ft_on_transfer_log = ft_on_transfer_logs?.[ft_on_transfer_logs?.length - 1];
- // const idx = ft_on_transfer_log?.indexOf("{");
-
- // const parsed_ft_on_transfer_log = JSON.parse(ft_on_transfer_log.slice(idx) || "");
- const isLong = actions[0]?.OpenPosition?.token_p_id == "wrap.testnet";
- console.log(actions);
- console.log(marginConfig);
- showPositionResult({
- title: "Open Position",
- type: isLong ? "Long" : "Short",
- price: (isLong
- ? Number(shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 18)) /
- Number(shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 24))
- : Number(shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 18)) /
- Number(shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 24))
- ).toString(),
- transactionHashes: Array.isArray(router.query.transactionHashes)
- ? router.query.transactionHashes[0]
- : (router.query.transactionHashes as string),
- positionSize: {
- // optional,
- amount: isLong
- ? shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 24, 6)
- : shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 24, 6),
- symbol: "NEAR",
- usdValue: "1000",
- },
- });
- }
- });
- } catch (error) {
- console.error("Error processing transactions:", error);
- }
- }
- if (query?.errorMessage) {
- showPositionFailure({
- title: "Open Position",
- errorMessage: decodeURIComponent(query.errorMessage as string),
- });
- }
- };
-
//
return (
diff --git a/services/transaction.ts b/services/transaction.ts
new file mode 100644
index 00000000..76df7bbd
--- /dev/null
+++ b/services/transaction.ts
@@ -0,0 +1,76 @@
+import { shrinkToken } from "../store";
+import { getTransactionResult, parsedArgs } from "../utils/txhashContract";
+import {
+ showPositionResult,
+ showPositionClose,
+ showPositionFailure,
+} from "../components/HashResultModal";
+
+interface TransactionResult {
+ txHash: string;
+ result: any;
+ hasStorageDeposit: boolean;
+}
+
+export const handleTransactionResults = async (
+ transactionHashes: string | string[] | undefined,
+ errorMessage?: string | string[],
+) => {
+ if (transactionHashes) {
+ try {
+ const txhash = Array.isArray(transactionHashes)
+ ? transactionHashes
+ : transactionHashes.split(",");
+
+ const results = await Promise.all(
+ txhash.map(async (txHash: string): Promise => {
+ const result: any = await getTransactionResult(txHash);
+ const hasStorageDeposit = result.transaction.actions.some(
+ (action: any) => action?.FunctionCall?.method_name === "margin_execute_with_pyth",
+ );
+ return { txHash, result, hasStorageDeposit };
+ }),
+ );
+
+ results.forEach(({ result, hasStorageDeposit }: TransactionResult) => {
+ if (hasStorageDeposit) {
+ const args = parsedArgs(result?.transaction?.actions?.[0]?.FunctionCall?.args || "");
+ const { actions } = JSON.parse(args || "");
+ const isLong = actions[0]?.OpenPosition?.token_p_id == "wrap.testnet";
+
+ if (actions[0]?.CloseMTPosition) {
+ showPositionClose({});
+ } else {
+ showPositionResult({
+ title: "Open Position",
+ type: isLong ? "Long" : "Short",
+ price: (isLong
+ ? Number(shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 18)) /
+ Number(shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 24))
+ : Number(shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 18)) /
+ Number(shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 24))
+ ).toString(),
+ transactionHashes: txhash[0],
+ positionSize: {
+ amount: isLong
+ ? shrinkToken(actions[0]?.OpenPosition?.min_token_p_amount, 24, 6)
+ : shrinkToken(actions[0]?.OpenPosition?.token_d_amount, 24, 6),
+ symbol: "NEAR",
+ usdValue: "1000",
+ },
+ });
+ }
+ }
+ });
+ } catch (error) {
+ console.error("Error processing transactions:", error);
+ }
+ }
+
+ if (errorMessage) {
+ showPositionFailure({
+ title: "Open Position",
+ errorMessage: decodeURIComponent(errorMessage as string),
+ });
+ }
+};