Fixed bottom UI buy container

This commit is contained in:
Justin Ferrari 2024-12-26 22:52:47 -05:00
parent 7ef7a8b73f
commit a52308d838
6 changed files with 544 additions and 402 deletions

View File

@ -1,5 +1,12 @@
import { Box, styled } from "@mui/system";
import { Typography } from "@mui/material";
import { Button, Typography } from "@mui/material";
export const MainContainer = styled(Box)({
display: "flex",
flexDirection: "column",
width: "100%",
height: "100%",
});
export const TextTableTitle = styled(Typography)(({ theme }) => ({
fontFamily: "Inter",
@ -11,14 +18,39 @@ export const TextTableTitle = styled(Typography)(({ theme }) => ({
}));
export const BuyContainer = styled(Box)({
width: "calc(100% - 60px)",
position: "fixed",
width: "calc(100% - 14px)",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
position: "fixed",
bottom: "0px",
height: "100px",
padding: "7px 14px",
padding: "18px 14px 12px 14px",
background: "#323336",
zIndex: 3
zIndex: 3,
});
export const BuyContainerDivider = styled(Box)({
position: "absolute",
width: "60%",
height: "1px",
background: "lightgray",
top: "10px",
left: "50%",
transform: "translateX(-50%)",
});
export const BuyOrderBtn = styled("button")(({ theme }) => ({
borderRadius: "8px",
width: "74px",
height: "30px",
background: "#4D7345",
color: "white",
cursor: "pointer",
border: "1px solid #375232",
boxShadow: "0px 2.77px 2.21px 0px #00000005",
marginRight: "10px",
[theme.breakpoints.down("sm")]: {
marginRight: "5px",
}
}));

View File

@ -15,8 +15,6 @@ import {
} from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import axios from "axios";
import { sendRequestToExtension } from "../../App";
import {
Alert,
Box,
@ -39,9 +37,15 @@ import { Hourglass } from "react-loader-spinner";
import ErrorIcon from "@mui/icons-material/Error";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import { CountdownCircleTimer } from "react-countdown-circle-timer";
import { BuyContainer } from "./Table-styles";
import {
BuyContainer,
BuyContainerDivider,
BuyOrderBtn,
ContentArea,
MainContainer,
} from "./Table-styles";
export const baseLocalHost = window.location.host
export const baseLocalHost = window.location.host;
// export const baseLocalHost = "127.0.0.1:12391";
interface RowData {
@ -110,23 +114,7 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
const [open, setOpen] = useState(false);
const [info, setInfo] = useState<any>(null);
const BuyButton = () => {
return (
<button
onClick={buyOrder}
style={{
borderRadius: "8px",
width: "74px",
height: "30px",
background: "#4D7345",
color: "white",
cursor: "pointer",
border: "1px solid #375232",
boxShadow: "0px 2.77px 2.21px 0px #00000005",
}}
>
BUY
</button>
);
return <BuyOrderBtn onClick={buyOrder}>BUY</BuyOrderBtn>;
};
const defaultColDef = {
@ -499,13 +487,13 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
const buyOrder = async () => {
try {
if(+foreignCoinBalance < +selectedTotalLTC.toFixed(4)){
setOpen(true)
if (+foreignCoinBalance < +selectedTotalLTC.toFixed(4)) {
setOpen(true);
setInfo({
type: 'error',
message: `You don't have enough ${getCoinLabel()} or your balance was not retrieved`
})
return
type: "error",
message: `You don't have enough ${getCoinLabel()} or your balance was not retrieved`,
});
return;
}
if (selectedOffers?.length < 1) return;
@ -653,11 +641,7 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
};
return (
<Box
sx={{
width: "100%",
}}
>
<MainContainer>
<div
className="ag-theme-alpine-dark"
style={{ height: 400, width: "100%" }}
@ -685,48 +669,76 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
<Button onClick={buyOrder}>Buy</Button>
)} */}
</div>
<div style={{
height: '120px'
}} />
<BuyContainer>
<Box sx={{
display: 'flex',
gap: '5px',
flexDirection: 'column',
width: '100%'
}}>
<Typography sx={{
fontSize: '16px',
color: 'white',
width: 'calc(100% - 75px)'
}}>{selectedTotalQORT?.toFixed(3)} QORT</Typography>
<Box sx={{
display: 'flex',
gap: '20px',
alignItems: 'center',
width: 'calc(100% - 75px)'
}}>
<Typography sx={{
fontSize: '16px',
color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white',
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
marginLeft: 'auto'
}}>{`${getCoinLabel()} `}</span></Typography>
</div>
<div
style={{
height: "120px",
}}
/>
<BuyContainer>
<BuyContainerDivider />
<Box
sx={{
display: "flex",
gap: "5px",
flexDirection: "column",
width: "100%",
}}
>
<Typography
sx={{
fontSize: "16px",
color: "white",
width: "calc(100% - 75px)",
}}
>
{selectedTotalQORT?.toFixed(3)} QORT
</Typography>
<Box
sx={{
display: "flex",
gap: "20px",
alignItems: "center",
width: "calc(100% - 75px)",
}}
>
<Typography
sx={{
fontSize: "16px",
color: selectedTotalLTC > foreignCoinBalance ? "red" : "white",
}}
>
<span>{selectedTotalLTC?.toFixed(4)}</span>{" "}
<span
style={{
marginLeft: "auto",
}}
>{`${getCoinLabel()} `}</span>
</Typography>
</Box>
<Typography
sx={{
fontSize: "16px",
color: "white",
}}
>
<span>{foreignCoinBalance?.toFixed(4)}</span>{" "}
<span
style={{
marginLeft: "auto",
}}
>
{`${getCoinLabel()} `} balance
</span>
</Typography>
</Box>
<Typography sx={{
fontSize: '16px',
color: 'white',
}}><span>{foreignCoinBalance?.toFixed(4)}</span> <span style={{
marginLeft: 'auto'
}}>{`${getCoinLabel()} `} balance</span></Typography>
</Box>
{BuyButton()}
</BuyContainer>
<Snackbar anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} open={open} onClose={handleClose}>
{BuyButton()}
</BuyContainer>
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={open}
onClose={handleClose}
>
<Alert
onClose={handleClose}
severity={info?.type}
@ -826,8 +838,7 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
</Typography>
<Spacer height="20px" />
<Typography>
You can see the progress of your
order in the "Pending" table.
You can see the progress of your order in the "Pending" table.
</Typography>
<Spacer height="20px" />
<Typography>
@ -859,29 +870,34 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
<Spacer height="20px" />
{isUsingGateway && (
<>
<Typography>
Using gateway: might take up to 3 minutes to submit the buy order.
</Typography>
<Spacer height="20px" />
<Box sx={{
width: '100%',
display: 'flex',
justifyContent: 'center'
}}>
<CountdownCircleTimer
isPlaying
duration={180}
colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
colorsTime={[7, 5, 2, 0]}
onComplete={() => {
//nothing
}}
size={60}
strokeWidth={4}
>
{({ remainingTime }) => <Typography>{remainingTime}</Typography>}
</CountdownCircleTimer>
</Box>
<Typography>
Using gateway: might take up to 3 minutes to submit the
buy order.
</Typography>
<Spacer height="20px" />
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
}}
>
<CountdownCircleTimer
isPlaying
duration={180}
colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
colorsTime={[7, 5, 2, 0]}
onComplete={() => {
//nothing
}}
size={60}
strokeWidth={4}
>
{({ remainingTime }) => (
<Typography>{remainingTime}</Typography>
)}
</CountdownCircleTimer>
</Box>
</>
)}
</Box>
@ -905,6 +921,6 @@ export const TradeOffers: React.FC<any> = ({ foreignCoinBalance }: any) => {
</DialogActions>
</Dialog>
)}
</Box>
</MainContainer>
);
};

