Skip to content

Commit

Permalink
feat: add modal
Browse files Browse the repository at this point in the history
  • Loading branch information
deep-path committed Nov 20, 2024
1 parent 2a465ed commit 9e77174
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 75 deletions.
96 changes: 96 additions & 0 deletions components/HashResultModal/ModalWithClosePosition.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
{isModalVisible && (
<div className="z-50 fixed right-5 bottom-10 w-93 bg-dark-100 text-white border rounded-sm">
<div className="relative w-full p-6 flex flex-col gap-3">
<div onClick={onClose} className="absolute" style={{ top: "-6px", right: "-4px" }}>
<CloseIcon />
</div>
<div className="fc">
<NearIconMini />
<span className="font-normal text-base px-2">{title}</span>
<div className="text-toolTipBoxBorderColor text-sm ml-auto">Success</div>
</div>
<div className="w-full h-1 bg-black">
<div
className="h-full bg-toolTipBoxBorderColor transition-all ease-linear"
style={{
width: `${progress}%`,
transitionDuration: "950ms",
}}
/>
</div>
</div>
</div>
)}
</div>
);
};

export default ModalWithFailure;
21 changes: 21 additions & 0 deletions components/HashResultModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -82,3 +83,23 @@ export const showPositionFailure = (params: {

root?.render(<ModalWithFailure show onClose={handleClose} {...params} />);
};

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(<ModalWithClosePosition show onClose={handleClose} {...params} />);
};
82 changes: 7 additions & 75 deletions screens/Trading/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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 (
<LayoutBox>
Expand Down
76 changes: 76 additions & 0 deletions services/transaction.ts
Original file line number Diff line number Diff line change
@@ -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<TransactionResult> => {
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),
});
}
};

0 comments on commit 9e77174

Please sign in to comment.