finished apps feature for mobile

This commit is contained in:
PhilReact 2024-10-21 11:40:45 +03:00
parent 44c6b5ad32
commit 6b3a1f51ba
23 changed files with 762 additions and 365 deletions

View File

@ -576,7 +576,6 @@ const showSaveFilePicker = async (data) => {
}
chrome.runtime?.onMessage.addListener( function (message, sender, sendResponse) {
console.log('message', message)
if (message.type === "LOGOUT") {
// Notify the web page
window.postMessage(
@ -812,7 +811,6 @@ if (!window.hasAddedQortalListener) {
const sendMessageToRuntime = (message, eventPort) => {
chrome?.runtime?.sendMessage(message, (response) => {
console.log('response', response);
if (response.error) {
eventPort.postMessage({
result: null,
@ -829,13 +827,11 @@ if (!window.hasAddedQortalListener) {
// Check if action is included in the predefined list of UI requests
if (UIQortalRequests.includes(event.data.action)) {
console.log('event?.data', event?.data);
sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: event.data },
event.ports[0]
);
} else if (event?.data?.action === 'PUBLISH_MULTIPLE_QDN_RESOURCES' || event?.data?.action === 'PUBLISH_QDN_RESOURCE' || event?.data?.action === 'ENCRYPT_DATA' || event?.data?.action === 'SAVE_FILE') {
console.log('event?.data?', event?.data)
let data;
try {
data = await storeFilesInIndexedDB(event.data);

View File

@ -100,8 +100,9 @@ import { Settings } from "./components/Group/Settings";
import { MainAvatar } from "./components/MainAvatar";
import { useRetrieveDataLocalStorage } from "./useRetrieveDataLocalStorage";
import { useQortalGetSaveSettings } from "./useQortalGetSaveSettings";
import { useResetRecoilState } from "recoil";
import { canSaveSettingToQdnAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from "./atoms/global";
import { useRecoilState, useResetRecoilState } from "recoil";
import { canSaveSettingToQdnAtom, fullScreenAtom, hasSettingsChangedAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from "./atoms/global";
import { useAppFullScreen } from "./useAppFullscreen";
type extStates =
| "not-authenticated"
@ -297,10 +298,12 @@ function App() {
const [txList, setTxList] = useState([]);
const [memberGroups, setMemberGroups] = useState([]);
const [isFocused, setIsFocused] = useState(true);
const [hasSettingsChanged, setHasSettingsChanged] = useRecoilState(hasSettingsChangedAtom)
const holdRefExtState = useRef<extStates>("not-authenticated");
const isFocusedRef = useRef<boolean>(true);
const { isShow, onCancel, onOk, show, message } = useModal();
const { isShow: isShowUnsavedChanges, onCancel: onCancelUnsavedChanges, onOk: onOkUnsavedChanges, show: showUnsavedChanges, message: messageUnsavedChanges } = useModal();
const {
onCancel: onCancelQortalRequest,
onOk: onOkQortalRequest,
@ -308,7 +311,14 @@ function App() {
isShow: isShowQortalRequest,
message: messageQortalRequest,
} = useModal();
const {
onCancel: onCancelQortalRequestExtension,
onOk: onOkQortalRequestExtension,
show: showQortalRequestExtension,
isShow: isShowQortalRequestExtension,
message: messageQortalRequestExtension,
} = useModal();
const [openRegisterName, setOpenRegisterName] = useState(false);
const registerNamePopoverRef = useRef(null);
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
@ -328,7 +338,24 @@ function App() {
const qortalRequestCheckbox1Ref = useRef(null);
useRetrieveDataLocalStorage()
useQortalGetSaveSettings(userInfo?.name)
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
const { toggleFullScreen } = useAppFullScreen(setFullScreen);
useEffect(() => {
// Attach a global event listener for double-click
const handleDoubleClick = () => {
toggleFullScreen();
};
// Add the event listener to the root HTML document
document.documentElement.addEventListener('dblclick', handleDoubleClick);
// Clean up the event listener on unmount
return () => {
document.documentElement.removeEventListener('dblclick', handleDoubleClick);
};
}, [toggleFullScreen]);
//resets for recoil
const resetAtomSortablePinnedAppsAtom = useResetRecoilState(sortablePinnedAppsAtom);
const resetAtomCanSaveSettingToQdnAtom = useResetRecoilState(canSaveSettingToQdnAtom);
@ -588,15 +615,10 @@ function App() {
const qortalRequestPermisson = async (message, sender, sendResponse) => {
if (message.action === "QORTAL_REQUEST_PERMISSION" && !isMainWindow) {
try {
console.log("payloadbefore", message.payload);
await showQortalRequest(message?.payload);
console.log("payload", message.payload);
if (message?.payload?.checkbox1) {
console.log(
"qortalRequestCheckbox1Ref.current",
qortalRequestCheckbox1Ref.current
);
sendResponse({
accepted: true,
checkbox1: qortalRequestCheckbox1Ref.current,
@ -605,7 +627,6 @@ function App() {
}
sendResponse({ accepted: true });
} catch (error) {
console.log("error", error);
sendResponse({ accepted: false });
} finally {
window.close();
@ -615,13 +636,11 @@ function App() {
const qortalRequestPermissonFromExtension = async (message, sender, sendResponse) => {
if (message.action === "QORTAL_REQUEST_PERMISSION" && isMainWindow) {
try {
console.log("payloadbefore", message.payload);
await show('do you accept?');
await showQortalRequestExtension(message?.payload);
sendResponse({ accepted: true });
} catch (error) {
console.log("error", error);
sendResponse({ accepted: false });
}
}
@ -695,7 +714,6 @@ function App() {
// Call the permission request handler for "QORTAL_REQUEST_PERMISSION"
qortalRequestPermisson(message, sender, sendResponse);
if (message.action === "QORTAL_REQUEST_PERMISSION" && !isMainWindow) {
console.log("isMainWindow", isMainWindow, window?.location?.href);
return true; // Return true to indicate an async response is coming
}
if (message.action === "QORTAL_REQUEST_PERMISSION" && isMainWindow && message?.isFromExtension) {
@ -994,8 +1012,11 @@ function App() {
}
};
const logoutFunc = () => {
const logoutFunc = async () => {
try {
if(hasSettingsChanged){
await showUnsavedChanges({message: 'Your settings have changed. If you logout you will lose your changes. Click on the save button in the header to keep your changed settings.'})
}
chrome?.runtime?.sendMessage({ action: "logout" }, (response) => {
if (response) {
resetAllStates();
@ -2762,6 +2783,246 @@ function App() {
</Button>
</DialogActions>
</Dialog>
)}
{isShowUnsavedChanges && (
<Dialog
open={isShowUnsavedChanges}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Warning"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{messageUnsavedChanges.message}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={onCancelUnsavedChanges}>
Cancel
</Button>
<Button variant="contained" onClick={onOkUnsavedChanges} autoFocus>
Continue to Logout
</Button>
</DialogActions>
</Dialog>
)}
{isShowQortalRequestExtension && isMainWindow && (
<Dialog
open={isShowQortalRequestExtension}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<CountdownCircleTimer
isPlaying
duration={30}
colors={["#004777", "#F7B801", "#A30000", "#A30000"]}
colorsTime={[7, 5, 2, 0]}
onComplete={() => {
onCancelQortalRequestExtension()
}}
size={50}
strokeWidth={5}
>
{({ remainingTime }) => <TextP>{remainingTime}</TextP>}
</CountdownCircleTimer>
<Box sx={{
display: 'flex',
padding: '20px',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
minHeight: '400px',
maxHeight: '90vh',
overflow: 'auto'
}}>
<Box
sx={{
display: "flex",
justifyContent: "center",
width: "100%",
}}
>
<TextP
sx={{
lineHeight: 1.2,
maxWidth: "90%",
textAlign: "center",
}}
>
{messageQortalRequestExtension?.text1}
</TextP>
</Box>
{messageQortalRequestExtension?.text2 && (
<>
<Spacer height="10px" />
<Box
sx={{
display: "flex",
justifyContent: "flex-start",
width: "90%",
}}
>
<TextP
sx={{
lineHeight: 1.2,
fontSize: "16px",
fontWeight: "normal",
}}
>
{messageQortalRequestExtension?.text2}
</TextP>
</Box>
<Spacer height="15px" />
</>
)}
{messageQortalRequestExtension?.text3 && (
<>
<Box
sx={{
display: "flex",
justifyContent: "flex-start",
width: "90%",
}}
>
<TextP
sx={{
lineHeight: 1.2,
fontSize: "16px",
fontWeight: "normal",
}}
>
{messageQortalRequestExtension?.text3}
</TextP>
<Spacer height="15px" />
</Box>
</>
)}
{messageQortalRequestExtension?.text4 && (
<Box
sx={{
display: "flex",
justifyContent: "flex-start",
width: "90%",
}}
>
<TextP
sx={{
lineHeight: 1.2,
fontSize: "16px",
fontWeight: "normal",
}}
>
{messageQortalRequestExtension?.text4}
</TextP>
</Box>
)}
{messageQortalRequestExtension?.html && (
<div
dangerouslySetInnerHTML={{ __html: messageQortalRequestExtension?.html }}
/>
)}
<Spacer height="15px" />
<TextP
sx={{
textAlign: "center",
lineHeight: 1.2,
fontSize: "16px",
fontWeight: 700,
maxWidth: "90%",
}}
>
{messageQortalRequestExtension?.highlightedText}
</TextP>
{messageQortalRequestExtension?.fee && (
<>
<Spacer height="15px" />
<TextP
sx={{
textAlign: "center",
lineHeight: 1.2,
fontSize: "16px",
fontWeight: "normal",
maxWidth: "90%",
}}
>
{'Fee: '}{messageQortalRequestExtension?.fee}{' QORT'}
</TextP>
<Spacer height="15px" />
</>
)}
{messageQortalRequestExtension?.checkbox1 && (
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
justifyContent: "center",
width: "90%",
marginTop: "20px",
}}
>
<Checkbox
onChange={(e) => {
qortalRequestCheckbox1Ref.current = e.target.checked;
}}
edge="start"
tabIndex={-1}
disableRipple
defaultChecked={messageQortalRequestExtension?.checkbox1?.value}
sx={{
"&.Mui-checked": {
color: "white", // Customize the color when checked
},
"& .MuiSvgIcon-root": {
color: "white",
},
}}
/>
<Typography
sx={{
fontSize: "14px",
}}
>
{messageQortalRequestExtension?.checkbox1?.label}
</Typography>
</Box>
)}
<Spacer height="29px" />
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "14px",
}}
>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => onOkQortalRequestExtension("accepted")}
>
accept
</CustomButton>
<CustomButton
sx={{
minWidth: "102px",
}}
onClick={() => onCancelQortalRequestExtension()}
>
decline
</CustomButton>
</Box>
<ErrorText>{sendPaymentError}</ErrorText>
</Box>
</Dialog>
)}
<Popover
open={openRegisterName}

View File

@ -24,4 +24,14 @@ export const settingsLocalLastUpdatedAtom = atom({
export const oldPinnedAppsAtom = atom({
key: 'oldPinnedAppsAtom',
default: [],
});
export const fullScreenAtom = atom({
key: 'fullScreenAtom',
default: false,
});
export const hasSettingsChangedAtom = atom({
key: 'hasSettingsChangedAtom',
default: false,
});

View File

@ -1,8 +1,7 @@
import React, { useEffect, useMemo, useState } from "react";
import React from "react";
import {
AppCircle,
AppCircleContainer,
AppCircleLabel,
AppDownloadButton,
AppDownloadButtonText,
AppInfoAppName,
@ -11,10 +10,8 @@ import {
AppInfoSnippetMiddle,
AppInfoSnippetRight,
AppInfoUserName,
AppsLibraryContainer,
} from "./Apps-styles";
import { Avatar, Box, ButtonBase, InputBase } from "@mui/material";
import { Add } from "@mui/icons-material";
import { Avatar, ButtonBase } from "@mui/material";
import { getBaseApiReact } from "../../App";
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
@ -22,8 +19,7 @@ import { Spacer } from "../../common/Spacer";
import { executeEvent } from "../../utils/events";
import { AppRating } from "./AppRating";
export const AppInfoSnippet = ({ app, myName }) => {
export const AppInfoSnippet = ({ app, myName, isFromCategory }) => {
const isInstalled = app?.status?.status === 'READY'
return (
@ -35,6 +31,12 @@ export const AppInfoSnippet = ({ app, myName }) => {
width: "60px",
}}
onClick={()=> {
if(isFromCategory){
executeEvent("selectedAppInfoCategory", {
data: app,
});
return
}
executeEvent("selectedAppInfo", {
data: app,
});
@ -73,6 +75,12 @@ export const AppInfoSnippet = ({ app, myName }) => {
</ButtonBase>
<AppInfoSnippetMiddle>
<ButtonBase onClick={()=> {
if(isFromCategory){
executeEvent("selectedAppInfoCategory", {
data: app,
});
return
}
executeEvent("selectedAppInfo", {
data: app,
});
@ -91,6 +99,7 @@ export const AppInfoSnippet = ({ app, myName }) => {
</AppInfoSnippetLeft>
<AppInfoSnippetRight>
<AppDownloadButton onClick={()=> {
executeEvent("addTab", {
data: app
})

View File

@ -25,9 +25,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
const [openSnack, setOpenSnack] = useState(false);
const [infoSnack, setInfoSnack] = useState(null);
const hasCalledRef = useRef(false);
console.log(`pollinfo-${app?.service}-${app?.name}`, value);
console.log("hasPublishedRating", hasPublishedRating);
const getRating = useCallback(async (name, service) => {
try {
hasCalledRef.current = true;
@ -42,7 +40,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
});
const responseData = await response.json();
console.log("responseData", responseData);
if (responseData?.message?.includes("POLL_NO_EXISTS")) {
setHasPublishedRating(false);
} else if (responseData?.pollName) {
@ -67,14 +64,12 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
const initialValueVote = voteCount.find((vote) =>
vote.optionName.startsWith("initialValue-")
);
console.log("initialValueVote", initialValueVote);
if (initialValueVote) {
// Convert "initialValue-X" to just "X" and add it to the ratingVotes array
const initialRating = parseInt(
initialValueVote.optionName.split("-")[1],
10
);
console.log("initialRating", initialRating);
ratingVotes.push({
optionName: initialRating.toString(),
voteCount: 1,
@ -91,14 +86,12 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
totalScore += rating * count; // Weighted score
totalVotes += count; // Total number of votes
});
console.log("ratingVotes", ratingVotes, totalScore, totalVotes);
// Calculate average rating (ensure no division by zero)
const averageRating = totalVotes > 0 ? totalScore / totalVotes : 0;
setValue(averageRating);
}
} catch (error) {
console.log("error rating", error);
if (error?.message?.includes("POLL_NO_EXISTS")) {
setHasPublishedRating(false);
}
@ -114,7 +107,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
try {
if (!myName) throw new Error("You need a name to rate.");
if (!app?.name) return;
console.log("newValue", newValue);
const fee = await getFee("ARBITRARY");
await show({
@ -138,7 +130,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
},
},
(response) => {
console.log("response", response);
if (response.error) {
rej(response?.message);
return;
@ -172,7 +163,6 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
},
},
(response) => {
console.log("response", response);
if (response.error) {
rej(response?.message);
return;
@ -197,11 +187,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => {
setOpenSnack(true);
}
};
console.log(
"vvotes",
(votesInfo?.totalVotes ?? 0) + votesInfo?.voteCounts?.length === 6 ? 1 : 0,
votesInfo
);
return (
<div>
<Box

View File

@ -8,17 +8,7 @@ const AppViewerContainer = ({app, isSelected, hide}) => {
const { rootHeight } = useContext(MyContext);
const frameRef = useRef(null);
const refreshAppFunc = (e) => {
console.log('getting refresh', e)
};
// useEffect(() => {
// subscribeToEvent("refreshAPp", refreshAppFunc);
// return () => {
// unsubscribeFromEvent("refreshApp", refreshAppFunc);
// };
// }, []);
return (
<Frame id={`browser-iframe-${app?.tabId}` } ref={frameRef} head={

View File

@ -2,7 +2,6 @@ import React, { useCallback, useContext, useEffect, useMemo, useRef, useState }
import { AppsHome } from "./AppsHome";
import { Spacer } from "../../common/Spacer";
import { MyContext, getBaseApiReact } from "../../App";
import { AppsLibrary } from "./AppsLibrary";
import { AppInfo } from "./AppInfo";
import {
executeEvent,
@ -16,12 +15,15 @@ import AppViewerContainer from "./AppViewerContainer";
import ShortUniqueId from "short-unique-id";
import { AppPublish } from "./AppPublish";
import { useRecoilState } from "recoil";
import { AppsCategory } from "./AppsCategory";
import { AppsLibrary } from "./AppsLibrary";
const uid = new ShortUniqueId({ length: 8 });
export const Apps = ({ mode, setMode, show , myName}) => {
const [availableQapps, setAvailableQapps] = useState([]);
const [selectedAppInfo, setSelectedAppInfo] = useState(null);
const [selectedCategory, setSelectedCategory] = useState(null)
const [tabs, setTabs] = useState([]);
const [selectedTab, setSelectedTab] = useState(null);
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
@ -85,7 +87,6 @@ export const Apps = ({ mode, setMode, show , myName}) => {
});
if (!response?.ok) return;
const responseData = await response.json();
console.log('responseData', responseData)
const urlWebsites = `${getBaseApiReact()}/arbitrary/resources/search?service=WEBSITE&mode=ALL&limit=0&includestatus=true&includemetadata=true`;
const responseWebsites = await fetch(urlWebsites, {
@ -125,8 +126,44 @@ export const Apps = ({ mode, setMode, show , myName}) => {
};
}, []);
const selectedAppInfoCategoryFunc = (e) => {
const data = e.detail?.data;
setSelectedAppInfo(data);
setMode("appInfo-from-category");
};
useEffect(() => {
subscribeToEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
return () => {
unsubscribeFromEvent("selectedAppInfoCategory", selectedAppInfoCategoryFunc);
};
}, []);
const selectedCategoryFunc = (e) => {
const data = e.detail?.data;
setSelectedCategory(data);
setMode("category");
};
useEffect(() => {
subscribeToEvent("selectedCategory", selectedCategoryFunc);
return () => {
unsubscribeFromEvent("selectedCategory", selectedCategoryFunc);
};
}, []);
const navigateBackFunc = (e) => {
if (mode === "appInfo") {
if(mode === 'category'){
setMode("library");
setSelectedCategory(null)
} else if (mode === "appInfo-from-category") {
setMode("category");
} else if (mode === "appInfo") {
setMode("library");
} else if (mode === "library") {
if (isNewTabWindow) {
@ -139,10 +176,8 @@ export const Apps = ({ mode, setMode, show , myName}) => {
} else {
const iframeId = `browser-iframe-${selectedTab?.tabId}`;
const iframe = document.getElementById(iframeId);
console.log("iframe", iframe);
// Go Back in the iframe's history
if (iframe) {
console.log(iframe.contentWindow);
if (iframe && iframe.contentWindow) {
const iframeWindow = iframe.contentWindow;
if (iframeWindow && iframeWindow.history) {
@ -247,6 +282,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
};
}, [tabs]);
return (
<AppsParent
sx={{
@ -264,9 +300,12 @@ export const Apps = ({ mode, setMode, show , myName}) => {
setMode={setMode}
myName={myName}
hasPublishApp={!!(myApp || myWebsite)}
categories={categories}
/>
{mode === "appInfo" && <AppInfo app={selectedAppInfo} myName={myName} />}
{mode === "appInfo-from-category" && <AppInfo app={selectedAppInfo} myName={myName} />}
<AppsCategory availableQapps={availableQapps} isShow={mode === 'category' && !selectedTab} category={selectedCategory} myName={myName} />
{mode === "publish" && <AppPublish names={myName ? [myName] : []} categories={categories} />}
{tabs.map((tab) => {
@ -282,7 +321,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
{isNewTabWindow && mode === "viewer" && (
<>
<Spacer height="30px" />
<AppsHome availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
<AppsHome availableQapps={availableQapps} setMode={setMode} myApp={myApp} myWebsite={myWebsite} />
</>
)}
{mode !== "viewer" && !selectedTab && <Spacer height="180px" />}

View File

@ -0,0 +1,188 @@
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import {
AppCircle,
AppCircleContainer,
AppCircleLabel,
AppLibrarySubTitle,
AppsContainer,
AppsLibraryContainer,
AppsParent,
AppsSearchContainer,
AppsSearchLeft,
AppsSearchRight,
AppsWidthLimiter,
PublishQAppCTAButton,
PublishQAppCTALeft,
PublishQAppCTAParent,
PublishQAppCTARight,
PublishQAppDotsBG,
} from "./Apps-styles";
import { Avatar, Box, ButtonBase, InputBase, styled } from "@mui/material";
import { Add } from "@mui/icons-material";
import { MyContext, getBaseApiReact } from "../../App";
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
import IconSearch from "../../assets/svgs/Search.svg";
import IconClearInput from "../../assets/svgs/ClearInput.svg";
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
import qappDots from "../../assets/svgs/qappDots.svg";
import { Spacer } from "../../common/Spacer";
import { AppInfoSnippet } from "./AppInfoSnippet";
import { Virtuoso } from "react-virtuoso";
import { executeEvent } from "../../utils/events";
const officialAppList = [
"q-tube",
"q-blog",
"q-share",
"q-support",
"q-mail",
"qombo",
"q-fund",
"q-shop",
];
const ScrollerStyled = styled('div')({
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-ms-overflow-style": "none",
});
const StyledVirtuosoContainer = styled('div')({
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
// Hide scrollbar for WebKit browsers (Chrome, Safari)
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-ms-overflow-style": "none",
});
export const AppsCategory = ({ availableQapps, myName, category, isShow }) => {
const [searchValue, setSearchValue] = useState("");
const virtuosoRef = useRef();
const { rootHeight } = useContext(MyContext);
const categoryList = useMemo(() => {
return availableQapps.filter(
(app) =>
app?.metadata?.category === category?.id
);
}, [availableQapps, category]);
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
// Debounce logic
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(searchValue);
}, 350);
// Cleanup timeout if searchValue changes before the timeout completes
return () => {
clearTimeout(handler);
};
}, [searchValue]); // Runs effect when searchValue changes
// Example: Perform search or other actions based on debouncedValue
const searchedList = useMemo(() => {
if (!debouncedValue) return categoryList
return categoryList.filter((app) =>
app.name.toLowerCase().includes(debouncedValue.toLowerCase())
);
}, [debouncedValue, categoryList]);
const rowRenderer = (index) => {
let app = searchedList[index];
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} isFromCategory={true} />;
};
return (
<AppsLibraryContainer sx={{
display: !isShow && 'none'
}}>
<AppsWidthLimiter>
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
}}
>
<AppsSearchContainer>
<AppsSearchLeft>
<img src={IconSearch} />
<InputBase
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
sx={{ ml: 1, flex: 1 }}
placeholder="Search for apps"
inputProps={{
"aria-label": "Search for apps",
fontSize: "16px",
fontWeight: 400,
}}
/>
</AppsSearchLeft>
<AppsSearchRight>
{searchValue && (
<ButtonBase
onClick={() => {
setSearchValue("");
}}
>
<img src={IconClearInput} />
</ButtonBase>
)}
</AppsSearchRight>
</AppsSearchContainer>
</Box>
</AppsWidthLimiter>
<Spacer height="25px" />
<AppsWidthLimiter>
<AppLibrarySubTitle>{`Category: ${category?.name}`}</AppLibrarySubTitle>
<Spacer height="25px" />
</AppsWidthLimiter>
<AppsWidthLimiter>
<StyledVirtuosoContainer sx={{
height: rootHeight
}}>
<Virtuoso
ref={virtuosoRef}
data={searchedList}
itemContent={rowRenderer}
atBottomThreshold={50}
followOutput="smooth"
components={{
Scroller: ScrollerStyled // Use the styled scroller component
}}
/>
</StyledVirtuosoContainer>
</AppsWidthLimiter>
</AppsLibraryContainer>
);
};

View File

@ -74,23 +74,11 @@ const ScrollerStyled = styled('div')({
"-ms-overflow-style": "none",
});
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow }) => {
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories={categories} }) => {
const [searchValue, setSearchValue] = useState("");
const virtuosoRef = useRef();
const { rootHeight } = useContext(MyContext);
const [appStates, setAppStates] = useState({});
const handleStateChange = (appId, newState) => {
setAppStates((prevState) => ({
...prevState,
[appId]: {
...(prevState[appId] || {}), // Preserve existing state for the app
...newState, // Merge in the new state properties
},
}));
};
console.log('appStates', appStates)
const officialApps = useMemo(() => {
return availableQapps.filter(
(app) =>
@ -121,12 +109,10 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
app.name.toLowerCase().includes(debouncedValue.toLowerCase())
);
}, [debouncedValue]);
console.log("officialApps", searchedList);
const rowRenderer = (index) => {
let app = searchedList[index];
console.log('appi', app)
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} />;
};
@ -273,6 +259,49 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
<Spacer height="18px" />
<AppLibrarySubTitle>Categories</AppLibrarySubTitle>
<Spacer height="18px" />
<AppsWidthLimiter sx={{
flexDirection: 'row',
overflowX: 'auto',
width: '100%',
gap: '5px',
"::-webkit-scrollbar": {
width: "0px",
height: "0px",
},
// Hide scrollbar for Firefox
scrollbarWidth: "none",
// Hide scrollbar for IE and older Edge
"-ms-overflow-style": "none",
}}>
{categories?.map((category)=> {
return (
<ButtonBase key={category?.id} onClick={()=> {
executeEvent('selectedCategory', {
data: category
})
}}>
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '110px',
width: '110px',
background: 'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
color: '#1D1D1E',
fontWeight: 700,
fontSize: '16px',
flexShrink: 0,
borderRadius: '11px'
}}>
{category?.name}
</Box>
</ButtonBase>
)
})}
</AppsWidthLimiter>
</AppsWidthLimiter>
</>
)}

View File

@ -41,7 +41,6 @@ export function saveToLocalStorage(key, subKey, newValue) {
// Save combined data back to localStorage
const serializedValue = JSON.stringify(combinedData);
localStorage.setItem(key, serializedValue);
console.log(`Data saved to localStorage with key: ${key} and subKey: ${subKey}`);
} catch (error) {
console.error('Error saving to localStorage:', error);
}
@ -57,6 +56,7 @@ export const AppsNavBar = () => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
const handleClick = (event) => {
@ -71,7 +71,6 @@ export const AppsNavBar = () => {
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added)
if (tabsRef.current) {
const tabElements = tabsRef.current.querySelectorAll('.MuiTab-root');
console.log('tabElements', tabElements)
if (tabElements.length > 0) {
const lastTab = tabElements[tabElements.length - 1];
lastTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'end' });
@ -95,7 +94,6 @@ export const AppsNavBar = () => {
};
}, []);
console.log('selectedTab', selectedTab)
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === selectedTab?.name && item?.service === selectedTab?.service)
return (

View File

@ -14,7 +14,6 @@ import { ContextMenuPinnedApps } from '../ContextMenuPinnedApps';
const SortableItem = ({ id, name, app }) => {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
console.log('namednd', name)
const style = {
transform: CSS.Transform.toString(transform),
transition,
@ -86,7 +85,6 @@ export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) =
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
const transformPinnedApps = useMemo(() => {
console.log({ myWebsite, myApp, availableQapps, pinnedApps });
// Clone the existing pinned apps list
let pinned = [...pinnedApps];
@ -130,27 +128,7 @@ export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) =
return pinned;
}, [myApp, myWebsite, pinnedApps, availableQapps]);
console.log('transformPinnedApps', transformPinnedApps)
// const hasSetPinned = useRef(false)
// useEffect(() => {
// if (!apps || apps.length === 0) return;
// setPinnedApps((prevPinnedApps) => {
// // Create a map of the previous pinned apps for easy lookup
// const pinnedAppsMap = new Map(prevPinnedApps.map(app => [`${app?.service}-${app?.name}`, app]));
// // Update the pinnedApps list based on new apps
// const updatedPinnedApps = apps.map(app => {
// const id = `${app?.service}-${app?.name}`;
// // Keep the existing app from pinnedApps if it exists
// return pinnedAppsMap.get(id) || app;
// });
// return updatedPinnedApps;
// });
// }, [apps]);
console.log('dnd',{pinnedApps})
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {

View File

@ -97,7 +97,6 @@ async function handleGetFileFromIndexedDB(fileId, sendResponse) {
const deleteRequest = deleteObjectStore.delete(fileId);
deleteRequest.onsuccess = function () {
console.log(`File with ID ${fileId} has been removed from IndexedDB`);
try {
sendResponse({ result: base64String });
@ -171,7 +170,6 @@ const UIQortalRequests = [
async function deleteQortalFilesFromIndexedDB() {
try {
console.log("Opening IndexedDB for deleting files...");
const db = await openIndexedDB();
const transaction = db.transaction(["files"], "readwrite");
const objectStore = transaction.objectStore("files");
@ -262,7 +260,6 @@ const UIQortalRequests = [
obj.fileId = fileId;
delete obj.file;
}
console.log(obj, obj.blob instanceof Blob, 'blob')
if (obj.blob) {
const fileId = "objFile_qortalfile";
@ -315,7 +312,6 @@ const UIQortalRequests = [
export const useQortalMessageListener = (frameWindow) => {
const [path, setPath] = useState('')
useEffect(() => {
console.log("Listener added react");
const listener = async (event) => {
event.preventDefault(); // Prevent default behavior
@ -325,7 +321,6 @@ export const useQortalMessageListener = (frameWindow) => {
const sendMessageToRuntime = (message, eventPort) => {
chrome?.runtime?.sendMessage(message, (response) => {
console.log('response', response);
if (response.error) {
eventPort.postMessage({
result: null,
@ -342,7 +337,6 @@ export const useQortalMessageListener = (frameWindow) => {
// Check if action is included in the predefined list of UI requests
if (UIQortalRequests.includes(event.data.action)) {
console.log('event?.data', event?.data);
sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: event.data, isExtension: true },
event.ports[0]
@ -353,7 +347,6 @@ export const useQortalMessageListener = (frameWindow) => {
event?.data?.action === 'ENCRYPT_DATA' || event?.data?.action === 'SAVE_FILE'
) {
console.log('event?.data?', event?.data);
let data;
try {
data = await storeFilesInIndexedDB(event.data);
@ -365,7 +358,6 @@ export const useQortalMessageListener = (frameWindow) => {
});
return;
}
console.log('data after', data)
if (data) {
sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true },
@ -396,7 +388,6 @@ export const useQortalMessageListener = (frameWindow) => {
}, []); // Empty dependency array to run once when the component mounts
chrome.runtime?.onMessage.addListener( function (message, sender, sendResponse) {
console.log('SHOWING UP')
if(message.action === "SHOW_SAVE_FILE_PICKER"){
showSaveFilePicker(message?.data)
}

View File

@ -127,7 +127,6 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
const forceCloseWebSocket = () => {
if (socketRef.current) {
console.log('Force closing the WebSocket');
clearTimeout(timeoutIdRef.current);
clearTimeout(groupSocketTimeoutRef.current);
socketRef.current.close(1000, 'forced');
@ -161,7 +160,6 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
socketRef.current = new WebSocket(socketLink);
socketRef.current.onopen = () => {
console.log('WebSocket connection opened');
setTimeout(pingWebSocket, 50); // Initial ping
};

View File

@ -824,98 +824,7 @@ export const Group = ({
}
}, [selectedGroup]);
// const handleNotification = async (data)=> {
// try {
// if(isFocusedRef.current){
// throw new Error('isFocused')
// }
// const newActiveChats= data
// const oldActiveChats = await new Promise((res, rej) => {
// chrome?.runtime?.sendMessage(
// {
// action: "getChatHeads",
// },
// (response) => {
// console.log({ response });
// if (!response?.error) {
// res(response);
// }
// rej(response.error);
// }
// );
// });
// let results = []
// newActiveChats?.groups?.forEach(newChat => {
// let isNewer = true;
// oldActiveChats?.data?.groups?.forEach(oldChat => {
// if (newChat?.timestamp <= oldChat?.timestamp) {
// isNewer = false;
// }
// });
// if (isNewer) {
// results.push(newChat)
// console.log('This newChat is newer than all oldChats:', newChat);
// }
// });
// if(results?.length > 0){
// if (!lastGroupNotification.current || (Date.now() - lastGroupNotification.current >= 60000)) {
// console.log((Date.now() - lastGroupNotification.current >= 60000), lastGroupNotification.current)
// chrome?.runtime?.sendMessage(
// {
// action: "notification",
// payload: {
// },
// },
// (response) => {
// console.log({ response });
// if (!response?.error) {
// }
// }
// );
// audio.play();
// lastGroupNotification.current = Date.now()
// }
// }
// } catch (error) {
// console.log('error not', error)
// if(!isFocusedRef.current){
// chrome?.runtime?.sendMessage(
// {
// action: "notification",
// payload: {
// },
// },
// (response) => {
// console.log({ response });
// if (!response?.error) {
// }
// }
// );
// audio.play();
// lastGroupNotification.current = Date.now()
// }
// } finally {
// chrome?.runtime?.sendMessage(
// {
// action: "setChatHeads",
// payload: {
// data,
// },
// }
// );
// }
// }
const getAdmins = async (groupId) => {
try {

View File

@ -48,20 +48,7 @@ export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, get
return true
})
// const getJoinGroupRequests = groupsAsAdmin.map(async (group)=> {
// console.log('getJoinGroupRequests', group)
// const joinRequestResponse = await requestQueueGroupJoinRequests.enqueue(()=> {
// return fetch(
// `${getBaseApiReact()}/groups/joinrequests/${group.groupId}`
// );
// })
// const joinRequestData = await joinRequestResponse.json()
// return {
// group,
// data: joinRequestData
// }
// })
await Promise.all(getAllGroupsAsAdmin)
const res = await Promise.all(groupsAsAdmin.map(async (group)=> {

View File

@ -20,6 +20,10 @@ import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import { MessagingIcon2 } from "../../assets/Icons/MessagingIcon2";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { Save } from "../Save/Save";
import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen';
import { useRecoilState } from "recoil";
import { fullScreenAtom, hasSettingsChangedAtom } from "../../atoms/global";
import { useAppFullScreen } from "../../useAppFullscreen";
const Header = ({
logoutFunc,
@ -33,16 +37,11 @@ const Header = ({
myName,
setSelectedDirect,
setNewChat
// selectedGroup,
// onHomeClick,
// onLogoutClick,
// onGroupChange,
// onWalletClick,
// onNotificationClick,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
const {exitFullScreen} = useAppFullScreen(setFullScreen)
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
@ -77,10 +76,10 @@ const Header = ({
width: "75px",
}}
>
<IconButton
edge="start"
color="inherit"
aria-label="home"
<ButtonBase
onClick={() => {
setMobileViewModeKeepOpen("");
goToHome();
@ -88,15 +87,24 @@ const Header = ({
// onClick={onHomeClick}
>
<HomeIcon height={20} width={27} color="rgba(145, 145, 147, 1)" />
</IconButton>
<IconButton
edge="start"
color="inherit"
aria-label="home"
</ButtonBase>
<ButtonBase
onClick={handleClick}
>
<NotificationIcon height={20} width={21} color={hasUnreadDirects || hasUnreadGroups ? "var(--unread)" : "rgba(145, 145, 147, 1)"} />
</IconButton>
</ButtonBase>
{fullScreen && (
<ButtonBase onClick={()=> {
exitFullScreen()
setFullScreen(false)
}}>
<CloseFullscreenIcon sx={{
color: 'rgba(145, 145, 147, 1)'
}} />
</ButtonBase>
)}
</Box>
{/* Center Title */}
@ -254,6 +262,16 @@ const Header = ({
>
<HomeIcon color="rgba(145, 145, 147, 1)" />
</ButtonBase>
{fullScreen && (
<ButtonBase onClick={()=> {
exitFullScreen()
setFullScreen(false)
}}>
<CloseFullscreenIcon sx={{
color: 'rgba(145, 145, 147, 1)'
}} />
</ButtonBase>
)}
</Box>
{/* Center Title */}
<Typography

View File

@ -1,7 +1,7 @@
import React, { useContext, useMemo, useState } from 'react'
import { useRecoilState } from 'recoil';
import React, { useContext, useEffect, useMemo, useState } from 'react'
import { useRecoilState, useSetRecoilState } from 'recoil';
import isEqual from 'lodash/isEqual'; // Import deep comparison utility
import { canSaveSettingToQdnAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
import { canSaveSettingToQdnAtom, hasSettingsChangedAtom, oldPinnedAppsAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
import { ButtonBase } from '@mui/material';
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
import { MyContext } from '../../App';
@ -12,13 +12,14 @@ export const Save = () => {
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
const [settingsQdnLastUpdated, setSettingsQdnLastUpdated] = useRecoilState(settingsQDNLastUpdatedAtom);
const [settingsLocalLastUpdated] = useRecoilState(settingsLocalLastUpdatedAtom);
const setHasSettingsChangedAtom = useSetRecoilState(hasSettingsChangedAtom);
const [canSave] = useRecoilState(canSaveSettingToQdnAtom);
const [openSnack, setOpenSnack] = useState(false);
const [isLoading, setIsLoading] = useState(false)
const [infoSnack, setInfoSnack] = useState(null);
const [oldPinnedApps, setOldPinnedApps] = useRecoilState(oldPinnedAppsAtom)
console.log('oldpin', {oldPinnedApps, pinnedApps}, settingsQdnLastUpdated, settingsLocalLastUpdated, settingsQdnLastUpdated < settingsLocalLastUpdated,)
const { show } = useContext(MyContext);
const hasChanged = useMemo(()=> {
@ -38,11 +39,14 @@ export const Save = () => {
}
})
}
console.log('!isEqual(oldChanges, newChanges)', !isEqual(oldChanges, newChanges))
if(settingsQdnLastUpdated === -100) return false
return !isEqual(oldChanges, newChanges) && settingsQdnLastUpdated < settingsLocalLastUpdated
}, [oldPinnedApps, pinnedApps, settingsQdnLastUpdated, settingsLocalLastUpdated])
useEffect(()=> {
setHasSettingsChangedAtom(hasChanged)
}, [hasChanged])
const saveToQdn = async ()=> {
try {
setIsLoading(true)
@ -64,7 +68,6 @@ export const Save = () => {
},
},
(response) => {
console.log("response", response);
if (response.error) {
rej(response?.message);
return;
@ -102,7 +105,6 @@ export const Save = () => {
}
);
});
console.log('saved', response)
if(response?.identifier){
setOldPinnedApps(pinnedApps)
setSettingsQdnLastUpdated(Date.now())
@ -114,7 +116,6 @@ export const Save = () => {
setOpenSnack(true);
}
}
console.log('save encryptedData', encryptData)
} catch (error) {
setInfoSnack({
type: "error",
@ -126,7 +127,6 @@ export const Save = () => {
setIsLoading(false)
}
}
console.log('settingsQdnLastUpdated', settingsQdnLastUpdated)
return (
<>
<ButtonBase onClick={saveToQdn} disabled={!hasChanged || !canSave || isLoading || settingsQdnLastUpdated === -100}>

View File

@ -319,7 +319,6 @@ export const decodeBase64ForUIChatMessages = (messages)=> {
if (decryptedKey) {
// Decrypt the data using the symmetric key.
const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey)
console.log('decryptedData', decryptedData)
// If decryption was successful, decryptedData will not be null.
if (decryptedData) {
return decryptedData

View File

@ -61,25 +61,7 @@ export const publishData = async ({
tag5,
feeAmount
}: any) => {
console.log({
registeredName,
file,
service,
identifier,
uploadType,
isBase64,
filename,
withFee,
title,
description,
category,
tag1,
tag2,
tag3,
tag4,
tag5,
feeAmount
})
const validateName = async (receiverName: string) => {
return await reusableGet(`/names/${receiverName}`)
}
@ -171,7 +153,6 @@ export const publishData = async ({
fee = feeAmount
} else if (withFee) {
const res = await getArbitraryFee()
console.log('res', res)
if (res.fee) {
fee = res.fee
} else {
@ -180,7 +161,6 @@ export const publishData = async ({
}
let transactionBytes = await uploadData(registeredName, file, fee)
console.log('transactionBytes', transactionBytes)
if (!transactionBytes || transactionBytes.error) {
throw new Error(transactionBytes?.message || 'Error when uploading')
} else if (transactionBytes.includes('Error 500 Internal Server Error')) {
@ -201,7 +181,6 @@ export const publishData = async ({
}
const uploadData = async (registeredName: string, file:any, fee: number) => {
console.log('uploadData', registeredName, file, fee)
let postBody = ''
let urlSuffix = ''
@ -230,7 +209,6 @@ export const publishData = async ({
}
let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}`
console.log('uploadDataUrl', uploadDataUrl)
if (identifier?.trim().length > 0) {
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${identifier}${urlSuffix}`
}
@ -273,7 +251,6 @@ export const publishData = async ({
if (tag5 != null && tag5 != 'undefined') {
uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag5)
}
console.log('uploadDataUrl2', uploadDataUrl)
return await reusablePost(uploadDataUrl, postBody)
@ -282,7 +259,6 @@ export const publishData = async ({
try {
return await validate()
} catch (error: any) {
console.log('error2', error)
throw new Error(error?.message)
}
}

View File

@ -63,7 +63,6 @@ function getLocalStorage(key) {
chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
if (request) {
console.log('rquest', request)
const isFromExtension = request?.isExtension
switch (request.action) {
case "GET_USER_ACCOUNT": {
@ -106,7 +105,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_LIST_ITEMS": {
const data = request.payload;
getListItems(data)
getListItems(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -119,7 +118,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "ADD_LIST_ITEMS": {
const data = request.payload;
addListItems(data)
addListItems(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -132,7 +131,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "DELETE_LIST_ITEM": {
const data = request.payload;
deleteListItems(data)
deleteListItems(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -145,7 +144,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "PUBLISH_QDN_RESOURCE": {
const data = request.payload;
publishQDNResource(data, sender)
publishQDNResource(data, sender, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -158,7 +157,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "PUBLISH_MULTIPLE_QDN_RESOURCES": {
const data = request.payload;
publishMultipleQDNResources(data, sender)
publishMultipleQDNResources(data, sender, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -184,7 +183,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "CREATE_POLL": {
const data = request.payload;
createPoll(data)
createPoll(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -196,8 +195,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
}
case "SEND_CHAT_MESSAGE": {
const data = request.payload;
console.log('data', data)
sendChatMessage(data)
sendChatMessage(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -210,7 +208,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "JOIN_GROUP": {
const data = request.payload;
joinGroup(data)
joinGroup(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -223,7 +221,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "SAVE_FILE": {
const data = request.payload;
saveFile(data, sender)
saveFile(data, sender, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -236,7 +234,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "DEPLOY_AT": {
const data = request.payload;
deployAt(data)
deployAt(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -249,7 +247,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_USER_WALLET": {
const data = request.payload;
getUserWallet(data)
getUserWallet(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -262,7 +260,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_WALLET_BALANCE": {
const data = request.payload;
getWalletBalance(data)
getWalletBalance(data, false, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -276,7 +274,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_USER_WALLET_INFO": {
const data = request.payload;
getUserWalletInfo(data)
getUserWalletInfo(data, isFromExtension)
.then((res) => {
sendResponse(res);
})
@ -414,7 +412,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "SEND_COIN": {
const data = request.payload;
sendCoin(data)
sendCoin(data, isFromExtension)
.then((res) => {
sendResponse(res);
})

View File

@ -38,7 +38,7 @@ const dgbFeePerByte = 0.00000010
const rvnFeePerByte = 0.00001125
const _createPoll = async (pollName, pollDescription, options) => {
const _createPoll = async ({pollName, pollDescription, options}, isFromExtension) => {
const fee = await getFee("CREATE_POLL");
const resPermission = await getUserPermission({
@ -47,7 +47,7 @@ const _createPoll = async (pollName, pollDescription, options) => {
text3: `Description: ${pollDescription}`,
text4: `Options: ${options?.join(", ")}`,
fee: fee.fee,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -82,13 +82,13 @@ const _createPoll = async (pollName, pollDescription, options) => {
};
const _deployAt = async (
name,
{name,
description,
tags,
creationBytes,
amount,
assetId,
atType
atType}, isFromExtension
) => {
const fee = await getFee("DEPLOY_AT");
@ -97,7 +97,7 @@ const _deployAt = async (
text2: `Name: ${name}`,
text3: `Description: ${description}`,
fee: fee.fee,
});
}, isFromExtension);
const { accepted } = resPermission;
@ -172,7 +172,6 @@ const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension)
});
const signedBytes = Base58.encode(tx.signedBytes);
const res = await processTransactionVersion2(signedBytes);
console.log('res', res)
if (!res?.signature)
throw new Error(res?.message || "Transaction was not able to be processed");
return res;
@ -182,13 +181,11 @@ const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension)
};
function getFileFromContentScript(fileId, sender) {
console.log("sender", sender);
return new Promise((resolve, reject) => {
chrome.tabs.sendMessage(
sender.tab.id,
{ action: "getFileFromIndexedDB", fileId: fileId },
(response) => {
console.log("response2", response);
if (response && response.result) {
resolve(response.result);
} else {
@ -199,7 +196,6 @@ function getFileFromContentScript(fileId, sender) {
});
}
function sendToSaveFilePicker(data, sender) {
console.log("sender", sender);
chrome.tabs.sendMessage(sender.tab.id, {
action: "SHOW_SAVE_FILE_PICKER",
@ -239,7 +235,6 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
});
}
console.log('isFromExtension', isFromExtension)
if(isFromExtension){
@ -253,7 +248,6 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
chrome.runtime.sendMessage(
{ action: "QORTAL_REQUEST_PERMISSION", payload, isFromExtension },
(response) => {
console.log("permission response", response);
if (response === undefined) return;
clearTimeout(timeout); // Clear the timeout if we get a response
@ -268,11 +262,9 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
}
await new Promise((res) => {
const popupUrl = chrome.runtime.getURL("index.html?secondary=true");
console.log("popupUrl", popupUrl);
chrome.windows.getAll(
{ populate: true, windowTypes: ["popup"] },
(windows) => {
console.log("windows", windows);
// Attempt to find an existing popup window that has a tab with the correct URL
const existingPopup = windows.find(
(w) =>
@ -340,11 +332,9 @@ async function getUserPermission(payload: any, isFromExtension?: boolean) {
}, 30000);
// Send message to the content script to check focus
console.log("send msg");
chrome.runtime.sendMessage(
{ action: "QORTAL_REQUEST_PERMISSION", payload },
(response) => {
console.log("permission response", response);
if (response === undefined) return;
clearTimeout(timeout); // Clear the timeout if we get a response
@ -386,7 +376,6 @@ export const encryptData = async (data, sender) => {
const parsedData = JSON.parse(resKeyPair);
const privateKey = parsedData.privateKey;
const userPublicKey = parsedData.publicKey;
console.log('data', data)
const encryptDataResponse = encryptDataGroup({
data64,
@ -441,7 +430,7 @@ export const decryptData = async (data) => {
throw new Error("Unable to decrypt");
};
export const getListItems = async (data) => {
export const getListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const requiredFields = ["list_name"];
@ -474,7 +463,7 @@ export const getListItems = async (data) => {
value: value,
label: "Always allow lists to be retrieved automatically",
},
});
}, isFromExtension);
const { accepted, checkbox1 } = resPermission;
acceptedVar = accepted;
checkbox1Var = checkbox1;
@ -483,20 +472,17 @@ export const getListItems = async (data) => {
if (acceptedVar || skip) {
const url = await createEndpoint(`/lists/${data.list_name}`);
console.log("url", url);
const response = await fetch(url);
console.log("response", response);
if (!response.ok) throw new Error("Failed to fetch");
const list = await response.json();
console.log("list", list);
return list;
} else {
throw new Error("User declined to share list");
}
};
export const addListItems = async (data) => {
export const addListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const requiredFields = ["list_name", "items"];
@ -519,12 +505,11 @@ export const addListItems = async (data) => {
text1: "Do you give this application permission to",
text2: `Add the following to the list ${list_name}:`,
highlightedText: items.join(", "),
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
const url = await createEndpoint(`/lists/${list_name}`);
console.log("url", url);
const body = {
items: items,
};
@ -537,7 +522,6 @@ export const addListItems = async (data) => {
body: bodyToString,
});
console.log("response", response);
if (!response.ok) throw new Error("Failed to add to list");
let res;
try {
@ -551,7 +535,7 @@ export const addListItems = async (data) => {
}
};
export const deleteListItems = async (data) => {
export const deleteListItems = async (data, isFromExtension) => {
const localNodeAvailable = await isUsingLocal()
if(!localNodeAvailable) throw new Error('Please use your local node.')
const requiredFields = ["list_name", "item"];
@ -574,12 +558,11 @@ export const deleteListItems = async (data) => {
text1: "Do you give this application permission to",
text2: `Remove the following from the list ${list_name}:`,
highlightedText: item,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
const url = await createEndpoint(`/lists/${list_name}`);
console.log("url", url);
const body = {
items: [item],
};
@ -592,7 +575,6 @@ export const deleteListItems = async (data) => {
body: bodyToString,
});
console.log("response", response);
if (!response.ok) throw new Error("Failed to add to list");
let res;
try {
@ -606,7 +588,7 @@ export const deleteListItems = async (data) => {
}
};
export const publishQDNResource = async (data: any, sender) => {
export const publishQDNResource = async (data: any, sender, isFromExtension) => {
const requiredFields = ["service"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -683,7 +665,7 @@ export const publishQDNResource = async (data: any, sender) => {
text3: `identifier: ${identifier || null}`,
highlightedText: `isEncrypted: ${!!data.encrypt}`,
fee: fee.fee,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
if (data.fileId && !data.encrypt) {
@ -718,7 +700,7 @@ export const publishQDNResource = async (data: any, sender) => {
}
};
export const publishMultipleQDNResources = async (data: any, sender) => {
export const publishMultipleQDNResources = async (data: any, sender, isFromExtension) => {
const requiredFields = ["resources"];
const missingFields: string[] = [];
let feeAmount = null;
@ -815,14 +797,12 @@ export const publishMultipleQDNResources = async (data: any, sender) => {
`,
highlightedText: `isEncrypted: ${!!data.encrypt}`,
fee: fee.fee * resources.length,
});
}, isFromExtension);
const { accepted } = resPermission;
console.log("accepted", accepted);
if (!accepted) {
throw new Error("User declined request");
}
let failedPublishesIdentifiers = [];
console.log("resources", resources);
for (const resource of resources) {
try {
const requiredFields = ["service"];
@ -934,7 +914,6 @@ export const publishMultipleQDNResources = async (data: any, sender) => {
});
}
} catch (error) {
console.log("error", error);
failedPublishesIdentifiers.push({
reason: "Unknown error",
identifier: resource.identifier,
@ -990,7 +969,7 @@ export const voteOnPoll = async (data, isFromExtension) => {
}
};
export const createPoll = async (data) => {
export const createPoll = async (data, isFromExtension) => {
const requiredFields = [
"pollName",
"pollDescription",
@ -1014,10 +993,12 @@ export const createPoll = async (data) => {
const pollOwnerAddress = data.pollOwnerAddress;
try {
const resCreatePoll = await _createPoll(
pollName,
{
pollName,
pollDescription,
pollOptions,
pollOwnerAddress
options: pollOptions,
},
isFromExtension
);
return resCreatePoll;
} catch (error) {
@ -1025,7 +1006,7 @@ export const createPoll = async (data) => {
}
};
export const sendChatMessage = async (data) => {
export const sendChatMessage = async (data, isFromExtension) => {
const message = data.message;
const recipient = data.destinationAddress;
const groupId = data.groupId;
@ -1034,7 +1015,7 @@ export const sendChatMessage = async (data) => {
text1: "Do you give this application permission to send this chat message?",
text2: `To: ${isRecipient ? recipient : `group ${groupId}`}`,
text3: `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -1058,11 +1039,7 @@ export const sendChatMessage = async (data) => {
repliedTo: "",
version: 3,
};
try {
JSON.stringify(messageObject);
} catch (error) {
console.log("my error", error);
}
const stringifyMessageObject = JSON.stringify(messageObject);
const balance = await getBalanceInfo();
@ -1088,7 +1065,6 @@ export const sendChatMessage = async (data) => {
// Otherwise, treat it as plain text
res = await response.text();
}
console.log("res", res);
if (res?.error === 102) {
key = "";
hasPublicKey = false;
@ -1198,7 +1174,7 @@ export const sendChatMessage = async (data) => {
}
};
export const joinGroup = async (data) => {
export const joinGroup = async (data, isFromExtension) => {
const requiredFields = ["groupId"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1228,7 +1204,7 @@ export const joinGroup = async (data) => {
text1: "Confirm joining the group:",
highlightedText: `${groupInfo.groupName}`,
fee: fee.fee,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -1249,9 +1225,8 @@ export const joinGroup = async (data) => {
}
};
export const saveFile = async (data, sender) => {
export const saveFile = async (data, sender, isFromExtension) => {
try {
console.log('save file', data)
const requiredFields = ["filename", "fileId"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1270,7 +1245,7 @@ export const saveFile = async (data, sender) => {
const resPermission = await getUserPermission({
text1: "Would you like to download:",
highlightedText: `${filename}`,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -1314,7 +1289,7 @@ export const saveFile = async (data, sender) => {
}
};
export const deployAt = async (data) => {
export const deployAt = async (data, isFromExtension) => {
const requiredFields = [
"name",
"description",
@ -1337,13 +1312,16 @@ export const deployAt = async (data) => {
}
try {
const resDeployAt = await _deployAt(
data.name,
data.description,
data.tags,
data.creationBytes,
data.amount,
data.assetId,
data.type
{
name: data.name,
description: data.description,
tags: data.tags,
creationBytes: data.creationBytes,
amount: data.amount,
assetId: data.assetId,
atType: data.type
},
isFromExtension
);
return resDeployAt;
} catch (error) {
@ -1351,7 +1329,7 @@ export const deployAt = async (data) => {
}
};
export const getUserWallet = async (data) => {
export const getUserWallet = async (data, isFromExtension) => {
const requiredFields = ["coin"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1367,7 +1345,7 @@ export const getUserWallet = async (data) => {
const resPermission = await getUserPermission({
text1:
"Do you give this application permission to get your wallet information?",
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -1437,7 +1415,7 @@ export const getUserWallet = async (data) => {
}
};
export const getWalletBalance = async (data, bypassPermission?: boolean) => {
export const getWalletBalance = async (data, bypassPermission?: boolean, isFromExtension) => {
const requiredFields = ["coin"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1456,7 +1434,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean) => {
resPermission = await getUserPermission({
text1: "Do you give this application permission to fetch your",
highlightedText: `${data.coin} balance`,
});
}, isFromExtension);
} else {
resPermission = {
accepted: false
@ -1558,7 +1536,6 @@ const getUserWalletFunc = async (coin) => {
const address = wallet.address0;
const resKeyPair = await getKeyPair();
const parsedData = JSON.parse(resKeyPair);
console.log('coin', coin)
switch (coin) {
case "QORT":
userWallet["address"] = address;
@ -1592,7 +1569,7 @@ const getUserWalletFunc = async (coin) => {
return userWallet;
};
export const getUserWalletInfo = async (data) => {
export const getUserWalletInfo = async (data, isFromExtension) => {
const requiredFields = ["coin"];
const missingFields: string[] = [];
requiredFields.forEach((field) => {
@ -1607,14 +1584,12 @@ export const getUserWalletInfo = async (data) => {
}
const resPermission = await getUserPermission({
text1: "Do you give this application permission to retrieve your wallet information",
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
let coin = data.coin;
let walletKeys = await getUserWalletFunc(coin);
console.log('walletKeys', walletKeys)
console.log('walletKeys["publickey"]', walletKeys["publickey"])
const _url = await createEndpoint(
`/crosschain/` + data.coin.toLowerCase() + `/addressinfos`
);
@ -2076,7 +2051,7 @@ export const getTxActivitySummary = async (data) => {
}
};
export const sendCoin = async (data) => {
export const sendCoin = async (data, isFromExtension) => {
const requiredFields = ['coin', 'destinationAddress', 'amount']
const missingFields: string[] = []
requiredFields.forEach((field) => {
@ -2105,9 +2080,7 @@ export const sendCoin = async (data) => {
const recipient = data.destinationAddress
const url = await createEndpoint(`/addresses/balance/${address}`);
console.log("url", url);
const response = await fetch(url);
console.log("response", response);
if (!response.ok) throw new Error("Failed to fetch");
let walletBalance;
try {
@ -2141,7 +2114,7 @@ export const sendCoin = async (data) => {
text1: "Do you give this application permission to send coins?",
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2174,7 +2147,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2231,7 +2204,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2288,7 +2261,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2343,7 +2316,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2401,7 +2374,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {
@ -2455,7 +2428,7 @@ export const sendCoin = async (data) => {
text2: `To: ${recipient}`,
highlightedText: `${amount} ${checkCoin}`,
fee: fee
});
}, isFromExtension);
const { accepted } = resPermission;
if (accepted) {

65
src/useAppFullscreen.tsx Normal file
View File

@ -0,0 +1,65 @@
import { useCallback, useEffect } from 'react';
export const useAppFullScreen = (setFullScreen) => {
const enterFullScreen = useCallback(() => {
const element = document.documentElement; // Target the entire HTML document
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) { // Firefox
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) { // Chrome, Safari and Opera
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) { // IE/Edge
element.msRequestFullscreen();
}
}, []);
const exitFullScreen = useCallback(() => {
if (document.fullscreenElement) {
document.exitFullscreen();
} else if (document.mozFullScreenElement) {
document.mozCancelFullScreen();
} else if (document.webkitFullscreenElement) {
document.webkitExitFullscreen();
} else if (document.msFullscreenElement) {
document.msExitFullscreen();
}
}, []);
const toggleFullScreen = useCallback(() => {
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
exitFullScreen();
setFullScreen(false)
} else {
enterFullScreen();
setFullScreen(true)
}
}, [enterFullScreen, exitFullScreen]);
// Listen for changes to fullscreen state
useEffect(() => {
const handleFullScreenChange = () => {
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
} else {
setFullScreen(false);
}
};
document.addEventListener('fullscreenchange', handleFullScreenChange);
document.addEventListener('webkitfullscreenchange', handleFullScreenChange); // Safari
document.addEventListener('mozfullscreenchange', handleFullScreenChange); // Firefox
document.addEventListener('MSFullscreenChange', handleFullScreenChange); // IE/Edge
return () => {
document.removeEventListener('fullscreenchange', handleFullScreenChange);
document.removeEventListener('webkitfullscreenchange', handleFullScreenChange);
document.removeEventListener('mozfullscreenchange', handleFullScreenChange);
document.removeEventListener('MSFullscreenChange', handleFullScreenChange);
};
}, []);
return { enterFullScreen, exitFullScreen, toggleFullScreen };
};

View File

@ -65,7 +65,6 @@ export const useQortalGetSaveSettings = (myName) => {
const {hasPublishRecord, timestamp} = await getPublishRecord(myName)
if(hasPublishRecord){
const settings = await getPublish(myName)
console.log('settings', settings, timestamp, settingsLocalLastUpdated )
if(settings?.sortablePinnedApps && timestamp > settingsLocalLastUpdated){
setSortablePinnedApps(settings.sortablePinnedApps)