added qortalRequests and payment component

This commit is contained in:
PhilReact 2025-03-06 17:46:07 +02:00
parent 2c006c12f9
commit e00f9e3974
5 changed files with 351 additions and 166 deletions

View File

@ -148,6 +148,7 @@ import { UserLookup } from "./components/UserLookup.tsx/UserLookup";
import { RegisterName } from "./components/RegisterName";
import { BuyQortInformation } from "./components/BuyQortInformation";
import { InstallPWA } from "./components/InstallPWA";
import { QortPayment } from "./components/QortPayment";
type extStates =
@ -860,53 +861,7 @@ function App() {
setLtcBalanceLoading(false);
});
};
const sendCoinFunc = async() => {
try {
setSendPaymentError("");
setSendPaymentSuccess("");
if (!paymentTo) {
setSendPaymentError("Please enter a recipient");
return;
}
if (!paymentAmount) {
setSendPaymentError("Please enter an amount greater than 0");
return;
}
if (!paymentPassword) {
setSendPaymentError("Please enter your wallet password");
return;
}
const fee = await getFee('PAYMENT')
await show({
message: `Would you like to transfer ${Number(paymentAmount)} QORT?` ,
paymentFee: fee.fee + ' QORT'
})
setIsLoading(true);
window
.sendMessage("sendCoin", {
amount: Number(paymentAmount),
receiver: paymentTo.trim(),
password: paymentPassword,
})
.then((response) => {
if (response?.error) {
setSendPaymentError(response.error);
} else {
setIsOpenSendQort(false);
setIsOpenSendQortSuccess(true);
}
setIsLoading(false);
})
.catch((error) => {
console.error("Failed to send coin:", error);
setIsLoading(false);
});
} catch (error) {
//error
}
};
const clearAllStates = () => {
setRequestConnection(null);
@ -1971,95 +1926,12 @@ function App() {
src={Return}
/>
</Box>
<Spacer height="35px" />
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Transfer QORT
</TextP>
<Spacer height="35px" />
<TextP
sx={{
textAlign: "start",
lineHeight: "16px",
fontSize: "20px",
fontWeight: 600,
color: "rgba(255, 255, 255, 0.5)",
}}
>
Balance:
</TextP>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
</Box>
<Spacer height="35px" />
<Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
value={paymentTo}
onChange={(e) => setPaymentTo(e.target.value)}
autoComplete="off"
<QortPayment balance={balance} show={show} onSuccess={()=> {
setIsOpenSendQort(false);
setIsOpenSendQortSuccess(true);
}}
defaultPaymentTo={paymentTo}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">
Amount
</CustomLabel>
<Spacer height="5px" />
<BoundedNumericTextField
value={paymentAmount}
minValue={0}
maxValue={+balance}
allowDecimals={true}
initialValue={'0'}
allowNegatives={false}
afterChange={(e: string) => setPaymentAmount(+e)}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
autoComplete="off"
/>
</Box>
<Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" />
<CustomButton
onClick={() => {
sendCoinFunc();
}}
>
Send
</CustomButton>
</Box>
)}

View File

@ -175,41 +175,85 @@ 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_PUBLIC_NODE', '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',
'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_PUBLIC_NODE',
'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'
'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',
'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'
]
@ -222,7 +266,8 @@ 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_PUBLIC_NODE', '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', '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'
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_PUBLIC_NODE', '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', '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'
];

View File

