mirror of
https://github.com/Qortal/q-trade.git
synced 2025-06-15 10:51:21 +00:00
334 lines
8.8 KiB
TypeScript
334 lines
8.8 KiB
TypeScript
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
import ReactGA from "react-ga4";
|
|
import "./App.css";
|
|
import socketService from "./services/socketService";
|
|
import GameContext, {
|
|
IContextProps,
|
|
UserNameAvatar,
|
|
} from "./contexts/gameContext";
|
|
import { Route, Routes } from "react-router-dom";
|
|
|
|
import { ThemeProvider } from "@mui/material";
|
|
import { darkTheme } from "./styles/theme";
|
|
import { HomePage } from "./pages/Home/Home";
|
|
import { UserContext, UserContextProps } from "./contexts/userContext";
|
|
import {
|
|
NotificationProps,
|
|
NotificationContext,
|
|
} from "./contexts/notificationContext";
|
|
import { Notification } from "./components/common/notification/Notification";
|
|
import { LoadingContext } from "./contexts/loadingContext";
|
|
import axios from "axios";
|
|
import { executeEvent } from "./utils/events";
|
|
import { useIndexedDBContext } from "./contexts/indexedDBContext";
|
|
import { useGetOngoingTransactions } from "./components/DbComponents/OngoingTransactions";
|
|
|
|
|
|
|
|
|
|
export async function sendRequestToExtension(
|
|
requestType: string,
|
|
payload?: any,
|
|
timeout: number = 20000
|
|
): Promise<any> {
|
|
return new Promise((resolve, reject) => {
|
|
const requestId = Math.random().toString(36).substring(2, 15); // Generate a unique ID for the request
|
|
const detail = {
|
|
type: requestType,
|
|
payload,
|
|
requestId,
|
|
timeout: timeout / 1000,
|
|
};
|
|
|
|
// Store the timeout ID so it can be cleared later
|
|
const timeoutId = setTimeout(() => {
|
|
document.removeEventListener("qortalExtensionResponses", handleResponse);
|
|
reject(new Error("Request timed out"));
|
|
}, timeout); // Adjust timeout as necessary
|
|
|
|
function handleResponse(event: any) {
|
|
const { requestId: responseId, data } = event.detail;
|
|
if (requestId === responseId) {
|
|
// Match the response with the request
|
|
document.removeEventListener(
|
|
"qortalExtensionResponses",
|
|
handleResponse
|
|
);
|
|
clearTimeout(timeoutId); // Clear the timeout upon successful response
|
|
resolve(data);
|
|
}
|
|
}
|
|
|
|
document.addEventListener("qortalExtensionResponses", handleResponse);
|
|
document.dispatchEvent(
|
|
new CustomEvent("qortalExtensionRequests", { detail })
|
|
);
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function App() {
|
|
const [userInfo, setUserInfo] = useState<any>(null);
|
|
const [qortBalance, setQortBalance] = useState<any>(null);
|
|
const [balances, setBalances] = useState<any>({});
|
|
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
|
|
|
const foreignCoinBalance = useMemo(()=> {
|
|
if(balances[selectedCoin] === 0) return 0
|
|
return balances[selectedCoin] || null
|
|
}, [balances, selectedCoin])
|
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
|
|
const [OAuthLoading, setOAuthLoading] = useState<boolean>(false);
|
|
const db = useIndexedDBContext();
|
|
const [isUsingGateway, setIsUsingGateway] = useState(true)
|
|
|
|
const [isSocketUp, setIsSocketUp] = useState<boolean>(false);
|
|
// const [onGoingTrades, setOngoingTrades] = useState([])
|
|
const {onGoingTrades, fetchOngoingTransactions, updateTransactionInDB, deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, sellOrders} = useGetOngoingTransactions({qortAddress: userInfo?.address})
|
|
const [userNameAvatar, setUserNameAvatar] = useState<
|
|
Record<string, UserNameAvatar>
|
|
>({});
|
|
const [avatar, setAvatar] = useState<string>("");
|
|
const [notification, setNotification] = useState<NotificationProps>({
|
|
alertType: "",
|
|
msg: "",
|
|
});
|
|
const [loadingSlider, setLoadingSlider] = useState<boolean>(false);
|
|
|
|
const loadingContextValue = {
|
|
loadingSlider,
|
|
setLoadingSlider,
|
|
};
|
|
|
|
const getIsUsingGateway = async ()=> {
|
|
try {
|
|
const res = await qortalRequest({
|
|
action: "IS_USING_GATEWAY"
|
|
})
|
|
setIsUsingGateway(res.isGateway)
|
|
} catch (error) {
|
|
|
|
}
|
|
}
|
|
|
|
|
|
useEffect(()=> {
|
|
getIsUsingGateway()
|
|
}, [])
|
|
|
|
const resetNotification = () => {
|
|
setNotification({ alertType: "", msg: "" });
|
|
};
|
|
|
|
|
|
const userContextValue: UserContextProps = {
|
|
avatar,
|
|
setAvatar,
|
|
};
|
|
|
|
const notificationContextValue = {
|
|
notification,
|
|
setNotification,
|
|
resetNotification,
|
|
};
|
|
|
|
async function getNameInfo(address: string) {
|
|
const response = await qortalRequest({
|
|
action: "GET_ACCOUNT_NAMES",
|
|
address: address,
|
|
});
|
|
const nameData = response;
|
|
|
|
if (nameData?.length > 0) {
|
|
return nameData[0].name;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
const askForAccountInformation = React.useCallback(async () => {
|
|
try {
|
|
const account = await qortalRequest({
|
|
action: "GET_USER_ACCOUNT",
|
|
});
|
|
|
|
const name = await getNameInfo(account.address);
|
|
setUserInfo({ ...account, name });
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}, []);
|
|
|
|
React.useEffect(() => {
|
|
askForAccountInformation();
|
|
}, [askForAccountInformation]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getQortBalance = async ()=> {
|
|
const balanceUrl: string = `/addresses/balance/${userInfo?.address}`;
|
|
const balanceResponse = await axios(balanceUrl);
|
|
setQortBalance(balanceResponse.data?.value)
|
|
}
|
|
|
|
const getLTCBalance = async (coin) => {
|
|
try {
|
|
const response = await qortalRequest({
|
|
action: "GET_WALLET_BALANCE",
|
|
coin: getCoinLabel(coin)
|
|
});
|
|
if(!response?.error){
|
|
setBalances((prev)=> {
|
|
return {
|
|
...prev,
|
|
[coin]: +response
|
|
}
|
|
})
|
|
}
|
|
} catch (error) {
|
|
//
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
if(!userInfo?.address || !selectedCoin) return
|
|
const intervalGetTradeInfo = setInterval(() => {
|
|
fetchOngoingTransactions()
|
|
getLTCBalance(selectedCoin)
|
|
getQortBalance()
|
|
}, 150000)
|
|
getLTCBalance(selectedCoin)
|
|
getQortBalance()
|
|
return () => {
|
|
clearInterval(intervalGetTradeInfo)
|
|
}
|
|
}, [userInfo?.address, isAuthenticated, selectedCoin])
|
|
|
|
|
|
const handleMessage = async (event: any) => {
|
|
if (event.data.type === "LOGOUT") {
|
|
console.log("Logged out from extension");
|
|
setUserInfo(null);
|
|
setAvatar("");
|
|
setIsAuthenticated(false);
|
|
setQortBalance(null)
|
|
localStorage.setItem("token", "");
|
|
} else if(event.data.type === "RESPONSE_FOR_TRADES"){
|
|
|
|
|
|
const response = event.data.payload
|
|
if (response?.extra?.atAddresses
|
|
) {
|
|
try {
|
|
const status = response.callResponse === true ? 'trade-ongoing' : 'trade-failed'
|
|
const token = localStorage.getItem("token");
|
|
// Prepare transaction data
|
|
const transactionData = {
|
|
qortalAtAddresses: response.extra.atAddresses,
|
|
qortAddress: userInfo.address,
|
|
status: status,
|
|
message: response.extra.message,
|
|
};
|
|
|
|
// Update transactions in IndexedDB
|
|
const result = await updateTransactionInDB(transactionData);
|
|
fetchOngoingTransactions()
|
|
executeEvent("execute-get-new-block-trades", {})
|
|
} catch (error) {
|
|
console.log({error})
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
window.addEventListener("message", handleMessage);
|
|
|
|
return () => {
|
|
window.removeEventListener("message", handleMessage);
|
|
};
|
|
}, [userInfo?.address]);
|
|
|
|
const getCoinLabel = useCallback((coin?: string)=> {
|
|
switch(coin || selectedCoin){
|
|
case "LITECOIN":{
|
|
|
|
return 'LTC'
|
|
}
|
|
case "DOGECOIN":{
|
|
|
|
return 'DOGE'
|
|
}
|
|
case "BITCOIN":{
|
|
|
|
return 'BTC'
|
|
}
|
|
case "DIGIBYTE":{
|
|
|
|
return 'DGB'
|
|
}
|
|
case "RAVENCOIN":{
|
|
|
|
return 'RVN'
|
|
}
|
|
case "PIRATECHAIN":{
|
|
|
|
return 'ARRR'
|
|
}
|
|
default:
|
|
return null
|
|
}
|
|
}, [selectedCoin])
|
|
|
|
const gameContextValue: IContextProps = {
|
|
userInfo,
|
|
setUserInfo,
|
|
userNameAvatar,
|
|
setUserNameAvatar,
|
|
onGoingTrades,
|
|
fetchOngoingTransactions,
|
|
foreignCoinBalance,
|
|
qortBalance,
|
|
isAuthenticated,
|
|
setIsAuthenticated,
|
|
OAuthLoading,
|
|
setOAuthLoading,
|
|
updateTransactionInDB,
|
|
sellOrders,
|
|
deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, isUsingGateway, selectedCoin, setSelectedCoin, getCoinLabel
|
|
};
|
|
|
|
|
|
return (
|
|
<NotificationContext.Provider value={notificationContextValue}>
|
|
<LoadingContext.Provider value={loadingContextValue}>
|
|
<UserContext.Provider value={userContextValue}>
|
|
<GameContext.Provider value={gameContextValue}>
|
|
<Notification />
|
|
<ThemeProvider theme={darkTheme}>
|
|
<Routes>
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<HomePage
|
|
/>
|
|
}
|
|
/>
|
|
</Routes>
|
|
</ThemeProvider>
|
|
</GameContext.Provider>
|
|
</UserContext.Provider>
|
|
</LoadingContext.Provider>
|
|
</NotificationContext.Provider>
|
|
);
|
|
}
|
|
|
|
export default App;
|