mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-03-28 08:15:55 +00:00
change save indicator
This commit is contained in:
parent
082c9c11cf
commit
7091e0b536
@ -9,4 +9,14 @@ export const sortablePinnedAppsAtom = atom({
|
|||||||
export const canSaveSettingToQdnAtom = atom({
|
export const canSaveSettingToQdnAtom = atom({
|
||||||
key: 'canSaveSettingToQdnAtom',
|
key: 'canSaveSettingToQdnAtom',
|
||||||
default: false,
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const settingsQDNLastUpdatedAtom = atom({
|
||||||
|
key: 'settingsQDNLastUpdatedAtom',
|
||||||
|
default: -100,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const settingsLocalLastUpdatedAtom = atom({
|
||||||
|
key: 'settingsLocalLastUpdatedAtom',
|
||||||
|
default: 0,
|
||||||
});
|
});
|
@ -12,28 +12,52 @@ import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../util
|
|||||||
import TabComponent from "./TabComponent";
|
import TabComponent from "./TabComponent";
|
||||||
import PushPinIcon from '@mui/icons-material/PushPin';
|
import PushPinIcon from '@mui/icons-material/PushPin';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import { useRecoilState } from "recoil";
|
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||||
import { sortablePinnedAppsAtom } from "../../atoms/global";
|
import { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from "../../atoms/global";
|
||||||
|
|
||||||
export function saveToLocalStorage(key, value) {
|
export function saveToLocalStorage(key, subKey, newValue) {
|
||||||
try {
|
try {
|
||||||
const serializedValue = JSON.stringify(value);
|
// Fetch existing data
|
||||||
localStorage.setItem(key, serializedValue);
|
const existingData = localStorage.getItem(key);
|
||||||
console.log(`Data saved to localStorage with key: ${key}`);
|
let combinedData = {};
|
||||||
|
|
||||||
|
if (existingData) {
|
||||||
|
// Parse the existing data
|
||||||
|
const parsedData = JSON.parse(existingData);
|
||||||
|
// Merge with the new data under the subKey
|
||||||
|
combinedData = {
|
||||||
|
...parsedData,
|
||||||
|
timestamp: Date.now(), // Update the root timestamp
|
||||||
|
[subKey]: newValue // Assuming the data is an array
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// If no existing data, just use the new data under the subKey
|
||||||
|
combinedData = {
|
||||||
|
timestamp: Date.now(), // Set the initial root timestamp
|
||||||
|
[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) {
|
} catch (error) {
|
||||||
console.error('Error saving to localStorage:', error);
|
console.error('Error saving to localStorage:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const AppsNavBar = () => {
|
export const AppsNavBar = () => {
|
||||||
const [tabs, setTabs] = useState([])
|
const [tabs, setTabs] = useState([])
|
||||||
const [selectedTab, setSelectedTab] = useState([])
|
const [selectedTab, setSelectedTab] = useState(null)
|
||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false)
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false)
|
||||||
const tabsRef = useRef(null);
|
const tabsRef = useRef(null);
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
|
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
@ -59,7 +83,7 @@ export const AppsNavBar = () => {
|
|||||||
const {tabs, selectedTab, isNewTabWindow} = e.detail?.data;
|
const {tabs, selectedTab, isNewTabWindow} = e.detail?.data;
|
||||||
|
|
||||||
setTabs([...tabs])
|
setTabs([...tabs])
|
||||||
setSelectedTab({...selectedTab})
|
setSelectedTab(!selectedTab ? nulll : {...selectedTab})
|
||||||
setIsNewTabWindow(isNewTabWindow)
|
setIsNewTabWindow(isNewTabWindow)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,6 +95,8 @@ export const AppsNavBar = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
console.log('selectedTab', selectedTab)
|
||||||
|
|
||||||
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === selectedTab?.name && item?.service === selectedTab?.service)
|
const isSelectedAppPinned = !!sortablePinnedApps?.find((item)=> item?.name === selectedTab?.name && item?.service === selectedTab?.service)
|
||||||
return (
|
return (
|
||||||
<AppsNavBarParent>
|
<AppsNavBarParent>
|
||||||
@ -115,6 +141,7 @@ export const AppsNavBar = () => {
|
|||||||
gap: '10px'
|
gap: '10px'
|
||||||
}}>
|
}}>
|
||||||
<ButtonBase onClick={()=> {
|
<ButtonBase onClick={()=> {
|
||||||
|
setSelectedTab(null)
|
||||||
executeEvent("newTabWindow", {
|
executeEvent("newTabWindow", {
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
@ -186,10 +213,11 @@ export const AppsNavBar = () => {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
saveToLocalStorage('sortablePinnedApps', updatedApps)
|
saveToLocalStorage('ext_saved_settings', 'sortablePinnedApps', updatedApps)
|
||||||
return updatedApps;
|
return updatedApps;
|
||||||
});
|
});
|
||||||
|
setSettingsLocalLastUpdated(Date.now())
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -7,9 +7,10 @@ import { Avatar, ButtonBase } from '@mui/material';
|
|||||||
import { AppCircle, AppCircleContainer, AppCircleLabel } from './Apps-styles';
|
import { AppCircle, AppCircleContainer, AppCircleLabel } from './Apps-styles';
|
||||||
import { getBaseApiReact } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
import { sortablePinnedAppsAtom } from '../../atoms/global';
|
import { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import { saveToLocalStorage } from './AppsNavBar';
|
import { saveToLocalStorage } from './AppsNavBar';
|
||||||
|
import { ContextMenuPinnedApps } from '../ContextMenuPinnedApps';
|
||||||
|
|
||||||
const SortableItem = ({ id, name, app }) => {
|
const SortableItem = ({ id, name, app }) => {
|
||||||
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
|
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
|
||||||
@ -27,6 +28,7 @@ const SortableItem = ({ id, name, app }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ContextMenuPinnedApps app={app}>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
ref={setNodeRef} {...attributes} {...listeners}
|
ref={setNodeRef} {...attributes} {...listeners}
|
||||||
sx={{
|
sx={{
|
||||||
@ -75,11 +77,13 @@ const SortableItem = ({ id, name, app }) => {
|
|||||||
</AppCircleLabel>
|
</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
</ContextMenuPinnedApps>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) => {
|
export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) => {
|
||||||
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
|
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
|
|
||||||
const transformPinnedApps = useMemo(()=> {
|
const transformPinnedApps = useMemo(()=> {
|
||||||
console.log({myWebsite, myApp, availableQapps, pinnedApps})
|
console.log({myWebsite, myApp, availableQapps, pinnedApps})
|
||||||
@ -149,8 +153,8 @@ export const SortablePinnedApps = ({ myWebsite, myApp, availableQapps = [] }) =
|
|||||||
|
|
||||||
const newOrder = arrayMove(transformPinnedApps, oldIndex, newIndex);
|
const newOrder = arrayMove(transformPinnedApps, oldIndex, newIndex);
|
||||||
setPinnedApps(newOrder);
|
setPinnedApps(newOrder);
|
||||||
saveToLocalStorage('sortablePinnedApps', newOrder)
|
saveToLocalStorage('ext_saved_settings','sortablePinnedApps', newOrder)
|
||||||
|
setSettingsLocalLastUpdated(Date.now())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
136
src/components/ContextMenuPinnedApps.tsx
Normal file
136
src/components/ContextMenuPinnedApps.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { ListItemIcon, Menu, MenuItem, Typography, styled } from '@mui/material';
|
||||||
|
import PushPinIcon from '@mui/icons-material/PushPin';
|
||||||
|
import { saveToLocalStorage } from './Apps/AppsNavBar';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { sortablePinnedAppsAtom } from '../atoms/global';
|
||||||
|
|
||||||
|
const CustomStyledMenu = styled(Menu)(({ theme }) => ({
|
||||||
|
'& .MuiPaper-root': {
|
||||||
|
backgroundColor: '#f9f9f9',
|
||||||
|
borderRadius: '12px',
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
boxShadow: '0 5px 15px rgba(0, 0, 0, 0.2)',
|
||||||
|
},
|
||||||
|
'& .MuiMenuItem-root': {
|
||||||
|
fontSize: '14px',
|
||||||
|
color: '#444',
|
||||||
|
transition: '0.3s background-color',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const ContextMenuPinnedApps = ({ children, app, setEnableDrag }) => {
|
||||||
|
const [menuPosition, setMenuPosition] = useState(null);
|
||||||
|
const longPressTimeout = useRef(null);
|
||||||
|
const maxHoldTimeout = useRef(null);
|
||||||
|
const preventClick = useRef(false);
|
||||||
|
const startTouchPosition = useRef({ x: 0, y: 0 }); // Track initial touch position
|
||||||
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
|
|
||||||
|
const handleContextMenu = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
preventClick.current = true;
|
||||||
|
setMenuPosition({
|
||||||
|
mouseX: event.clientX,
|
||||||
|
mouseY: event.clientY,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchStart = (event) => {
|
||||||
|
const { clientX, clientY } = event.touches[0];
|
||||||
|
startTouchPosition.current = { x: clientX, y: clientY };
|
||||||
|
|
||||||
|
longPressTimeout.current = setTimeout(() => {
|
||||||
|
preventClick.current = true;
|
||||||
|
setEnableDrag(false);
|
||||||
|
event.stopPropagation();
|
||||||
|
setMenuPosition({
|
||||||
|
mouseX: clientX,
|
||||||
|
mouseY: clientY,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// Set a maximum hold duration (e.g., 1.5 seconds)
|
||||||
|
maxHoldTimeout.current = setTimeout(() => {
|
||||||
|
clearTimeout(longPressTimeout.current);
|
||||||
|
}, 1500);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchMove = (event) => {
|
||||||
|
const { clientX, clientY } = event.touches[0];
|
||||||
|
const { x, y } = startTouchPosition.current;
|
||||||
|
|
||||||
|
// Determine if the touch has moved beyond a small threshold (e.g., 10px)
|
||||||
|
const movedEnough = Math.abs(clientX - x) > 10 || Math.abs(clientY - y) > 10;
|
||||||
|
|
||||||
|
if (movedEnough) {
|
||||||
|
clearTimeout(longPressTimeout.current);
|
||||||
|
clearTimeout(maxHoldTimeout.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchEnd = (event) => {
|
||||||
|
clearTimeout(longPressTimeout.current);
|
||||||
|
clearTimeout(maxHoldTimeout.current);
|
||||||
|
setEnableDrag(true);
|
||||||
|
if (preventClick.current) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
preventClick.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setMenuPosition(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
|
onTouchStart={handleTouchStart}
|
||||||
|
onTouchMove={handleTouchMove}
|
||||||
|
onTouchEnd={handleTouchEnd}
|
||||||
|
style={{ touchAction: 'none' }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<CustomStyledMenu
|
||||||
|
disableAutoFocusItem
|
||||||
|
open={!!menuPosition}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorReference="anchorPosition"
|
||||||
|
anchorPosition={
|
||||||
|
menuPosition
|
||||||
|
? { top: menuPosition.mouseY, left: menuPosition.mouseX }
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={(e) => {
|
||||||
|
handleClose(e);
|
||||||
|
setSortablePinnedApps((prev) => {
|
||||||
|
const updatedApps = prev.filter(
|
||||||
|
(item) => !(item?.name === app?.name && item?.service === app?.service)
|
||||||
|
);
|
||||||
|
saveToLocalStorage('ext_saved_settings', 'sortablePinnedApps', updatedApps);
|
||||||
|
return updatedApps;
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
<ListItemIcon sx={{ minWidth: '32px' }}>
|
||||||
|
<PushPinIcon fontSize="small" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant="inherit" sx={{ fontSize: '14px' }}>
|
||||||
|
Unpin app
|
||||||
|
</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
</CustomStyledMenu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -239,16 +239,22 @@ const Header = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Left Home Icon */}
|
{/* Left Home Icon */}
|
||||||
<IconButton
|
<Box
|
||||||
edge="start"
|
sx={{
|
||||||
color="inherit"
|
display: "flex",
|
||||||
aria-label="home"
|
alignItems: "center",
|
||||||
|
gap: "18px",
|
||||||
|
width: "75px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ButtonBase
|
||||||
|
|
||||||
onClick={goToHome}
|
onClick={goToHome}
|
||||||
// onClick={onHomeClick}
|
// onClick={onHomeClick}
|
||||||
>
|
>
|
||||||
<HomeIcon color="rgba(145, 145, 147, 1)" />
|
<HomeIcon color="rgba(145, 145, 147, 1)" />
|
||||||
</IconButton>
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
{/* Center Title */}
|
{/* Center Title */}
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
@ -261,18 +267,26 @@ const Header = ({
|
|||||||
>
|
>
|
||||||
QORTAL
|
QORTAL
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "30px",
|
||||||
|
width: "75px",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* Right Logout Icon */}
|
{/* Right Logout Icon */}
|
||||||
<IconButton
|
<Save />
|
||||||
|
<ButtonBase
|
||||||
onClick={logoutFunc}
|
onClick={logoutFunc}
|
||||||
edge="end"
|
|
||||||
color="inherit"
|
|
||||||
aria-label="logout"
|
|
||||||
|
|
||||||
// onClick={onLogoutClick}
|
// onClick={onLogoutClick}
|
||||||
>
|
>
|
||||||
<LogoutIcon color="rgba(145, 145, 147, 1)" />
|
<LogoutIcon color="rgba(145, 145, 147, 1)" />
|
||||||
</IconButton>
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useContext, useMemo, useState } from 'react'
|
import React, { useContext, useMemo, useState } from 'react'
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import isEqual from 'lodash/isEqual'; // Import deep comparison utility
|
import isEqual from 'lodash/isEqual'; // Import deep comparison utility
|
||||||
import { canSaveSettingToQdnAtom, sortablePinnedAppsAtom } from '../../atoms/global';
|
import { canSaveSettingToQdnAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from '../../atoms/global';
|
||||||
import { ButtonBase } from '@mui/material';
|
import { ButtonBase } from '@mui/material';
|
||||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||||
import { MyContext } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
@ -10,12 +10,15 @@ import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
|||||||
import { SaveIcon } from '../../assets/svgs/SaveIcon';
|
import { SaveIcon } from '../../assets/svgs/SaveIcon';
|
||||||
export const Save = () => {
|
export const Save = () => {
|
||||||
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
const [pinnedApps, setPinnedApps] = useRecoilState(sortablePinnedAppsAtom);
|
||||||
const [canSave, _] = useRecoilState(canSaveSettingToQdnAtom);
|
const [settingsQdnLastUpdated, setSettingsQdnLastUpdated] = useRecoilState(settingsQDNLastUpdatedAtom);
|
||||||
|
const [settingsLocalLastUpdated] = useRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
|
|
||||||
|
const [canSave] = useRecoilState(canSaveSettingToQdnAtom);
|
||||||
const [openSnack, setOpenSnack] = useState(false);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [infoSnack, setInfoSnack] = useState(null);
|
const [infoSnack, setInfoSnack] = useState(null);
|
||||||
const [oldPinnedApps, setOldPinnedApps] = useState(pinnedApps)
|
const [oldPinnedApps, setOldPinnedApps] = useState(pinnedApps)
|
||||||
console.log('oldpin', {oldPinnedApps, pinnedApps})
|
console.log('oldpin', {oldPinnedApps, pinnedApps}, settingsQdnLastUpdated, settingsLocalLastUpdated, settingsQdnLastUpdated < settingsLocalLastUpdated,)
|
||||||
const { show } = useContext(MyContext);
|
const { show } = useContext(MyContext);
|
||||||
|
|
||||||
const hasChanged = useMemo(()=> {
|
const hasChanged = useMemo(()=> {
|
||||||
@ -35,14 +38,21 @@ export const Save = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return !isEqual(oldChanges, newChanges)
|
console.log('!isEqual(oldChanges, newChanges)', !isEqual(oldChanges, newChanges))
|
||||||
}, [oldPinnedApps, pinnedApps])
|
if(settingsQdnLastUpdated === -100) return false
|
||||||
|
return !isEqual(oldChanges, newChanges) || settingsQdnLastUpdated < settingsLocalLastUpdated
|
||||||
|
}, [oldPinnedApps, pinnedApps, settingsQdnLastUpdated, settingsLocalLastUpdated])
|
||||||
|
|
||||||
const saveToQdn = async ()=> {
|
const saveToQdn = async ()=> {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const data64 = await objectToBase64({
|
const data64 = await objectToBase64({
|
||||||
sortablePinnedApps: pinnedApps
|
sortablePinnedApps: pinnedApps.map((item)=> {
|
||||||
|
return {
|
||||||
|
name: item?.name,
|
||||||
|
service: item?.service
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
const encryptData = await new Promise((res, rej) => {
|
const encryptData = await new Promise((res, rej) => {
|
||||||
chrome?.runtime?.sendMessage(
|
chrome?.runtime?.sendMessage(
|
||||||
@ -95,6 +105,7 @@ export const Save = () => {
|
|||||||
console.log('saved', response)
|
console.log('saved', response)
|
||||||
if(response?.identifier){
|
if(response?.identifier){
|
||||||
setOldPinnedApps(pinnedApps)
|
setOldPinnedApps(pinnedApps)
|
||||||
|
setSettingsQdnLastUpdated(Date.now())
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "success",
|
type: "success",
|
||||||
message:
|
message:
|
||||||
@ -115,11 +126,12 @@ export const Save = () => {
|
|||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log('settingsQdnLastUpdated', settingsQdnLastUpdated)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonBase onClick={saveToQdn} disabled={!hasChanged || !canSave || isLoading}>
|
<ButtonBase onClick={saveToQdn} disabled={!hasChanged || !canSave || isLoading || settingsQdnLastUpdated === -100}>
|
||||||
<SaveIcon
|
<SaveIcon
|
||||||
color={(hasChanged && !isLoading) ? '#5EB049' : '#8F8F91'}
|
color={settingsQdnLastUpdated === -100 ? '#8F8F91' : (hasChanged && !isLoading) ? '#5EB049' : '#8F8F91'}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<CustomizedSnackbars
|
<CustomizedSnackbars
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect } from 'react'
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import { canSaveSettingToQdnAtom, sortablePinnedAppsAtom } from './atoms/global';
|
import { canSaveSettingToQdnAtom, settingsLocalLastUpdatedAtom, settingsQDNLastUpdatedAtom, sortablePinnedAppsAtom } from './atoms/global';
|
||||||
import { getArbitraryEndpointReact, getBaseApiReact } from './App';
|
import { getArbitraryEndpointReact, getBaseApiReact } from './App';
|
||||||
import { decryptResource } from './components/Group/Group';
|
import { decryptResource } from './components/Group/Group';
|
||||||
import { base64ToUint8Array, uint8ArrayToObject } from './backgroundFunctions/encryption';
|
import { base64ToUint8Array, uint8ArrayToObject } from './backgroundFunctions/encryption';
|
||||||
@ -28,12 +28,13 @@ const getPublishRecord = async (myName) => {
|
|||||||
}
|
}
|
||||||
const publishData = await response.json();
|
const publishData = await response.json();
|
||||||
|
|
||||||
if(publishData?.length > 0) return true
|
if(publishData?.length > 0) return {hasPublishRecord: false, timestamp: publishData[0]?.updated || publishData[0].created}
|
||||||
|
|
||||||
return false
|
return {hasPublishRecord: false}
|
||||||
};
|
};
|
||||||
const getPublish = async (myName) => {
|
const getPublish = async (myName) => {
|
||||||
let data
|
try {
|
||||||
|
let data
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${myName}/ext_saved_settings?encoding=base64`
|
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${myName}/ext_saved_settings?encoding=base64`
|
||||||
);
|
);
|
||||||
@ -47,22 +48,32 @@ const getPublishRecord = async (myName) => {
|
|||||||
const dataint8Array = base64ToUint8Array(decryptedKey.data);
|
const dataint8Array = base64ToUint8Array(decryptedKey.data);
|
||||||
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
|
const decryptedKeyToObject = uint8ArrayToObject(dataint8Array);
|
||||||
return decryptedKeyToObject
|
return decryptedKeyToObject
|
||||||
|
} catch (error) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useQortalGetSaveSettings = (myName) => {
|
export const useQortalGetSaveSettings = (myName) => {
|
||||||
const setSortablePinnedApps = useSetRecoilState(sortablePinnedAppsAtom);
|
const setSortablePinnedApps = useSetRecoilState(sortablePinnedAppsAtom);
|
||||||
const setCanSave = useSetRecoilState(canSaveSettingToQdnAtom);
|
const setCanSave = useSetRecoilState(canSaveSettingToQdnAtom);
|
||||||
|
const setSettingsQDNLastUpdated = useSetRecoilState(settingsQDNLastUpdatedAtom);
|
||||||
|
const [settingsLocalLastUpdated] = useRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
const getSavedSettings = useCallback(async (myName)=> {
|
const getSavedSettings = useCallback(async (myName, settingsLocalLastUpdated)=> {
|
||||||
try {
|
try {
|
||||||
const hasPublishRecord = await getPublishRecord(myName)
|
const {hasPublishRecord, timestamp} = await getPublishRecord(myName)
|
||||||
if(hasPublishRecord){
|
if(hasPublishRecord){
|
||||||
const settings = await getPublish(myName)
|
const settings = await getPublish(myName)
|
||||||
if(settings?.sortablePinnedApps){
|
if(settings?.sortablePinnedApps && timestamp > settingsLocalLastUpdated){
|
||||||
fetchFromLocalStorage('sortablePinnedApps', settings.sortablePinnedApps)
|
|
||||||
setSortablePinnedApps(settings.sortablePinnedApps)
|
setSortablePinnedApps(settings.sortablePinnedApps)
|
||||||
|
setSettingsQDNLastUpdated(timestamp || 0)
|
||||||
}
|
}
|
||||||
|
if(!settings){
|
||||||
|
// set -100 to indicate that it couldn't fetch the publish
|
||||||
|
setSettingsQDNLastUpdated(-100)
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setSettingsQDNLastUpdated( 0)
|
||||||
}
|
}
|
||||||
setCanSave(true)
|
setCanSave(true)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -70,8 +81,8 @@ export const useQortalGetSaveSettings = (myName) => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
if(!myName) return
|
if(!myName || !settingsLocalLastUpdated) return
|
||||||
getSavedSettings(myName)
|
getSavedSettings(myName, settingsLocalLastUpdated)
|
||||||
}, [getSavedSettings, myName])
|
}, [getSavedSettings, myName, settingsLocalLastUpdated])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect } from 'react'
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { sortablePinnedAppsAtom } from './atoms/global';
|
import { settingsLocalLastUpdatedAtom, sortablePinnedAppsAtom } from './atoms/global';
|
||||||
|
|
||||||
function fetchFromLocalStorage(key) {
|
function fetchFromLocalStorage(key) {
|
||||||
try {
|
try {
|
||||||
@ -18,13 +18,14 @@ function fetchFromLocalStorage(key) {
|
|||||||
|
|
||||||
export const useRetrieveDataLocalStorage = () => {
|
export const useRetrieveDataLocalStorage = () => {
|
||||||
const setSortablePinnedApps = useSetRecoilState(sortablePinnedAppsAtom);
|
const setSortablePinnedApps = useSetRecoilState(sortablePinnedAppsAtom);
|
||||||
|
const setSettingsLocalLastUpdated = useSetRecoilState(settingsLocalLastUpdatedAtom);
|
||||||
|
|
||||||
const getSortablePinnedApps = useCallback(()=> {
|
const getSortablePinnedApps = useCallback(()=> {
|
||||||
const pinnedAppsLocal = fetchFromLocalStorage('sortablePinnedApps')
|
const pinnedAppsLocal = fetchFromLocalStorage('ext_saved_settings')
|
||||||
if(pinnedAppsLocal){
|
if(pinnedAppsLocal?.sortablePinnedApps){
|
||||||
setSortablePinnedApps(pinnedAppsLocal)
|
setSortablePinnedApps(pinnedAppsLocal?.sortablePinnedApps)
|
||||||
}
|
}
|
||||||
|
setSettingsLocalLastUpdated(pinnedAppsLocal?.timestamp || -1)
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user