diff --git a/src/components/Apps/useQortalMessageListener.tsx b/src/components/Apps/useQortalMessageListener.tsx
index 83bd708..68c7fa1 100644
--- a/src/components/Apps/useQortalMessageListener.tsx
+++ b/src/components/Apps/useQortalMessageListener.tsx
@@ -173,6 +173,44 @@ export function openIndexedDB() {
});
}
+ export const listOfAllQortalRequests = [
+ 'GET_USER_ACCOUNT', 'DECRYPT_DATA', 'SEND_COIN', 'GET_LIST_ITEMS',
+ 'ADD_LIST_ITEMS', 'DELETE_LIST_ITEM', 'VOTE_ON_POLL', 'CREATE_POLL',
+ 'SEND_CHAT_MESSAGE', 'JOIN_GROUP', 'DEPLOY_AT', 'GET_USER_WALLET',
+ 'GET_WALLET_BALANCE', 'GET_USER_WALLET_INFO', 'GET_CROSSCHAIN_SERVER_INFO',
+ 'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
+ '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_GATEWAY', 'ADMIN_ACTION', 'SIGN_TRANSACTION', 'OPEN_NEW_TAB', 'CREATE_AND_COPY_EMBED_LINK', 'DECRYPT_QORTAL_GROUP_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'PUBLISH_MULTIPLE_QDN_RESOURCES',
+ 'PUBLISH_QDN_RESOURCE',
+ 'ENCRYPT_DATA',
+ 'ENCRYPT_DATA_WITH_SHARING_KEY',
+ 'ENCRYPT_QORTAL_GROUP_DATA',
+ 'SAVE_FILE',
+ 'GET_ACCOUNT_DATA',
+ 'GET_ACCOUNT_NAMES',
+ 'SEARCH_NAMES',
+ 'GET_NAME_DATA',
+ 'GET_QDN_RESOURCE_URL',
+ 'LINK_TO_QDN_RESOURCE',
+ 'LIST_QDN_RESOURCES',
+ 'SEARCH_QDN_RESOURCES',
+ 'FETCH_QDN_RESOURCE',
+ 'GET_QDN_RESOURCE_STATUS',
+ 'GET_QDN_RESOURCE_PROPERTIES',
+ 'GET_QDN_RESOURCE_METADATA',
+ 'SEARCH_CHAT_MESSAGES',
+ 'LIST_GROUPS',
+ 'GET_BALANCE',
+ 'GET_AT',
+ 'GET_AT_DATA',
+ 'LIST_ATS',
+ 'FETCH_BLOCK',
+ 'FETCH_BLOCK_RANGE',
+ 'SEARCH_TRANSACTIONS',
+ 'GET_PRICE',
+ 'SHOW_ACTIONS'
+ ]
+
const UIQortalRequests = [
@@ -183,7 +221,7 @@ const UIQortalRequests = [
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
'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_GATEWAY', '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'
+ 'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', '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'
];
diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx
index cdc58df..8e58f59 100644
--- a/src/components/Group/Group.tsx
+++ b/src/components/Group/Group.tsx
@@ -250,7 +250,7 @@ export const getGroupMembers = async (groupNumber: number) => {
return groupData;
};
-export const decryptResource = async (data: string) => {
+export const decryptResource = async (data: string, fromQortalRequest?:boolean) => {
try {
return new Promise((res, rej) => {
window.sendMessage("decryptGroupEncryption", {
@@ -261,10 +261,19 @@ export const decryptResource = async (data: string) => {
res(response);
return;
}
- rej(response.error);
+ if(fromQortalRequest){
+ rej({error: response.error, message: response?.error});
+ } else {
+ rej(response.error);
+
+ }
})
.catch((error) => {
- rej(error.message || "An error occurred");
+ if(fromQortalRequest){
+ rej({message: error.message || "An error occurred", error: error.message || "An error occurred"});
+ } else {
+ rej(error.message || "An error occurred",);
+ }
});
});
diff --git a/src/components/Group/ListOfGroupPromotions.tsx b/src/components/Group/ListOfGroupPromotions.tsx
index 3cb5c4f..d5750b3 100644
--- a/src/components/Group/ListOfGroupPromotions.tsx
+++ b/src/components/Group/ListOfGroupPromotions.tsx
@@ -24,15 +24,12 @@ import {
TextField,
Typography,
} from "@mui/material";
-import {
- AutoSizer,
- CellMeasurer,
- CellMeasurerCache,
- List,
-} from "react-virtualized";
+
import { getNameInfo } from "./Group";
import { getBaseApi, getFee } from "../../background";
import { LoadingButton } from "@mui/lab";
+import LockIcon from '@mui/icons-material/Lock';
+import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import {
MyContext,
getArbitraryEndpointReact,
@@ -49,8 +46,9 @@ import ShortUniqueId from "short-unique-id";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { getGroupNames } from "./UserListOfInvites";
import { WrapperUserAction } from "../WrapperUserAction";
-import LockIcon from '@mui/icons-material/Lock';
-import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
+import { useVirtualizer } from "@tanstack/react-virtual";
+import ErrorBoundary from "../../common/ErrorBoundary";
+
export const requestQueuePromos = new RequestQueueWithPromise(20);
export function utf8ToBase64(inputString: string): string {
@@ -67,10 +65,7 @@ export function utf8ToBase64(inputString: string): string {
const uid = new ShortUniqueId({ length: 8 });
-const cache = new CellMeasurerCache({
- fixedWidth: true,
- defaultHeight: 50,
-});
+
export function getGroupId(str) {
const match = str.match(/group-(\d+)-/);
@@ -101,6 +96,18 @@ export const ListOfGroupPromotions = () => {
const { show, setTxList } = useContext(MyContext);
const listRef = useRef();
+ const rowVirtualizer = useVirtualizer({
+ count: promotions.length,
+ getItemKey: React.useCallback(
+ (index) => promotions[index]?.identifier,
+ [promotions]
+ ),
+ getScrollElement: () => listRef.current,
+ estimateSize: () => 80, // Provide an estimated height of items, adjust this as needed
+ overscan: 10, // Number of items to render outside the visible area to improve smoothness
+ });
+
+
useEffect(() => {
try {
@@ -189,7 +196,7 @@ export const ListOfGroupPromotions = () => {
}, initialDelay);
return () => clearTimeout(initialTimeout);
- }, [getPromotions]);
+ }, [getPromotions, promotionTimeInterval]);
const handlePopoverOpen = (event, index) => {
setPopoverAnchor(event.currentTarget);
@@ -323,286 +330,6 @@ export const ListOfGroupPromotions = () => {
}
};
- // const handleCancelInvitation = async (address)=> {
- // try {
- // const fee = await getFee('CANCEL_GROUP_INVITE')
- // await show({
- // message: "Would you like to perform a CANCEL_GROUP_INVITE transaction?" ,
- // publishFee: fee.fee + ' QORT'
- // })
- // setIsLoadingCancelInvite(true)
- // await new Promise((res, rej)=> {
- // window.sendMessage("cancelInvitationToGroup", {
- // groupId,
- // qortalAddress: address,
- // })
- // .then((response) => {
- // if (!response?.error) {
- // setInfoSnack({
- // type: "success",
- // message: "Successfully canceled invitation. It may take a couple of minutes for the changes to propagate",
- // });
- // setOpenSnack(true);
- // handlePopoverClose();
- // setIsLoadingCancelInvite(true);
- // res(response);
- // return;
- // }
- // setInfoSnack({
- // type: "error",
- // message: response?.error,
- // });
- // setOpenSnack(true);
- // rej(response.error);
- // })
- // .catch((error) => {
- // setInfoSnack({
- // type: "error",
- // message: error.message || "An error occurred",
- // });
- // setOpenSnack(true);
- // rej(error);
- // });
-
- // })
- // } catch (error) {
-
- // } finally {
- // setIsLoadingCancelInvite(false)
- // }
- // }
-
- const rowRenderer = ({ index, key, parent, style }) => {
- const promotion = promotions[index];
-
- return (
-
- {({ measure }) => (
-
-
- {
- if (reason === "backdropClick") {
- // Prevent closing on backdrop click
- return;
- }
- handlePopoverClose(); // Close only on other events like Esc key press
- }}
- anchorOrigin={{
- vertical: "top",
- horizontal: "center",
- }}
- transformOrigin={{
- vertical: "bottom",
- horizontal: "center",
- }}
- style={{ marginTop: "8px" }}
- >
-
-
- Group name: {` ${promotion?.groupName}`}
-
-
- Number of members: {` ${promotion?.memberCount}`}
-
- {promotion?.description && (
-
- {promotion?.description}
-
- )}
- {promotion?.isOpen === false && (
-
- *This is a closed/private group, so you will need to wait
- until an admin accepts your request
-
- )}
-
-
-
- Close
-
-
- handleJoinGroup(promotion, promotion?.isOpen)
- }
- >
- Join
-
-
-
-
-
-
-
-
- {promotion?.name?.charAt(0)}
-
-
- {promotion?.name}
-
-
-
-
-
-
- {promotion?.groupName}
-
-
-
- {promotion?.isOpen === false && (
-
- )}
- {promotion?.isOpen === true && (
-
- )}
-
- {promotion?.isOpen ? 'Public group' : 'Private group' }
-
-
-
-
- {promotion?.data}
-
-
-
-
-
-
-
-
- )}
-
- );
- };
return (
@@ -697,25 +424,293 @@ export const ListOfGroupPromotions = () => {
)}
-
-
- {({ height, width }) => (
-
+
- )}
-
-
+ className="scrollable-container"
+ style={{
+ flexGrow: 1,
+ overflow: "auto",
+ position: "relative",
+ display: "flex",
+ height: "0px",
+ }}
+ >
+
+
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => {
+ const index = virtualRow.index;
+ const promotion = promotions[index];
+ return (
+
+
+
+ Error loading content: Invalid Data
+
+ }
+ >
+
+ {
+ if (reason === "backdropClick") {
+ // Prevent closing on backdrop click
+ return;
+ }
+ handlePopoverClose(); // Close only on other events like Esc key press
+ }}
+ anchorOrigin={{
+ vertical: "top",
+ horizontal: "center",
+ }}
+ transformOrigin={{
+ vertical: "bottom",
+ horizontal: "center",
+ }}
+ style={{ marginTop: "8px" }}
+ >
+
+
+ Group name: {` ${promotion?.groupName}`}
+
+
+ Number of members: {` ${promotion?.memberCount}`}
+
+ {promotion?.description && (
+
+ {promotion?.description}
+
+ )}
+ {promotion?.isOpen === false && (
+
+ *This is a closed/private group, so you will need to wait
+ until an admin accepts your request
+
+ )}
+
+
+
+ Close
+
+
+ handleJoinGroup(promotion, promotion?.isOpen)
+ }
+ >
+ Join
+
+
+
+
+
+
+
+
+ {promotion?.name?.charAt(0)}
+
+
+ {promotion?.name}
+
+
+
+
+
+
+ {promotion?.groupName}
+
+
+
+ {promotion?.isOpen === false && (
+
+ )}
+ {promotion?.isOpen === true && (
+
+ )}
+
+ {promotion?.isOpen ? 'Public group' : 'Private group' }
+
+
+
+
+ {promotion?.data}
+
+
+
+
+
+
+
+
+
+
+ );
+ })}
+
+
+
+
+
@@ -726,7 +721,7 @@ export const ListOfGroupPromotions = () => {
aria-describedby="alert-dialog-description"
>
- {"Promote your group to non-members"}
+ {"Promote your group to non-members"}
diff --git a/src/components/Group/ManageMembers.tsx b/src/components/Group/ManageMembers.tsx
index 2bf00fe..9ca3a17 100644
--- a/src/components/Group/ManageMembers.tsx
+++ b/src/components/Group/ManageMembers.tsx
@@ -17,9 +17,9 @@ import { InviteMember } from "./InviteMember";
import { ListOfInvites } from "./ListOfInvites";
import { ListOfBans } from "./ListOfBans";
import { ListOfJoinRequests } from "./ListOfJoinRequests";
-import { Box, Tab, Tabs } from "@mui/material";
+import { Box, Card, Tab, Tabs } from "@mui/material";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
-import { MyContext, isMobile } from "../../App";
+import { MyContext, getBaseApiReact, isMobile } from "../../App";
import { getGroupMembers, getNames } from "./Group";
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
import { getFee } from "../../background";
@@ -59,6 +59,8 @@ export const ManageMembers = ({
const [infoSnack, setInfoSnack] = React.useState(null);
const [isLoadingMembers, setIsLoadingMembers] = React.useState(false)
const [isLoadingLeave, setIsLoadingLeave] = React.useState(false)
+ const [groupInfo, setGroupInfo] = React.useState(null)
+
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
@@ -131,9 +133,20 @@ export const ManageMembers = ({
} catch (error) {}
};
+ const getGroupInfo = async (groupId) => {
+ try {
+ const response = await fetch(
+ `${getBaseApiReact()}/groups/${groupId}`
+ );
+ const groupData = await response.json();
+ setGroupInfo(groupData)
+ } catch (error) {}
+ };
+
React.useEffect(()=> {
if(selectedGroup?.groupId){
getMembers(selectedGroup?.groupId)
+ getGroupInfo(selectedGroup?.groupId)
}
}, [selectedGroup?.groupId])
@@ -249,12 +262,23 @@ export const ManageMembers = ({
+
+
+ GroupId: {groupInfo?.groupId}
+ GroupName: {groupInfo?.groupName}
+ Number of members: {groupInfo?.memberCount}
+
+
{selectedGroup?.groupId && !isOwner && (
-
Leave Group
)}
+
{value === 0 && (
{
}
break;
}
+
+ case "SHOW_ACTIONS" : {
+ try {
+
+ event.source.postMessage({
+ requestId: request.requestId,
+ action: request.action,
+ payload: listOfAllQortalRequests,
+ type: "backgroundMessageResponse",
+ }, event.origin);
+ } catch (error) {
+ event.source.postMessage({
+ requestId: request.requestId,
+ action: request.action,
+ error: error?.message,
+ type: "backgroundMessageResponse",
+ }, event.origin);
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts
index 6b8fc2c..586cbfc 100644
--- a/src/qortalRequests/get.ts
+++ b/src/qortalRequests/get.ts
@@ -410,7 +410,7 @@ export const encryptData = async (data, sender) => {
export const encryptQortalGroupData = async (data, sender) => {
- let data64 = data.data64;
+ let data64 = data?.data64 || data?.base64;
let groupId = data?.groupId
let isAdmins = data?.isAdmins
if(!groupId){
@@ -445,7 +445,7 @@ export const encryptQortalGroupData = async (data, sender) => {
url
);
const resData = await res.text();
- const decryptedKey: any = await decryptResource(resData);
+ const decryptedKey: any = await decryptResource(resData, true);
const dataint8Array = base64ToUint8Array(decryptedKey.data);
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
@@ -479,7 +479,7 @@ url
url
);
const resData = await res.text();
- const decryptedKey: any = await decryptResource(resData);
+ const decryptedKey: any = await decryptResource(resData, true);
const dataint8Array = base64ToUint8Array(decryptedKey.data);
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
@@ -509,7 +509,7 @@ url
};
export const decryptQortalGroupData = async (data, sender) => {
- let data64 = data.data64;
+ let data64 = data?.data64 || data?.base64;
let groupId = data?.groupId
let isAdmins = data?.isAdmins
if(!groupId){
@@ -540,7 +540,7 @@ export const decryptQortalGroupData = async (data, sender) => {
url
);
const resData = await res.text();
- const decryptedKey: any = await decryptResource(resData);
+ const decryptedKey: any = await decryptResource(resData, true);
const dataint8Array = base64ToUint8Array(decryptedKey.data);
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
@@ -571,7 +571,7 @@ url
url
);
const resData = await res.text();
- const decryptedKey: any = await decryptResource(resData);
+ const decryptedKey: any = await decryptResource(resData, true);
const dataint8Array = base64ToUint8Array(decryptedKey.data);
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
@@ -598,7 +598,7 @@ url
};
export const encryptDataWithSharingKey = async (data, sender) => {
- let data64 = data.data64;
+ let data64 = data?.data64 || data?.base64;
let publicKeys = data.publicKeys || [];
if (data.fileId) {
data64 = await getFileFromContentScript(data.fileId);
@@ -3697,7 +3697,10 @@ export const createAndCopyEmbedLink = async (data, isFromExtension) => {
};
export const getHostedData = async (data, isFromExtension) => {
-
+ const isGateway = await isRunningGateway();
+ if (isGateway) {
+ throw new Error("This action cannot be done through a gateway");
+ }
const resPermission = await getUserPermission(
{
text1: "Do you give this application permission to",
@@ -3709,18 +3712,19 @@ export const getHostedData = async (data, isFromExtension) => {
if(accepted){
const limit = data?.limit ? data?.limit : 20;
- const query = data?.query ? data?.query : undefined
+ const query = data?.query ? data?.query : ""
const offset = data?.offset ? data?.offset : 0
- try {
-
- const url = await createEndpoint(`/arbitrary/hosted/resources/?limit=${limit}&query=${query}&offset=${offset}`);
- const response = await fetch(url);
- const data = await response.json();
- return data
- } catch (error) {
- throw error
+ let urlPath = `/arbitrary/hosted/resources/?limit=${limit}&offset=${offset}`
+ if(query){
+ urlPath = urlPath + `&query=${query}`
}
+
+ const url = await createEndpoint(urlPath);
+ const response = await fetch(url);
+ const dataResponse = await response.json();
+ return dataResponse
+
} else {
throw new Error("User declined to get list of hosted resources");
@@ -3729,6 +3733,10 @@ export const getHostedData = async (data, isFromExtension) => {
};
export const deleteHostedData = async (data, isFromExtension) => {
+ const isGateway = await isRunningGateway();
+ if (isGateway) {
+ throw new Error("This action cannot be done through a gateway");
+ }
const requiredFields = ["hostedData"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@@ -3750,7 +3758,7 @@ export const deleteHostedData = async (data, isFromExtension) => {
for (const hostedDataItem of hostedData){
try {
- const url = await createEndpoint(`/arbitrary/resource/${hostedDataItem.service}/${hostedDataItem.name}/${hostedDataItem.identifer}`);
+ const url = await createEndpoint(`/arbitrary/resource/${hostedDataItem.service}/${hostedDataItem.name}/${hostedDataItem.identifier}`);
await fetch(url, {
method: "DELETE",
headers: {