From ed5d69b4b61eaf6fab1cd93bb729c60be611d8f8 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Wed, 18 Jun 2025 22:08:25 +0300 Subject: [PATCH] added txGroupId and event publish status --- src/background/background-cases.ts | 45 ++++++++++++++++------ src/background/background.ts | 30 ++++++++++++--- src/components/Apps/AppViewer.tsx | 45 +++++++++++++++++++++- src/hooks/useQortalMessageListener.tsx | 3 +- src/qdn/publish/publish.ts | 53 +++++++++++++++++++++++++- src/qortal/get.ts | 23 +++++++++-- src/qortal/qortal-requests.ts | 3 +- 7 files changed, 177 insertions(+), 25 deletions(-) diff --git a/src/background/background-cases.ts b/src/background/background-cases.ts index 0392893..04777fb 100644 --- a/src/background/background-cases.ts +++ b/src/background/background-cases.ts @@ -358,11 +358,17 @@ export async function sendCoinCase(request, event) { export async function inviteToGroupCase(request, event) { try { - const { groupId, qortalAddress, inviteTime } = request.payload; + const { + groupId, + qortalAddress, + inviteTime, + txGroupId = 0, + } = request.payload; const response = await inviteToGroup({ groupId, qortalAddress, inviteTime, + txGroupId, }); event.source.postMessage( @@ -483,8 +489,12 @@ export async function createGroupCase(request, event) { export async function cancelInvitationToGroupCase(request, event) { try { - const { groupId, qortalAddress } = request.payload; - const response = await cancelInvitationToGroup({ groupId, qortalAddress }); + const { groupId, qortalAddress, txGroupId = 0 } = request.payload; + const response = await cancelInvitationToGroup({ + groupId, + qortalAddress, + txGroupId, + }); event.source.postMessage( { @@ -564,11 +574,17 @@ export async function joinGroupCase(request, event) { export async function kickFromGroupCase(request, event) { try { - const { groupId, qortalAddress, rBanReason } = request.payload; + const { + groupId, + qortalAddress, + rBanReason, + txGroupId = 0, + } = request.payload; const response = await kickFromGroup({ groupId, qortalAddress, rBanReason, + txGroupId, }); event.source.postMessage( @@ -595,12 +611,19 @@ export async function kickFromGroupCase(request, event) { export async function banFromGroupCase(request, event) { try { - const { groupId, qortalAddress, rBanReason, rBanTime } = request.payload; + const { + groupId, + qortalAddress, + rBanReason, + rBanTime, + txGroupId = 0, + } = request.payload; const response = await banFromGroup({ groupId, qortalAddress, rBanReason, rBanTime, + txGroupId, }); event.source.postMessage( @@ -734,8 +757,8 @@ export async function getUserSettingsCase(request, event) { export async function cancelBanCase(request, event) { try { - const { groupId, qortalAddress } = request.payload; - const response = await cancelBan({ groupId, qortalAddress }); + const { groupId, qortalAddress, txGroupId = 0 } = request.payload; + const response = await cancelBan({ groupId, qortalAddress, txGroupId }); event.source.postMessage( { @@ -847,8 +870,8 @@ export async function voteOnPollCase(request, event) { export async function makeAdminCase(request, event) { try { - const { groupId, qortalAddress } = request.payload; - const response = await makeAdmin({ groupId, qortalAddress }); + const { groupId, qortalAddress, txGroupId = 0 } = request.payload; + const response = await makeAdmin({ groupId, qortalAddress, txGroupId }); event.source.postMessage( { @@ -874,8 +897,8 @@ export async function makeAdminCase(request, event) { export async function removeAdminCase(request, event) { try { - const { groupId, qortalAddress } = request.payload; - const response = await removeAdmin({ groupId, qortalAddress }); + const { groupId, qortalAddress, txGroupId = 0 } = request.payload; + const response = await removeAdmin({ groupId, qortalAddress, txGroupId }); event.source.postMessage( { diff --git a/src/background/background.ts b/src/background/background.ts index e2b41cc..9a56706 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -2069,7 +2069,11 @@ export async function joinGroup({ groupId }) { return res; } -export async function cancelInvitationToGroup({ groupId, qortalAddress }) { +export async function cancelInvitationToGroup({ + groupId, + qortalAddress, + txGroupId = 0, +}) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -2086,6 +2090,7 @@ export async function cancelInvitationToGroup({ groupId, qortalAddress }) { recipient: qortalAddress, rGroupId: groupId, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2096,7 +2101,7 @@ export async function cancelInvitationToGroup({ groupId, qortalAddress }) { return res; } -export async function cancelBan({ groupId, qortalAddress }) { +export async function cancelBan({ groupId, qortalAddress, txGroupId = 0 }) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -2113,6 +2118,7 @@ export async function cancelBan({ groupId, qortalAddress }) { recipient: qortalAddress, rGroupId: groupId, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2175,7 +2181,7 @@ export async function updateName({ newName, oldName, description }) { throw new Error(res?.message || 'Transaction was not able to be processed'); return res; } -export async function makeAdmin({ groupId, qortalAddress }) { +export async function makeAdmin({ groupId, qortalAddress, txGroupId = 0 }) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -2192,6 +2198,7 @@ export async function makeAdmin({ groupId, qortalAddress }) { recipient: qortalAddress, rGroupId: groupId, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2202,7 +2209,7 @@ export async function makeAdmin({ groupId, qortalAddress }) { return res; } -export async function removeAdmin({ groupId, qortalAddress }) { +export async function removeAdmin({ groupId, qortalAddress, txGroupId = 0 }) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -2219,6 +2226,7 @@ export async function removeAdmin({ groupId, qortalAddress }) { recipient: qortalAddress, rGroupId: groupId, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2234,6 +2242,7 @@ export async function banFromGroup({ qortalAddress, rBanReason = '', rBanTime, + txGroupId = 0, }) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); @@ -2253,6 +2262,7 @@ export async function banFromGroup({ rBanReason: rBanReason, rBanTime, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2267,6 +2277,7 @@ export async function kickFromGroup({ groupId, qortalAddress, rBanReason = '', + txGroupId = 0, }) { const lastReference = await getLastRef(); const resKeyPair = await getKeyPair(); @@ -2285,6 +2296,7 @@ export async function kickFromGroup({ rGroupId: groupId, rBanReason: rBanReason, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2461,6 +2473,7 @@ export async function updateGroup({ newApprovalThreshold, newMinimumBlockDelay, newMaximumBlockDelay, + txGroupId = 0, }) { const wallet = await getSaveWallet(); const address = wallet.address0; @@ -2486,6 +2499,7 @@ export async function updateGroup({ newMinimumBlockDelay, newMaximumBlockDelay, lastReference: lastReference, + groupID: txGroupId, }); const signedBytes = Base58.encode(tx.signedBytes); @@ -2495,7 +2509,12 @@ export async function updateGroup({ 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, + txGroupId = 0, +}) { const address = await getNameOrAddress(qortalAddress); if (!address) throw new Error('Cannot find user'); const lastReference = await getLastRef(); @@ -2510,6 +2529,7 @@ export async function inviteToGroup({ groupId, qortalAddress, inviteTime }) { }; const tx = await createTransaction(29, keyPair, { + groupID: txGroupId, fee: feeres.fee, recipient: address, rGroupId: groupId, diff --git a/src/components/Apps/AppViewer.tsx b/src/components/Apps/AppViewer.tsx index 0dd695d..24350bf 100644 --- a/src/components/Apps/AppViewer.tsx +++ b/src/components/Apps/AppViewer.tsx @@ -1,4 +1,4 @@ -import { forwardRef, useEffect, useMemo, useState } from 'react'; +import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'; import { Box } from '@mui/material'; import { getBaseApiReact } from '../../App'; import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events'; @@ -157,6 +157,49 @@ export const AppViewer = forwardRef( }; }, [app, path]); + const receiveChunksFunc = useCallback( + (e) => { + const iframe = iframeRef?.current; + if (!iframe || !iframe?.src) return; + if (app?.tabId !== e.detail?.tabId) return; + const publishLocation = e.detail?.publishLocation; + const chunksSubmitted = e.detail?.chunksSubmitted; + const totalChunks = e.detail?.totalChunks; + try { + if (publishLocation === undefined || publishLocation === null) return; + const dataToBeSent = {}; + if (chunksSubmitted !== undefined && chunksSubmitted !== null) { + dataToBeSent.chunks = chunksSubmitted; + } + if (totalChunks !== undefined && totalChunks !== null) { + dataToBeSent.totalChunks = totalChunks; + } + const targetOrigin = new URL(iframe.src).origin; + iframe.contentWindow?.postMessage( + { + action: 'PUBLISH_STATUS', + publishLocation, + ...dataToBeSent, + requestedHandler: 'UI', + processed: e.detail?.processed || false, + }, + targetOrigin + ); + } catch (err) { + console.error('Failed to send status to iframe:', err); + } + }, + [iframeRef, app?.tabId] + ); + + useEffect(() => { + subscribeToEvent('receiveChunks', receiveChunksFunc); + + return () => { + unsubscribeFromEvent('receiveChunks', receiveChunksFunc); + }; + }, [receiveChunksFunc]); + // Function to navigate back in iframe const navigateBackInIframe = async () => { if ( diff --git a/src/hooks/useQortalMessageListener.tsx b/src/hooks/useQortalMessageListener.tsx index d2a54c4..9192205 100644 --- a/src/hooks/useQortalMessageListener.tsx +++ b/src/hooks/useQortalMessageListener.tsx @@ -575,6 +575,7 @@ export const useQortalMessageListener = ( { name: appName, service: appService, + tabId, }, skipAuth ) @@ -734,7 +735,7 @@ export const useQortalMessageListener = ( return () => { frameWindow.removeEventListener('message', listener); }; - }, [isDevMode, appName, appService]); // Empty dependency array to run once when the component mounts + }, [isDevMode, appName, appService, tabId]); // Empty dependency array to run once when the component mounts return { path, history, resetHistory, changeCurrentIndex }; }; diff --git a/src/qdn/publish/publish.ts b/src/qdn/publish/publish.ts index 782ecdd..41deab2 100644 --- a/src/qdn/publish/publish.ts +++ b/src/qdn/publish/publish.ts @@ -6,6 +6,7 @@ import nacl from '../../encryption/nacl-fast'; import utils from '../../utils/utils'; import { createEndpoint, getBaseApi } from '../../background/background'; import { getData } from '../../utils/chromeStorage'; +import { executeEvent } from '../../utils/events'; export async function reusableGet(endpoint) { const validApi = await getBaseApi(); @@ -98,6 +99,7 @@ export const publishData = async ({ title, uploadType, withFee, + appInfo, }: any) => { const validateName = async (receiverName: string) => { return await reusableGet(`/names/${receiverName}`); @@ -240,7 +242,17 @@ export const publishData = async ({ if (signAndProcessRes?.error) { throw new Error('Error when signing'); } - + if (appInfo?.tabId) { + executeEvent('receiveChunks', { + tabId: appInfo.tabId, + publishLocation: { + name: registeredName, + identifier, + service, + }, + processed: true, + }); + } return signAndProcessRes; }; @@ -313,6 +325,19 @@ export const publishData = async ({ uploadDataUrl = uploadDataUrl + urlSuffix; } uploadDataUrl = uploadDataUrl + paramQueries; + if (appInfo?.tabId) { + executeEvent('receiveChunks', { + tabId: appInfo.tabId, + publishLocation: { + name: registeredName, + identifier, + service, + }, + chunksSubmitted: 1, + totalChunks: 1, + processed: false, + }); + } return await reusablePost(uploadDataUrl, postBody); } @@ -329,7 +354,19 @@ export const publishData = async ({ const chunkSize = 5 * 1024 * 1024; // 5MB const totalChunks = Math.ceil(file.size / chunkSize); - + if (appInfo?.tabId) { + executeEvent('receiveChunks', { + tabId: appInfo.tabId, + publishLocation: { + name: registeredName, + identifier, + service, + }, + chunksSubmitted: 0, + totalChunks, + processed: false, + }); + } for (let index = 0; index < totalChunks; index++) { const start = index * chunkSize; const end = Math.min(start + chunkSize, file.size); @@ -340,6 +377,18 @@ export const publishData = async ({ formData.append('index', index); await uploadChunkWithRetry(chunkUrl, formData, index); + if (appInfo?.tabId) { + executeEvent('receiveChunks', { + tabId: appInfo.tabId, + publishLocation: { + name: registeredName, + identifier, + service, + }, + chunksSubmitted: index + 1, + totalChunks, + }); + } } const finalizeUrl = uploadDataUrl + `/finalize` + paramQueries; diff --git a/src/qortal/get.ts b/src/qortal/get.ts index 93bcb63..efc81fe 100644 --- a/src/qortal/get.ts +++ b/src/qortal/get.ts @@ -1532,7 +1532,8 @@ export const checkArrrSyncStatus = async (seed) => { export const publishMultipleQDNResources = async ( data: any, sender, - isFromExtension + isFromExtension, + appInfo ) => { const requiredFields = ['resources']; const missingFields: string[] = []; @@ -1880,6 +1881,7 @@ export const publishMultipleQDNResources = async ( title, uploadType: dataType, withFee: true, + appInfo, }, ], true @@ -5632,6 +5634,7 @@ export const inviteToGroupRequest = async (data, isFromExtension) => { const groupId = data.groupId; const qortalAddress = data?.inviteeAddress; const inviteTime = data?.inviteTime; + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { @@ -5677,6 +5680,7 @@ export const inviteToGroupRequest = async (data, isFromExtension) => { groupId, qortalAddress, inviteTime, + txGroupId, }); return response; } else { @@ -5707,7 +5711,7 @@ export const kickFromGroupRequest = async (data, isFromExtension) => { const groupId = data.groupId; const qortalAddress = data?.qortalAddress; const reason = data?.reason; - + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { const url = await createEndpoint(`/groups/${groupId}`); @@ -5752,6 +5756,7 @@ export const kickFromGroupRequest = async (data, isFromExtension) => { groupId, qortalAddress, rBanReason: reason, + txGroupId, }); return response; } else { @@ -5783,6 +5788,7 @@ export const banFromGroupRequest = async (data, isFromExtension) => { const qortalAddress = data?.qortalAddress; const rBanTime = data?.banTime; const reason = data?.reason; + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { const url = await createEndpoint(`/groups/${groupId}`); @@ -5828,6 +5834,7 @@ export const banFromGroupRequest = async (data, isFromExtension) => { qortalAddress, rBanTime, rBanReason: reason, + txGroupId, }); return response; } else { @@ -5857,6 +5864,7 @@ export const cancelGroupBanRequest = async (data, isFromExtension) => { } const groupId = data.groupId; const qortalAddress = data?.qortalAddress; + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { @@ -5901,6 +5909,7 @@ export const cancelGroupBanRequest = async (data, isFromExtension) => { const response = await cancelBan({ groupId, qortalAddress, + txGroupId, }); return response; } else { @@ -5930,6 +5939,7 @@ export const addGroupAdminRequest = async (data, isFromExtension) => { } const groupId = data.groupId; const qortalAddress = data?.qortalAddress; + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { @@ -5974,6 +5984,7 @@ export const addGroupAdminRequest = async (data, isFromExtension) => { const response = await makeAdmin({ groupId, qortalAddress, + txGroupId, }); return response; } else { @@ -6003,7 +6014,7 @@ export const removeGroupAdminRequest = async (data, isFromExtension) => { } const groupId = data.groupId; const qortalAddress = data?.qortalAddress; - + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { const url = await createEndpoint(`/groups/${groupId}`); @@ -6047,6 +6058,7 @@ export const removeGroupAdminRequest = async (data, isFromExtension) => { const response = await removeAdmin({ groupId, qortalAddress, + txGroupId, }); return response; } else { @@ -6076,6 +6088,7 @@ export const cancelGroupInviteRequest = async (data, isFromExtension) => { } const groupId = data.groupId; const qortalAddress = data?.qortalAddress; + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { @@ -6122,6 +6135,7 @@ export const cancelGroupInviteRequest = async (data, isFromExtension) => { const response = await cancelInvitationToGroup({ groupId, qortalAddress, + txGroupId, }); return response; } else { @@ -6228,7 +6242,7 @@ export const updateGroupRequest = async (data, isFromExtension) => { const approvalThreshold = +data?.approvalThreshold; const minBlock = +data?.minBlock; const maxBlock = +data.maxBlock; - + const txGroupId = data?.txGroupId || 0; let groupInfo = null; try { const url = await createEndpoint(`/groups/${groupId}`); @@ -6280,6 +6294,7 @@ export const updateGroupRequest = async (data, isFromExtension) => { newApprovalThreshold: approvalThreshold, newMinimumBlockDelay: minBlock, newMaximumBlockDelay: maxBlock, + txGroupId, }); return response; } else { diff --git a/src/qortal/qortal-requests.ts b/src/qortal/qortal-requests.ts index 2836533..f1f8a22 100644 --- a/src/qortal/qortal-requests.ts +++ b/src/qortal/qortal-requests.ts @@ -398,7 +398,8 @@ function setupMessageListenerQortalRequest() { const res = await publishMultipleQDNResources( request.payload, event.source, - isFromExtension + isFromExtension, + appInfo ); event.source.postMessage( {