added other coins
64
src/App.tsx
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import ReactGA from "react-ga4";
|
import ReactGA from "react-ga4";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import socketService from "./services/socketService";
|
import socketService from "./services/socketService";
|
||||||
@ -71,7 +71,12 @@ export async function sendRequestToExtension(
|
|||||||
function App() {
|
function App() {
|
||||||
const [userInfo, setUserInfo] = useState<any>(null);
|
const [userInfo, setUserInfo] = useState<any>(null);
|
||||||
const [qortBalance, setQortBalance] = useState<any>(null);
|
const [qortBalance, setQortBalance] = useState<any>(null);
|
||||||
const [ltcBalance, setLtcBalance] = useState<any>(null);
|
const [balances, setBalances] = useState<any>({});
|
||||||
|
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
||||||
|
|
||||||
|
const foreignCoinBalance = useMemo(()=> {
|
||||||
|
return balances[selectedCoin] || null
|
||||||
|
}, [balances, selectedCoin])
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
|
||||||
const [OAuthLoading, setOAuthLoading] = useState<boolean>(false);
|
const [OAuthLoading, setOAuthLoading] = useState<boolean>(false);
|
||||||
const db = useIndexedDBContext();
|
const db = useIndexedDBContext();
|
||||||
@ -172,14 +177,19 @@ function App() {
|
|||||||
setQortBalance(balanceResponse.data?.value)
|
setQortBalance(balanceResponse.data?.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getLTCBalance = async () => {
|
const getLTCBalance = async (coin) => {
|
||||||
try {
|
try {
|
||||||
const response = await qortalRequest({
|
const response = await qortalRequest({
|
||||||
action: "GET_WALLET_BALANCE",
|
action: "GET_WALLET_BALANCE",
|
||||||
coin: "LTC"
|
coin: getCoinLabel(coin)
|
||||||
});
|
});
|
||||||
if(!response?.error){
|
if(!response?.error){
|
||||||
setLtcBalance(+response)
|
setBalances((prev)=> {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[coin]: +response
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//
|
//
|
||||||
@ -187,18 +197,18 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!userInfo?.address) return
|
if(!userInfo?.address || !selectedCoin) return
|
||||||
const intervalGetTradeInfo = setInterval(() => {
|
const intervalGetTradeInfo = setInterval(() => {
|
||||||
fetchOngoingTransactions()
|
fetchOngoingTransactions()
|
||||||
getLTCBalance()
|
getLTCBalance(selectedCoin)
|
||||||
getQortBalance()
|
getQortBalance()
|
||||||
}, 150000)
|
}, 150000)
|
||||||
getLTCBalance()
|
getLTCBalance(selectedCoin)
|
||||||
getQortBalance()
|
getQortBalance()
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(intervalGetTradeInfo)
|
clearInterval(intervalGetTradeInfo)
|
||||||
}
|
}
|
||||||
}, [userInfo?.address, isAuthenticated])
|
}, [userInfo?.address, isAuthenticated, selectedCoin])
|
||||||
|
|
||||||
|
|
||||||
const handleMessage = async (event: any) => {
|
const handleMessage = async (event: any) => {
|
||||||
@ -208,7 +218,6 @@ function App() {
|
|||||||
setAvatar("");
|
setAvatar("");
|
||||||
setIsAuthenticated(false);
|
setIsAuthenticated(false);
|
||||||
setQortBalance(null)
|
setQortBalance(null)
|
||||||
setLtcBalance(null)
|
|
||||||
localStorage.setItem("token", "");
|
localStorage.setItem("token", "");
|
||||||
} else if(event.data.type === "RESPONSE_FOR_TRADES"){
|
} else if(event.data.type === "RESPONSE_FOR_TRADES"){
|
||||||
|
|
||||||
@ -246,6 +255,37 @@ function App() {
|
|||||||
};
|
};
|
||||||
}, [userInfo?.address]);
|
}, [userInfo?.address]);
|
||||||
|
|
||||||
|
const getCoinLabel = (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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const gameContextValue: IContextProps = {
|
const gameContextValue: IContextProps = {
|
||||||
userInfo,
|
userInfo,
|
||||||
setUserInfo,
|
setUserInfo,
|
||||||
@ -253,7 +293,7 @@ function App() {
|
|||||||
setUserNameAvatar,
|
setUserNameAvatar,
|
||||||
onGoingTrades,
|
onGoingTrades,
|
||||||
fetchOngoingTransactions,
|
fetchOngoingTransactions,
|
||||||
ltcBalance,
|
foreignCoinBalance,
|
||||||
qortBalance,
|
qortBalance,
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
setIsAuthenticated,
|
setIsAuthenticated,
|
||||||
@ -261,7 +301,7 @@ function App() {
|
|||||||
setOAuthLoading,
|
setOAuthLoading,
|
||||||
updateTransactionInDB,
|
updateTransactionInDB,
|
||||||
sellOrders,
|
sellOrders,
|
||||||
deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, isUsingGateway
|
deleteTemporarySellOrder, updateTemporaryFailedTradeBots, fetchTemporarySellOrders, isUsingGateway, selectedCoin, setSelectedCoin, getCoinLabel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BIN
src/assets/img/arrr.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/img/btc.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/img/dgb.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/img/doge.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/img/ltc.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/img/qort.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/img/rvn.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { AgGridReact } from 'ag-grid-react';
|
import { AgGridReact } from 'ag-grid-react';
|
||||||
import { ColDef, SizeColumnsToContentStrategy } from 'ag-grid-community';
|
import { ColDef, RowClassParams, RowStyle, SizeColumnsToContentStrategy } from 'ag-grid-community';
|
||||||
import 'ag-grid-community/styles/ag-grid.css';
|
import 'ag-grid-community/styles/ag-grid.css';
|
||||||
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
||||||
import gameContext from '../../contexts/gameContext';
|
import gameContext from '../../contexts/gameContext';
|
||||||
@ -10,9 +10,17 @@ const autoSizeStrategy: SizeColumnsToContentStrategy = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const OngoingTrades = () => {
|
export const OngoingTrades = () => {
|
||||||
const { onGoingTrades } = useContext(gameContext);
|
const { onGoingTrades, getCoinLabel, selectedCoin } = useContext(gameContext);
|
||||||
|
const gridRef = useRef<any>(null)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const onGridReady = useCallback((params: any) => {
|
||||||
|
// params.api.sizeColumnsToFit(); // Adjust columns to fit the grid width
|
||||||
|
// const allColumnIds = params.columnApi.getAllColumns().map((col: any) => col.getColId());
|
||||||
|
// params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content
|
||||||
|
}, []);
|
||||||
|
|
||||||
const defaultColDef = {
|
const defaultColDef = {
|
||||||
resizable: true, // Make columns resizable by default
|
resizable: true, // Make columns resizable by default
|
||||||
sortable: true, // Make columns sortable by default
|
sortable: true, // Make columns sortable by default
|
||||||
@ -35,9 +43,10 @@ export const OngoingTrades = () => {
|
|||||||
resizable: true ,
|
resizable: true ,
|
||||||
flex: 1, minWidth: 100
|
flex: 1, minWidth: 100
|
||||||
},
|
},
|
||||||
{ headerName: "Amount (QORT)", valueGetter: (params) => +params.data.tradeInfo.qortAmount, resizable: true, flex: 1, minWidth: 100 },
|
{ headerName: "Amount (QORT)", valueGetter: (params) => +params.data.tradeInfo.qortAmount, resizable: true, flex: 1, minWidth: 150 },
|
||||||
{ headerName: "LTC/QORT", valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount / +params.data.tradeInfo.qortAmount , resizable: true , flex: 1, minWidth: 100},
|
{ headerName: `${getCoinLabel()}/QORT`, valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount / +params.data.tradeInfo.qortAmount , resizable: true , flex: 1, minWidth: 150},
|
||||||
{ headerName: "Total LTC Value", valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount, resizable: true , flex: 1, minWidth: 100 },
|
{ headerName: `Total ${getCoinLabel()} Value`, valueGetter: (params) => +params.data.tradeInfo.expectedForeignAmount, resizable: true , flex: 1, minWidth: 150,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
headerName: "Notes", valueGetter: (params) => {
|
headerName: "Notes", valueGetter: (params) => {
|
||||||
if (params.data.tradeInfo.mode === 'TRADING') {
|
if (params.data.tradeInfo.mode === 'TRADING') {
|
||||||
@ -54,7 +63,7 @@ export const OngoingTrades = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (params.data.message) return params.data.message
|
if (params.data.message) return params.data.message
|
||||||
}, resizable: true, flex: 1, minWidth: 100
|
}, resizable: true, flex: 1, minWidth:300, autoHeight: true, cellStyle: { whiteSpace: 'normal', wordBreak: 'break-word', padding: '5px' },
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -65,15 +74,20 @@ export const OngoingTrades = () => {
|
|||||||
// return null;
|
// return null;
|
||||||
// };
|
// };
|
||||||
const getRowId = useCallback(function (params: any) {
|
const getRowId = useCallback(function (params: any) {
|
||||||
return String(params.data._id);
|
return String(params.data?.qortalAtAddress);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ag-theme-alpine-dark" style={{ height: 225, width: '100%' }}>
|
<div className="ag-theme-alpine-dark" style={{ height: 225, width: '100%' }}>
|
||||||
<AgGridReact
|
<AgGridReact
|
||||||
|
onGridReady={onGridReady}
|
||||||
|
ref={gridRef}
|
||||||
|
|
||||||
columnDefs={columnDefs}
|
columnDefs={columnDefs}
|
||||||
defaultColDef={defaultColDef}
|
defaultColDef={defaultColDef}
|
||||||
rowData={onGoingTrades}
|
rowData={onGoingTrades?.filter((item)=> item?.tradeInfo?.foreignBlockchain === selectedCoin)}
|
||||||
// onRowClicked={onRowClicked}
|
// onRowClicked={onRowClicked}
|
||||||
rowSelection="single"
|
rowSelection="single"
|
||||||
getRowId={getRowId}
|
getRowId={getRowId}
|
||||||
|
@ -11,6 +11,9 @@ import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
|||||||
import { useModal } from '../common/useModal';
|
import { useModal } from '../common/useModal';
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
|
|
||||||
|
// export const baseLocalHost = window.location.host
|
||||||
|
export const baseLocalHost = '127.0.0.1:12391'
|
||||||
|
|
||||||
interface RowData {
|
interface RowData {
|
||||||
amountQORT: number;
|
amountQORT: number;
|
||||||
priceUSD: number;
|
priceUSD: number;
|
||||||
@ -32,10 +35,10 @@ export const autoSizeStrategy: SizeColumnsToContentStrategy = {
|
|||||||
type: 'fitCellContents'
|
type: 'fitCellContents'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
export const TradeOffers: React.FC<any> = ({foreignCoinBalance}:any) => {
|
||||||
const [offers, setOffers] = useState<any[]>([])
|
const [offers, setOffers] = useState<any[]>([])
|
||||||
|
const [qortalNames, setQortalNames] = useState({})
|
||||||
const { fetchOngoingTransactions, onGoingTrades, updateTransactionInDB, isUsingGateway } = useContext(gameContext);
|
const { fetchOngoingTransactions, onGoingTrades, updateTransactionInDB, isUsingGateway, getCoinLabel, selectedCoin } = useContext(gameContext);
|
||||||
const listOfOngoingTradesAts = useMemo(()=> {
|
const listOfOngoingTradesAts = useMemo(()=> {
|
||||||
return onGoingTrades?.filter((item)=> item?.status !== 'trade-failed')?.map((trade)=> trade?.qortalAtAddress) || []
|
return onGoingTrades?.filter((item)=> item?.status !== 'trade-failed')?.map((trade)=> trade?.qortalAtAddress) || []
|
||||||
}, [onGoingTrades])
|
}, [onGoingTrades])
|
||||||
@ -50,7 +53,7 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
const offersWithoutOngoing = useMemo(()=> {
|
const offersWithoutOngoing = useMemo(()=> {
|
||||||
return offers.filter((item)=> !listOfOngoingTradesAts.includes(item.qortalAtAddress))
|
return offers.filter((item)=> !listOfOngoingTradesAts.includes(item.qortalAtAddress))
|
||||||
}, [listOfOngoingTradesAts, offers])
|
}, [listOfOngoingTradesAts, offers])
|
||||||
|
const initiatedFetchPresence = useRef(false)
|
||||||
|
|
||||||
|
|
||||||
const [selectedOffer, setSelectedOffer] = useState<any>(null)
|
const [selectedOffer, setSelectedOffer] = useState<any>(null)
|
||||||
@ -80,6 +83,30 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
suppressMovable: true, // Prevent columns from being movable
|
suppressMovable: true, // Prevent columns from being movable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getName = async (address)=> {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/names/address/" + address);
|
||||||
|
const nameData = await response.json();
|
||||||
|
if (nameData?.length > 0) {
|
||||||
|
setQortalNames((prev)=> {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[address]: nameData[0].name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setQortalNames((prev)=> {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[address]: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const columnDefs: ColDef[] = [
|
const columnDefs: ColDef[] = [
|
||||||
{
|
{
|
||||||
headerCheckboxSelection: true, // Adds a checkbox in the header for selecting all rows
|
headerCheckboxSelection: true, // Adds a checkbox in the header for selecting all rows
|
||||||
@ -92,15 +119,28 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
{ headerName: "QORT AMOUNT", field: "qortAmount" , flex: 1, // Flex makes this column responsive
|
{ headerName: "QORT AMOUNT", field: "qortAmount" , flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true },
|
resizable: true },
|
||||||
{ headerName: "LTC/QORT", valueGetter: (params) => +params.data.foreignAmount / +params.data.qortAmount, sortable: true, sort: 'asc', flex: 1, // Flex makes this column responsive
|
{ headerName: `${getCoinLabel()}/QORT`, valueGetter: (params) => +params.data.foreignAmount / +params.data.qortAmount, sortable: true, sort: 'asc', flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true },
|
resizable: true },
|
||||||
{ headerName: "Total LTC Value", field: "foreignAmount", flex: 1, // Flex makes this column responsive
|
{ headerName: `Total ${getCoinLabel()} Value`, field: "foreignAmount", flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true },
|
resizable: true },
|
||||||
{ headerName: "Seller", field: "qortalCreator", flex: 1, // Flex makes this column responsive
|
{ headerName: "Seller", field: "qortalCreator", flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 300, // Ensure it doesn't shrink too much
|
minWidth: 300, // Ensure it doesn't shrink too much
|
||||||
resizable: true },
|
resizable: true, valueGetter: (params)=> {
|
||||||
|
if(params?.data?.qortalCreator){
|
||||||
|
if(qortalNames[params?.data?.qortalCreator]){
|
||||||
|
return qortalNames[params?.data?.qortalCreator]
|
||||||
|
} else if(qortalNames[params?.data?.qortalCreator] === undefined){
|
||||||
|
getName(params?.data?.qortalCreator)
|
||||||
|
|
||||||
|
return params?.data?.qortalCreator
|
||||||
|
} else {
|
||||||
|
return params?.data?.qortalCreator
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@ -225,7 +265,7 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
if(isUsingGateway){
|
if(isUsingGateway){
|
||||||
socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradepresence`
|
socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradepresence`
|
||||||
} else {
|
} else {
|
||||||
socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradepresence`;
|
socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradepresence`;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,44 +285,59 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
}
|
}
|
||||||
socket.onerror = (e) => {
|
socket.onerror = (e) => {
|
||||||
clearTimeout(socketTimeout)
|
clearTimeout(socketTimeout)
|
||||||
|
restartTradePresenceWebSocket()
|
||||||
}
|
}
|
||||||
const pingSocket = () => {
|
const pingSocket = () => {
|
||||||
socket.send('ping')
|
socket.send('ping')
|
||||||
socketTimeout = setTimeout(pingSocket, 295000)
|
socketTimeout = setTimeout(pingSocket, 295000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const socketRef = useRef(null)
|
||||||
|
|
||||||
|
const restartTradeOffers = ()=> {
|
||||||
|
if (socketRef.current) {
|
||||||
|
socketRef.current.close(1000, 'forced'); // Close with a custom reason
|
||||||
|
socketRef.current = null
|
||||||
|
}
|
||||||
|
offeringTrades.current = []
|
||||||
|
setOffers([])
|
||||||
|
setSelectedOffer(null)
|
||||||
|
}
|
||||||
|
|
||||||
const initTradeOffersWebSocket = (restarted = false) => {
|
const initTradeOffersWebSocket = (restarted = false) => {
|
||||||
let tradeOffersSocketCounter = 0
|
|
||||||
|
if(socketRef.current) return
|
||||||
let socketTimeout: any
|
let socketTimeout: any
|
||||||
|
|
||||||
let socketLink
|
let socketLink
|
||||||
if(isUsingGateway){
|
if(isUsingGateway){
|
||||||
socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradeoffers?foreignBlockchain=LITECOIN&includeHistoric=true`
|
socketLink = `wss://appnode.qortal.org/websockets/crosschain/tradeoffers?foreignBlockchain=${selectedCoin}&includeHistoric=true`
|
||||||
} else {
|
} else {
|
||||||
socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradeoffers?foreignBlockchain=LITECOIN&includeHistoric=true`
|
socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradeoffers?foreignBlockchain=${selectedCoin}&includeHistoric=true`
|
||||||
|
|
||||||
}
|
}
|
||||||
const socket = new WebSocket(socketLink)
|
socketRef.current = new WebSocket(socketLink)
|
||||||
socket.onopen = () => {
|
socketRef.current.onopen = () => {
|
||||||
setTimeout(pingSocket, 50)
|
setTimeout(pingSocket, 50)
|
||||||
tradeOffersSocketCounter += 1
|
|
||||||
}
|
}
|
||||||
socket.onmessage = (e) => {
|
socketRef.current.onmessage = (e) => {
|
||||||
offeringTrades.current = [...offeringTrades.current, ...JSON.parse(e.data)]
|
offeringTrades.current = [...offeringTrades.current?.filter((coin)=> coin?.foreignBlockchain === selectedCoin), ...JSON.parse(e.data)?.filter((coin)=> coin?.foreignBlockchain === selectedCoin)]
|
||||||
tradeOffersSocketCounter += 1
|
|
||||||
restarted = false
|
restarted = false
|
||||||
processOffersWithPresence()
|
processOffersWithPresence()
|
||||||
}
|
}
|
||||||
socket.onclose = () => {
|
socketRef.current.onclose = (event) => {
|
||||||
clearTimeout(socketTimeout)
|
clearTimeout(socketTimeout)
|
||||||
restartTradeOffersWebSocket()
|
if (event.reason === 'forced') {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
socket.onerror = (e) => {
|
restartTradeOffersWebSocket()
|
||||||
|
socketRef.current = null
|
||||||
|
}
|
||||||
|
socketRef.current.onerror = (e) => {
|
||||||
clearTimeout(socketTimeout)
|
clearTimeout(socketTimeout)
|
||||||
}
|
}
|
||||||
const pingSocket = () => {
|
const pingSocket = () => {
|
||||||
socket.send('ping')
|
socketRef.current.send('ping')
|
||||||
socketTimeout = setTimeout(pingSocket, 295000)
|
socketTimeout = setTimeout(pingSocket, 295000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,8 +345,11 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
blockedTradesList.current = JSON.parse(localStorage.getItem('failedTrades') || '[]')
|
blockedTradesList.current = JSON.parse(localStorage.getItem('failedTrades') || '[]')
|
||||||
|
if(!initiatedFetchPresence.current){
|
||||||
|
initiatedFetchPresence.current = true
|
||||||
initTradePresenceWebSocket()
|
initTradePresenceWebSocket()
|
||||||
initTradeOffersWebSocket()
|
|
||||||
|
}
|
||||||
getNewBlockedTrades()
|
getNewBlockedTrades()
|
||||||
const intervalBlockTrades = setInterval(() => {
|
const intervalBlockTrades = setInterval(() => {
|
||||||
getNewBlockedTrades()
|
getNewBlockedTrades()
|
||||||
@ -304,6 +362,24 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(selectedCoin === null) return
|
||||||
|
restartTradeOffers()
|
||||||
|
setTimeout(() => {
|
||||||
|
initTradeOffersWebSocket()
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
return () => {
|
||||||
|
if(socketRef.current){
|
||||||
|
socketRef.current.close(1000, 'forced');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isUsingGateway, selectedCoin])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const selectedTotalLTC = useMemo(() => {
|
const selectedTotalLTC = useMemo(() => {
|
||||||
return selectedOffers.reduce((acc: number, curr: any) => {
|
return selectedOffers.reduce((acc: number, curr: any) => {
|
||||||
return acc + (+curr.foreignAmount || 0); // Ensure qortAmount is defined
|
return acc + (+curr.foreignAmount || 0); // Ensure qortAmount is defined
|
||||||
@ -313,11 +389,11 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
|
|
||||||
const buyOrder = async () => {
|
const buyOrder = async () => {
|
||||||
try {
|
try {
|
||||||
if(+ltcBalance < +selectedTotalLTC.toFixed(4)){
|
if(+foreignCoinBalance < +selectedTotalLTC.toFixed(4)){
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
setInfo({
|
setInfo({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: "You don't have enough LTC or your balance was not retrieved"
|
message: `You don't have enough ${getCoinLabel()} or your balance was not retrieved`
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -329,11 +405,10 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
message: "Attempting to submit buy order. Please wait..."
|
message: "Attempting to submit buy order. Please wait..."
|
||||||
})
|
})
|
||||||
const listOfATs = selectedOffers
|
const listOfATs = selectedOffers
|
||||||
|
|
||||||
const response = await qortalRequestWithTimeout({
|
const response = await qortalRequestWithTimeout({
|
||||||
action: "CREATE_TRADE_BUY_ORDER",
|
action: "CREATE_TRADE_BUY_ORDER",
|
||||||
crosschainAtInfo: listOfATs,
|
crosschainAtInfo: listOfATs,
|
||||||
foreignBlockchain: 'LITECOIN'
|
foreignBlockchain: selectedCoin
|
||||||
}, 900000);
|
}, 900000);
|
||||||
|
|
||||||
if(response?.error){
|
if(response?.error){
|
||||||
@ -381,7 +456,7 @@ export const TradeOffers: React.FC<any> = ({ltcBalance}:any) => {
|
|||||||
setOpen(true)
|
setOpen(true)
|
||||||
setInfo({
|
setInfo({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error?.message || "Failed to submit trade order."
|
message: error?.error || error?.message || "Failed to submit trade order."
|
||||||
})
|
})
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
@ -471,7 +546,7 @@ const handleClose = (
|
|||||||
onSelectionChanged={onSelectionChanged}
|
onSelectionChanged={onSelectionChanged}
|
||||||
getRowStyle={getRowStyle}
|
getRowStyle={getRowStyle}
|
||||||
autoSizeStrategy={autoSizeStrategy}
|
autoSizeStrategy={autoSizeStrategy}
|
||||||
rowSelection="multiple" // Enable multi-select
|
rowSelection={selectedCoin === 'PIRATECHAIN' ? "single" :"multiple"} // Enable multi-select
|
||||||
rowMultiSelectWithClick={true}
|
rowMultiSelectWithClick={true}
|
||||||
suppressHorizontalScroll={false} // Allow horizontal scroll on mobile if needed
|
suppressHorizontalScroll={false} // Allow horizontal scroll on mobile if needed
|
||||||
suppressCellFocus={true} // Prevents cells from stealing focus in mobile
|
suppressCellFocus={true} // Prevents cells from stealing focus in mobile
|
||||||
@ -486,6 +561,9 @@ const handleClose = (
|
|||||||
|
|
||||||
)} */}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{
|
||||||
|
height: '120px'
|
||||||
|
}} />
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -517,10 +595,10 @@ const handleClose = (
|
|||||||
}}>
|
}}>
|
||||||
<Typography sx={{
|
<Typography sx={{
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: selectedTotalLTC > ltcBalance ? 'red' : 'white',
|
color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white',
|
||||||
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
|
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
|
||||||
marginLeft: 'auto'
|
marginLeft: 'auto'
|
||||||
}}>LTC</span></Typography>
|
}}>{`${getCoinLabel()} `}</span></Typography>
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
@ -528,9 +606,9 @@ const handleClose = (
|
|||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
|
|
||||||
}}><span>{ltcBalance?.toFixed(4)}</span> <span style={{
|
}}><span>{foreignCoinBalance?.toFixed(4)}</span> <span style={{
|
||||||
marginLeft: 'auto'
|
marginLeft: 'auto'
|
||||||
}}>LTC balance</span></Typography>
|
}}>{`${getCoinLabel()} `} balance</span></Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{BuyButton()}
|
{BuyButton()}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -55,14 +55,14 @@ export const Terms =() => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Typography gutterBottom>
|
<Typography gutterBottom>
|
||||||
The purpose of q-trade is to make trading LTC for QORT as easy as possible. The maintainers of this site do not profit from its use—there are no additional fees for buying QORT through this site. There are two ways to place a buy order:
|
The purpose of q-trade is to make trading LTC and other coins for QORT as easy as possible. The maintainers of this site do not profit from its use—there are no additional fees for buying QORT through this site. There are two ways to place a buy order:
|
||||||
1. Use the gateway
|
1. Use the gateway
|
||||||
2. Use your local node.
|
2. Use your local node.
|
||||||
By using q-trade, you agree to the following terms and conditions.
|
By using q-trade, you agree to the following terms and conditions.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography gutterBottom>
|
<Typography gutterBottom>
|
||||||
Using the gateway means you trust the maintainer of the node, as your LTC private key will need to be handled by that node to execute a trade order. If you have more than 4 QORT and your public key is already on the blockchain, your LTC private key will be transmitted using q-chat. If not, the message will be encrypted in the same manner as q-chat but stored temporarily in a database to ensure it reaches its destination.
|
Using the gateway means you trust the maintainer of the node, as your foreign coin (i.e. LTC) private key will need to be handled by that node to execute a trade order. If you have more than 4 QORT and your public key is already on the blockchain, your foreign coin private key will be transmitted using q-chat. If not, the message will be encrypted in the same manner as q-chat but stored temporarily in a database to ensure it reaches its destination.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography gutterBottom>
|
<Typography gutterBottom>
|
||||||
@ -70,7 +70,7 @@ export const Terms =() => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography gutterBottom>
|
<Typography gutterBottom>
|
||||||
The maintainers and devs of this site are not responsible for any lost LTC, QORT, or other cryptocurrencies that may result from using this site. This is a hobby project, and mistakes in the code may occur. Please proceed with caution.
|
The maintainers and devs of this site are not responsible for any lost foreign coin, QORT, or other cryptocurrencies that may result from using this site. This is a hobby project, and mistakes in the code may occur.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
@ -36,6 +36,12 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { sendRequestToExtension } from "../../App";
|
import { sendRequestToExtension } from "../../App";
|
||||||
import { Terms } from "../Terms";
|
import { Terms } from "../Terms";
|
||||||
|
import ltcIcon from '../../assets/img/ltc.png'
|
||||||
|
import btcIcon from '../../assets/img/btc.png'
|
||||||
|
import dogeIcon from '../../assets/img/doge.png'
|
||||||
|
import rvnIcon from '../../assets/img/rvn.png'
|
||||||
|
import dgbIcon from '../../assets/img/dgb.png'
|
||||||
|
import arrrIcon from '../../assets/img/arrr.png'
|
||||||
|
|
||||||
const checkIfLocal = async () => {
|
const checkIfLocal = async () => {
|
||||||
try {
|
try {
|
||||||
@ -59,7 +65,47 @@ export const Label = styled("label")(
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
const SelectRow = ({coin})=> {
|
||||||
|
let img
|
||||||
|
switch (coin) {
|
||||||
|
case 'LTC':
|
||||||
|
img = ltcIcon
|
||||||
|
break;
|
||||||
|
case 'BTC':
|
||||||
|
img = btcIcon
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DOGE':
|
||||||
|
img = dogeIcon
|
||||||
|
break;
|
||||||
|
case 'RVN':
|
||||||
|
img = rvnIcon
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ARRR':
|
||||||
|
img = arrrIcon
|
||||||
|
break;
|
||||||
|
case 'DGB':
|
||||||
|
img = dgbIcon
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '10px',
|
||||||
|
height: '25px'
|
||||||
|
}}><img style={{
|
||||||
|
height: '20px',
|
||||||
|
width: 'auto'
|
||||||
|
}} src={img} /><p>{coin}</p></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Header = ({ qortBalance, foreignCoinBalance, mode, setMode }: any) => {
|
||||||
const [openDropdown, setOpenDropdown] = useState<boolean>(false);
|
const [openDropdown, setOpenDropdown] = useState<boolean>(false);
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
const buttonRef = useRef<HTMLDivElement>(null);
|
const buttonRef = useRef<HTMLDivElement>(null);
|
||||||
@ -67,7 +113,6 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [info, setInfo] = useState<any>(null);
|
const [info, setInfo] = useState<any>(null);
|
||||||
const { isUsingGateway } = useContext(gameContext);
|
const { isUsingGateway } = useContext(gameContext);
|
||||||
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
|
||||||
|
|
||||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setChecked(false);
|
setChecked(false);
|
||||||
@ -77,7 +122,7 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
|||||||
message: "Change the node you are using at the authentication page",
|
message: "Change the node you are using at the authentication page",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const { userInfo } = useContext(gameContext);
|
const { userInfo, selectedCoin, setSelectedCoin, getCoinLabel } = useContext(gameContext);
|
||||||
const { avatar, setAvatar } = useContext(UserContext);
|
const { avatar, setAvatar } = useContext(UserContext);
|
||||||
|
|
||||||
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
|
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
|
||||||
@ -185,7 +230,12 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
|||||||
value={selectedCoin}
|
value={selectedCoin}
|
||||||
onChange={(e) => setSelectedCoin(e.target.value)}
|
onChange={(e) => setSelectedCoin(e.target.value)}
|
||||||
>
|
>
|
||||||
<MenuItem value={"LITECOIN"}>LTC</MenuItem>
|
<MenuItem value={"LITECOIN"}><SelectRow coin="LTC" /></MenuItem>
|
||||||
|
<MenuItem value={"DOGECOIN"}><SelectRow coin="DOGE" /></MenuItem>
|
||||||
|
<MenuItem value={"BITCOIN"}><SelectRow coin="BTC" /></MenuItem>
|
||||||
|
<MenuItem value={"DIGIBYTE"}><SelectRow coin="DGB" /></MenuItem>
|
||||||
|
<MenuItem value={"RAVENCOIN"}><SelectRow coin="RVN" /></MenuItem>
|
||||||
|
<MenuItem value={"PIRATECHAIN"}><SelectRow coin="ARRR" /></MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@ -195,7 +245,7 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
|||||||
}}>
|
}}>
|
||||||
<HeaderText>
|
<HeaderText>
|
||||||
Balance: {qortBalance} QORT |{" "}
|
Balance: {qortBalance} QORT |{" "}
|
||||||
{ltcBalance === null ? "N/A" : ltcBalance} LTC
|
{foreignCoinBalance === null ? "N/A" : foreignCoinBalance} {getCoinLabel()}
|
||||||
</HeaderText>
|
</HeaderText>
|
||||||
<NameRow>
|
<NameRow>
|
||||||
{userInfo?.name ? (
|
{userInfo?.name ? (
|
||||||
@ -247,8 +297,20 @@ export const Header = ({ qortBalance, ltcBalance, mode, setMode }: any) => {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button onClick={() => setMode("buy")}>Buy QORT</Button>
|
<Button sx={{
|
||||||
<Button onClick={() => setMode("sell")}>SELL QORT</Button>
|
opacity: 0.8,
|
||||||
|
"&:hover": {
|
||||||
|
background: mode === 'buy' ? "#0085ff" : 'unset',
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
}} variant={mode === 'buy' ? 'contained' : 'text'} onClick={() => setMode("buy")}>Buy QORT</Button>
|
||||||
|
<Button sx={{
|
||||||
|
opacity: 0.8,
|
||||||
|
"&:hover": {
|
||||||
|
background: mode === 'sell' ? "#0085ff" : 'unset',
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
}} variant={mode === 'sell' ? 'contained' : 'text'} onClick={() => setMode("sell")}>SELL QORT</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Snackbar
|
<Snackbar
|
||||||
|
@ -19,7 +19,27 @@ export const minimumAmountSellTrades = {
|
|||||||
'LITECOIN': {
|
'LITECOIN': {
|
||||||
value: 0.01,
|
value: 0.01,
|
||||||
ticker: 'LTC'
|
ticker: 'LTC'
|
||||||
}
|
},
|
||||||
|
DOGECOIN: {
|
||||||
|
value: 1,
|
||||||
|
ticker: "DOGE",
|
||||||
|
},
|
||||||
|
BITCOIN: {
|
||||||
|
value: 0.001,
|
||||||
|
ticker: "BTC",
|
||||||
|
},
|
||||||
|
DIGIBYTE: {
|
||||||
|
value: 0.01,
|
||||||
|
ticker: "DGB",
|
||||||
|
},
|
||||||
|
RAVENCOIN: {
|
||||||
|
value: 0.01,
|
||||||
|
ticker: "RVN",
|
||||||
|
},
|
||||||
|
PIRATECHAIN: {
|
||||||
|
value: 0.0002,
|
||||||
|
ticker: "ARRR",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CustomInput = styled(TextField)({
|
export const CustomInput = styled(TextField)({
|
||||||
@ -66,7 +86,7 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const [qortAmount, setQortAmount] = React.useState(0)
|
const [qortAmount, setQortAmount] = React.useState(0)
|
||||||
const [foreignAmount, setForeignAmount] = React.useState(0)
|
const [foreignAmount, setForeignAmount] = React.useState(0)
|
||||||
const {updateTemporaryFailedTradeBots, sellOrders, fetchTemporarySellOrders, isUsingGateway} = useContext(gameContext)
|
const {updateTemporaryFailedTradeBots, sellOrders, fetchTemporarySellOrders, isUsingGateway, getCoinLabel, selectedCoin} = useContext(gameContext)
|
||||||
const [openAlert, setOpenAlert] = React.useState(false)
|
const [openAlert, setOpenAlert] = React.useState(false)
|
||||||
const [info, setInfo] = React.useState<any>(null)
|
const [info, setInfo] = React.useState<any>(null)
|
||||||
const handleClickOpen = () => {
|
const handleClickOpen = () => {
|
||||||
@ -80,7 +100,6 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
|
|
||||||
const createSellOrder = async() => {
|
const createSellOrder = async() => {
|
||||||
try {
|
try {
|
||||||
setOpen(true)
|
|
||||||
setInfo({
|
setInfo({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: "Attempting to create sell order. Please wait..."
|
message: "Attempting to create sell order. Please wait..."
|
||||||
@ -88,8 +107,8 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
const res = await qortalRequestWithTimeout({
|
const res = await qortalRequestWithTimeout({
|
||||||
action: "CREATE_TRADE_SELL_ORDER",
|
action: "CREATE_TRADE_SELL_ORDER",
|
||||||
qortAmount,
|
qortAmount,
|
||||||
foreignBlockchain: 'LITECOIN',
|
foreignBlockchain: selectedCoin,
|
||||||
foreignAmount
|
foreignAmount: qortAmount * foreignAmount
|
||||||
}, 900000);
|
}, 900000);
|
||||||
|
|
||||||
if(res?.error && res?.failedTradeBot){
|
if(res?.error && res?.failedTradeBot){
|
||||||
@ -167,7 +186,6 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@ -187,7 +205,7 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
|
<DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
|
||||||
New Sell Order - QORT for LTC
|
{`New Sell Order - QORT for ${getCoinLabel()}`}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
@ -214,7 +232,7 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
/>
|
/>
|
||||||
<Spacer height="6px" />
|
<Spacer height="6px" />
|
||||||
<CustomLabel htmlFor="standard-adornment-amount">
|
<CustomLabel htmlFor="standard-adornment-amount">
|
||||||
Price Each (LTC)
|
{`Price Each (${getCoinLabel()})`}
|
||||||
</CustomLabel>
|
</CustomLabel>
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
<CustomInput
|
<CustomInput
|
||||||
@ -225,10 +243,10 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<Spacer height="6px" />
|
<Spacer height="6px" />
|
||||||
<Typography>{qortAmount * foreignAmount} LTC for {qortAmount} QORT</Typography>
|
<Typography>{`${qortAmount * foreignAmount} ${getCoinLabel()}`} for {qortAmount} QORT</Typography>
|
||||||
<Typography sx={{
|
<Typography sx={{
|
||||||
fontSize: '12px'
|
fontSize: '12px'
|
||||||
}}>Total sell amount needs to be greater than: {minimumAmountSellTrades.LITECOIN.value} {' '} {minimumAmountSellTrades.LITECOIN.ticker}</Typography>
|
}}>Total sell amount needs to be greater than: {minimumAmountSellTrades[selectedCoin]?.value} {' '} {minimumAmountSellTrades[selectedCoin]?.ticker}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
@ -236,7 +254,7 @@ export const CreateSell = ({qortAddress, show}) => {
|
|||||||
<Button autoFocus onClick={handleClose}>
|
<Button autoFocus onClick={handleClose}>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
<Button disabled={!qortAmount || !(qortAmount * foreignAmount > minimumAmountSellTrades.LITECOIN.value)} autoFocus onClick={createSellOrder}>
|
<Button disabled={!qortAmount || !(qortAmount * foreignAmount > minimumAmountSellTrades[selectedCoin]?.value)} autoFocus onClick={createSellOrder}>
|
||||||
Create sell order
|
Create sell order
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
@ -8,7 +8,7 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { autoSizeStrategy } from "../Grids/TradeOffers";
|
import { autoSizeStrategy, baseLocalHost } from "../Grids/TradeOffers";
|
||||||
import { Alert, Box, Snackbar, SnackbarCloseReason, Typography } from "@mui/material";
|
import { Alert, Box, Snackbar, SnackbarCloseReason, Typography } from "@mui/material";
|
||||||
import gameContext from "../../contexts/gameContext";
|
import gameContext from "../../contexts/gameContext";
|
||||||
|
|
||||||
@ -18,47 +18,47 @@ const defaultColDef = {
|
|||||||
suppressMovable: true, // Prevent columns from being movable
|
suppressMovable: true, // Prevent columns from being movable
|
||||||
};
|
};
|
||||||
|
|
||||||
const columnDefs: ColDef[] = [
|
// const columnDefs: ColDef[] = [
|
||||||
{
|
// {
|
||||||
headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows
|
// headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows
|
||||||
checkboxSelection: true, // Adds checkboxes in each row for selection
|
// checkboxSelection: true, // Adds checkboxes in each row for selection
|
||||||
headerName: "Select", // You can customize the header name
|
// headerName: "Select", // You can customize the header name
|
||||||
width: 50, // Adjust the width as needed
|
// width: 50, // Adjust the width as needed
|
||||||
pinned: "left", // Optional, to pin this column on the left
|
// pinned: "left", // Optional, to pin this column on the left
|
||||||
resizable: false,
|
// resizable: false,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
headerName: "QORT AMOUNT",
|
// headerName: "QORT AMOUNT",
|
||||||
field: "qortAmount",
|
// field: "qortAmount",
|
||||||
flex: 1, // Flex makes this column responsive
|
// flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
// minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
// resizable: true,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
headerName: "LTC/QORT",
|
// headerName: "LTC/QORT",
|
||||||
valueGetter: (params) =>
|
// valueGetter: (params) =>
|
||||||
+params.data.foreignAmount / +params.data.qortAmount,
|
// +params.data.foreignAmount / +params.data.qortAmount,
|
||||||
sortable: true,
|
// sortable: true,
|
||||||
sort: "asc",
|
// sort: "asc",
|
||||||
flex: 1, // Flex makes this column responsive
|
// flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
// minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
// resizable: true,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
headerName: "Total LTC Value",
|
// headerName: "Total LTC Value",
|
||||||
field: "foreignAmount",
|
// field: "foreignAmount",
|
||||||
flex: 1, // Flex makes this column responsive
|
// flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 150, // Ensure it doesn't shrink too much
|
// minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
// resizable: true,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
headerName: "Status",
|
// headerName: "Status",
|
||||||
field: "status",
|
// field: "status",
|
||||||
flex: 1, // Flex makes this column responsive
|
// flex: 1, // Flex makes this column responsive
|
||||||
minWidth: 300, // Ensure it doesn't shrink too much
|
// minWidth: 300, // Ensure it doesn't shrink too much
|
||||||
resizable: true,
|
// resizable: true,
|
||||||
},
|
// },
|
||||||
];
|
// ];
|
||||||
|
|
||||||
export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
||||||
const [tradeBotList, setTradeBotList] = useState([]);
|
const [tradeBotList, setTradeBotList] = useState([]);
|
||||||
@ -67,7 +67,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
const offeringTrades = useRef<any[]>([]);
|
const offeringTrades = useRef<any[]>([]);
|
||||||
const qortAddressRef = useRef(null);
|
const qortAddressRef = useRef(null);
|
||||||
const gridRef = useRef<any>(null);
|
const gridRef = useRef<any>(null);
|
||||||
const {updateTemporaryFailedTradeBots, fetchTemporarySellOrders, deleteTemporarySellOrder} = useContext(gameContext)
|
const {updateTemporaryFailedTradeBots, fetchTemporarySellOrders, deleteTemporarySellOrder, getCoinLabel, selectedCoin} = useContext(gameContext)
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [info, setInfo] = useState<any>(null)
|
const [info, setInfo] = useState<any>(null)
|
||||||
const filteredOutTradeBotListWithoutFailed = useMemo(() => {
|
const filteredOutTradeBotListWithoutFailed = useMemo(() => {
|
||||||
@ -88,6 +88,51 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content
|
params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
const columnDefs: ColDef[] = useMemo(()=> {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows
|
||||||
|
checkboxSelection: true, // Adds checkboxes in each row for selection
|
||||||
|
headerName: "Select", // You can customize the header name
|
||||||
|
width: 50, // Adjust the width as needed
|
||||||
|
pinned: "left", // Optional, to pin this column on the left
|
||||||
|
resizable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: "QORT AMOUNT",
|
||||||
|
field: "qortAmount",
|
||||||
|
flex: 1, // Flex makes this column responsive
|
||||||
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: `${getCoinLabel()}/QORT`,
|
||||||
|
valueGetter: (params) =>
|
||||||
|
+params.data.foreignAmount / +params.data.qortAmount,
|
||||||
|
sortable: true,
|
||||||
|
sort: "asc",
|
||||||
|
flex: 1, // Flex makes this column responsive
|
||||||
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: `Total ${getCoinLabel()} Value`,
|
||||||
|
field: "foreignAmount",
|
||||||
|
flex: 1, // Flex makes this column responsive
|
||||||
|
minWidth: 150, // Ensure it doesn't shrink too much
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headerName: "Status",
|
||||||
|
field: "status",
|
||||||
|
flex: 1, // Flex makes this column responsive
|
||||||
|
minWidth: 300, // Ensure it doesn't shrink too much
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
}, [selectedCoin])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (qortAddress) {
|
if (qortAddress) {
|
||||||
qortAddressRef.current = qortAddress;
|
qortAddressRef.current = qortAddress;
|
||||||
@ -154,38 +199,64 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
tradeBotListRef.current = sellTrades;
|
tradeBotListRef.current = sellTrades;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const restartTradeOffers = ()=> {
|
||||||
|
if (socketRef.current) {
|
||||||
|
socketRef.current.close(1000, 'forced'); // Close with a custom reason
|
||||||
|
socketRef.current = null
|
||||||
|
}
|
||||||
|
offeringTrades.current = []
|
||||||
|
setTradeBotList([]);
|
||||||
|
tradeBotListRef.current = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const socketRef = useRef(null)
|
||||||
|
|
||||||
const initTradeOffersWebSocket = (restarted = false) => {
|
const initTradeOffersWebSocket = (restarted = false) => {
|
||||||
let tradeOffersSocketCounter = 0;
|
let tradeOffersSocketCounter = 0;
|
||||||
let socketTimeout: any;
|
let socketTimeout: any;
|
||||||
// let socketLink = `ws://127.0.0.1:12391/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`;
|
// let socketLink = `ws://127.0.0.1:12391/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`;
|
||||||
let socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`;
|
let socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradebot?foreignBlockchain=${selectedCoin}`;
|
||||||
const socket = new WebSocket(socketLink);
|
socketRef.current = new WebSocket(socketLink);
|
||||||
socket.onopen = () => {
|
socketRef.current.onopen = () => {
|
||||||
setTimeout(pingSocket, 50);
|
setTimeout(pingSocket, 50);
|
||||||
tradeOffersSocketCounter += 1;
|
tradeOffersSocketCounter += 1;
|
||||||
};
|
};
|
||||||
socket.onmessage = (e) => {
|
socketRef.current.onmessage = (e) => {
|
||||||
tradeOffersSocketCounter += 1;
|
tradeOffersSocketCounter += 1;
|
||||||
restarted = false;
|
restarted = false;
|
||||||
processTradeBots(JSON.parse(e.data));
|
processTradeBots(JSON.parse(e.data));
|
||||||
};
|
};
|
||||||
socket.onclose = () => {
|
socketRef.current.onclose = (event) => {
|
||||||
clearTimeout(socketTimeout);
|
clearTimeout(socketTimeout);
|
||||||
|
if (event.reason === 'forced') {
|
||||||
|
return
|
||||||
|
}
|
||||||
restartTradeOffersWebSocket();
|
restartTradeOffersWebSocket();
|
||||||
};
|
};
|
||||||
socket.onerror = (e) => {
|
socketRef.current.onerror = (e) => {
|
||||||
clearTimeout(socketTimeout);
|
clearTimeout(socketTimeout);
|
||||||
};
|
};
|
||||||
const pingSocket = () => {
|
const pingSocket = () => {
|
||||||
socket.send("ping");
|
socketRef.current.send("ping");
|
||||||
socketTimeout = setTimeout(pingSocket, 295000);
|
socketTimeout = setTimeout(pingSocket, 295000);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!qortAddress) return
|
if(!qortAddress) return
|
||||||
initTradeOffersWebSocket();
|
if(selectedCoin === null) return
|
||||||
}, [qortAddress]);
|
restartTradeOffers()
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
initTradeOffersWebSocket()
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
return () => {
|
||||||
|
if(socketRef.current){
|
||||||
|
socketRef.current.close(1000, 'forced');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [qortAddress, selectedCoin]);
|
||||||
|
|
||||||
const onSelectionChanged = (event: any) => {
|
const onSelectionChanged = (event: any) => {
|
||||||
const selectedRows = event.api.getSelectedRows();
|
const selectedRows = event.api.getSelectedRows();
|
||||||
@ -222,7 +293,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
const res = await qortalRequestWithTimeout({
|
const res = await qortalRequestWithTimeout({
|
||||||
action: "CANCEL_TRADE_SELL_ORDER",
|
action: "CANCEL_TRADE_SELL_ORDER",
|
||||||
qortAmount: selectedTrade.qortAmount,
|
qortAmount: selectedTrade.qortAmount,
|
||||||
foreignBlockchain: 'LITECOIN',
|
foreignBlockchain: selectedTrade.foreignBlockchain,
|
||||||
foreignAmount: selectedTrade.foreignAmount,
|
foreignAmount: selectedTrade.foreignAmount,
|
||||||
atAddress: selectedTrade.atAddress
|
atAddress: selectedTrade.atAddress
|
||||||
}, 900000);
|
}, 900000);
|
||||||
@ -329,7 +400,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
}}>
|
}}>
|
||||||
{/* <Typography sx={{
|
{/* <Typography sx={{
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: selectedTotalLTC > ltcBalance ? 'red' : 'white',
|
color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white',
|
||||||
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
|
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
|
||||||
marginLeft: 'auto'
|
marginLeft: 'auto'
|
||||||
}}>LTC</span></Typography> */}
|
}}>LTC</span></Typography> */}
|
||||||
@ -340,7 +411,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
|
|||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
|
|
||||||
}}><span>{ltcBalance?.toFixed(4)}</span> <span style={{
|
}}><span>{foreignCoinBalance?.toFixed(4)}</span> <span style={{
|
||||||
marginLeft: 'auto'
|
marginLeft: 'auto'
|
||||||
}}>LTC balance</span></Typography> */}
|
}}>LTC balance</span></Typography> */}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -14,7 +14,7 @@ export interface UserNameAvatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IContextProps {
|
export interface IContextProps {
|
||||||
ltcBalance: number | null;
|
foreignCoinBalance: number | null;
|
||||||
qortBalance: number | null;
|
qortBalance: number | null;
|
||||||
userInfo: any;
|
userInfo: any;
|
||||||
setUserInfo: (val: any) => void;
|
setUserInfo: (val: any) => void;
|
||||||
@ -32,11 +32,14 @@ export interface IContextProps {
|
|||||||
updateTemporaryFailedTradeBots: (val: any)=> void;
|
updateTemporaryFailedTradeBots: (val: any)=> void;
|
||||||
fetchTemporarySellOrders: ()=> void;
|
fetchTemporarySellOrders: ()=> void;
|
||||||
isUsingGateway: boolean;
|
isUsingGateway: boolean;
|
||||||
|
selectedCoin: string;
|
||||||
|
setSelectedCoin: (val: any)=> void;
|
||||||
|
getCoinLabel: ()=> void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultState: IContextProps = {
|
const defaultState: IContextProps = {
|
||||||
qortBalance: null,
|
qortBalance: null,
|
||||||
ltcBalance: null,
|
foreignCoinBalance: null,
|
||||||
userInfo: null,
|
userInfo: null,
|
||||||
setUserInfo: () => {},
|
setUserInfo: () => {},
|
||||||
userNameAvatar: {},
|
userNameAvatar: {},
|
||||||
@ -52,7 +55,10 @@ const defaultState: IContextProps = {
|
|||||||
deleteTemporarySellOrder: ()=> {},
|
deleteTemporarySellOrder: ()=> {},
|
||||||
updateTemporaryFailedTradeBots: ()=> {},
|
updateTemporaryFailedTradeBots: ()=> {},
|
||||||
fetchTemporarySellOrders: ()=> {},
|
fetchTemporarySellOrders: ()=> {},
|
||||||
isUsingGateway: true
|
isUsingGateway: true,
|
||||||
|
selectedCoin: 'LITECOIN',
|
||||||
|
setSelectedCoin: ()=> {},
|
||||||
|
getCoinLabel: ()=> {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.createContext(defaultState);
|
export default React.createContext(defaultState);
|
||||||
|
@ -24,7 +24,7 @@ export const HomePage: FC<IsInstalledProps> = ({}) => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const {
|
const {
|
||||||
qortBalance,
|
qortBalance,
|
||||||
ltcBalance,
|
foreignCoinBalance,
|
||||||
userInfo,
|
userInfo,
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
setIsAuthenticated,
|
setIsAuthenticated,
|
||||||
@ -53,7 +53,7 @@ export const HomePage: FC<IsInstalledProps> = ({}) => {
|
|||||||
<AppContainer>
|
<AppContainer>
|
||||||
<Header
|
<Header
|
||||||
qortBalance={qortBalance}
|
qortBalance={qortBalance}
|
||||||
ltcBalance={ltcBalance}
|
foreignCoinBalance={foreignCoinBalance}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
setMode={setMode}
|
setMode={setMode}
|
||||||
/>
|
/>
|
||||||
@ -97,7 +97,7 @@ export const HomePage: FC<IsInstalledProps> = ({}) => {
|
|||||||
</TextTableTitle>
|
</TextTableTitle>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
<TradeOffers ltcBalance={ltcBalance} />
|
<TradeOffers foreignCoinBalance={foreignCoinBalance} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CreateSell show={mode === "sell"} qortAddress={userInfo?.address} />
|
<CreateSell show={mode === "sell"} qortAddress={userInfo?.address} />
|
||||||
|