added pdf viewer and optimizations

This commit is contained in:
2025-04-02 05:58:17 +03:00
committed by Nicola Benaglia
parent 0a16655acb
commit 3611f5d33a
209 changed files with 143827 additions and 34 deletions

View File

@@ -133,6 +133,7 @@ import { BuyQortInformation } from "./components/BuyQortInformation";
import { QortPayment } from "./components/QortPayment";
import { GeneralNotifications } from "./components/GeneralNotifications";
import ThemeSelector from "./components/Theme/ThemeSelector";
import { PdfViewer } from "./common/PdfViewer";
type extStates =
| "not-authenticated"
@@ -2019,32 +2020,31 @@ function App() {
// backgroundRepeat: desktopViewMode === "apps" && "no-repeat",
}}
>
<GlobalContext.Provider
value={{
showTutorial,
openTutorialModal,
setOpenTutorialModal,
downloadResource,
hasSeenGettingStarted,
}}
>
<Tutorials />
{extState === "not-authenticated" && (
<NotAuthenticated
getRootProps={getRootProps}
getInputProps={getInputProps}
setExtstate={setExtstate}
apiKey={apiKey}
globalApiKey={globalApiKey}
setApiKey={setApiKey}
handleSetGlobalApikey={handleSetGlobalApikey}
currentNode={currentNode}
setCurrentNode={setCurrentNode}
setUseLocalNode={setUseLocalNode}
useLocalNode={useLocalNode}
/>
)}
{/* {extState !== "not-authenticated" && (
<PdfViewer />
<GlobalContext.Provider value={{
showTutorial,
openTutorialModal,
setOpenTutorialModal,
downloadResource,
hasSeenGettingStarted
}}>
<Tutorials />
{extState === "not-authenticated" && (
<NotAuthenticated
getRootProps={getRootProps}
getInputProps={getInputProps}
setExtstate={setExtstate}
apiKey={apiKey}
globalApiKey={globalApiKey}
setApiKey={setApiKey}
handleSetGlobalApikey={handleSetGlobalApikey}
currentNode={currentNode}
setCurrentNode={setCurrentNode}
setUseLocalNode={setUseLocalNode}
useLocalNode={useLocalNode}
/>
)}
{/* {extState !== "not-authenticated" && (
<button onClick={logoutFunc}>logout</button>
)} */}
{extState === "authenticated" && isMainWindow && (

80
src/common/PdfViewer.tsx Normal file
View File

@@ -0,0 +1,80 @@
import { useEffect, useState } from "react";
import { subscribeToEvent, unsubscribeFromEvent } from "../utils/events";
import { Box, Button } from "@mui/material";
export const PdfViewer = () => {
const [pdfUrl, setPdfUrl] = useState("");
const openPdf = (e) => {
try {
const blob = e.detail?.blob;
if (blob) {
// Create Object URL
const url = URL.createObjectURL(blob);
setPdfUrl(url);
}
} catch (error) {
console.error(error);
}
};
useEffect(() => {
return () => {
if (pdfUrl) {
URL.revokeObjectURL(pdfUrl);
}
};
}, [pdfUrl]);
useEffect(() => {
subscribeToEvent("openPdf", openPdf);
return () => {
unsubscribeFromEvent("openPdf", openPdf);
};
}, []);
if (!pdfUrl) return null;
return (
<Box
sx={{
position: "fixed",
height: "100vh",
width: "100vw",
backgroundColor: 'var(--Mail-Background)',
zIndex: 990000000
}}
>
<Box
sx={{
height: "50px",
display: "flex",
width: "100%",
alignItems: "center",
justifyContent: "flex-end",
padding: '10px'
}}
>
<Button
onClick={() => {
setPdfUrl("");
}}
variant="contained"
>
Exit
</Button>
</Box>
<iframe
title="PDFViewer"
src={`/pdfjs/web/viewer.html?file=${pdfUrl}`}
style={{
width: "100vw",
height: "calc(100vh - 50px)",
display: "fixed",
left: 0,
}}
/>
</Box>
);
};

View File

@@ -254,7 +254,8 @@ export const listOfAllQortalRequests = [
'GET_USER_WALLET_TRANSACTIONS',
'GET_NODE_INFO',
'GET_NODE_STATUS',
'GET_ARRR_SYNC_STATUS'
'GET_ARRR_SYNC_STATUS',
'SHOW_PDF_READER'
]
export const UIQortalRequests = [
@@ -309,7 +310,8 @@ export const UIQortalRequests = [
'GET_USER_WALLET_TRANSACTIONS',
'GET_NODE_INFO',
'GET_NODE_STATUS',
'GET_ARRR_SYNC_STATUS'
'GET_ARRR_SYNC_STATUS',
'SHOW_PDF_READER'
];

View File

@@ -572,11 +572,17 @@ const WatchComponent = ({onSeen, isLast, children})=> {
const { ref, inView } = useInView({
threshold: 0.7, // Fully visible
triggerOnce: true, // Only trigger once when it becomes visible
delay: 100,
trackVisibility: false,
});
useEffect(() => {
if (inView && isLast && onSeen) {
setTimeout(() => {
onSeen();
}, 100);
}
}, [inView, isLast, onSeen]);

View File

@@ -17,7 +17,7 @@ import { InviteMember } from "./InviteMember";
import { ListOfInvites } from "./ListOfInvites";
import { ListOfBans } from "./ListOfBans";
import { ListOfJoinRequests } from "./ListOfJoinRequests";
import { Box, Card, Tab, Tabs } from "@mui/material";
import { Box, ButtonBase, Card, Tab, Tabs } from "@mui/material";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { MyContext, getBaseApiReact, isMobile } from "../../App";
import { getGroupMembers, getNames } from "./Group";
@@ -26,7 +26,7 @@ import { getFee } from "../../background";
import { LoadingButton } from "@mui/lab";
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import { Spacer } from "../../common/Spacer";
import InsertLinkIcon from '@mui/icons-material/InsertLink';
function a11yProps(index: number) {
return {
id: `simple-tab-${index}`,
@@ -268,6 +268,12 @@ export const ManageMembers = ({
<Typography>GroupId: {groupInfo?.groupId}</Typography>
<Typography>GroupName: {groupInfo?.groupName}</Typography>
<Typography>Number of members: {groupInfo?.memberCount}</Typography>
<ButtonBase sx={{
gap: '10px'
}} onClick={async ()=> {
const link = `qortal://use-group/action-join/groupid-${groupInfo?.groupId}`
await navigator.clipboard.writeText(link);
}}><InsertLinkIcon /> <Typography>Join Group Link</Typography></ButtonBase>
</Box>
<Spacer height="20px" />
{selectedGroup?.groupId && !isOwner && (

View File

@@ -2,6 +2,7 @@ import { gateways, getApiKeyFromStorage } from "./background";
import { listOfAllQortalRequests } from "./components/Apps/useQortalMessageListener";
import { addForeignServer, addGroupAdminRequest, addListItems, adminAction, banFromGroupRequest, cancelGroupBanRequest, cancelGroupInviteRequest, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createGroupRequest, createPoll, createSellOrder, decryptAESGCMRequest, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getCrossChainServerInfo, getDaySummary, getNodeInfo, getNodeStatus, getForeignFee, getHostedData, getListItems, 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, getArrrSyncStatus } from "./qortalRequests/get";
import { getData, storeData } from "./utils/chromeStorage";
import { executeEvent } from "./utils/events";
function getLocalStorage(key) {
return getData(key).catch((error) => {
@@ -1214,7 +1215,29 @@ export const isRunningGateway = async ()=> {
}
break;
}
case "SHOW_PDF_READER" : {
try {
if(!request.payload?.blob){
throw new Error('Missing blob')
}
if(request.payload?.blob?.type !== "application/pdf") throw new Error('blob type must be application/pdf')
executeEvent("openPdf", { blob: request.payload?.blob});
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: true,
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;
}

View File

@@ -106,6 +106,30 @@ const dogeFeePerByte = 0.00001;
const dgbFeePerByte = 0.0000001;
const rvnFeePerByte = 0.00001125;
const MAX_RETRIES = 3; // Set max number of retries
export async function retryTransaction(fn, args, throwError, retries = MAX_RETRIES) {
let attempt = 0;
while (attempt < retries) {
try {
return await fn(...args);
} catch (error) {
console.error(`Attempt ${attempt + 1} failed: ${error.message}`);
attempt++;
if (attempt === retries) {
console.error("Max retries reached. Skipping transaction.");
if(throwError){
throw new Error(error?.message || "Unable to process transaction")
} else {
return null
}
}
await new Promise(res => setTimeout(res, 10000));
}
}
}
function roundUpToDecimals(number, decimals = 8) {
const factor = Math.pow(10, decimals); // Create a factor based on the number of decimals
return Math.ceil(+number * factor) / factor;
@@ -1395,8 +1419,9 @@ export const publishMultipleQDNResources = async (
}
try {
await publishData({
registeredName: encodeURIComponent(name),
await retryTransaction(publishData, [
{
registeredName: encodeURIComponent(name),
file: data64,
service: service,
identifier: encodeURIComponent(identifier),
@@ -1413,7 +1438,8 @@ export const publishMultipleQDNResources = async (
tag5,
apiVersion: 2,
withFee: true,
});
},
], false);
await new Promise((res) => {
setTimeout(() => {
res();