finished apps feature for mobile

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

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}>