@ -0,0 +1,167 @@
import { Box, CircularProgress } from '@mui/material';
import React, { useEffect, useState } from 'react'
import { CustomButton, CustomInput, CustomLabel, TextP } from '../App-styles';
import { Spacer } from '../common/Spacer';
import BoundedNumericTextField from '../common/BoundedNumericTextField';
import { PasswordField } from './PasswordField/PasswordField';
import { ErrorText } from './ErrorText/ErrorText';
import { getFee } from '../background';
export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
const [paymentAmount, setPaymentAmount] = useState<number>(0);
const [paymentPassword, setPaymentPassword] = useState<string>("");
const [sendPaymentError, setSendPaymentError] = useState<string>("");
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>("");
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
const sendCoinFunc = async() => {
try {
setSendPaymentError("");
setSendPaymentSuccess("");
if (!paymentTo) {
setSendPaymentError("Please enter a recipient");
return;
}
if (!paymentAmount) {
setSendPaymentError("Please enter an amount greater than 0");
return;
}
if (!paymentPassword) {
setSendPaymentError("Please enter your wallet password");
return;
}
const fee = await getFee('PAYMENT')
await show({
message: `Would you like to transfer ${Number(paymentAmount)} QORT?` ,
paymentFee: fee.fee + ' QORT'
})
setIsLoadingSendCoin(true);
window
.sendMessage("sendCoin", {
amount: Number(paymentAmount),
receiver: paymentTo.trim(),
password: paymentPassword,
})
.then((response) => {
if (response?.error) {
setSendPaymentError(response.error);
} else {
onSuccess()
}
setIsLoadingSendCoin(false);
})
.catch((error) => {
console.error("Failed to send coin:", error);
setIsLoadingSendCoin(false);
});
} catch (error) {
// error
}
};
return (
<>
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Transfer QORT
</TextP>
<Spacer height="35px" />
<TextP
sx={{
textAlign: "start",
lineHeight: "16px",
fontSize: "20px",
fontWeight: 600,
color: "rgba(255, 255, 255, 0.5)",
}}
>
Balance:
</TextP>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
</Box>
<Spacer height="35px" />
<Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
value={paymentTo}
onChange={(e) => setPaymentTo(e.target.value)}
autoComplete="off"
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">
Amount
</CustomLabel>
<Spacer height="5px" />
<BoundedNumericTextField
value={paymentAmount}
minValue={0}
maxValue={+balance}
allowDecimals={true}
initialValue={'0'}
allowNegatives={false}
afterChange={(e: string) => setPaymentAmount(+e)}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
autoComplete="off"
/>
</Box>
<Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" />
<CustomButton
sx={{
cursor: isLoadingSendCoin ? 'default' : 'pointer'
}}
onClick={() => {
if(isLoadingSendCoin) return
sendCoinFunc();
}}
>
{isLoadingSendCoin && (
<CircularProgress size={16} sx={{
color: 'white'
}} />
)}
Send
</CustomButton>
</>
)
}

View File

@ -1,6 +1,6 @@
import { gateways, getApiKeyFromStorage } from "./background";
import { listOfAllQortalRequests } from "./components/Apps/useQortalMessageListener";
import { addForeignServer, addGroupAdminRequest, addListItems, adminAction, banFromGroupRequest, cancelGroupBanRequest, cancelGroupInviteRequest, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createGroupRequest, createPoll, decryptAESGCMRequest, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getCrossChainServerInfo, getDaySummary, 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 } from "./qortalRequests/get";
import { addForeignServer, addGroupAdminRequest, addListItems, adminAction, banFromGroupRequest, cancelGroupBanRequest, cancelGroupInviteRequest, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createGroupRequest, createPoll, decryptAESGCMRequest, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getCrossChainServerInfo, getDaySummary, getForeignFee, getHostedData, getListItems, getNodeInfo, getNodeStatus, 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 } from "./qortalRequests/get";
import { getData, storeData } from "./utils/chromeStorage";
@ -1122,6 +1122,45 @@ export const isRunningGateway = async ()=> {
}
break;
}
case "GET_NODE_INFO": {
try {
const res = await getNodeInfo();
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
type: "backgroundMessageResponse",
}, event.origin);
} catch (error) {
event.source.postMessage({
requestId: request.requestId,
action: request.action,
error: error.message,
type: "backgroundMessageResponse",
}, event.origin);
}
break;
}
case "GET_NODE_STATUS": {
try {
const res = await getNodeStatus();
event.source.postMessage({
requestId: request.requestId,
action: request.action,
payload: res,
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

@ -4416,4 +4416,66 @@ if (resPermission) {
} else {
throw new Error("User declined request");
}
};
export const getNodeInfo = async () => {
const url = `/admin/info`; // Simplified endpoint URL
try {
const endpoint = await createEndpoint(url); // Assuming createEndpoint is available for constructing the full URL
const response = await fetch(endpoint, {
method: "GET",
headers: {
Accept: "*/*",
},
});
if (!response.ok) throw new Error("Failed to retrieve node info");
let res;
try {
res = await response.clone().json();
} catch (e) {
res = await response.text();
}
if (res?.error && res?.message) {
throw new Error(res.message);
}
return res; // Return the full response
} catch (error) {
throw new Error(error?.message || "Error in retrieving node info");
}
};
export const getNodeStatus = async () => {
const url = `/admin/status`; // Simplified endpoint URL
try {
const endpoint = await createEndpoint(url); // Assuming createEndpoint is available for constructing the full URL
const response = await fetch(endpoint, {
method: "GET",
headers: {
Accept: "*/*",
},
});
if (!response.ok) throw new Error("Failed to retrieve node status");
let res;
try {
res = await response.clone().json();
} catch (e) {
res = await response.text();
}
if (res?.error && res?.message) {
throw new Error(res.message);
}
return res; // Return the full response
} catch (error) {
throw new Error(error?.message || "Error in retrieving node status");
}
};