View File

@ -1,10 +1,24 @@
import { Alert, Box, Button, DialogActions, DialogContent, DialogTitle, IconButton, InputLabel, Snackbar, SnackbarCloseReason, TextField, Typography, styled } from '@mui/material'
import React, { useContext } from 'react'
import { BootstrapDialog } from '../Terms'
import CloseIcon from '@mui/icons-material/Close';
import { Spacer } from '../common/Spacer';
import gameContext from '../../contexts/gameContext';
import TradeBotList from './TradeBotList';
import {
Alert,
Box,
Button,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
InputLabel,
Snackbar,
SnackbarCloseReason,
TextField,
Typography,
styled,
} from "@mui/material";
import React, { useContext } from "react";
import { BootstrapDialog } from "../Terms";
import CloseIcon from "@mui/icons-material/Close";
import { Spacer } from "../common/Spacer";
import gameContext from "../../contexts/gameContext";
import TradeBotList from "./TradeBotList";
export const CustomLabel = styled(InputLabel)`
font-weight: 400;
@ -12,13 +26,12 @@ export const CustomLabel = styled(InputLabel)`
font-size: 10px;
line-height: 12px;
color: rgba(255, 255, 255, 0.5);
`
`;
export const minimumAmountSellTrades = {
'LITECOIN': {
LITECOIN: {
value: 0.01,
ticker: 'LTC'
ticker: "LTC",
},
DOGECOIN: {
value: 1,
@ -40,168 +53,186 @@ export const minimumAmountSellTrades = {
value: 0.0002,
ticker: "ARRR",
},
}
};
export const CustomInput = styled(TextField)({
width: "183px", // Adjust the width as needed
borderRadius: "5px",
// backgroundColor: "rgba(30, 30, 32, 1)",
width: "183px", // Adjust the width as needed
borderRadius: "5px",
// backgroundColor: "rgba(30, 30, 32, 1)",
outline: "none",
input: {
fontSize: 10,
fontFamily: "Inter",
fontWeight: 400,
color: "white",
"&::placeholder": {
fontSize: 16,
color: "rgba(255, 255, 255, 0.2)",
},
outline: "none",
input: {
fontSize: 10,
fontFamily: "Inter",
fontWeight: 400,
color: "white",
"&::placeholder": {
fontSize: 16,
color: "rgba(255, 255, 255, 0.2)",
},
outline: "none",
padding: "10px",
padding: "10px",
},
"& .MuiOutlinedInput-root": {
"& fieldset": {
border: "0.5px solid rgba(255, 255, 255, 0.5)",
},
"& .MuiOutlinedInput-root": {
"& fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
"&:hover fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
"&.Mui-focused fieldset": {
border: '0.5px solid rgba(255, 255, 255, 0.5)',
},
"&:hover fieldset": {
border: "0.5px solid rgba(255, 255, 255, 0.5)",
},
"& .MuiInput-underline:before": {
borderBottom: "none",
"&.Mui-focused fieldset": {
border: "0.5px solid rgba(255, 255, 255, 0.5)",
},
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
borderBottom: "none",
},
"& .MuiInput-underline:after": {
borderBottom: "none",
},
});
},
"& .MuiInput-underline:before": {
borderBottom: "none",
},
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
borderBottom: "none",
},
"& .MuiInput-underline:after": {
borderBottom: "none",
},
});
export const CreateSell = ({ qortAddress, show }) => {
const [open, setOpen] = React.useState(false);
const [qortAmount, setQortAmount] = React.useState(0);
const [foreignAmount, setForeignAmount] = React.useState(0);
const {
updateTemporaryFailedTradeBots,
sellOrders,
fetchTemporarySellOrders,
isUsingGateway,
getCoinLabel,
selectedCoin,
} = useContext(gameContext);
const [openAlert, setOpenAlert] = React.useState(false);
const [info, setInfo] = React.useState<any>(null);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
setForeignAmount(0);
setQortAmount(0);
};
export const CreateSell = ({qortAddress, show}) => {
const [open, setOpen] = React.useState(false);
const [qortAmount, setQortAmount] = React.useState(0)
const [foreignAmount, setForeignAmount] = React.useState(0)
const {updateTemporaryFailedTradeBots, sellOrders, fetchTemporarySellOrders, isUsingGateway, getCoinLabel, selectedCoin} = useContext(gameContext)
const [openAlert, setOpenAlert] = React.useState(false)
const [info, setInfo] = React.useState<any>(null)
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
setForeignAmount(0)
setQortAmount(0)
};
const createSellOrder = async () => {
try {
setInfo({
type: "info",
message: "Attempting to create sell order. Please wait...",
});
const res = await qortalRequestWithTimeout(
{
action: "CREATE_TRADE_SELL_ORDER",
qortAmount,
foreignBlockchain: selectedCoin,
foreignAmount: qortAmount * foreignAmount,
},
900000
);
const createSellOrder = async() => {
try {
setInfo({
type: 'info',
message: "Attempting to create sell order. Please wait..."
})
const res = await qortalRequestWithTimeout({
action: "CREATE_TRADE_SELL_ORDER",
qortAmount,
foreignBlockchain: selectedCoin,
foreignAmount: qortAmount * foreignAmount
}, 900000);
if(res?.error && res?.failedTradeBot){
await updateTemporaryFailedTradeBots({
atAddress: res?.failedTradeBot?.atAddress,
status: 'FAILED',
qortAddress: res?.failedTradeBot?.creatorAddress,
})
fetchTemporarySellOrders()
setOpenAlert(true)
setInfo({
type: 'error',
message: "Unable to create sell order. Please try again."
})
}
if(!res?.error){
setOpenAlert(true)
setForeignAmount(0)
setQortAmount(0)
setOpen(false)
setInfo({
type: 'success',
message: "Sell order created. Please wait a couple of minutes for the network to propogate the changes."
})
}
} catch (error) {
if(error?.error && error?.failedTradeBot){
await updateTemporaryFailedTradeBots({
atAddress: error?.failedTradeBot?.atAddress,
status: 'FAILED',
qortAddress: error?.failedTradeBot?.creatorAddress,
})
fetchTemporarySellOrders()
setOpenAlert(true)
setInfo({
type: 'error',
message: "Unable to create sell order. Please try again."
})
}
}
}
const handleCloseAlert = (
event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
if (res?.error && res?.failedTradeBot) {
await updateTemporaryFailedTradeBots({
atAddress: res?.failedTradeBot?.atAddress,
status: "FAILED",
qortAddress: res?.failedTradeBot?.creatorAddress,
});
fetchTemporarySellOrders();
setOpenAlert(true);
setInfo({
type: "error",
message: "Unable to create sell order. Please try again.",
});
}
if (!res?.error) {
setOpenAlert(true);
setForeignAmount(0);
setQortAmount(0);
setOpen(false);
setOpenAlert(false);
setInfo(null)
};
if(isUsingGateway){
return (
<div style={{
width: '100%',
display: show ? 'flex' : 'none',
height: '500px',
alignItems: 'center',
justifyContent: 'center',
}}>
<Typography sx={{
color: 'white',
maxWidth: '340px',
padding: '10px'
}}>
Managing your sell orders is not possible using a gateway node. Please switch to a local or custom node at the authentication page
</Typography>
</div>
)
setInfo({
type: "success",
message:
"Sell order created. Please wait a couple of minutes for the network to propogate the changes.",
});
}
} catch (error) {
if (error?.error && error?.failedTradeBot) {
await updateTemporaryFailedTradeBots({
atAddress: error?.failedTradeBot?.atAddress,
status: "FAILED",
qortAddress: error?.failedTradeBot?.creatorAddress,
});
fetchTemporarySellOrders();
setOpenAlert(true);
setInfo({
type: "error",
message: "Unable to create sell order. Please try again.",
});
}
}
return (
<div style={{
width: '100%',
display: show ? 'block' : 'none'
}}>
<Button onClick={handleClickOpen}>New Sell Order</Button>
<TradeBotList qortAddress={qortAddress} failedTradeBots={sellOrders.filter((item)=> item.status === 'FAILED')} />
};
<BootstrapDialog
const handleCloseAlert = (
event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason
) => {
if (reason === "clickaway") {
return;
}
setOpenAlert(false);
setInfo(null);
};
if (isUsingGateway) {
return (
<div
style={{
width: "100%",
display: show ? "flex" : "none",
height: "500px",
alignItems: "flex-start",
marginTop: "20px",
justifyContent: "center",
}}
>
<Typography
sx={{
color: "white",
maxWidth: "340px",
padding: "10px",
}}
>
Managing your sell orders is not possible using a gateway node. Please
switch to a local or custom node at the authentication page
</Typography>
</div>
);
}
return (
<div
style={{
width: "100%",
display: show ? "block" : "none",
}}
>
<Button onClick={handleClickOpen}>New Sell Order</Button>
<TradeBotList
qortAddress={qortAddress}
failedTradeBots={sellOrders.filter((item) => item.status === "FAILED")}
/>
<BootstrapDialog
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
sx={{
'& .MuiDialogContent-root': {
width: '300px'
},
"& .MuiDialogContent-root": {
width: "300px",
},
}}
>
<DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
@ -211,7 +242,7 @@ export const CreateSell = ({qortAddress, show}) => {
aria-label="close"
onClick={handleClose}
sx={(theme) => ({
position: 'absolute',
position: "absolute",
right: 8,
top: 8,
color: theme.palette.grey[500],
@ -220,8 +251,10 @@ export const CreateSell = ({qortAddress, show}) => {
<CloseIcon />
</IconButton>
<DialogContent dividers>
<Box>
<CustomLabel htmlFor="standard-adornment-name">QORT amount</CustomLabel>
<Box>
<CustomLabel htmlFor="standard-adornment-name">
QORT amount
</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
@ -243,34 +276,54 @@ export const CreateSell = ({qortAddress, show}) => {
autoComplete="off"
/>
<Spacer height="6px" />
<Typography>{`${qortAmount * foreignAmount} ${getCoinLabel()}`} for {qortAmount} QORT</Typography>
<Typography sx={{
fontSize: '14px'
}}>Total sell amount needs to be greater than: {minimumAmountSellTrades[selectedCoin]?.value} {' '} {minimumAmountSellTrades[selectedCoin]?.ticker}</Typography>
<Typography>
{`${qortAmount * foreignAmount} ${getCoinLabel()}`} for{" "}
{qortAmount} QORT
</Typography>
<Typography
sx={{
fontSize: "14px",
}}
>
Total sell amount needs to be greater than:{" "}
{minimumAmountSellTrades[selectedCoin]?.value}{" "}
{minimumAmountSellTrades[selectedCoin]?.ticker}
</Typography>
</Box>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleClose}>
Close
</Button>
<Button disabled={!qortAmount || !(qortAmount * foreignAmount > minimumAmountSellTrades[selectedCoin]?.value)} autoFocus onClick={createSellOrder}>
<Button
disabled={
!qortAmount ||
!(
qortAmount * foreignAmount >
minimumAmountSellTrades[selectedCoin]?.value
)
}
autoFocus
onClick={createSellOrder}
>
Create sell order
</Button>
</DialogActions>
</BootstrapDialog>
<Snackbar anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} open={openAlert} onClose={handleCloseAlert}>
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={openAlert}
onClose={handleCloseAlert}
>
<Alert
onClose={handleCloseAlert}
severity={info?.type}
variant="filled"
sx={{ width: '100%' }}
sx={{ width: "100%" }}
>
{info?.message}
</Alert>
</Snackbar>
</div>
)
}
);
};

View File

@ -9,8 +9,15 @@ import React, {
useState,
} from "react";
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 { BuyContainerDivider } from "../Grids/Table-styles";
const defaultColDef = {
resizable: true, // Make columns resizable by default
@ -18,18 +25,22 @@ const defaultColDef = {
suppressMovable: true, // Prevent columns from being movable
};
export default function TradeBotList({ qortAddress, failedTradeBots }) {
const [tradeBotList, setTradeBotList] = useState([]);
const [selectedTrade, setSelectedTrade] = useState(null);
const tradeBotListRef = useRef([])
const tradeBotListRef = useRef([]);
const offeringTrades = useRef<any[]>([]);
const qortAddressRef = useRef(null);
const gridRef = useRef<any>(null);
const {updateTemporaryFailedTradeBots, fetchTemporarySellOrders, deleteTemporarySellOrder, getCoinLabel, selectedCoin} = useContext(gameContext)
const [open, setOpen] = useState(false)
const [info, setInfo] = useState<any>(null)
const {
updateTemporaryFailedTradeBots,
fetchTemporarySellOrders,
deleteTemporarySellOrder,
getCoinLabel,
selectedCoin,
} = useContext(gameContext);
const [open, setOpen] = useState(false);
const [info, setInfo] = useState<any>(null);
const filteredOutTradeBotListWithoutFailed = useMemo(() => {
const list = tradeBotList.filter(
(item) =>
@ -37,7 +48,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
(failedItem) => failedItem.atAddress === item.atAddress
)
);
return list
return list;
}, [failedTradeBots, tradeBotList]);
const onGridReady = useCallback((params: any) => {
@ -48,8 +59,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
params.columnApi.autoSizeColumns(allColumnIds); // Automatically adjust the width to fit content
}, []);
const columnDefs: ColDef[] = useMemo(()=> {
const columnDefs: ColDef[] = useMemo(() => {
return [
{
headerCheckboxSelection: false, // Adds a checkbox in the header for selecting all rows
@ -91,8 +101,7 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
resizable: true,
},
];
}, [selectedCoin])
}, [selectedCoin]);
useEffect(() => {
if (qortAddress) {
qortAddressRef.current = qortAddress;
@ -159,23 +168,25 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
tradeBotListRef.current = sellTrades;
};
const restartTradeOffers = ()=> {
const restartTradeOffers = () => {
if (socketRef.current) {
socketRef.current.close(1000, 'forced'); // Close with a custom reason
socketRef.current = null
socketRef.current.close(1000, "forced"); // Close with a custom reason
socketRef.current = null;
}
offeringTrades.current = []
offeringTrades.current = [];
setTradeBotList([]);
tradeBotListRef.current = [];
}
};
const socketRef = useRef(null)
const socketRef = useRef(null);
const initTradeOffersWebSocket = (restarted = false) => {
let tradeOffersSocketCounter = 0;
let socketTimeout: any;
// let socketLink = `ws://127.0.0.1:12391/websockets/crosschain/tradebot?foreignBlockchain=LITECOIN`;
let socketLink = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${baseLocalHost}/websockets/crosschain/tradebot?foreignBlockchain=${selectedCoin}`;
let socketLink = `${
window.location.protocol === "https:" ? "wss:" : "ws:"
}//${baseLocalHost}/websockets/crosschain/tradebot?foreignBlockchain=${selectedCoin}`;
socketRef.current = new WebSocket(socketLink);
socketRef.current.onopen = () => {
setTimeout(pingSocket, 50);
@ -188,8 +199,8 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
};
socketRef.current.onclose = (event) => {
clearTimeout(socketTimeout);
if (event.reason === 'forced') {
return
if (event.reason === "forced") {
return;
}
restartTradeOffersWebSocket();
};
@ -203,94 +214,113 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
};
useEffect(() => {
if(!qortAddress) return
if(selectedCoin === null) return
restartTradeOffers()
setTimeout(() => {
initTradeOffersWebSocket()
if (!qortAddress) return;
if (selectedCoin === null) return;
restartTradeOffers();
setTimeout(() => {
initTradeOffersWebSocket();
}, 500);
return () => {
if(socketRef.current){
socketRef.current.close(1000, 'forced');
return () => {
if (socketRef.current) {
socketRef.current.close(1000, "forced");
}
}
};
}, [qortAddress, selectedCoin]);
const onSelectionChanged = (event: any) => {
const selectedRows = event.api.getSelectedRows();
if(selectedRows[0]){
setSelectedTrade(selectedRows[0])
if (selectedRows[0]) {
setSelectedTrade(selectedRows[0]);
} else {
setSelectedTrade(null)
setSelectedTrade(null);
}
};
const handleClose = (
event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
reason?: SnackbarCloseReason
) => {
if (reason === 'clickaway') {
if (reason === "clickaway") {
return;
}
setOpen(false);
setInfo(null)
setInfo(null);
};
const cancelSell = async ()=> {
const cancelSell = async () => {
try {
if(!selectedTrade) return
setOpen(true)
if (!selectedTrade) return;
setOpen(true);
setInfo({
type: 'info',
message: "Attempting to cancel sell order"
})
const res = await qortalRequestWithTimeout({
action: "CANCEL_TRADE_SELL_ORDER",
qortAmount: selectedTrade.qortAmount,
foreignBlockchain: selectedTrade.foreignBlockchain,
foreignAmount: selectedTrade.foreignAmount,
atAddress: selectedTrade.atAddress
}, 900000);
if(res?.signature){
await deleteTemporarySellOrder(selectedTrade.atAddress)
setSelectedTrade(null)
setOpen(true)
setInfo({
type: 'success',
message: "Sell order canceled. Please wait a couple of minutes for the network to propogate the changes"
})
}
if(res?.error && res?.failedTradeBot){
setOpen(true)
setInfo({
type: 'error',
message: "Unable to cancel sell order. Please try again."
})
}
} catch (error) {
if(error?.error && error?.failedTradeBot){
setOpen(true)
setInfo({
type: 'error',
message: "Unable to cancel sell order. Please try again."
})
}
}
}
type: "info",
message: "Attempting to cancel sell order",
});
const res = await qortalRequestWithTimeout(
{
action: "CANCEL_TRADE_SELL_ORDER",
qortAmount: selectedTrade.qortAmount,
foreignBlockchain: selectedTrade.foreignBlockchain,
foreignAmount: selectedTrade.foreignAmount,
atAddress: selectedTrade.atAddress,
},
900000
);
if (res?.signature) {
await deleteTemporarySellOrder(selectedTrade.atAddress);
setSelectedTrade(null);
setOpen(true);
setInfo({
type: "success",
message:
"Sell order canceled. Please wait a couple of minutes for the network to propogate the changes",
});
}
if (res?.error && res?.failedTradeBot) {
setOpen(true);
setInfo({
type: "error",
message: "Unable to cancel sell order. Please try again.",
});
}
} catch (error) {
if (error?.error && error?.failedTradeBot) {
setOpen(true);
setInfo({
type: "error",
message: "Unable to cancel sell order. Please try again.",
});
}
}
};
const CancelButton = () => {
return (
<button disabled={!selectedTrade || selectedTrade?.status === 'PENDING'} onClick={cancelSell} style={{borderRadius: '8px', width: '150px', height:"30px", background: (!selectedTrade || selectedTrade?.status === 'PENDING') ? 'gray' : "#4D7345",
color: 'white', cursor: (!selectedTrade || selectedTrade?.status === 'PENDING') ? 'default' : 'pointer', border: '1px solid #375232', boxShadow: '0px 2.77px 2.21px 0px #00000005'
}}>
<button
disabled={!selectedTrade || selectedTrade?.status === "PENDING"}
onClick={cancelSell}
style={{
borderRadius: "8px",
width: "150px",
height: "auto",
minHeight: "30px",
background:
!selectedTrade || selectedTrade?.status === "PENDING"
? "gray"
: "#4D7345",
color: "white",
cursor:
!selectedTrade || selectedTrade?.status === "PENDING"
? "default"
: "pointer",
border: "1px solid #375232",
boxShadow: "0px 2.77px 2.21px 0px #00000005",
marginRight: "15px",
}}
>
Cancel sell order
</button>
);
@ -329,62 +359,73 @@ export default function TradeBotList({ qortAddress, failedTradeBots }) {
)} */}
</div>
<Box sx={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
position: 'fixed',
bottom: '0px',
height: '100px',
padding: '7px',
background: '#181d1f',
}}>
<Box sx={{
display: 'flex',
gap: '5px',
flexDirection: 'column',
width: '100%'
}}>
{/* <Typography sx={{
<div
style={{
height: "120px",
}}
/>
<Box
sx={{
width: "calc(100% - 14px)",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
position: "fixed",
bottom: "0px",
height: "100px",
padding: "7px",
background: "#323336",
}}
>
<BuyContainerDivider />
<Box
sx={{
display: "flex",
gap: "5px",
flexDirection: "column",
width: "100%",
}}
>
{/* <Typography sx={{
fontSize: '16px',
color: 'white',
width: 'calc(100% - 75px)'
}}>{selectedTotalQORT?.toFixed(3)} QORT</Typography> */}
<Box sx={{
display: 'flex',
gap: '20px',
alignItems: 'center',
width: 'calc(100% - 75px)'
}}>
{/* <Typography sx={{
<Box
sx={{
display: "flex",
gap: "20px",
alignItems: "center",
width: "calc(100% - 75px)",
}}
>
{/* <Typography sx={{
fontSize: '16px',
color: selectedTotalLTC > foreignCoinBalance ? 'red' : 'white',
}}><span>{selectedTotalLTC?.toFixed(4)}</span> <span style={{
marginLeft: 'auto'
}}>LTC</span></Typography> */}
</Box>
{/* <Typography sx={{
</Box>
{/* <Typography sx={{
fontSize: '16px',
color: 'white',
}}><span>{foreignCoinBalance?.toFixed(4)}</span> <span style={{
marginLeft: 'auto'
}}>LTC balance</span></Typography> */}
</Box>
{CancelButton()}
</Box>
{CancelButton()}
</Box>
<Snackbar anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} open={open} onClose={handleClose}>
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={open}
onClose={handleClose}
>
<Alert
onClose={handleClose}
severity={info?.type}
variant="filled"
sx={{ width: '100%' }}
sx={{ width: "100%" }}
>
{info?.message}
</Alert>

View File

@ -69,7 +69,6 @@ export const HomeWrapper = styled(Box)({
export const TabsContainer = styled(Box)({
display: "flex",
flexDirection: "column",
gap: "15px",
alignItems: "flex-start",
width: "100%",
justifyContent: "center",
@ -78,6 +77,7 @@ export const TabsContainer = styled(Box)({
export const TabsRow = styled(Box)({
display: "flex",
flexDirection: "row",
gap: "5px",
justifyContent: "space-evenly",
alignItems: "center",
backgroundColor: "#323336",

View File

@ -58,17 +58,17 @@ export const HomePage = () => {
<Tab activeTab={mode === "buy"} onClick={() => setMode("buy")}>
Buy QORT
</Tab>
<TabDivider activeTab={mode === "buy" || mode === "sell"} />
{/* <TabDivider activeTab={mode === "buy" || mode === "sell"} /> */}
<Tab activeTab={mode === "sell"} onClick={() => setMode("sell")}>
Sell QORT
</Tab>
<TabDivider activeTab={mode === "sell" || mode === "history"} />
<Tab
{/* <TabDivider activeTab={mode === "sell" || mode === "history"} /> */}
{/* <Tab
activeTab={mode === "history"}
onClick={() => setMode("history")}
>
Trade History
</Tab>
</Tab> */}
</TabsRow>
</TabsContainer>
<div