mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-24 20:07:51 +00:00
added devmode
This commit is contained in:
parent
a499b25050
commit
ebfd6db4dc
11
src/App.tsx
11
src/App.tsx
@ -103,6 +103,7 @@ import { useQortalGetSaveSettings } from "./useQortalGetSaveSettings";
|
||||
import { useRecoilState, useResetRecoilState, useSetRecoilState } from "recoil";
|
||||
import {
|
||||
canSaveSettingToQdnAtom,
|
||||
enabledDevModeAtom,
|
||||
fullScreenAtom,
|
||||
hasSettingsChangedAtom,
|
||||
oldPinnedAppsAtom,
|
||||
@ -370,9 +371,17 @@ function App() {
|
||||
useRetrieveDataLocalStorage();
|
||||
useQortalGetSaveSettings(userInfo?.name);
|
||||
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
|
||||
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
|
||||
|
||||
const { toggleFullScreen } = useAppFullScreen(setFullScreen);
|
||||
|
||||
useEffect(()=> {
|
||||
const isDevModeFromStorage = localStorage.getItem('isEnabledDevMode');
|
||||
if(isDevModeFromStorage){
|
||||
setIsEnabledDevMode(JSON.parse(isDevModeFromStorage))
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// Attach a global event listener for double-click
|
||||
const handleDoubleClick = () => {
|
||||
@ -1519,7 +1528,7 @@ function App() {
|
||||
desktopViewMode={desktopViewMode}
|
||||
setDesktopViewMode={setDesktopViewMode}
|
||||
/>
|
||||
{!isMobile && desktopViewMode !== "apps" && renderProfile()}
|
||||
{!isMobile && desktopViewMode !== "apps" && desktopViewMode !== "dev" && renderProfile()}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
|
@ -62,3 +62,8 @@ export const navigationControllerAtom = atom({
|
||||
key: 'navigationControllerAtom',
|
||||
default: {},
|
||||
});
|
||||
|
||||
export const enabledDevModeAtom = atom({
|
||||
key: 'enabledDevModeAtom',
|
||||
default: false,
|
||||
});
|
@ -11,25 +11,35 @@ import { useQortalMessageListener } from "./useQortalMessageListener";
|
||||
|
||||
|
||||
|
||||
export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
||||
export const AppViewer = React.forwardRef(({ app , hide, isDevMode}, iframeRef) => {
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
// const iframeRef = useRef(null);
|
||||
const { document, window: frameWindow } = useFrame();
|
||||
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId)
|
||||
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId, isDevMode)
|
||||
const [url, setUrl] = useState('')
|
||||
|
||||
useEffect(()=> {
|
||||
if(isDevMode){
|
||||
setUrl(app?.url)
|
||||
return
|
||||
}
|
||||
|
||||
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? `/${app?.path}` : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}`)
|
||||
}, [app?.service, app?.name, app?.identifier, app?.path])
|
||||
const defaultUrl = useMemo(()=> {
|
||||
return url
|
||||
}, [url])
|
||||
}, [url, isDevMode])
|
||||
|
||||
|
||||
|
||||
const refreshAppFunc = (e) => {
|
||||
const {tabId} = e.detail
|
||||
if(tabId === app?.tabId){
|
||||
if(isDevMode){
|
||||
setUrl(app?.url + `?time=${Date.now()}`)
|
||||
return
|
||||
|
||||
}
|
||||
const constructUrl = `${getBaseApiReact()}/render/${app?.service}/${app?.name}${path != null ? path : ''}?theme=dark&identifier=${app?.identifier != null ? app?.identifier : ''}&time=${new Date().getMilliseconds()}`
|
||||
setUrl(constructUrl)
|
||||
}
|
||||
@ -41,7 +51,7 @@ export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
||||
return () => {
|
||||
unsubscribeFromEvent("refreshApp", refreshAppFunc);
|
||||
};
|
||||
}, [app, path]);
|
||||
}, [app, path, isDevMode]);
|
||||
|
||||
// Function to navigate back in iframe
|
||||
const navigateBackInIframe = async () => {
|
||||
|
@ -3,7 +3,7 @@ import { AppViewer } from './AppViewer';
|
||||
import Frame from 'react-frame-component';
|
||||
import { MyContext, isMobile } from '../../App';
|
||||
|
||||
const AppViewerContainer = React.forwardRef(({ app, isSelected, hide }, ref) => {
|
||||
const AppViewerContainer = React.forwardRef(({ app, isSelected, hide, isDevMode }, ref) => {
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ const AppViewerContainer = React.forwardRef(({ app, isSelected, hide }, ref) =>
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<AppViewer app={app} ref={ref} hide={!isSelected || hide} />
|
||||
<AppViewer app={app} ref={ref} hide={!isSelected || hide} isDevMode={isDevMode} />
|
||||
</Frame>
|
||||
);
|
||||
});
|
||||
|
310
src/components/Apps/AppsDevMode.tsx
Normal file
310
src/components/Apps/AppsDevMode.tsx
Normal file
@ -0,0 +1,310 @@
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { AppsDevModeHome } from "./AppsDevModeHome";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { MyContext, getBaseApiReact } from "../../App";
|
||||
import { AppInfo } from "./AppInfo";
|
||||
import {
|
||||
executeEvent,
|
||||
subscribeToEvent,
|
||||
unsubscribeFromEvent,
|
||||
} from "../../utils/events";
|
||||
import { AppsParent } from "./Apps-styles";
|
||||
import AppViewerContainer from "./AppViewerContainer";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { AppPublish } from "./AppPublish";
|
||||
import { AppsLibraryDesktop } from "./AppsLibraryDesktop";
|
||||
import { AppsCategoryDesktop } from "./AppsCategoryDesktop";
|
||||
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
||||
import { Box, ButtonBase } from "@mui/material";
|
||||
import { HomeIcon } from "../../assets/Icons/HomeIcon";
|
||||
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
|
||||
import { Save } from "../Save/Save";
|
||||
import { HubsIcon } from "../../assets/Icons/HubsIcon";
|
||||
import { AppsDevModeNavBar } from "./AppsDevModeNavBar";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 8 });
|
||||
|
||||
export const AppsDevMode = ({ mode, setMode, show , myName, goToHome, setDesktopSideView, hasUnreadDirects, isDirects, isGroups, hasUnreadGroups, toggleSideViewGroups, toggleSideViewDirects}) => {
|
||||
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);
|
||||
const [categories, setCategories] = useState([])
|
||||
const iframeRefs = useRef({});
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
executeEvent("appsDevModeSetTabsToNav", {
|
||||
data: {
|
||||
tabs: tabs,
|
||||
selectedTab: selectedTab,
|
||||
isNewTabWindow: isNewTabWindow,
|
||||
},
|
||||
});
|
||||
}, 100);
|
||||
}, [show, tabs, selectedTab, isNewTabWindow]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const navigateBackFunc = (e) => {
|
||||
if (['category', 'appInfo-from-category', 'appInfo', 'library', 'publish'].includes(mode)) {
|
||||
// Handle the various modes as needed
|
||||
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) {
|
||||
setMode('viewer');
|
||||
} else {
|
||||
setMode('home');
|
||||
}
|
||||
} else if (mode === 'publish') {
|
||||
setMode('library');
|
||||
}
|
||||
} else if(selectedTab?.tabId) {
|
||||
executeEvent(`navigateBackApp-${selectedTab?.tabId}`, {})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("devModeNavigateBack", navigateBackFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("devModeNavigateBack", navigateBackFunc);
|
||||
};
|
||||
}, [mode, selectedTab]);
|
||||
|
||||
const addTabFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
const newTab = {
|
||||
...data,
|
||||
tabId: uid.rnd(),
|
||||
};
|
||||
setTabs((prev) => [...prev, newTab]);
|
||||
setSelectedTab(newTab);
|
||||
setMode("viewer");
|
||||
|
||||
setIsNewTabWindow(false);
|
||||
};
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("appsDevModeAddTab", addTabFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("appsDevModeAddTab", addTabFunc);
|
||||
};
|
||||
}, [tabs]);
|
||||
const setSelectedTabFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
|
||||
setSelectedTab(data);
|
||||
setTimeout(() => {
|
||||
executeEvent("appsDevModeSetTabsToNav", {
|
||||
data: {
|
||||
tabs: tabs,
|
||||
selectedTab: data,
|
||||
isNewTabWindow: isNewTabWindow,
|
||||
},
|
||||
});
|
||||
}, 100);
|
||||
setIsNewTabWindow(false);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("setSelectedTab", setSelectedTabFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("setSelectedTab", setSelectedTabFunc);
|
||||
};
|
||||
}, [tabs, isNewTabWindow]);
|
||||
|
||||
const removeTabFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
const copyTabs = [...tabs].filter((tab) => tab?.tabId !== data?.tabId);
|
||||
if (copyTabs?.length === 0) {
|
||||
setMode("home");
|
||||
} else {
|
||||
setSelectedTab(copyTabs[0]);
|
||||
}
|
||||
setTabs(copyTabs);
|
||||
setSelectedTab(copyTabs[0]);
|
||||
setTimeout(() => {
|
||||
executeEvent("setTabsToNav", {
|
||||
data: {
|
||||
tabs: copyTabs,
|
||||
selectedTab: copyTabs[0],
|
||||
},
|
||||
});
|
||||
}, 400);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("removeTab", removeTabFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("removeTab", removeTabFunc);
|
||||
};
|
||||
}, [tabs]);
|
||||
|
||||
const setNewTabWindowFunc = (e) => {
|
||||
setIsNewTabWindow(true);
|
||||
setSelectedTab(null)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("devModeNewTabWindow", setNewTabWindowFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("devModeNewTabWindow", setNewTabWindowFunc);
|
||||
};
|
||||
}, [tabs]);
|
||||
|
||||
|
||||
return (
|
||||
<AppsParent
|
||||
sx={{
|
||||
display: !show && "none",
|
||||
flexDirection: 'row'
|
||||
}}
|
||||
>
|
||||
|
||||
<Box sx={{
|
||||
width: '60px',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
gap: '30px'
|
||||
}}>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
paddingTop: '23px'
|
||||
}}
|
||||
onClick={() => {
|
||||
goToHome();
|
||||
|
||||
}}
|
||||
>
|
||||
|
||||
<HomeIcon
|
||||
height={34}
|
||||
color="rgba(250, 250, 250, 0.5)"
|
||||
/>
|
||||
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopSideView("directs");
|
||||
toggleSideViewDirects()
|
||||
}}
|
||||
>
|
||||
|
||||
<MessagingIcon
|
||||
height={30}
|
||||
color={
|
||||
hasUnreadDirects
|
||||
? "var(--unread)"
|
||||
: isDirects
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
/>
|
||||
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopSideView("groups");
|
||||
toggleSideViewGroups()
|
||||
}}
|
||||
>
|
||||
<HubsIcon
|
||||
height={30}
|
||||
color={
|
||||
hasUnreadGroups
|
||||
? "var(--unread)"
|
||||
: isGroups
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
/>
|
||||
|
||||
</ButtonBase>
|
||||
<Save isDesktop />
|
||||
{mode !== 'home' && (
|
||||
<AppsDevModeNavBar />
|
||||
|
||||
)}
|
||||
|
||||
</Box>
|
||||
|
||||
|
||||
{mode === "home" && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
|
||||
<Spacer height="30px" />
|
||||
<AppsDevModeHome availableQapps={availableQapps} setMode={setMode} myApp={null} myWebsite={null} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
{tabs.map((tab) => {
|
||||
if (!iframeRefs.current[tab.tabId]) {
|
||||
iframeRefs.current[tab.tabId] = React.createRef();
|
||||
}
|
||||
return (
|
||||
<AppViewerContainer
|
||||
key={tab?.tabId}
|
||||
hide={isNewTabWindow}
|
||||
isSelected={tab?.tabId === selectedTab?.tabId}
|
||||
app={tab}
|
||||
ref={iframeRefs.current[tab.tabId]}
|
||||
isDevMode={true}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{isNewTabWindow && mode === "viewer" && (
|
||||
<>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
|
||||
<Spacer height="30px" />
|
||||
<AppsDevModeHome availableQapps={availableQapps} setMode={setMode} myApp={null} myWebsite={null} />
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</AppsParent>
|
||||
);
|
||||
};
|
183
src/components/Apps/AppsDevModeHome.tsx
Normal file
183
src/components/Apps/AppsDevModeHome.tsx
Normal file
@ -0,0 +1,183 @@
|
||||
import React, { useContext, useMemo, useState } from "react";
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
AppCircleLabel,
|
||||
AppLibrarySubTitle,
|
||||
AppsContainer,
|
||||
AppsParent,
|
||||
} from "./Apps-styles";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Input,
|
||||
} from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { AppsDevModeSortablePinnedApps } from "./AppsDevModeSortablePinnedApps";
|
||||
import { useModal } from "../../common/useModal";
|
||||
import { isUsingLocal } from "../../background";
|
||||
import { Label } from "../Group/AddGroup";
|
||||
|
||||
export const AppsDevModeHome = ({
|
||||
setMode,
|
||||
myApp,
|
||||
myWebsite,
|
||||
availableQapps,
|
||||
}) => {
|
||||
|
||||
const [domain, setDomain] = useState("");
|
||||
const [port, setPort] = useState("");
|
||||
const { isShow, onCancel, onOk, show, message } = useModal();
|
||||
const {
|
||||
openSnackGlobal,
|
||||
setOpenSnackGlobal,
|
||||
infoSnackCustom,
|
||||
setInfoSnackCustom,
|
||||
} = useContext(MyContext);
|
||||
|
||||
const addDevModeApp = async () => {
|
||||
try {
|
||||
const usingLocal = await isUsingLocal();
|
||||
if (!usingLocal) {
|
||||
setOpenSnackGlobal(true);
|
||||
|
||||
setInfoSnackCustom({
|
||||
type: "error",
|
||||
message:
|
||||
"Please use your local node for dev mode! Logout and use Local node.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await show({
|
||||
message: "",
|
||||
publishFee: "",
|
||||
});
|
||||
const framework = domain + ":" + port;
|
||||
const response = await fetch(
|
||||
`${getBaseApiReact()}/developer/proxy/start`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "text/plain",
|
||||
},
|
||||
body: framework,
|
||||
}
|
||||
);
|
||||
const responseData = await response.text();
|
||||
executeEvent("appsDevModeAddTab", {
|
||||
data: {
|
||||
url: "http://127.0.0.1:" + responseData,
|
||||
},
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppsContainer
|
||||
sx={{
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<AppLibrarySubTitle
|
||||
sx={{
|
||||
fontSize: "30px",
|
||||
}}
|
||||
>
|
||||
Dev Mode Apps
|
||||
</AppLibrarySubTitle>
|
||||
</AppsContainer>
|
||||
<Spacer height="45px" />
|
||||
<AppsContainer
|
||||
sx={{
|
||||
gap: "75px",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
addDevModeApp();
|
||||
}}
|
||||
>
|
||||
<AppCircleContainer
|
||||
sx={{
|
||||
gap: !isMobile ? "10px" : "5px",
|
||||
}}
|
||||
>
|
||||
<AppCircle>
|
||||
<Add>+</Add>
|
||||
</AppCircle>
|
||||
<AppCircleLabel>App</AppCircleLabel>
|
||||
</AppCircleContainer>
|
||||
</ButtonBase>
|
||||
</AppsContainer>
|
||||
{isShow && (
|
||||
<Dialog
|
||||
open={isShow}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"Add custom framework"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "5px",
|
||||
}}
|
||||
>
|
||||
<Label>Domain</Label>
|
||||
<Input
|
||||
placeholder="Domain"
|
||||
value={domain}
|
||||
onChange={(e) => setDomain(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "5px",
|
||||
marginTop: '15px'
|
||||
}}
|
||||
>
|
||||
<Label>Port</Label>
|
||||
|
||||
<Input
|
||||
placeholder="Port"
|
||||
value={port}
|
||||
onChange={(e) => setPort(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={onCancel}>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!domain || !port}
|
||||
variant="contained"
|
||||
onClick={onOk}
|
||||
autoFocus
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
272
src/components/Apps/AppsDevModeNavBar.tsx
Normal file
272
src/components/Apps/AppsDevModeNavBar.tsx
Normal file
@ -0,0 +1,272 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
AppsNavBarLeft,
|
||||
AppsNavBarParent,
|
||||
AppsNavBarRight,
|
||||
} from "./Apps-styles";
|
||||
import NavBack from "../../assets/svgs/NavBack.svg";
|
||||
import NavAdd from "../../assets/svgs/NavAdd.svg";
|
||||
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg";
|
||||
import {
|
||||
ButtonBase,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Tab,
|
||||
Tabs,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
executeEvent,
|
||||
subscribeToEvent,
|
||||
unsubscribeFromEvent,
|
||||
} from "../../utils/events";
|
||||
import TabComponent from "./TabComponent";
|
||||
import PushPinIcon from "@mui/icons-material/PushPin";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||
import {
|
||||
navigationControllerAtom,
|
||||
settingsLocalLastUpdatedAtom,
|
||||
sortablePinnedAppsAtom,
|
||||
} from "../../atoms/global";
|
||||
import { AppsDevModeTabComponent } from "./AppsDevModeTabComponent";
|
||||
|
||||
|
||||
|
||||
export const AppsDevModeNavBar = () => {
|
||||
const [tabs, setTabs] = useState([]);
|
||||
const [selectedTab, setSelectedTab] = useState(null);
|
||||
const [navigationController, setNavigationController] = useRecoilState(navigationControllerAtom)
|
||||
|
||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||
const tabsRef = useRef(null);
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 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");
|
||||
if (tabElements.length > 0) {
|
||||
const lastTab = tabElements[tabElements.length - 1];
|
||||
lastTab.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
inline: "end",
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [tabs.length]); // Dependency on the number of tabs
|
||||
|
||||
|
||||
const isDisableBackButton = useMemo(()=> {
|
||||
if(selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false
|
||||
if(selectedTab && !navigationController[selectedTab?.tabId]?.hasBack) return true
|
||||
return false
|
||||
}, [navigationController, selectedTab])
|
||||
|
||||
|
||||
|
||||
|
||||
const setTabsToNav = (e) => {
|
||||
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
||||
|
||||
setTabs([...tabs]);
|
||||
setSelectedTab(!selectedTab ? null : { ...selectedTab });
|
||||
setIsNewTabWindow(isNewTabWindow);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("appsDevModeSetTabsToNav", setTabsToNav);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("appsDevModeSetTabsToNav", setTabsToNav);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<AppsNavBarParent
|
||||
sx={{
|
||||
position: "relative",
|
||||
flexDirection: "column",
|
||||
width: "60px",
|
||||
height: "unset",
|
||||
maxHeight: "70vh",
|
||||
borderRadius: "0px 30px 30px 0px",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<AppsNavBarLeft
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
executeEvent("devModeNavigateBack", selectedTab?.tabId);
|
||||
}}
|
||||
disabled={isDisableBackButton}
|
||||
sx={{
|
||||
opacity: !isDisableBackButton ? 1 : 0.1,
|
||||
cursor: !isDisableBackButton ? 'pointer': 'default'
|
||||
}}
|
||||
>
|
||||
<img src={NavBack} />
|
||||
</ButtonBase>
|
||||
<Tabs
|
||||
orientation="vertical"
|
||||
ref={tabsRef}
|
||||
aria-label="basic tabs example"
|
||||
variant="scrollable" // Make tabs scrollable
|
||||
scrollButtons={true}
|
||||
sx={{
|
||||
"& .MuiTabs-indicator": {
|
||||
backgroundColor: "white",
|
||||
},
|
||||
maxHeight: `320px`, // Ensure the tabs container fits within the available space
|
||||
overflow: "hidden", // Prevents overflow on small screens
|
||||
}}
|
||||
>
|
||||
{tabs?.map((tab) => (
|
||||
<Tab
|
||||
key={tab.tabId}
|
||||
label={
|
||||
<AppsDevModeTabComponent
|
||||
isSelected={
|
||||
tab?.tabId === selectedTab?.tabId && !isNewTabWindow
|
||||
}
|
||||
app={tab}
|
||||
/>
|
||||
} // Pass custom component
|
||||
sx={{
|
||||
"&.Mui-selected": {
|
||||
color: "white",
|
||||
},
|
||||
padding: "0px",
|
||||
margin: "0px",
|
||||
minWidth: "0px",
|
||||
width: "50px",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
</AppsNavBarLeft>
|
||||
{selectedTab && (
|
||||
<AppsNavBarRight
|
||||
sx={{
|
||||
gap: "10px",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setSelectedTab(null);
|
||||
executeEvent("devModeNewTabWindow", {});
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
height: "40px",
|
||||
width: "40px",
|
||||
}}
|
||||
src={NavAdd}
|
||||
/>
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={(e) => {
|
||||
if (!selectedTab) return;
|
||||
handleClick(e);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
height: "34px",
|
||||
width: "34px",
|
||||
}}
|
||||
src={NavMoreMenu}
|
||||
/>
|
||||
</ButtonBase>
|
||||
</AppsNavBarRight>
|
||||
)}
|
||||
|
||||
<Menu
|
||||
id="navbar-more-mobile"
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
"aria-labelledby": "basic-button",
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
slotProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
backgroundColor: "var(--bg-primary)",
|
||||
color: "#fff",
|
||||
width: "148px",
|
||||
borderRadius: "5px",
|
||||
},
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
marginTop: "10px",
|
||||
}}
|
||||
>
|
||||
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
executeEvent("refreshApp", {
|
||||
tabId: selectedTab?.tabId,
|
||||
});
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
minWidth: "24px !important",
|
||||
marginRight: "5px",
|
||||
}}
|
||||
>
|
||||
<RefreshIcon
|
||||
height={20}
|
||||
sx={{
|
||||
color: "rgba(250, 250, 250, 0.5)",
|
||||
}}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
sx={{
|
||||
"& .MuiTypography-root": {
|
||||
fontSize: "12px",
|
||||
fontWeight: 600,
|
||||
color: "rgba(250, 250, 250, 0.5)",
|
||||
},
|
||||
}}
|
||||
primary="Refresh"
|
||||
/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</AppsNavBarParent>
|
||||
);
|
||||
};
|
58
src/components/Apps/AppsDevModeTabComponent.tsx
Normal file
58
src/components/Apps/AppsDevModeTabComponent.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import React from 'react'
|
||||
import { TabParent } from './Apps-styles'
|
||||
import NavCloseTab from "../../assets/svgs/NavCloseTab.svg";
|
||||
import { getBaseApiReact } from '../../App';
|
||||
import { Avatar, ButtonBase } from '@mui/material';
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import { executeEvent } from '../../utils/events';
|
||||
|
||||
export const AppsDevModeTabComponent = ({isSelected, app}) => {
|
||||
return (
|
||||
<ButtonBase onClick={()=> {
|
||||
if(isSelected){
|
||||
executeEvent('removeTab', {
|
||||
data: app
|
||||
})
|
||||
return
|
||||
}
|
||||
executeEvent('setSelectedTab', {
|
||||
data: app
|
||||
})
|
||||
}}>
|
||||
<TabParent sx={{
|
||||
border: isSelected && '1px solid #FFFFFF'
|
||||
}}>
|
||||
{isSelected && (
|
||||
|
||||
<img style={
|
||||
{
|
||||
position: 'absolute',
|
||||
top: '-5px',
|
||||
right: '-5px',
|
||||
zIndex: 1
|
||||
}
|
||||
} src={NavCloseTab}/>
|
||||
|
||||
) }
|
||||
<Avatar
|
||||
sx={{
|
||||
height: "28px",
|
||||
width: "28px",
|
||||
}}
|
||||
alt=''
|
||||
src={``}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "28px",
|
||||
height: "auto",
|
||||
}}
|
||||
src={LogoSelected}
|
||||
alt="center-icon"
|
||||
/>
|
||||
</Avatar>
|
||||
</TabParent>
|
||||
</ButtonBase>
|
||||
)
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import { Add } from "@mui/icons-material";
|
||||
import { getBaseApiReact, isMobile } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
import { SortablePinnedApps } from "./SortablePinnedApps";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { SortablePinnedApps } from "./SortablePinnedApps";
|
||||
|
||||
export const AppsHomeDesktop = ({
|
||||
setMode,
|
||||
|
@ -383,7 +383,7 @@ const UIQortalRequests = [
|
||||
return obj; // Updated object with references to stored files
|
||||
}
|
||||
|
||||
export const useQortalMessageListener = (frameWindow, iframeRef, tabId) => {
|
||||
export const useQortalMessageListener = (frameWindow, iframeRef, tabId, isDevMode) => {
|
||||
const [path, setPath] = useState('')
|
||||
const [history, setHistory] = useState({
|
||||
customQDNHistoryPaths: [],
|
||||
@ -530,7 +530,7 @@ isDOMContentLoaded: false
|
||||
setHistory(event?.data?.payload)
|
||||
|
||||
}
|
||||
} else if(event?.data?.action === 'SET_TAB'){
|
||||
} else if(event?.data?.action === 'SET_TAB' && !isDevMode){
|
||||
executeEvent("addTab", {
|
||||
data: event?.data?.payload
|
||||
})
|
||||
@ -553,7 +553,7 @@ isDOMContentLoaded: false
|
||||
};
|
||||
|
||||
|
||||
}, []); // Empty dependency array to run once when the component mounts
|
||||
}, [isDevMode]); // Empty dependency array to run once when the component mounts
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,8 @@ import AppIcon from "../../assets/svgs/AppIcon.svg";
|
||||
|
||||
import { HomeIcon } from "../../assets/Icons/HomeIcon";
|
||||
import { Save } from "../Save/Save";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { enabledDevModeAtom } from "../../atoms/global";
|
||||
|
||||
export const IconWrapper = ({ children, label, color, selected }) => {
|
||||
return (
|
||||
@ -81,6 +83,7 @@ export const DesktopFooter = ({
|
||||
setIsOpenSideViewGroups
|
||||
|
||||
}) => {
|
||||
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
|
||||
|
||||
if(hide) return
|
||||
return (
|
||||
@ -179,6 +182,24 @@ export const DesktopFooter = ({
|
||||
</ButtonBase>
|
||||
|
||||
<Save isDesktop />
|
||||
{isEnabledDevMode && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode('dev')
|
||||
setIsOpenSideViewDirects(false)
|
||||
setIsOpenSideViewGroups(false)
|
||||
}}
|
||||
>
|
||||
<IconWrapper
|
||||
color="rgba(250, 250, 250, 0.5)"
|
||||
label="Dev Mode"
|
||||
selected={isApps}
|
||||
>
|
||||
<img src={AppIcon} />
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
@ -91,6 +91,7 @@ import { DesktopHeader } from "../Desktop/DesktopHeader";
|
||||
import { Apps } from "../Apps/Apps";
|
||||
import { AppsNavBar } from "../Apps/AppsNavBar";
|
||||
import { AppsDesktop } from "../Apps/AppsDesktop";
|
||||
import { AppsDevMode } from "../Apps/AppsDevMode";
|
||||
|
||||
// let touchStartY = 0;
|
||||
// let disablePullToRefresh = false;
|
||||
@ -437,6 +438,7 @@ export const Group = ({
|
||||
const initiatedGetMembers = useRef(false);
|
||||
const [groupChatTimestamps, setGroupChatTimestamps] = React.useState({});
|
||||
const [appsMode, setAppsMode] = useState('home')
|
||||
const [appsModeDev, setAppsModeDev] = useState('home')
|
||||
const [isOpenSideViewDirects, setIsOpenSideViewDirects] = useState(false)
|
||||
const [isOpenSideViewGroups, setIsOpenSideViewGroups] = useState(false)
|
||||
const toggleSideViewDirects = ()=> {
|
||||
@ -1553,6 +1555,8 @@ export const Group = ({
|
||||
}
|
||||
};
|
||||
|
||||
console.log('desktopViewMode', desktopViewMode)
|
||||
|
||||
const renderDirects = () => {
|
||||
return (
|
||||
<div
|
||||
@ -2021,8 +2025,8 @@ export const Group = ({
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
{!isMobile && ((desktopSideView === 'groups' && desktopViewMode !== 'apps') || isOpenSideViewGroups) && renderGroups()}
|
||||
{!isMobile && ((desktopSideView === 'directs' && desktopViewMode !== 'apps') || isOpenSideViewDirects) && renderDirects()}
|
||||
{!isMobile && ((desktopSideView === 'groups' && desktopViewMode !== 'apps' && desktopViewMode !== 'dev') || isOpenSideViewGroups) && renderGroups()}
|
||||
{!isMobile && ((desktopSideView === 'directs' && desktopViewMode !== 'apps' && desktopViewMode !== 'dev') || isOpenSideViewDirects) && renderDirects()}
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
@ -2480,13 +2484,13 @@ export const Group = ({
|
||||
hasUnreadDirects={directChatHasUnread}
|
||||
myName={userInfo?.name || null}
|
||||
isHome={groupSection === "home" && desktopViewMode === 'home'}
|
||||
isGroups={desktopSideView === 'groups' && desktopViewMode !== 'apps'}
|
||||
isDirects={desktopSideView === 'directs' && desktopViewMode !== 'apps'}
|
||||
isGroups={desktopSideView === 'groups' && desktopViewMode !== 'apps' && desktopViewMode !== 'apps'}
|
||||
isDirects={desktopSideView === 'directs' && desktopViewMode !== 'apps' && desktopViewMode !== 'apps'}
|
||||
setDesktopViewMode={setDesktopViewMode}
|
||||
isApps={desktopViewMode === 'apps'}
|
||||
setDesktopSideView={setDesktopSideView}
|
||||
desktopViewMode={desktopViewMode}
|
||||
hide={desktopViewMode === 'apps'}
|
||||
hide={desktopViewMode === 'apps' || desktopViewMode === 'dev'}
|
||||
setIsOpenSideViewDirects={setIsOpenSideViewDirects}
|
||||
setIsOpenSideViewGroups={setIsOpenSideViewGroups}
|
||||
/>
|
||||
@ -2515,10 +2519,15 @@ export const Group = ({
|
||||
isDirects={isOpenSideViewDirects} hasUnreadGroups={groupChatHasUnread ||
|
||||
groupsAnnHasUnread} />
|
||||
)}
|
||||
{!isMobile && (
|
||||
<AppsDevMode toggleSideViewGroups={toggleSideViewGroups} toggleSideViewDirects={toggleSideViewDirects} goToHome={goToHome} mode={appsModeDev} setMode={setAppsModeDev} setDesktopSideView={setDesktopSideView} hasUnreadDirects={directChatHasUnread} show={desktopViewMode === "dev"} myName={userInfo?.name} isGroups={isOpenSideViewGroups}
|
||||
isDirects={isOpenSideViewDirects} hasUnreadGroups={groupChatHasUnread ||
|
||||
groupsAnnHasUnread} />
|
||||
)}
|
||||
|
||||
|
||||
{!isMobile && !selectedGroup &&
|
||||
groupSection === "home" && desktopViewMode !== "apps" && (
|
||||
groupSection === "home" && desktopViewMode !== "apps" && desktopViewMode !== "dev" && (
|
||||
<HomeDesktop
|
||||
refreshHomeDataFunc={refreshHomeDataFunc}
|
||||
myAddress={myAddress}
|
||||
@ -2543,7 +2552,7 @@ export const Group = ({
|
||||
width: "31px",
|
||||
// minWidth: "135px",
|
||||
padding: "5px",
|
||||
display: (isMobile || desktopViewMode === 'apps') ? "none" : "flex",
|
||||
display: (isMobile || desktopViewMode === 'apps' || desktopViewMode === 'dev') ? "none" : "flex",
|
||||
}}
|
||||
>
|
||||
|
||||
|
@ -25,6 +25,8 @@ import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
|
||||
import { getFee } from "../../background";
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
||||
import { enabledDevModeAtom } from "../../atoms/global";
|
||||
import { useRecoilState } from "recoil";
|
||||
|
||||
function a11yProps(index: number) {
|
||||
return {
|
||||
@ -81,6 +83,9 @@ export const Settings = ({
|
||||
setOpen,
|
||||
}) => {
|
||||
const [checked, setChecked] = React.useState(false);
|
||||
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
|
||||
|
||||
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setChecked(event.target.checked);
|
||||
@ -166,29 +171,35 @@ export const Settings = ({
|
||||
flexGrow: 1,
|
||||
overflowY: "auto",
|
||||
color: "white",
|
||||
padding: '20px'
|
||||
padding: "20px",
|
||||
flexDirection: 'column',
|
||||
display: 'flex',
|
||||
gap: '20px'
|
||||
}}
|
||||
>
|
||||
|
||||
<FormControlLabel
|
||||
sx={{
|
||||
color: 'white'
|
||||
color: "white",
|
||||
}}
|
||||
control={<LocalNodeSwitch checked={checked}
|
||||
onChange={handleChange} />}
|
||||
control={
|
||||
<LocalNodeSwitch checked={checked} onChange={handleChange} />
|
||||
}
|
||||
label="Disable all push notifications"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormControlLabel
|
||||
sx={{
|
||||
color: "white",
|
||||
}}
|
||||
control={
|
||||
<LocalNodeSwitch checked={isEnabledDevMode} onChange={(e)=> {
|
||||
setIsEnabledDevMode(e.target.checked)
|
||||
localStorage.setItem('isEnabledDevMode', JSON.stringify(e.target.checked))
|
||||
}} />
|
||||
}
|
||||
label="Enable dev mode"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
</Dialog>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user