diff --git a/package-lock.json b/package-lock.json
index b2cd9a0..2d3d276 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -53,6 +53,7 @@
"react-frame-component": "^5.2.7",
"react-infinite-scroller": "^1.2.6",
"react-intersection-observer": "^9.13.0",
+ "react-json-view-lite": "^2.0.1",
"react-qr-code": "^2.0.15",
"react-quill": "^2.0.0",
"react-redux": "^9.1.2",
@@ -9573,6 +9574,17 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/react-json-view-lite": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.0.1.tgz",
+ "integrity": "sha512-yElNMSzL7UJ9rMDQIbTiBemXbvfAoqpxM/0IQd3nr52CLLBC0HxOSKcta/bayct2QCq7ZVzLzI8CGfuf387hHw==",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0"
+ }
+ },
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
diff --git a/package.json b/package.json
index 1ba83b0..17410d6 100644
--- a/package.json
+++ b/package.json
@@ -57,6 +57,7 @@
"react-frame-component": "^5.2.7",
"react-infinite-scroller": "^1.2.6",
"react-intersection-observer": "^9.13.0",
+ "react-json-view-lite": "^2.0.1",
"react-qr-code": "^2.0.15",
"react-quill": "^2.0.0",
"react-redux": "^9.1.2",
diff --git a/src/App.tsx b/src/App.tsx
index b127506..1b80e97 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -43,7 +43,8 @@ import Return from "./assets/svgs/Return.svg";
import Success from "./assets/svgs/Success.svg";
import Info from "./assets/svgs/Info.svg";
import CloseIcon from "@mui/icons-material/Close";
-
+import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite';
+import 'react-json-view-lite/dist/index.css';
import {
createAccount,
generateRandomSentence,
@@ -2797,6 +2798,15 @@ function App() {
{messageQortalRequestExtension?.highlightedText}
+ {messageQortalRequestExtension?.json && (
+ <>
+
+
+
+
+
+ >
+ )}
{messageQortalRequestExtension?.fee && (
<>
diff --git a/src/components/Apps/AppRating.tsx b/src/components/Apps/AppRating.tsx
index a498779..aab1a87 100644
--- a/src/components/Apps/AppRating.tsx
+++ b/src/components/Apps/AppRating.tsx
@@ -103,14 +103,15 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
getRating(app?.name, app?.service);
}, [getRating, app?.name]);
- const rateFunc = async (event, newValue) => {
+ const rateFunc = async (event, chosenValue, currentValue) => {
try {
+ const newValue = chosenValue || currentValue
if (!myName) throw new Error("You need a name to rate.");
if (!app?.name) return;
- const fee = await getFee("ARBITRARY");
+ const fee = await getFee("CREATE_POLL");
await show({
- message: `Would you like to rate this app a rating of ${newValue}?`,
+ message: `Would you like to rate this app a rating of ${newValue}?. It will create a POLL tx.`,
publishFee: fee.fee + " QORT",
});
@@ -212,7 +213,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
rateFunc(event, rating, value)}
precision={1}
readOnly={hasPublishedRating === null}
size="small"
diff --git a/src/components/Apps/AppsDesktop.tsx b/src/components/Apps/AppsDesktop.tsx
index 6d84ba7..8d01024 100644
--- a/src/components/Apps/AppsDesktop.tsx
+++ b/src/components/Apps/AppsDesktop.tsx
@@ -368,7 +368,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
{mode !== 'home' && (
-
+
)}
diff --git a/src/components/Apps/AppsNavBarDesktop.tsx b/src/components/Apps/AppsNavBarDesktop.tsx
index 9ba6540..d33ba09 100644
--- a/src/components/Apps/AppsNavBarDesktop.tsx
+++ b/src/components/Apps/AppsNavBarDesktop.tsx
@@ -64,7 +64,7 @@ export function saveToLocalStorage(key, subKey, newValue) {
}
}
-export const AppsNavBarDesktop = () => {
+export const AppsNavBarDesktop = ({disableBack}) => {
const [tabs, setTabs] = useState([]);
const [selectedTab, setSelectedTab] = useState(null);
const [navigationController, setNavigationController] = useRecoilState(navigationControllerAtom)
@@ -108,10 +108,11 @@ export const AppsNavBarDesktop = () => {
const isDisableBackButton = useMemo(()=> {
+ if(disableBack) return true
if(selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false
if(selectedTab && !navigationController[selectedTab?.tabId]?.hasBack) return true
return false
- }, [navigationController, selectedTab])
+ }, [navigationController, selectedTab, disableBack])
diff --git a/src/components/Chat/ChatGroup.tsx b/src/components/Chat/ChatGroup.tsx
index 26833fa..98b73e5 100644
--- a/src/components/Chat/ChatGroup.tsx
+++ b/src/components/Chat/ChatGroup.tsx
@@ -252,7 +252,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
const content = item?.content || item.decryptedData?.content;
const sender = item.sender;
const newTimestamp = item.timestamp;
- const contentState = item?.contentState || item.decryptedData?.contentState;
+ const contentState = item?.contentState !== undefined ? item?.contentState : item.decryptedData?.contentState;
if (!content || typeof content !== "string" || !sender || typeof sender !== "string" || !newTimestamp) {
console.warn("Invalid content, sender, or timestamp in reaction data", item);
@@ -344,7 +344,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
const content = item?.content || item.decryptedData?.content;
const sender = item.sender;
const newTimestamp = item.timestamp;
- const contentState = item?.contentState || item.decryptedData?.contentState;
+ const contentState = item?.contentState !== undefined ? item?.contentState : item.decryptedData?.contentState;
if (!content || typeof content !== "string" || !sender || typeof sender !== "string" || !newTimestamp) {
console.warn("Invalid content, sender, or timestamp in reaction data", item);
@@ -755,7 +755,7 @@ useEffect(() => {
setIsSending(false)
resumeAllQueues()
}
- }, [])
+ }, [isPrivate])
console.log('isPrivate', isPrivate)
diff --git a/src/components/Embeds/PollEmbed.tsx b/src/components/Embeds/PollEmbed.tsx
index 3da02c3..6b104c4 100644
--- a/src/components/Embeds/PollEmbed.tsx
+++ b/src/components/Embeds/PollEmbed.tsx
@@ -48,16 +48,17 @@ export const PollCard = ({
});
setIsLoadingSubmit(true);
- window
- .sendMessage(
- "voteOnPoll",
+ chrome?.runtime?.sendMessage(
{
- pollName: poll?.info?.pollName,
+ action: "VOTE_ON_POLL",
+ type: "qortalRequest",
+ payload: {
+ pollName: poll?.info?.pollName,
optionIndex: +selectedOption,
+ }
+
},
- 60000
- )
- .then((response) => {
+ (response) => {
setIsLoadingSubmit(false);
if (response.error) {
setInfoSnack({
@@ -75,14 +76,6 @@ export const PollCard = ({
setOpenSnack(true);
}
})
- .catch((error) => {
- setIsLoadingSubmit(false);
- setInfoSnack({
- type: "error",
- message: error?.message || "Unable to vote.",
- });
- setOpenSnack(true);
- });
};
const getName = async (owner) => {
diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx
index 2859d51..595f2c8 100644
--- a/src/components/Group/Group.tsx
+++ b/src/components/Group/Group.tsx
@@ -96,6 +96,7 @@ import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import { useSetRecoilState } from "recoil";
import { selectedGroupIdAtom } from "../../atoms/global";
+import { sortArrayByTimestampAndGroupName } from "../../utils/time";
// let touchStartY = 0;
// let disablePullToRefresh = false;
@@ -976,7 +977,7 @@ export const Group = ({
chrome?.runtime?.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "SET_GROUPS") {
// Update the component state with the received 'sendqort' state
- setGroups(message.payload);
+ setGroups(sortArrayByTimestampAndGroupName(message.payload));
getLatestRegularChat(message.payload)
setMemberGroups(message.payload);
@@ -2632,6 +2633,10 @@ export const Group = ({
Wait until an admin re-encrypts the keys.
+
+ Only unencrypted messages will be displayed.
+
+
Try notifying an admin from the list of admins below:
diff --git a/src/components/Group/ListOfBans.tsx b/src/components/Group/ListOfBans.tsx
index 41ef9f4..e1d7698 100644
--- a/src/components/Group/ListOfBans.tsx
+++ b/src/components/Group/ListOfBans.tsx
@@ -12,7 +12,7 @@ export const getMemberInvites = async (groupNumber) => {
return groupData;
}
-const getNames = async (listOfMembers) => {
+const getNames = async (listOfMembers, includeNoNames) => {
let members = [];
if (listOfMembers && Array.isArray(listOfMembers)) {
for (const member of listOfMembers) {
@@ -20,6 +20,8 @@ const getNames = async (listOfMembers) => {
const name = await getNameInfo(member.offender);
if (name) {
members.push({ ...member, name });
+ } else if(includeNoNames){
+ members.push({ ...member, name: name || "" });
}
}
}
@@ -42,7 +44,8 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
const getInvites = async (groupId) => {
try {
const res = await getMemberInvites(groupId);
- const resWithNames = await getNames(res);
+ const resWithNames = await getNames(res, true);
+
setBans(resWithNames);
} catch (error) {
console.error(error);
@@ -151,9 +154,9 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
handlePopoverOpen(event, index)}>
-
diff --git a/src/components/Group/ListOfInvites.tsx b/src/components/Group/ListOfInvites.tsx
index 9bdf124..8dfc599 100644
--- a/src/components/Group/ListOfInvites.tsx
+++ b/src/components/Group/ListOfInvites.tsx
@@ -12,7 +12,7 @@ export const getMemberInvites = async (groupNumber) => {
return groupData;
}
-const getNames = async (listOfMembers) => {
+const getNames = async (listOfMembers, includeNoNames) => {
let members = [];
if (listOfMembers && Array.isArray(listOfMembers)) {
for (const member of listOfMembers) {
@@ -20,6 +20,8 @@ const getNames = async (listOfMembers) => {
const name = await getNameInfo(member.invitee);
if (name) {
members.push({ ...member, name });
+ } else if(includeNoNames){
+ members.push({ ...member, name: name || "" });
}
}
}
@@ -43,7 +45,7 @@ export const ListOfInvites = ({ groupId, setInfoSnack, setOpenSnack, show }) =>
const getInvites = async (groupId) => {
try {
const res = await getMemberInvites(groupId);
- const resWithNames = await getNames(res);
+ const resWithNames = await getNames(res, true);
setInvites(resWithNames);
} catch (error) {
console.error(error);
@@ -152,9 +154,9 @@ export const ListOfInvites = ({ groupId, setInfoSnack, setOpenSnack, show }) =>
handlePopoverOpen(event, index)}>
-
diff --git a/src/components/Group/ListOfJoinRequests.tsx b/src/components/Group/ListOfJoinRequests.tsx
index b3422da..026cfee 100644
--- a/src/components/Group/ListOfJoinRequests.tsx
+++ b/src/components/Group/ListOfJoinRequests.tsx
@@ -12,14 +12,16 @@ export const getMemberInvites = async (groupNumber) => {
return groupData;
}
-const getNames = async (listOfMembers) => {
+const getNames = async (listOfMembers, includeNoNames) => {
let members = [];
if (listOfMembers && Array.isArray(listOfMembers)) {
for (const member of listOfMembers) {
if (member.joiner) {
const name = await getNameInfo(member.joiner);
if (name) {
- members.push({ ...member, name });
+ members.push({ ...member, name: name || "" });
+ } else if(includeNoNames){
+ members.push({ ...member, name: name || "" });
}
}
}
@@ -27,6 +29,7 @@ const getNames = async (listOfMembers) => {
return members;
}
+
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 50,
@@ -44,7 +47,7 @@ export const ListOfJoinRequests = ({ groupId, setInfoSnack, setOpenSnack, show }
const getInvites = async (groupId) => {
try {
const res = await getMemberInvites(groupId);
- const resWithNames = await getNames(res);
+ const resWithNames = await getNames(res, true);
setInvites(resWithNames);
} catch (error) {
console.error(error);
@@ -165,9 +168,9 @@ export const ListOfJoinRequests = ({ groupId, setInfoSnack, setOpenSnack, show }
handlePopoverOpen(event, index)}>
-
diff --git a/src/components/Group/ListOfMembers.tsx b/src/components/Group/ListOfMembers.tsx
index 54950f6..515686c 100644
--- a/src/components/Group/ListOfMembers.tsx
+++ b/src/components/Group/ListOfMembers.tsx
@@ -328,7 +328,7 @@ const ListOfMembers = ({
{
+ const getMembersWithNames = React.useCallback(async (groupId) => {
try {
setIsLoadingMembers(true)
const res = await getGroupMembers(groupId);
@@ -121,6 +122,13 @@ export const ManageMembers = ({
setMembersWithNames(resWithNames);
setIsLoadingMembers(false)
} catch (error) {}
+ }, []);
+
+ const getMembers = async (groupId) => {
+ try {
+ const res = await getGroupMembers(groupId);
+ setMembersWithNames(res?.members || []);
+ } catch (error) {}
};
React.useEffect(()=> {
@@ -256,6 +264,8 @@ export const ManageMembers = ({
maxWidth: '750px'
}}
>
+
+
{
+export const TaskManger = ({ getUserInfo }) => {
const { txList, setTxList, memberGroups } = useContext(MyContext);
- const [open, setOpen] = React.useState(true);
-
+ const [open, setOpen] = React.useState(false);
+ const intervals = useRef({});
+
const handleClick = () => {
- setOpen(!open);
+ setOpen((prev) => !prev);
};
- const intervals = useRef({})
+ const getStatus = ({ signature }, callback) => {
+ let stop = false;
+ const getAnswer = async () => {
+ const getTx = async () => {
+ const url = `${getBaseApiReact()}/transactions/signature/${signature}`;
+ const res = await fetch(url);
+ return await res.json();
+ };
- const getStatus = ({signature}, callback?: any) =>{
-
- let stop = false
-
- const getAnswer = async () => {
- const getTx = async () => {
- const url = `${getBaseApiReact()}/transactions/signature/${signature}`
- const res = await fetch(url)
-
- return await res.json()
- }
-
- if (!stop) {
- stop = true
-
- try {
- const txTransaction = await getTx()
-
- if (!txTransaction.error && txTransaction.signature) {
- await new Promise((res)=> {
+ if (!stop) {
+ stop = true;
+ try {
+ const txTransaction = await getTx();
+ if (!txTransaction.error && txTransaction.signature) {
+ await new Promise((res) =>
setTimeout(() => {
- res(null)
- }, 300000);
- })
- setTxList((prev)=> {
+ res(null);
+ }, 300000)
+ );
+ setTxList((prev) => {
let previousData = [...prev];
- const findTxWithSignature = previousData.findIndex((tx)=> tx.signature === signature)
- if(findTxWithSignature !== -1){
+ const findTxWithSignature = previousData.findIndex(
+ (tx) => tx.signature === signature
+ );
+ if (findTxWithSignature !== -1) {
previousData[findTxWithSignature].done = true;
- return previousData
+ return previousData;
}
- return previousData
- })
- if(callback){
- callback(true)
+ return previousData;
+ });
+ if (callback) {
+ callback(true);
}
- clearInterval(intervals.current[signature])
+ clearInterval(intervals.current[signature]);
+ }
+ } catch (error) {}
+ stop = false;
+ }
+ };
- }
- } catch (error) { }
-
- stop = false
- }
- }
-
- intervals.current[signature] = setInterval(getAnswer, 120000)
- }
+ intervals.current[signature] = setInterval(getAnswer, 120000);
+ };
useEffect(() => {
setTxList((prev) => {
@@ -80,111 +72,117 @@ export const TaskManger = ({getUserInfo}) => {
const findGroup = txList.findIndex(
(tx) => tx?.type === "joined-group" && tx?.groupId === group.groupId
);
- if (findGroup !== -1 && !previousData[findGroup]?.done ) {
- // add notification
+ if (findGroup !== -1 && !previousData[findGroup]?.done) {
previousData[findGroup].done = true;
}
-
});
+
memberGroups.forEach((group) => {
const findGroup = txList.findIndex(
- (tx) => tx?.type === "created-group" && tx?.groupName === group.groupName
+ (tx) =>
+ tx?.type === "created-group" && tx?.groupName === group.groupName
);
- if (findGroup !== -1 && !previousData[findGroup]?.done ) {
- // add notification
+ if (findGroup !== -1 && !previousData[findGroup]?.done) {
previousData[findGroup].done = true;
}
-
});
- prev.forEach((tx, index)=> {
- if(tx?.type === "leave-group" && memberGroups.findIndex(
- (group) => tx?.groupId === group.groupId
- ) === -1){
+
+ prev.forEach((tx, index) => {
+ if (
+ tx?.type === "leave-group" &&
+ memberGroups.findIndex((group) => tx?.groupId === group.groupId) === -1
+ ) {
previousData[index].done = true;
}
+ });
- })
- prev.forEach((tx, index)=> {
-
- if(tx?.type === "created-common-secret" && tx?.signature && !tx.done){
- if(intervals.current[tx.signature]) return
-
- getStatus({signature: tx.signature})
+ prev.forEach((tx) => {
+ if (
+ ["created-common-secret", "joined-group-request", "join-request-accept"].includes(
+ tx?.type
+ ) &&
+ tx?.signature &&
+ !tx.done
+ ) {
+ if (!intervals.current[tx.signature]) {
+ getStatus({ signature: tx.signature });
+ }
}
-
- })
- prev.forEach((tx, index)=> {
-
- if(tx?.type === "joined-group-request" && tx?.signature && !tx.done){
- if(intervals.current[tx.signature]) return
-
- getStatus({signature: tx.signature})
+ if (tx?.type === "register-name" && tx?.signature && !tx.done) {
+ if (!intervals.current[tx.signature]) {
+ getStatus({ signature: tx.signature }, getUserInfo);
+ }
}
+ });
- })
- prev.forEach((tx, index)=> {
-
- if(tx?.type === "join-request-accept" && tx?.signature && !tx.done){
- if(intervals.current[tx.signature]) return
-
- getStatus({signature: tx.signature})
- }
-
- })
-
- prev.forEach((tx, index)=> {
-
- if(tx?.type === "register-name" && tx?.signature && !tx.done){
- if(intervals.current[tx.signature]) return
-
- getStatus({signature: tx.signature}, getUserInfo)
- }
-
- })
-
return previousData;
});
}, [memberGroups, getUserInfo]);
- if(isMobile) return null
+ if (isMobile || txList?.length === 0 || txList.every((item) => item?.done))
+ return null;
- if (txList?.length === 0 || txList.filter((item) => !item?.done).length === 0) return null;
return (
-
-
-
- {txList.find((item) => !item.done) ? (
-
- ) : (
-
- )}
-
-
- {open ? : }
-
-
-
- {txList.map((item) => {
- return (
-
-
-
-
- );
- })}
+ <>
+ {!open && (
+
+ {txList.some((item) => !item.done) ? : }
+
+ )}
+ {open && (
+
+
+
+ {txList.some((item) => !item.done) ? (
+
+ ) : (
+
+ )}
+
+
+ {open ? : }
+
+
+
+ {txList.map((item) => (
+
+
+
+ ))}
+
+
-
-
+ )}
+ >
);
};
diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts
index 63f6b72..c824cfe 100644
--- a/src/qortalRequests/get.ts
+++ b/src/qortalRequests/get.ts
@@ -1638,6 +1638,10 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
throw new Error(errorMsg);
}
+ const isGateway = await isRunningGateway()
+
+ if(data?.coin === 'ARRR' && isGateway) throw new Error('Cannot view ARRR balance through the gateway. Please use your local node.')
+
const value = (await getPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`)) || false;
let skip = false;
if (value) {
@@ -1691,7 +1695,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
case "BTC":
_url = await createEndpoint(`/crosschain/btc/walletbalance`);
- _body = parsedData.derivedMasterPublicKey;
+ _body = parsedData.btcPublicKey;
break;
case "LTC":
_url = await createEndpoint(`/crosschain/ltc/walletbalance`);
diff --git a/src/utils/time.ts b/src/utils/time.ts
index 77a0daf..b0a27cf 100644
--- a/src/utils/time.ts
+++ b/src/utils/time.ts
@@ -35,4 +35,22 @@ export function formatTimestamp(timestamp: number): string {
const date = moment(unixTimestamp, 'x').fromNow()
return date
+ }
+
+ export function sortArrayByTimestampAndGroupName(array) {
+ return array.sort((a, b) => {
+ if (a.timestamp && b.timestamp) {
+ // Both have timestamp, sort by timestamp descending
+ return b.timestamp - a.timestamp;
+ } else if (a.timestamp) {
+ // Only `a` has timestamp, it comes first
+ return -1;
+ } else if (b.timestamp) {
+ // Only `b` has timestamp, it comes first
+ return 1;
+ } else {
+ // Neither has timestamp, sort alphabetically by groupName
+ return a.groupName.localeCompare(b.groupName);
+ }
+ });
}
\ No newline at end of file