From 459230897ac1c5004d5383ef1e4cbc522eaa0853 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Mon, 20 Jan 2025 19:30:36 +0200 Subject: [PATCH] fixes --- .../Apps/useQortalMessageListener.tsx | 5 +- .../Group/ListOfGroupPromotions.tsx | 325 ++++++++++-------- src/components/Group/ManageMembers.tsx | 31 +- src/qortalRequests.ts | 42 ++- src/qortalRequests/get.ts | 36 +- 5 files changed, 278 insertions(+), 161 deletions(-) diff --git a/src/components/Apps/useQortalMessageListener.tsx b/src/components/Apps/useQortalMessageListener.tsx index bebbeeb..54794e5 100644 --- a/src/components/Apps/useQortalMessageListener.tsx +++ b/src/components/Apps/useQortalMessageListener.tsx @@ -232,6 +232,9 @@ async function handleGetFileFromIndexedDB(fileId, sendResponse) { } } + + + const UIQortalRequests = [ 'GET_USER_ACCOUNT', 'DECRYPT_DATA', 'SEND_COIN', 'GET_LIST_ITEMS', 'ADD_LIST_ITEMS', 'DELETE_LIST_ITEM', 'VOTE_ON_POLL', 'CREATE_POLL', @@ -240,7 +243,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', 'ADMIN_ACTION', 'SIGN_TRANSACTION', 'DECRYPT_QORTAL_GROUP_DATA', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY' + 'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', 'ADMIN_ACTION', 'SIGN_TRANSACTION', 'DECRYPT_QORTAL_GROUP_DATA', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'SHOW_ACTIONS' ]; diff --git a/src/components/Group/ListOfGroupPromotions.tsx b/src/components/Group/ListOfGroupPromotions.tsx index 84aca1c..6c777dd 100644 --- a/src/components/Group/ListOfGroupPromotions.tsx +++ b/src/components/Group/ListOfGroupPromotions.tsx @@ -24,12 +24,7 @@ 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"; @@ -51,6 +46,8 @@ import ShortUniqueId from "short-unique-id"; import { CustomizedSnackbars } from "../Snackbar/Snackbar"; import { getGroupNames } from "./UserListOfInvites"; import { WrapperUserAction } from "../WrapperUserAction"; +import { useVirtualizer } from "@tanstack/react-virtual"; +import ErrorBoundary from "../../common/ErrorBoundary"; export const requestQueuePromos = new RequestQueueWithPromise(20); @@ -68,10 +65,6 @@ 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+)-/); @@ -103,6 +96,18 @@ export const ListOfGroupPromotions = () => { 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 { (async () => { @@ -190,7 +195,7 @@ export const ListOfGroupPromotions = () => { }, initialDelay); return () => clearTimeout(initialTimeout); - }, [getPromotions]); + }, [getPromotions, promotionTimeInterval]); const handlePopoverOpen = (event, index) => { setPopoverAnchor(event.currentTarget); @@ -317,20 +322,166 @@ export const ListOfGroupPromotions = () => { - const rowRenderer = ({ index, key, parent, style }) => { - const promotion = promotions[index]; - return ( - + - {({ measure }) => ( -
- + + Group Promotions + + + + + + + + {loading && promotions.length === 0 && ( + + + + )} + {!loading && promotions.length === 0 && ( + + + Nothing to display + + + )} +
+
+
+
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => { + const index = virtualRow.index; + const promotion = promotions[index]; + return ( + +
+ + Error loading content: Invalid Data + + } + > + { }} >
- )} - - ); - }; - - - return ( - - - - - Group Promotions - - - - - - - - {loading && promotions.length === 0 && ( - - - - )} - {!loading && promotions.length === 0 && ( - - - Nothing to display - - - )} -
- - {({ height, width }) => ( - - )} - -
+ +
+ + ); + })} +
+
+
+
diff --git a/src/components/Group/ManageMembers.tsx b/src/components/Group/ManageMembers.tsx index 6c6f146..b2beebd 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,13 +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" : { + sendResponse(listOfAllQortalRequests) + break; + } } } return true; diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index e7683b9..d6bf434 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -3516,7 +3516,7 @@ export const signTransaction = async (data, isFromExtension) => { 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){ @@ -3605,7 +3605,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, sender); @@ -3653,7 +3653,7 @@ export const decryptDataWithSharingKey = 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){ @@ -3752,7 +3752,10 @@ url }; 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", @@ -3764,18 +3767,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"); @@ -3784,6 +3788,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) => { @@ -3805,7 +3813,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: {