Update wallets

This commit is contained in:
AlphaX-Qortal
2025-03-12 08:18:27 +01:00
parent 8d31ed330b
commit 0e19fd1a7a
11 changed files with 4267 additions and 231 deletions

View File

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/png" href="/ico.png" />
<link rel="icon" type="image/png" href="/qw-ico.png" />
<meta name="viewport" content="initial-scale=1, width=device-width" />
<title>Qortal Wallets App</title>
</head>

26
package-lock.json generated
View File

@@ -22,7 +22,8 @@
"react-number-format": "^5.4.3",
"react-qr-code": "^2.0.15",
"react-router": "^7.2.0",
"react-router-dom": "^7.2.0"
"react-router-dom": "^7.2.0",
"react-window": "^1.8.11"
},
"devDependencies": {
"@types/react": "^19.0.10",
@@ -2384,6 +2385,12 @@
"yallist": "^3.0.2"
}
},
"node_modules/memoize-one": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
"license": "MIT"
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -2767,6 +2774,23 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/react-window": {
"version": "1.8.11",
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz",
"integrity": "sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.0.0",
"memoize-one": ">=3.1.1 <6"
},
"engines": {
"node": ">8.0.0"
},
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",

View File

@@ -23,7 +23,8 @@
"react-number-format": "^5.4.3",
"react-qr-code": "^2.0.15",
"react-router": "^7.2.0",
"react-router-dom": "^7.2.0"
"react-router-dom": "^7.2.0",
"react-window": "^1.8.11"
},
"devDependencies": {
"@types/react": "^19.0.10",
@@ -32,4 +33,4 @@
"typescript": "^5.7.3",
"vite": "^6.2.0"
}
}
}

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,10 +1,11 @@
import * as React from 'react';
import packageJson from '../package.json';
import { Container, Typography } from "@mui/material";
import { createTheme } from '@mui/material/styles';
import { Session, Navigation } from '@toolpad/core/AppProvider';
import { ReactRouterAppProvider } from '@toolpad/core/react-router';
import { Route, Routes } from "react-router-dom";
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { DashboardLayout, type SidebarFooterProps } from '@toolpad/core/DashboardLayout';
import WalletContext, { IContextProps, UserNameAvatar } from './contexts/walletContext';
import qort from "./assets/qort.png";
import btc from "./assets/btc.png";
@@ -223,24 +224,37 @@ function App() {
},
Pirate,
];
function SidebarFooter({ mini }: SidebarFooterProps) {
return (
<Typography
variant="caption"
sx={{ m: 1, whiteSpace: 'nowrap', overflow: 'hidden' }}
>
{mini ? `v${packageJson.version}` : `© ${new Date().getFullYear()} Qortal Wallets App v${packageJson.version}`}
</Typography>
);
}
const BRANDING = {
logo: <img src={qwallets} alt="MWA Logo" />,
title: <Typography>
<span style={{ color: '#60d0fd', fontSize: "24px", fontWeight: 700 }}>QORTAL </span>
<span style={{ color: '#05a2e4', fontSize: "24px", fontWeight: 700 }}>WALLETS </span>
<span style={{ color: '#02648d', fontSize: "24px", fontWeight: 700 }}>APP</span>
</Typography>
}
return (
<ReactRouterAppProvider
session={session}
authentication={authentication}
navigation={NAVIGATION}
branding={{
logo: <img src={qwallets} alt="MWA Logo" />,
title: (<Typography>
<span style={{ color: '#60d0fd', fontSize: "24px", fontWeight: 700 }}>QORTAL </span>
<span style={{ color: '#05a2e4', fontSize: "24px", fontWeight: 700 }}>WALLETS </span>
<span style={{ color: '#02648d', fontSize: "24px", fontWeight: 700 }}>APP</span>
</Typography>)
}}
branding={BRANDING}
theme={walletTheme}
>
<WalletContext.Provider value={walletContextValue}>
<DashboardLayout defaultSidebarCollapsed>
<DashboardLayout defaultSidebarCollapsed slots={{ sidebarFooter: SidebarFooter }}>
<Container sx={{ maxWidth: '100%' }} maxWidth={false}>
<Routes>
<Route path="/" element={<WelcomePage />} />

6
src/global.d.ts vendored
View File

@@ -29,7 +29,9 @@ interface QortalRequestOptions {
tag5?: string;
coin?: string;
destinationAddress?: string;
amount?: number;
amount?: number | Number;
recipient?: string;
fee?: number | any;
blob?: Blob;
mimeType?: string;
file?: File;
@@ -40,6 +42,8 @@ interface QortalRequestOptions {
exactMatchNames?: boolean;
creationBytes?: string;
type?: string;
host?: string;
port?: number;
assetId?: number;
txType?: TransactionType[];
confirmationStatus?: string;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,8 +15,10 @@ import {
DialogContent,
DialogTitle,
IconButton,
List,
ListItemButton,
ListItemText,
Paper,
Slide,
Slider,
Table,
TableBody,
@@ -34,6 +36,8 @@ import {
} from '@mui/material';
import { NumericFormat } from 'react-number-format';
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
import Snackbar, { SnackbarCloseReason } from '@mui/material/Snackbar';
import Slide, { SlideProps } from '@mui/material/Slide';
import { TransitionProps } from '@mui/material/transitions';
import CircularProgress from '@mui/material/CircularProgress';
import LinearProgress from '@mui/material/LinearProgress';
@@ -46,7 +50,9 @@ import {
LastPage,
CopyAllTwoTone,
Close,
Send
Send,
Refresh,
PublishedWithChangesTwoTone
} from '@mui/icons-material';
import coinLogoDOGE from '../../assets/doge.png';
@@ -125,6 +131,10 @@ const Transition = React.forwardRef(function Transition(
return <Slide direction="up" ref={ref} {...props} />;
});
function SlideTransition(props: SlideProps) {
return <Slide {...props} direction="up" />;
}
const DogeQrDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
@@ -132,6 +142,33 @@ const DogeQrDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const DogeElectrumDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const DogeSubmittDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
@@ -223,6 +260,8 @@ export default function DogecoinWallet() {
const [walletInfoDoge, setWalletInfoDoge] = React.useState<any>({});
const [walletBalanceDoge, setWalletBalanceDoge] = React.useState<any>(null);
const [isLoadingWalletBalanceDoge, setIsLoadingWalletBalanceDoge] = React.useState<boolean>(true);
const [allElectrumServersDoge, setAllElectrumServersDoge] = React.useState<any>([]);
const [currentElectrumServerDoge, setCurrentElectrumServerDoge] = React.useState<any>([]);
const [allWalletAddressesDoge, setAllWalletAddressesDoge] = React.useState<any>([]);
const [transactionsDoge, setTransactionsDoge] = React.useState<any>([]);
const [isLoadingDogeTransactions, setIsLoadingDogeTransactions] = React.useState<boolean>(true);
@@ -231,9 +270,15 @@ export default function DogecoinWallet() {
const [copyDogeAddress, setCopyDogeAddress] = React.useState('');
const [copyDogeTxHash, setCopyDogeTxHash] = React.useState('');
const [openDogeQR, setOpenDogeQR] = React.useState(false);
const [openDogeElectrum, setOpenDogeElectrum] = React.useState(false);
const [openDogeSend, setOpenDogeSend] = React.useState(false);
const [amountDoge, setAmountDoge] = React.useState<number>(0);
const [feeDoge, setFeeDoge] = React.useState<number>(0);
const [dogeAmount, setDogeAmount] = React.useState<number>(0);
const [dogeRecipient, setDogeRecipient] = React.useState('');
const [dogeFee, setDogeFee] = React.useState<number>(0);
const [loadingRefreshDoge, setLoadingRefreshDoge] = React.useState(false);
const [openTxDogeSubmit, setOpenTxDogeSubmit] = React.useState(false);
const [openSendDogeSuccess, setOpenSendDogeSuccess] = React.useState(false);
const [openSendDogeeError, setOpenSendDogeError] = React.useState(false);
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - transactionsDoge.length) : 0;
@@ -245,15 +290,30 @@ export default function DogecoinWallet() {
setOpenDogeQR(false);
}
const handleCloseDogeElectrum = () => {
setOpenDogeElectrum(false);
}
const handleOpenDogeSend = () => {
setAmountDoge(0);
setFeeDoge(1000);
setDogeAmount(0);
setDogeRecipient('');
setDogeFee(1000);
setOpenDogeSend(true);
}
const validateCanSendDoge = () => {
if (dogeAmount <= 0 || null || !dogeAmount) {
return true;
}
if (dogeRecipient.length < 34 || '') {
return true;
}
return false;
}
const handleCloseDogeSend = () => {
setAmountDoge(0);
setFeeDoge(0);
setDogeAmount(0);
setDogeFee(0);
setOpenDogeSend(false);
}
@@ -269,7 +329,7 @@ export default function DogecoinWallet() {
setCopyDogeTxHash('');
}
const handleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, newPage: number,) => {
const handleChangePage = (_event: React.MouseEvent<HTMLButtonElement> | null, newPage: number,) => {
setPage(newPage);
};
@@ -278,13 +338,29 @@ export default function DogecoinWallet() {
setPage(0);
};
const handleChangeDogeAmount = (_: Event, newValue: number | number[]) => {
setAmountDoge(newValue as number);
console.log("AMOUNT DOGE", amountDoge)
const handleChangeDogeFee = (_: Event, newValue: number | number[]) => {
setDogeFee(newValue as number);
setDogeAmount(0);
};
const handleChangeDogeFee = (_: Event, newValue: number | number[]) => {
setFeeDoge(newValue as number);
const handleCloseSendDogeSuccess = (
_event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
}
setOpenSendDogeSuccess(false);
};
const handleCloseSendDogeError = (
_event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
}
setOpenSendDogeError(false);
};
const getWalletInfoDoge = async () => {
@@ -337,6 +413,37 @@ export default function DogecoinWallet() {
}
}, [isAuthenticated]);
const getElectrumServersDoge = async () => {
try {
const response = await qortalRequest({
action: "GET_CROSSCHAIN_SERVER_INFO",
coin: "DOGE"
});
if (!response?.error) {
setAllElectrumServersDoge(response);
let currentDogeServer = response.filter(function (item: { isCurrent: boolean; }) {
return item.isCurrent === true;
});
setCurrentElectrumServerDoge(currentDogeServer);
console.log("GET DOGE SERVERS INFO", response);
console.log("CURRENT DOGE SERVER INFO", currentDogeServer);
}
} catch (error) {
setAllElectrumServersDoge({});
console.log("ERROR GET DOGE SERVERS INFO", error);
}
}
React.useEffect(() => {
if (!isAuthenticated) return;
getElectrumServersDoge();
}, [isAuthenticated]);
const handleOpenDogeElectrum = async () => {
await getElectrumServersDoge();
setOpenDogeElectrum(true);
}
const getTransactionsDoge = async () => {
try {
setIsLoadingDogeTransactions(true);
@@ -376,6 +483,21 @@ export default function DogecoinWallet() {
getTransactionsDoge();
}, [isAuthenticated]);
const handleLoadingRefreshDoge = async () => {
setLoadingRefreshDoge(true);
await getTransactionsDoge();
setLoadingRefreshDoge(false);
}
const handleSendMaxDoge = () => {
const maxDogeAmount = parseFloat((walletBalanceDoge - ((dogeFee * 1000) / 1e8)).toFixed(8));
if (maxDogeAmount <= 0) {
setDogeAmount(0);
} else {
setDogeAmount(maxDogeAmount);
}
}
const DogeQrDialogPage = () => {
return (
<DogeQrDialog
@@ -407,6 +529,44 @@ export default function DogecoinWallet() {
);
}
const sendDogeRequest = async () => {
setOpenTxDogeSubmit(true);
const dogeFeeCalculated = Number(dogeFee / 1e8).toFixed(8);
console.log("RECIPIENT", dogeRecipient);
console.log("AMOUNT", dogeAmount);
console.log("FEE", dogeFeeCalculated);
try {
const sendRequest = await qortalRequest({
action: "SEND_COIN",
coin: "DOGE",
recipient: dogeRecipient,
amount: dogeAmount,
fee: dogeFeeCalculated
});
if (!sendRequest?.error) {
setDogeAmount(0);
setDogeRecipient('');
setDogeFee(1000);
setOpenTxDogeSubmit(false);
setOpenSendDogeSuccess(true);
setIsLoadingWalletBalanceDoge(true);
await timeoutDelay(3000);
getWalletBalanceDoge();
console.log("DOGE SENDED", sendRequest);
}
} catch (error) {
setDogeAmount(0);
setDogeRecipient('');
setDogeFee(1000);
setOpenTxDogeSubmit(false);
setOpenSendDogeError(true);
setIsLoadingWalletBalanceDoge(true);
await timeoutDelay(3000);
getWalletBalanceDoge();
console.log("ERROR SENDING DOGE", error);
}
}
const DogeSendDialogPage = () => {
return (
<Dialog
@@ -415,6 +575,58 @@ export default function DogecoinWallet() {
onClose={handleCloseDogeSend}
slots={{ transition: Transition }}
>
<DogeSubmittDialog
fullWidth={true}
maxWidth='xs'
open={openTxDogeSubmit}
>
<DialogContent>
<Box sx={{ display: 'flex', justifyContent: 'center', flexWrap: 'wrap' }}>
<div style={{
width: "100%",
display: 'flex',
justifyContent: 'center'
}}>
<CircularProgress color="success" size={64} />
</div>
<div style={{
width: "100%",
display: 'flex',
justifyContent: 'center',
marginTop: '20px'
}}>
<Typography variant="h6" sx={{ color: 'primary.main', fontStyle: 'italic', fontWeight: 700 }}>
Processing Transaction Please Wait...
</Typography>
</div>
</Box>
</DialogContent>
</DogeSubmittDialog>
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={openSendDogeSuccess}
autoHideDuration={4000}
slots={{ transition: SlideTransition }}
onClose={handleCloseSendDogeSuccess}>
<Alert
onClose={handleCloseSendDogeSuccess}
severity="success"
variant="filled"
sx={{ width: '100%' }}
>
Sent DOGE transaction was successful!
</Alert>
</Snackbar>
<Snackbar open={openSendDogeeError} autoHideDuration={4000} onClose={handleCloseSendDogeError}>
<Alert
onClose={handleCloseSendDogeError}
severity="error"
variant="filled"
sx={{ width: '100%' }}
>
Something went wrong, please try again!
</Alert>
</Snackbar>
<AppBar sx={{ position: 'static' }}>
<Toolbar>
<IconButton
@@ -437,10 +649,11 @@ export default function DogecoinWallet() {
Transfer DOGE
</Typography>
<Button
disabled={validateCanSendDoge()}
variant="contained"
startIcon={<Send />}
aria-label="send"
onClick={handleOpenDogeSend}
aria-label="send-doge"
onClick={sendDogeRequest}
sx={{ backgroundColor: "#05a2e4", color: "white", "&:hover": { backgroundColor: "#02648d", } }}
>
SEND
@@ -468,7 +681,7 @@ export default function DogecoinWallet() {
gutterBottom
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{walletBalanceDoge + " DOGE"}
{isLoadingWalletBalanceDoge ? <Box sx={{ width: '175px' }}><LinearProgress /></Box> : walletBalanceDoge + " DOGE"}
</Typography>
</div>
<div style={{
@@ -481,7 +694,6 @@ export default function DogecoinWallet() {
<Typography
variant="h5"
align="center"
gutterBottom
sx={{ color: 'primary.main', fontWeight: 700 }}
>
Max Sendable:&nbsp;&nbsp;
@@ -489,11 +701,27 @@ export default function DogecoinWallet() {
<Typography
variant="h5"
align="center"
gutterBottom
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{(walletBalanceDoge - 0.05000000) + " DOGE"}
{(() => {
const newMaxDogeAmount = parseFloat((walletBalanceDoge - ((dogeFee * 1000) / 1e8)).toFixed(8));
if (newMaxDogeAmount < 0) {
return Number(0.00000000) + " DOGE"
} else {
return newMaxDogeAmount + " DOGE"
}
})()}
</Typography>
<div style={{ marginInlineStart: '15px' }}>
<Button
variant="outlined"
size="small"
onClick={handleSendMaxDoge}
style={{ borderRadius: 50 }}
>
Send Max
</Button>
</div>
</div>
<Box
sx={{
@@ -507,22 +735,32 @@ export default function DogecoinWallet() {
>
<NumericFormat
decimalScale={8}
value={amountDoge}
defaultValue={0}
value={dogeAmount}
allowNegative={false}
customInput={TextField}
valueIsNumericString
variant="outlined"
label="Amount (DOGE)"
isAllowed={(values) => {
const maxDogeCoin = (walletBalanceDoge - (dogeFee * 1000) / 1e8);
const { formattedValue, floatValue } = values;
return formattedValue === "" || floatValue <= maxDogeCoin;
}}
onValueChange={(values) => {
setAmountDoge(values.floatValue);
setDogeAmount(values.floatValue);
}}
required
/>
<TextField
required
label="Receiver Adress"
id="dogeaddress"
id="dogea-address"
margin="normal"
value={dogeRecipient}
helperText="Doge Address 34 Characters long !"
slotProps={{ htmlInput: { maxLength: 34, minLength: 34 } }}
onChange={(e) => setDogeRecipient(e.target.value)}
/>
</Box>
<div style={{
@@ -540,7 +778,7 @@ export default function DogecoinWallet() {
width: '50ch'
}}>
<Typography id="doge-fee-slider" gutterBottom>
Current fee per byte : {feeDoge} SAT
Current fee per byte : {dogeFee} SAT
</Typography>
<Slider
track={false}
@@ -554,6 +792,12 @@ export default function DogecoinWallet() {
marks={dogeMarks}
onChange={handleChangeDogeFee}
/>
<Typography
align="center"
sx={{ fontWeight: 600, fontSize: '14px', marginTop: '15px' }}
>
Low fees may result in slow or unconfirmed transactions.
</Typography>
</Box>
</div>
</Dialog>
@@ -602,8 +846,8 @@ export default function DogecoinWallet() {
? transactionsDoge.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: transactionsDoge
).map((row: {
inputs: { address: any; }[];
outputs: { address: any; }[];
inputs: { address: any; addressInWallet: boolean; }[];
outputs: { address: any; addressInWallet: boolean; }[];
txHash: string;
totalAmount: any;
timestamp: number;
@@ -611,27 +855,31 @@ export default function DogecoinWallet() {
<StyledTableRow>
<StyledTableCell style={{ width: 'auto' }} align="left">
{(() => {
if (allWalletAddressesDoge.some(dogeAll => dogeAll.address === row?.inputs[0].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.inputs[0].address}</div>;
if (row?.totalAmount < 0) {
let meWasSender = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === true;
});
return <div style={{ color: '#05a2e4' }}>{meWasSender[0]?.address}</div>;
} else {
return row?.inputs[0].address;
let meWasNotSender = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === false;
});
return meWasNotSender[0].address;
}
})()}
</StyledTableCell>
<StyledTableCell style={{ width: 'auto' }} align="left">
{(() => {
if (row?.outputs[0].address === row?.inputs[0].address) {
if (allWalletAddressesDoge.some((dogeAll: { address: any; }) => dogeAll.address === row?.outputs[1].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.outputs[1].address}</div>;
} else {
return row?.outputs[1].address;
}
} else {
if (allWalletAddressesDoge.some((dogeAll: { address: any; }) => dogeAll.address === row?.outputs[0].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.outputs[0].address}</div>;
} else {
return row?.outputs[0].address;
}
if (row?.totalAmount < 0) {
let meWasNotRecipient = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === false;
});
return meWasNotRecipient[0].address;
} else if (row?.totalAmount > 0) {
let meWasRecipient = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === true;
});
return <div style={{ color: '#05a2e4' }}>{meWasRecipient[0]?.address}</div>
}
})()}
</StyledTableCell>
@@ -644,7 +892,7 @@ export default function DogecoinWallet() {
</CustomWidthTooltip>
</StyledTableCell>
<StyledTableCell style={{ width: 'auto' }} align="left">
{row?.outputs[0].address === walletInfoDoge?.address ?
{row?.totalAmount > 0 ?
<div style={{ color: '#66bb6a' }}>+{(Number(row?.totalAmount) / 1e8).toFixed(8)}</div> : <div style={{ color: '#f44336' }}>{(Number(row?.totalAmount) / 1e8).toFixed(8)}</div>
}
</StyledTableCell>
@@ -686,10 +934,77 @@ export default function DogecoinWallet() {
);
}
const setNewCurrentDogeServer = async (typeServer: string, hostServer: string, portServer: number) => {
console.log("SERVER CHHOSED", typeServer, hostServer, portServer);
try {
const setServer = await qortalRequest({
action: "SET_CURRENT_FOREIGN_SERVER",
coin: "DOGE",
type: typeServer,
host: hostServer,
port: portServer
});
if (!setServer?.error) {
await getElectrumServersDoge();
setOpenDogeElectrum(false);
await getWalletBalanceDoge();
await getTransactionsDoge();
}
} catch (error) {
await getElectrumServersDoge();
setOpenDogeElectrum(false);
console.log("ERROR GET DOGE SERVERS INFO", error);
}
}
const DogeElectrumDialogPage = () => {
return (
<DogeElectrumDialog
onClose={handleCloseDogeQR}
aria-labelledby="doge-electrum-servers"
open={openDogeElectrum}
keepMounted={false}
>
<DialogTitle sx={{ m: 0, p: 2, fontSize: '14px' }} id="doge-electrum-servers">
Available Dogecoin Electrum Servers.
</DialogTitle>
<DialogContent dividers>
<Box sx={{
width: '100%',
maxWidth: 500,
position: 'relative',
overflow: 'auto',
maxHeight: 400
}}>
<List>
{(
allElectrumServersDoge
).map((server: {
connectionType: string;
hostName: string;
port: number;
}) => (
<ListItemButton onClick={() => { setNewCurrentDogeServer(server?.connectionType, server?.hostName, server?.port) }}>
<ListItemText primary={server?.hostName + ':' + server?.port} />
</ListItemButton>
))}
</List>
</Box>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCloseDogeElectrum}>
CLOSE
</Button>
</DialogActions>
</DogeElectrumDialog>
);
}
return (
<Box sx={{ width: '100%', marginTop: "20px" }}>
{DogeSendDialogPage()}
{DogeQrDialogPage()}
{DogeElectrumDialogPage()}
<Typography gutterBottom variant="h5" sx={{ color: 'primary.main', fontStyle: 'italic', fontWeight: 700 }}>
Dogecoin Wallet
</Typography>
@@ -741,12 +1056,38 @@ export default function DogecoinWallet() {
>
{walletInfoDoge?.address}
</Typography>
<Tooltip placement="top" title={copyDogeAddress ? copyDogeAddress : "Copy Address"}>
<Tooltip placement="right" title={copyDogeAddress ? copyDogeAddress : "Copy Address"}>
<IconButton aria-label="copy" size="small" onClick={() => { navigator.clipboard.writeText(walletInfoDoge?.address), changeCopyDogeStatus() }}>
<CopyAllTwoTone fontSize="small" />
</IconButton>
</Tooltip>
</div>
<div style={{
width: "100%",
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<Typography
variant="subtitle1"
align="center"
sx={{ color: 'primary.main', fontWeight: 700 }}
>
Electrum Server:&nbsp;&nbsp;
</Typography>
<Typography
variant="subtitle1"
align="center"
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{currentElectrumServerDoge[0]?.hostName + ":" + currentElectrumServerDoge[0]?.port}
</Typography>
<Tooltip placement="right" title="CHange Server">
<IconButton aria-label="open-electrum" size="small" onClick={handleOpenDogeElectrum}>
<PublishedWithChangesTwoTone fontSize="small" />
</IconButton>
</Tooltip>
</div>
<div style={{
width: "100%",
display: 'flex',
@@ -779,9 +1120,27 @@ export default function DogecoinWallet() {
Address Book
</WalletButtons>
</div>
<Typography variant="h6" paddingTop={2} paddingBottom={2}>
Transactions:
</Typography>
<div style={{
width: "100%",
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<Typography variant="h6" paddingTop={2} paddingBottom={2}>
Transactions:
</Typography>
<Button
size="small"
onClick={handleLoadingRefreshDoge}
loading={loadingRefreshDoge}
loadingPosition="start"
startIcon={<Refresh />}
variant="outlined"
style={{ borderRadius: 50 }}
>
Refresh
</Button>
</div>
{isLoadingDogeTransactions ? tableLoader() : transactionsTable()}
</WalleteCard>
</Box>

View File

@@ -15,8 +15,10 @@ import {
DialogContent,
DialogTitle,
IconButton,
List,
ListItemButton,
ListItemText,
Paper,
Slide,
Slider,
Table,
TableBody,
@@ -34,6 +36,8 @@ import {
} from '@mui/material';
import { NumericFormat } from 'react-number-format';
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
import Snackbar, { SnackbarCloseReason } from '@mui/material/Snackbar';
import Slide, { SlideProps } from '@mui/material/Slide';
import { TransitionProps } from '@mui/material/transitions';
import CircularProgress from '@mui/material/CircularProgress';
import LinearProgress from '@mui/material/LinearProgress';
@@ -46,7 +50,9 @@ import {
LastPage,
CopyAllTwoTone,
Close,
Send
Send,
Refresh,
PublishedWithChangesTwoTone
} from '@mui/icons-material';
import coinLogoLTC from '../../assets/ltc.png';
@@ -125,6 +131,10 @@ const Transition = React.forwardRef(function Transition(
return <Slide direction="up" ref={ref} {...props} />;
});
function SlideTransition(props: SlideProps) {
return <Slide {...props} direction="up" />;
}
const LtcQrDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
@@ -132,6 +142,33 @@ const LtcQrDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const LtcElectrumDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const LtcSubmittDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
"& .MuiDialog-paper": {
borderRadius: "15px",
},
}));
const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
@@ -212,7 +249,6 @@ export default function LitecoinWallet() {
const { isAuthenticated } = React.useContext(WalletContext);
if (!isAuthenticated) {
console.log("WE ARE NOT LOGGED IN");
return (
<Alert variant="filled" severity="error">
You must sign in, to use the Litecoin wallet !!!
@@ -223,6 +259,8 @@ export default function LitecoinWallet() {
const [walletInfoLtc, setWalletInfoLtc] = React.useState<any>({});
const [walletBalanceLtc, setWalletBalanceLtc] = React.useState<any>(null);
const [isLoadingWalletBalanceLtc, setIsLoadingWalletBalanceLtc] = React.useState<boolean>(true);
const [allElectrumServersLtc, setAllElectrumServersLtc] = React.useState<any>([]);
const [currentElectrumServerLtc, setCurrentElectrumServerLtc] = React.useState<any>([]);
const [allWalletAddressesLtc, setAllWalletAddressesLtc] = React.useState<any>([]);
const [transactionsLtc, setTransactionsLtc] = React.useState<any>([]);
const [isLoadingLtcTransactions, setIsLoadingLtcTransactions] = React.useState<boolean>(true);
@@ -231,9 +269,15 @@ export default function LitecoinWallet() {
const [copyLtcAddress, setCopyLtcAddress] = React.useState('');
const [copyLtcTxHash, setCopyLtcTxHash] = React.useState('');
const [openLtcQR, setOpenLtcQR] = React.useState(false);
const [openLtcElectrum, setOpenLtcElectrum] = React.useState(false);
const [openLtcSend, setOpenLtcSend] = React.useState(false);
const [amountLtc, setAmountLtc] = React.useState<number>(0);
const [feeLtc, setFeeLtc] = React.useState<number>(0);
const [ltcAmount, setLtcAmount] = React.useState<number>(0);
const [ltcRecipient, setLtcRecipient] = React.useState('');
const [ltcFee, setLtcFee] = React.useState<number>(0);
const [loadingRefreshLtc, setLoadingRefreshLtc] = React.useState(false);
const [openTxLtcSubmit, setOpenTxLtcSubmit] = React.useState(false);
const [openSendLtcSuccess, setOpenSendLtcSuccess] = React.useState(false);
const [openSendLtceError, setOpenSendLtcError] = React.useState(false);
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - transactionsLtc.length) : 0;
@@ -245,15 +289,30 @@ export default function LitecoinWallet() {
setOpenLtcQR(false);
}
const handleCloseLtcElectrum = () => {
setOpenLtcElectrum(false);
}
const handleOpenLtcSend = () => {
setAmountLtc(0);
setFeeLtc(30);
setLtcAmount(0);
setLtcRecipient('');
setLtcFee(30);
setOpenLtcSend(true);
}
const validateCanSendLtc = () => {
if (ltcAmount <= 0 || null || !ltcAmount) {
return true;
}
if (ltcRecipient.length < 34 || '') {
return true;
}
return false;
}
const handleCloseLtcSend = () => {
setAmountLtc(0);
setFeeLtc(0);
setLtcAmount(0);
setLtcFee(0);
setOpenLtcSend(false);
}
@@ -269,7 +328,7 @@ export default function LitecoinWallet() {
setCopyLtcTxHash('');
}
const handleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, newPage: number,) => {
const handleChangePage = (_event: React.MouseEvent<HTMLButtonElement> | null, newPage: number,) => {
setPage(newPage);
};
@@ -278,12 +337,29 @@ export default function LitecoinWallet() {
setPage(0);
};
const handleChangeLtcAmount = (_: Event, newValue: number | number[]) => {
setAmountLtc(newValue as number);
const handleChangeLtcFee = (_: Event, newValue: number | number[]) => {
setLtcFee(newValue as number);
setLtcAmount(0);
};
const handleChangeLtcFee = (_: Event, newValue: number | number[]) => {
setFeeLtc(newValue as number);
const handleCloseSendLtcSuccess = (
_event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
}
setOpenSendLtcSuccess(false);
};
const handleCloseSendLtcError = (
_event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
}
setOpenSendLtcError(false);
};
const getWalletInfoLtc = async () => {
@@ -294,11 +370,10 @@ export default function LitecoinWallet() {
});
if (!response?.error) {
setWalletInfoLtc(response);
console.log("GET LTC WALLET INFO", response);
}
} catch (error) {
setWalletInfoLtc({});
console.log("ERROR GET LTC WALLET INFO", error);
console.error("ERROR GET LTC WALLET INFO", error);
}
}
@@ -316,12 +391,11 @@ export default function LitecoinWallet() {
if (!response?.error) {
setWalletBalanceLtc(response);
setIsLoadingWalletBalanceLtc(false);
console.log("GET LTC BALANCE", response);
}
} catch (error) {
setWalletBalanceLtc(null);
setIsLoadingWalletBalanceLtc(false);
console.log("ERROR GET LTC BALANCE", error);
console.error("ERROR GET LTC BALANCE", error);
}
}
@@ -336,6 +410,35 @@ export default function LitecoinWallet() {
}
}, [isAuthenticated]);
const getElectrumServersLtc = async () => {
try {
const response = await qortalRequest({
action: "GET_CROSSCHAIN_SERVER_INFO",
coin: "LTC"
});
if (!response?.error) {
setAllElectrumServersLtc(response);
let currentLtcServer = response.filter(function (item: { isCurrent: boolean; }) {
return item.isCurrent === true;
});
setCurrentElectrumServerLtc(currentLtcServer);
}
} catch (error) {
setAllElectrumServersLtc({});
console.error("ERROR GET LTC SERVERS INFO", error);
}
}
React.useEffect(() => {
if (!isAuthenticated) return;
getElectrumServersLtc();
}, [isAuthenticated]);
const handleOpenLtcElectrum = async () => {
await getElectrumServersLtc();
setOpenLtcElectrum(true);
}
const getTransactionsLtc = async () => {
try {
setIsLoadingLtcTransactions(true);
@@ -351,22 +454,20 @@ export default function LitecoinWallet() {
await responseLtcAllAddresses;
if (!responseLtcAllAddresses?.error) {
setAllWalletAddressesLtc(responseLtcAllAddresses);
console.log("GET LTC ALL ADDRESSES", responseLtcAllAddresses);
}
} catch (error) {
setAllWalletAddressesLtc([]);
console.log("ERROR GET LTC ALL ADDRESSES", error);
console.error("ERROR GET LTC ALL ADDRESSES", error);
}
await responseLtcTransactions;
if (!responseLtcTransactions?.error) {
setTransactionsLtc(responseLtcTransactions);
setIsLoadingLtcTransactions(false);
console.log("GET LTC TRANSACTIONS", responseLtcTransactions);
}
} catch (error) {
setIsLoadingLtcTransactions(false);
setTransactionsLtc([]);
console.log("ERROR GET LTC TRANSACTIONS", error);
console.error("ERROR GET LTC TRANSACTIONS", error);
}
}
@@ -375,6 +476,21 @@ export default function LitecoinWallet() {
getTransactionsLtc();
}, [isAuthenticated]);
const handleLoadingRefreshLtc = async () => {
setLoadingRefreshLtc(true);
await getTransactionsLtc();
setLoadingRefreshLtc(false);
}
const handleSendMaxLtc = () => {
const maxLtcAmount = parseFloat((walletBalanceLtc - ((ltcFee * 1000) / 1e8)).toFixed(8));
if (maxLtcAmount <= 0) {
setLtcAmount(0);
} else {
setLtcAmount(maxLtcAmount);
}
}
const LtcQrDialogPage = () => {
return (
<LtcQrDialog
@@ -406,6 +522,40 @@ export default function LitecoinWallet() {
);
}
const sendLtcRequest = async () => {
setOpenTxLtcSubmit(true);
const ltcFeeCalculated = Number(ltcFee / 1e8).toFixed(8);
try {
const sendRequest = await qortalRequest({
action: "SEND_COIN",
coin: "LTC",
recipient: ltcRecipient,
amount: ltcAmount,
fee: ltcFeeCalculated
});
if (!sendRequest?.error) {
setLtcAmount(0);
setLtcRecipient('');
setLtcFee(30);
setOpenTxLtcSubmit(false);
setOpenSendLtcSuccess(true);
setIsLoadingWalletBalanceLtc(true);
await timeoutDelay(3000);
getWalletBalanceLtc();
}
} catch (error) {
setLtcAmount(0);
setLtcRecipient('');
setLtcFee(30);
setOpenTxLtcSubmit(false);
setOpenSendLtcError(true);
setIsLoadingWalletBalanceLtc(true);
await timeoutDelay(3000);
getWalletBalanceLtc();
console.error("ERROR SENDING LTC", error);
}
}
const LtcSendDialogPage = () => {
return (
<Dialog
@@ -414,6 +564,58 @@ export default function LitecoinWallet() {
onClose={handleCloseLtcSend}
slots={{ transition: Transition }}
>
<LtcSubmittDialog
fullWidth={true}
maxWidth='xs'
open={openTxLtcSubmit}
>
<DialogContent>
<Box sx={{ display: 'flex', justifyContent: 'center', flexWrap: 'wrap' }}>
<div style={{
width: "100%",
display: 'flex',
justifyContent: 'center'
}}>
<CircularProgress color="success" size={64} />
</div>
<div style={{
width: "100%",
display: 'flex',
justifyContent: 'center',
marginTop: '20px'
}}>
<Typography variant="h6" sx={{ color: 'primary.main', fontStyle: 'italic', fontWeight: 700 }}>
Processing Transaction Please Wait...
</Typography>
</div>
</Box>
</DialogContent>
</LtcSubmittDialog>
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={openSendLtcSuccess}
autoHideDuration={4000}
slots={{ transition: SlideTransition }}
onClose={handleCloseSendLtcSuccess}>
<Alert
onClose={handleCloseSendLtcSuccess}
severity="success"
variant="filled"
sx={{ width: '100%' }}
>
Sent LTC transaction was successful!
</Alert>
</Snackbar>
<Snackbar open={openSendLtceError} autoHideDuration={4000} onClose={handleCloseSendLtcError}>
<Alert
onClose={handleCloseSendLtcError}
severity="error"
variant="filled"
sx={{ width: '100%' }}
>
Something went wrong, please try again!
</Alert>
</Snackbar>
<AppBar sx={{ position: 'static' }}>
<Toolbar>
<IconButton
@@ -436,10 +638,11 @@ export default function LitecoinWallet() {
Transfer LTC
</Typography>
<Button
disabled={validateCanSendLtc()}
variant="contained"
startIcon={<Send />}
aria-label="send"
onClick={handleOpenLtcSend}
aria-label="send-ltc"
onClick={sendLtcRequest}
sx={{ backgroundColor: "#05a2e4", color: "white", "&:hover": { backgroundColor: "#02648d", } }}
>
SEND
@@ -467,9 +670,48 @@ export default function LitecoinWallet() {
gutterBottom
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{walletBalanceLtc + " LTC"}
{isLoadingWalletBalanceLtc ? <Box sx={{ width: '175px' }}><LinearProgress /></Box> : walletBalanceLtc + " LTC"}
</Typography>
</div>
<div style={{
width: "100%",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginTop: '20px'
}}>
<Typography
variant="h5"
align="center"
sx={{ color: 'primary.main', fontWeight: 700 }}
>
Max Sendable:&nbsp;&nbsp;
</Typography>
<Typography
variant="h5"
align="center"
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{(() => {
const newMaxLtcAmount = parseFloat((walletBalanceLtc - ((ltcFee * 1000) / 1e8)).toFixed(8));
if (newMaxLtcAmount < 0) {
return Number(0.00000000) + " LTC"
} else {
return newMaxLtcAmount + " LTC"
}
})()}
</Typography>
<div style={{ marginInlineStart: '15px' }}>
<Button
variant="outlined"
size="small"
onClick={handleSendMaxLtc}
style={{ borderRadius: 50 }}
>
Send Max
</Button>
</div>
</div>
<Box
sx={{
display: 'flex',
@@ -482,22 +724,32 @@ export default function LitecoinWallet() {
>
<NumericFormat
decimalScale={8}
value={amountLtc}
defaultValue={0}
value={ltcAmount}
allowNegative={false}
customInput={TextField}
valueIsNumericString
variant="outlined"
label="Amount (LTC)"
isAllowed={(values) => {
const maxLtcCoin = (walletBalanceLtc - (ltcFee * 1000) / 1e8);
const { formattedValue, floatValue } = values;
return formattedValue === "" || floatValue <= maxLtcCoin;
}}
onValueChange={(values) => {
setAmountLtc(values.floatValue);
setLtcAmount(values.floatValue);
}}
required
/>
<TextField
required
label="Receiver Adress"
id="ltcaddress"
id="ltca-address"
margin="normal"
value={ltcRecipient}
helperText="Ltc Address 34 Characters long !"
slotProps={{ htmlInput: { maxLength: 34, minLength: 34 } }}
onChange={(e) => setLtcRecipient(e.target.value)}
/>
</Box>
<div style={{
@@ -514,8 +766,8 @@ export default function LitecoinWallet() {
flexDirection: 'column',
width: '50ch'
}}>
<Typography id="doge-fee-slider" gutterBottom>
Current fee per byte : {feeLtc} SAT
<Typography id="ltc-fee-slider" gutterBottom>
Current fee per byte : {ltcFee} SAT
</Typography>
<Slider
track={false}
@@ -523,12 +775,18 @@ export default function LitecoinWallet() {
min={10}
max={100}
valueLabelDisplay="auto"
aria-labelledby="doge-fee-slider"
aria-labelledby="ltc-fee-slider"
getAriaValueText={valueTextLtc}
defaultValue={30}
marks={ltcMarks}
onChange={handleChangeLtcFee}
/>
<Typography
align="center"
sx={{ fontWeight: 600, fontSize: '14px', marginTop: '15px' }}
>
Low fees may result in slow or unconfirmed transactions.
</Typography>
</Box>
</div>
</Dialog>
@@ -577,37 +835,40 @@ export default function LitecoinWallet() {
? transactionsLtc.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: transactionsLtc
).map((row: {
name: React.Key;
inputs: { address: any; }[];
outputs: { address: any; }[];
inputs: { address: any; addressInWallet: boolean; }[];
outputs: { address: any; addressInWallet: boolean; }[];
txHash: string;
totalAmount: any;
timestamp: number;
}) => (
<StyledTableRow key={row.name}>
<StyledTableRow>
<StyledTableCell style={{ width: 'auto' }} align="left">
{(() => {
if (allWalletAddressesLtc.some(ltcAll => ltcAll.address === row?.inputs[0].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.inputs[0].address}</div>;
if (row?.totalAmount < 0) {
let meWasSender = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === true;
});
return <div style={{ color: '#05a2e4' }}>{meWasSender[0]?.address}</div>;
} else {
return row?.inputs[0].address;
let meWasNotSender = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === false;
});
return meWasNotSender[0].address;
}
})()}
</StyledTableCell>
<StyledTableCell style={{ width: 'auto' }} align="left">
{(() => {
if (row?.outputs[0].address === row?.inputs[0].address) {
if (allWalletAddressesLtc.some(ltcAll => ltcAll.address === row?.outputs[1].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.outputs[1].address}</div>;
} else {
return row?.outputs[1].address;
}
} else {
if (allWalletAddressesLtc.some(ltcAll => ltcAll.address === row?.outputs[0].address)) {
return <div style={{ color: '#05a2e4' }}>{row?.outputs[0].address}</div>;
} else {
return row?.outputs[0].address;
}
if (row?.totalAmount < 0) {
let meWasNotRecipient = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === false;
});
return meWasNotRecipient[0].address;
} else if (row?.totalAmount > 0) {
let meWasRecipient = row?.outputs.filter(function (item: { addressInWallet: boolean; }) {
return item.addressInWallet === true;
});
return <div style={{ color: '#05a2e4' }}>{meWasRecipient[0]?.address}</div>
}
})()}
</StyledTableCell>
@@ -620,7 +881,7 @@ export default function LitecoinWallet() {
</CustomWidthTooltip>
</StyledTableCell>
<StyledTableCell style={{ width: 'auto' }} align="left">
{row?.outputs[0].address === walletInfoLtc?.address ?
{row?.totalAmount > 0 ?
<div style={{ color: '#66bb6a' }}>+{(Number(row?.totalAmount) / 1e8).toFixed(8)}</div> : <div style={{ color: '#f44336' }}>{(Number(row?.totalAmount) / 1e8).toFixed(8)}</div>
}
</StyledTableCell>
@@ -662,10 +923,76 @@ export default function LitecoinWallet() {
);
}
const setNewCurrentLtcServer = async (typeServer: string, hostServer: string, portServer: number) => {
try {
const setServer = await qortalRequest({
action: "SET_CURRENT_FOREIGN_SERVER",
coin: "LTC",
type: typeServer,
host: hostServer,
port: portServer
});
if (!setServer?.error) {
await getElectrumServersLtc();
setOpenLtcElectrum(false);
await getWalletBalanceLtc();
await getTransactionsLtc();
}
} catch (error) {
await getElectrumServersLtc();
setOpenLtcElectrum(false);
console.error("ERROR GET LTC SERVERS INFO", error);
}
}
const LtcElectrumDialogPage = () => {
return (
<LtcElectrumDialog
onClose={handleCloseLtcQR}
aria-labelledby="ltc-electrum-servers"
open={openLtcElectrum}
keepMounted={false}
>
<DialogTitle sx={{ m: 0, p: 2, fontSize: '14px' }} id="ltc-electrum-servers">
Available Litecoin Electrum Servers.
</DialogTitle>
<DialogContent dividers>
<Box sx={{
width: '100%',
maxWidth: 500,
position: 'relative',
overflow: 'auto',
maxHeight: 400
}}>
<List>
{(
allElectrumServersLtc
).map((server: {
connectionType: string;
hostName: string;
port: number;
}) => (
<ListItemButton onClick={() => { setNewCurrentLtcServer(server?.connectionType, server?.hostName, server?.port) }}>
<ListItemText primary={server?.hostName + ':' + server?.port} />
</ListItemButton>
))}
</List>
</Box>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCloseLtcElectrum}>
CLOSE
</Button>
</DialogActions>
</LtcElectrumDialog>
);
}
return (
<Box sx={{ width: '100%', marginTop: "20px" }}>
{LtcSendDialogPage()}
{LtcQrDialogPage()}
{LtcElectrumDialogPage()}
<Typography gutterBottom variant="h5" sx={{ color: 'primary.main', fontStyle: 'italic', fontWeight: 700 }}>
Litecoin Wallet
</Typography>
@@ -717,12 +1044,38 @@ export default function LitecoinWallet() {
>
{walletInfoLtc?.address}
</Typography>
<Tooltip placement="top" title={copyLtcAddress ? copyLtcAddress : "Copy Address"}>
<Tooltip placement="right" title={copyLtcAddress ? copyLtcAddress : "Copy Address"}>
<IconButton aria-label="copy" size="small" onClick={() => { navigator.clipboard.writeText(walletInfoLtc?.address), changeCopyLtcStatus() }}>
<CopyAllTwoTone fontSize="small" />
</IconButton>
</Tooltip>
</div>
<div style={{
width: "100%",
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<Typography
variant="subtitle1"
align="center"
sx={{ color: 'primary.main', fontWeight: 700 }}
>
Electrum Server:&nbsp;&nbsp;
</Typography>
<Typography
variant="subtitle1"
align="center"
sx={{ color: 'text.primary', fontWeight: 700 }}
>
{currentElectrumServerLtc[0]?.hostName + ":" + currentElectrumServerLtc[0]?.port}
</Typography>
<Tooltip placement="right" title="CHange Server">
<IconButton aria-label="open-electrum" size="small" onClick={handleOpenLtcElectrum}>
<PublishedWithChangesTwoTone fontSize="small" />
</IconButton>
</Tooltip>
</div>
<div style={{
width: "100%",
display: 'flex',
@@ -755,9 +1108,27 @@ export default function LitecoinWallet() {
Address Book
</WalletButtons>
</div>
<Typography variant="h6" paddingTop={2} paddingBottom={2}>
Transactions:
</Typography>
<div style={{
width: "100%",
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<Typography variant="h6" paddingTop={2} paddingBottom={2}>
Transactions:
</Typography>
<Button
size="small"
onClick={handleLoadingRefreshLtc}
loading={loadingRefreshLtc}
loadingPosition="start"
startIcon={<Refresh />}
variant="outlined"
style={{ borderRadius: 50 }}
>
Refresh
</Button>
</div>
{isLoadingLtcTransactions ? tableLoader() : transactionsTable()}
</WalleteCard>
</Box>

File diff suppressed because it is too large Load Diff