diff --git a/src/App.tsx b/src/App.tsx
index 140cc77..5b33b5d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -21,6 +21,7 @@ import {
DialogContent,
DialogContentText,
DialogTitle,
+ FormControlLabel,
Input,
InputLabel,
Popover,
@@ -139,6 +140,8 @@ import { useBlockedAddresses } from "./components/Chat/useBlockUsers";
import { QortPayment } from "./components/QortPayment";
import { GeneralNotifications } from "./components/GeneralNotifications";
import { PdfViewer } from "./common/PdfViewer";
+import PriorityHighIcon from '@mui/icons-material/PriorityHigh';
+
type extStates =
| "not-authenticated"
@@ -354,6 +357,8 @@ function App() {
url: "http://127.0.0.1:12391",
});
const [useLocalNode, setUseLocalNode] = useState(false);
+ const [confirmRequestRead, setConfirmRequestRead] = useState(false);
+
const {downloadResource} = useFetchResources()
const [showSeed, setShowSeed] = useState(false)
const [creationStep, setCreationStep] = useState(1)
@@ -716,6 +721,8 @@ function App() {
if(message?.payload?.checkbox1){
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1?.value || false
}
+ setConfirmRequestRead(false)
+
await showQortalRequestExtension(message?.payload);
if (qortalRequestCheckbox1Ref.current) {
@@ -2157,11 +2164,13 @@ function App() {
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
+ maxWidth: '700px'
}}
>
{
setRawWallet(null);
@@ -2689,11 +2700,13 @@ function App() {
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
+ maxWidth: '700px'
}}
>
{
setRawWallet(null);
@@ -2793,11 +2806,13 @@ function App() {
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
+ maxWidth: '700px'
}}
>
{
if(creationStep === 2){
@@ -3533,6 +3550,35 @@ function App() {
)}
+ {messageQortalRequestExtension?.confirmCheckbox && (
+ setConfirmRequestRead(e.target.checked)}
+ checked={confirmRequestRead}
+ edge="start"
+ tabIndex={-1}
+ disableRipple
+ sx={{
+ "&.Mui-checked": {
+ color: "white",
+ },
+ "& .MuiSvgIcon-root": {
+ color: "white",
+ },
+ }}
+ />
+ }
+ label={
+
+
+ I have read this request
+
+
+
+ }
+ />
+ )}
{
+ if(messageQortalRequestExtension?.confirmCheckbox && !confirmRequestRead) return
+ onOkQortalRequestExtension("accepted")
}}
- onClick={() => onOkQortalRequestExtension("accepted")}
>
accept
diff --git a/src/atoms/global.ts b/src/atoms/global.ts
index c34a9fa..9502661 100644
--- a/src/atoms/global.ts
+++ b/src/atoms/global.ts
@@ -37,6 +37,14 @@ export const sortablePinnedAppsAtom = atom({
{
name: 'Q-Wallets',
service: 'APP'
+ },
+ {
+ name: 'Q-Search',
+ service: 'APP'
+ },
+ {
+ name: 'Q-Nodecontrol',
+ service: 'APP'
}
],
});
@@ -163,4 +171,8 @@ export const groupsPropertiesAtom = atom({
export const lastPaymentSeenTimestampAtom = atom({
key: 'lastPaymentSeenTimestampAtom',
default: null,
+});
+export const isOpenBlockedModalAtom = atom({
+ key: 'isOpenBlockedModalAtom',
+ default: false,
});
\ No newline at end of file
diff --git a/src/background.ts b/src/background.ts
index 543960a..c028ff2 100644
--- a/src/background.ts
+++ b/src/background.ts
@@ -2673,6 +2673,150 @@ export async function createGroup({
if (!res?.signature) throw new Error(res?.message || "Transaction was not able to be processed");
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 }) {
const address = await getNameOrAddress(qortalAddress);
if (!address) throw new Error("Cannot find user");
diff --git a/src/components/Apps/AppsLibrary.tsx b/src/components/Apps/AppsLibrary.tsx
index 09f9eff..29c21df 100644
--- a/src/components/Apps/AppsLibrary.tsx
+++ b/src/components/Apps/AppsLibrary.tsx
@@ -43,7 +43,9 @@ const officialAppList = [
"q-shop",
"q-trade",
"q-support",
- "q-wallets"
+ "q-wallets",
+ "q-search",
+ "q-nodecontrol"
];
const ScrollerStyled = styled('div')({
diff --git a/src/components/Apps/AppsLibraryDesktop.tsx b/src/components/Apps/AppsLibraryDesktop.tsx
index 3c0d62b..cb36225 100644
--- a/src/components/Apps/AppsLibraryDesktop.tsx
+++ b/src/components/Apps/AppsLibraryDesktop.tsx
@@ -60,7 +60,9 @@ const officialAppList = [
"q-support",
"q-mintership",
"q-manager",
- "q-wallets"
+ "q-wallets",
+ "q-search",
+ "q-nodecontrol"
];
const ScrollerStyled = styled("div")({
diff --git a/src/components/Apps/useQortalMessageListener.tsx b/src/components/Apps/useQortalMessageListener.tsx
index 26a77e0..d7ad040 100644
--- a/src/components/Apps/useQortalMessageListener.tsx
+++ b/src/components/Apps/useQortalMessageListener.tsx
@@ -247,7 +247,10 @@ const UIQortalRequests = [
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
'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', 'ADMIN_ACTION', 'SIGN_TRANSACTION', 'DECRYPT_QORTAL_GROUP_DATA', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', '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'
+ 'GET_NODE_STATUS', 'GET_ARRR_SYNC_STATUS', 'UPDATE_GROUP',
+ 'SELL_NAME',
+'CANCEL_SELL_NAME',
+'BUY_NAME'
];
@@ -614,7 +617,7 @@ isDOMContentLoaded: false
);
} else if(event?.data?.action === 'OPEN_NEW_TAB'){
try {
- await openNewTab(event?.data?.payload)
+ await openNewTab(event?.data)
event.ports[0].postMessage({
result: true,
error: null,
@@ -639,6 +642,27 @@ isDOMContentLoaded: false
error: error?.message,
});
}
+ } else if(event?.data?.action === 'SHOW_PDF_READER'){
+ try {
+ if(!event?.data?.blob){
+ throw new Error('Missing blob')
+ }
+ if(event?.data?.blob?.type !== "application/pdf") throw new Error('blob type must be application/pdf')
+
+
+ executeEvent("openPdf", { blob: event?.data?.blob});
+
+
+ event.ports[0].postMessage({
+ result: true,
+ error: null,
+ });
+ } catch (error) {
+ event.ports[0].postMessage({
+ result: null,
+ error: error?.message,
+ });
+ }
}
};
diff --git a/src/components/Chat/useBlockUsers.tsx b/src/components/Chat/useBlockUsers.tsx
index aaef617..b787735 100644
--- a/src/components/Chat/useBlockUsers.tsx
+++ b/src/components/Chat/useBlockUsers.tsx
@@ -1,6 +1,5 @@
import React, { useCallback, useEffect, useRef } from "react";
-import { getBaseApiReact } from "../../App";
-import { truncate } from "lodash";
+
@@ -19,7 +18,7 @@ export const useBlockedAddresses = () => {
const isUserBlocked = useCallback((address, name)=> {
try {
if(!address) return false
- if(userBlockedRef.current[address] || userNamesBlockedRef.current[name]) return true
+ if(userBlockedRef.current[address]) return true
return false
@@ -88,47 +87,47 @@ export const useBlockedAddresses = () => {
}
fetchBlockedList()
}, [])
-
const removeBlockFromList = useCallback(async (address, name)=> {
- await new Promise((res, rej) => {
- chrome?.runtime?.sendMessage(
- {
- action: "listActions",
- payload: {
- type: 'remove',
- items: name ? [name] : [address],
- listName: name ? 'blockedNames' : 'blockedAddresses'
+ if(name){
+ await new Promise((res, rej) => {
+
+ chrome?.runtime?.sendMessage(
+ {
+ action: "listActions",
+ payload: {
+ type: 'remove',
+ items: [name] ,
+ listName: 'blockedNames'
+ },
},
- },
- (response) => {
- if (response.error) {
- rej(response?.message);
- return;
- } else {
- if(!name){
- const copyObject = {...userBlockedRef.current}
- delete copyObject[address]
- userBlockedRef.current = copyObject
+ (response) => {
+ if (response.error) {
+ rej(response?.message);
+ return;
} else {
const copyObject = {...userNamesBlockedRef.current}
delete copyObject[name]
userNamesBlockedRef.current = copyObject
- }
+
+
res(response);
+ }
}
- }
- );
+ );
})
- if(name && userBlockedRef.current[address]){
+
+ }
+
+ if(address){
await new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
action: "listActions",
payload: {
type: 'remove',
- items: !name ? [name] : [address],
- listName: !name ? 'blockedNames' : 'blockedAddresses'
+ items: [address],
+ listName: 'blockedAddresses'
},
},
(response) => {
@@ -139,47 +138,77 @@ export const useBlockedAddresses = () => {
const copyObject = {...userBlockedRef.current}
delete copyObject[address]
userBlockedRef.current = copyObject
- res(response);
+
+
+ res(response);
}
}
);
- })
+ })
}
+
}, [])
const addToBlockList = useCallback(async (address, name)=> {
- await new Promise((res, rej) => {
- chrome?.runtime?.sendMessage(
- {
- action: "listActions",
- payload: {
- type: 'add',
- items: name ? [name] : [address],
- listName: name ? 'blockedNames' : 'blockedAddresses'
+ if(name){
+ await new Promise((res, rej) => {
+
+
+ chrome?.runtime?.sendMessage(
+ {
+ action: "listActions",
+ payload: {
+ type: 'add',
+ items: [name],
+ listName: 'blockedNames'
+ },
},
- },
- (response) => {
- if (response.error) {
- rej(response?.message);
- return;
- } else {
- if(name){
-
+ (response) => {
+ if (response.error) {
+ rej(response?.message);
+ return;
+ } else {
const copyObject = {...userNamesBlockedRef.current}
copyObject[name] = true
userNamesBlockedRef.current = copyObject
- }else {
+
+
+ res(response);
+ }
+ }
+ );
+ })
+ }
+ if(address){
+ await new Promise((res, rej) => {
+ chrome?.runtime?.sendMessage(
+ {
+ action: "listActions",
+ payload: {
+ type: 'add',
+ items: [address],
+ listName: 'blockedAddresses'
+ },
+ },
+ (response) => {
+ if (response.error) {
+ rej(response?.message);
+ return;
+ } else {
const copyObject = {...userBlockedRef.current}
copyObject[address] = true
userBlockedRef.current = copyObject
-
- }
+
res(response);
+ }
}
- }
- )
- })
+ );
+ })
+
+
+ }
+
}, [])
return {
diff --git a/src/components/Group/BlockedUsersModal.tsx b/src/components/Group/BlockedUsersModal.tsx
index 84fa3fa..f82d632 100644
--- a/src/components/Group/BlockedUsersModal.tsx
+++ b/src/components/Group/BlockedUsersModal.tsx
@@ -10,15 +10,23 @@ import {
Typography,
} from "@mui/material";
import React, { useContext, useEffect, useState } from "react";
-import { MyContext } from "../../App";
+import { getBaseApiReact, MyContext } from "../../App";
import { Spacer } from "../../common/Spacer";
-import { executeEvent } from "../../utils/events";
-
-export const BlockedUsersModal = ({ close }) => {
+import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
+import { validateAddress } from "../../utils/validateAddress";
+import { getNameInfo, requestQueueMemberNames } from "./Group";
+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 [value, setValue] = useState("");
-
- const { getAllBlockedUsers, removeBlockFromList, addToBlockList } = useContext(MyContext);
+ const [addressesWithNames, setAddressesWithNames] = useState({})
+ const { isShow, onCancel, onOk, show, message } = useModal();
+ const { getAllBlockedUsers, removeBlockFromList, addToBlockList, setOpenSnackGlobal, setInfoSnackCustom } =
+ useContext(MyContext);
const [blockedUsers, setBlockedUsers] = useState({
addresses: {},
names: {},
@@ -28,60 +36,162 @@ export const BlockedUsersModal = ({ close }) => {
};
useEffect(() => {
+ if(!isOpenBlockedModal) return
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 (
+
{Object.entries(blockedUsers?.addresses).length > 0 && (
<>
- Blocked Users for Chat ( addresses )
+ Blocked addresses- blocks processing of txs
+
+
>
)}
-
+
{Object.entries(blockedUsers?.addresses || {})?.map(
([key, value]) => {
return (
@@ -90,18 +200,22 @@ export const BlockedUsersModal = ({ close }) => {
display: "flex",
alignItems: "center",
gap: "10px",
- width: '100%',
- justifyContent: 'space-between'
+ width: "100%",
+ justifyContent: "space-between",
}}
>
- {key}
+ {addressesWithNames[key] || key}