mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-02-14 11:15:49 +00:00
finished apps feature for mobile
This commit is contained in:
parent
44c6b5ad32
commit
6b3a1f51ba
@ -576,7 +576,6 @@ const showSaveFilePicker = async (data) => {
|
||||
}
|
||||
|
||||
chrome.runtime?.onMessage.addListener( function (message, sender, sendResponse) {
|
||||
console.log('message', message)
|
||||
if (message.type === "LOGOUT") {
|
||||
// Notify the web page
|
||||
window.postMessage(
|
||||
@ -812,7 +811,6 @@ if (!window.hasAddedQortalListener) {
|
||||
|
||||
const sendMessageToRuntime = (message, eventPort) => {
|
||||
chrome?.runtime?.sendMessage(message, (response) => {
|
||||
console.log('response', response);
|
||||
if (response.error) {
|
||||
eventPort.postMessage({
|
||||
result: null,
|
||||
@ -829,13 +827,11 @@ if (!window.hasAddedQortalListener) {
|
||||
|
||||
// Check if action is included in the predefined list of UI requests
|
||||
if (UIQortalRequests.includes(event.data.action)) {
|
||||
console.log('event?.data', event?.data);
|
||||
sendMessageToRuntime(
|
||||
{ action: event.data.action, type: 'qortalRequest', payload: event.data },
|
||||
event.ports[0]
|
||||
);
|
||||
} else if (event?.data?.action === 'PUBLISH_MULTIPLE_QDN_RESOURCES' || event?.data?.action === 'PUBLISH_QDN_RESOURCE' || event?.data?.action === 'ENCRYPT_DATA' || event?.data?.action === 'SAVE_FILE') {
|
||||
console.log('event?.data?', event?.data)
|
||||
let data;
|
||||
try {
|
||||
data = await storeFilesInIndexedDB(event.data);
|
||||
|
293
src/App.tsx
293
src/App.tsx
@ -100,8 +100,9 @@ import { Settings } from "./components/Group/Settings";
|
||||
import { MainAvatar } from "./components/MainAvatar";
|
||||
import { useRetrieveDataLocalStorage } from "./useRetrieveDataLocalStorage";
|
||||
import { useQortalGetSaveSettings } from "./useQortalGetSaveSettings";
|
||||
import { useResetRecoilState } from "recoil";
|
||||
import { canSaveSettingToQdnAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from "./atoms/global";
|
||||
import { useRecoilState, useResetRecoilState } from "recoil";
|
||||
import { canSaveSettingToQdnAtom, fullScreenAtom, hasSettingsChangedAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from "./atoms/global";
|
||||
import { useAppFullScreen } from "./useAppFullscreen";
|
||||
|
||||
type extStates =
|
||||
| "not-authenticated"
|
||||
@ -297,10 +298,12 @@ function App() {
|
||||
const [txList, setTxList] = useState([]);
|
||||
const [memberGroups, setMemberGroups] = useState([]);
|
||||
const [isFocused, setIsFocused] = useState(true);
|
||||
|
||||
const [hasSettingsChanged, setHasSettingsChanged] = useRecoilState(hasSettingsChangedAtom)
|
||||
const holdRefExtState = useRef<extStates>("not-authenticated");
|
||||
const isFocusedRef = useRef<boolean>(true);
|
||||
const { isShow, onCancel, onOk, show, message } = useModal();
|
||||
const { isShow: isShowUnsavedChanges, onCancel: onCancelUnsavedChanges, onOk: onOkUnsavedChanges, show: showUnsavedChanges, message: messageUnsavedChanges } = useModal();
|
||||
|
||||
const {
|
||||
onCancel: onCancelQortalRequest,
|
||||
onOk: onOkQortalRequest,
|
||||
@ -308,7 +311,14 @@ function App() {
|
||||
isShow: isShowQortalRequest,
|
||||
message: messageQortalRequest,
|
||||
} = useModal();
|
||||
|
||||
const {
|
||||
onCancel: onCancelQortalRequestExtension,
|
||||
onOk: onOkQortalRequestExtension,
|
||||
show: showQortalRequestExtension,
|
||||
isShow: isShowQortalRequestExtension,
|
||||
message: messageQortalRequestExtension,
|
||||
} = useModal();
|
||||
|
||||
const [openRegisterName, setOpenRegisterName] = useState(false);
|
||||
const registerNamePopoverRef = useRef(null);
|
||||
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
|
||||
@ -328,7 +338,24 @@ function App() {
|
||||
const qortalRequestCheckbox1Ref = useRef(null);
|
||||
useRetrieveDataLocalStorage()
|
||||
useQortalGetSaveSettings(userInfo?.name)
|
||||
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
|
||||
|
||||
const { toggleFullScreen } = useAppFullScreen(setFullScreen);
|
||||
|
||||
useEffect(() => {
|
||||
// Attach a global event listener for double-click
|
||||
const handleDoubleClick = () => {
|
||||
toggleFullScreen();
|
||||
};
|
||||
|
||||
// Add the event listener to the root HTML document
|
||||
document.documentElement.addEventListener('dblclick', handleDoubleClick);
|
||||
|
||||
// Clean up the event listener on unmount
|
||||
return () => {
|
||||
document.documentElement.removeEventListener('dblclick', handleDoubleClick);
|
||||
};
|
||||
}, [toggleFullScreen]);
|
||||
//resets for recoil
|
||||
const resetAtomSortablePinnedAppsAtom = useResetRecoilState(sortablePinnedAppsAtom);
|
||||
const resetAtomCanSaveSettingToQdnAtom = useResetRecoilState(canSaveSettingToQdnAtom);
|
||||
@ -588,15 +615,10 @@ function App() {
|
||||
const qortalRequestPermisson = async (message, sender, sendResponse) => {
|
||||
if (message.action === "QORTAL_REQUEST_PERMISSION" && !isMainWindow) {
|
||||
try {
|
||||
console.log("payloadbefore", message.payload);
|
||||
|
||||
await showQortalRequest(message?.payload);
|
||||
console.log("payload", message.payload);
|
||||
if (message?.payload?.checkbox1) {
|
||||
console.log(
|
||||
"qortalRequestCheckbox1Ref.current",
|
||||
qortalRequestCheckbox1Ref.current
|
||||
);
|
||||
|
||||
sendResponse({
|
||||
accepted: true,
|
||||
checkbox1: qortalRequestCheckbox1Ref.current,
|
||||
@ -605,7 +627,6 @@ function App() {
|
||||
}
|
||||
sendResponse({ accepted: true });
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
sendResponse({ accepted: false });
|
||||
} finally {
|
||||
window.close();
|
||||
@ -615,13 +636,11 @@ function App() {
|
||||
const qortalRequestPermissonFromExtension = async (message, sender, sendResponse) => {
|
||||
if (message.action === "QORTAL_REQUEST_PERMISSION" && isMainWindow) {
|
||||
try {
|
||||
console.log("payloadbefore", message.payload);
|
||||
|
||||
await show('do you accept?');
|
||||
await showQortalRequestExtension(message?.payload);
|
||||
|
||||
sendResponse({ accepted: true });
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
sendResponse({ accepted: false });
|
||||
}
|
||||
}
|
||||
@ -695,7 +714,6 @@ function App() {
|
||||
// Call the permission request handler for "QORTAL_REQUEST_PERMISSION"
|
||||
qortalRequestPermisson(message, sender, sendResponse);
|
||||
if (message.action === "QORTAL_REQUEST_PERMISSION" && !isMainWindow) {
|
||||
console.log("isMainWindow", isMainWindow, window?.location?.href);
|
||||
return true; // Return true to indicate an async response is coming
|
||||
}
|
||||
if (message.action === "QORTAL_REQUEST_PERMISSION" && isMainWindow && message?.isFromExtension) {
|
||||
@ -994,8 +1012,11 @@ function App() {
|
||||
}
|
||||
};
|
||||
|
||||
const logoutFunc = () => {
|
||||
const logoutFunc = async () => {
|
||||
try {
|
||||
if(hasSettingsChanged){
|
||||
await showUnsavedChanges({message: 'Your settings have changed. If you logout you will lose your changes. Click on the save button in the header to keep your changed settings.'})
|
||||
}
|
||||
chrome?.runtime?.sendMessage({ action: "logout" }, (response) => {
|
||||
if (response) {
|
||||
resetAllStates();
|
||||
@ -2762,6 +2783,246 @@ function App() {
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
{isShowUnsavedChanges && (
|
||||
<Dialog
|
||||
open={isShowUnsavedChanges}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{"Warning"}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
{messageUnsavedChanges.message}
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={onCancelUnsavedChanges}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="contained" onClick={onOkUnsavedChanges} autoFocus>
|
||||
Continue to Logout
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
{isShowQortalRequestExtension && isMainWindow && (
|
||||
<Dialog
|
||||
open={isShowQortalRequestExtension}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<CountdownCircleTimer
|
||||
isPlaying
|
||||
duration={30}
|
||||
colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
|
||||
colorsTime={[7, 5, 2, 0]}
|
||||
onComplete={() => {
|
||||
onCancelQortalRequestExtension()
|
||||
}}
|
||||
size={50}
|
||||
strokeWidth={5}
|
||||
>
|
||||
{({ remainingTime }) => <TextP>{remainingTime}</TextP>}
|
||||
</CountdownCircleTimer>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
padding: '20px',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
minHeight: '400px',
|
||||
maxHeight: '90vh',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<TextP
|
||||
sx={{
|
||||
lineHeight: 1.2,
|
||||
maxWidth: "90%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.text1}
|
||||
</TextP>
|
||||
</Box>
|
||||
{messageQortalRequestExtension?.text2 && (
|
||||
<>
|
||||
<Spacer height="10px" />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
width: "90%",
|
||||
}}
|
||||
>
|
||||
<TextP
|
||||
sx={{
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: "normal",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.text2}
|
||||
</TextP>
|
||||
</Box>
|
||||
<Spacer height="15px" />
|
||||
</>
|
||||
)}
|
||||
{messageQortalRequestExtension?.text3 && (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
width: "90%",
|
||||
}}
|
||||
>
|
||||
<TextP
|
||||
sx={{
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: "normal",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.text3}
|
||||
</TextP>
|
||||
<Spacer height="15px" />
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{messageQortalRequestExtension?.text4 && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
width: "90%",
|
||||
}}
|
||||
>
|
||||
<TextP
|
||||
sx={{
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: "normal",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.text4}
|
||||
</TextP>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{messageQortalRequestExtension?.html && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: messageQortalRequestExtension?.html }}
|
||||
/>
|
||||
)}
|
||||
<Spacer height="15px" />
|
||||
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: 700,
|
||||
maxWidth: "90%",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.highlightedText}
|
||||
</TextP>
|
||||
|
||||
{messageQortalRequestExtension?.fee && (
|
||||
<>
|
||||
<Spacer height="15px" />
|
||||
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: "normal",
|
||||
maxWidth: "90%",
|
||||
}}
|
||||
>
|
||||
{'Fee: '}{messageQortalRequestExtension?.fee}{' QORT'}
|
||||
</TextP>
|
||||
<Spacer height="15px" />
|
||||
|
||||
</>
|
||||
)}
|
||||
{messageQortalRequestExtension?.checkbox1 && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "90%",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
onChange={(e) => {
|
||||
qortalRequestCheckbox1Ref.current = e.target.checked;
|
||||
}}
|
||||
edge="start"
|
||||
tabIndex={-1}
|
||||
disableRipple
|
||||
defaultChecked={messageQortalRequestExtension?.checkbox1?.value}
|
||||
sx={{
|
||||
"&.Mui-checked": {
|
||||
color: "white", // Customize the color when checked
|
||||
},
|
||||
"& .MuiSvgIcon-root": {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
}}
|
||||
>
|
||||
{messageQortalRequestExtension?.checkbox1?.label}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Spacer height="29px" />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "14px",
|
||||
}}
|
||||
>
|
||||
<CustomButton
|
||||
sx={{
|
||||
minWidth: "102px",
|
||||
}}
|
||||
onClick={() => onOkQortalRequestExtension("accepted")}
|
||||
>
|
||||
accept
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
sx={{
|
||||
minWidth: "102px",
|
||||
}}
|
||||
onClick={() => onCancelQortalRequestExtension()}
|
||||
>
|
||||
decline
|
||||
</CustomButton>
|
||||
</Box>
|
||||
<ErrorText>{sendPaymentError}</ErrorText>
|
||||
</Box>
|
||||
</Dialog>
|
||||
)}
|
||||
<Popover
|
||||
open={openRegisterName}
|
||||
|
@ -24,4 +24,14 @@ export const settingsLocalLastUpdatedAtom = atom({
|
||||
export const oldPinnedAppsAtom = atom({
|
||||
key: 'oldPinnedAppsAtom',
|
||||
default: [],
|
||||
});
|
||||
|
||||
export const fullScreenAtom = atom({
|
||||
key: 'fullScreenAtom',
|
||||
default: false,
|
||||
});
|
||||
|
||||
export const hasSettingsChangedAtom = atom({
|
||||
key: 'hasSettingsChangedAtom',
|
||||
default: false,
|
||||
});
|
@ -1,8 +1,7 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import React from "react";
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
AppCircleLabel,
|
||||
AppDownloadButton,
|
||||
AppDownloadButtonText,
|
||||
AppInfoAppName,
|
||||
@ -11,10 +10,8 @@ import {
|
||||
AppInfoSnippetMiddle,
|
||||
AppInfoSnippetRight,
|
||||
AppInfoUserName,
|
||||
AppsLibraryContainer,
|
||||
} from "./Apps-styles";
|
||||
import { Avatar, Box, ButtonBase, InputBase } from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { Avatar, ButtonBase } from "@mui/material";
|
||||
import { getBaseApiReact } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
|
||||
@ -22,8 +19,7 @@ import { Spacer } from "../../common/Spacer";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
import { AppRating } from "./AppRating";
|
||||
|
||||
export const AppInfoSnippet = ({ app, myName }) => {
|
||||
|
||||
export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
|
||||
|
||||
const isInstalled = app?.status?.status === 'READY'
|
||||
return (
|
||||
@ -35,6 +31,12 @@ export const AppInfoSnippet = ({ app, myName }) => {
|
||||
width: "60px",
|
||||
}}
|
||||
onClick={()=> {
|
||||
if(isFromCategory){
|
||||
executeEvent("selectedAppInfoCategory", {
|
||||
data: app,
|
||||
});
|
||||
return
|
||||
}
|
||||
executeEvent("selectedAppInfo", {
|
||||
data: app,
|
||||
});
|
||||
@ -73,6 +75,12 @@ export const AppInfoSnippet = ({ app, myName }) => {
|
||||
</ButtonBase>
|
||||
<AppInfoSnippetMiddle>
|
||||
<ButtonBase onClick={()=> {
|
||||
if(isFromCategory){
|
||||
executeEvent("selectedAppInfoCategory", {
|
||||
data: app,
|
||||
});
|
||||
return
|
||||
}
|
||||
executeEvent("selectedAppInfo", {
|
||||
data: app,
|
||||
});
|
||||
@ -91,6 +99,7 @@ export const AppInfoSnippet = ({ app, myName }) => {
|
||||
</AppInfoSnippetLeft>
|
||||
<AppInfoSnippetRight>
|
||||
<AppDownloadButton onClick={()=> {
|
||||
|
||||
executeEvent("addTab", {
|
||||
data: app
|
||||
})
|
||||
|
@ -25,9 +25,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
const [openSnack, setOpenSnack] = useState(false);
|
||||
const [infoSnack, setInfoSnack] = useState(null);
|
||||
const hasCalledRef = useRef(false);
|
||||
console.log(`pollinfo-${app?.service}-${app?.name}`, value);
|
||||
|
||||
console.log("hasPublishedRating", hasPublishedRating);
|
||||
const getRating = useCallback(async (name, service) => {
|
||||
try {
|
||||
hasCalledRef.current = true;
|
||||
@ -42,7 +40,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
});
|
||||
|
||||
const responseData = await response.json();
|
||||
console.log("responseData", responseData);
|
||||
if (responseData?.message?.includes("POLL_NO_EXISTS")) {
|
||||
setHasPublishedRating(false);
|
||||
} else if (responseData?.pollName) {
|
||||
@ -67,14 +64,12 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
const initialValueVote = voteCount.find((vote) =>
|
||||
vote.optionName.startsWith("initialValue-")
|
||||
);
|
||||
console.log("initialValueVote", initialValueVote);
|
||||
if (initialValueVote) {
|
||||
// Convert "initialValue-X" to just "X" and add it to the ratingVotes array
|
||||
const initialRating = parseInt(
|
||||
initialValueVote.optionName.split("-")[1],
|
||||
10
|
||||
);
|
||||
console.log("initialRating", initialRating);
|
||||
ratingVotes.push({
|
||||
optionName: initialRating.toString(),
|
||||
voteCount: 1,
|
||||
@ -91,14 +86,12 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
totalScore += rating * count; // Weighted score
|
||||
totalVotes += count; // Total number of votes
|
||||
});
|
||||
console.log("ratingVotes", ratingVotes, totalScore, totalVotes);
|
||||
|
||||
// Calculate average rating (ensure no division by zero)
|
||||
const averageRating = totalVotes > 0 ? totalScore / totalVotes : 0;
|
||||
setValue(averageRating);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error rating", error);
|
||||
if (error?.message?.includes("POLL_NO_EXISTS")) {
|
||||
setHasPublishedRating(false);
|
||||
}
|
||||
@ -114,7 +107,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
try {
|
||||
if (!myName) throw new Error("You need a name to rate.");
|
||||
if (!app?.name) return;
|
||||
console.log("newValue", newValue);
|
||||
const fee = await getFee("ARBITRARY");
|
||||
|
||||
await show({
|
||||
@ -138,7 +130,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
},
|
||||
},
|
||||
(response) => {
|
||||
console.log("response", response);
|
||||
if (response.error) {
|
||||
rej(response?.message);
|
||||
return;
|
||||
@ -172,7 +163,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
},
|
||||
},
|
||||
(response) => {
|
||||
console.log("response", response);
|
||||
if (response.error) {
|
||||
rej(response?.message);
|
||||
return;
|
||||
@ -197,11 +187,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
|
||||
setOpenSnack(true);
|
||||
}
|
||||
};
|
||||
console.log(
|
||||
"vvotes",
|
||||
(votesInfo?.totalVotes ?? 0) + votesInfo?.voteCounts?.length === 6 ? 1 : 0,
|
||||
votesInfo
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box
|
||||
|
@ -8,17 +8,7 @@ const AppViewerContainer = ({app, isSelected, hide}) => {
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
const frameRef = useRef(null);
|
||||
|
||||
const refreshAppFunc = (e) => {
|
||||
console.log('getting refresh', e)
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// subscribeToEvent("refreshAPp", refreshAppFunc);
|
||||
|
||||
// return () => {
|
||||
// unsubscribeFromEvent("refreshApp", refreshAppFunc);
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<Frame id={`browser-iframe-${app?.tabId}` } ref={frameRef} head={
|
||||
|
@ -2,7 +2,6 @@ import React, { useCallback, useContext, useEffect, useMemo, useRef, useState }
|
||||
import { AppsHome } from "./AppsHome";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { MyContext, getBaseApiReact } from "../../App";
|
||||
import { AppsLibrary } from "./AppsLibrary";
|
||||
import { AppInfo } from "./AppInfo";
|
||||
import {
|
||||
executeEvent,
|
||||
@ -16,12 +15,15 @@ import AppViewerContainer from "./AppViewerContainer";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { AppPublish } from "./AppPublish";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { AppsCategory } from "./AppsCategory";
|
||||
import { AppsLibrary } from "./AppsLibrary";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 8 });
|
||||
|
||||
export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
const [availableQapps, setAvailableQapps] = useState([]);
|
||||
const [selectedAppInfo, setSelectedAppInfo] = useState(null);
|
||||
const [selectedCategory, setSelectedCategory] = useState(null)
|
||||
const [tabs, setTabs] = useState([]);
|
||||
const [selectedTab, setSelectedTab] = useState(null);
|
||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||
@ -85,7 +87,6 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
});
|
||||
if (!response?.ok) return;
|
||||
const responseData = await response.json();
|
||||
console.log('responseData', responseData)
|
||||
const urlWebsites = `${getBaseApiReact()}/arbitrary/resources/search?service=WEBSITE&mode=ALL&limit=0&includestatus=true&includemetadata=true`;
|
||||
|
||||
const responseWebsites = await fetch(urlWebsites, {
|
||||
@ -125,8 +126,44 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const selectedAppInfoCategoryFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
setSelectedAppInfo(data);
|
||||
setMode("appInfo-from-category");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
const selectedCategoryFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
setSelectedCategory(data);
|
||||
setMode("category");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("selectedCategory", selectedCategoryFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("selectedCategory", selectedCategoryFunc);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const navigateBackFunc = (e) => {
|
||||
if (mode === "appInfo") {
|
||||
if(mode === 'category'){
|
||||
setMode("library");
|
||||
setSelectedCategory(null)
|
||||
} else if (mode === "appInfo-from-category") {
|
||||
setMode("category");
|
||||
} else if (mode === "appInfo") {
|
||||
setMode("library");
|
||||
} else if (mode === "library") {
|
||||
if (isNewTabWindow) {
|
||||
@ -139,10 +176,8 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
} else {
|
||||
const iframeId = `browser-iframe-${selectedTab?.tabId}`;
|
||||
const iframe = document.getElementById(iframeId);
|
||||
console.log("iframe", iframe);
|
||||
// Go Back in the iframe's history
|
||||
if (iframe) {
|
||||
console.log(iframe.contentWindow);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
const iframeWindow = iframe.contentWindow;
|
||||
if (iframeWindow && iframeWindow.history) {
|
||||
@ -247,6 +282,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
};
|
||||
}, [tabs]);
|
||||
|
||||
|
||||
return (
|
||||
<AppsParent
|
||||
sx={{
|
||||
@ -264,9 +300,12 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
setMode={setMode}
|
||||
myName={myName}
|
||||
hasPublishApp={!!(myApp || myWebsite)}
|
||||
categories={categories}
|
||||
/>
|
||||
|
||||
{mode === "appInfo" && <AppInfo app={selectedAppInfo} myName={myName} />}
|
||||
{mode === "appInfo-from-category" && <AppInfo app={selectedAppInfo} myName={myName} />}
|
||||
<AppsCategory availableQapps={availableQapps} isShow={mode === 'category' && !selectedTab} category={selectedCategory} myName={myName} />
|
||||
{mode === "publish" && <AppPublish names={myName ? [myName] : []} categories={categories} />}
|
||||
|
||||
{tabs.map((tab) => {
|
||||
@ -282,7 +321,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
{isNewTabWindow && mode === "viewer" && (
|
||||
<>
|
||||
<Spacer height="30px" />
|
||||
<AppsHome availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
|
||||
<AppsHome availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
|
||||
</>
|
||||
)}
|
||||
{mode !== "viewer" && !selectedTab && <Spacer height="180px" />}
|
||||
|
188
src/components/Apps/AppsCategory.tsx
Normal file
188
src/components/Apps/AppsCategory.tsx
Normal file
@ -0,0 +1,188 @@
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
AppCircleLabel,
|
||||
AppLibrarySubTitle,
|
||||
AppsContainer,
|
||||
AppsLibraryContainer,
|
||||
AppsParent,
|
||||
AppsSearchContainer,
|
||||
AppsSearchLeft,
|
||||
AppsSearchRight,
|
||||
AppsWidthLimiter,
|
||||
PublishQAppCTAButton,
|
||||
PublishQAppCTALeft,
|
||||
PublishQAppCTAParent,
|
||||
PublishQAppCTARight,
|
||||
PublishQAppDotsBG,
|
||||
} from "./Apps-styles";
|
||||
import { Avatar, Box, ButtonBase, InputBase, styled } from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { MyContext, getBaseApiReact } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import IconSearch from "../../assets/svgs/Search.svg";
|
||||
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
||||
import qappDots from "../../assets/svgs/qappDots.svg";
|
||||
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { AppInfoSnippet } from "./AppInfoSnippet";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
const officialAppList = [
|
||||
"q-tube",
|
||||
"q-blog",
|
||||
"q-share",
|
||||
"q-support",
|
||||
"q-mail",
|
||||
"qombo",
|
||||
"q-fund",
|
||||
"q-shop",
|
||||
];
|
||||
|
||||
const ScrollerStyled = styled('div')({
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-ms-overflow-style": "none",
|
||||
});
|
||||
|
||||
const StyledVirtuosoContainer = styled('div')({
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-ms-overflow-style": "none",
|
||||
});
|
||||
|
||||
export const AppsCategory = ({ availableQapps, myName, category, isShow }) => {
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const virtuosoRef = useRef();
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
|
||||
|
||||
|
||||
const categoryList = useMemo(() => {
|
||||
return availableQapps.filter(
|
||||
(app) =>
|
||||
app?.metadata?.category === category?.id
|
||||
);
|
||||
}, [availableQapps, category]);
|
||||
|
||||
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
|
||||
|
||||
// Debounce logic
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(searchValue);
|
||||
}, 350);
|
||||
|
||||
// Cleanup timeout if searchValue changes before the timeout completes
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [searchValue]); // Runs effect when searchValue changes
|
||||
|
||||
// Example: Perform search or other actions based on debouncedValue
|
||||
|
||||
const searchedList = useMemo(() => {
|
||||
if (!debouncedValue) return categoryList
|
||||
return categoryList.filter((app) =>
|
||||
app.name.toLowerCase().includes(debouncedValue.toLowerCase())
|
||||
);
|
||||
}, [debouncedValue, categoryList]);
|
||||
|
||||
const rowRenderer = (index) => {
|
||||
|
||||
let app = searchedList[index];
|
||||
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} isFromCategory={true} />;
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<AppsLibraryContainer sx={{
|
||||
display: !isShow && 'none'
|
||||
}}>
|
||||
<AppsWidthLimiter>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<AppsSearchContainer>
|
||||
<AppsSearchLeft>
|
||||
<img src={IconSearch} />
|
||||
<InputBase
|
||||
value={searchValue}
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
sx={{ ml: 1, flex: 1 }}
|
||||
placeholder="Search for apps"
|
||||
inputProps={{
|
||||
"aria-label": "Search for apps",
|
||||
fontSize: "16px",
|
||||
fontWeight: 400,
|
||||
}}
|
||||
/>
|
||||
</AppsSearchLeft>
|
||||
<AppsSearchRight>
|
||||
{searchValue && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setSearchValue("");
|
||||
}}
|
||||
>
|
||||
<img src={IconClearInput} />
|
||||
</ButtonBase>
|
||||
)}
|
||||
</AppsSearchRight>
|
||||
</AppsSearchContainer>
|
||||
</Box>
|
||||
</AppsWidthLimiter>
|
||||
<Spacer height="25px" />
|
||||
<AppsWidthLimiter>
|
||||
<AppLibrarySubTitle>{`Category: ${category?.name}`}</AppLibrarySubTitle>
|
||||
|
||||
<Spacer height="25px" />
|
||||
</AppsWidthLimiter>
|
||||
<AppsWidthLimiter>
|
||||
<StyledVirtuosoContainer sx={{
|
||||
height: rootHeight
|
||||
}}>
|
||||
<Virtuoso
|
||||
ref={virtuosoRef}
|
||||
data={searchedList}
|
||||
itemContent={rowRenderer}
|
||||
atBottomThreshold={50}
|
||||
followOutput="smooth"
|
||||
components={{
|
||||
Scroller: ScrollerStyled // Use the styled scroller component
|
||||
}}
|
||||
/>
|
||||
</StyledVirtuosoContainer>
|
||||
</AppsWidthLimiter>
|
||||
|
||||
</AppsLibraryContainer>
|
||||
);
|
||||
};
|
@ -74,23 +74,11 @@ const ScrollerStyled = styled('div')({
|
||||
"-ms-overflow-style": "none",
|
||||
});
|
||||
|
||||
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow }) => {
|
||||
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories={categories} }) => {
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const virtuosoRef = useRef();
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
const [appStates, setAppStates] = useState({});
|
||||
|
||||
const handleStateChange = (appId, newState) => {
|
||||
setAppStates((prevState) => ({
|
||||
...prevState,
|
||||
[appId]: {
|
||||
...(prevState[appId] || {}), // Preserve existing state for the app
|
||||
...newState, // Merge in the new state properties
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
console.log('appStates', appStates)
|
||||
const officialApps = useMemo(() => {
|
||||
return availableQapps.filter(
|
||||
(app) =>
|
||||
@ -121,12 +109,10 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
app.name.toLowerCase().includes(debouncedValue.toLowerCase())
|
||||
);
|
||||
}, [debouncedValue]);
|
||||
console.log("officialApps", searchedList);
|
||||
|
||||
const rowRenderer = (index) => {
|
||||
|
||||
let app = searchedList[index];
|
||||
console.log('appi', app)
|
||||
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} />;
|
||||
};
|
||||
|
||||
@ -273,6 +259,49 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
|
||||
<Spacer height="18px" />
|
||||
<AppLibrarySubTitle>Categories</AppLibrarySubTitle>
|
||||
<Spacer height="18px" />
|
||||
<AppsWidthLimiter sx={{
|
||||
flexDirection: 'row',
|
||||
overflowX: 'auto',
|
||||
width: '100%',
|
||||
gap: '5px',
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-ms-overflow-style": "none",
|
||||
}}>
|
||||
{categories?.map((category)=> {
|
||||
return (
|
||||
<ButtonBase key={category?.id} onClick={()=> {
|
||||
executeEvent('selectedCategory', {
|
||||
data: category
|
||||
})
|
||||
}}>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '110px',
|
||||
width: '110px',
|
||||
background: 'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
|
||||
color: '#1D1D1E',
|
||||
fontWeight: 700,
|
||||
fontSize: '16px',
|
||||
flexShrink: 0,
|
||||
borderRadius: '11px'
|
||||
}}>
|
||||
{category?.name}
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
)
|
||||
})}
|
||||
</AppsWidthLimiter>
|
||||
</AppsWidthLimiter>
|
||||
</>
|
||||
)}
|
||||
|
@ -41,7 +41,6 @@ export function saveToLocalStorage(key, subKey, newValue) {
|
||||
// Save combined data back to localStorage
|
||||
const serializedValue = JSON.stringify(combinedData);
|
||||
localStorage.setItem(key, serializedValue);
|
||||
console.log(`Data saved to localStorage with key: ${key} and subKey: ${subKey}`);
|
||||
} catch (error) {
|
||||
console.error('Error saving to localStorage:', error);
|
||||
}
|
||||
@ -57,6 +56,7 @@ export const AppsNavBar = () => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||
|
||||
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||
|
||||
const handleClick = (event) => {
|
||||
@ -71,7 +71,6 @@ export const AppsNavBar = () => {
|
||||
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added)
|
||||
if (tabsRef.current) {
|
||||
const tabElements = tabsRef.current.querySelectorAll('.MuiTab-root');
|
||||
console.log('tabElements', tabElements)
|
||||
if (tabElements.length > 0) {
|
||||
const lastTab = tabElements[tabElements.length - 1];
|
||||
lastTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'end' });
|
||||
@ -95,7 +94,6 @@ export const AppsNavBar = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
console.log('selectedTab', selectedTab)
|
||||
|
||||
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === selectedTab?.name && item?.service === selectedTab?.service)
|
||||
return (
|
||||
|
@ -14,7 +14,6 @@ import { ContextMenuPinnedApps } from '../ContextMenuPinnedApps';
|
||||
|
||||
const SortableItem = ({ id, name, app }) => {
|
||||
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
|
||||
console.log('namednd', name)
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
@ -86,7 +85,6 @@ export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) =
|
||||
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||
|
||||
const transformPinnedApps = useMemo(() => {
|
||||
console.log({ myWebsite, myApp, availableQapps, pinnedApps });
|
||||
|
||||
// Clone the existing pinned apps list
|
||||
let pinned = [...pinnedApps];
|
||||
@ -130,27 +128,7 @@ export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) =
|
||||
return pinned;
|
||||
}, [myApp, myWebsite, pinnedApps, availableQapps]);
|
||||
|
||||
console.log('transformPinnedApps', transformPinnedApps)
|
||||
// const hasSetPinned = useRef(false)
|
||||
// useEffect(() => {
|
||||
// if (!apps || apps.length === 0) return;
|
||||
|
||||
// setPinnedApps((prevPinnedApps) => {
|
||||
// // Create a map of the previous pinned apps for easy lookup
|
||||
// const pinnedAppsMap = new Map(prevPinnedApps.map(app => [`${app?.service}-${app?.name}`, app]));
|
||||
|
||||
// // Update the pinnedApps list based on new apps
|
||||
// const updatedPinnedApps = apps.map(app => {
|
||||
// const id = `${app?.service}-${app?.name}`;
|
||||
// // Keep the existing app from pinnedApps if it exists
|
||||
// return pinnedAppsMap.get(id) || app;
|
||||
// });
|
||||
|
||||
// return updatedPinnedApps;
|
||||
// });
|
||||
// }, [apps]);
|
||||
|
||||
console.log('dnd',{pinnedApps})
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: {
|
||||
|
@ -97,7 +97,6 @@ async function handleGetFileFromIndexedDB(fileId, sendResponse) {
|
||||
const deleteRequest = deleteObjectStore.delete(fileId);
|
||||
|
||||
deleteRequest.onsuccess = function () {
|
||||
console.log(`File with ID ${fileId} has been removed from IndexedDB`);
|
||||
try {
|
||||
sendResponse({ result: base64String });
|
||||
|
||||
@ -171,7 +170,6 @@ const UIQortalRequests = [
|
||||
|
||||
async function deleteQortalFilesFromIndexedDB() {
|
||||
try {
|
||||
console.log("Opening IndexedDB for deleting files...");
|
||||
const db = await openIndexedDB();
|
||||
const transaction = db.transaction(["files"], "readwrite");
|
||||
const objectStore = transaction.objectStore("files");
|
||||
@ -262,7 +260,6 @@ const UIQortalRequests = [
|
||||
obj.fileId = fileId;
|
||||
delete obj.file;
|
||||
}
|
||||
console.log(obj, obj.blob instanceof Blob, 'blob')
|
||||
if (obj.blob) {
|
||||
const fileId = "objFile_qortalfile";
|
||||
|
||||
@ -315,7 +312,6 @@ const UIQortalRequests = [
|
||||
export const useQortalMessageListener = (frameWindow) => {
|
||||
const [path, setPath] = useState('')
|
||||
useEffect(() => {
|
||||
console.log("Listener added react");
|
||||
|
||||
const listener = async (event) => {
|
||||
event.preventDefault(); // Prevent default behavior
|
||||
@ -325,7 +321,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
||||
|
||||
const sendMessageToRuntime = (message, eventPort) => {
|
||||
chrome?.runtime?.sendMessage(message, (response) => {
|
||||
console.log('response', response);
|
||||
if (response.error) {
|
||||
eventPort.postMessage({
|
||||
result: null,
|
||||
@ -342,7 +337,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
||||
|
||||
// Check if action is included in the predefined list of UI requests
|
||||
if (UIQortalRequests.includes(event.data.action)) {
|
||||
console.log('event?.data', event?.data);
|
||||
sendMessageToRuntime(
|
||||
{ action: event.data.action, type: 'qortalRequest', payload: event.data, isExtension: true },
|
||||
event.ports[0]
|
||||
@ -353,7 +347,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
||||
event?.data?.action === 'ENCRYPT_DATA' || event?.data?.action === 'SAVE_FILE'
|
||||
|
||||
) {
|
||||
console.log('event?.data?', event?.data);
|
||||
let data;
|
||||
try {
|
||||
data = await storeFilesInIndexedDB(event.data);
|
||||
@ -365,7 +358,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log('data after', data)
|
||||
if (data) {
|
||||
sendMessageToRuntime(
|
||||
{ action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true },
|
||||
@ -396,7 +388,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
||||
}, []); // Empty dependency array to run once when the component mounts
|
||||
|
||||
chrome.runtime?.onMessage.addListener( function (message, sender, sendResponse) {
|
||||
console.log('SHOWING UP')
|
||||
if(message.action === "SHOW_SAVE_FILE_PICKER"){
|
||||
showSaveFilePicker(message?.data)
|
||||
}
|
||||
|
@ -127,7 +127,6 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
|
||||
const forceCloseWebSocket = () => {
|
||||
if (socketRef.current) {
|
||||
console.log('Force closing the WebSocket');
|
||||
clearTimeout(timeoutIdRef.current);
|
||||
clearTimeout(groupSocketTimeoutRef.current);
|
||||
socketRef.current.close(1000, 'forced');
|
||||
@ -161,7 +160,6 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
socketRef.current = new WebSocket(socketLink);
|
||||
|
||||
socketRef.current.onopen = () => {
|
||||
console.log('WebSocket connection opened');
|
||||
setTimeout(pingWebSocket, 50); // Initial ping
|
||||
};
|
||||
|
||||
|
@ -824,98 +824,7 @@ export const Group = ({
|
||||
}
|
||||
}, [selectedGroup]);
|
||||
|
||||
// const handleNotification = async (data)=> {
|
||||
// try {
|
||||
// if(isFocusedRef.current){
|
||||
// throw new Error('isFocused')
|
||||
// }
|
||||
// const newActiveChats= data
|
||||
// const oldActiveChats = await new Promise((res, rej) => {
|
||||
// chrome?.runtime?.sendMessage(
|
||||
// {
|
||||
// action: "getChatHeads",
|
||||
// },
|
||||
// (response) => {
|
||||
// console.log({ response });
|
||||
// if (!response?.error) {
|
||||
// res(response);
|
||||
// }
|
||||
// rej(response.error);
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
|
||||
// let results = []
|
||||
// newActiveChats?.groups?.forEach(newChat => {
|
||||
// let isNewer = true;
|
||||
// oldActiveChats?.data?.groups?.forEach(oldChat => {
|
||||
// if (newChat?.timestamp <= oldChat?.timestamp) {
|
||||
// isNewer = false;
|
||||
// }
|
||||
// });
|
||||
// if (isNewer) {
|
||||
// results.push(newChat)
|
||||
// console.log('This newChat is newer than all oldChats:', newChat);
|
||||
// }
|
||||
// });
|
||||
|
||||
// if(results?.length > 0){
|
||||
// if (!lastGroupNotification.current || (Date.now() - lastGroupNotification.current >= 60000)) {
|
||||
// console.log((Date.now() - lastGroupNotification.current >= 60000), lastGroupNotification.current)
|
||||
// chrome?.runtime?.sendMessage(
|
||||
// {
|
||||
// action: "notification",
|
||||
// payload: {
|
||||
// },
|
||||
// },
|
||||
// (response) => {
|
||||
// console.log({ response });
|
||||
// if (!response?.error) {
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
// );
|
||||
// audio.play();
|
||||
// lastGroupNotification.current = Date.now()
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// } catch (error) {
|
||||
// console.log('error not', error)
|
||||
// if(!isFocusedRef.current){
|
||||
// chrome?.runtime?.sendMessage(
|
||||
// {
|
||||
// action: "notification",
|
||||
// payload: {
|
||||
// },
|
||||
// },
|
||||
// (response) => {
|
||||
// console.log({ response });
|
||||
// if (!response?.error) {
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
// );
|
||||
// audio.play();
|
||||
// lastGroupNotification.current = Date.now()
|
||||
// }
|
||||
|
||||
// } finally {
|
||||
|
||||
// chrome?.runtime?.sendMessage(
|
||||
// {
|
||||
// action: "setChatHeads",
|
||||
// payload: {
|
||||
// data,
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
const getAdmins = async (groupId) => {
|
||||
try {
|
||||
|
@ -48,20 +48,7 @@ export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, get
|
||||
return true
|
||||
})
|
||||
|
||||
// const getJoinGroupRequests = groupsAsAdmin.map(async (group)=> {
|
||||
// console.log('getJoinGroupRequests', group)
|
||||
// const joinRequestResponse = await requestQueueGroupJoinRequests.enqueue(()=> {
|
||||
// return fetch(
|
||||
// `${getBaseApiReact()}/groups/joinrequests/${group.groupId}`
|
||||
// );
|
||||
// })
|
||||
|
||||
// const joinRequestData = await joinRequestResponse.json()
|
||||
// return {
|
||||
// group,
|
||||
// data: joinRequestData
|
||||
// }
|
||||
// })
|
||||
|
||||
await Promise.all(getAllGroupsAsAdmin)
|
||||
const res = await Promise.all(groupsAsAdmin.map(async (group)=> {
|
||||
|
||||
|
@ -20,6 +20,10 @@ import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
|
||||
import { MessagingIcon2 } from "../../assets/Icons/MessagingIcon2";
|
||||
import { HubsIcon } from "../../assets/Icons/HubsIcon";
|
||||
import { Save } from "../Save/Save";
|
||||
import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen';
|
||||
import { useRecoilState } from "recoil";
|
||||
import { fullScreenAtom, hasSettingsChangedAtom } from "../../atoms/global";
|
||||
import { useAppFullScreen } from "../../useAppFullscreen";
|
||||
|
||||
const Header = ({
|
||||
logoutFunc,
|
||||
@ -33,16 +37,11 @@ const Header = ({
|
||||
myName,
|
||||
setSelectedDirect,
|
||||
setNewChat
|
||||
// selectedGroup,
|
||||
// onHomeClick,
|
||||
// onLogoutClick,
|
||||
// onGroupChange,
|
||||
// onWalletClick,
|
||||
// onNotificationClick,
|
||||
}) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
|
||||
const {exitFullScreen} = useAppFullScreen(setFullScreen)
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
@ -77,10 +76,10 @@ const Header = ({
|
||||
width: "75px",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
edge="start"
|
||||
color="inherit"
|
||||
aria-label="home"
|
||||
<ButtonBase
|
||||
|
||||
|
||||
|
||||
onClick={() => {
|
||||
setMobileViewModeKeepOpen("");
|
||||
goToHome();
|
||||
@ -88,15 +87,24 @@ const Header = ({
|
||||
// onClick={onHomeClick}
|
||||
>
|
||||
<HomeIcon height={20} width={27} color="rgba(145, 145, 147, 1)" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
edge="start"
|
||||
color="inherit"
|
||||
aria-label="home"
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
|
||||
onClick={handleClick}
|
||||
>
|
||||
<NotificationIcon height={20} width={21} color={hasUnreadDirects || hasUnreadGroups ? "var(--unread)" : "rgba(145, 145, 147, 1)"} />
|
||||
</IconButton>
|
||||
</ButtonBase>
|
||||
{fullScreen && (
|
||||
<ButtonBase onClick={()=> {
|
||||
exitFullScreen()
|
||||
setFullScreen(false)
|
||||
}}>
|
||||
<CloseFullscreenIcon sx={{
|
||||
color: 'rgba(145, 145, 147, 1)'
|
||||
}} />
|
||||
</ButtonBase>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
|
||||
{/* Center Title */}
|
||||
@ -254,6 +262,16 @@ const Header = ({
|
||||
>
|
||||
<HomeIcon color="rgba(145, 145, 147, 1)" />
|
||||
</ButtonBase>
|
||||
{fullScreen && (
|
||||
<ButtonBase onClick={()=> {
|
||||
exitFullScreen()
|
||||
setFullScreen(false)
|
||||
}}>
|
||||
<CloseFullscreenIcon sx={{
|
||||
color: 'rgba(145, 145, 147, 1)'
|
||||
}} />
|
||||
</ButtonBase>
|
||||
)}
|
||||
</Box>
|
||||
{/* Center Title */}
|
||||
<Typography
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useContext, useMemo, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil';
|
||||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import isEqual from 'lodash/isEqual'; // Import deep comparison utility
|
||||
import { canSaveSettingToQdnAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
|
||||
import { canSaveSettingToQdnAtom, hasSettingsChangedAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
|
||||
import { ButtonBase } from '@mui/material';
|
||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||
import { MyContext } from '../../App';
|
||||
@ -12,13 +12,14 @@ export const Save = () => {
|
||||
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||
const [settingsQdnLastUpdated, setSettingsQdnLastUpdated] = useRecoilState(settingsQDNLastUpdatedAtom);
|
||||
const [settingsLocalLastUpdated] = useRecoilState(settingsLocalLastUpdatedAtom);
|
||||
const setHasSettingsChangedAtom = useSetRecoilState(hasSettingsChangedAtom);
|
||||
|
||||
const [canSave] = useRecoilState(canSaveSettingToQdnAtom);
|
||||
const [openSnack, setOpenSnack] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [infoSnack, setInfoSnack] = useState(null);
|
||||
const [oldPinnedApps, setOldPinnedApps] = useRecoilState(oldPinnedAppsAtom)
|
||||
console.log('oldpin', {oldPinnedApps, pinnedApps}, settingsQdnLastUpdated, settingsLocalLastUpdated, settingsQdnLastUpdated < settingsLocalLastUpdated,)
|
||||
|
||||
const { show } = useContext(MyContext);
|
||||
|
||||
const hasChanged = useMemo(()=> {
|
||||
@ -38,11 +39,14 @@ export const Save = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log('!isEqual(oldChanges, newChanges)', !isEqual(oldChanges, newChanges))
|
||||
if(settingsQdnLastUpdated === -100) return false
|
||||
return !isEqual(oldChanges, newChanges) && settingsQdnLastUpdated < settingsLocalLastUpdated
|
||||
}, [oldPinnedApps, pinnedApps, settingsQdnLastUpdated, settingsLocalLastUpdated])
|
||||
|
||||
useEffect(()=> {
|
||||
setHasSettingsChangedAtom(hasChanged)
|
||||
}, [hasChanged])
|
||||
|
||||
const saveToQdn = async ()=> {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
@ -64,7 +68,6 @@ export const Save = () => {
|
||||
},
|
||||
},
|
||||
(response) => {
|
||||
console.log("response", response);
|
||||
if (response.error) {
|
||||
rej(response?.message);
|
||||
return;
|
||||
@ -102,7 +105,6 @@ export const Save = () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
console.log('saved', response)
|
||||
if(response?.identifier){
|
||||
setOldPinnedApps(pinnedApps)
|
||||
setSettingsQdnLastUpdated(Date.now())
|
||||
@ -114,7 +116,6 @@ export const Save = () => {
|
||||
setOpenSnack(true);
|
||||
}
|
||||
}
|
||||
console.log('save encryptedData', encryptData)
|
||||
} catch (error) {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
@ -126,7 +127,6 @@ export const Save = () => {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
console.log('settingsQdnLastUpdated', settingsQdnLastUpdated)
|
||||
return (
|
||||
<>
|
||||
<ButtonBase onClick={saveToQdn} disabled={!hasChanged || !canSave || isLoading || settingsQdnLastUpdated === -100}>
|
||||
|
@ -319,7 +319,6 @@ export const decodeBase64ForUIChatMessages = (messages)=> {
|
||||
if (decryptedKey) {
|
||||
// Decrypt the data using the symmetric key.
|
||||
const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey)
|
||||
console.log('decryptedData', decryptedData)
|
||||
// If decryption was successful, decryptedData will not be null.
|
||||
if (decryptedData) {
|
||||
return decryptedData
|
||||
|
@ -61,25 +61,7 @@ export const publishData = async ({
|
||||
tag5,
|
||||
feeAmount
|
||||
}: any) => {
|
||||
console.log({
|
||||
registeredName,
|
||||
file,
|
||||
service,
|
||||
identifier,
|
||||
uploadType,
|
||||
isBase64,
|
||||
filename,
|
||||
withFee,
|
||||
title,
|
||||
description,
|
||||
category,
|
||||
tag1,
|
||||
tag2,
|
||||
tag3,
|
||||
tag4,
|
||||
tag5,
|
||||
feeAmount
|
||||
})
|
||||
|
||||
const validateName = async (receiverName: string) => {
|
||||
return await reusableGet(`/names/${receiverName}`)
|
||||
}
|
||||
@ -171,7 +153,6 @@ export const publishData = async ({
|
||||
fee = feeAmount
|
||||
} else if (withFee) {
|
||||
const res = await getArbitraryFee()
|
||||
console.log('res', res)
|
||||
if (res.fee) {
|
||||
fee = res.fee
|
||||
} else {
|
||||
@ -180,7 +161,6 @@ export const publishData = async ({
|
||||
}
|
||||
|
||||
let transactionBytes = await uploadData(registeredName, file, fee)
|
||||
console.log('transactionBytes', transactionBytes)
|
||||
if (!transactionBytes || transactionBytes.error) {
|
||||
throw new Error(transactionBytes?.message || 'Error when uploading')
|
||||
} else if (transactionBytes.includes('Error 500 Internal Server Error')) {
|
||||
@ -201,7 +181,6 @@ export const publishData = async ({
|
||||
}
|
||||
|
||||
const uploadData = async (registeredName: string, file:any, fee: number) => {
|
||||
console.log('uploadData', registeredName, file, fee)
|
||||
|
||||
let postBody = ''
|
||||
let urlSuffix = ''
|
||||
@ -230,7 +209,6 @@ export const publishData = async ({
|
||||
}
|
||||
|
||||
let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}`
|
||||
console.log('uploadDataUrl', uploadDataUrl)
|
||||
if (identifier?.trim().length > 0) {
|
||||
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${identifier}${urlSuffix}`
|
||||
}
|
||||
@ -273,7 +251,6 @@ export const publishData = async ({
|
||||
if (tag5 != null && tag5 != 'undefined') {
|
||||
uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag5)
|
||||
}
|
||||
console.log('uploadDataUrl2', uploadDataUrl)
|
||||
|
||||
return await reusablePost(uploadDataUrl, postBody)
|
||||
|
||||
@ -282,7 +259,6 @@ export const publishData = async ({
|
||||
try {
|
||||
return await validate()
|
||||
} catch (error: any) {
|
||||
console.log('error2', error)
|
||||
throw new Error(error?.message)
|
||||
}
|
||||
}
|
@ -63,7 +63,6 @@ function getLocalStorage(key) {
|
||||
|
||||
chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request) {
|
||||
console.log('rquest', request)
|
||||
const isFromExtension = request?.isExtension
|
||||
switch (request.action) {
|
||||
case "GET_USER_ACCOUNT": {
|
||||
@ -106,7 +105,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "GET_LIST_ITEMS": {
|
||||
const data = request.payload;
|
||||
|
||||
getListItems(data)
|
||||
getListItems(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -119,7 +118,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "ADD_LIST_ITEMS": {
|
||||
const data = request.payload;
|
||||
|
||||
addListItems(data)
|
||||
addListItems(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -132,7 +131,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "DELETE_LIST_ITEM": {
|
||||
const data = request.payload;
|
||||
|
||||
deleteListItems(data)
|
||||
deleteListItems(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -145,7 +144,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "PUBLISH_QDN_RESOURCE": {
|
||||
const data = request.payload;
|
||||
|
||||
publishQDNResource(data, sender)
|
||||
publishQDNResource(data, sender, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -158,7 +157,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "PUBLISH_MULTIPLE_QDN_RESOURCES": {
|
||||
const data = request.payload;
|
||||
|
||||
publishMultipleQDNResources(data, sender)
|
||||
publishMultipleQDNResources(data, sender, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -184,7 +183,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "CREATE_POLL": {
|
||||
const data = request.payload;
|
||||
|
||||
createPoll(data)
|
||||
createPoll(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -196,8 +195,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
}
|
||||
case "SEND_CHAT_MESSAGE": {
|
||||
const data = request.payload;
|
||||
console.log('data', data)
|
||||
sendChatMessage(data)
|
||||
sendChatMessage(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -210,7 +208,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "JOIN_GROUP": {
|
||||
const data = request.payload;
|
||||
|
||||
joinGroup(data)
|
||||
joinGroup(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -223,7 +221,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "SAVE_FILE": {
|
||||
const data = request.payload;
|
||||
|
||||
saveFile(data, sender)
|
||||
saveFile(data, sender, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -236,7 +234,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "DEPLOY_AT": {
|
||||
const data = request.payload;
|
||||
|
||||
deployAt(data)
|
||||
deployAt(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -249,7 +247,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "GET_USER_WALLET": {
|
||||
const data = request.payload;
|
||||
|
||||
getUserWallet(data)
|
||||
getUserWallet(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -262,7 +260,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "GET_WALLET_BALANCE": {
|
||||
const data = request.payload;
|
||||
|
||||
getWalletBalance(data)
|
||||
getWalletBalance(data, false, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -276,7 +274,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "GET_USER_WALLET_INFO": {
|
||||
const data = request.payload;
|
||||
|
||||
getUserWalletInfo(data)
|
||||
getUserWalletInfo(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
@ -414,7 +412,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
||||
case "SEND_COIN": {
|
||||
const data = request.payload;
|
||||
|
||||
sendCoin(data)
|
||||
sendCoin(data, isFromExtension)
|
||||
.then((res) => {
|
||||
sendResponse(res);
|
||||
})
|
||||
|
@ -38,7 +38,7 @@ const dgbFeePerByte = 0.00000010
|
||||
const rvnFeePerByte = 0.00001125
|
||||
|
||||
|
||||
const _createPoll = async (pollName, pollDescription, options) => {
|
||||
const _createPoll = async ({pollName, pollDescription, options}, isFromExtension) => {
|
||||
const fee = await getFee("CREATE_POLL");
|
||||
|
||||
const resPermission = await getUserPermission({
|
||||
@ -47,7 +47,7 @@ const _createPoll = async (pollName, pollDescription, options) => {
|
||||
text3: `Description: ${pollDescription}`,
|
||||
text4: `Options: ${options?.join(", ")}`,
|
||||
fee: fee.fee,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -82,13 +82,13 @@ const _createPoll = async (pollName, pollDescription, options) => {
|
||||
};
|
||||
|
||||
const _deployAt = async (
|
||||
name,
|
||||
{name,
|
||||
description,
|
||||
tags,
|
||||
creationBytes,
|
||||
amount,
|
||||
assetId,
|
||||
atType
|
||||
atType}, isFromExtension
|
||||
) => {
|
||||
const fee = await getFee("DEPLOY_AT");
|
||||
|
||||
@ -97,7 +97,7 @@ const _deployAt = async (
|
||||
text2: `Name: ${name}`,
|
||||
text3: `Description: ${description}`,
|
||||
fee: fee.fee,
|
||||
});
|
||||
}, isFromExtension);
|
||||
|
||||
const { accepted } = resPermission;
|
||||
|
||||
@ -172,7 +172,6 @@ const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension)
|
||||
});
|
||||
const signedBytes = Base58.encode(tx.signedBytes);
|
||||
const res = await processTransactionVersion2(signedBytes);
|
||||
console.log('res', res)
|
||||
if (!res?.signature)
|
||||
throw new Error(res?.message || "Transaction was not able to be processed");
|
||||
return res;
|
||||
@ -182,13 +181,11 @@ const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension)
|
||||
};
|
||||
|
||||
function getFileFromContentScript(fileId, sender) {
|
||||
console.log("sender", sender);
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.tabs.sendMessage(
|
||||
sender.tab.id,
|
||||
{ action: "getFileFromIndexedDB", fileId: fileId },
|
||||
(response) => {
|
||||
console.log("response2", response);
|
||||
if (response && response.result) {
|
||||
resolve(response.result);
|
||||
} else {
|
||||
@ -199,7 +196,6 @@ function getFileFromContentScript(fileId, sender) {
|
||||
});
|
||||
}
|
||||
function sendToSaveFilePicker(data, sender) {
|
||||
console.log("sender", sender);
|
||||
|
||||
chrome.tabs.sendMessage(sender.tab.id, {
|
||||
action: "SHOW_SAVE_FILE_PICKER",
|
||||
@ -239,7 +235,6 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('isFromExtension', isFromExtension)
|
||||
if(isFromExtension){
|
||||
|
||||
|
||||
@ -253,7 +248,6 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
|
||||
chrome.runtime.sendMessage(
|
||||
{ action: "QORTAL_REQUEST_PERMISSION", payload, isFromExtension },
|
||||
(response) => {
|
||||
console.log("permission response", response);
|
||||
if (response === undefined) return;
|
||||
clearTimeout(timeout); // Clear the timeout if we get a response
|
||||
|
||||
@ -268,11 +262,9 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
|
||||
}
|
||||
await new Promise((res) => {
|
||||
const popupUrl = chrome.runtime.getURL("index.html?secondary=true");
|
||||
console.log("popupUrl", popupUrl);
|
||||
chrome.windows.getAll(
|
||||
{ populate: true, windowTypes: ["popup"] },
|
||||
(windows) => {
|
||||
console.log("windows", windows);
|
||||
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||
const existingPopup = windows.find(
|
||||
(w) =>
|
||||
@ -340,11 +332,9 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
|
||||
}, 30000);
|
||||
|
||||
// Send message to the content script to check focus
|
||||
console.log("send msg");
|
||||
chrome.runtime.sendMessage(
|
||||
{ action: "QORTAL_REQUEST_PERMISSION", payload },
|
||||
(response) => {
|
||||
console.log("permission response", response);
|
||||
if (response === undefined) return;
|
||||
clearTimeout(timeout); // Clear the timeout if we get a response
|
||||
|
||||
@ -386,7 +376,6 @@ export const encryptData = async (data, sender) => {
|
||||
const parsedData = JSON.parse(resKeyPair);
|
||||
const privateKey = parsedData.privateKey;
|
||||
const userPublicKey = parsedData.publicKey;
|
||||
console.log('data', data)
|
||||
|
||||
const encryptDataResponse = encryptDataGroup({
|
||||
data64,
|
||||
@ -441,7 +430,7 @@ export const decryptData = async (data) => {
|
||||
throw new Error("Unable to decrypt");
|
||||
};
|
||||
|
||||
export const getListItems = async (data) => {
|
||||
export const getListItems = async (data, isFromExtension) => {
|
||||
const localNodeAvailable = await isUsingLocal()
|
||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
||||
const requiredFields = ["list_name"];
|
||||
@ -474,7 +463,7 @@ export const getListItems = async (data) => {
|
||||
value: value,
|
||||
label: "Always allow lists to be retrieved automatically",
|
||||
},
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted, checkbox1 } = resPermission;
|
||||
acceptedVar = accepted;
|
||||
checkbox1Var = checkbox1;
|
||||
@ -483,20 +472,17 @@ export const getListItems = async (data) => {
|
||||
|
||||
if (acceptedVar || skip) {
|
||||
const url = await createEndpoint(`/lists/${data.list_name}`);
|
||||
console.log("url", url);
|
||||
const response = await fetch(url);
|
||||
console.log("response", response);
|
||||
if (!response.ok) throw new Error("Failed to fetch");
|
||||
|
||||
const list = await response.json();
|
||||
console.log("list", list);
|
||||
return list;
|
||||
} else {
|
||||
throw new Error("User declined to share list");
|
||||
}
|
||||
};
|
||||
|
||||
export const addListItems = async (data) => {
|
||||
export const addListItems = async (data, isFromExtension) => {
|
||||
const localNodeAvailable = await isUsingLocal()
|
||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
||||
const requiredFields = ["list_name", "items"];
|
||||
@ -519,12 +505,11 @@ export const addListItems = async (data) => {
|
||||
text1: "Do you give this application permission to",
|
||||
text2: `Add the following to the list ${list_name}:`,
|
||||
highlightedText: items.join(", "),
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
const url = await createEndpoint(`/lists/${list_name}`);
|
||||
console.log("url", url);
|
||||
const body = {
|
||||
items: items,
|
||||
};
|
||||
@ -537,7 +522,6 @@ export const addListItems = async (data) => {
|
||||
body: bodyToString,
|
||||
});
|
||||
|
||||
console.log("response", response);
|
||||
if (!response.ok) throw new Error("Failed to add to list");
|
||||
let res;
|
||||
try {
|
||||
@ -551,7 +535,7 @@ export const addListItems = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteListItems = async (data) => {
|
||||
export const deleteListItems = async (data, isFromExtension) => {
|
||||
const localNodeAvailable = await isUsingLocal()
|
||||
if(!localNodeAvailable) throw new Error('Please use your local node.')
|
||||
const requiredFields = ["list_name", "item"];
|
||||
@ -574,12 +558,11 @@ export const deleteListItems = async (data) => {
|
||||
text1: "Do you give this application permission to",
|
||||
text2: `Remove the following from the list ${list_name}:`,
|
||||
highlightedText: item,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
const url = await createEndpoint(`/lists/${list_name}`);
|
||||
console.log("url", url);
|
||||
const body = {
|
||||
items: [item],
|
||||
};
|
||||
@ -592,7 +575,6 @@ export const deleteListItems = async (data) => {
|
||||
body: bodyToString,
|
||||
});
|
||||
|
||||
console.log("response", response);
|
||||
if (!response.ok) throw new Error("Failed to add to list");
|
||||
let res;
|
||||
try {
|
||||
@ -606,7 +588,7 @@ export const deleteListItems = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const publishQDNResource = async (data: any, sender) => {
|
||||
export const publishQDNResource = async (data: any, sender, isFromExtension) => {
|
||||
const requiredFields = ["service"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -683,7 +665,7 @@ export const publishQDNResource = async (data: any, sender) => {
|
||||
text3: `identifier: ${identifier || null}`,
|
||||
highlightedText: `isEncrypted: ${!!data.encrypt}`,
|
||||
fee: fee.fee,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
if (accepted) {
|
||||
if (data.fileId && !data.encrypt) {
|
||||
@ -718,7 +700,7 @@ export const publishQDNResource = async (data: any, sender) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const publishMultipleQDNResources = async (data: any, sender) => {
|
||||
export const publishMultipleQDNResources = async (data: any, sender, isFromExtension) => {
|
||||
const requiredFields = ["resources"];
|
||||
const missingFields: string[] = [];
|
||||
let feeAmount = null;
|
||||
@ -815,14 +797,12 @@ export const publishMultipleQDNResources = async (data: any, sender) => {
|
||||
`,
|
||||
highlightedText: `isEncrypted: ${!!data.encrypt}`,
|
||||
fee: fee.fee * resources.length,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
console.log("accepted", accepted);
|
||||
if (!accepted) {
|
||||
throw new Error("User declined request");
|
||||
}
|
||||
let failedPublishesIdentifiers = [];
|
||||
console.log("resources", resources);
|
||||
for (const resource of resources) {
|
||||
try {
|
||||
const requiredFields = ["service"];
|
||||
@ -934,7 +914,6 @@ export const publishMultipleQDNResources = async (data: any, sender) => {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
failedPublishesIdentifiers.push({
|
||||
reason: "Unknown error",
|
||||
identifier: resource.identifier,
|
||||
@ -990,7 +969,7 @@ export const voteOnPoll = async (data, isFromExtension) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const createPoll = async (data) => {
|
||||
export const createPoll = async (data, isFromExtension) => {
|
||||
const requiredFields = [
|
||||
"pollName",
|
||||
"pollDescription",
|
||||
@ -1014,10 +993,12 @@ export const createPoll = async (data) => {
|
||||
const pollOwnerAddress = data.pollOwnerAddress;
|
||||
try {
|
||||
const resCreatePoll = await _createPoll(
|
||||
pollName,
|
||||
{
|
||||
pollName,
|
||||
pollDescription,
|
||||
pollOptions,
|
||||
pollOwnerAddress
|
||||
options: pollOptions,
|
||||
},
|
||||
isFromExtension
|
||||
);
|
||||
return resCreatePoll;
|
||||
} catch (error) {
|
||||
@ -1025,7 +1006,7 @@ export const createPoll = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const sendChatMessage = async (data) => {
|
||||
export const sendChatMessage = async (data, isFromExtension) => {
|
||||
const message = data.message;
|
||||
const recipient = data.destinationAddress;
|
||||
const groupId = data.groupId;
|
||||
@ -1034,7 +1015,7 @@ export const sendChatMessage = async (data) => {
|
||||
text1: "Do you give this application permission to send this chat message?",
|
||||
text2: `To: ${isRecipient ? recipient : `group ${groupId}`}`,
|
||||
text3: `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`,
|
||||
});
|
||||
}, isFromExtension);
|
||||
|
||||
const { accepted } = resPermission;
|
||||
if (accepted) {
|
||||
@ -1058,11 +1039,7 @@ export const sendChatMessage = async (data) => {
|
||||
repliedTo: "",
|
||||
version: 3,
|
||||
};
|
||||
try {
|
||||
JSON.stringify(messageObject);
|
||||
} catch (error) {
|
||||
console.log("my error", error);
|
||||
}
|
||||
|
||||
const stringifyMessageObject = JSON.stringify(messageObject);
|
||||
|
||||
const balance = await getBalanceInfo();
|
||||
@ -1088,7 +1065,6 @@ export const sendChatMessage = async (data) => {
|
||||
// Otherwise, treat it as plain text
|
||||
res = await response.text();
|
||||
}
|
||||
console.log("res", res);
|
||||
if (res?.error === 102) {
|
||||
key = "";
|
||||
hasPublicKey = false;
|
||||
@ -1198,7 +1174,7 @@ export const sendChatMessage = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const joinGroup = async (data) => {
|
||||
export const joinGroup = async (data, isFromExtension) => {
|
||||
const requiredFields = ["groupId"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -1228,7 +1204,7 @@ export const joinGroup = async (data) => {
|
||||
text1: "Confirm joining the group:",
|
||||
highlightedText: `${groupInfo.groupName}`,
|
||||
fee: fee.fee,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -1249,9 +1225,8 @@ export const joinGroup = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const saveFile = async (data, sender) => {
|
||||
export const saveFile = async (data, sender, isFromExtension) => {
|
||||
try {
|
||||
console.log('save file', data)
|
||||
const requiredFields = ["filename", "fileId"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -1270,7 +1245,7 @@ export const saveFile = async (data, sender) => {
|
||||
const resPermission = await getUserPermission({
|
||||
text1: "Would you like to download:",
|
||||
highlightedText: `${filename}`,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -1314,7 +1289,7 @@ export const saveFile = async (data, sender) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const deployAt = async (data) => {
|
||||
export const deployAt = async (data, isFromExtension) => {
|
||||
const requiredFields = [
|
||||
"name",
|
||||
"description",
|
||||
@ -1337,13 +1312,16 @@ export const deployAt = async (data) => {
|
||||
}
|
||||
try {
|
||||
const resDeployAt = await _deployAt(
|
||||
data.name,
|
||||
data.description,
|
||||
data.tags,
|
||||
data.creationBytes,
|
||||
data.amount,
|
||||
data.assetId,
|
||||
data.type
|
||||
{
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
tags: data.tags,
|
||||
creationBytes: data.creationBytes,
|
||||
amount: data.amount,
|
||||
assetId: data.assetId,
|
||||
atType: data.type
|
||||
},
|
||||
isFromExtension
|
||||
);
|
||||
return resDeployAt;
|
||||
} catch (error) {
|
||||
@ -1351,7 +1329,7 @@ export const deployAt = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserWallet = async (data) => {
|
||||
export const getUserWallet = async (data, isFromExtension) => {
|
||||
const requiredFields = ["coin"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -1367,7 +1345,7 @@ export const getUserWallet = async (data) => {
|
||||
const resPermission = await getUserPermission({
|
||||
text1:
|
||||
"Do you give this application permission to get your wallet information?",
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -1437,7 +1415,7 @@ export const getUserWallet = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getWalletBalance = async (data, bypassPermission?: boolean) => {
|
||||
export const getWalletBalance = async (data, bypassPermission?: boolean, isFromExtension) => {
|
||||
const requiredFields = ["coin"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -1456,7 +1434,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean) => {
|
||||
resPermission = await getUserPermission({
|
||||
text1: "Do you give this application permission to fetch your",
|
||||
highlightedText: `${data.coin} balance`,
|
||||
});
|
||||
}, isFromExtension);
|
||||
} else {
|
||||
resPermission = {
|
||||
accepted: false
|
||||
@ -1558,7 +1536,6 @@ const getUserWalletFunc = async (coin) => {
|
||||
const address = wallet.address0;
|
||||
const resKeyPair = await getKeyPair();
|
||||
const parsedData = JSON.parse(resKeyPair);
|
||||
console.log('coin', coin)
|
||||
switch (coin) {
|
||||
case "QORT":
|
||||
userWallet["address"] = address;
|
||||
@ -1592,7 +1569,7 @@ const getUserWalletFunc = async (coin) => {
|
||||
return userWallet;
|
||||
};
|
||||
|
||||
export const getUserWalletInfo = async (data) => {
|
||||
export const getUserWalletInfo = async (data, isFromExtension) => {
|
||||
const requiredFields = ["coin"];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -1607,14 +1584,12 @@ export const getUserWalletInfo = async (data) => {
|
||||
}
|
||||
const resPermission = await getUserPermission({
|
||||
text1: "Do you give this application permission to retrieve your wallet information",
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
let coin = data.coin;
|
||||
let walletKeys = await getUserWalletFunc(coin);
|
||||
console.log('walletKeys', walletKeys)
|
||||
console.log('walletKeys["publickey"]', walletKeys["publickey"])
|
||||
const _url = await createEndpoint(
|
||||
`/crosschain/` + data.coin.toLowerCase() + `/addressinfos`
|
||||
);
|
||||
@ -2076,7 +2051,7 @@ export const getTxActivitySummary = async (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const sendCoin = async (data) => {
|
||||
export const sendCoin = async (data, isFromExtension) => {
|
||||
const requiredFields = ['coin', 'destinationAddress', 'amount']
|
||||
const missingFields: string[] = []
|
||||
requiredFields.forEach((field) => {
|
||||
@ -2105,9 +2080,7 @@ export const sendCoin = async (data) => {
|
||||
const recipient = data.destinationAddress
|
||||
|
||||
const url = await createEndpoint(`/addresses/balance/${address}`);
|
||||
console.log("url", url);
|
||||
const response = await fetch(url);
|
||||
console.log("response", response);
|
||||
if (!response.ok) throw new Error("Failed to fetch");
|
||||
let walletBalance;
|
||||
try {
|
||||
@ -2141,7 +2114,7 @@ export const sendCoin = async (data) => {
|
||||
text1: "Do you give this application permission to send coins?",
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2174,7 +2147,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2231,7 +2204,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2288,7 +2261,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2343,7 +2316,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2401,7 +2374,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
@ -2455,7 +2428,7 @@ export const sendCoin = async (data) => {
|
||||
text2: `To: ${recipient}`,
|
||||
highlightedText: `${amount} ${checkCoin}`,
|
||||
fee: fee
|
||||
});
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted) {
|
||||
|
65
src/useAppFullscreen.tsx
Normal file
65
src/useAppFullscreen.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
export const useAppFullScreen = (setFullScreen) => {
|
||||
const enterFullScreen = useCallback(() => {
|
||||
const element = document.documentElement; // Target the entire HTML document
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen();
|
||||
} else if (element.mozRequestFullScreen) { // Firefox
|
||||
element.mozRequestFullScreen();
|
||||
} else if (element.webkitRequestFullscreen) { // Chrome, Safari and Opera
|
||||
element.webkitRequestFullscreen();
|
||||
} else if (element.msRequestFullscreen) { // IE/Edge
|
||||
element.msRequestFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const exitFullScreen = useCallback(() => {
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.mozFullScreenElement) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitFullscreenElement) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.msFullscreenElement) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleFullScreen = useCallback(() => {
|
||||
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
|
||||
exitFullScreen();
|
||||
setFullScreen(false)
|
||||
} else {
|
||||
enterFullScreen();
|
||||
setFullScreen(true)
|
||||
}
|
||||
}, [enterFullScreen, exitFullScreen]);
|
||||
|
||||
// Listen for changes to fullscreen state
|
||||
useEffect(() => {
|
||||
const handleFullScreenChange = () => {
|
||||
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
|
||||
|
||||
} else {
|
||||
setFullScreen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('fullscreenchange', handleFullScreenChange);
|
||||
document.addEventListener('webkitfullscreenchange', handleFullScreenChange); // Safari
|
||||
document.addEventListener('mozfullscreenchange', handleFullScreenChange); // Firefox
|
||||
document.addEventListener('MSFullscreenChange', handleFullScreenChange); // IE/Edge
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('fullscreenchange', handleFullScreenChange);
|
||||
document.removeEventListener('webkitfullscreenchange', handleFullScreenChange);
|
||||
document.removeEventListener('mozfullscreenchange', handleFullScreenChange);
|
||||
document.removeEventListener('MSFullscreenChange', handleFullScreenChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { enterFullScreen, exitFullScreen, toggleFullScreen };
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,6 @@ export const useQortalGetSaveSettings = (myName) => {
|
||||
const {hasPublishRecord, timestamp} = await getPublishRecord(myName)
|
||||
if(hasPublishRecord){
|
||||
const settings = await getPublish(myName)
|
||||
console.log('settings', settings, timestamp, settingsLocalLastUpdated )
|
||||
if(settings?.sortablePinnedApps && timestamp > settingsLocalLastUpdated){
|
||||
setSortablePinnedApps(settings.sortablePinnedApps)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user