2024-09-25 02:45:38 -04:00

2527 lines
72 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
createContext,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
import { useDropzone } from "react-dropzone";
import {
Box,
Button,
ButtonBase,
Checkbox,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Input,
InputLabel,
Popover,
Tooltip,
Typography,
} from "@mui/material";
import { decryptStoredWallet } from "./utils/decryptWallet";
import { CountdownCircleTimer } from "react-countdown-circle-timer";
import Logo1 from "./assets/svgs/Logo1.svg";
import Logo1Dark from "./assets/svgs/Logo1Dark.svg";
import RefreshIcon from "@mui/icons-material/Refresh";
import Logo2 from "./assets/svgs/Logo2.svg";
import Copy from "./assets/svgs/Copy.svg";
import ltcLogo from "./assets/ltc.png";
import qortLogo from "./assets/qort.png";
import { CopyToClipboard } from "react-copy-to-clipboard";
import Download from "./assets/svgs/Download.svg";
import Logout from "./assets/svgs/Logout.svg";
import Return from "./assets/svgs/Return.svg";
import Success from "./assets/svgs/Success.svg";
import Info from "./assets/svgs/Info.svg";
import CloseIcon from '@mui/icons-material/Close';
import {
createAccount,
generateRandomSentence,
saveFileToDisk,
} from "./utils/generateWallet/generateWallet";
import { kdf } from "./deps/kdf";
import { generateSaveWalletData } from "./utils/generateWallet/storeWallet";
import { crypto, walletVersion } from "./constants/decryptWallet";
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
import {
AddressBox,
AppContainer,
AuthenticatedContainer,
AuthenticatedContainerInnerLeft,
AuthenticatedContainerInnerRight,
CustomButton,
CustomInput,
CustomLabel,
TextItalic,
TextP,
TextSpan,
} from "./App-styles";
import { Spacer } from "./common/Spacer";
import { Loader } from "./components/Loader";
import { PasswordField, ErrorText } from "./components";
import { ChatGroup } from "./components/Chat/ChatGroup";
import { Group, requestQueueMemberNames } from "./components/Group/Group";
import { TaskManger } from "./components/TaskManager/TaskManger";
import { useModal } from "./common/useModal";
import { LoadingButton } from "@mui/lab";
import { Label } from "./components/Group/AddGroup";
import { CustomizedSnackbars } from "./components/Snackbar/Snackbar";
import SettingsIcon from '@mui/icons-material/Settings';
import {
getFee,
groupApi,
groupApiLocal,
groupApiSocket,
groupApiSocketLocal,
} from "./background";
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "./utils/events";
import { requestQueueCommentCount, requestQueuePublishedAccouncements } from "./components/Chat/GroupAnnouncements";
import { requestQueueGroupJoinRequests } from "./components/Group/GroupJoinRequests";
import { DrawerComponent } from "./components/Drawer/Drawer";
import { AddressQRCode } from "./components/AddressQRCode";
import { Settings } from "./components/Group/Settings";
import { MainAvatar } from "./components/MainAvatar";
type extStates =
| "not-authenticated"
| "authenticated"
| "send-qort"
| "web-app-request-connection"
| "web-app-request-payment"
| "web-app-request-authentication"
| "download-wallet"
| "create-wallet"
| "transfer-success-regular"
| "transfer-success-request"
| "wallet-dropped"
| "web-app-request-buy-order"
| "buy-order-submitted"
| "group";
interface MyContextInterface {
txList: any[];
memberGroups: any[];
setTxList: (val) => void;
setMemberGroups: (val) => void;
isShow: boolean;
onCancel: () => void;
onOk: () => void;
show: () => void;
message: any;
}
const defaultValues: MyContextInterface = {
txList: [],
memberGroups: [],
setTxList: () => {},
setMemberGroups: () => {},
isShow: false,
onCancel: () => {},
onOk: () => {},
show: () => {},
message: {
publishFee: "",
message: "",
},
};
export let isMobile = false
const isMobileDevice = () => {
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
if (/android/i.test(userAgent)) {
return true; // Android device
}
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
return true; // iOS device
}
return false;
};
if (isMobileDevice()) {
isMobile = true
console.log("Running on a mobile device");
} else {
console.log("Running on a desktop");
}
export const allQueues = {
requestQueueCommentCount: requestQueueCommentCount,
requestQueuePublishedAccouncements: requestQueuePublishedAccouncements,
requestQueueMemberNames: requestQueueMemberNames,
requestQueueGroupJoinRequests: requestQueueGroupJoinRequests
}
const controlAllQueues = (action) => {
Object.keys(allQueues).forEach((key) => {
const val = allQueues[key];
try {
if (typeof val[action] === 'function') {
val[action]();
}
} catch (error) {
console.error(error);
}
});
};
export const clearAllQueues = () => {
Object.keys(allQueues).forEach((key) => {
const val = allQueues[key];
try {
val.clear();
} catch (error) {
console.error(error);
}
});
}
export const pauseAllQueues = () => {
controlAllQueues('pause');
chrome?.runtime?.sendMessage(
{
action: "pauseAllQueues",
payload: {
},
}
);
}
export const resumeAllQueues = () => {
controlAllQueues('resume');
chrome?.runtime?.sendMessage(
{
action: "resumeAllQueues",
payload: {
},
}
);
}
export const MyContext = createContext<MyContextInterface>(defaultValues);
export let globalApiKey: string | null = null;
export const getBaseApiReact = (customApi?: string) => {
if (customApi) {
return customApi;
}
if (globalApiKey) {
return groupApiLocal;
} else {
return groupApi;
}
};
// export const getArbitraryEndpointReact = () => {
// if (globalApiKey) {
// return `/arbitrary/resources/search`;
// } else {
// return `/arbitrary/resources/searchsimple`;
// }
// };
export const getArbitraryEndpointReact = () => {
if (globalApiKey) {
return `/arbitrary/resources/search`;
} else {
return `/arbitrary/resources/searchsimple`;
}
};
export const getBaseApiReactSocket = (customApi?: string) => {
if (customApi) {
return customApi;
}
if (globalApiKey) {
return groupApiSocketLocal;
} else {
return groupApiSocket;
}
};
export const isMainWindow = window?.location?.href?.includes("?main=true");
function App() {
const [extState, setExtstate] = useState<extStates>("not-authenticated");
const [backupjson, setBackupjson] = useState<any>(null);
const [rawWallet, setRawWallet] = useState<any>(null);
const [ltcBalanceLoading, setLtcBalanceLoading] = useState<boolean>(false);
const [qortBalanceLoading, setQortBalanceLoading] = useState<boolean>(false);
const [decryptedWallet, setdecryptedWallet] = useState<any>(null);
const [requestConnection, setRequestConnection] = useState<any>(null);
const [requestBuyOrder, setRequestBuyOrder] = useState<any>(null);
const [authenticatedMode, setAuthenticatedMode] = useState("qort");
const [requestAuthentication, setRequestAuthentication] = useState<any>(null);
const [userInfo, setUserInfo] = useState<any>(null);
const [balance, setBalance] = useState<any>(null);
const [ltcBalance, setLtcBalance] = useState<any>(null);
const [paymentTo, setPaymentTo] = useState<string>("");
const [paymentAmount, setPaymentAmount] = useState<number>(0);
const [paymentPassword, setPaymentPassword] = useState<string>("");
const [sendPaymentError, setSendPaymentError] = useState<string>("");
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>("");
const [countdown, setCountdown] = useState<null | number>(null);
const [walletToBeDownloaded, setWalletToBeDownloaded] = useState<any>(null);
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
useState<string>("");
const [isMain, setIsMain] = useState<boolean>(
window?.location?.href?.includes("?main=true")
);
const isMainRef = useRef(false);
const [authenticatePassword, setAuthenticatePassword] = useState<string>("");
const [sendqortState, setSendqortState] = useState<any>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [
walletToBeDownloadedPasswordConfirm,
setWalletToBeDownloadedPasswordConfirm,
] = useState<string>("");
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
useState<string>("");
const [walletToBeDecryptedError, setWalletToBeDecryptedError] =
useState<string>("");
const [txList, setTxList] = useState([]);
const [memberGroups, setMemberGroups] = useState([]);
const [isFocused, setIsFocused] = useState(true);
const holdRefExtState = useRef<extStates>("not-authenticated");
const isFocusedRef = useRef<boolean>(true);
const { isShow, onCancel, onOk, show, message } = useModal();
const [openRegisterName, setOpenRegisterName] = useState(false);
const registerNamePopoverRef = useRef(null);
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
const [registerNameValue, setRegisterNameValue] = useState("");
const [infoSnack, setInfoSnack] = useState(null);
const [openSnack, setOpenSnack] = useState(false);
const [hasLocalNode, setHasLocalNode] = useState(false);
const [openAdvancedSettings, setOpenAdvancedSettings] = useState(false);
const [useLocalNode, setUseLocalNode] = useState(false);
const [confirmUseOfLocal, setConfirmUseOfLocal] = useState(false);
const [isOpenDrawerProfile, setIsOpenDrawerProfile] = useState(false);
const [apiKey, setApiKey] = useState("");
const [isOpenSendQort, setIsOpenSendQort] = useState(false)
const [isOpenSendQortSuccess, setIsOpenSendQortSuccess] = useState(false)
const [rootHeight, setRootHeight] = useState('100%')
const [isSettingsOpen, setIsSettingsOpen] = useState(false)
useEffect(() => {
if(!isMobile) return
// Function to set the height of the app to the viewport height
const resetHeight = () => {
const height = window.visualViewport ? window.visualViewport.height : window.innerHeight;
// Set the height to the root element (usually #root)
document.getElementById('root').style.height = height + "px";
setRootHeight(height + "px")
};
// Set the initial height
resetHeight();
// Add event listeners for resize and visualViewport changes
window.addEventListener('resize', resetHeight);
window.visualViewport?.addEventListener('resize', resetHeight);
// Clean up the event listeners when the component unmounts
return () => {
window.removeEventListener('resize', resetHeight);
window.visualViewport?.removeEventListener('resize', resetHeight);
};
}, []);
useEffect(() => {
chrome?.runtime?.sendMessage({ action: "getApiKey" }, (response) => {
if (response) {
globalApiKey = response;
setApiKey(response);
setUseLocalNode(true)
setConfirmUseOfLocal(true)
setOpenAdvancedSettings(true)
}
});
}, []);
useEffect(() => {
if (extState) {
holdRefExtState.current = extState;
}
}, [extState]);
useEffect(() => {
isFocusedRef.current = isFocused;
}, [isFocused]);
// Handler for file selection
const handleFileChangeApiKey = (event) => {
const file = event.target.files[0]; // Get the selected file
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result; // Get the file content
setApiKey(text); // Store the file content in the state
};
reader.readAsText(file); // Read the file as text
}
};
// const checkIfUserHasLocalNode = useCallback(async () => {
// try {
// const url = `http://127.0.0.1:12391/admin/status`;
// const response = await fetch(url, {
// method: "GET",
// headers: {
// "Content-Type": "application/json",
// },
// });
// const data = await response.json();
// if (data?.isSynchronizing === false && data?.syncPercent === 100) {
// setHasLocalNode(true);
// }
// } catch (error) {}
// }, []);
// useEffect(() => {
// checkIfUserHasLocalNode();
// }, [extState]);
const address = useMemo(() => {
if (!rawWallet?.address0) return "";
return rawWallet.address0;
}, [rawWallet]);
const { getRootProps, getInputProps } = useDropzone({
accept: {
"application/json": [".json"], // Only accept JSON files
},
maxFiles: 1,
onDrop: async (acceptedFiles) => {
const file: any = acceptedFiles[0];
const fileContents = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onabort = () => reject("File reading was aborted");
reader.onerror = () => reject("File reading has failed");
reader.onload = () => {
// Resolve the promise with the reader result when reading completes
resolve(reader.result);
};
// Read the file as text
reader.readAsText(file);
});
let error: any = null;
let pf: any;
try {
if (typeof fileContents !== "string") return;
pf = JSON.parse(fileContents);
} catch (e) {}
try {
const requiredFields = [
"address0",
"salt",
"iv",
"version",
"encryptedSeed",
"mac",
"kdfThreads",
];
for (const field of requiredFields) {
if (!(field in pf)) throw new Error(field + " not found in JSON");
}
// storeWalletInfo(pf);
setRawWallet(pf);
// setExtstate("authenticated");
setExtstate("wallet-dropped");
setdecryptedWallet(null);
} catch (e) {
console.log(e);
error = e;
}
},
});
const saveWalletFunc = async (password: string) => {
let wallet = structuredClone(rawWallet);
const res = await decryptStoredWallet(password, wallet);
const wallet2 = new PhraseWallet(res, walletVersion);
wallet = await wallet2.generateSaveWalletData(
password,
crypto.kdfThreads,
() => {}
);
setWalletToBeDownloaded({
wallet,
qortAddress: rawWallet.address0,
});
return {
wallet,
qortAddress: rawWallet.address0,
};
};
const storeWalletInfo = (wallet: any) => {
chrome?.runtime?.sendMessage(
{ action: "storeWalletInfo", wallet },
(response) => {
if (response) {
}
}
);
chrome.tabs.query(
{ active: true, currentWindow: true },
function (tabs: any[]) {
chrome.tabs.sendMessage(
tabs[0].id,
{ from: "popup", subject: "anySubject" },
function (response) {}
);
}
);
};
const getBalanceFunc = () => {
setQortBalanceLoading(true);
chrome?.runtime?.sendMessage({ action: "balance" }, (response) => {
if (!response?.error && !isNaN(+response)) {
setBalance(response);
}
setQortBalanceLoading(false);
});
};
const getLtcBalanceFunc = () => {
setLtcBalanceLoading(true);
chrome?.runtime?.sendMessage({ action: "ltcBalance" }, (response) => {
if (!response?.error && !isNaN(+response)) {
setLtcBalance(response);
}
setLtcBalanceLoading(false);
});
};
const sendCoinFunc = () => {
setSendPaymentError("");
setSendPaymentSuccess("");
if (!paymentTo) {
setSendPaymentError("Please enter a recipient");
return;
}
if (!paymentAmount) {
setSendPaymentError("Please enter an amount greater than 0");
return;
}
if (!paymentPassword) {
setSendPaymentError("Please enter your wallet password");
return;
}
setIsLoading(true);
chrome?.runtime?.sendMessage(
{
action: "sendCoin",
payload: {
amount: Number(paymentAmount),
receiver: paymentTo.trim(),
password: paymentPassword,
},
},
(response) => {
if (response?.error) {
setSendPaymentError(response.error);
} else {
setIsOpenSendQort(false)
setIsOpenSendQortSuccess(true)
// setExtstate("transfer-success-regular");
// setSendPaymentSuccess("Payment successfully sent");
}
setIsLoading(false);
}
);
};
const clearAllStates = () => {
setRequestConnection(null);
setRequestAuthentication(null);
};
useEffect(() => {
// Listen for messages from the background script
chrome.runtime?.onMessage.addListener((message, sender, sendResponse) => {
// Check if the message is to update the state
if (
message.action === "UPDATE_STATE_CONFIRM_SEND_QORT" &&
!isMainWindow
) {
// Update the component state with the received 'sendqort' state
setSendqortState(message.payload);
setExtstate("web-app-request-payment");
} else if (message.action === "closePopup" && !isMainWindow) {
// Update the component state with the received 'sendqort' state
window.close();
} else if (
message.action === "UPDATE_STATE_REQUEST_CONNECTION" &&
!isMainWindow
) {
// Update the component state with the received 'sendqort' state
setRequestConnection(message.payload);
setExtstate("web-app-request-connection");
} else if (
message.action === "UPDATE_STATE_REQUEST_BUY_ORDER" &&
!isMainWindow
) {
// Update the component state with the received 'sendqort' state
setRequestBuyOrder(message.payload);
setExtstate("web-app-request-buy-order");
} else if (
message.action === "UPDATE_STATE_REQUEST_AUTHENTICATION" &&
!isMainWindow
) {
// Update the component state with the received 'sendqort' state
setRequestAuthentication(message.payload);
setExtstate("web-app-request-authentication");
} else if (message.action === "SET_COUNTDOWN" && !isMainWindow) {
setCountdown(message.payload);
} else if (message.action === "INITIATE_MAIN") {
// Update the component state with the received 'sendqort' state
setIsMain(true);
isMainRef.current = true;
} else if (message.action === "CHECK_FOCUS" && isMainWindow) {
sendResponse(isFocusedRef.current);
} else if (
message.action === "NOTIFICATION_OPEN_DIRECT" &&
isMainWindow
) {
executeEvent("openDirectMessage", {
from: message.payload.from,
});
} else if (message.action === "NOTIFICATION_OPEN_GROUP" && isMainWindow) {
executeEvent("openGroupMessage", {
from: message.payload.from,
});
} else if (
message.action === "NOTIFICATION_OPEN_ANNOUNCEMENT_GROUP" &&
isMainWindow
) {
executeEvent("openGroupAnnouncement", {
from: message.payload.from,
});
} else if (
message.action === "NOTIFICATION_OPEN_THREAD_NEW_POST" &&
isMainWindow
) {
executeEvent("openThreadNewPost", {
data: message.payload.data,
});
}
});
}, []);
//param = isDecline
const confirmPayment = (isDecline: boolean) => {
if (isDecline) {
chrome?.runtime?.sendMessage(
{
action: "sendQortConfirmation",
payload: {
amount: sendqortState?.amount,
receiver: sendqortState?.address,
password: paymentPassword,
interactionId: sendqortState?.interactionId,
isDecline: true,
},
},
(response) => {
if (response) {
setSendPaymentSuccess("Payment successfully sent");
} else {
window.close();
}
}
);
return;
}
setIsLoading(true);
chrome?.runtime?.sendMessage(
{
action: "sendQortConfirmation",
payload: {
amount: sendqortState.amount,
receiver: sendqortState.address,
password: paymentPassword,
interactionId: sendqortState.interactionId,
isDecline: false,
},
},
(response) => {
if (response === true) {
setExtstate("transfer-success-request");
setCountdown(null);
} else {
setSendPaymentError(
response?.error || "Unable to perform payment. Please try again."
);
}
setIsLoading(false);
}
);
};
const confirmBuyOrder = (isDecline: boolean) => {
if (isDecline) {
chrome?.runtime?.sendMessage(
{
action: "buyOrderConfirmation",
payload: {
crosschainAtInfo: requestBuyOrder?.crosschainAtInfo,
interactionId: requestBuyOrder?.interactionId,
isDecline: true,
useLocal: requestBuyOrder?.useLocal
},
},
(response) => {
window.close();
}
);
return;
}
setIsLoading(true);
chrome?.runtime?.sendMessage(
{
action: "buyOrderConfirmation",
payload: {
crosschainAtInfo: requestBuyOrder?.crosschainAtInfo,
interactionId: requestBuyOrder?.interactionId,
isDecline: false,
useLocal: requestBuyOrder?.useLocal
},
},
(response) => {
if (response === true) {
setExtstate("buy-order-submitted");
setCountdown(null);
} else {
setSendPaymentError(
response?.error || "Unable to perform payment. Please try again."
);
}
setIsLoading(false);
}
);
};
const responseToConnectionRequest = (
isOkay: boolean,
hostname: string,
interactionId: string
) => {
chrome?.runtime?.sendMessage(
{
action: "responseToConnectionRequest",
payload: { isOkay, hostname, interactionId },
},
(response) => {
if (response === false || response === true) {
window.close();
}
}
);
};
// const rawWalletRef = useRef(null)
// useEffect(()=> {
// rawWalletRef.current = rawWallet
// }, [rawWallet])
useEffect(() => {
try {
setIsLoading(true);
chrome?.runtime?.sendMessage({ action: "getWalletInfo" }, (response) => {
if (response && response?.walletInfo) {
setRawWallet(response?.walletInfo);
if (
holdRefExtState.current === "web-app-request-payment" ||
holdRefExtState.current === "web-app-request-connection" ||
holdRefExtState.current === "web-app-request-buy-order"
)
return;
setExtstate("authenticated");
}
});
} catch (error) {
} finally {
setIsLoading(false);
}
}, []);
const getUserInfo = useCallback(async (useTimer?: boolean) => {
try {
if (useTimer) {
await new Promise((res) => {
setTimeout(() => {
res(null);
}, 10000);
});
}
chrome?.runtime?.sendMessage({ action: "userInfo" }, (response) => {
if (response && !response.error) {
setUserInfo(response);
}
});
getBalanceFunc();
} catch (error) {}
}, []);
useEffect(() => {
if (!address) return;
getUserInfo();
}, [address]);
useEffect(() => {
return () => {
console.log("exit");
};
}, []);
useEffect(() => {
if (
authenticatedMode === "ltc" &&
!ltcBalanceLoading &&
ltcBalance === null
) {
getLtcBalanceFunc();
}
}, [authenticatedMode]);
const confirmPasswordToDownload = async () => {
try {
setWalletToBeDownloadedError("");
if (!walletToBeDownloadedPassword) {
setSendPaymentError("Please enter your password");
return;
}
setIsLoading(true);
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 250);
});
const res = await saveWalletFunc(walletToBeDownloadedPassword);
} catch (error: any) {
setWalletToBeDownloadedError(error?.message);
} finally {
setIsLoading(false);
}
};
const saveFileToDiskFunc = async () => {
try {
await saveFileToDisk(
walletToBeDownloaded.wallet,
walletToBeDownloaded.qortAddress
);
} catch (error: any) {
setWalletToBeDownloadedError(error?.message);
} finally {
}
};
const createAccountFunc = async () => {
try {
if (!walletToBeDownloadedPassword) {
setWalletToBeDownloadedError("Please enter a password");
return;
}
if (!walletToBeDownloadedPasswordConfirm) {
setWalletToBeDownloadedError("Please confirm your password");
return;
}
if (
walletToBeDownloadedPasswordConfirm !== walletToBeDownloadedPassword
) {
setWalletToBeDownloadedError("Password fields do not match!");
return;
}
setIsLoading(true);
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 250);
});
const res = await createAccount();
const wallet = await res.generateSaveWalletData(
walletToBeDownloadedPassword,
crypto.kdfThreads,
() => {}
);
chrome?.runtime?.sendMessage(
{
action: "decryptWallet",
payload: {
password: walletToBeDownloadedPassword,
wallet,
},
},
(response) => {
if (response && !response?.error) {
setRawWallet(wallet);
setWalletToBeDownloaded({
wallet,
qortAddress: wallet.address0,
});
chrome?.runtime?.sendMessage({ action: "userInfo" }, (response2) => {
setIsLoading(false);
if (response2 && !response2.error) {
setUserInfo(response);
}
});
getBalanceFunc();
} else if (response?.error) {
setIsLoading(false);
setWalletToBeDecryptedError(response.error);
}
}
);
} catch (error: any) {
setWalletToBeDownloadedError(error?.message);
setIsLoading(false);
}
};
const logoutFunc = () => {
try {
chrome?.runtime?.sendMessage({ action: "logout" }, (response) => {
if (response) {
resetAllStates();
executeEvent("logout-event", {});
}
});
} catch (error) {}
};
const returnToMain = () => {
setPaymentTo("");
setPaymentAmount(0);
setPaymentPassword("");
setSendPaymentError("");
setSendPaymentSuccess("");
setCountdown(null);
setWalletToBeDownloaded(null);
setWalletToBeDownloadedPassword("");
setExtstate("authenticated");
setIsOpenSendQort(false)
setIsOpenSendQortSuccess(false)
};
const resetAllStates = () => {
setExtstate("not-authenticated");
setAuthenticatedMode("qort");
setBackupjson(null);
setRawWallet(null);
setdecryptedWallet(null);
setRequestConnection(null);
setRequestBuyOrder(null);
setRequestAuthentication(null);
setUserInfo(null);
setBalance(null);
setLtcBalance(null);
setPaymentTo("");
setPaymentAmount(0);
setPaymentPassword("");
setSendPaymentError("");
setSendPaymentSuccess("");
setCountdown(null);
setWalletToBeDownloaded(null);
setWalletToBeDownloadedPassword("");
setWalletToBeDownloadedPasswordConfirm("");
setWalletToBeDownloadedError("");
setSendqortState(null);
globalApiKey = null;
setApiKey("");
setUseLocalNode(false);
setHasLocalNode(false);
setOpenAdvancedSettings(false);
setConfirmUseOfLocal(false)
setTxList([])
setMemberGroups([])
};
function roundUpToDecimals(number, decimals = 8) {
const factor = Math.pow(10, decimals); // Create a factor based on the number of decimals
return Math.ceil(+number * factor) / factor;
}
const authenticateWallet = async () => {
try {
setIsLoading(true);
setWalletToBeDecryptedError("");
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 250);
});
chrome?.runtime?.sendMessage(
{
action: "decryptWallet",
payload: {
password: authenticatePassword,
wallet: rawWallet,
},
},
(response) => {
if (response && !response?.error) {
setAuthenticatePassword("");
setExtstate("authenticated");
setWalletToBeDecryptedError("");
chrome?.runtime?.sendMessage({ action: "userInfo" }, (response) => {
setIsLoading(false);
if (response && !response.error) {
setUserInfo(response);
}
});
getBalanceFunc();
chrome?.runtime?.sendMessage(
{ action: "getWalletInfo" },
(response) => {
if (response && response?.walletInfo) {
setRawWallet(response?.walletInfo);
}
}
);
} else if (response?.error) {
setIsLoading(false);
setWalletToBeDecryptedError(response.error);
}
}
);
} catch (error) {
setWalletToBeDecryptedError("Unable to authenticate. Wrong password");
}
};
// const handleBeforeUnload = (e)=> {
// const shouldClose = confirm('Are you sure you want to close this window? You may have unsaved changes.');
// if (!shouldClose) {
// // Prevent the window from closing
// e.preventDefault();
// e.returnValue = ''; // Required for Chrome
// } else {
// // Allow the window to close
// // No need to call preventDefault here; returnValue must be left empty
// }
// }
// useEffect(()=> {
// window.addEventListener('beforeunload', handleBeforeUnload);
// return ()=> {
// window.removeEventListener('beforeunload', handleBeforeUnload);
// }
// }, [])
useEffect(() => {
if (!isMainWindow || isMobile) return;
const handleBeforeUnload = (e) => {
e.preventDefault();
e.returnValue = ""; // This is required for Chrome to display the confirmation dialog.
return "";
};
// Add the event listener when the component mounts
window.addEventListener("beforeunload", handleBeforeUnload);
// Clean up the event listener when the component unmounts
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
};
}, []);
useEffect(() => {
if (!isMainWindow) return;
// Handler for when the window gains focus
const handleFocus = () => {
setIsFocused(true);
if(isMobile){
chrome?.runtime?.sendMessage(
{
action: "clearAllNotifications",
payload: {
},
}
);
}
console.log("Webview is focused");
};
// Handler for when the window loses focus
const handleBlur = () => {
setIsFocused(false);
console.log("Webview is not focused");
};
// Attach the event listeners
window.addEventListener("focus", handleFocus);
window.addEventListener("blur", handleBlur);
// Optionally, listen for visibility changes
const handleVisibilityChange = () => {
if (document.visibilityState === "visible") {
setIsFocused(true);
if(isMobile){
chrome?.runtime?.sendMessage(
{
action: "clearAllNotifications",
payload: {
},
}
);
}
console.log("Webview is visible");
} else {
setIsFocused(false);
console.log("Webview is hidden");
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
// Cleanup the event listeners on component unmount
return () => {
window.removeEventListener("focus", handleFocus);
window.removeEventListener("blur", handleBlur);
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, []);
const openPaymentInternal = (e) => {
const directAddress = e.detail?.address;
const name = e.detail?.name
setIsOpenSendQort(true)
setPaymentTo(name || directAddress)
};
useEffect(() => {
subscribeToEvent("openPaymentInternal", openPaymentInternal);
return () => {
unsubscribeFromEvent("openPaymentInternal", openPaymentInternal);
};
}, []);
const registerName = async () => {
try {
if (!userInfo?.address) throw new Error("Your address was not found");
const fee = await getFee("REGISTER_NAME");
await show({
message: "Would you like to register this name?",
publishFee: fee.fee + " QORT",
});
setIsLoadingRegisterName(true);
new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
action: "registerName",
payload: {
name: registerNameValue,
},
},
(response) => {
if (!response?.error) {
res(response);
setIsLoadingRegisterName(false);
setInfoSnack({
type: "success",
message:
"Successfully registered. It may take a couple of minutes for the changes to propagate",
});
setOpenRegisterName(false);
setRegisterNameValue("");
setOpenSnack(true);
setTxList((prev) => [
{
...response,
type: "register-name",
label: `Registered name: awaiting confirmation. This may take a couple minutes.`,
labelDone: `Registered name: success!`,
done: false,
},
...prev.filter((item) => !item.done),
]);
return;
}
setInfoSnack({
type: "error",
message: response?.error,
});
setOpenSnack(true);
rej(response.error);
}
);
});
} catch (error) {
if (error?.message) {
setInfoSnack({
type: "error",
message: error?.message,
});
}
} finally {
setIsLoadingRegisterName(false);
}
};
const renderProfile = ()=> {
return (
<AuthenticatedContainer sx={{ width: isMobile ? '100vw' : "350px", display: 'flex', backgroundColor: 'var(--bg-2)' }}>
{isMobile && (
<Box sx={{
padding: '10px',
display: 'flex',
justifyContent: 'flex-end'
}}><CloseIcon onClick={()=> {
setIsOpenDrawerProfile(false)
}} sx={{
cursor: 'pointer',
color: 'white'
}} /></Box>
)}
<AuthenticatedContainerInnerLeft>
<Spacer height="48px" />
{authenticatedMode === "ltc" ? (
<>
<img src={ltcLogo} />
<Spacer height="32px" />
<CopyToClipboard text={rawWallet?.ltcAddress}>
<AddressBox>
{rawWallet?.ltcAddress?.slice(0, 6)}...
{rawWallet?.ltcAddress?.slice(-4)} <img src={Copy} />
</AddressBox>
</CopyToClipboard>
<Spacer height="10px" />
{ltcBalanceLoading && (
<CircularProgress color="success" size={16} />
)}
{!isNaN(+ltcBalance) && !ltcBalanceLoading && (
<Box
sx={{
gap: "10px",
display: "flex",
alignItems: "center",
}}
>
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{ltcBalance} LTC
</TextP>
<RefreshIcon
onClick={getLtcBalanceFunc}
sx={{
fontSize: "16px",
color: "white",
cursor: "pointer",
}}
/>
</Box>
)}
<AddressQRCode targetAddress={rawWallet?.ltcAddress} />
</>
) : (
<>
<MainAvatar myName={userInfo?.name} />
<Spacer height="32px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
}}
>
{userInfo?.name}
</TextP>
<Spacer height="10px" />
<CopyToClipboard text={rawWallet?.address0}>
<AddressBox>
{rawWallet?.address0?.slice(0, 6)}...
{rawWallet?.address0?.slice(-4)} <img src={Copy} />
</AddressBox>
</CopyToClipboard>
<Spacer height="10px" />
{qortBalanceLoading && (
<CircularProgress color="success" size={16} />
)}
{!qortBalanceLoading && balance >= 0 && (
<Box
sx={{
gap: "10px",
display: "flex",
alignItems: "center",
}}
>
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
<RefreshIcon
onClick={getBalanceFunc}
sx={{
fontSize: "16px",
color: "white",
cursor: "pointer",
}}
/>
</Box>
)}
<Spacer height="35px" />
{userInfo && !userInfo?.name && (
<TextP
ref={registerNamePopoverRef}
sx={{
textAlign: "center",
lineHeight: 1.2,
fontSize: "16px",
fontWeight: 500,
cursor: "pointer",
marginTop: "10px",
color: "red",
textDecoration: "underline",
}}
onClick={() => {
setOpenRegisterName(true);
}}
>
REGISTER NAME
</TextP>
)}
<Spacer height="20px" />
<CustomButton
onClick={() => {
setIsOpenSendQort(true)
// setExtstate("send-qort");
setIsOpenDrawerProfile(false)
}}
>
Transfer QORT
</CustomButton>
<AddressQRCode targetAddress={rawWallet?.address0} />
</>
)}
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "12px",
fontWeight: 500,
cursor: "pointer",
marginTop: "10px",
textDecoration: "underline",
}}
onClick={() => {
chrome.tabs.create({ url: "https://www.qort.trade" });
}}
>
Get QORT at qort.trade
</TextP>
</AuthenticatedContainerInnerLeft>
<AuthenticatedContainerInnerRight>
<Spacer height="20px" />
<img
onClick={() => {
setExtstate("download-wallet");
setIsOpenDrawerProfile(false)
}}
src={Download}
style={{
cursor: "pointer",
}}
/>
{!isMobile && (
<>
<Spacer height="20px" />
<img
src={Logout}
onClick={()=> {
logoutFunc()
setIsOpenDrawerProfile(false)
}}
style={{
cursor: "pointer",
}}
/>
</>
)}
<Spacer height="20px" />
<ButtonBase onClick={()=> {
setIsSettingsOpen(true)
}}>
<SettingsIcon sx={{
color: 'rgba(255, 255, 255, 0.5)'
}} />
</ButtonBase>
<Spacer height="20px" />
{authenticatedMode === "qort" && (
<img
onClick={() => {
setAuthenticatedMode("ltc");
}}
src={ltcLogo}
style={{
cursor: "pointer",
width: "20px",
height: "auto",
}}
/>
)}
{authenticatedMode === "ltc" && (
<img
onClick={() => {
setAuthenticatedMode("qort");
}}
src={qortLogo}
style={{
cursor: "pointer",
width: "20px",
height: "auto",
}}
/>
)}
</AuthenticatedContainerInnerRight>
</AuthenticatedContainer>
)
}
return (
<AppContainer sx={{
height: isMobile ? '100%' : '100vh'
}}>
{/* {extState === 'group' && (
<Group myAddress={userInfo?.address} />
)} */}
{extState === "not-authenticated" && (
<>
<Spacer height="48px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="38px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
WELCOME TO <TextItalic>YOUR</TextItalic> <br></br>
<TextSpan> QORTAL WALLET</TextSpan>
</TextP>
<Spacer height="38px" />
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
marginLeft: "28px",
}}
>
<CustomButton {...getRootProps()}>
<input {...getInputProps()} />
Authenticate
</CustomButton>
<Tooltip
title="Authenticate by importing your Qortal JSON file"
arrow
>
<img src={Info} />
</Tooltip>
</Box>
<Spacer height="6px" />
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
marginLeft: "28px",
}}
>
<CustomButton
onClick={() => {
setExtstate("create-wallet");
}}
>
Create account
</CustomButton>
<img
src={Info}
style={{
visibility: "hidden",
}}
/>
</Box>
<>
<Spacer height="15px" />
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
flexDirection: "column",
}}
>
<Typography
sx={{
cursor: 'pointer',
fontSize: '14px'
}}
onClick={() => {
setOpenAdvancedSettings(true);
}}
>
Advanced settings
</Typography>
{openAdvancedSettings && (
<>
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
justifyContent: 'center',
width: '100%'
}}
>
<Checkbox
edge="start"
checked={useLocalNode}
tabIndex={-1}
disableRipple
onChange={(event) => {
setUseLocalNode(event.target.checked);
}}
disabled={confirmUseOfLocal}
sx={{
"&.Mui-checked": {
color: "white", // Customize the color when checked
},
"& .MuiSvgIcon-root": {
color: "white",
},
}}
/>
<Typography>Use local node</Typography>
</Box>
{useLocalNode && (
<>
<Button disabled={confirmUseOfLocal} variant="contained" component="label">
Select apiKey.txt
<input
type="file"
accept=".txt"
hidden
onChange={handleFileChangeApiKey} // File input handler
/>
</Button>
<Spacer height="5px" />
<Typography
sx={{
fontSize: "12px",
}}
>
{apiKey}
</Typography>
<Spacer height="5px" />
<Button
onClick={() => {
const valueToSet = !confirmUseOfLocal
const payload = valueToSet ? apiKey : null
chrome?.runtime?.sendMessage(
{ action: "setApiKey", payload },
(response) => {
if (response) {
globalApiKey = payload;
setConfirmUseOfLocal(valueToSet)
if(!globalApiKey){
setUseLocalNode(false)
setOpenAdvancedSettings(false)
setApiKey('')
}
}
}
);
}}
variant="contained"
sx={{
color: "white",
}}
>
{!confirmUseOfLocal ? 'Confirm use of local node' : 'Switch back to gateway'}
</Button>
</>
)}
</>
)}
</Box>
</>
</>
)}
{/* {extState !== "not-authenticated" && (
<button onClick={logoutFunc}>logout</button>
)} */}
{extState === "authenticated" && isMainWindow && (
<MyContext.Provider
value={{
txList,
setTxList,
memberGroups,
setMemberGroups,
isShow,
onCancel,
onOk,
show,
message,
rootHeight
}}
>
<Box
sx={{
width: "100vw",
height: isMobile ? '100%' : "100vh",
display: "flex",
flexDirection: isMobile ? 'column' : 'row',
overflow: isMobile && 'hidden'
}}
>
<Group
logoutFunc={logoutFunc}
balance={balance}
userInfo={userInfo}
myAddress={address}
isFocused={isFocused}
isMain={isMain}
isOpenDrawerProfile={isOpenDrawerProfile}
setIsOpenDrawerProfile={setIsOpenDrawerProfile}
/>
{!isMobile && renderProfile()}
</Box>
{!isMobile && (
<Box
sx={{
position: "fixed",
right: "25px",
bottom: "25px",
width: "350px",
zIndex: 100000,
}}
>
<TaskManger getUserInfo={getUserInfo} />
</Box>
)}
</MyContext.Provider>
)}
{isOpenSendQort && isMainWindow && (
<Box sx={{
width: '100%',
height: '100%',
position: 'fixed',
background: '#27282c',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
zIndex: 6
}}>
<Spacer height="22px" />
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
}}
>
<img
style={{
cursor: "pointer",
}}
onClick={returnToMain}
src={Return}
/>
</Box>
<Spacer height="35px" />
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Transfer QORT
</TextP>
<Spacer height="35px" />
<TextP
sx={{
textAlign: "start",
lineHeight: "16px",
fontSize: "20px",
fontWeight: 600,
color: "rgba(255, 255, 255, 0.5)",
}}
>
Balance:
</TextP>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
</Box>
<Spacer height="35px" />
<Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
value={paymentTo}
onChange={(e) => setPaymentTo(e.target.value)}
autoComplete="off"
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">
Amount
</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-amount"
type="number"
value={paymentAmount}
onChange={(e) => setPaymentAmount(+e.target.value)}
autoComplete="off"
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
autoComplete="off"
/>
</Box>
<Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" />
<CustomButton
onClick={() => {
sendCoinFunc();
}}
>
Send
</CustomButton>
</Box>
)}
{extState === "web-app-request-buy-order" && !isMainWindow && (
<>
<Spacer height="100px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The Application <br></br>{" "}
<TextItalic>{requestBuyOrder?.hostname}</TextItalic> <br></br>
<TextSpan>is requesting {requestBuyOrder?.crosschainAtInfo?.length} {`buy order${requestBuyOrder?.crosschainAtInfo.length === 1 ? '' : 's'}`}</TextSpan>
</TextP>
<Spacer height="10px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{requestBuyOrder?.crosschainAtInfo?.reduce((latest, cur)=> {
return latest + +cur?.qortAmount
}, 0)} QORT
</TextP>
<Spacer height="15px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
fontSize: "14px",
}}
>
FOR
</TextP>
<Spacer height="15px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{roundUpToDecimals(requestBuyOrder?.crosschainAtInfo?.reduce((latest, cur)=> {
return latest + +cur?.expectedForeignAmount
}, 0))}
{` ${requestBuyOrder?.crosschainAtInfo?.[0]?.foreignBlockchain}`}
</TextP>
{/* <Spacer height="29px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
/> */}
<Spacer height="29px" />
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "14px",
}}
>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => confirmBuyOrder(false)}
>
accept
</CustomButton>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => confirmBuyOrder(true)}
>
decline
</CustomButton>
</Box>
<ErrorText>{sendPaymentError}</ErrorText>
</>
)}
{extState === "web-app-request-payment" && !isMainWindow && (
<>
<Spacer height="100px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The Application <br></br>{" "}
<TextItalic>{sendqortState?.hostname}</TextItalic> <br></br>
<TextSpan>is requesting a payment</TextSpan>
</TextP>
<Spacer height="10px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
fontSize: "10px",
}}
>
{sendqortState?.description}
</TextP>
<Spacer height="15px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{sendqortState?.amount} QORT
</TextP>
{/* <Spacer height="29px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
/> */}
<Spacer height="29px" />
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "14px",
}}
>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => confirmPayment(false)}
>
accept
</CustomButton>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => confirmPayment(true)}
>
decline
</CustomButton>
</Box>
<ErrorText>{sendPaymentError}</ErrorText>
</>
)}
{extState === "web-app-request-connection" && !isMainWindow && (
<>
<Spacer height="48px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="38px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The Application <br></br>{" "}
<TextItalic>{requestConnection?.hostname}</TextItalic> <br></br>
<TextSpan>is requestion a connection</TextSpan>
</TextP>
<Spacer height="38px" />
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "14px",
}}
>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() =>
responseToConnectionRequest(
true,
requestConnection?.hostname,
requestConnection.interactionId
)
}
>
accept
</CustomButton>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() =>
responseToConnectionRequest(
false,
requestConnection?.hostname,
requestConnection.interactionId
)
}
>
decline
</CustomButton>
</Box>
</>
)}
{extState === "web-app-request-authentication" && !isMainWindow && (
<>
<Spacer height="48px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="38px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The Application <br></br>{" "}
<TextItalic>{requestConnection?.hostname}</TextItalic> <br></br>
<TextSpan>requests authentication</TextSpan>
</TextP>
<Spacer height="38px" />
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "14px",
}}
></Box>
<Spacer height="38px" />
<CustomButton {...getRootProps()}>
<input {...getInputProps()} />
Authenticate
</CustomButton>
<Spacer height="6px" />
<CustomButton
onClick={() => {
setExtstate("create-wallet");
}}
>
Create account
</CustomButton>
</>
)}
{rawWallet && extState === "wallet-dropped" && (
<>
<Spacer height="22px" />
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
}}
>
<img
style={{
cursor: "pointer",
}}
onClick={() => {
setRawWallet(null);
setExtstate("not-authenticated");
}}
src={Return}
/>
</Box>
<Spacer height="10px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="35px" />
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Authenticate
</TextP>
</Box>
<Spacer height="35px" />
<>
<CustomLabel htmlFor="standard-adornment-password">
Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={authenticatePassword}
onChange={(e) => setAuthenticatePassword(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
authenticateWallet();
}
}}
/>
<Spacer height="20px" />
<CustomButton onClick={authenticateWallet}>
Authenticate
</CustomButton>
<ErrorText>{walletToBeDecryptedError}</ErrorText>
</>
</>
)}
{extState === "download-wallet" && (
<>
<Spacer height="22px" />
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
}}
>
<img
style={{
cursor: "pointer",
}}
onClick={returnToMain}
src={Return}
/>
</Box>
<Spacer height="10px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="35px" />
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Download Wallet
</TextP>
</Box>
<Spacer height="35px" />
{!walletToBeDownloaded && (
<>
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={walletToBeDownloadedPassword}
onChange={(e) =>
setWalletToBeDownloadedPassword(e.target.value)
}
/>
<Spacer height="20px" />
<CustomButton onClick={confirmPasswordToDownload}>
Confirm password
</CustomButton>
<ErrorText>{walletToBeDownloadedError}</ErrorText>
</>
)}
{walletToBeDownloaded && (
<>
<CustomButton onClick={saveFileToDiskFunc}>
Download wallet
</CustomButton>
</>
)}
</>
)}
{extState === "create-wallet" && (
<>
{!walletToBeDownloaded && (
<>
<Spacer height="22px" />
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
}}
>
<img
style={{
cursor: "pointer",
}}
onClick={() => {
setExtstate("not-authenticated");
}}
src={Return}
/>
</Box>
<Spacer height="15px" />
<div
className="image-container"
style={{
width: "136px",
height: "154px",
}}
>
<img src={Logo1} className="base-image" />
<img src={Logo1Dark} className="hover-image" />
</div>
<Spacer height="38px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
Set up your Qortal account
</TextP>
<Spacer height="14px" />
<CustomLabel htmlFor="standard-adornment-password">
Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={walletToBeDownloadedPassword}
onChange={(e) =>
setWalletToBeDownloadedPassword(e.target.value)
}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={walletToBeDownloadedPasswordConfirm}
onChange={(e) =>
setWalletToBeDownloadedPasswordConfirm(e.target.value)
}
/>
<Spacer height="17px" />
<CustomButton onClick={createAccountFunc}>
Create Account
</CustomButton>
<ErrorText>{walletToBeDownloadedError}</ErrorText>
</>
)}
{walletToBeDownloaded && (
<>
<Spacer height="48px" />
<img src={Success} />
<Spacer height="45px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
Congrats, youre all set up!
</TextP>
<Spacer height="100px" />
<CustomButton
onClick={() => {
saveFileToDiskFunc();
returnToMain();
}}
>
Backup Account
</CustomButton>
</>
)}
</>
)}
{isOpenSendQortSuccess && (
<Box sx={{
width: '100%',
height: '100%',
position: 'fixed',
background: '#27282c',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
zIndex: 6
}}>
<Spacer height="48px" />
<img src={Success} />
<Spacer height="45px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The transfer was succesful!
</TextP>
<Spacer height="100px" />
<CustomButton
onClick={() => {
returnToMain();
}}
>
Continue
</CustomButton>
</Box>
)}
{extState === "transfer-success-request" && (
<>
<Spacer height="48px" />
<img src={Success} />
<Spacer height="45px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
The transfer was succesful!
</TextP>
<Spacer height="100px" />
<CustomButton
onClick={() => {
window.close();
}}
>
Continue
</CustomButton>
</>
)}
{extState === "buy-order-submitted" && (
<>
<Spacer height="48px" />
<img src={Success} />
<Spacer height="45px" />
<TextP
sx={{
textAlign: "center",
lineHeight: "15px",
}}
>
Your buy order was submitted
</TextP>
<Spacer height="100px" />
<CustomButton
onClick={() => {
window.close();
}}
>
Close
</CustomButton>
</>
)}
{countdown && (
<Box
style={{
position: "absolute",
top: "20px",
left: "20px",
}}
>
{/* <Spacer height="25px"/> */}
<CountdownCircleTimer
isPlaying
duration={countdown}
colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
colorsTime={[7, 5, 2, 0]}
onComplete={() => {
window.close();
}}
size={75}
strokeWidth={8}
>
{({ remainingTime }) => <TextP>{remainingTime}</TextP>}
</CountdownCircleTimer>
</Box>
)}
{isLoading && <Loader />}
{isShow && (
<Dialog
open={isShow}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Publish"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{message.message}
</DialogContentText>
<DialogContentText id="alert-dialog-description2">
publish fee: {message.publishFee}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={onCancel}>
Disagree
</Button>
<Button variant="contained" onClick={onOk} autoFocus>
Agree
</Button>
</DialogActions>
</Dialog>
)}
<Popover
open={openRegisterName}
anchorEl={registerNamePopoverRef.current}
onClose={() => {
setOpenRegisterName(false);
setRegisterNameValue("");
}}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
}}
style={{ marginTop: "8px" }}
>
<Box
sx={{
width: "325px",
height: "250px",
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
padding: "10px",
}}
>
<Label>Choose a name</Label>
<Input
onChange={(e) => setRegisterNameValue(e.target.value)}
value={registerNameValue}
placeholder="Choose a name"
/>
<Spacer height="25px" />
<LoadingButton
loading={isLoadingRegisterName}
loadingPosition="start"
variant="contained"
disabled={!registerNameValue}
onClick={registerName}
>
Register Name
</LoadingButton>
</Box>
</Popover>
{isSettingsOpen && (
<Settings open={isSettingsOpen} setOpen={setIsSettingsOpen} />
)}
<CustomizedSnackbars
open={openSnack}
setOpen={setOpenSnack}
info={infoSnack}
setInfo={setInfoSnack}
/>
<DrawerComponent open={isOpenDrawerProfile} setOpen={setIsOpenDrawerProfile} >{renderProfile()}</DrawerComponent>
</AppContainer>
);
}
export default App;