mirror of
https://github.com/Qortal/q-trade.git
synced 2025-06-16 11:21:22 +00:00
added stuck sell order table
This commit is contained in:
parent
e0ab3846d7
commit
733c49e33c
10
package-lock.json
generated
10
package-lock.json
generated
@ -28,6 +28,7 @@
|
|||||||
"react-qr-code": "^2.0.15",
|
"react-qr-code": "^2.0.15",
|
||||||
"react-router-dom": "^6.23.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
|
"react-virtuoso": "^4.12.7",
|
||||||
"sass": "^1.76.0",
|
"sass": "^1.76.0",
|
||||||
"short-unique-id": "^5.2.0",
|
"short-unique-id": "^5.2.0",
|
||||||
"socket.io-client": "^4.7.5"
|
"socket.io-client": "^4.7.5"
|
||||||
@ -6846,6 +6847,15 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-virtuoso": {
|
||||||
|
"version": "4.12.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.7.tgz",
|
||||||
|
"integrity": "sha512-njJp764he6Fi1p89PUW0k2kbyWu9w/y+MwdxmwK2kvdwwzVDbz2c2wMj5xdSruBFVgFTsI7Z85hxZR7aSHBrbQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16 || >=17 || >= 18 || >= 19",
|
||||||
|
"react-dom": ">=16 || >=17 || >= 18 || >=19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"react-qr-code": "^2.0.15",
|
"react-qr-code": "^2.0.15",
|
||||||
"react-router-dom": "^6.23.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
|
"react-virtuoso": "^4.12.7",
|
||||||
"sass": "^1.76.0",
|
"sass": "^1.76.0",
|
||||||
"short-unique-id": "^5.2.0",
|
"short-unique-id": "^5.2.0",
|
||||||
"socket.io-client": "^4.7.5"
|
"socket.io-client": "^4.7.5"
|
||||||
|
@ -56,12 +56,15 @@ import {
|
|||||||
|
|
||||||
export const baseLocalHost = window.location.host;
|
export const baseLocalHost = window.location.host;
|
||||||
// export const baseLocalHost = "devnet-nodes.qortal.link:11111";
|
// export const baseLocalHost = "devnet-nodes.qortal.link:11111";
|
||||||
|
// export const baseLocalHost = "127.0.0.1:12391";
|
||||||
|
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
|
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { RequestQueueWithPromise } from "qapp-core";
|
import { RequestQueueWithPromise } from "qapp-core";
|
||||||
import { useUpdateFee } from "../../hooks/useUpdateFee";
|
import { useUpdateFee } from "../../hooks/useUpdateFee";
|
||||||
|
import { useSetAtom } from "jotai/react";
|
||||||
|
import { stuckTradesAtom } from "../../global/state";
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
@ -97,6 +100,7 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
const [offers, setOffers] = useState<any[]>([]);
|
const [offers, setOffers] = useState<any[]>([]);
|
||||||
const [signedUnlockingFees, setSignedUnlockingFees] = useState(null);
|
const [signedUnlockingFees, setSignedUnlockingFees] = useState(null);
|
||||||
const [qortalNames, setQortalNames] = useState({});
|
const [qortalNames, setQortalNames] = useState({});
|
||||||
|
const setStuckTrades = useSetAtom(stuckTradesAtom)
|
||||||
const {
|
const {
|
||||||
fetchOngoingTransactions,
|
fetchOngoingTransactions,
|
||||||
onGoingTrades,
|
onGoingTrades,
|
||||||
@ -448,6 +452,10 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
return offeringTrade.tradePresenceExpiry > Date.now();
|
return offeringTrade.tradePresenceExpiry > Date.now();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterForStuckDrades = (offeringTrade: any) => {
|
||||||
|
return (!offeringTrade?.tradePresenceExpiry || offeringTrade.tradePresenceExpiry < Date.now());
|
||||||
|
};
|
||||||
|
|
||||||
const startOfferPresenceMapping = async () => {
|
const startOfferPresenceMapping = async () => {
|
||||||
if (tradePresenceTxns.current) {
|
if (tradePresenceTxns.current) {
|
||||||
for (const tradePresence of tradePresenceTxns.current) {
|
for (const tradePresence of tradePresenceTxns.current) {
|
||||||
@ -467,6 +475,11 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
offeringTrades.current?.filter((offeringTrade) =>
|
offeringTrades.current?.filter((offeringTrade) =>
|
||||||
filterOffersUsingTradePresence(offeringTrade)
|
filterOffersUsingTradePresence(offeringTrade)
|
||||||
) || [];
|
) || [];
|
||||||
|
|
||||||
|
const stuckTrades = offeringTrades.current?.filter((offeringTrade) =>
|
||||||
|
filterForStuckDrades(offeringTrade)
|
||||||
|
) || [];
|
||||||
|
setStuckTrades(stuckTrades?.sort((a, b) => b.timestamp - a.timestamp))
|
||||||
let tradesPresenceCleaned: any[] = filteredOffers;
|
let tradesPresenceCleaned: any[] = filteredOffers;
|
||||||
|
|
||||||
blockedTradesList.current.forEach((item: any) => {
|
blockedTradesList.current.forEach((item: any) => {
|
||||||
@ -549,10 +562,10 @@ export const TradeOffers: React.FC<any> = ({
|
|||||||
socketRef.current.onmessage = (e) => {
|
socketRef.current.onmessage = (e) => {
|
||||||
offeringTrades.current = [
|
offeringTrades.current = [
|
||||||
...offeringTrades.current?.filter(
|
...offeringTrades.current?.filter(
|
||||||
(coin) => coin?.foreignBlockchain === selectedCoin
|
(coin) => coin?.foreignBlockchain === selectedCoin && coin?.mode === 'OFFERING'
|
||||||
),
|
),
|
||||||
...JSON.parse(e.data)?.filter(
|
...JSON.parse(e.data)?.filter(
|
||||||
(coin) => coin?.foreignBlockchain === selectedCoin
|
(coin) => coin?.foreignBlockchain === selectedCoin && coin?.mode === 'OFFERING'
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
restarted = false;
|
restarted = false;
|
||||||
|
@ -69,6 +69,8 @@ import UnsignedFees from "../sell/UnsignedFees";
|
|||||||
import { FeeManager } from "../sell/FeeManager";
|
import { FeeManager } from "../sell/FeeManager";
|
||||||
import { Info } from "../sell/Info";
|
import { Info } from "../sell/Info";
|
||||||
import { Settings } from "../sell/Settings";
|
import { Settings } from "../sell/Settings";
|
||||||
|
import { useSetAtom } from "jotai/react";
|
||||||
|
import { stuckTradesAtom } from "../../global/state";
|
||||||
|
|
||||||
const checkIfLocal = async () => {
|
const checkIfLocal = async () => {
|
||||||
try {
|
try {
|
||||||
@ -171,6 +173,8 @@ export const Header = ({
|
|||||||
const [amount, setAmount] = useState<string>("");
|
const [amount, setAmount] = useState<string>("");
|
||||||
const [coinAddresses, setCoinAddresses] = useState({});
|
const [coinAddresses, setCoinAddresses] = useState({});
|
||||||
const { isUsingGateway } = useContext(gameContext);
|
const { isUsingGateway } = useContext(gameContext);
|
||||||
|
const setStuckTrades = useSetAtom(stuckTradesAtom)
|
||||||
|
|
||||||
|
|
||||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setChecked(false);
|
setChecked(false);
|
||||||
@ -492,6 +496,7 @@ export const Header = ({
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setFee(null)
|
setFee(null)
|
||||||
setSelectedCoin(e.target.value)
|
setSelectedCoin(e.target.value)
|
||||||
|
setStuckTrades([])
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem value={"LITECOIN"}>
|
<MenuItem value={"LITECOIN"}>
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
IconButton,
|
IconButton,
|
||||||
InputLabel,
|
InputLabel,
|
||||||
@ -13,12 +14,16 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
styled,
|
styled,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import React, { useContext } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import { BootstrapDialog } from "../Terms";
|
import { BootstrapDialog } from "../Terms";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { Spacer } from "../common/Spacer";
|
import { Spacer } from "../common/Spacer";
|
||||||
import gameContext from "../../contexts/gameContext";
|
import gameContext from "../../contexts/gameContext";
|
||||||
import TradeBotList from "./TradeBotList";
|
import TradeBotList from "./TradeBotList";
|
||||||
|
import { stuckTradesAtom } from "../../global/state";
|
||||||
|
import { useAtom } from "jotai/react";
|
||||||
|
import { StuckOrdersTable } from "./StuckOrdersTable";
|
||||||
|
import { useGlobal } from "qapp-core";
|
||||||
|
|
||||||
export const CustomLabel = styled(InputLabel)`
|
export const CustomLabel = styled(InputLabel)`
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@ -97,6 +102,7 @@ export const CustomInput = styled(TextField)({
|
|||||||
|
|
||||||
export const CreateSell = ({ qortAddress, show }) => {
|
export const CreateSell = ({ qortAddress, show }) => {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const [openStuckOrders, setOpenStuckOrders] = 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 {
|
const {
|
||||||
@ -220,7 +226,21 @@ export const CreateSell = ({ qortAddress, show }) => {
|
|||||||
display: show ? "block" : "none",
|
display: show ? "block" : "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button onClick={handleClickOpen}>New Sell Order</Button>
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
}}>
|
||||||
|
<Button sx={{
|
||||||
|
margin: '10px 0px'
|
||||||
|
}} variant="outlined" onClick={handleClickOpen}>New Sell Order</Button>
|
||||||
|
{!isUsingGateway && (
|
||||||
|
<Button sx={{
|
||||||
|
margin: '10px 0px'
|
||||||
|
}} variant="outlined" onClick={()=> setOpenStuckOrders(true)}>Stuck orders</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Box>
|
||||||
<TradeBotList
|
<TradeBotList
|
||||||
qortAddress={qortAddress}
|
qortAddress={qortAddress}
|
||||||
failedTradeBots={sellOrders.filter((item) => item.status === "FAILED")}
|
failedTradeBots={sellOrders.filter((item) => item.status === "FAILED")}
|
||||||
@ -325,6 +345,55 @@ export const CreateSell = ({ qortAddress, show }) => {
|
|||||||
{info?.message}
|
{info?.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
|
{openStuckOrders && (
|
||||||
|
<StuckOrders setOpenStuckOrders={setOpenStuckOrders} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const StuckOrders = ({setOpenStuckOrders})=> {
|
||||||
|
const [stuckTrades] = useAtom(stuckTradesAtom)
|
||||||
|
const address = useGlobal().auth.address
|
||||||
|
const filteredByAddress = stuckTrades?.filter((item)=> item?.qortalCreator === address)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BootstrapDialog
|
||||||
|
aria-labelledby="customized-dialog-title"
|
||||||
|
open={true}
|
||||||
|
maxWidth="lg"
|
||||||
|
fullWidth={true}
|
||||||
|
>
|
||||||
|
<DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
|
||||||
|
Stuck sell orders
|
||||||
|
</DialogTitle>
|
||||||
|
<IconButton
|
||||||
|
aria-label="close"
|
||||||
|
onClick={()=> setOpenStuckOrders(false)}
|
||||||
|
sx={(theme) => ({
|
||||||
|
position: "absolute",
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
color: theme.palette.grey[500],
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
<DialogContent dividers>
|
||||||
|
<DialogContentText></DialogContentText>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
{filteredByAddress?.length === 0 && (
|
||||||
|
<DialogContentText>No stuck trades</DialogContentText>
|
||||||
|
)}
|
||||||
|
<Spacer height="20px" />
|
||||||
|
<StuckOrdersTable data={filteredByAddress} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button autoFocus onClick={()=> setOpenStuckOrders(false)}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</BootstrapDialog>
|
||||||
|
)
|
||||||
|
}
|
@ -83,7 +83,10 @@ export const FeeManager = ({ selectedCoin, setFee, fee }) => {
|
|||||||
const [openModal, setOpenModal] = useState(false);
|
const [openModal, setOpenModal] = useState(false);
|
||||||
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
||||||
|
|
||||||
const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selectedCoin, recommendedFee})
|
const { hideRecommendations, recommendedFeeDisplay } = useRecommendedFees({
|
||||||
|
selectedCoin,
|
||||||
|
recommendedFee,
|
||||||
|
});
|
||||||
|
|
||||||
const [openAlert, setOpenAlert] = useState(false);
|
const [openAlert, setOpenAlert] = useState(false);
|
||||||
const [info, setInfo] = useState<any>(null);
|
const [info, setInfo] = useState<any>(null);
|
||||||
@ -143,10 +146,6 @@ const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selecte
|
|||||||
establishUpdateFeeForm(coin);
|
establishUpdateFeeForm(coin);
|
||||||
}, [coin, establishUpdateFeeForm]);
|
}, [coin, establishUpdateFeeForm]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hideRecommendations) {
|
if (hideRecommendations) {
|
||||||
setRecommendedFee("custom");
|
setRecommendedFee("custom");
|
||||||
@ -158,13 +157,12 @@ const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selecte
|
|||||||
const typeRequestLocking = "feekb";
|
const typeRequestLocking = "feekb";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let feeToSave = editFee;
|
let feeToSave = editFee;
|
||||||
if (recommendedFee !== "custom") {
|
if (recommendedFee !== "custom") {
|
||||||
feeToSave = calculateFeeFromRate(recommendedFeeDisplay, 300);
|
feeToSave = calculateFeeFromRate(recommendedFeeDisplay, 300);
|
||||||
}
|
}
|
||||||
if (+fee === +feeToSave) {
|
if (+fee === +feeToSave) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const response = await qortalRequestWithTimeout(
|
const response = await qortalRequestWithTimeout(
|
||||||
{
|
{
|
||||||
@ -215,8 +213,6 @@ const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selecte
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (fee === null || fee === undefined) return;
|
if (fee === null || fee === undefined) return;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -274,6 +270,18 @@ const {hideRecommendations, recommendedFeeDisplay} = useRecommendedFees({selecte
|
|||||||
</Typography>
|
</Typography>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
</CoinActionRow>
|
</CoinActionRow>
|
||||||
|
<CoinActionRow>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>current fee: {fee}</Typography>
|
||||||
|
</Box>
|
||||||
|
</CoinActionRow>
|
||||||
<CoinActionRow>
|
<CoinActionRow>
|
||||||
<HeaderRow>
|
<HeaderRow>
|
||||||
<Box
|
<Box
|
||||||
|
@ -52,10 +52,13 @@ export const Settings = () => {
|
|||||||
const [lockingFee, setLockingFee] = useState("");
|
const [lockingFee, setLockingFee] = useState("");
|
||||||
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
const [recommendedFee, setRecommendedFee] = useState("medium_fee_per_kb");
|
||||||
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
const [selectedCoin, setSelectedCoin] = useState("LITECOIN");
|
||||||
|
const {
|
||||||
const { hideRecommendations, recommendedFeeDisplay, coin } = useRecommendedFees({
|
isUsingGateway
|
||||||
|
} = useContext(gameContext);
|
||||||
|
const { hideRecommendations, recommendedFeeDisplay, coin } =
|
||||||
|
useRecommendedFees({
|
||||||
selectedCoin,
|
selectedCoin,
|
||||||
recommendedFee
|
recommendedFee,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [editLockingFee, setEditLockingFee] = useState("");
|
const [editLockingFee, setEditLockingFee] = useState("");
|
||||||
@ -85,7 +88,7 @@ export const Settings = () => {
|
|||||||
try {
|
try {
|
||||||
let feeToSave = editLockingFee;
|
let feeToSave = editLockingFee;
|
||||||
if (recommendedFee !== "custom") {
|
if (recommendedFee !== "custom") {
|
||||||
feeToSave = recommendedFeeDisplay
|
feeToSave = recommendedFeeDisplay;
|
||||||
}
|
}
|
||||||
const response = await qortalRequestWithTimeout(
|
const response = await qortalRequestWithTimeout(
|
||||||
{
|
{
|
||||||
@ -218,6 +221,7 @@ export const Settings = () => {
|
|||||||
}}
|
}}
|
||||||
open={openModal}
|
open={openModal}
|
||||||
>
|
>
|
||||||
|
{!isUsingGateway && (
|
||||||
<CoinActionContainer
|
<CoinActionContainer
|
||||||
sx={{
|
sx={{
|
||||||
border: "1px solid #3F3F3F",
|
border: "1px solid #3F3F3F",
|
||||||
@ -241,8 +245,8 @@ export const Settings = () => {
|
|||||||
<CoinSelectRow
|
<CoinSelectRow
|
||||||
sx={{
|
sx={{
|
||||||
gap: "20px",
|
gap: "20px",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
justifyContent: 'center'
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
@ -273,8 +277,17 @@ export const Settings = () => {
|
|||||||
<SelectRow coin="ARRR" />
|
<SelectRow coin="ARRR" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
<Box>
|
</CoinSelectRow>
|
||||||
|
<CoinSelectRow>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>current fee: {lockingFee}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</CoinSelectRow>
|
</CoinSelectRow>
|
||||||
<CoinActionRow>
|
<CoinActionRow>
|
||||||
@ -350,8 +363,7 @@ export const Settings = () => {
|
|||||||
{" "}
|
{" "}
|
||||||
New fee:
|
New fee:
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{recommendedFeeDisplay}{" "}
|
{recommendedFeeDisplay} sats per kb
|
||||||
sats per kb
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@ -383,7 +395,6 @@ export const Settings = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={updateLockingFee}
|
onClick={updateLockingFee}
|
||||||
disabled={recommendedFee === "custom" && !editLockingFee}
|
disabled={recommendedFee === "custom" && !editLockingFee}
|
||||||
@ -409,6 +420,7 @@ export const Settings = () => {
|
|||||||
<Typography>Update locking fee</Typography>
|
<Typography>Update locking fee</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</CoinActionContainer>
|
</CoinActionContainer>
|
||||||
|
)}
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
<CoinActionContainer
|
<CoinActionContainer
|
||||||
sx={{
|
sx={{
|
||||||
|
118
src/components/sell/StuckOrdersTable.tsx
Normal file
118
src/components/sell/StuckOrdersTable.tsx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
Button,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { forwardRef } from "react";
|
||||||
|
import { TableVirtuoso, TableComponents } from "react-virtuoso";
|
||||||
|
import {
|
||||||
|
dismissToast,
|
||||||
|
showError,
|
||||||
|
showLoading,
|
||||||
|
showSuccess,
|
||||||
|
useGlobal,
|
||||||
|
} from "qapp-core";
|
||||||
|
import { formatTimestampForum } from "../../utils/formatTime";
|
||||||
|
|
||||||
|
interface NameData {
|
||||||
|
name: string;
|
||||||
|
isSelling?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VirtuosoTableComponents: TableComponents<NameData> = {
|
||||||
|
Scroller: forwardRef<HTMLDivElement>((props, ref) => (
|
||||||
|
<TableContainer component={Paper} {...props} ref={ref} />
|
||||||
|
)),
|
||||||
|
Table: (props) => (
|
||||||
|
<Table
|
||||||
|
{...props}
|
||||||
|
sx={{ borderCollapse: "separate", tableLayout: "fixed" }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
TableHead: forwardRef<HTMLTableSectionElement>((props, ref) => (
|
||||||
|
<TableHead {...props} ref={ref} />
|
||||||
|
)),
|
||||||
|
TableRow,
|
||||||
|
TableBody: forwardRef<HTMLTableSectionElement>((props, ref) => (
|
||||||
|
<TableBody {...props} ref={ref} />
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
function fixedHeaderContent() {
|
||||||
|
return (
|
||||||
|
<TableRow sx={{ backgroundColor: "background.paper" }}>
|
||||||
|
<TableCell>Date</TableCell>
|
||||||
|
<TableCell>Amount (QORT)</TableCell>
|
||||||
|
<TableCell>Actions</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowContent(_index: number, row: NameData) {
|
||||||
|
const cancelSell = async (name: string) => {
|
||||||
|
const loadId = showLoading("Attempting to cancel sell...please wait");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await qortalRequestWithTimeout(
|
||||||
|
{
|
||||||
|
action: "CANCEL_TRADE_SELL_ORDER",
|
||||||
|
qortAmount: row.qortAmount,
|
||||||
|
foreignBlockchain: row.foreignBlockchain,
|
||||||
|
foreignAmount: row.foreignAmount,
|
||||||
|
atAddress: row.qortalAtAddress,
|
||||||
|
},
|
||||||
|
900000
|
||||||
|
);
|
||||||
|
if (res?.signature) {
|
||||||
|
showSuccess(
|
||||||
|
"Canceled sell order. It might take awhile for the cancel sell order changes to show up."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError(error?.message || "Unable to cancel sell order");
|
||||||
|
|
||||||
|
console.log("error", error);
|
||||||
|
} finally {
|
||||||
|
dismissToast(loadId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableCell>{formatTimestampForum(row?.timestamp)}</TableCell>
|
||||||
|
<TableCell>{row?.qortAmount}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
onClick={() => cancelSell(row.name)}
|
||||||
|
>
|
||||||
|
Cancel sell
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StuckOrdersTable = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
height: "80vh", // Header + footer height
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableVirtuoso
|
||||||
|
data={data}
|
||||||
|
components={VirtuosoTableComponents}
|
||||||
|
fixedHeaderContent={fixedHeaderContent}
|
||||||
|
itemContent={(index, row) => rowContent(index, row)}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
@ -5,3 +5,5 @@ import { atomWithReset } from 'jotai/utils';
|
|||||||
export const selectedFeePublisherAtom = atomWithReset('Ice.JSON');
|
export const selectedFeePublisherAtom = atomWithReset('Ice.JSON');
|
||||||
|
|
||||||
export const isEnabledCustomLockingFeeAtom = atomWithReset(false);
|
export const isEnabledCustomLockingFeeAtom = atomWithReset(false);
|
||||||
|
|
||||||
|
export const stuckTradesAtom = atomWithReset([]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user