Adapt to theme

This commit is contained in:
Nicola Benaglia
2025-04-06 22:00:38 +02:00
parent 768d959d78
commit a792474f55
9 changed files with 766 additions and 701 deletions

View File

@@ -1,7 +1,13 @@
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import React, {
useContext,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { AppsHomeDesktop } from "./AppsHomeDesktop";
import { Spacer } from "../../common/Spacer";
import { GlobalContext, MyContext, getBaseApiReact } from "../../App";
import { GlobalContext, getBaseApiReact } from "../../App";
import { AppInfo } from "./AppInfo";
import {
executeEvent,
@@ -15,47 +21,58 @@ import { AppPublish } from "./AppPublish";
import { AppsLibraryDesktop } from "./AppsLibraryDesktop";
import { AppsCategoryDesktop } from "./AppsCategoryDesktop";
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
import { Box, ButtonBase } from "@mui/material";
import { Box, ButtonBase, useTheme } 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 { CoreSyncStatus } from "../CoreSyncStatus";
import { IconWrapper } from "../Desktop/DesktopFooter";
import AppIcon from "../../assets/svgs/AppIcon.svg";
import { useRecoilState } from "recoil";
import { enabledDevModeAtom } from "../../atoms/global";
import { AppsIcon } from "../../assets/Icons/AppsIcon";
const uid = new ShortUniqueId({ length: 8 });
export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktopSideView, hasUnreadDirects, isDirects, isGroups, hasUnreadGroups, toggleSideViewGroups, toggleSideViewDirects, setDesktopViewMode, isApps, desktopViewMode}) => {
export const AppsDesktop = ({
mode,
setMode,
show,
myName,
goToHome,
hasUnreadDirects,
hasUnreadGroups,
setDesktopViewMode,
desktopViewMode,
}) => {
const [availableQapps, setAvailableQapps] = useState([]);
const [selectedAppInfo, setSelectedAppInfo] = useState(null);
const [selectedCategory, setSelectedCategory] = 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 [categories, setCategories] = useState([]);
const iframeRefs = useRef({});
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
const [isEnabledDevMode, setIsEnabledDevMode] =
useRecoilState(enabledDevModeAtom);
const { showTutorial } = useContext(GlobalContext);
const theme = useTheme();
const myApp = useMemo(()=> {
return availableQapps.find((app)=> app.name === myName && app.service === 'APP')
}, [myName, availableQapps])
const myWebsite = useMemo(()=> {
return availableQapps.find((app)=> app.name === myName && app.service === 'WEBSITE')
}, [myName, availableQapps])
const myApp = useMemo(() => {
return availableQapps.find(
(app) => app.name === myName && app.service === "APP"
);
}, [myName, availableQapps]);
const myWebsite = useMemo(() => {
return availableQapps.find(
(app) => app.name === myName && app.service === "WEBSITE"
);
}, [myName, availableQapps]);
useEffect(()=> {
if(show){
showTutorial('qapps')
useEffect(() => {
if (show) {
showTutorial("qapps");
}
}, [show])
}, [show]);
useEffect(() => {
setTimeout(() => {
@@ -81,10 +98,10 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
});
if (!response?.ok) return;
const responseData = await response.json();
setCategories(responseData);
} catch (error) {
console.log(error);
} finally {
// dispatch(setIsLoadingGlobal(false))
}
@@ -115,18 +132,19 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
});
if (!responseWebsites?.ok) return;
const responseDataWebsites = await responseWebsites.json();
apps = responseData;
websites = responseDataWebsites;
const combine = [...apps, ...websites];
setAvailableQapps(combine);
} catch (error) {
console.log(error);
} finally {
// dispatch(setIsLoadingGlobal(false))
}
}, []);
useEffect(() => {
getCategories()
getCategories();
}, [getCategories]);
useEffect(() => {
@@ -163,12 +181,13 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
subscribeToEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
return () => {
unsubscribeFromEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
unsubscribeFromEvent(
"selectedAppInfoCategory",
selectedAppInfoCategoryFunc
);
};
}, []);
const selectedCategoryFunc = (e) => {
const data = e.detail?.data;
setSelectedCategory(data);
@@ -183,35 +202,37 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
};
}, []);
const navigateBackFunc = (e) => {
if (['category', 'appInfo-from-category', 'appInfo', 'library', 'publish'].includes(mode)) {
if (
[
"category",
"appInfo-from-category",
"appInfo",
"library",
"publish",
].includes(mode)
) {
// Handle the various modes as needed
if (mode === 'category') {
setMode('library');
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') {
} else if (mode === "appInfo-from-category") {
setMode("category");
} else if (mode === "appInfo") {
setMode("library");
} else if (mode === "library") {
if (isNewTabWindow) {
setMode('viewer');
setMode("viewer");
} else {
setMode('home');
setMode("home");
}
} else if (mode === 'publish') {
setMode('library');
} else if (mode === "publish") {
setMode("library");
}
} else if(selectedTab?.tabId) {
executeEvent(`navigateBackApp-${selectedTab?.tabId}`, {})
} else if (selectedTab?.tabId) {
executeEvent(`navigateBackApp-${selectedTab?.tabId}`, {});
}
};
useEffect(() => {
subscribeToEvent("navigateBack", navigateBackFunc);
@@ -234,8 +255,6 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
setIsNewTabWindow(false);
};
useEffect(() => {
subscribeToEvent("addTab", addTabFunc);
@@ -245,7 +264,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
}, [tabs]);
const setSelectedTabFunc = (e) => {
const data = e.detail?.data;
if(e.detail?.isDevMode) return
if (e.detail?.isDevMode) return;
setSelectedTab(data);
setTimeout(() => {
@@ -259,7 +278,6 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
}, 100);
setIsNewTabWindow(false);
};
useEffect(() => {
subscribeToEvent("setSelectedTab", setSelectedTabFunc);
@@ -299,7 +317,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
const setNewTabWindowFunc = (e) => {
setIsNewTabWindow(true);
setSelectedTab(null)
setSelectedTab(null);
};
useEffect(() => {
@@ -314,70 +332,65 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
<AppsParent
sx={{
display: !show && "none",
flexDirection: 'row'
flexDirection: "row",
}}
>
<Box sx={{
width: '60px',
flexDirection: 'column',
height: '100vh',
alignItems: 'center',
display: 'flex',
gap: '25px'
}}>
<Box
sx={{
width: "60px",
flexDirection: "column",
height: "100vh",
alignItems: "center",
display: "flex",
gap: "25px",
}}
>
<ButtonBase
sx={{
width: '60px',
height: '60px',
paddingTop: '23px'
width: "60px",
height: "60px",
paddingTop: "23px",
}}
onClick={() => {
goToHome();
}}
>
<HomeIcon
height={34}
color={desktopViewMode === 'home' ? 'white': "rgba(250, 250, 250, 0.5)"}
/>
<HomeIcon height={34} />
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('apps')
setDesktopViewMode("apps");
}}
>
<IconWrapper label="Apps" disableWidth>
<AppsIcon height={30} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode("chat");
}}
>
<IconWrapper
color={isApps ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Apps"
disableWidth
>
<AppsIcon height={30} color={isApps ? 'white' :"rgba(250, 250, 250, 0.5)"} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('chat')
}}
>
<IconWrapper
color={(hasUnreadDirects || hasUnreadGroups) ? "var(--unread)" : desktopViewMode === 'chat' ? 'white' :"rgba(250, 250, 250, 0.5)"}
color={
hasUnreadDirects || hasUnreadGroups
? "var(--unread)"
: theme.palette.text.primary
}
label="Chat"
disableWidth
>
<MessagingIcon
height={30}
color={
(hasUnreadDirects || hasUnreadGroups)
hasUnreadDirects || hasUnreadGroups
? "var(--unread)"
: desktopViewMode === 'chat'
? "white"
: "rgba(250, 250, 250, 0.5)"
: theme.palette.text.primary
}
/>
</IconWrapper>
</IconWrapper>
</ButtonBase>
{/* <ButtonBase
onClick={() => {
@@ -416,65 +429,78 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
/>
</ButtonBase> */}
<Save isDesktop disableWidth myName={myName}/>
<Save isDesktop disableWidth myName={myName} />
{isEnabledDevMode && (
<ButtonBase
onClick={() => {
setDesktopViewMode('dev')
}}
>
<IconWrapper
color={desktopViewMode === 'dev' ? 'white' : "rgba(250, 250, 250, 0.5)"}
label="Dev"
disableWidth
>
<AppsIcon color={desktopViewMode === 'dev' ? 'white' : "rgba(250, 250, 250, 0.5)"} height={30} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode("dev");
}}
>
<IconWrapper label="Dev" disableWidth>
<AppsIcon height={30} />
</IconWrapper>
</ButtonBase>
)}
{mode !== 'home' && (
<AppsNavBarDesktop disableBack={isNewTabWindow && mode === 'viewer'} />
{mode !== "home" && (
<AppsNavBarDesktop
disableBack={isNewTabWindow && mode === "viewer"}
/>
)}
</Box>
</Box>
{mode === "home" && (
<Box sx={{
display: 'flex',
width: '100%',
flexDirection: 'column',
height: '100vh',
overflow: 'auto'
}}>
<Spacer height="30px" />
<AppsHomeDesktop myName={myName} availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
<Box
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
height: "100vh",
overflow: "auto",
}}
>
<Spacer height="30px" />
<AppsHomeDesktop
myName={myName}
availableQapps={availableQapps}
setMode={setMode}
myApp={myApp}
myWebsite={myWebsite}
/>
</Box>
)}
<AppsLibraryDesktop
<AppsLibraryDesktop
isShow={mode === "library" && !selectedTab}
availableQapps={availableQapps}
setMode={setMode}
myName={myName}
hasPublishApp={!!(myApp || myWebsite)}
categories={categories}
getQapps={getQapps}
/>
{mode === "appInfo" && !selectedTab && <AppInfo app={selectedAppInfo} myName={myName} />}
{mode === "appInfo-from-category" && !selectedTab && <AppInfo app={selectedAppInfo} myName={myName} />}
<AppsCategoryDesktop availableQapps={availableQapps} isShow={mode === 'category' && !selectedTab} category={selectedCategory} myName={myName} />
{mode === "publish" && !selectedTab && <AppPublish names={myName ? [myName] : []} categories={categories} />}
availableQapps={availableQapps}
setMode={setMode}
myName={myName}
hasPublishApp={!!(myApp || myWebsite)}
categories={categories}
getQapps={getQapps}
/>
{mode === "appInfo" && !selectedTab && (
<AppInfo app={selectedAppInfo} myName={myName} />
)}
{mode === "appInfo-from-category" && !selectedTab && (
<AppInfo app={selectedAppInfo} myName={myName} />
)}
<AppsCategoryDesktop
availableQapps={availableQapps}
isShow={mode === "category" && !selectedTab}
category={selectedCategory}
myName={myName}
/>
{mode === "publish" && !selectedTab && (
<AppPublish names={myName ? [myName] : []} categories={categories} />
)}
{tabs.map((tab) => {
if (!iframeRefs.current[tab.tabId]) {
iframeRefs.current[tab.tabId] = React.createRef();
}
return (
<AppViewerContainer
key={tab?.tabId}
key={tab?.tabId}
hide={isNewTabWindow}
isSelected={tab?.tabId === selectedTab?.tabId}
app={tab}
@@ -486,16 +512,23 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
{isNewTabWindow && mode === "viewer" && (
<>
<Box sx={{
display: 'flex',
width: '100%',
flexDirection: 'column',
height: '100vh',
overflow: 'auto'
}}>
<Spacer height="30px" />
<AppsHomeDesktop myName={myName} availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
<Box
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
height: "100vh",
overflow: "auto",
}}
>
<Spacer height="30px" />
<AppsHomeDesktop
myName={myName}
availableQapps={availableQapps}
setMode={setMode}
myApp={myApp}
myWebsite={myWebsite}
/>
</Box>
</>
)}

View File

@@ -1,17 +1,6 @@
import * as React from "react";
import {
BottomNavigation,
BottomNavigationAction,
ButtonBase,
Typography,
} from "@mui/material";
import { Home, Groups, Message, ShowChart } from "@mui/icons-material";
import { ButtonBase, Typography, useTheme } from "@mui/material";
import Box from "@mui/material/Box";
import BottomLogo from "../../assets/svgs/BottomLogo5.svg";
import { CustomSvg } from "../../common/CustomSvg";
import { WalletIcon } from "../../assets/Icons/WalletIcon";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { TradingIcon } from "../../assets/Icons/TradingIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import AppIcon from "../../assets/svgs/AppIcon.svg";
@@ -20,19 +9,31 @@ import { Save } from "../Save/Save";
import { useRecoilState } from "recoil";
import { enabledDevModeAtom } from "../../atoms/global";
export const IconWrapper = ({ children, label, color, selected, disableWidth, customWidth }) => {
export const IconWrapper = ({
children,
label,
color,
selected,
disableWidth,
customWidth,
}) => {
const theme = useTheme();
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "5px",
gap: "5px",
flexDirection: "column",
height: customWidth ? customWidth : disableWidth ? 'auto' : "89px",
width: customWidth? customWidth : disableWidth ? 'auto' : "89px",
height: customWidth ? customWidth : disableWidth ? "auto" : "89px",
width: customWidth ? customWidth : disableWidth ? "auto" : "89px",
borderRadius: "50%",
backgroundColor: selected ? "rgba(28, 29, 32, 1)" : "transparent",
backgroundColor: selected
? theme.palette.background.default
: "transparent",
color: color ? color : theme.palette.text.primary,
}}
>
{children}
@@ -41,7 +42,7 @@ export const IconWrapper = ({ children, label, color, selected, disableWidth, cu
fontFamily: "Inter",
fontSize: "12px",
fontWeight: 500,
color: color,
color: theme.palette.text.primary,
}}
>
{label}
@@ -51,24 +52,7 @@ export const IconWrapper = ({ children, label, color, selected, disableWidth, cu
};
export const DesktopFooter = ({
selectedGroup,
groupSection,
isUnread,
goToAnnouncements,
isUnreadChat,
goToChat,
goToThreads,
setOpenManageMembers,
groupChatHasUnread,
groupsAnnHasUnread,
directChatHasUnread,
chatMode,
openDrawerGroups,
goToHome,
setIsOpenDrawerProfile,
mobileViewMode,
setMobileViewMode,
setMobileViewModeKeepOpen,
hasUnreadGroups,
hasUnreadDirects,
isHome,
@@ -77,15 +61,14 @@ export const DesktopFooter = ({
setDesktopSideView,
isApps,
setDesktopViewMode,
desktopViewMode,
hide,
setIsOpenSideViewDirects,
setIsOpenSideViewGroups
setIsOpenSideViewGroups,
}) => {
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
const [isEnabledDevMode, setIsEnabledDevMode] =
useRecoilState(enabledDevModeAtom);
if(hide) return
if (hide) return;
return (
<Box
sx={{
@@ -110,42 +93,31 @@ export const DesktopFooter = ({
goToHome();
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Home"
selected={isHome}
>
<IconWrapper label="Home" selected={isHome}>
<HomeIcon
height={30}
color={isHome ? "white" : "rgba(250, 250, 250, 0.5)"}
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('apps')
setIsOpenSideViewDirects(false)
setIsOpenSideViewGroups(false)
setDesktopViewMode("apps");
setIsOpenSideViewDirects(false);
setIsOpenSideViewGroups(false);
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Apps"
selected={isApps}
>
<img src={AppIcon} />
<IconWrapper label="Apps" selected={isApps}>
<img src={AppIcon} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("groups");
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Groups"
selected={isGroups}
>
<IconWrapper label="Groups" selected={isGroups}>
<HubsIcon
height={30}
color={
@@ -158,16 +130,13 @@ export const DesktopFooter = ({
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("directs");
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Messaging"
selected={isDirects}
>
<IconWrapper label="Messaging" selected={isDirects}>
<MessagingIcon
height={30}
color={
@@ -180,26 +149,21 @@ export const DesktopFooter = ({
/>
</IconWrapper>
</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}
onClick={() => {
setDesktopViewMode("dev");
setIsOpenSideViewDirects(false);
setIsOpenSideViewGroups(false);
}}
>
<img src={AppIcon} />
</IconWrapper>
</ButtonBase>
<IconWrapper label="Dev Mode" selected={isApps}>
<img src={AppIcon} />
</IconWrapper>
</ButtonBase>
)}
</Box>
</Box>
);

View File

@@ -1,12 +1,8 @@
import { Box, ButtonBase } from "@mui/material";
import React from "react";
import { Box, ButtonBase, useTheme } 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 { CoreSyncStatus } from "./CoreSyncStatus";
import { IconWrapper } from "./Desktop/DesktopFooter";
import AppIcon from "./../assets/svgs/AppIcon.svg";
import { useRecoilState } from "recoil";
import { enabledDevModeAtom } from "../atoms/global";
import { AppsIcon } from "../assets/Icons/AppsIcon";
@@ -28,6 +24,8 @@ export const DesktopSideBar = ({
}) => {
const [isEnabledDevMode, setIsEnabledDevMode] =
useRecoilState(enabledDevModeAtom);
const theme = useTheme();
return (
<Box
@@ -52,9 +50,6 @@ export const DesktopSideBar = ({
>
<HomeIcon
height={34}
color={
desktopViewMode === "home" ? "white" : "rgba(250, 250, 250, 0.5)"
}
/>
</ButtonBase>
<ButtonBase
@@ -65,17 +60,16 @@ export const DesktopSideBar = ({
}}
>
<IconWrapper
color={isApps ? "white" : "rgba(250, 250, 250, 0.5)"}
label="Apps"
selected={isApps}
disableWidth
>
<AppsIcon
color={isApps ? "white" : "rgba(250, 250, 250, 0.5)"}
height={30}
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode("chat");
@@ -85,9 +79,7 @@ export const DesktopSideBar = ({
color={
hasUnreadDirects || hasUnreadGroups
? "var(--unread)"
: desktopViewMode === "chat"
? "white"
: "rgba(250, 250, 250, 0.5)"
: theme.palette.text.primary
}
label="Chat"
disableWidth
@@ -97,9 +89,7 @@ export const DesktopSideBar = ({
color={
hasUnreadDirects || hasUnreadGroups
? "var(--unread)"
: desktopViewMode === "chat"
? "white"
: "rgba(250, 250, 250, 0.5)"
: theme.palette.text.primary
}
/>
</IconWrapper>
@@ -131,16 +121,10 @@ export const DesktopSideBar = ({
}}
>
<IconWrapper
color={
desktopViewMode === "dev" ? "white" : "rgba(250, 250, 250, 0.5)"
}
label="Dev"
disableWidth
>
<AppsIcon
color={
desktopViewMode === "dev" ? "white" : "rgba(250, 250, 250, 0.5)"
}
height={30}
/>
</IconWrapper>

View File

@@ -20,7 +20,7 @@ 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 CloseFullscreenIcon from "@mui/icons-material/CloseFullscreen";
import { useRecoilState } from "recoil";
import { fullScreenAtom, hasSettingsChangedAtom } from "../../atoms/global";
import { useAppFullScreen } from "../../useAppFullscreen";
@@ -36,12 +36,12 @@ const Header = ({
setMobileViewMode,
myName,
setSelectedDirect,
setNewChat
setNewChat,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
const {exitFullScreen} = useAppFullScreen(setFullScreen)
const { exitFullScreen } = useAppFullScreen(setFullScreen);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
@@ -77,34 +77,39 @@ const Header = ({
}}
>
<ButtonBase
onClick={() => {
setMobileViewModeKeepOpen("");
goToHome();
}}
// onClick={onHomeClick}
>
<HomeIcon height={20} width={27} color="rgba(145, 145, 147, 1)" />
<HomeIcon height={20} width={27} />
</ButtonBase>
<ButtonBase
onClick={handleClick}
>
<NotificationIcon height={20} width={21} color={hasUnreadDirects || hasUnreadGroups ? "var(--danger)" : "rgba(145, 145, 147, 1)"} />
<ButtonBase onClick={handleClick}>
<NotificationIcon
height={20}
width={21}
color={
hasUnreadDirects || hasUnreadGroups
? "var(--danger)"
: "rgba(145, 145, 147, 1)"
}
/>
</ButtonBase>
{fullScreen && (
<ButtonBase onClick={()=> {
exitFullScreen()
setFullScreen(false)
}}>
<CloseFullscreenIcon sx={{
color: 'rgba(145, 145, 147, 1)'
}} />
</ButtonBase>
<ButtonBase
onClick={() => {
exitFullScreen();
setFullScreen(false);
}}
>
<CloseFullscreenIcon
sx={{
color: "rgba(145, 145, 147, 1)",
}}
/>
</ButtonBase>
)}
</Box>
{/* Center Title */}
@@ -135,14 +140,15 @@ const Header = ({
setMobileViewModeKeepOpen("messaging");
}}
>
<MessagingIcon2 height={20} color={hasUnreadDirects ? "var(--danger)" : "rgba(145, 145, 147, 1)"}
<MessagingIcon2
height={20}
color={
hasUnreadDirects ? "var(--danger)" : "rgba(145, 145, 147, 1)"
}
/>
</ButtonBase>
<Save />
<ButtonBase
onClick={logoutFunc}
>
<ButtonBase onClick={logoutFunc}>
<LogoutIcon
height={20}
width={21}
@@ -152,83 +158,104 @@ const Header = ({
</Box>
</Toolbar>
<Menu
id="home-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
id="home-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
vertical: "top",
horizontal: "center",
}}
slotProps={{
paper: {
sx: {
backgroundColor: 'var(--bg-primary)',
color: '#fff',
width: '148px',
borderRadius: '5px'
backgroundColor: "var(--bg-primary)",
color: "#fff",
width: "148px",
borderRadius: "5px",
},
},
}}
sx={{
marginTop: '10px'
}}
>
<MenuItem
onClick={() => {
setSelectedDirect(null)
setNewChat(false)
setMobileViewMode("groups");
setMobileViewModeKeepOpen("")
handleClose();
marginTop: "10px",
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<HubsIcon height={20} color={hasUnreadGroups ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadGroups ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Groups" />
</MenuItem>
<MenuItem
onClick={() => {
setMobileViewModeKeepOpen("messaging");
<MenuItem
onClick={() => {
setSelectedDirect(null);
setNewChat(false);
setMobileViewMode("groups");
setMobileViewModeKeepOpen("");
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: "24px !important",
}}
>
<HubsIcon
height={20}
color={
hasUnreadGroups ? "var(--danger)" : "rgba(250, 250, 250, 0.5)"
}
/>
</ListItemIcon>
<ListItemText
sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadGroups
? "var(--danger)"
: "rgba(250, 250, 250, 0.5)",
},
}}
primary="Groups"
/>
</MenuItem>
<MenuItem
onClick={() => {
setMobileViewModeKeepOpen("messaging");
handleClose();
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<MessagingIcon height={20} color={hasUnreadDirects ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Messaging" />
</MenuItem>
</Menu>
handleClose();
}}
>
<ListItemIcon
sx={{
minWidth: "24px !important",
}}
>
<MessagingIcon
height={20}
color={
hasUnreadDirects
? "var(--danger)"
: "rgba(250, 250, 250, 0.5)"
}
/>
</ListItemIcon>
<ListItemText
sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects
? "var(--danger)"
: "rgba(250, 250, 250, 0.5)",
},
}}
primary="Messaging"
/>
</MenuItem>
</Menu>
</AppBar>
);
}
@@ -255,24 +282,27 @@ const Header = ({
width: "75px",
}}
>
<ButtonBase
onClick={goToHome}
// onClick={onHomeClick}
>
<HomeIcon color="rgba(145, 145, 147, 1)" />
</ButtonBase>
{fullScreen && (
<ButtonBase onClick={()=> {
exitFullScreen()
setFullScreen(false)
}}>
<CloseFullscreenIcon sx={{
color: 'rgba(145, 145, 147, 1)'
}} />
</ButtonBase>
<ButtonBase
onClick={goToHome}
// onClick={onHomeClick}
>
<HomeIcon />
</ButtonBase>
{fullScreen && (
<ButtonBase
onClick={() => {
exitFullScreen();
setFullScreen(false);
}}
>
<CloseFullscreenIcon
sx={{
color: "rgba(145, 145, 147, 1)",
}}
/>
</ButtonBase>
)}
</Box>
</Box>
{/* Center Title */}
<Typography
variant="h6"
@@ -294,16 +324,15 @@ const Header = ({
justifyContent: "flex-end",
}}
>
{/* Right Logout Icon */}
<Save />
<ButtonBase
onClick={logoutFunc}
{/* Right Logout Icon */}
<Save />
<ButtonBase
onClick={logoutFunc}
// onClick={onLogoutClick}
>
<LogoutIcon color="rgba(145, 145, 147, 1)" />
</ButtonBase>
// onClick={onLogoutClick}
>
<LogoutIcon color="rgba(145, 145, 147, 1)" />
</ButtonBase>
</Box>
</Toolbar>
</AppBar>
@@ -357,8 +386,14 @@ const Header = ({
boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.3)", // Optional shadow for the circle
}}
>
<IconButton onClick={handleClick} color="inherit">
<NotificationIcon color={hasUnreadDirects || hasUnreadGroups ? "var(--danger)" : "rgba(255, 255, 255, 1)"} />
<IconButton onClick={handleClick} color="inherit">
<NotificationIcon
color={
hasUnreadDirects || hasUnreadGroups
? "var(--danger)"
: "rgba(255, 255, 255, 1)"
}
/>
</IconButton>
</Box>
@@ -389,6 +424,7 @@ const Header = ({
</Box>
</ButtonBase> */}
</Box>
<Menu
id="home-menu"
anchorEl={anchorEl}
@@ -398,51 +434,60 @@ const Header = ({
"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'
},
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'
}}
},
}}
sx={{
marginTop: "10px",
}}
>
<MenuItem
onClick={() => {
setMobileViewMode("groups");
setMobileViewModeKeepOpen("")
setMobileViewModeKeepOpen("");
handleClose();
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<HubsIcon height={20} color={hasUnreadGroups ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"} />
<ListItemIcon
sx={{
minWidth: "24px !important",
}}
>
<HubsIcon
height={20}
color={
hasUnreadGroups ? "var(--danger)" : "rgba(250, 250, 250, 0.5)"
}
/>
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Groups" />
<ListItemText
sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects
? "var(--danger)"
: "rgba(250, 250, 250, 0.5)",
},
}}
primary="Groups"
/>
</MenuItem>
<MenuItem
onClick={() => {
setMobileViewModeKeepOpen("messaging");
@@ -450,21 +495,32 @@ const Header = ({
handleClose();
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<MessagingIcon height={20} color={hasUnreadDirects ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"} />
<ListItemIcon
sx={{
minWidth: "24px !important",
}}
>
<MessagingIcon
height={20}
color={
hasUnreadDirects ? "var(--danger)" : "rgba(250, 250, 250, 0.5)"
}
/>
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--danger)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Messaging" />
<ListItemText
sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects
? "var(--danger)"
: "rgba(250, 250, 250, 0.5)",
},
}}
primary="Messaging"
/>
</MenuItem>
</Menu>
</Menu>
</>
);
};

View File

@@ -22,20 +22,22 @@ import { LoadingButton } from "@mui/lab";
import { saveToLocalStorage } from "../Apps/AppsNavBar";
import { decryptData, encryptData } from "../../qortalRequests/get";
import { saveFileToDiskGeneric } from "../../utils/generateWallet/generateWallet";
import { base64ToUint8Array, uint8ArrayToObject } from "../../backgroundFunctions/encryption";
import {
base64ToUint8Array,
uint8ArrayToObject,
} from "../../backgroundFunctions/encryption";
export const handleImportClick = async () => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.base64,.txt';
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = ".base64,.txt";
// Create a promise to handle file selection and reading synchronously
return await new Promise((resolve, reject) => {
fileInput.onchange = () => {
const file = fileInput.files[0];
if (!file) {
reject(new Error('No file selected'));
reject(new Error("No file selected"));
return;
}
@@ -44,7 +46,7 @@ export const handleImportClick = async () => {
resolve(e.target.result); // Resolve with the file content
};
reader.onerror = () => {
reject(new Error('Error reading file'));
reject(new Error("Error reading file"));
};
reader.readAsText(file); // Read the file as text (Base64 string)
@@ -53,8 +55,7 @@ export const handleImportClick = async () => {
// Trigger the file input dialog
fileInput.click();
});
}
};
export const Save = ({ isDesktop, disableWidth, myName }) => {
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
@@ -65,7 +66,8 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
settingsLocalLastUpdatedAtom
);
const setHasSettingsChangedAtom = useSetRecoilState(hasSettingsChangedAtom);
const [isUsingImportExportSettings, setIsUsingImportExportSettings] = useRecoilState(isUsingImportExportSettingsAtom);
const [isUsingImportExportSettings, setIsUsingImportExportSettings] =
useRecoilState(isUsingImportExportSettingsAtom);
const [canSave] = useRecoilState(canSaveSettingToQdnAtom);
const [openSnack, setOpenSnack] = useState(false);
@@ -104,8 +106,6 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
settingsLocalLastUpdated,
]);
useEffect(() => {
setHasSettingsChangedAtom(hasChanged);
}, [hasChanged]);
@@ -176,7 +176,7 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
message: "Sucessfully published to QDN",
});
setOpenSnack(true);
setAnchorEl(null)
setAnchorEl(null);
}
}
} catch (error) {
@@ -197,7 +197,7 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
const revertChanges = () => {
setPinnedApps(oldPinnedApps);
saveToLocalStorage("ext_saved_settings", "sortablePinnedApps", null);
setAnchorEl(null)
setAnchorEl(null);
};
return (
@@ -207,37 +207,22 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
disabled={
// !hasChanged ||
// !canSave ||
isLoading
isLoading
// settingsQdnLastUpdated === -100
}
>
{isDesktop ? (
<IconWrapper
disableWidth={disableWidth}
color="rgba(250, 250, 250, 0.5)"
label="Save"
selected={false}
>
<SaveIcon
color={
settingsQdnLastUpdated === -100
? "#8F8F91"
: hasChanged && !isLoading
? "#5EB049"
: "#8F8F91"
}
color={hasChanged && !isLoading ? "#5EB049" : undefined}
/>
</IconWrapper>
) : (
<SaveIcon
color={
settingsQdnLastUpdated === -100
? "#8F8F91"
: hasChanged && !isLoading
? "#5EB049"
: "#8F8F91"
}
/>
<SaveIcon color={hasChanged && !isLoading ? "#5EB049" : undefined} />
)}
</ButtonBase>
<Popover
@@ -261,15 +246,15 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
>
{isUsingImportExportSettings && (
<Box
sx={{
padding: "15px",
display: "flex",
flexDirection: "column",
gap: 1,
width: '100%'
}}
>
<Box
sx={{
padding: "15px",
display: "flex",
flexDirection: "column",
gap: 1,
width: "100%",
}}
>
<Box
sx={{
width: "100%",
display: "flex",
@@ -286,59 +271,45 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
</Typography>
<Spacer height="40px" />
<Button
size="small"
onClick={()=> {
saveToLocalStorage("ext_saved_settings_import_export", "sortablePinnedApps", null, true);
setIsUsingImportExportSettings(false)
}}
variant="contained"
sx={{
size="small"
onClick={() => {
saveToLocalStorage(
"ext_saved_settings_import_export",
"sortablePinnedApps",
null,
true
);
setIsUsingImportExportSettings(false);
}}
variant="contained"
sx={{
backgroundColor: "var(--danger)",
color: "black",
fontWeight: "bold",
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
fontWeight: 'bold',
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
opacity: 1,
},
}}
>
Use QDN saving
</Button>
</Box>
</Box>
opacity: 1,
},
}}
>
Use QDN saving
</Button>
</Box>
</Box>
)}
{!isUsingImportExportSettings && (
<Box
<Box
sx={{
padding: "15px",
display: "flex",
flexDirection: "column",
gap: 1,
width: '100%'
width: "100%",
}}
>
{!myName ? (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
You need a registered Qortal name to save your pinned apps to QDN.
</Typography>
</Box>
) : (
<>
{hasChanged && (
<Box
sx={{
width: "100%",
@@ -352,213 +323,242 @@ export const Save = ({ isDesktop, disableWidth, myName }) => {
fontSize: "14px",
}}
>
You have unsaved changes to your pinned apps. Save them to QDN.
You need a registered Qortal name to save your pinned apps to
QDN.
</Typography>
<Spacer height="10px" />
<LoadingButton
sx={{
backgroundColor: "var(--green)",
color: "black",
opacity: 0.7,
fontWeight: 'bold',
"&:hover": {
backgroundColor: "var(--green)",
color: "black",
opacity: 1,
},
}}
size="small"
loading={isLoading}
onClick={saveToQdn}
variant="contained"
>
Save to QDN
</LoadingButton>
<Spacer height="20px" />
{!isNaN(settingsQdnLastUpdated) && settingsQdnLastUpdated > 0 && (
<>
</Box>
) : (
<>
{hasChanged && (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
Don't like your current local changes? Would you like to
reset to your saved QDN pinned apps?
You have unsaved changes to your pinned apps. Save them to
QDN.
</Typography>
<Spacer height="10px" />
<LoadingButton
size="small"
loading={isLoading}
onClick={revertChanges}
variant="contained"
sx={{
backgroundColor: "var(--danger)",
backgroundColor: "var(--green)",
color: "black",
fontWeight: 'bold',
opacity: 0.7,
fontWeight: "bold",
"&:hover": {
backgroundColor: "var(--danger)",
backgroundColor: "var(--green)",
color: "black",
opacity: 1,
},
}}
size="small"
loading={isLoading}
onClick={saveToQdn}
variant="contained"
>
Revert to QDN
Save to QDN
</LoadingButton>
</>
<Spacer height="20px" />
{!isNaN(settingsQdnLastUpdated) &&
settingsQdnLastUpdated > 0 && (
<>
<Typography
sx={{
fontSize: "14px",
}}
>
Don't like your current local changes? Would you
like to reset to your saved QDN pinned apps?
</Typography>
<Spacer height="10px" />
<LoadingButton
size="small"
loading={isLoading}
onClick={revertChanges}
variant="contained"
sx={{
backgroundColor: "var(--danger)",
color: "black",
fontWeight: "bold",
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
opacity: 1,
},
}}
>
Revert to QDN
</LoadingButton>
</>
)}
{!isNaN(settingsQdnLastUpdated) &&
settingsQdnLastUpdated === 0 && (
<>
<Typography
sx={{
fontSize: "14px",
}}
>
Don't like your current local changes? Would you
like to reset to the default pinned apps?
</Typography>
<Spacer height="10px" />
<LoadingButton
loading={isLoading}
onClick={revertChanges}
variant="contained"
>
Revert to default
</LoadingButton>
</>
)}
</Box>
)}
{!isNaN(settingsQdnLastUpdated) && settingsQdnLastUpdated === 0 && (
<>
{!isNaN(settingsQdnLastUpdated) &&
settingsQdnLastUpdated === -100 &&
isUsingImportExportSettings !== true && (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
The app was unable to download your existing QDN-saved
pinned apps. Would you like to overwrite those changes?
</Typography>
<Spacer height="10px" />
<LoadingButton
size="small"
loading={isLoading}
onClick={saveToQdn}
variant="contained"
sx={{
backgroundColor: "var(--danger)",
color: "black",
fontWeight: "bold",
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
opacity: 1,
},
}}
>
Overwrite to QDN
</LoadingButton>
</Box>
)}
{!hasChanged && (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
Don't like your current local changes? Would you like to
reset to the default pinned apps?
You currently do not have any changes to your pinned apps
</Typography>
<Spacer height="10px" />
<LoadingButton
loading={isLoading}
onClick={revertChanges}
variant="contained"
>
Revert to default
</LoadingButton>
</>
</Box>
)}
</Box>
)}
{!isNaN(settingsQdnLastUpdated) && settingsQdnLastUpdated === -100 && isUsingImportExportSettings !== true && (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
The app was unable to download your existing QDN-saved pinned
apps. Would you like to overwrite those changes?
</Typography>
<Spacer height="10px" />
<LoadingButton
size="small"
loading={isLoading}
onClick={saveToQdn}
variant="contained"
sx={{
backgroundColor: "var(--danger)",
color: "black",
fontWeight: 'bold',
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
opacity: 1,
},
}}
>
Overwrite to QDN
</LoadingButton>
</Box>
)}
{!hasChanged && (
<Box
sx={{
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
}}
>
You currently do not have any changes to your pinned apps
</Typography>
</Box>
)}
</>
)}
</Box>
)}
<Box
<Box
sx={{
padding: "15px",
display: "flex",
flexDirection: "column",
gap: 1,
width: "100%",
}}
>
<Box
sx={{
padding: "15px",
display: "flex",
flexDirection: "column",
gap: 1,
width: '100%'
gap: "10px",
justifyContent: "flex-end",
width: "100%",
}}
>
<Box sx={{
display: 'flex',
gap: '10px',
justifyContent: 'flex-end',
width: '100%'
}}>
<ButtonBase onClick={async () => {
try {
const fileContent = await handleImportClick();
const decryptedData = await decryptData({
encryptedData: fileContent,
});
const decryptToUnit8ArraySubject =
base64ToUint8Array(decryptedData);
const responseData = uint8ArrayToObject(
decryptToUnit8ArraySubject
);
if(Array.isArray(responseData)){
saveToLocalStorage("ext_saved_settings_import_export", "sortablePinnedApps", responseData, {
isUsingImportExport: true
});
setPinnedApps(responseData)
setOldPinnedApps(responseData)
setIsUsingImportExportSettings(true)
}
} catch (error) {
console.log("error", error);
<ButtonBase
onClick={async () => {
try {
const fileContent = await handleImportClick();
const decryptedData = await decryptData({
encryptedData: fileContent,
});
const decryptToUnit8ArraySubject =
base64ToUint8Array(decryptedData);
const responseData = uint8ArrayToObject(
decryptToUnit8ArraySubject
);
if (Array.isArray(responseData)) {
saveToLocalStorage(
"ext_saved_settings_import_export",
"sortablePinnedApps",
responseData,
{
isUsingImportExport: true,
}
}}>
Import
</ButtonBase>
<ButtonBase onClick={async () => {
try {
const data64 = await objectToBase64(pinnedApps);
const encryptedData = await encryptData({
data64,
});
const blob = new Blob([encryptedData], {
type: "text/plain",
});
const timestamp = new Date()
.toISOString()
.replace(/:/g, "-"); // Safe timestamp for filenames
const filename = `qortal-new-ui-backup-settings-${timestamp}.txt`;
await saveFileToDiskGeneric(blob, filename)
} catch (error) {
console.log('error', error)
}
}}>
Export
);
setPinnedApps(responseData);
setOldPinnedApps(responseData);
setIsUsingImportExportSettings(true);
}
} catch (error) {
console.log("error", error);
}
}}
>
Import
</ButtonBase>
</Box>
</Box>
<ButtonBase
onClick={async () => {
try {
const data64 = await objectToBase64(pinnedApps);
const encryptedData = await encryptData({
data64,
});
const blob = new Blob([encryptedData], {
type: "text/plain",
});
const timestamp = new Date().toISOString().replace(/:/g, "-"); // Safe timestamp for filenames
const filename = `qortal-new-ui-backup-settings-${timestamp}.txt`;
await saveFileToDiskGeneric(blob, filename);
} catch (error) {
console.log("error", error);
}
}}
>
Export
</ButtonBase>
</Box>
</Box>
</Popover>
<CustomizedSnackbars
duration={3500}