dynamic remote node feature

This commit is contained in:
PhilReact 2024-10-24 03:55:10 +03:00
parent 4f343178bc
commit aeeac2fdaa
4 changed files with 458 additions and 116 deletions

View File

@ -78,7 +78,9 @@ import { Label } from "./components/Group/AddGroup";
import { CustomizedSnackbars } from "./components/Snackbar/Snackbar"; import { CustomizedSnackbars } from "./components/Snackbar/Snackbar";
import SettingsIcon from "@mui/icons-material/Settings"; import SettingsIcon from "@mui/icons-material/Settings";
import { import {
cleanUrl,
getFee, getFee,
getProtocol,
groupApi, groupApi,
groupApiLocal, groupApiLocal,
groupApiSocket, groupApiSocket,
@ -147,7 +149,7 @@ const defaultValues: MyContextInterface = {
message: "", message: "",
}, },
}; };
export let isMobile = false; export let isMobile = true;
const isMobileDevice = () => { const isMobileDevice = () => {
const userAgent = navigator.userAgent || navigator.vendor || window.opera; const userAgent = navigator.userAgent || navigator.vendor || window.opera;
@ -226,7 +228,7 @@ export const getBaseApiReact = (customApi?: string) => {
} }
if (globalApiKey) { if (globalApiKey) {
return groupApiLocal; return globalApiKey?.url;
} else { } else {
return groupApi; return groupApi;
} }
@ -252,7 +254,7 @@ export const getBaseApiReactSocket = (customApi?: string) => {
} }
if (globalApiKey) { if (globalApiKey) {
return groupApiSocketLocal; return `${getProtocol(globalApiKey?.url) === 'http' ? 'ws://': 'wss://'}${cleanUrl(globalApiKey?.url)}`
} else { } else {
return groupApiSocket; return groupApiSocket;
} }
@ -329,7 +331,6 @@ function App() {
const [infoSnack, setInfoSnack] = useState(null); const [infoSnack, setInfoSnack] = useState(null);
const [openSnack, setOpenSnack] = useState(false); const [openSnack, setOpenSnack] = useState(false);
const [hasLocalNode, setHasLocalNode] = useState(false); const [hasLocalNode, setHasLocalNode] = useState(false);
const [openAdvancedSettings, setOpenAdvancedSettings] = useState(false);
const [isOpenDrawerProfile, setIsOpenDrawerProfile] = useState(false); const [isOpenDrawerProfile, setIsOpenDrawerProfile] = useState(false);
const [apiKey, setApiKey] = useState(""); const [apiKey, setApiKey] = useState("");
const [isOpenSendQort, setIsOpenSendQort] = useState(false); const [isOpenSendQort, setIsOpenSendQort] = useState(false);
@ -406,7 +407,7 @@ function App() {
console.log('response', response) console.log('response', response)
handleSetGlobalApikey(response) handleSetGlobalApikey(response)
setApiKey(response); setApiKey(response);
setOpenAdvancedSettings(true);
} }
}); });
}, []); }, []);
@ -420,18 +421,7 @@ function App() {
isFocusedRef.current = isFocused; isFocusedRef.current = isFocused;
}, [isFocused]); }, [isFocused]);
// Handler for file selection
const handleFileChangeApiKey = (event) => {
const file = event.target.files[0]; // Get the selected file
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result; // Get the file content
setApiKey(text); // Store the file content in the state
};
reader.readAsText(file); // Read the file as text
}
};
// const checkIfUserHasLocalNode = useCallback(async () => { // const checkIfUserHasLocalNode = useCallback(async () => {
// try { // try {
@ -1068,8 +1058,6 @@ function App() {
setWalletToBeDownloadedError(""); setWalletToBeDownloadedError("");
setSendqortState(null); setSendqortState(null);
setHasLocalNode(false); setHasLocalNode(false);
setOpenAdvancedSettings(false);
setConfirmUseOfLocal(false);
setTxList([]); setTxList([]);
setMemberGroups([]); setMemberGroups([]);
resetAllRecoil() resetAllRecoil()
@ -1563,7 +1551,7 @@ function App() {
> >
{extState === "not-authenticated" && ( {extState === "not-authenticated" && (
<NotAuthenticated getRootProps={getRootProps} getInputProps={getInputProps} setExtstate={setExtstate} setOpenAdvancedSettings={setOpenAdvancedSettings} openAdvancedSettings={openAdvancedSettings} handleFileChangeApiKey={handleFileChangeApiKey} apiKey={apiKey} globalApiKey={globalApiKey} setApiKey={setApiKey} handleSetGlobalApikey={handleSetGlobalApikey}/> <NotAuthenticated getRootProps={getRootProps} getInputProps={getInputProps} setExtstate={setExtstate} apiKey={apiKey} globalApiKey={globalApiKey} setApiKey={setApiKey} handleSetGlobalApikey={handleSetGlobalApikey}/>
)} )}
{/* {extState !== "not-authenticated" && ( {/* {extState !== "not-authenticated" && (
<button onClick={logoutFunc}>logout</button> <button onClick={logoutFunc}>logout</button>

View File

@ -1,11 +1,16 @@
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useRef, useState } from "react";
import { Spacer } from "../common/Spacer"; import { Spacer } from "../common/Spacer";
import { CustomButton, TextItalic, TextP, TextSpan } from "../App-styles"; import { CustomButton, TextItalic, TextP, TextSpan } from "../App-styles";
import { import {
Box, Box,
Button, Button,
Checkbox, Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
FormControlLabel, FormControlLabel,
Input,
Switch, Switch,
Tooltip, Tooltip,
Typography, Typography,
@ -14,14 +19,15 @@ import Logo1 from "../assets/svgs/Logo1.svg";
import Logo1Dark from "../assets/svgs/Logo1Dark.svg"; import Logo1Dark from "../assets/svgs/Logo1Dark.svg";
import Info from "../assets/svgs/Info.svg"; import Info from "../assets/svgs/Info.svg";
import { CustomizedSnackbars } from "../components/Snackbar/Snackbar"; import { CustomizedSnackbars } from "../components/Snackbar/Snackbar";
import { set } from "lodash";
import { cleanUrl, isUsingLocal } from "../background";
export const NotAuthenticated = ({ export const NotAuthenticated = ({
getRootProps, getRootProps,
getInputProps, getInputProps,
setExtstate, setExtstate,
setOpenAdvancedSettings,
openAdvancedSettings,
handleFileChangeApiKey,
apiKey, apiKey,
setApiKey, setApiKey,
globalApiKey, globalApiKey,
@ -33,6 +39,36 @@ export const NotAuthenticated = ({
const [useLocalNode, setUseLocalNode] = useState(false); const [useLocalNode, setUseLocalNode] = useState(false);
const [openSnack, setOpenSnack] = React.useState(false); const [openSnack, setOpenSnack] = React.useState(false);
const [infoSnack, setInfoSnack] = React.useState(null); const [infoSnack, setInfoSnack] = React.useState(null);
const [show, setShow] = React.useState(false);
const [mode, setMode] = React.useState("list");
const [customNodes, setCustomNodes] = React.useState(null);
const [currentNode, setCurrentNode] = React.useState({
url: "http://127.0.0.1:12391",
});
const [importedApiKey, setImportedApiKey] = React.useState(null);
//add and edit states
const [url, setUrl] = React.useState("http://");
const [customApikey, setCustomApiKey] = React.useState("");
const [customNodeToSaveIndex, setCustomNodeToSaveIndex] =
React.useState(null);
const importedApiKeyRef = useRef(null)
const currentNodeRef = useRef(null)
const isLocal = cleanUrl(currentNode?.url) === "127.0.0.1:12391";
const handleFileChangeApiKey = (event) => {
const file = event.target.files[0]; // Get the selected file
console.log('file', file)
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result; // Get the file content
console.log('text', text)
setImportedApiKey(text); // Store the file content in the state
};
reader.readAsText(file); // Read the file as text
}
};
const checkIfUserHasLocalNode = useCallback(async () => { const checkIfUserHasLocalNode = useCallback(async () => {
try { try {
@ -44,7 +80,7 @@ export const NotAuthenticated = ({
}, },
}); });
const data = await response.json(); const data = await response.json();
if (data?.syncPercent) { if (data?.height) {
setHasLocalNode(true); setHasLocalNode(true);
} }
} catch (error) {} } catch (error) {}
@ -54,14 +90,55 @@ export const NotAuthenticated = ({
checkIfUserHasLocalNode(); checkIfUserHasLocalNode();
}, []); }, []);
useEffect(() => {
chrome?.runtime?.sendMessage(
{ action: "getCustomNodesFromStorage" },
(response) => {
if (response) {
console.log("response", response);
setCustomNodes(response || []);
}
}
);
}, []);
useEffect(()=> {
importedApiKeyRef.current = importedApiKey
}, [importedApiKey])
useEffect(()=> {
currentNodeRef.current = currentNode
}, [currentNode])
console.log('currentNode', currentNode)
const validateApiKey = useCallback(async (key) => { const validateApiKey = useCallback(async (key) => {
try { try {
const url = `http://127.0.0.1:12391/admin/apikey/test`; console.log('currentNodeRef.current', currentNodeRef.current, key)
if(!currentNodeRef.current) return
const isLocalKey = cleanUrl(key?.url) === "127.0.0.1:12391";
const isCurrentNodeLocal = cleanUrl(currentNodeRef.current?.url) === "127.0.0.1:12391";
if(isLocalKey && !isCurrentNodeLocal) {
setIsValidApiKey(false);
setUseLocalNode(false);
return
}
let payload = {};
if (currentNodeRef.current?.url === "http://127.0.0.1:12391") {
payload = {
apikey: importedApiKeyRef.current || key?.apikey,
url: currentNode?.url,
};
} else if(currentNodeRef.current) {
payload = currentNodeRef.current;
}
console.log('payload', payload)
const url = `${payload?.url}/admin/apikey/test`;
const response = await fetch(url, { const response = await fetch(url, {
method: "GET", method: "GET",
headers: { headers: {
accept: "text/plain", accept: "text/plain",
"X-API-KEY": key, // Include the API key here "X-API-KEY": payload?.apikey, // Include the API key here
}, },
}); });
@ -69,7 +146,6 @@ export const NotAuthenticated = ({
const data = await response.text(); const data = await response.text();
console.log("data", data); console.log("data", data);
if (data === "true") { if (data === "true") {
const payload = key;
chrome?.runtime?.sendMessage( chrome?.runtime?.sendMessage(
{ action: "setApiKey", payload }, { action: "setApiKey", payload },
(response) => { (response) => {
@ -107,6 +183,44 @@ export const NotAuthenticated = ({
} }
}, [apiKey]); }, [apiKey]);
const addCustomNode = () => {
setMode("add-node");
};
const saveCustomNodes = (myNodes) => {
let nodes = [...(myNodes || [])];
console.log("customNodeToSaveIndex", customNodeToSaveIndex);
if (customNodeToSaveIndex !== null) {
nodes.splice(customNodeToSaveIndex, 1, {
url,
apikey: customApikey,
});
} else if (url && customApikey) {
nodes.push({
url,
apikey: customApikey,
});
}
setCustomNodes(nodes);
setCustomNodeToSaveIndex(null);
if (!nodes) return;
chrome?.runtime?.sendMessage(
{ action: "setCustomNodes", nodes },
(response) => {
console.log("setCustomNodes", response);
if (response) {
setMode("list");
setUrl("http://");
setCustomApiKey("");
// add alert
}
}
);
};
console.log("render customNodes", customNodes, mode);
return ( return (
<> <>
<Spacer height="48px" /> <Spacer height="48px" />
@ -172,7 +286,16 @@ export const NotAuthenticated = ({
}} }}
/> />
</Box> </Box>
<Spacer height="15px" />
<Typography
sx={{
fontSize: "12px",
visibility: !useLocalNode && 'hidden'
}}
>
{"Using node: "} {apiKey?.url}
</Typography>
<> <>
<Spacer height="15px" /> <Spacer height="15px" />
<Box <Box
@ -196,97 +319,71 @@ export const NotAuthenticated = ({
<FormControlLabel <FormControlLabel
control={ control={
<Switch <Switch
sx={{ sx={{
'& .MuiSwitch-switchBase.Mui-checked': { "& .MuiSwitch-switchBase.Mui-checked": {
color: '#5EB049', color: "#5EB049",
}, },
"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track":
}} {
backgroundColor: "white", // Change track color when checked
},
}}
checked={useLocalNode} checked={useLocalNode}
onChange={(event) => { onChange={(event) => {
if (event.target.checked) { if (event.target.checked) {
validateApiKey(apiKey); validateApiKey(currentNode);
} else { } else {
setUseLocalNode(false); setCurrentNode({
const payload = null; url: "http://127.0.0.1:12391",
chrome?.runtime?.sendMessage( })
{ action: "setApiKey", payload }, setUseLocalNode(false)
(response) => { chrome?.runtime?.sendMessage(
console.log("setApiKey", response); { action: "setApiKey", payload:null },
if (response) { (response) => {
globalApiKey = payload; console.log("setApiKey", response);
setApiKey(payload); if (response) {
handleSetGlobalApikey(payload); setApiKey(payload);
if (!globalApiKey) {
setUseLocalNode(false);
setOpenAdvancedSettings(false);
setApiKey("");
handleSetGlobalApikey(payload); handleSetGlobalApikey(payload);
} }
} }
} );
);
} }
}} }}
disabled={false} disabled={false}
defaultChecked defaultChecked
/> />
} }
label="Use Local Node" label={`Use ${isLocal ? 'Local' : 'Custom'} Node`}
/> />
</Box> </Box>
{currentNode?.url === "http://127.0.0.1:12391" && (
<>
<Button variant="contained" component="label">
{apiKey ? "Change " : "Import "} apiKey.txt
<input
type="file"
accept=".txt"
hidden
onChange={handleFileChangeApiKey} // File input handler
/>
</Button>
<Spacer height="5px" />
<>
<Button variant="contained" component="label">
{apiKey ? "Change " : "Import "} apiKey.txt </>
<input )}
type="file" <Button
accept=".txt" onClick={() => {
hidden setShow(true);
onChange={handleFileChangeApiKey} // File input handler }}
/> variant="contained"
</Button> component="label"
<Spacer height="5px" /> >
Choose custom node
<Spacer height="5px" /> </Button>
{apiKey && (
<>
<Button
onClick={() => {
const payload = null;
chrome?.runtime?.sendMessage(
{ action: "setApiKey", payload },
(response) => {
console.log("setApiKey", response);
if (response) {
globalApiKey = payload;
setApiKey(payload);
if (!globalApiKey) {
setUseLocalNode(false);
setOpenAdvancedSettings(false);
setApiKey("");
}
}
}
);
}}
variant="contained"
sx={{
color: "white",
}}
>
Clear Apikey
</Button>
<Typography
sx={{
fontSize: "12px",
}}
>
{"Apikey : "} {apiKey}
</Typography>
</>
)}
</>
</> </>
</Box> </Box>
</> </>
@ -296,6 +393,223 @@ export const NotAuthenticated = ({
info={infoSnack} info={infoSnack}
setInfo={setInfoSnack} setInfo={setInfoSnack}
/> />
{show && (
<Dialog
open={show}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
fullWidth
>
<DialogTitle id="alert-dialog-title">{"Custom nodes"}</DialogTitle>
<DialogContent>
<Box
sx={{
width: "100% !important",
overflow: "auto",
height: "60vh",
display: "flex",
flexDirection: "column",
}}
>
{mode === "list" && (
<Box
sx={{
gap: "20px",
display: "flex",
flexDirection: "column",
}}
>
<Box
sx={{
display: "flex",
gap: "10px",
flexDirection: "column",
}}
>
<Typography
sx={{
color: "white",
fontSize: "14px",
}}
>
http://127.0.0.1:12391
</Typography>
<Box
sx={{
display: "flex",
gap: "10px",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Button
disabled={currentNode?.url === "http://127.0.0.1:12391"}
size="small"
onClick={() => {
setCurrentNode({
url: "http://127.0.0.1:12391",
});
setMode("list");
setShow(false);
}}
variant="contained"
>
Choose
</Button>
</Box>
</Box>
{customNodes?.map((node, index) => {
return (
<Box
sx={{
display: "flex",
gap: "10px",
flexDirection: "column",
}}
>
<Typography
sx={{
color: "white",
fontSize: "14px",
}}
>
{node?.url}
</Typography>
<Box
sx={{
display: "flex",
gap: "10px",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Button
disabled={currentNode?.url === node?.url}
size="small"
onClick={() => {
setCurrentNode({
url: node?.url,
apikey: node?.apikey,
});
setMode("list");
setShow(false);
setIsValidApiKey(false);
setUseLocalNode(false);
}}
variant="contained"
>
Choose
</Button>
<Button
size="small"
onClick={() => {
setCustomApiKey(node?.apikey);
setUrl(node?.url);
setMode("add-node");
setCustomNodeToSaveIndex(index);
}}
variant="contained"
>
Edit
</Button>
<Button
size="small"
onClick={() => {
const nodesToSave = [
...(customNodes || []),
].filter((item) => item?.url !== node?.url);
console.log(
"nodesToSave",
nodesToSave,
customNodes,
node
);
saveCustomNodes(nodesToSave);
}}
variant="contained"
>
Remove
</Button>
</Box>
</Box>
);
})}
</Box>
)}
{mode === "add-node" && (
<Box
sx={{
display: "flex",
gap: "10px",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Input
placeholder="Url"
value={url}
onChange={(e) => {
setUrl(e.target.value);
}}
/>
<Input
placeholder="Api key"
value={customApikey}
onChange={(e) => {
setCustomApiKey(e.target.value);
}}
/>
</Box>
)}
</Box>
</DialogContent>
<DialogActions>
{mode === "list" && (
<>
<Button
variant="contained"
onClick={() => {
setShow(false);
}}
autoFocus
>
Close
</Button>
</>
)}
{mode === "list" && (
<Button variant="contained" onClick={addCustomNode}>
Add
</Button>
)}
{mode === "add-node" && (
<>
<Button
variant="contained"
onClick={() => {
setMode("list");
setCustomNodeToSaveIndex(null);
}}
>
Return to list
</Button>
<Button
variant="contained"
disabled={!customApikey || !url}
onClick={() => saveCustomNodes(customNodes)}
autoFocus
>
Save
</Button>
</>
)}
</DialogActions>
</Dialog>
)}
</> </>
); );
}; };

View File

@ -31,6 +31,19 @@ import { Sha256 } from "asmcrypto.js";
import { TradeBotRespondMultipleRequest } from "./transactions/TradeBotRespondMultipleRequest"; import { TradeBotRespondMultipleRequest } from "./transactions/TradeBotRespondMultipleRequest";
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from "./constants/resourceTypes"; import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from "./constants/resourceTypes";
export function cleanUrl(url) {
return url?.replace(/^(https?:\/\/)?(www\.)?/, '');
}
export function getProtocol(url) {
if (url?.startsWith('https://')) {
return 'https';
} else if (url?.startsWith('http://')) {
return 'http';
} else {
return 'unknown'; // If neither protocol is present
}
}
let lastGroupNotification; let lastGroupNotification;
export const groupApi = "https://ext-node.qortal.link"; export const groupApi = "https://ext-node.qortal.link";
export const groupApiSocket = "wss://ext-node.qortal.link"; export const groupApiSocket = "wss://ext-node.qortal.link";
@ -40,6 +53,7 @@ const timeDifferenceForNotificationChatsBackground = 600000;
const requestQueueAnnouncements = new RequestQueueWithPromise(1); const requestQueueAnnouncements = new RequestQueueWithPromise(1);
let isMobile = false; let isMobile = false;
const isMobileDevice = () => { const isMobileDevice = () => {
const userAgent = navigator.userAgent || navigator.vendor || window.opera; const userAgent = navigator.userAgent || navigator.vendor || window.opera;
@ -106,6 +120,17 @@ const getApiKeyFromStorage = async () => {
}); });
}; };
const getCustomNodesFromStorage = async () => {
return new Promise((resolve, reject) => {
chrome.storage.local.get("customNodes", (result) => {
if (chrome.runtime.lastError) {
return reject(chrome.runtime.lastError);
}
resolve(result.customNodes || null); // Return null if apiKey isn't found
});
});
};
// const getArbitraryEndpoint = ()=> { // const getArbitraryEndpoint = ()=> {
// const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously // const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously
// if (apiKey) { // if (apiKey) {
@ -130,7 +155,7 @@ export const getBaseApi = async (customApi?: string) => {
const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously
if (apiKey) { if (apiKey) {
return groupApiLocal; return apiKey?.url;
} else { } else {
return groupApi; return groupApi;
} }
@ -145,15 +170,7 @@ export const isUsingLocal = async () => {
} }
}; };
export const createEndpointSocket = async (endpoint) => {
const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously
if (apiKey) {
return `${groupApiSocketLocal}${endpoint}`;
} else {
return `${groupApiSocket}${endpoint}`;
}
};
export const createEndpoint = async (endpoint, customApi?: string) => { export const createEndpoint = async (endpoint, customApi?: string) => {
if (customApi) { if (customApi) {
@ -165,7 +182,7 @@ export const createEndpoint = async (endpoint, customApi?: string) => {
if (apiKey) { if (apiKey) {
// Check if the endpoint already contains a query string // Check if the endpoint already contains a query string
const separator = endpoint.includes("?") ? "&" : "?"; const separator = endpoint.includes("?") ? "&" : "?";
return `${groupApiLocal}${endpoint}${separator}apiKey=${apiKey}`; return `${apiKey?.url}${endpoint}${separator}apiKey=${apiKey?.apikey}`;
} else { } else {
return `${groupApi}${endpoint}`; return `${groupApi}${endpoint}`;
} }
@ -1816,7 +1833,7 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) {
let responseVar let responseVar
const txn = new TradeBotRespondMultipleRequest().createTransaction(message) const txn = new TradeBotRespondMultipleRequest().createTransaction(message)
const apiKey = await getApiKeyFromStorage(); const apiKey = await getApiKeyFromStorage();
const responseFetch = await fetch(`http://127.0.0.1:12391/crosschain/tradebot/respondmultiple?apiKey=${apiKey}`, { const responseFetch = await fetch(`${apiKey?.url}/crosschain/tradebot/respondmultiple?apiKey=${apiKey?.apikey}`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -3291,6 +3308,16 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
return true; return true;
break; break;
} }
case "setCustomNodes": {
const { nodes } = request;
// Save the customNodes in chrome.storage.local for persistence
chrome.storage.local.set({ customNodes: nodes }, () => {
sendResponse(true);
});
return true;
break;
}
case "getApiKey": { case "getApiKey": {
getApiKeyFromStorage() getApiKeyFromStorage()
.then((res) => { .then((res) => {
@ -3303,6 +3330,19 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
return true; return true;
break; break;
} }
case "getCustomNodesFromStorage": {
getCustomNodesFromStorage()
.then((res) => {
sendResponse(res);
})
.catch((error) => {
sendResponse({ error: error.message });
console.error(error.message);
});
return true;
break;
}
case "notifyAdminRegenerateSecretKey": { case "notifyAdminRegenerateSecretKey": {
const { groupName, adminAddress } = request.payload; const { groupName, adminAddress } = request.payload;
notifyAdminRegenerateSecretKey({ groupName, adminAddress }) notifyAdminRegenerateSecretKey({ groupName, adminAddress })

View File

@ -28,7 +28,7 @@ export const useAppFullScreen = (setFullScreen) => {
}, []); }, []);
const toggleFullScreen = useCallback(() => { const toggleFullScreen = useCallback(() => {
if(!isMobile) return if(!isMobile || isMobile) return
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) { if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
exitFullScreen(); exitFullScreen();
setFullScreen(false) setFullScreen(false)