Compare commits

..

No commits in common. "feature/initial-conversion" and "v0.5.4-pre" have entirely different histories.

28 changed files with 306 additions and 2274 deletions

View File

@ -21,7 +21,6 @@ import {
DialogContentText, DialogContentText,
DialogTitle, DialogTitle,
Divider, Divider,
FormControlLabel,
Input, Input,
InputLabel, InputLabel,
Popover, Popover,
@ -30,7 +29,6 @@ import {
} from "@mui/material"; } from "@mui/material";
import { decryptStoredWallet } from "./utils/decryptWallet"; import { decryptStoredWallet } from "./utils/decryptWallet";
import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet'; import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet';
import PriorityHighIcon from '@mui/icons-material/PriorityHigh';
import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite'; import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite';
import 'react-json-view-lite/dist/index.css'; import 'react-json-view-lite/dist/index.css';
@ -155,7 +153,6 @@ import { BuyQortInformation } from "./components/BuyQortInformation";
import { InstallPWA } from "./components/InstallPWA"; import { InstallPWA } from "./components/InstallPWA";
import { QortPayment } from "./components/QortPayment"; import { QortPayment } from "./components/QortPayment";
import { PdfViewer } from "./common/PdfViewer"; import { PdfViewer } from "./common/PdfViewer";
import { DownloadWallet } from "./components/Auth/DownloadWallet";
type extStates = type extStates =
@ -489,8 +486,6 @@ function App() {
url: "http://127.0.0.1:12391", url: "http://127.0.0.1:12391",
}); });
const [useLocalNode, setUseLocalNode] = useState(false); const [useLocalNode, setUseLocalNode] = useState(false);
const [confirmRequestRead, setConfirmRequestRead] = useState(false);
const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [showSeed, setShowSeed] = useState(false) const [showSeed, setShowSeed] = useState(false)
const [creationStep, setCreationStep] = useState(1) const [creationStep, setCreationStep] = useState(1)
@ -883,8 +878,6 @@ function App() {
if(message?.payload?.checkbox1){ if(message?.payload?.checkbox1){
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1?.value || false qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1?.value || false
} }
setConfirmRequestRead(false)
await showQortalRequestExtension(message?.payload); await showQortalRequestExtension(message?.payload);
if (qortalRequestCheckbox1Ref.current) { if (qortalRequestCheckbox1Ref.current) {
event.source.postMessage( event.source.postMessage(
@ -2585,14 +2578,87 @@ function App() {
)} )}
{extState === "download-wallet" && ( {extState === "download-wallet" && (
<> <>
<DownloadWallet <Spacer height="22px" />
returnToMain={returnToMain} <Box
setIsLoading={setIsLoading} sx={{
showInfo={showInfo} display: "flex",
rawWallet={rawWallet} width: "100%",
setWalletToBeDownloaded={setWalletToBeDownloaded} justifyContent: "flex-start",
walletToBeDownloaded={walletToBeDownloaded} 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={Logo1Dark} className="base-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 Account
</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={async ()=> {
await saveFileToDiskFunc()
await showInfo({
message: isNative ? `Your account file was saved to internal storage, in the document folder. Keep that file secure.` : `Your account file was downloaded by your browser. Keep that file secure.` ,
})
}}>
Download account
</CustomButton>
</>
)}
</> </>
)} )}
{extState === "create-wallet" && ( {extState === "create-wallet" && (
@ -3044,7 +3110,7 @@ function App() {
> >
<CountdownCircleTimer <CountdownCircleTimer
isPlaying isPlaying
duration={60} duration={30}
colors={["#004777", "#F7B801", "#A30000", "#A30000"]} colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
colorsTime={[7, 5, 2, 0]} colorsTime={[7, 5, 2, 0]}
onComplete={() => { onComplete={() => {
@ -3125,14 +3191,12 @@ function App() {
> >
{messageQortalRequestExtension?.text3} {messageQortalRequestExtension?.text3}
</TextP> </TextP>
</Box>
<Spacer height="15px" /> <Spacer height="15px" />
</Box>
</> </>
)} )}
{messageQortalRequestExtension?.text4 && ( {messageQortalRequestExtension?.text4 && (
<>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -3150,8 +3214,6 @@ function App() {
{messageQortalRequestExtension?.text4} {messageQortalRequestExtension?.text4}
</TextP> </TextP>
</Box> </Box>
<Spacer height="15px" />
</>
)} )}
{messageQortalRequestExtension?.html && ( {messageQortalRequestExtension?.html && (
@ -3279,35 +3341,6 @@ function App() {
</Typography> </Typography>
</Box> </Box>
)} )}
{messageQortalRequestExtension?.confirmCheckbox && (
<FormControlLabel
control={
<Checkbox
onChange={(e) => setConfirmRequestRead(e.target.checked)}
checked={confirmRequestRead}
edge="start"
tabIndex={-1}
disableRipple
sx={{
"&.Mui-checked": {
color: "white",
},
"& .MuiSvgIcon-root": {
color: "white",
},
}}
/>
}
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography sx={{ fontSize: "14px" }}>
I have read this request
</Typography>
<PriorityHighIcon color="warning" />
</Box>
}
/>
)}
<Spacer height="29px" /> <Spacer height="29px" />
<Box <Box
@ -3322,16 +3355,8 @@ function App() {
bgColor="var(--green)" bgColor="var(--green)"
sx={{ sx={{
minWidth: "102px", minWidth: "102px",
opacity: messageQortalRequestExtension?.confirmCheckbox && !confirmRequestRead ? 0.1 : 0.7,
cursor: messageQortalRequestExtension?.confirmCheckbox && !confirmRequestRead ? 'default' : 'pointer',
"&:hover": {
opacity: messageQortalRequestExtension?.confirmCheckbox && !confirmRequestRead ? 0.1 : 1,
}
}}
onClick={() => {
if(messageQortalRequestExtension?.confirmCheckbox && !confirmRequestRead) return
onOkQortalRequestExtension("accepted")
}} }}
onClick={() => onOkQortalRequestExtension("accepted")}
> >
accept accept
</CustomButtonAccept> </CustomButtonAccept>

View File

@ -41,14 +41,6 @@ export const sortablePinnedAppsAtom = atom({
{ {
name: 'Q-Wallets', name: 'Q-Wallets',
service: 'APP' service: 'APP'
},
{
name: 'Q-Search',
service: 'APP'
},
{
name: 'Q-Nodecontrol',
service: 'APP'
} }
], ],
}); });
@ -188,8 +180,3 @@ export const lastPaymentSeenTimestampAtom = atom<null | number>({
key: 'lastPaymentSeenTimestampAtom', key: 'lastPaymentSeenTimestampAtom',
default: null, default: null,
}); });
export const isOpenBlockedModalAtom = atom({
key: 'isOpenBlockedModalAtom',
default: false,
});

View File

@ -928,59 +928,6 @@ export async function getBalanceInfo() {
const data = await response.json(); const data = await response.json();
return data; return data;
} }
export async function getAssetBalanceInfo(assetId: number) {
const wallet = await getSaveWallet();
const address = wallet.address0;
const validApi = await getBaseApi();
const response = await fetch(validApi + `/assets/balances?address=${address}&assetid=${assetId}&ordering=ASSET_BALANCE_ACCOUNT&limit=1`);
if (!response?.ok) throw new Error("Cannot fetch asset balance");
const data = await response.json();
return +data?.[0]?.balance
}
export async function getAssetInfo(assetId: number) {
const validApi = await getBaseApi();
const response = await fetch(validApi + `/assets/info?assetId=${assetId}`);
if (!response?.ok) throw new Error("Cannot fetch asset info");
const data = await response.json();
return data
}
export async function transferAsset({
amount,
recipient,
assetId,
}) {
const lastReference = await getLastRef();
const resKeyPair = await getKeyPair();
const parsedData = resKeyPair;
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
const uint8PublicKey = Base58.decode(parsedData.publicKey);
const keyPair = {
privateKey: uint8PrivateKey,
publicKey: uint8PublicKey,
};
const feeres = await getFee("TRANSFER_ASSET");
const tx = await createTransaction(12, keyPair, {
fee: feeres.fee,
recipient: recipient,
amount: amount,
assetId: assetId,
lastReference: lastReference,
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
}
export async function getLTCBalance() { export async function getLTCBalance() {
const wallet = await getSaveWallet(); const wallet = await getSaveWallet();
let _url = `${buyTradeNodeBaseUrl}/crosschain/ltc/walletbalance`; let _url = `${buyTradeNodeBaseUrl}/crosschain/ltc/walletbalance`;
@ -2300,150 +2247,6 @@ export async function createGroup({
if (!res?.signature) throw new Error(res?.message || "Transaction was not able to be processed"); if (!res?.signature) throw new Error(res?.message || "Transaction was not able to be processed");
return res; return res;
} }
export async function sellName({
name,
sellPrice
}) {
const wallet = await getSaveWallet();
const address = wallet.address0;
if (!address) throw new Error("Cannot find user");
const lastReference = await getLastRef();
const feeres = await getFee("SELL_NAME");
const resKeyPair = await getKeyPair();
const parsedData = resKeyPair;
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
const uint8PublicKey = Base58.decode(parsedData.publicKey);
const keyPair = {
privateKey: uint8PrivateKey,
publicKey: uint8PublicKey,
};
const tx = await createTransaction(5, keyPair, {
fee: feeres.fee,
name,
sellPrice: sellPrice,
lastReference: lastReference,
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
}
export async function cancelSellName({
name
}) {
const wallet = await getSaveWallet();
const address = wallet.address0;
if (!address) throw new Error("Cannot find user");
const lastReference = await getLastRef();
const feeres = await getFee("SELL_NAME");
const resKeyPair = await getKeyPair();
const parsedData = resKeyPair;
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
const uint8PublicKey = Base58.decode(parsedData.publicKey);
const keyPair = {
privateKey: uint8PrivateKey,
publicKey: uint8PublicKey,
};
const tx = await createTransaction(6, keyPair, {
fee: feeres.fee,
name,
lastReference: lastReference,
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
}
export async function buyName({
name,
sellerAddress,
sellPrice
}) {
const wallet = await getSaveWallet();
const address = wallet.address0;
if (!address) throw new Error("Cannot find user");
const lastReference = await getLastRef();
const feeres = await getFee("BUY_NAME");
const resKeyPair = await getKeyPair();
const parsedData = resKeyPair;
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
const uint8PublicKey = Base58.decode(parsedData.publicKey);
const keyPair = {
privateKey: uint8PrivateKey,
publicKey: uint8PublicKey,
};
const tx = await createTransaction(7, keyPair, {
fee: feeres.fee,
name,
sellPrice,
recipient: sellerAddress,
lastReference: lastReference,
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
}
export async function updateGroup({
groupId,
newOwner,
newIsOpen,
newDescription,
newApprovalThreshold,
newMinimumBlockDelay,
newMaximumBlockDelay
}) {
const wallet = await getSaveWallet();
const address = wallet.address0;
if (!address) throw new Error("Cannot find user");
const lastReference = await getLastRef();
const feeres = await getFee("UPDATE_GROUP");
const resKeyPair = await getKeyPair();
const parsedData = resKeyPair;
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
const uint8PublicKey = Base58.decode(parsedData.publicKey);
const keyPair = {
privateKey: uint8PrivateKey,
publicKey: uint8PublicKey,
};
const tx = await createTransaction(23, keyPair, {
fee: feeres.fee,
_groupId: groupId,
newOwner,
newIsOpen,
newDescription,
newApprovalThreshold,
newMinimumBlockDelay,
newMaximumBlockDelay,
lastReference: lastReference,
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
}
export async function inviteToGroup({ groupId, qortalAddress, inviteTime }) { export async function inviteToGroup({ groupId, qortalAddress, inviteTime }) {
const address = await getNameOrAddress(qortalAddress); const address = await getNameOrAddress(qortalAddress);
if (!address) throw new Error("Cannot find user"); if (!address) throw new Error("Cannot find user");

View File

@ -130,17 +130,12 @@ export const BoundedNumericTextField = ({
...props?.InputProps, ...props?.InputProps,
endAdornment: addIconButtons ? ( endAdornment: addIconButtons ? (
<InputAdornment position="end"> <InputAdornment position="end">
<IconButton size="small" onClick={() => <IconButton size="small" onClick={() => changeValueWithIncDecButton(1)}>
changeValueWithIncDecButton(1)
} onTouchStart={(e)=> e.stopPropagation()}>
<AddIcon sx={{ <AddIcon sx={{
color: 'white' color: 'white'
}} />{" "} }} />{" "}
</IconButton> </IconButton>
<IconButton onTouchStart={(e)=> e.stopPropagation()} size="small" onClick={() => <IconButton size="small" onClick={() => changeValueWithIncDecButton(-1)}>
changeValueWithIncDecButton(-1)
}>
<RemoveIcon sx={{ <RemoveIcon sx={{
color: 'white' color: 'white'
}} />{" "} }} />{" "}

View File

@ -41,9 +41,7 @@ const officialAppList = [
"q-trade", "q-trade",
"q-support", "q-support",
"q-manager", "q-manager",
"q-wallets", "q-wallets"
"q-search",
"q-nodecontrol"
]; ];
const ScrollerStyled = styled('div')({ const ScrollerStyled = styled('div')({

View File

@ -47,9 +47,7 @@ const officialAppList = [
"q-fund", "q-fund",
"q-shop", "q-shop",
"q-manager", "q-manager",
"q-wallets", "q-wallets"
"q-search",
"q-nodecontrol"
]; ];
const ScrollerStyled = styled("div")({ const ScrollerStyled = styled("div")({

View File

@ -45,9 +45,7 @@ const officialAppList = [
"q-support", "q-support",
"q-manager", "q-manager",
"q-mintership", "q-mintership",
"q-wallets", "q-wallets"
"q-search",
"q-nodecontrol"
]; ];
const ScrollerStyled = styled('div')({ const ScrollerStyled = styled('div')({

View File

@ -56,9 +56,7 @@ const officialAppList = [
"q-shop", "q-shop",
"q-manager", "q-manager",
"q-mintership", "q-mintership",
"q-wallets", "q-wallets"
"q-search",
"q-nodecontrol"
]; ];
const ScrollerStyled = styled("div")({ const ScrollerStyled = styled("div")({

View File

@ -255,13 +255,7 @@ export function openIndexedDB() {
'GET_NODE_INFO', 'GET_NODE_INFO',
'GET_NODE_STATUS', 'GET_NODE_STATUS',
'GET_ARRR_SYNC_STATUS', 'GET_ARRR_SYNC_STATUS',
'SHOW_PDF_READER', 'SHOW_PDF_READER'
'UPDATE_GROUP',
'SELL_NAME',
'CANCEL_SELL_NAME',
'BUY_NAME', 'MULTI_ASSET_PAYMENT_WITH_PRIVATE_DATA',
'TRANSFER_ASSET',
'SIGN_FOREIGN_FEES',
] ]
@ -275,11 +269,7 @@ const UIQortalRequests = [
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER', 'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER', 'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER',
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_PUBLIC_NODE', 'SIGN_TRANSACTION', 'ADMIN_ACTION', 'OPEN_NEW_TAB', 'CREATE_AND_COPY_EMBED_LINK', 'DECRYPT_QORTAL_GROUP_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'SHOW_ACTIONS', 'REGISTER_NAME', 'UPDATE_NAME', 'LEAVE_GROUP', 'INVITE_TO_GROUP', 'KICK_FROM_GROUP', 'BAN_FROM_GROUP', 'CANCEL_GROUP_BAN', 'ADD_GROUP_ADMIN', 'REMOVE_GROUP_ADMIN','DECRYPT_AESGCM', 'CANCEL_GROUP_INVITE', 'CREATE_GROUP', 'GET_USER_WALLET_TRANSACTIONS', 'GET_NODE_INFO', 'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_PUBLIC_NODE', 'SIGN_TRANSACTION', 'ADMIN_ACTION', 'OPEN_NEW_TAB', 'CREATE_AND_COPY_EMBED_LINK', 'DECRYPT_QORTAL_GROUP_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'SHOW_ACTIONS', 'REGISTER_NAME', 'UPDATE_NAME', 'LEAVE_GROUP', 'INVITE_TO_GROUP', 'KICK_FROM_GROUP', 'BAN_FROM_GROUP', 'CANCEL_GROUP_BAN', 'ADD_GROUP_ADMIN', 'REMOVE_GROUP_ADMIN','DECRYPT_AESGCM', 'CANCEL_GROUP_INVITE', 'CREATE_GROUP', 'GET_USER_WALLET_TRANSACTIONS', 'GET_NODE_INFO',
'GET_NODE_STATUS', 'GET_ARRR_SYNC_STATUS', 'SHOW_PDF_READER', 'UPDATE_GROUP', 'SELL_NAME', 'GET_NODE_STATUS', 'GET_ARRR_SYNC_STATUS', 'SHOW_PDF_READER'
'CANCEL_SELL_NAME',
'BUY_NAME', 'MULTI_ASSET_PAYMENT_WITH_PRIVATE_DATA',
'TRANSFER_ASSET',
'SIGN_FOREIGN_FEES',
]; ];
@ -561,7 +551,7 @@ isDOMContentLoaded: false
result: null, result: null,
error: { error: {
error: response.error, error: response.error,
message: typeof response?.error === 'string' ? response?.error : typeof response?.message === 'string' ? response?.message : 'An error has occurred' message: typeof response?.error === 'string' ? response.error : 'An error has occurred'
}, },
}); });
} else { } else {

View File

@ -1,248 +0,0 @@
import {
Box,
Checkbox,
FormControlLabel,
Typography,
useTheme,
} from '@mui/material';
import { Spacer } from '../../common/Spacer';
import { PasswordField } from '../PasswordField/PasswordField';
import { ErrorText } from '../ErrorText/ErrorText';
import Logo1Dark from '../../assets/svgs/Logo1Dark.svg';
import { saveFileToDisk } from '../../utils/generateWallet/generateWallet';
import { useState } from 'react';
import { decryptStoredWallet } from '../../utils/decryptWallet';
import PhraseWallet from '../../utils/generateWallet/phrase-wallet';
import { crypto, walletVersion } from '../../constants/decryptWallet';
import Return from "../../assets/svgs/Return.svg";
import { CustomButton, CustomLabel, TextP } from '../../App-styles';
export const DownloadWallet = ({
returnToMain,
setIsLoading,
showInfo,
rawWallet,
setWalletToBeDownloaded,
walletToBeDownloaded,
}) => {
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
useState<string>('');
const [newPassword, setNewPassword] = useState<string>('');
const [keepCurrentPassword, setKeepCurrentPassword] = useState<boolean>(true);
const theme = useTheme();
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
useState<string>('');
const saveFileToDiskFunc = async () => {
try {
await saveFileToDisk(
walletToBeDownloaded.wallet,
walletToBeDownloaded.qortAddress
);
} catch (error: any) {
setWalletToBeDownloadedError(error?.message);
}
};
const saveWalletFunc = async (password: string, newPassword) => {
let wallet = structuredClone(rawWallet);
const res = await decryptStoredWallet(password, wallet);
const wallet2 = new PhraseWallet(res, wallet?.version || walletVersion);
const passwordToUse = newPassword || password;
wallet = await wallet2.generateSaveWalletData(
passwordToUse,
crypto.kdfThreads,
() => {}
);
setWalletToBeDownloaded({
wallet,
qortAddress: rawWallet.address0,
});
return {
wallet,
qortAddress: rawWallet.address0,
};
};
const confirmPasswordToDownload = async () => {
try {
setWalletToBeDownloadedError('');
if (!keepCurrentPassword && !newPassword) {
setWalletToBeDownloadedError(
'Please enter a new password'
);
return;
}
if (!walletToBeDownloadedPassword) {
setWalletToBeDownloadedError(
'Please enter your password'
);
return;
}
setIsLoading(true);
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 250);
});
const newPasswordForWallet = !keepCurrentPassword ? newPassword : null;
const res = await saveWalletFunc(
walletToBeDownloadedPassword,
newPasswordForWallet
);
} catch (error: any) {
setWalletToBeDownloadedError(error?.message);
} finally {
setIsLoading(false);
}
};
return (
<>
<Spacer height="22px" />
<Box
sx={{
boxSizing: 'border-box',
display: 'flex',
justifyContent: 'flex-start',
maxWidth: '700px',
paddingLeft: '22px',
width: '100%',
}}
>
<img
style={{
cursor: "pointer",
height: '24px'
}}
onClick={returnToMain}
src={Return}
/>
</Box>
<Spacer height="10px" />
<div
className="image-container"
style={{
width: '136px',
height: '154px',
}}
>
<img src={Logo1Dark} className="base-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 account
</TextP>
</Box>
<Spacer height="35px" />
{!walletToBeDownloaded && (
<>
<CustomLabel htmlFor="standard-adornment-password">
Confirm password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={walletToBeDownloadedPassword}
onChange={(e) => setWalletToBeDownloadedPassword(e.target.value)}
/>
<Spacer height="20px" />
<FormControlLabel
sx={{
margin: 0,
}}
control={
<Checkbox
onChange={(e) => setKeepCurrentPassword(e.target.checked)}
checked={keepCurrentPassword}
edge="start"
tabIndex={-1}
disableRipple
sx={{
'&.Mui-checked': {
color: theme.palette.text.secondary,
},
'& .MuiSvgIcon-root': {
color: theme.palette.text.secondary,
},
}}
/>
}
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography sx={{ fontSize: '14px' }}>
Keep current password
</Typography>
</Box>
}
/>
<Spacer height="20px" />
{!keepCurrentPassword && (
<>
<CustomLabel htmlFor="standard-adornment-password">
New password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
<Spacer height="20px" />
</>
)}
<CustomButton onClick={confirmPasswordToDownload}>
Confirm wallet password
</CustomButton>
<ErrorText>{walletToBeDownloadedError}</ErrorText>
</>
)}
{walletToBeDownloaded && (
<>
<CustomButton
onClick={async () => {
await saveFileToDiskFunc();
await showInfo({
message: 'Keep your account file secure',
});
}}
>
Download account
</CustomButton>
</>
)}
</>
);
};

View File

@ -79,7 +79,7 @@ export const AdminSpaceInner = ({
const res = await fetch( const res = await fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${ `${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${
getLatestPublish.name getLatestPublish.name
}/${getLatestPublish.identifier}?encoding=base64&rebuild=true` }/${getLatestPublish.identifier}?encoding=base64`
); );
data = await res.text(); data = await res.text();

View File

@ -66,7 +66,7 @@ export const CreateCommonSecret = ({groupId, secretKey, isOwner, myAddress, sec
const res = await fetch( const res = await fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ `${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${
publish.identifier publish.identifier
}?encoding=base64&rebuild=true` }?encoding=base64`
); );
const data = await res.text(); const data = await res.text();

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useRef } from "react"; import React, { useCallback, useEffect, useRef } from "react";
import { getBaseApiReact } from "../../App";
import { truncate } from "lodash";
@ -18,7 +19,7 @@ export const useBlockedAddresses = () => {
const isUserBlocked = useCallback((address, name)=> { const isUserBlocked = useCallback((address, name)=> {
try { try {
if(!address) return false if(!address) return false
if(userBlockedRef.current[address]) return true if(userBlockedRef.current[address] || userNamesBlockedRef.current[name]) return true
return false return false
@ -89,13 +90,12 @@ export const useBlockedAddresses = () => {
}, []) }, [])
const removeBlockFromList = useCallback(async (address, name)=> { const removeBlockFromList = useCallback(async (address, name)=> {
if(name){
await new Promise((res, rej) => { await new Promise((res, rej) => {
window.sendMessage("listActions", { window.sendMessage("listActions", {
type: 'remove', type: 'remove',
items: [name] , items: name ? [name] : [address],
listName: 'blockedNames' listName: name ? 'blockedNames' : 'blockedAddresses'
}) })
.then((response) => { .then((response) => {
@ -103,40 +103,15 @@ export const useBlockedAddresses = () => {
rej(response?.message); rej(response?.message);
return; return;
} else { } else {
if(!name){
const copyObject = {...userNamesBlockedRef.current}
delete copyObject[name]
userNamesBlockedRef.current = copyObject
res(response);
}
})
.catch((error) => {
console.error("Failed qortalRequest", error);
});
})
}
if(address){
await new Promise((res, rej) => {
window.sendMessage("listActions", {
type: 'remove',
items: [address],
listName: 'blockedAddresses'
})
.then((response) => {
if (response.error) {
rej(response?.message);
return;
} else {
const copyObject = {...userBlockedRef.current} const copyObject = {...userBlockedRef.current}
delete copyObject[address] delete copyObject[address]
userBlockedRef.current = copyObject userBlockedRef.current = copyObject
} else {
const copyObject = {...userNamesBlockedRef.current}
delete copyObject[name]
userNamesBlockedRef.current = copyObject
}
res(response); res(response);
} }
@ -145,19 +120,41 @@ export const useBlockedAddresses = () => {
console.error("Failed qortalRequest", error); console.error("Failed qortalRequest", error);
}); });
}) })
} if(name && userBlockedRef.current[address]){
await new Promise((res, rej) => {
window.sendMessage("listActions", {
type: 'remove',
items: !name ? [name] : [address],
listName: !name ? 'blockedNames' : 'blockedAddresses'
})
.then((response) => {
if (response.error) {
rej(response?.message);
return;
} else {
const copyObject = {...userBlockedRef.current}
delete copyObject[address]
userBlockedRef.current = copyObject
res(response);
}
})
.catch((error) => {
console.error("Failed qortalRequest", error);
});
})
}
}, []) }, [])
const addToBlockList = useCallback(async (address, name)=> { const addToBlockList = useCallback(async (address, name)=> {
if(name){
await new Promise((res, rej) => { await new Promise((res, rej) => {
window.sendMessage("listActions", { window.sendMessage("listActions", {
type: 'add', type: 'add',
items: [name], items: name ? [name] : [address],
listName: 'blockedNames' listName: name ? 'blockedNames' : 'blockedAddresses'
}) })
.then((response) => { .then((response) => {
@ -165,38 +162,18 @@ export const useBlockedAddresses = () => {
rej(response?.message); rej(response?.message);
return; return;
} else { } else {
if(name){
const copyObject = {...userNamesBlockedRef.current} const copyObject = {...userNamesBlockedRef.current}
copyObject[name] = true copyObject[name] = true
userNamesBlockedRef.current = copyObject userNamesBlockedRef.current = copyObject
res(response);
}
})
.catch((error) => {
console.error("Failed qortalRequest", error);
});
})
}
if(address){
await new Promise((res, rej) => {
window.sendMessage("listActions", {
type: 'add',
items: [address],
listName: 'blockedAddresses'
})
.then((response) => {
if (response.error) {
rej(response?.message);
return;
}else { }else {
const copyObject = {...userBlockedRef.current} const copyObject = {...userBlockedRef.current}
copyObject[address] = true copyObject[address] = true
userBlockedRef.current = copyObject userBlockedRef.current = copyObject
}
res(response); res(response);
} }
}) })
@ -204,8 +181,6 @@ export const useBlockedAddresses = () => {
console.error("Failed qortalRequest", error); console.error("Failed qortalRequest", error);
}); });
}) })
}
}, []) }, [])
return { return {

View File

@ -10,23 +10,15 @@ import {
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import { getBaseApiReact, MyContext } from "../../App"; import { MyContext } from "../../App";
import { Spacer } from "../../common/Spacer"; import { Spacer } from "../../common/Spacer";
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events"; import { executeEvent } from "../../utils/events";
import { validateAddress } from "../../utils/validateAddress";
import { getNameInfo, requestQueueMemberNames } from "./Group"; export const BlockedUsersModal = ({ close }) => {
import { useModal } from "../../common/useModal";
import { useRecoilState } from "recoil";
import { isOpenBlockedModalAtom } from "../../atoms/global";
import InfoIcon from '@mui/icons-material/Info';
export const BlockedUsersModal = () => {
const [isOpenBlockedModal, setIsOpenBlockedModal] = useRecoilState(isOpenBlockedModalAtom)
const [hasChanged, setHasChanged] = useState(false); const [hasChanged, setHasChanged] = useState(false);
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [addressesWithNames, setAddressesWithNames] = useState({})
const { isShow, onCancel, onOk, show, message } = useModal(); const { getAllBlockedUsers, removeBlockFromList, addToBlockList } = useContext(MyContext);
const { getAllBlockedUsers, removeBlockFromList, addToBlockList, setOpenSnackGlobal, setInfoSnackCustom } =
useContext(MyContext);
const [blockedUsers, setBlockedUsers] = useState({ const [blockedUsers, setBlockedUsers] = useState({
addresses: {}, addresses: {},
names: {}, names: {},
@ -36,119 +28,20 @@ export const BlockedUsersModal = () => {
}; };
useEffect(() => { useEffect(() => {
if(!isOpenBlockedModal) return
fetchBlockedUsers(); fetchBlockedUsers();
}, [isOpenBlockedModal]);
const getNames = async () => {
// const validApi = await findUsableApi();
const addresses = Object.keys(blockedUsers?.addresses)
const addressNames = {}
const getMemNames = addresses.map(async (address) => {
const name = await requestQueueMemberNames.enqueue(() => {
return getNameInfo(address);
});
if (name) {
addressNames[address] = name
}
return true;
});
await Promise.all(getMemNames);
setAddressesWithNames(addressNames)
};
const blockUser = async (e, user?: string) => {
try {
const valUser = user || value
if (!valUser) return;
const isAddress = validateAddress(valUser);
let userName = null;
let userAddress = null;
if (isAddress) {
userAddress = valUser;
const name = await getNameInfo(valUser);
if (name) {
userName = name;
}
}
if (!isAddress) {
const response = await fetch(`${getBaseApiReact()}/names/${valUser}`);
const data = await response.json();
if (!data?.owner) throw new Error("Name does not exist");
if (data?.owner) {
userAddress = data.owner;
userName = valUser;
}
}
if(!userName){
await addToBlockList(userAddress, null);
fetchBlockedUsers();
setHasChanged(true);
executeEvent('updateChatMessagesWithBlocks', true)
setValue('')
return
}
const responseModal = await show({
userName,
userAddress,
});
if (responseModal === "both") {
await addToBlockList(userAddress, userName);
} else if (responseModal === "address") {
await addToBlockList(userAddress, null);
} else if (responseModal === "name") {
await addToBlockList(null, userName);
}
fetchBlockedUsers();
setHasChanged(true);
setValue('')
if(user){
setIsOpenBlockedModal(false)
}
if(responseModal === 'both' || responseModal === 'address'){
executeEvent('updateChatMessagesWithBlocks', true)
}
} catch (error) {
setOpenSnackGlobal(true);
setInfoSnackCustom({
type: "error",
message: error?.message || "Unable to block user",
});
}
};
const blockUserFromOutsideModalFunc = (e) => {
const user = e.detail?.user;
setIsOpenBlockedModal(true)
blockUser(null, user)
};
useEffect(() => {
subscribeToEvent("blockUserFromOutside", blockUserFromOutsideModalFunc);
return () => {
unsubscribeFromEvent("blockUserFromOutside", blockUserFromOutsideModalFunc);
};
}, []); }, []);
return ( return (
<Dialog <Dialog
open={isOpenBlockedModal} open={true}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle>Blocked Users</DialogTitle> <DialogTitle>Blocked Users</DialogTitle>
<DialogContent <DialogContent sx={{
sx={{ padding: '20px'
padding: "20px", }}>
}}
>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
@ -156,42 +49,39 @@ export const BlockedUsersModal = () => {
}} }}
> >
<TextField <TextField
placeholder="Name or address" placeholder="Name"
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value); setValue(e.target.value);
}} }}
/> />
<Button <Button variant="contained" onClick={async ()=> {
sx={{ try {
flexShrink: 0, if(!value) return
}} await addToBlockList(undefined, value)
variant="contained" fetchBlockedUsers()
onClick={blockUser} setHasChanged(true)
> } catch (error) {
Block console.error(error)
</Button> }
}}>Block</Button>
</Box> </Box>
{Object.entries(blockedUsers?.addresses).length > 0 && ( {Object.entries(blockedUsers?.addresses).length > 0 && (
<> <>
<Spacer height="20px" /> <Spacer height="20px" />
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Blocked addresses- blocks processing of txs Blocked Users for Chat ( addresses )
</DialogContentText> </DialogContentText>
<Spacer height="10px" /> <Spacer height="10px" />
<Button variant="contained" size="small" onClick={getNames}>Fetch names</Button>
<Spacer height="10px" />
</> </>
)} )}
<Box <Box sx={{
sx={{ display: 'flex',
display: "flex", flexDirection: 'column',
flexDirection: "column", gap: '10px'
gap: "10px", }}>
}}
>
{Object.entries(blockedUsers?.addresses || {})?.map( {Object.entries(blockedUsers?.addresses || {})?.map(
([key, value]) => { ([key, value]) => {
return ( return (
@ -200,22 +90,18 @@ export const BlockedUsersModal = () => {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
gap: "10px", gap: "10px",
width: "100%", width: '100%',
justifyContent: "space-between", justifyContent: 'space-between'
}} }}
> >
<Typography>{addressesWithNames[key] || key}</Typography> <Typography>{key}</Typography>
<Button <Button
sx={{
flexShrink: 0,
}}
size="small"
variant="contained" variant="contained"
onClick={async () => { onClick={async () => {
try { try {
await removeBlockFromList(key, undefined); await removeBlockFromList(key, undefined);
setHasChanged(true); setHasChanged(true);
setValue(""); setValue('')
fetchBlockedUsers(); fetchBlockedUsers();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -233,19 +119,17 @@ export const BlockedUsersModal = () => {
<> <>
<Spacer height="20px" /> <Spacer height="20px" />
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Blocked names for QDN Blocked Users for QDN and Chat (names)
</DialogContentText> </DialogContentText>
<Spacer height="10px" /> <Spacer height="10px" />
</> </>
)} )}
<Box <Box sx={{
sx={{ display: 'flex',
display: "flex", flexDirection: 'column',
flexDirection: "column", gap: '10px'
gap: "10px", }}>
}}
>
{Object.entries(blockedUsers?.names || {})?.map(([key, value]) => { {Object.entries(blockedUsers?.names || {})?.map(([key, value]) => {
return ( return (
<Box <Box
@ -253,16 +137,12 @@ export const BlockedUsersModal = () => {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
gap: "10px", gap: "10px",
width: "100%", width: '100%',
justifyContent: "space-between", justifyContent: 'space-between'
}} }}
> >
<Typography>{key}</Typography> <Typography>{key}</Typography>
<Button <Button
size="small"
sx={{
flexShrink: 0,
}}
variant="contained" variant="contained"
onClick={async () => { onClick={async () => {
try { try {
@ -297,65 +177,14 @@ export const BlockedUsersModal = () => {
variant="contained" variant="contained"
onClick={()=> { onClick={()=> {
if(hasChanged){ if(hasChanged){
executeEvent("updateChatMessagesWithBlocks", true); executeEvent('updateChatMessagesWithBlocks', true)
} }
setIsOpenBlockedModal(false); close()
}} }}
> >
close close
</Button> </Button>
</DialogActions> </DialogActions>
<Dialog
open={isShow}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Decide what to block"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Blocking {message?.userName || message?.userAddress}
</DialogContentText>
<Box sx={{
display: 'flex',
alignItems: 'center',
gap: '10px',
marginTop: '20px'
}}>
<InfoIcon sx={{
color: 'fff'
}}/> <Typography>Choose "block txs" or "all" to block chat messages </Typography>
</Box>
</DialogContent>
<DialogActions>
<Button
variant="contained"
onClick={() => {
onOk("address");
}}
>
Block txs
</Button>
<Button
variant="contained"
onClick={() => {
onOk("name");
}}
>
Block QDN data
</Button>
<Button
variant="contained"
onClick={() => {
onOk("both");
}}
>
Block All
</Button>
</DialogActions>
</Dialog>
</Dialog> </Dialog>
); );
}; };

View File

@ -19,8 +19,7 @@ import React, {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import PersonOffIcon from '@mui/icons-material/PersonOff'; import BlockIcon from '@mui/icons-material/Block';
import { WalletsAppWrapper } from "./WalletsAppWrapper"; import { WalletsAppWrapper } from "./WalletsAppWrapper";
import SettingsIcon from "@mui/icons-material/Settings"; import SettingsIcon from "@mui/icons-material/Settings";
@ -100,7 +99,7 @@ import { formatEmailDate } from "./QMailMessages";
import { useHandleMobileNativeBack } from "../../hooks/useHandleMobileNativeBack"; import { useHandleMobileNativeBack } from "../../hooks/useHandleMobileNativeBack";
import { AdminSpace } from "../Chat/AdminSpace"; import { AdminSpace } from "../Chat/AdminSpace";
import { useRecoilState, useSetRecoilState } from "recoil"; import { useRecoilState, useSetRecoilState } from "recoil";
import { addressInfoControllerAtom, groupsPropertiesAtom, isOpenBlockedModalAtom, lastEnteredGroupIdAtom, selectedGroupIdAtom } from "../../atoms/global"; import { addressInfoControllerAtom, groupsPropertiesAtom, lastEnteredGroupIdAtom, selectedGroupIdAtom } from "../../atoms/global";
import { sortArrayByTimestampAndGroupName } from "../../utils/time"; import { sortArrayByTimestampAndGroupName } from "../../utils/time";
import { BlockedUsersModal } from "./BlockedUsersModal"; import { BlockedUsersModal } from "./BlockedUsersModal";
import { GlobalTouchMenu } from "../GlobalTouchMenu"; import { GlobalTouchMenu } from "../GlobalTouchMenu";
@ -484,8 +483,6 @@ export const Group = ({
const [groupAnnouncements, setGroupAnnouncements] = React.useState({}); const [groupAnnouncements, setGroupAnnouncements] = React.useState({});
const [defaultThread, setDefaultThread] = React.useState(null); const [defaultThread, setDefaultThread] = React.useState(null);
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false); const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
const setIsOpenBlockedUserModal = useSetRecoilState(isOpenBlockedModalAtom)
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false); const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState(""); const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState("");
const [drawerMode, setDrawerMode] = React.useState("groups"); const [drawerMode, setDrawerMode] = React.useState("groups");
@ -510,6 +507,7 @@ export const Group = ({
const [isForceShowCreationKeyPopup, setIsForceShowCreationKeyPopup] = useState(false) const [isForceShowCreationKeyPopup, setIsForceShowCreationKeyPopup] = useState(false)
const [groupsProperties, setGroupsProperties] = useRecoilState(groupsPropertiesAtom) const [groupsProperties, setGroupsProperties] = useRecoilState(groupsPropertiesAtom)
const setUserInfoForLevels = useSetRecoilState(addressInfoControllerAtom); const setUserInfoForLevels = useSetRecoilState(addressInfoControllerAtom);
const [isOpenBlockedUserModal, setIsOpenBlockedUserModal] = React.useState(false);
const setLastEnteredGroupIdAtom = useSetRecoilState(lastEnteredGroupIdAtom) const setLastEnteredGroupIdAtom = useSetRecoilState(lastEnteredGroupIdAtom)
const isPrivate = useMemo(()=> { const isPrivate = useMemo(()=> {
if(selectedGroup?.groupId === '0') return false if(selectedGroup?.groupId === '0') return false
@ -841,7 +839,7 @@ export const Group = ({
const res = await fetch( const res = await fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ `${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${
publish.identifier publish.identifier
}?encoding=base64&rebuild=true` }?encoding=base64`
); );
data = await res.text(); data = await res.text();
} }
@ -2161,7 +2159,7 @@ export const Group = ({
padding: '10px' padding: '10px'
}} }}
> >
<PersonOffIcon <BlockIcon
sx={{ sx={{
color: "white", color: "white",
}} }}
@ -2658,9 +2656,11 @@ export const Group = ({
)} )}
</> </>
)} )}
{isOpenBlockedUserModal && (
<BlockedUsersModal /> <BlockedUsersModal close={()=> {
setIsOpenBlockedUserModal(false)
}} />
)}
{selectedDirect && !newChat && ( {selectedDirect && !newChat && (
<> <>
<Box <Box

View File

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { DrawerUserLookup } from "../Drawer/DrawerUserLookup"; import { DrawerUserLookup } from "../Drawer/DrawerUserLookup";
import { import {
Avatar, Avatar,
@ -16,7 +16,6 @@ import {
Typography, Typography,
Table, Table,
CircularProgress, CircularProgress,
Autocomplete,
} from "@mui/material"; } from "@mui/material";
import { getAddressInfo, getNameOrAddress } from "../../background"; import { getAddressInfo, getNameOrAddress } from "../../background";
import { getBaseApiReact } from "../../App"; import { getBaseApiReact } from "../../App";
@ -27,7 +26,6 @@ import { formatTimestamp } from "../../utils/time";
import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen'; import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen';
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events"; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import { useNameSearch } from "../../hooks/useNameSearch";
function formatAddress(str) { function formatAddress(str) {
if (str.length <= 12) return str; if (str.length <= 12) return str;
@ -40,9 +38,6 @@ function formatAddress(str) {
export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
const [nameOrAddress, setNameOrAddress] = useState(""); const [nameOrAddress, setNameOrAddress] = useState("");
const [inputValue, setInputValue] = useState('');
const { results, isLoading } = useNameSearch(inputValue);
const options = useMemo(() => results?.map((item) => item.name), [results]);
const [errorMessage, setErrorMessage] = useState(""); const [errorMessage, setErrorMessage] = useState("");
const [addressInfo, setAddressInfo] = useState(null); const [addressInfo, setAddressInfo] = useState(null);
const [isLoadingUser, setIsLoadingUser] = useState(false); const [isLoadingUser, setIsLoadingUser] = useState(false);
@ -111,7 +106,6 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
setIsOpenDrawerLookup(false) setIsOpenDrawerLookup(false)
setNameOrAddress('') setNameOrAddress('')
setErrorMessage('') setErrorMessage('')
setInputValue('');
setPayments([]) setPayments([])
setIsLoadingUser(false) setIsLoadingUser(false)
setIsLoadingPayments(false) setIsLoadingPayments(false)
@ -140,66 +134,27 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
flexShrink: 0, flexShrink: 0,
}} }}
> >
<Autocomplete
value={nameOrAddress}
onChange={(event: any, newValue: string | null) => {
if (!newValue) {
setNameOrAddress('');
return;
}
setNameOrAddress(newValue);
lookupFunc(newValue);
}}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
id="controllable-states-demo"
loading={isLoading}
options={options}
sx={{ width: 300 }}
size="small"
renderInput={(params) => (
<TextField <TextField
autoFocus autoFocus
value={nameOrAddress}
onChange={(e) => setNameOrAddress(e.target.value)}
size="small"
placeholder="Address or Name"
autoComplete="off" autoComplete="off"
{...params}
label="Address or Name"
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter' && nameOrAddress) { if (e.key === "Enter" && nameOrAddress) {
lookupFunc(inputValue); lookupFunc();
} }
}} }}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'white',
},
'&:hover fieldset': {
borderColor: 'white',
},
'&.Mui-focused fieldset': {
borderColor: 'white',
},
'& input': {
color: 'white',
},
},
'& .MuiInputLabel-root': {
color: 'white',
},
'& .MuiInputLabel-root.Mui-focused': {
color: 'white',
},
'& .MuiAutocomplete-endAdornment svg': {
color: 'white',
},
}}
/> />
)} <ButtonBase onClick={()=> {
/> lookupFunc();
}} >
<SearchIcon sx={{
color: 'white',
marginRight: '20px'
}} />
</ButtonBase>
<ButtonBase sx={{ <ButtonBase sx={{
marginLeft: 'auto', marginLeft: 'auto',

View File

@ -167,9 +167,12 @@ useEffect(()=> {
onClick={async () => { onClick={async () => {
try { try {
setIsLoading(true) setIsLoading(true)
executeEvent("blockUserFromOutside", { if(isAlreadyBlocked === true){
user: address await removeBlockFromList(address, name)
}) } else if(isAlreadyBlocked === false) {
await addToBlockList(address, name)
}
executeEvent('updateChatMessagesWithBlocks', true)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {

View File

@ -1,55 +0,0 @@
import { useCallback, useEffect, useState } from 'react';
import { getBaseApiReact } from '../App';
interface NameListItem {
name: string;
address: string;
}
export const useNameSearch = (value: string, limit = 20) => {
const [nameList, setNameList] = useState<NameListItem[]>([]);
const [isLoading, setIsLoading] = useState(false);
const checkIfNameExisits = useCallback(
async (name: string, listLimit: number) => {
try {
if (!name) {
setNameList([]);
return;
}
const res = await fetch(
`${getBaseApiReact()}/names/search?query=${name}&prefix=true&limit=${listLimit}`
);
const data = await res.json();
setNameList(
data?.map((item: any) => {
return {
name: item.name,
address: item.owner,
};
})
);
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
},
[]
);
// Debounce logic
useEffect(() => {
setIsLoading(true);
const handler = setTimeout(() => {
checkIfNameExisits(value, limit);
}, 500);
// Cleanup timeout if searchValue changes before the timeout completes
return () => {
clearTimeout(handler);
};
}, [value, limit, checkIfNameExisits]);
return {
isLoading,
results: nameList,
};
};

View File

@ -24,7 +24,7 @@ window.addEventListener("message", (event) => {
} }
}); });
export const sendMessageBackground = (action, data = {}, timeout = 240000, isExtension, appInfo, skipAuth) => { export const sendMessageBackground = (action, data = {}, timeout = 180000, isExtension, appInfo, skipAuth) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const requestId = generateRequestId(); // Unique ID for each request const requestId = generateRequestId(); // Unique ID for each request
callbackMap.set(requestId, { resolve, reject }); // Store both resolve and reject callbacks callbackMap.set(requestId, { resolve, reject }); // Store both resolve and reject callbacks

View File

@ -1,6 +1,6 @@
import { gateways, getApiKeyFromStorage } from "./background"; import { gateways, getApiKeyFromStorage } from "./background";
import { listOfAllQortalRequests } from "./components/Apps/useQortalMessageListener"; import { listOfAllQortalRequests } from "./components/Apps/useQortalMessageListener";
import { addForeignServer, addGroupAdminRequest, addListItems, adminAction, banFromGroupRequest, buyNameRequest, cancelGroupBanRequest, cancelGroupInviteRequest, cancelSellNameRequest, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createGroupRequest, createPoll, decryptAESGCMRequest, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getArrrSyncStatus, getCrossChainServerInfo, getDaySummary, getForeignFee, getHostedData, getListItems, getNodeInfo, getNodeStatus, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getUserWalletTransactions, getWalletBalance, inviteToGroupRequest, joinGroup, kickFromGroupRequest, leaveGroupRequest, multiPaymentWithPrivateData, openNewTab, publishMultipleQDNResources, publishQDNResource, registerNameRequest, removeForeignServer, removeGroupAdminRequest, saveFile, sellNameRequest, sendChatMessage, sendCoin, setCurrentForeignServer, signForeignFees, signTransaction, transferAssetRequest, updateForeignFee, updateGroupRequest, updateNameRequest, voteOnPoll } from "./qortalRequests/get"; import { addForeignServer, addGroupAdminRequest, addListItems, adminAction, banFromGroupRequest, cancelGroupBanRequest, cancelGroupInviteRequest, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createGroupRequest, createPoll, decryptAESGCMRequest, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getArrrSyncStatus, getCrossChainServerInfo, getDaySummary, getForeignFee, getHostedData, getListItems, getNodeInfo, getNodeStatus, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getUserWalletTransactions, getWalletBalance, inviteToGroupRequest, joinGroup, kickFromGroupRequest, leaveGroupRequest, openNewTab, publishMultipleQDNResources, publishQDNResource, registerNameRequest, removeForeignServer, removeGroupAdminRequest, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, signTransaction, updateForeignFee, updateNameRequest, voteOnPoll } from "./qortalRequests/get";
import { getData, storeData } from "./utils/chromeStorage"; import { getData, storeData } from "./utils/chromeStorage";
import { executeEvent } from "./utils/events"; import { executeEvent } from "./utils/events";
@ -462,7 +462,7 @@ export const isRunningGateway = async ()=> {
case "UPDATE_FOREIGN_FEE": { case "UPDATE_FOREIGN_FEE": {
try { try {
const res = await updateForeignFee(request.payload, isFromExtension); const res = await updateForeignFee(request.payload);
event.source.postMessage({ event.source.postMessage({
requestId: request.requestId, requestId: request.requestId,
action: request.action, action: request.action,
@ -502,7 +502,7 @@ export const isRunningGateway = async ()=> {
case "SET_CURRENT_FOREIGN_SERVER": { case "SET_CURRENT_FOREIGN_SERVER": {
try { try {
const res = await setCurrentForeignServer(request.payload, isFromExtension); const res = await setCurrentForeignServer(request.payload);
event.source.postMessage({ event.source.postMessage({
requestId: request.requestId, requestId: request.requestId,
action: request.action, action: request.action,
@ -522,7 +522,7 @@ export const isRunningGateway = async ()=> {
case "ADD_FOREIGN_SERVER": { case "ADD_FOREIGN_SERVER": {
try { try {
const res = await addForeignServer(request.payload, isFromExtension); const res = await addForeignServer(request.payload);
event.source.postMessage({ event.source.postMessage({
requestId: request.requestId, requestId: request.requestId,
action: request.action, action: request.action,
@ -542,7 +542,7 @@ export const isRunningGateway = async ()=> {
case "REMOVE_FOREIGN_SERVER": { case "REMOVE_FOREIGN_SERVER": {
try { try {
const res = await removeForeignServer(request.payload, isFromExtension); const res = await removeForeignServer(request.payload);
event.source.postMessage({ event.source.postMessage({
requestId: request.requestId, requestId: request.requestId,
action: request.action, action: request.action,
@ -1206,146 +1206,6 @@ export const isRunningGateway = async ()=> {
} }
break; break;
} }
case "UPDATE_GROUP" : {
try {
const res = await updateGroupRequest(request.payload, isFromExtension)
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error?.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "BUY_NAME": {
try {
const res = await buyNameRequest(request.payload, isFromExtension);
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "SELL_NAME": {
try {
const res = await sellNameRequest(request.payload, isFromExtension);
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "CANCEL_SELL_NAME": {
try {
const res = await cancelSellNameRequest(request.payload, isFromExtension);
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "MULTI_ASSET_PAYMENT_WITH_PRIVATE_DATA" : {
try {
const res = await multiPaymentWithPrivateData(request.payload, isFromExtension)
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error?.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "TRANSFER_ASSET" : {
try {
const res = await transferAssetRequest(request.payload, isFromExtension)
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error?.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case 'SIGN_FOREIGN_FEES': {
try {
const res = await signForeignFees(request.payload, isFromExtension);
event.source.postMessage(
{
requestId: request.requestId,
action: request.action,
payload: res,
type: 'backgroundMessageResponse',
},
event.origin
);
} catch (error) {
event.source.postMessage(
{
requestId: request.requestId,
action: request.action,
error: error.message,
type: 'backgroundMessageResponse',
},
event.origin
);
}
break;
}
default: default:
break; break;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +0,0 @@
// @ts-nocheck
import { QORT_DECIMALS } from "../constants/constants"
import TransactionBase from "./TransactionBase"
export default class BuyNameTransacion extends TransactionBase {
constructor() {
super()
this.type = 7
}
set fee(fee) {
this._fee = fee * QORT_DECIMALS
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
}
set name(name) {
this.nameText = name
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
}
set sellPrice(sellPrice) {
this._sellPrice = sellPrice * QORT_DECIMALS
this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice)
}
set recipient(recipient) {
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
this.theRecipient = recipient
}
get params() {
const params = super.params
params.push(
this._nameLength,
this._nameBytes,
this._sellPriceBytes,
this._recipient,
this._feeBytes
)
return params
}
}

View File

@ -1,33 +0,0 @@
// @ts-nocheck
import { QORT_DECIMALS } from "../constants/constants"
import TransactionBase from "./TransactionBase"
export default class CancelSellNameTransacion extends TransactionBase {
constructor() {
super()
this.type = 6
}
set fee(fee) {
this._fee = fee * QORT_DECIMALS
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
}
set name(name) {
this.nameText = name
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
}
get params() {
const params = super.params
params.push(
this._nameLength,
this._nameBytes,
this._feeBytes
)
return params
}
}

View File

@ -1,40 +0,0 @@
// @ts-nocheck
import { QORT_DECIMALS } from "../constants/constants"
import TransactionBase from "./TransactionBase"
export default class SellNameTransacion extends TransactionBase {
constructor() {
super()
this.type = 5
}
set fee(fee) {
this._fee = fee * QORT_DECIMALS
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
}
set name(name) {
this.nameText = name
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
}
set sellPrice(sellPrice) {
this.showSellPrice = sellPrice
this._sellPrice = sellPrice * QORT_DECIMALS
this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice)
}
get params() {
const params = super.params
params.push(
this._nameLength,
this._nameBytes,
this._sellPriceBytes,
this._feeBytes
)
return params
}
}

View File

@ -1,35 +0,0 @@
// @ts-nocheck
import { QORT_DECIMALS } from '../constants/constants'
import TransactionBase from './TransactionBase'
export default class TransferAssetTransaction extends TransactionBase {
constructor() {
super()
this.type = 12
}
set recipient(recipient) {
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
}
set amount(amount) {
this._amount = Math.round(amount * QORT_DECIMALS)
this._amountBytes = this.constructor.utils.int64ToBytes(this._amount)
}
set assetId(assetId) {
this._assetId = this.constructor.utils.int64ToBytes(assetId)
}
get params() {
const params = super.params
params.push(
this._recipient,
this._assetId,
this._amountBytes,
this._feeBytes
)
return params
}
}

View File

@ -1,62 +0,0 @@
// @ts-nocheck
import { QORT_DECIMALS } from "../constants/constants";
import TransactionBase from "./TransactionBase";
export default class UpdateGroupTransaction extends TransactionBase {
constructor() {
super()
this.type = 23
}
set fee(fee) {
this._fee = fee * QORT_DECIMALS
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
}
set newOwner(newOwner) {
this._newOwner = newOwner instanceof Uint8Array ? newOwner : this.constructor.Base58.decode(newOwner)
}
set newIsOpen(newIsOpen) {
this._rGroupType = new Uint8Array(1)
this._rGroupType[0] = newIsOpen
}
set newDescription(newDescription) {
this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(newDescription.toLocaleLowerCase())
this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length)
}
set newApprovalThreshold(newApprovalThreshold) {
this._rGroupApprovalThreshold = new Uint8Array(1)
this._rGroupApprovalThreshold[0] = newApprovalThreshold;
}
set newMinimumBlockDelay(newMinimumBlockDelay) {
this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMinimumBlockDelay)
}
set newMaximumBlockDelay(newMaximumBlockDelay) {
this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMaximumBlockDelay)
}
set _groupId(_groupId){
this._groupBytes = this.constructor.utils.int32ToBytes(_groupId)
}
get params() {
const params = super.params
params.push(
this._groupBytes,
this._newOwner,
this._rGroupDescLength,
this._rGroupDescBytes,
this._rGroupType,
this._rGroupApprovalThreshold,
this._rGroupMinimumBlockDelayBytes,
this._rGroupMaximumBlockDelayBytes,
this._feeBytes
)
return params
}
}

View File

@ -20,27 +20,17 @@ import DeployAtTransaction from './DeployAtTransaction.js'
import RewardShareTransaction from './RewardShareTransaction.js' import RewardShareTransaction from './RewardShareTransaction.js'
import RemoveRewardShareTransaction from './RemoveRewardShareTransaction.js' import RemoveRewardShareTransaction from './RemoveRewardShareTransaction.js'
import UpdateNameTransaction from './UpdateNameTransaction.js' import UpdateNameTransaction from './UpdateNameTransaction.js'
import UpdateGroupTransaction from './UpdateGroupTransaction.js'
import SellNameTransacion from './SellNameTransacion.js'
import CancelSellNameTransacion from './CancelSellNameTransacion.js'
import BuyNameTransacion from './BuyNameTransacion.js'
import TransferAssetTransaction from './TransferAssetTransaction.js'
export const transactionTypes = { export const transactionTypes = {
3: RegisterNameTransaction, 3: RegisterNameTransaction,
4: UpdateNameTransaction, 4: UpdateNameTransaction,
2: PaymentTransaction, 2: PaymentTransaction,
5: SellNameTransacion,
6: CancelSellNameTransacion,
7: BuyNameTransacion,
8: CreatePollTransaction, 8: CreatePollTransaction,
9: VoteOnPollTransaction, 9: VoteOnPollTransaction,
12: TransferAssetTransaction,
16: DeployAtTransaction, 16: DeployAtTransaction,
18: ChatTransaction, 18: ChatTransaction,
181: GroupChatTransaction, 181: GroupChatTransaction,
22: CreateGroupTransaction, 22: CreateGroupTransaction,
23: UpdateGroupTransaction,
24: AddGroupAdminTransaction, 24: AddGroupAdminTransaction,
25: RemoveGroupAdminTransaction, 25: RemoveGroupAdminTransaction,
26: GroupBanTransaction, 26: GroupBanTransaction,

View File

@ -14,18 +14,3 @@ export function decodeIfEncoded(input) {
// Return input as-is if not URI-encoded // Return input as-is if not URI-encoded
return input; return input;
} }
export const isValidBase64 = (str: string): boolean => {
if (typeof str !== "string" || str.length % 4 !== 0) return false;
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
return base64Regex.test(str);
};
export const isValidBase64WithDecode = (str: string): boolean => {
try {
return isValidBase64(str) && Boolean(atob(str));
} catch {
return false;
}
};