mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-06-07 17:06:58 +00:00
Merge pull request #2 from nbenaglia/feature/remove-is-mobile-check
Remove is mobile check
This commit is contained in:
commit
d2e81fda44
218
src/App.tsx
218
src/App.tsx
@ -118,9 +118,7 @@ import {
|
|||||||
import { useAppFullScreen } from './useAppFullscreen';
|
import { useAppFullScreen } from './useAppFullscreen';
|
||||||
import { NotAuthenticated } from './ExtStates/NotAuthenticated';
|
import { NotAuthenticated } from './ExtStates/NotAuthenticated';
|
||||||
import { handleGetFileFromIndexedDB } from './utils/indexedDB';
|
import { handleGetFileFromIndexedDB } from './utils/indexedDB';
|
||||||
import { CoreSyncStatus } from './components/CoreSyncStatus';
|
|
||||||
import { Wallets } from './Wallets';
|
import { Wallets } from './Wallets';
|
||||||
import { RandomSentenceGenerator } from './utils/seedPhrase/RandomSentenceGenerator';
|
|
||||||
import { useFetchResources } from './common/useFetchResources';
|
import { useFetchResources } from './common/useFetchResources';
|
||||||
import { Tutorials } from './components/Tutorials/Tutorials';
|
import { Tutorials } from './components/Tutorials/Tutorials';
|
||||||
import { useHandleTutorials } from './components/Tutorials/useHandleTutorials';
|
import { useHandleTutorials } from './components/Tutorials/useHandleTutorials';
|
||||||
@ -182,28 +180,6 @@ const defaultValues: MyContextInterface = {
|
|||||||
message: '',
|
message: '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export let isMobile = false;
|
|
||||||
|
|
||||||
const isMobileDevice = () => {
|
|
||||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
||||||
|
|
||||||
if (/android/i.test(userAgent)) {
|
|
||||||
return true; // Android device
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
|
|
||||||
return true; // iOS device
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isMobileDevice()) {
|
|
||||||
isMobile = true;
|
|
||||||
console.log('Running on a mobile device');
|
|
||||||
} else {
|
|
||||||
console.log('Running on a desktop');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const allQueues = {
|
export const allQueues = {
|
||||||
requestQueueCommentCount: requestQueueCommentCount,
|
requestQueueCommentCount: requestQueueCommentCount,
|
||||||
@ -436,16 +412,20 @@ function App() {
|
|||||||
const [isOpenMinting, setIsOpenMinting] = useState(false);
|
const [isOpenMinting, setIsOpenMinting] = useState(false);
|
||||||
const { toggleFullScreen } = useAppFullScreen(setFullScreen);
|
const { toggleFullScreen } = useAppFullScreen(setFullScreen);
|
||||||
const generatorRef = useRef(null);
|
const generatorRef = useRef(null);
|
||||||
|
|
||||||
const exportSeedphrase = () => {
|
const exportSeedphrase = () => {
|
||||||
const seedPhrase = generatorRef.current.parsedString;
|
const seedPhrase = generatorRef.current.parsedString;
|
||||||
saveSeedPhraseToDisk(seedPhrase);
|
saveSeedPhraseToDisk(seedPhrase);
|
||||||
};
|
};
|
||||||
|
|
||||||
const passwordRef = useRef<HTMLInputElement>(null);
|
const passwordRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (extState === 'wallet-dropped' && passwordRef.current) {
|
if (extState === 'wallet-dropped' && passwordRef.current) {
|
||||||
passwordRef.current.focus();
|
passwordRef.current.focus();
|
||||||
}
|
}
|
||||||
}, [extState]);
|
}, [extState]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isDevModeFromStorage = localStorage.getItem('isEnabledDevMode');
|
const isDevModeFromStorage = localStorage.getItem('isEnabledDevMode');
|
||||||
if (isDevModeFromStorage) {
|
if (isDevModeFromStorage) {
|
||||||
@ -491,31 +471,38 @@ function App() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}, [toggleFullScreen]);
|
}, [toggleFullScreen]);
|
||||||
|
|
||||||
//resets for recoil
|
//resets for recoil
|
||||||
const resetAtomSortablePinnedAppsAtom = useResetRecoilState(
|
const resetAtomSortablePinnedAppsAtom = useResetRecoilState(
|
||||||
sortablePinnedAppsAtom
|
sortablePinnedAppsAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAtomIsUsingImportExportSettingsAtom = useResetRecoilState(
|
const resetAtomIsUsingImportExportSettingsAtom = useResetRecoilState(
|
||||||
isUsingImportExportSettingsAtom
|
isUsingImportExportSettingsAtom
|
||||||
);
|
);
|
||||||
const resetAtomCanSaveSettingToQdnAtom = useResetRecoilState(
|
const resetAtomCanSaveSettingToQdnAtom = useResetRecoilState(
|
||||||
canSaveSettingToQdnAtom
|
canSaveSettingToQdnAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAtomSettingsQDNLastUpdatedAtom = useResetRecoilState(
|
const resetAtomSettingsQDNLastUpdatedAtom = useResetRecoilState(
|
||||||
settingsQDNLastUpdatedAtom
|
settingsQDNLastUpdatedAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAtomSettingsLocalLastUpdatedAtom = useResetRecoilState(
|
const resetAtomSettingsLocalLastUpdatedAtom = useResetRecoilState(
|
||||||
settingsLocalLastUpdatedAtom
|
settingsLocalLastUpdatedAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAtomOldPinnedAppsAtom = useResetRecoilState(oldPinnedAppsAtom);
|
const resetAtomOldPinnedAppsAtom = useResetRecoilState(oldPinnedAppsAtom);
|
||||||
const resetAtomQMailLastEnteredTimestampAtom = useResetRecoilState(
|
const resetAtomQMailLastEnteredTimestampAtom = useResetRecoilState(
|
||||||
qMailLastEnteredTimestampAtom
|
qMailLastEnteredTimestampAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAtomMailsAtom = useResetRecoilState(mailsAtom);
|
const resetAtomMailsAtom = useResetRecoilState(mailsAtom);
|
||||||
const resetGroupPropertiesAtom = useResetRecoilState(groupsPropertiesAtom);
|
const resetGroupPropertiesAtom = useResetRecoilState(groupsPropertiesAtom);
|
||||||
const resetLastPaymentSeenTimestampAtom = useResetRecoilState(
|
const resetLastPaymentSeenTimestampAtom = useResetRecoilState(
|
||||||
lastPaymentSeenTimestampAtom
|
lastPaymentSeenTimestampAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetAllRecoil = () => {
|
const resetAllRecoil = () => {
|
||||||
resetAtomSortablePinnedAppsAtom();
|
resetAtomSortablePinnedAppsAtom();
|
||||||
resetAtomCanSaveSettingToQdnAtom();
|
resetAtomCanSaveSettingToQdnAtom();
|
||||||
@ -528,34 +515,11 @@ function App() {
|
|||||||
resetGroupPropertiesAtom();
|
resetGroupPropertiesAtom();
|
||||||
resetLastPaymentSeenTimestampAtom();
|
resetLastPaymentSeenTimestampAtom();
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
|
||||||
if (!isMobile) return;
|
|
||||||
// Function to set the height of the app to the viewport height
|
|
||||||
const resetHeight = () => {
|
|
||||||
const height = window.visualViewport
|
|
||||||
? window.visualViewport.height
|
|
||||||
: window.innerHeight;
|
|
||||||
// Set the height to the root element (usually #root)
|
|
||||||
document.getElementById('root').style.height = height + 'px';
|
|
||||||
setRootHeight(height + 'px');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the initial height
|
|
||||||
resetHeight();
|
|
||||||
|
|
||||||
// Add event listeners for resize and visualViewport changes
|
|
||||||
window.addEventListener('resize', resetHeight);
|
|
||||||
window.visualViewport?.addEventListener('resize', resetHeight);
|
|
||||||
|
|
||||||
// Clean up the event listeners when the component unmounts
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', resetHeight);
|
|
||||||
window.visualViewport?.removeEventListener('resize', resetHeight);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
const handleSetGlobalApikey = (key) => {
|
const handleSetGlobalApikey = (key) => {
|
||||||
globalApiKey = key;
|
globalApiKey = key;
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -1232,14 +1196,6 @@ function App() {
|
|||||||
// Handler for when the window gains focus
|
// Handler for when the window gains focus
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
setIsFocused(true);
|
setIsFocused(true);
|
||||||
if (isMobile) {
|
|
||||||
window.sendMessage('clearAllNotifications', {}).catch((error) => {
|
|
||||||
console.error(
|
|
||||||
'Failed to clear notifications:',
|
|
||||||
error.message || 'An error occurred'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handler for when the window loses focus
|
// Handler for when the window loses focus
|
||||||
@ -1255,14 +1211,6 @@ function App() {
|
|||||||
const handleVisibilityChange = () => {
|
const handleVisibilityChange = () => {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
setIsFocused(true);
|
setIsFocused(true);
|
||||||
if (isMobile) {
|
|
||||||
window.sendMessage('clearAllNotifications', {}).catch((error) => {
|
|
||||||
console.error(
|
|
||||||
'Failed to clear notifications:',
|
|
||||||
error.message || 'An error occurred'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setIsFocused(false);
|
setIsFocused(false);
|
||||||
}
|
}
|
||||||
@ -1315,7 +1263,7 @@ function App() {
|
|||||||
return (
|
return (
|
||||||
<AuthenticatedContainerInnerLeft
|
<AuthenticatedContainerInnerLeft
|
||||||
sx={{
|
sx={{
|
||||||
overflowY: isMobile && 'auto',
|
overflowY: 'auto',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
minWidth: '225px',
|
minWidth: '225px',
|
||||||
}}
|
}}
|
||||||
@ -1568,27 +1516,9 @@ function App() {
|
|||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
width: isMobile ? '100vw' : 'auto',
|
width: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isMobile && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
padding: '10px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CloseIcon
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpenDrawerProfile(false);
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
cursor: 'pointer',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{desktopViewMode !== 'apps' &&
|
{desktopViewMode !== 'apps' &&
|
||||||
desktopViewMode !== 'dev' &&
|
desktopViewMode !== 'dev' &&
|
||||||
desktopViewMode !== 'chat' && <>{renderProfileLeft()}</>}
|
desktopViewMode !== 'chat' && <>{renderProfileLeft()}</>}
|
||||||
@ -1609,51 +1539,46 @@ function App() {
|
|||||||
>
|
>
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
{!isMobile && (
|
<Tooltip
|
||||||
<>
|
title={
|
||||||
<Spacer height="20px" />
|
<span
|
||||||
<Tooltip
|
style={{
|
||||||
title={
|
fontSize: '14px',
|
||||||
<span
|
fontWeight: 700,
|
||||||
style={{
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
LOG OUT
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
placement="left"
|
|
||||||
arrow
|
|
||||||
sx={{ fontSize: '24' }}
|
|
||||||
slotProps={{
|
|
||||||
tooltip: {
|
|
||||||
sx: {
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
arrow: {
|
|
||||||
sx: {
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Logout
|
LOG OUT
|
||||||
style={{
|
</span>
|
||||||
cursor: 'pointer',
|
}
|
||||||
width: '20px',
|
placement="left"
|
||||||
height: 'auto',
|
arrow
|
||||||
}}
|
sx={{ fontSize: '24' }}
|
||||||
onClick={() => {
|
slotProps={{
|
||||||
logoutFunc();
|
tooltip: {
|
||||||
setIsOpenDrawerProfile(false);
|
sx: {
|
||||||
}}
|
color: theme.palette.text.primary,
|
||||||
/>
|
backgroundColor: theme.palette.background.default,
|
||||||
</Tooltip>
|
},
|
||||||
</>
|
},
|
||||||
)}
|
arrow: {
|
||||||
|
sx: {
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Logout
|
||||||
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: '20px',
|
||||||
|
height: 'auto',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
logoutFunc();
|
||||||
|
setIsOpenDrawerProfile(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
@ -2009,7 +1934,7 @@ function App() {
|
|||||||
return (
|
return (
|
||||||
<AppContainer
|
<AppContainer
|
||||||
sx={{
|
sx={{
|
||||||
height: isMobile ? '100%' : '100vh',
|
height: '100vh',
|
||||||
// backgroundImage: desktopViewMode === "apps" && 'url("appsBg.svg")',
|
// backgroundImage: desktopViewMode === "apps" && 'url("appsBg.svg")',
|
||||||
// backgroundSize: desktopViewMode === "apps" && "cover",
|
// backgroundSize: desktopViewMode === "apps" && "cover",
|
||||||
// backgroundPosition: desktopViewMode === "apps" && "center",
|
// backgroundPosition: desktopViewMode === "apps" && "center",
|
||||||
@ -2075,51 +2000,50 @@ function App() {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100vw',
|
|
||||||
height: isMobile ? '100%' : '100vh',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: isMobile ? 'column' : 'row',
|
flexDirection: 'row',
|
||||||
overflow: isMobile && 'hidden',
|
height: '100vh',
|
||||||
|
width: '100vw',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Group
|
<Group
|
||||||
logoutFunc={logoutFunc}
|
|
||||||
balance={balance}
|
balance={balance}
|
||||||
userInfo={userInfo}
|
desktopViewMode={desktopViewMode}
|
||||||
myAddress={address}
|
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
isMain={isMain}
|
isMain={isMain}
|
||||||
isOpenDrawerProfile={isOpenDrawerProfile}
|
isOpenDrawerProfile={isOpenDrawerProfile}
|
||||||
setIsOpenDrawerProfile={setIsOpenDrawerProfile}
|
logoutFunc={logoutFunc}
|
||||||
desktopViewMode={desktopViewMode}
|
myAddress={address}
|
||||||
setDesktopViewMode={setDesktopViewMode}
|
setDesktopViewMode={setDesktopViewMode}
|
||||||
|
setIsOpenDrawerProfile={setIsOpenDrawerProfile}
|
||||||
|
userInfo={userInfo}
|
||||||
/>
|
/>
|
||||||
{!isMobile && renderProfile()}
|
renderProfile()
|
||||||
</Box>
|
</Box>
|
||||||
</MyContext.Provider>
|
</MyContext.Provider>
|
||||||
)}
|
)}
|
||||||
{isOpenSendQort && isMainWindow && (
|
{isOpenSendQort && isMainWindow && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
height: '100%',
|
|
||||||
position: 'fixed',
|
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
height: '100%',
|
||||||
|
position: 'fixed',
|
||||||
|
width: '100%',
|
||||||
zIndex: 10000,
|
zIndex: 10000,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Spacer height="22px" />
|
<Spacer height="22px" />
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'flex-start',
|
|
||||||
paddingLeft: '22px',
|
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
maxWidth: '700px',
|
maxWidth: '700px',
|
||||||
|
paddingLeft: '22px',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Return
|
<Return
|
||||||
@ -2130,7 +2054,9 @@ function App() {
|
|||||||
onClick={returnToMain}
|
onClick={returnToMain}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
|
|
||||||
<QortPayment
|
<QortPayment
|
||||||
balance={balance}
|
balance={balance}
|
||||||
show={show}
|
show={show}
|
||||||
|
26
src/assets/Icons/Search.tsx
Normal file
26
src/assets/Icons/Search.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useTheme } from '@mui/material';
|
||||||
|
import { SVGProps } from './interfaces';
|
||||||
|
|
||||||
|
export const Search: React.FC<SVGProps> = ({ color, opacity, ...children }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const setColor = color ? color : theme.palette.text.primary;
|
||||||
|
const setOpacity = opacity ? opacity : 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...children}
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.08728 0.00158245C2.72507 0.00158245 0 2.7262 0 6.08784C0 9.44948 2.72507 12.1741 6.08728 12.1741C7.62099 12.1741 9.02317 11.6043 10.0947 10.6668L13.3088 13.8803C13.3881 13.9596 13.4911 14 13.595 14C13.6988 14 13.8018 13.9596 13.8811 13.8803C14.0396 13.7218 14.0396 13.4643 13.8811 13.3066L10.667 10.093C11.6047 9.02162 12.1746 7.62202 12.1746 6.08626C12.1746 2.72461 9.44951 0 6.0873 0L6.08728 0.00158245ZM6.08728 11.3626C3.17756 11.3626 0.811637 8.99707 0.811637 6.08784C0.811637 3.17861 3.17756 0.813083 6.08728 0.813083C8.997 0.813083 11.3629 3.17861 11.3629 6.08784C11.3629 8.99707 8.997 11.3626 6.08728 11.3626Z"
|
||||||
|
fill={setColor}
|
||||||
|
opacity={setOpacity}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
Before Width: | Height: | Size: 4.0 KiB |
@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import './qortalRequests';
|
import './qortalRequests';
|
||||||
import { isArray } from 'lodash';
|
import { isArray } from 'lodash';
|
||||||
import {
|
import {
|
||||||
@ -30,7 +29,6 @@ import { RequestQueueWithPromise } from './utils/queue/queue';
|
|||||||
import { validateAddress } from './utils/validateAddress';
|
import { validateAddress } from './utils/validateAddress';
|
||||||
import { Sha256 } from 'asmcrypto.js';
|
import { Sha256 } from 'asmcrypto.js';
|
||||||
import { TradeBotRespondMultipleRequest } from './transactions/TradeBotRespondMultipleRequest';
|
import { TradeBotRespondMultipleRequest } from './transactions/TradeBotRespondMultipleRequest';
|
||||||
|
|
||||||
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from './constants/resourceTypes';
|
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from './constants/resourceTypes';
|
||||||
import {
|
import {
|
||||||
addDataPublishesCase,
|
addDataPublishesCase,
|
||||||
@ -111,6 +109,7 @@ export let groupSecretkeys = {};
|
|||||||
export function cleanUrl(url) {
|
export function cleanUrl(url) {
|
||||||
return url?.replace(/^(https?:\/\/)?(www\.)?/, '');
|
return url?.replace(/^(https?:\/\/)?(www\.)?/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProtocol(url) {
|
export function getProtocol(url) {
|
||||||
if (url?.startsWith('https://')) {
|
if (url?.startsWith('https://')) {
|
||||||
return 'https';
|
return 'https';
|
||||||
@ -130,7 +129,6 @@ export const groupApiLocal = 'http://127.0.0.1:12391';
|
|||||||
export const groupApiSocketLocal = 'ws://127.0.0.1:12391';
|
export const groupApiSocketLocal = 'ws://127.0.0.1:12391';
|
||||||
const timeDifferenceForNotificationChatsBackground = 86400000;
|
const timeDifferenceForNotificationChatsBackground = 86400000;
|
||||||
const requestQueueAnnouncements = new RequestQueueWithPromise(1);
|
const requestQueueAnnouncements = new RequestQueueWithPromise(1);
|
||||||
let isMobile = true;
|
|
||||||
|
|
||||||
function handleNotificationClick(notificationId) {
|
function handleNotificationClick(notificationId) {
|
||||||
// Decode the notificationId if it was encoded
|
// Decode the notificationId if it was encoded
|
||||||
@ -193,26 +191,6 @@ function handleNotificationClick(notificationId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMobileDevice = () => {
|
|
||||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
||||||
|
|
||||||
if (/android/i.test(userAgent)) {
|
|
||||||
return true; // Android device
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
|
|
||||||
return true; // iOS device
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isMobileDevice()) {
|
|
||||||
isMobile = true;
|
|
||||||
console.log('Running on a mobile device');
|
|
||||||
} else {
|
|
||||||
console.log('Running on a desktop');
|
|
||||||
}
|
|
||||||
const allQueues = {
|
const allQueues = {
|
||||||
requestQueueAnnouncements: requestQueueAnnouncements,
|
requestQueueAnnouncements: requestQueueAnnouncements,
|
||||||
};
|
};
|
||||||
@ -264,7 +242,9 @@ export const getForeignKey = async (foreignBlockchain) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const pauseAllQueues = () => controlAllQueues('pause');
|
export const pauseAllQueues = () => controlAllQueues('pause');
|
||||||
|
|
||||||
export const resumeAllQueues = () => controlAllQueues('resume');
|
export const resumeAllQueues = () => controlAllQueues('resume');
|
||||||
|
|
||||||
export const checkDifference = (
|
export const checkDifference = (
|
||||||
createdTimestamp,
|
createdTimestamp,
|
||||||
diff = timeDifferenceForNotificationChatsBackground
|
diff = timeDifferenceForNotificationChatsBackground
|
||||||
@ -302,6 +282,7 @@ export const getBaseApi = async (customApi?: string) => {
|
|||||||
return groupApi;
|
return groupApi;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isUsingLocal = async () => {
|
export const isUsingLocal = async () => {
|
||||||
const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously
|
const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously
|
||||||
if (apiKey?.url) {
|
if (apiKey?.url) {
|
||||||
@ -345,13 +326,13 @@ const proxyAccountAddress = 'QXPejUe5Za1KD3zCMViWCX35AreMQ9H7ku';
|
|||||||
const proxyAccountPublicKey = '5hP6stDWybojoDw5t8z9D51nV945oMPX7qBd29rhX1G7';
|
const proxyAccountPublicKey = '5hP6stDWybojoDw5t8z9D51nV945oMPX7qBd29rhX1G7';
|
||||||
const pendingResponses = new Map();
|
const pendingResponses = new Map();
|
||||||
let groups = null;
|
let groups = null;
|
||||||
|
|
||||||
let socket;
|
let socket;
|
||||||
let timeoutId;
|
let timeoutId;
|
||||||
let groupSocketTimeout;
|
let groupSocketTimeout;
|
||||||
let socketTimeout: any;
|
let socketTimeout: any;
|
||||||
let interval;
|
let interval;
|
||||||
let intervalThreads;
|
let intervalThreads;
|
||||||
|
|
||||||
// Function to check each API endpoint
|
// Function to check each API endpoint
|
||||||
export async function findUsableApi() {
|
export async function findUsableApi() {
|
||||||
for (const endpoint of apiEndpoints) {
|
for (const endpoint of apiEndpoints) {
|
||||||
@ -435,6 +416,7 @@ async function checkWebviewFocus() {
|
|||||||
window.addEventListener('message', handleMessage);
|
window.addEventListener('message', handleMessage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const worker = new ChatComputePowWorker();
|
const worker = new ChatComputePowWorker();
|
||||||
|
|
||||||
export async function performPowTask(chatBytes, difficulty) {
|
export async function performPowTask(chatBytes, difficulty) {
|
||||||
@ -584,6 +566,7 @@ const handleNotificationDirect = async (directs) => {
|
|||||||
setChatHeadsDirect(dataDirects);
|
setChatHeadsDirect(dataDirects);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getThreadActivity(): Promise<any | null> {
|
async function getThreadActivity(): Promise<any | null> {
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
const address = wallet.address0;
|
const address = wallet.address0;
|
||||||
@ -852,6 +835,7 @@ export async function getNameInfoForOthers(address) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAddressInfo(address) {
|
export async function getAddressInfo(address) {
|
||||||
const validApi = await getBaseApi();
|
const validApi = await getBaseApi();
|
||||||
const response = await fetch(validApi + '/addresses/' + address);
|
const response = await fetch(validApi + '/addresses/' + address);
|
||||||
@ -932,6 +916,7 @@ async function getTradeInfo(qortalAtAddress) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTradesInfo(qortalAtAddresses) {
|
async function getTradesInfo(qortalAtAddresses) {
|
||||||
// Use Promise.all to fetch data for all addresses concurrently
|
// Use Promise.all to fetch data for all addresses concurrently
|
||||||
const trades = await Promise.all(
|
const trades = await Promise.all(
|
||||||
@ -951,6 +936,7 @@ export async function getBalanceInfo() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLTCBalance() {
|
export async function getLTCBalance() {
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
let _url = `${buyTradeNodeBaseUrl}/crosschain/ltc/walletbalance`;
|
let _url = `${buyTradeNodeBaseUrl}/crosschain/ltc/walletbalance`;
|
||||||
@ -1075,6 +1061,7 @@ const transaction = async (
|
|||||||
data: res,
|
data: res,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeTransactionRequest = async (
|
const makeTransactionRequest = async (
|
||||||
receiver,
|
receiver,
|
||||||
lastRef,
|
lastRef,
|
||||||
@ -1113,6 +1100,7 @@ export const getLastRef = async () => {
|
|||||||
const data = await response.text();
|
const data = await response.text();
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendQortFee = async (): Promise<number> => {
|
export const sendQortFee = async (): Promise<number> => {
|
||||||
const validApi = await getBaseApi();
|
const validApi = await getBaseApi();
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@ -1386,6 +1374,7 @@ export async function signChatFunc(
|
|||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sbrk(size, heap) {
|
function sbrk(size, heap) {
|
||||||
let brk = 512 * 1024; // stack top
|
let brk = 512 * 1024; // stack top
|
||||||
let old = brk;
|
let old = brk;
|
||||||
|
@ -2,7 +2,6 @@ import React, { useEffect, useMemo, useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
AppCircleLabel,
|
|
||||||
AppDownloadButton,
|
AppDownloadButton,
|
||||||
AppDownloadButtonText,
|
AppDownloadButtonText,
|
||||||
AppInfoAppName,
|
AppInfoAppName,
|
||||||
@ -17,14 +16,11 @@ import {
|
|||||||
AppsCategoryInfoValue,
|
AppsCategoryInfoValue,
|
||||||
AppsInfoDescription,
|
AppsInfoDescription,
|
||||||
AppsLibraryContainer,
|
AppsLibraryContainer,
|
||||||
AppsParent,
|
|
||||||
AppsWidthLimiter,
|
AppsWidthLimiter,
|
||||||
} from './Apps-styles';
|
} from './Apps-styles';
|
||||||
import { Avatar, Box, ButtonBase, InputBase } from '@mui/material';
|
import { Avatar, Box } from '@mui/material';
|
||||||
import { Add } from '@mui/icons-material';
|
import { getBaseApiReact } from '../../App';
|
||||||
import { getBaseApiReact, isMobile } from '../../App';
|
|
||||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||||
|
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
import { AppRating } from './AppRating';
|
import { AppRating } from './AppRating';
|
||||||
@ -51,9 +47,8 @@ export const AppInfo = ({ app, myName }) => {
|
|||||||
return (
|
return (
|
||||||
<AppsLibraryContainer
|
<AppsLibraryContainer
|
||||||
sx={{
|
sx={{
|
||||||
height: !isMobile && '100%',
|
height: '100%',
|
||||||
justifyContent: !isMobile && 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
alignItems: isMobile && 'center',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@ -64,7 +59,8 @@ export const AppInfo = ({ app, myName }) => {
|
|||||||
width: '90%',
|
width: '90%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && <Spacer height="30px" />}
|
<Spacer height="30px" />
|
||||||
|
|
||||||
<AppsWidthLimiter>
|
<AppsWidthLimiter>
|
||||||
<AppInfoSnippetContainer>
|
<AppInfoSnippetContainer>
|
||||||
<AppInfoSnippetLeft
|
<AppInfoSnippetLeft
|
||||||
@ -172,15 +168,9 @@ export const AppInfo = ({ app, myName }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppDownloadButtonText>
|
<AppDownloadButtonText>
|
||||||
{!isMobile ? (
|
{isSelectedAppPinned
|
||||||
<>
|
? 'Unpin from dashboard'
|
||||||
{isSelectedAppPinned
|
: 'Pin to dashboard'}
|
||||||
? 'Unpin from dashboard'
|
|
||||||
: 'Pin to dashboard'}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>{isSelectedAppPinned ? 'Unpin' : 'Pin'}</>
|
|
||||||
)}
|
|
||||||
</AppDownloadButtonText>
|
</AppDownloadButtonText>
|
||||||
</AppDownloadButton>
|
</AppDownloadButton>
|
||||||
<AppDownloadButton
|
<AppDownloadButton
|
||||||
|
@ -12,9 +12,8 @@ import {
|
|||||||
AppInfoUserName,
|
AppInfoUserName,
|
||||||
} from './Apps-styles';
|
} from './Apps-styles';
|
||||||
import { Avatar, ButtonBase } from '@mui/material';
|
import { Avatar, ButtonBase } from '@mui/material';
|
||||||
import { getBaseApiReact, isMobile } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||||
|
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
import { AppRating } from './AppRating';
|
import { AppRating } from './AppRating';
|
||||||
@ -124,52 +123,49 @@ export const AppInfoSnippet = ({
|
|||||||
gap: '10px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
<AppDownloadButton
|
||||||
<AppDownloadButton
|
onClick={() => {
|
||||||
onClick={() => {
|
setSortablePinnedApps((prev) => {
|
||||||
setSortablePinnedApps((prev) => {
|
let updatedApps;
|
||||||
let updatedApps;
|
|
||||||
|
|
||||||
if (isSelectedAppPinned) {
|
if (isSelectedAppPinned) {
|
||||||
// Remove the selected app if it is pinned
|
// Remove the selected app if it is pinned
|
||||||
updatedApps = prev.filter(
|
updatedApps = prev.filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
!(
|
!(
|
||||||
item?.name === app?.name &&
|
item?.name === app?.name && item?.service === app?.service
|
||||||
item?.service === app?.service
|
)
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Add the selected app if it is not pinned
|
|
||||||
updatedApps = [
|
|
||||||
...prev,
|
|
||||||
{
|
|
||||||
name: app?.name,
|
|
||||||
service: app?.service,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
saveToLocalStorage(
|
|
||||||
'ext_saved_settings',
|
|
||||||
'sortablePinnedApps',
|
|
||||||
updatedApps
|
|
||||||
);
|
);
|
||||||
return updatedApps;
|
} else {
|
||||||
});
|
// Add the selected app if it is not pinned
|
||||||
setSettingsLocalLastUpdated(Date.now());
|
updatedApps = [
|
||||||
}}
|
...prev,
|
||||||
sx={{
|
{
|
||||||
backgroundColor: '#359ff7ff',
|
name: app?.name,
|
||||||
opacity: isSelectedAppPinned ? 0.6 : 1,
|
service: app?.service,
|
||||||
}}
|
},
|
||||||
>
|
];
|
||||||
<AppDownloadButtonText>
|
}
|
||||||
{' '}
|
|
||||||
{isSelectedAppPinned ? 'Unpin' : 'Pin'}
|
saveToLocalStorage(
|
||||||
</AppDownloadButtonText>
|
'ext_saved_settings',
|
||||||
</AppDownloadButton>
|
'sortablePinnedApps',
|
||||||
)}
|
updatedApps
|
||||||
|
);
|
||||||
|
return updatedApps;
|
||||||
|
});
|
||||||
|
setSettingsLocalLastUpdated(Date.now());
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#359ff7ff',
|
||||||
|
opacity: isSelectedAppPinned ? 0.6 : 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AppDownloadButtonText>
|
||||||
|
{' '}
|
||||||
|
{isSelectedAppPinned ? 'Unpin' : 'Pin'}
|
||||||
|
</AppDownloadButtonText>
|
||||||
|
</AppDownloadButton>
|
||||||
|
|
||||||
<AppDownloadButton
|
<AppDownloadButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from "react";
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
@ -19,90 +19,74 @@ import {
|
|||||||
PublishQAppCTAButton,
|
PublishQAppCTAButton,
|
||||||
PublishQAppChoseFile,
|
PublishQAppChoseFile,
|
||||||
PublishQAppInfo,
|
PublishQAppInfo,
|
||||||
} from "./Apps-styles";
|
} from './Apps-styles';
|
||||||
import {
|
import { InputBase, InputLabel, MenuItem, Select } from '@mui/material';
|
||||||
Avatar,
|
import { styled } from '@mui/system';
|
||||||
Box,
|
import UnfoldMoreRoundedIcon from '@mui/icons-material/UnfoldMoreRounded';
|
||||||
ButtonBase,
|
import { Add } from '@mui/icons-material';
|
||||||
InputBase,
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
InputLabel,
|
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||||
MenuItem,
|
import { Spacer } from '../../common/Spacer';
|
||||||
Select,
|
import { executeEvent } from '../../utils/events';
|
||||||
} from "@mui/material";
|
import { useDropzone } from 'react-dropzone';
|
||||||
import {
|
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
||||||
Select as BaseSelect,
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
SelectProps,
|
import { getFee } from '../../background';
|
||||||
selectClasses,
|
import { fileToBase64 } from '../../utils/fileReading';
|
||||||
SelectRootSlotProps,
|
|
||||||
} from "@mui/base/Select";
|
|
||||||
import { Option as BaseOption, optionClasses } from "@mui/base/Option";
|
|
||||||
import { styled } from "@mui/system";
|
|
||||||
import UnfoldMoreRoundedIcon from "@mui/icons-material/UnfoldMoreRounded";
|
|
||||||
import { Add } from "@mui/icons-material";
|
|
||||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
|
||||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
|
||||||
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
|
||||||
import { executeEvent } from "../../utils/events";
|
|
||||||
import { useDropzone } from "react-dropzone";
|
|
||||||
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
|
|
||||||
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
|
|
||||||
import { getFee } from "../../background";
|
|
||||||
import { fileToBase64 } from "../../utils/fileReading";
|
|
||||||
|
|
||||||
const CustomSelect = styled(Select)({
|
const CustomSelect = styled(Select)({
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
maxWidth: "450px",
|
maxWidth: '450px',
|
||||||
"& .MuiSelect-select": {
|
'& .MuiSelect-select': {
|
||||||
padding: "0px",
|
padding: '0px',
|
||||||
},
|
},
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
borderColor: "none", // Border color on hover
|
borderColor: 'none', // Border color on hover
|
||||||
},
|
},
|
||||||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
||||||
borderColor: "none", // Border color when focused
|
borderColor: 'none', // Border color when focused
|
||||||
},
|
},
|
||||||
"&.Mui-disabled": {
|
'&.Mui-disabled': {
|
||||||
opacity: 0.5, // Lower opacity when disabled
|
opacity: 0.5, // Lower opacity when disabled
|
||||||
},
|
},
|
||||||
"& .MuiSvgIcon-root": {
|
'& .MuiSvgIcon-root': {
|
||||||
color: "var(--50-white, #FFFFFF80)",
|
color: 'var(--50-white, #FFFFFF80)',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const CustomMenuItem = styled(MenuItem)({
|
const CustomMenuItem = styled(MenuItem)({
|
||||||
backgroundColor: "#1f1f1f", // Background for dropdown items
|
backgroundColor: '#1f1f1f', // Background for dropdown items
|
||||||
color: "#ccc",
|
color: '#ccc',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: "#333", // Darker background on hover
|
backgroundColor: '#333', // Darker background on hover
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AppPublish = ({ names, categories }) => {
|
export const AppPublish = ({ names, categories }) => {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState('');
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState('');
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState('');
|
||||||
const [category, setCategory] = useState("");
|
const [category, setCategory] = useState('');
|
||||||
const [appType, setAppType] = useState("APP");
|
const [appType, setAppType] = useState('APP');
|
||||||
const [file, setFile] = useState(null);
|
const [file, setFile] = useState(null);
|
||||||
const { show } = useContext(MyContext);
|
const { show } = useContext(MyContext);
|
||||||
|
|
||||||
const [tag1, setTag1] = useState("");
|
const [tag1, setTag1] = useState('');
|
||||||
const [tag2, setTag2] = useState("");
|
const [tag2, setTag2] = useState('');
|
||||||
const [tag3, setTag3] = useState("");
|
const [tag3, setTag3] = useState('');
|
||||||
const [tag4, setTag4] = useState("");
|
const [tag4, setTag4] = useState('');
|
||||||
const [tag5, setTag5] = useState("");
|
const [tag5, setTag5] = useState('');
|
||||||
const [openSnack, setOpenSnack] = useState(false);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [infoSnack, setInfoSnack] = useState(null);
|
const [infoSnack, setInfoSnack] = useState(null);
|
||||||
const [isLoading, setIsLoading] = useState("");
|
const [isLoading, setIsLoading] = useState('');
|
||||||
const maxFileSize = appType === "APP" ? 50 * 1024 * 1024 : 400 * 1024 * 1024; // 50MB or 400MB
|
const maxFileSize = appType === 'APP' ? 50 * 1024 * 1024 : 400 * 1024 * 1024; // 50MB or 400MB
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
accept: {
|
accept: {
|
||||||
"application/zip": [".zip"], // Only accept zip files
|
'application/zip': ['.zip'], // Only accept zip files
|
||||||
},
|
},
|
||||||
maxSize: maxFileSize, // Set the max size based on appType
|
maxSize: maxFileSize, // Set the max size based on appType
|
||||||
multiple: false, // Disable multiple file uploads
|
multiple: false, // Disable multiple file uploads
|
||||||
@ -114,7 +98,7 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
onDropRejected: (fileRejections) => {
|
onDropRejected: (fileRejections) => {
|
||||||
fileRejections.forEach(({ file, errors }) => {
|
fileRejections.forEach(({ file, errors }) => {
|
||||||
errors.forEach((error) => {
|
errors.forEach((error) => {
|
||||||
if (error.code === "file-too-large") {
|
if (error.code === 'file-too-large') {
|
||||||
console.error(
|
console.error(
|
||||||
`File ${file.name} is too large. Max size allowed is ${
|
`File ${file.name} is too large. Max size allowed is ${
|
||||||
maxFileSize / (1024 * 1024)
|
maxFileSize / (1024 * 1024)
|
||||||
@ -128,13 +112,13 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
|
|
||||||
const getQapp = React.useCallback(async (name, appType) => {
|
const getQapp = React.useCallback(async (name, appType) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading("Loading app information");
|
setIsLoading('Loading app information');
|
||||||
const url = `${getBaseApiReact()}/arbitrary/resources/search?service=${appType}&mode=ALL&name=${name}&includemetadata=true`;
|
const url = `${getBaseApiReact()}/arbitrary/resources/search?service=${appType}&mode=ALL&name=${name}&includemetadata=true`;
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!response?.ok) return;
|
if (!response?.ok) return;
|
||||||
@ -142,18 +126,18 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
|
|
||||||
if (responseData?.length > 0) {
|
if (responseData?.length > 0) {
|
||||||
const myApp = responseData[0];
|
const myApp = responseData[0];
|
||||||
setTitle(myApp?.metadata?.title || "");
|
setTitle(myApp?.metadata?.title || '');
|
||||||
setDescription(myApp?.metadata?.description || "");
|
setDescription(myApp?.metadata?.description || '');
|
||||||
setCategory(myApp?.metadata?.category || "");
|
setCategory(myApp?.metadata?.category || '');
|
||||||
setTag1(myApp?.metadata?.tags[0] || "");
|
setTag1(myApp?.metadata?.tags[0] || '');
|
||||||
setTag2(myApp?.metadata?.tags[1] || "");
|
setTag2(myApp?.metadata?.tags[1] || '');
|
||||||
setTag3(myApp?.metadata?.tags[2] || "");
|
setTag3(myApp?.metadata?.tags[2] || '');
|
||||||
setTag4(myApp?.metadata?.tags[3] || "");
|
setTag4(myApp?.metadata?.tags[3] || '');
|
||||||
setTag5(myApp?.metadata?.tags[4] || "");
|
setTag5(myApp?.metadata?.tags[4] || '');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading("");
|
setIsLoading('');
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -173,12 +157,12 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
file,
|
file,
|
||||||
};
|
};
|
||||||
const requiredFields = [
|
const requiredFields = [
|
||||||
"name",
|
'name',
|
||||||
"title",
|
'title',
|
||||||
"description",
|
'description',
|
||||||
"category",
|
'category',
|
||||||
"appType",
|
'appType',
|
||||||
"file",
|
'file',
|
||||||
];
|
];
|
||||||
|
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
@ -188,32 +172,33 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (missingFields.length > 0) {
|
if (missingFields.length > 0) {
|
||||||
const missingFieldsString = missingFields.join(", ");
|
const missingFieldsString = missingFields.join(', ');
|
||||||
const errorMsg = `Missing fields: ${missingFieldsString}`;
|
const errorMsg = `Missing fields: ${missingFieldsString}`;
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
}
|
}
|
||||||
const fee = await getFee("ARBITRARY");
|
const fee = await getFee('ARBITRARY');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: "Would you like to publish this app?",
|
message: 'Would you like to publish this app?',
|
||||||
publishFee: fee.fee + " QORT",
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoading("Publishing... Please wait.");
|
setIsLoading('Publishing... Please wait.');
|
||||||
const fileBase64 = await fileToBase64(file);
|
const fileBase64 = await fileToBase64(file);
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window.sendMessage("publishOnQDN", {
|
window
|
||||||
data: fileBase64,
|
.sendMessage('publishOnQDN', {
|
||||||
service: appType,
|
data: fileBase64,
|
||||||
title,
|
service: appType,
|
||||||
description,
|
title,
|
||||||
category,
|
description,
|
||||||
tag1,
|
category,
|
||||||
tag2,
|
tag1,
|
||||||
tag3,
|
tag2,
|
||||||
tag4,
|
tag3,
|
||||||
tag5,
|
tag4,
|
||||||
uploadType: "zip",
|
tag5,
|
||||||
})
|
uploadType: 'zip',
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -222,14 +207,13 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "success",
|
type: 'success',
|
||||||
message:
|
message:
|
||||||
"Successfully published. Please wait a couple minutes for the network to propogate the changes.",
|
'Successfully published. Please wait a couple minutes for the network to propogate the changes.',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
const dataObj = {
|
const dataObj = {
|
||||||
@ -242,35 +226,49 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
},
|
},
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
};
|
};
|
||||||
executeEvent("addTab", {
|
executeEvent('addTab', {
|
||||||
data: dataObj,
|
data: dataObj,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to publish app",
|
message: error?.message || 'Unable to publish app',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading("");
|
setIsLoading('');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppsLibraryContainer sx={{
|
<AppsLibraryContainer
|
||||||
height: !isMobile ? '100%' : 'auto',
|
sx={{
|
||||||
paddingTop: !isMobile && '30px',
|
alignItems: 'center',
|
||||||
alignItems: !isMobile && 'center'
|
height: '100%',
|
||||||
}}>
|
paddingTop: '30px',
|
||||||
<AppsWidthLimiter sx={{
|
}}
|
||||||
width: !isMobile ? 'auto' : '90%'
|
>
|
||||||
}}>
|
<AppsWidthLimiter
|
||||||
|
sx={{
|
||||||
|
width: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AppLibrarySubTitle>Create Apps!</AppLibrarySubTitle>
|
<AppLibrarySubTitle>Create Apps!</AppLibrarySubTitle>
|
||||||
|
|
||||||
<Spacer height="18px" />
|
<Spacer height="18px" />
|
||||||
|
|
||||||
<PublishQAppInfo>
|
<PublishQAppInfo>
|
||||||
Note: Currently, only one App and Website is allowed per Name.
|
Note: Currently, only one App and Website is allowed per Name.
|
||||||
</PublishQAppInfo>
|
</PublishQAppInfo>
|
||||||
|
|
||||||
<Spacer height="18px" />
|
<Spacer height="18px" />
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>Name/App</InputLabel>
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
Name/App
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
placeholder="Select Name/App"
|
placeholder="Select Name/App"
|
||||||
displayEmpty
|
displayEmpty
|
||||||
@ -280,19 +278,26 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
<CustomMenuItem value="">
|
<CustomMenuItem value="">
|
||||||
<em
|
<em
|
||||||
style={{
|
style={{
|
||||||
color: "var(--50-white, #FFFFFF80)",
|
color: 'var(--50-white, #FFFFFF80)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Select Name/App
|
Select Name/App
|
||||||
</em>{" "}
|
</em>{' '}
|
||||||
{/* This is the placeholder item */}
|
{/* This is the placeholder item */}
|
||||||
</CustomMenuItem>
|
</CustomMenuItem>
|
||||||
{names.map((name) => {
|
{names.map((name) => {
|
||||||
return <CustomMenuItem value={name}>{name}</CustomMenuItem>;
|
return <CustomMenuItem value={name}>{name}</CustomMenuItem>;
|
||||||
})}
|
})}
|
||||||
</CustomSelect>
|
</CustomSelect>
|
||||||
|
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>App service type</InputLabel>
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
App service type
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
placeholder="SERVICE TYPE"
|
placeholder="SERVICE TYPE"
|
||||||
displayEmpty
|
displayEmpty
|
||||||
@ -302,59 +307,79 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
<CustomMenuItem value="">
|
<CustomMenuItem value="">
|
||||||
<em
|
<em
|
||||||
style={{
|
style={{
|
||||||
color: "var(--50-white, #FFFFFF80)",
|
color: 'var(--50-white, #FFFFFF80)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Select App Type
|
Select App Type
|
||||||
</em>{" "}
|
</em>{' '}
|
||||||
{/* This is the placeholder item */}
|
{/* This is the placeholder item */}
|
||||||
</CustomMenuItem>
|
</CustomMenuItem>
|
||||||
<CustomMenuItem value={"APP"}>App</CustomMenuItem>
|
<CustomMenuItem value={'APP'}>App</CustomMenuItem>
|
||||||
<CustomMenuItem value={"WEBSITE"}>Website</CustomMenuItem>
|
<CustomMenuItem value={'WEBSITE'}>Website</CustomMenuItem>
|
||||||
</CustomSelect>
|
</CustomSelect>
|
||||||
|
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>Title</InputLabel>
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
Title
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
<InputBase
|
<InputBase
|
||||||
value={title}
|
value={title}
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
maxWidth: "450px",
|
maxWidth: '450px',
|
||||||
}}
|
}}
|
||||||
placeholder="Title"
|
placeholder="Title"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Title",
|
'aria-label': 'Title',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Spacer height="15px" />
|
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>Description</InputLabel>
|
|
||||||
<InputBase
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
sx={{
|
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
|
||||||
padding: "0px 15px",
|
|
||||||
borderRadius: "5px",
|
|
||||||
height: "36px",
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: "450px",
|
|
||||||
}}
|
|
||||||
placeholder="Description"
|
|
||||||
inputProps={{
|
|
||||||
"aria-label": "Description",
|
|
||||||
fontSize: "14px",
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>Category</InputLabel>
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
Description
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
|
<InputBase
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
|
padding: '0px 15px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
height: '36px',
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '450px',
|
||||||
|
}}
|
||||||
|
placeholder="Description"
|
||||||
|
inputProps={{
|
||||||
|
'aria-label': 'Description',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Spacer height="15px" />
|
||||||
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
Category
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
<CustomSelect
|
<CustomSelect
|
||||||
displayEmpty
|
displayEmpty
|
||||||
placeholder="Select Category"
|
placeholder="Select Category"
|
||||||
@ -364,11 +389,11 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
<CustomMenuItem value="">
|
<CustomMenuItem value="">
|
||||||
<em
|
<em
|
||||||
style={{
|
style={{
|
||||||
color: "var(--50-white, #FFFFFF80)",
|
color: 'var(--50-white, #FFFFFF80)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Select Category
|
Select Category
|
||||||
</em>{" "}
|
</em>{' '}
|
||||||
{/* This is the placeholder item */}
|
{/* This is the placeholder item */}
|
||||||
</CustomMenuItem>
|
</CustomMenuItem>
|
||||||
{categories?.map((category) => {
|
{categories?.map((category) => {
|
||||||
@ -379,23 +404,30 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</CustomSelect>
|
</CustomSelect>
|
||||||
|
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<InputLabel sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}>Tags</InputLabel>
|
|
||||||
|
<InputLabel
|
||||||
|
sx={{ color: '#888', fontSize: '14px', marginBottom: '2px' }}
|
||||||
|
>
|
||||||
|
Tags
|
||||||
|
</InputLabel>
|
||||||
|
|
||||||
<AppPublishTagsContainer>
|
<AppPublishTagsContainer>
|
||||||
<InputBase
|
<InputBase
|
||||||
value={tag1}
|
value={tag1}
|
||||||
onChange={(e) => setTag1(e.target.value)}
|
onChange={(e) => setTag1(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100px",
|
width: '100px',
|
||||||
}}
|
}}
|
||||||
placeholder="Tag 1"
|
placeholder="Tag 1"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Tag 1",
|
'aria-label': 'Tag 1',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -403,16 +435,16 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
value={tag2}
|
value={tag2}
|
||||||
onChange={(e) => setTag2(e.target.value)}
|
onChange={(e) => setTag2(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100px",
|
width: '100px',
|
||||||
}}
|
}}
|
||||||
placeholder="Tag 2"
|
placeholder="Tag 2"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Tag 2",
|
'aria-label': 'Tag 2',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -420,16 +452,16 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
value={tag3}
|
value={tag3}
|
||||||
onChange={(e) => setTag3(e.target.value)}
|
onChange={(e) => setTag3(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100px",
|
width: '100px',
|
||||||
}}
|
}}
|
||||||
placeholder="Tag 3"
|
placeholder="Tag 3"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Tag 3",
|
'aria-label': 'Tag 3',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -437,16 +469,16 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
value={tag4}
|
value={tag4}
|
||||||
onChange={(e) => setTag4(e.target.value)}
|
onChange={(e) => setTag4(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100px",
|
width: '100px',
|
||||||
}}
|
}}
|
||||||
placeholder="Tag 4"
|
placeholder="Tag 4"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Tag 4",
|
'aria-label': 'Tag 4',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -454,27 +486,31 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
value={tag5}
|
value={tag5}
|
||||||
onChange={(e) => setTag5(e.target.value)}
|
onChange={(e) => setTag5(e.target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
border: "0.5px solid var(--50-white, #FFFFFF80)",
|
border: '0.5px solid var(--50-white, #FFFFFF80)',
|
||||||
padding: "0px 15px",
|
padding: '0px 15px',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
height: "36px",
|
height: '36px',
|
||||||
width: "100px",
|
width: '100px',
|
||||||
}}
|
}}
|
||||||
placeholder="Tag 5"
|
placeholder="Tag 5"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
"aria-label": "Tag 5",
|
'aria-label': 'Tag 5',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</AppPublishTagsContainer>
|
</AppPublishTagsContainer>
|
||||||
|
|
||||||
<Spacer height="30px" />
|
<Spacer height="30px" />
|
||||||
|
|
||||||
<PublishQAppInfo>
|
<PublishQAppInfo>
|
||||||
Select .zip file containing static content:{" "}
|
Select .zip file containing static content:{' '}
|
||||||
</PublishQAppInfo>
|
</PublishQAppInfo>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
|
|
||||||
<PublishQAppInfo>{`(${
|
<PublishQAppInfo>{`(${
|
||||||
appType === "APP" ? "50mb" : "400mb"
|
appType === 'APP' ? '50mb' : '400mb'
|
||||||
} MB maximum)`}</PublishQAppInfo>
|
} MB maximum)`}</PublishQAppInfo>
|
||||||
{file && (
|
{file && (
|
||||||
<>
|
<>
|
||||||
@ -484,21 +520,25 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Spacer height="18px" />
|
<Spacer height="18px" />
|
||||||
|
|
||||||
<PublishQAppChoseFile {...getRootProps()}>
|
<PublishQAppChoseFile {...getRootProps()}>
|
||||||
{" "}
|
{' '}
|
||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
Choose File
|
Choose File
|
||||||
</PublishQAppChoseFile>
|
</PublishQAppChoseFile>
|
||||||
|
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
|
|
||||||
<PublishQAppCTAButton
|
<PublishQAppCTAButton
|
||||||
sx={{
|
sx={{
|
||||||
alignSelf: "center",
|
alignSelf: 'center',
|
||||||
}}
|
}}
|
||||||
onClick={publishApp}
|
onClick={publishApp}
|
||||||
>
|
>
|
||||||
Publish
|
Publish
|
||||||
</PublishQAppCTAButton>
|
</PublishQAppCTAButton>
|
||||||
</AppsWidthLimiter>
|
</AppsWidthLimiter>
|
||||||
|
|
||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={!!isLoading}
|
open={!!isLoading}
|
||||||
info={{
|
info={{
|
||||||
@ -512,7 +552,6 @@ export const AppPublish = ({ names, categories }) => {
|
|||||||
info={infoSnack}
|
info={infoSnack}
|
||||||
setInfo={setInfoSnack}
|
setInfo={setInfoSnack}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</AppsLibraryContainer>
|
</AppsLibraryContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,210 +1,249 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from "react";
|
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { Box } from '@mui/material';
|
||||||
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||||
|
import { useFrame } from 'react-frame-component';
|
||||||
|
import { useQortalMessageListener } from './useQortalMessageListener';
|
||||||
|
import { useThemeContext } from '../Theme/ThemeContext';
|
||||||
|
|
||||||
import { Box, } from "@mui/material";
|
export const AppViewer = React.forwardRef(
|
||||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
({ app, hide, isDevMode, skipAuth }, iframeRef) => {
|
||||||
|
const { rootHeight } = useContext(MyContext);
|
||||||
|
// const iframeRef = useRef(null);
|
||||||
|
const { window: frameWindow } = useFrame();
|
||||||
|
const { path, history, changeCurrentIndex, resetHistory } =
|
||||||
|
useQortalMessageListener(
|
||||||
|
frameWindow,
|
||||||
|
iframeRef,
|
||||||
|
app?.tabId,
|
||||||
|
isDevMode,
|
||||||
|
app?.name,
|
||||||
|
app?.service,
|
||||||
|
skipAuth
|
||||||
|
);
|
||||||
|
const [url, setUrl] = useState('');
|
||||||
|
const { themeMode } = useThemeContext();
|
||||||
|
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
useEffect(() => {
|
||||||
import { useFrame } from "react-frame-component";
|
if (app?.isPreview) return;
|
||||||
import { useQortalMessageListener } from "./useQortalMessageListener";
|
if (isDevMode) {
|
||||||
import { useThemeContext } from "../Theme/ThemeContext";
|
setUrl(app?.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let hasQueryParam = false;
|
||||||
|
if (app?.path && app.path.includes('?')) {
|
||||||
|
hasQueryParam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUrl(
|
||||||
|
`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? `/${app?.path}` : ''}${hasQueryParam ? '&' : '?'}theme=${themeMode}&identifier=${app?.identifier != null && app?.identifier != 'null' ? app?.identifier : ''}`
|
||||||
|
);
|
||||||
|
}, [app?.service, app?.name, app?.identifier, app?.path, app?.isPreview]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (app?.isPreview && app?.url) {
|
||||||
|
resetHistory();
|
||||||
|
setUrl(app.url);
|
||||||
|
}
|
||||||
|
}, [app?.url, app?.isPreview]);
|
||||||
|
const defaultUrl = useMemo(() => {
|
||||||
|
return url;
|
||||||
|
}, [url, isDevMode]);
|
||||||
|
|
||||||
|
const refreshAppFunc = (e) => {
|
||||||
export const AppViewer = React.forwardRef(({ app , hide, isDevMode, skipAuth}, iframeRef) => {
|
const { tabId } = e.detail;
|
||||||
const { rootHeight } = useContext(MyContext);
|
if (tabId === app?.tabId) {
|
||||||
// const iframeRef = useRef(null);
|
if (isDevMode) {
|
||||||
const { window: frameWindow } = useFrame();
|
resetHistory();
|
||||||
const {path, history, changeCurrentIndex, resetHistory} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId, isDevMode, app?.name, app?.service, skipAuth)
|
if (!app?.isPreview || app?.isPrivate) {
|
||||||
const [url, setUrl] = useState('')
|
setUrl(app?.url + `?time=${Date.now()}`);
|
||||||
const { themeMode } = useThemeContext();
|
}
|
||||||
|
return;
|
||||||
useEffect(()=> {
|
|
||||||
if(app?.isPreview) return
|
|
||||||
if(isDevMode){
|
|
||||||
setUrl(app?.url)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let hasQueryParam = false
|
|
||||||
if(app?.path && app.path.includes('?')){
|
|
||||||
hasQueryParam = true
|
|
||||||
}
|
|
||||||
|
|
||||||
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? `/${app?.path}` : ''}${hasQueryParam ? "&": "?" }theme=${themeMode}&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}`)
|
|
||||||
}, [app?.service, app?.name, app?.identifier, app?.path, app?.isPreview])
|
|
||||||
|
|
||||||
useEffect(()=> {
|
|
||||||
if(app?.isPreview && app?.url){
|
|
||||||
resetHistory()
|
|
||||||
setUrl(app.url)
|
|
||||||
}
|
|
||||||
}, [app?.url, app?.isPreview])
|
|
||||||
const defaultUrl = useMemo(()=> {
|
|
||||||
return url
|
|
||||||
}, [url, isDevMode])
|
|
||||||
|
|
||||||
|
|
||||||
const refreshAppFunc = (e) => {
|
|
||||||
const {tabId} = e.detail
|
|
||||||
if(tabId === app?.tabId){
|
|
||||||
if(isDevMode){
|
|
||||||
resetHistory()
|
|
||||||
if(!app?.isPreview || app?.isPrivate){
|
|
||||||
setUrl(app?.url + `?time=${Date.now()}`)
|
|
||||||
}
|
}
|
||||||
return
|
const constructUrl = `${getBaseApiReact()}/render/${app?.service}/${app?.name}${path != null ? path : ''}?theme=${themeMode}&identifier=${app?.identifier != null ? app?.identifier : ''}&time=${new Date().getMilliseconds()}`;
|
||||||
|
setUrl(constructUrl);
|
||||||
}
|
}
|
||||||
const constructUrl = `${getBaseApiReact()}/render/${app?.service}/${app?.name}${path != null ? path : ''}?theme=${themeMode}&identifier=${app?.identifier != null ? app?.identifier : ''}&time=${new Date().getMilliseconds()}`
|
|
||||||
setUrl(constructUrl)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
subscribeToEvent("refreshApp", refreshAppFunc);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unsubscribeFromEvent("refreshApp", refreshAppFunc);
|
|
||||||
};
|
};
|
||||||
}, [app, path, isDevMode]);
|
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
if(!iframeRef?.current) return
|
subscribeToEvent('refreshApp', refreshAppFunc);
|
||||||
const targetOrigin = iframeRef.current ? new URL(iframeRef.current.src).origin : "*";
|
|
||||||
// Send the navigation command after setting up the listener and timeout
|
|
||||||
iframeRef.current.contentWindow.postMessage(
|
|
||||||
{ action: 'THEME_CHANGED', theme: themeMode, requestedHandler: 'UI' }, targetOrigin
|
|
||||||
);
|
|
||||||
}, [themeMode])
|
|
||||||
|
|
||||||
const removeTrailingSlash = (str) => str.replace(/\/$/, '');
|
return () => {
|
||||||
const copyLinkFunc = (e) => {
|
unsubscribeFromEvent('refreshApp', refreshAppFunc);
|
||||||
const {tabId} = e.detail
|
};
|
||||||
if(tabId === app?.tabId){
|
}, [app, path, isDevMode]);
|
||||||
let link = 'qortal://' + app?.service + '/' + app?.name
|
|
||||||
if(path && path.startsWith('/')){
|
|
||||||
link = link + removeTrailingSlash(path)
|
|
||||||
}
|
|
||||||
if(path && !path.startsWith('/')){
|
|
||||||
link = link + '/' + removeTrailingSlash(path)
|
|
||||||
}
|
|
||||||
navigator.clipboard.writeText(link)
|
|
||||||
.then(() => {
|
|
||||||
console.log("Path copied to clipboard:", path);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Failed to copy path:", error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("copyLink", copyLinkFunc);
|
if (!iframeRef?.current) return;
|
||||||
|
const targetOrigin = iframeRef.current
|
||||||
return () => {
|
? new URL(iframeRef.current.src).origin
|
||||||
unsubscribeFromEvent("copyLink", copyLinkFunc);
|
: '*';
|
||||||
};
|
|
||||||
}, [app, path]);
|
|
||||||
|
|
||||||
// Function to navigate back in iframe
|
|
||||||
const navigateBackInIframe = async () => {
|
|
||||||
if (iframeRef.current && iframeRef.current.contentWindow && history?.currentIndex > 0) {
|
|
||||||
// Calculate the previous index and path
|
|
||||||
const previousPageIndex = history.currentIndex - 1;
|
|
||||||
const previousPath = history.customQDNHistoryPaths[previousPageIndex];
|
|
||||||
const targetOrigin = iframeRef.current ? new URL(iframeRef.current.src).origin : "*";
|
|
||||||
// Signal non-manual navigation
|
|
||||||
iframeRef.current.contentWindow.postMessage(
|
|
||||||
{ action: 'PERFORMING_NON_MANUAL', currentIndex: previousPageIndex },targetOrigin
|
|
||||||
);
|
|
||||||
// Update the current index locally
|
|
||||||
changeCurrentIndex(previousPageIndex);
|
|
||||||
|
|
||||||
// Create a navigation promise with a 200ms timeout
|
|
||||||
const navigationPromise = new Promise((resolve, reject) => {
|
|
||||||
function handleNavigationSuccess(event) {
|
|
||||||
if (event.data?.action === 'NAVIGATION_SUCCESS' && event.data.path === previousPath) {
|
|
||||||
frameWindow.removeEventListener('message', handleNavigationSuccess);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
frameWindow.addEventListener('message', handleNavigationSuccess);
|
|
||||||
|
|
||||||
// Timeout after 200ms if no response
|
|
||||||
setTimeout(() => {
|
|
||||||
window.removeEventListener('message', handleNavigationSuccess);
|
|
||||||
reject(new Error("Navigation timeout"));
|
|
||||||
}, 200);
|
|
||||||
const targetOrigin = iframeRef.current ? new URL(iframeRef.current.src).origin : "*";
|
|
||||||
// Send the navigation command after setting up the listener and timeout
|
// Send the navigation command after setting up the listener and timeout
|
||||||
iframeRef.current.contentWindow.postMessage(
|
iframeRef.current.contentWindow.postMessage(
|
||||||
{ action: 'NAVIGATE_TO_PATH', path: previousPath, requestedHandler: 'UI' }, targetOrigin
|
{ action: 'THEME_CHANGED', theme: themeMode, requestedHandler: 'UI' },
|
||||||
|
targetOrigin
|
||||||
);
|
);
|
||||||
});
|
}, [themeMode]);
|
||||||
|
|
||||||
// Execute navigation promise and handle timeout fallback
|
const removeTrailingSlash = (str) => str.replace(/\/$/, '');
|
||||||
try {
|
|
||||||
await navigationPromise;
|
|
||||||
} catch (error) {
|
|
||||||
if(isDevMode){
|
|
||||||
setUrl(`${url}${previousPath != null ? previousPath : ''}?theme=${themeMode}&time=${new Date().getMilliseconds()}&isManualNavigation=false`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${previousPath != null ? previousPath : ''}?theme=${themeMode}&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}&time=${new Date().getMilliseconds()}&isManualNavigation=false`)
|
|
||||||
// iframeRef.current.contentWindow.location.href = previousPath; // Fallback URL update
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('Iframe not accessible or does not have a content window.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const navigateBackAppFunc = (e) => {
|
const copyLinkFunc = (e) => {
|
||||||
|
const { tabId } = e.detail;
|
||||||
navigateBackInIframe()
|
if (tabId === app?.tabId) {
|
||||||
};
|
let link = 'qortal://' + app?.service + '/' + app?.name;
|
||||||
|
if (path && path.startsWith('/')) {
|
||||||
useEffect(() => {
|
link = link + removeTrailingSlash(path);
|
||||||
if(!app?.tabId) return
|
}
|
||||||
subscribeToEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
if (path && !path.startsWith('/')) {
|
||||||
|
link = link + '/' + removeTrailingSlash(path);
|
||||||
return () => {
|
}
|
||||||
unsubscribeFromEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
navigator.clipboard
|
||||||
|
.writeText(link)
|
||||||
|
.then(() => {
|
||||||
|
console.log('Path copied to clipboard:', path);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to copy path:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [app, history]);
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent('copyLink', copyLinkFunc);
|
||||||
|
|
||||||
// Function to navigate back in iframe
|
return () => {
|
||||||
const navigateForwardInIframe = async () => {
|
unsubscribeFromEvent('copyLink', copyLinkFunc);
|
||||||
|
};
|
||||||
|
}, [app, path]);
|
||||||
|
|
||||||
|
// Function to navigate back in iframe
|
||||||
if (iframeRef.current && iframeRef.current.contentWindow) {
|
const navigateBackInIframe = async () => {
|
||||||
const targetOrigin = iframeRef.current ? new URL(iframeRef.current.src).origin : "*";
|
if (
|
||||||
iframeRef.current.contentWindow.postMessage(
|
iframeRef.current &&
|
||||||
{ action: 'NAVIGATE_FORWARD'},
|
iframeRef.current.contentWindow &&
|
||||||
|
history?.currentIndex > 0
|
||||||
|
) {
|
||||||
|
// Calculate the previous index and path
|
||||||
|
const previousPageIndex = history.currentIndex - 1;
|
||||||
|
const previousPath = history.customQDNHistoryPaths[previousPageIndex];
|
||||||
|
const targetOrigin = iframeRef.current
|
||||||
|
? new URL(iframeRef.current.src).origin
|
||||||
|
: '*';
|
||||||
|
// Signal non-manual navigation
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'PERFORMING_NON_MANUAL', currentIndex: previousPageIndex },
|
||||||
targetOrigin
|
targetOrigin
|
||||||
);
|
);
|
||||||
} else {
|
// Update the current index locally
|
||||||
console.log('Iframe not accessible or does not have a content window.');
|
changeCurrentIndex(previousPageIndex);
|
||||||
|
|
||||||
|
// Create a navigation promise with a 200ms timeout
|
||||||
|
const navigationPromise = new Promise((resolve, reject) => {
|
||||||
|
function handleNavigationSuccess(event) {
|
||||||
|
if (
|
||||||
|
event.data?.action === 'NAVIGATION_SUCCESS' &&
|
||||||
|
event.data.path === previousPath
|
||||||
|
) {
|
||||||
|
frameWindow.removeEventListener(
|
||||||
|
'message',
|
||||||
|
handleNavigationSuccess
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frameWindow.addEventListener('message', handleNavigationSuccess);
|
||||||
|
|
||||||
|
// Timeout after 200ms if no response
|
||||||
|
setTimeout(() => {
|
||||||
|
window.removeEventListener('message', handleNavigationSuccess);
|
||||||
|
reject(new Error('Navigation timeout'));
|
||||||
|
}, 200);
|
||||||
|
const targetOrigin = iframeRef.current
|
||||||
|
? new URL(iframeRef.current.src).origin
|
||||||
|
: '*';
|
||||||
|
// Send the navigation command after setting up the listener and timeout
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{
|
||||||
|
action: 'NAVIGATE_TO_PATH',
|
||||||
|
path: previousPath,
|
||||||
|
requestedHandler: 'UI',
|
||||||
|
},
|
||||||
|
targetOrigin
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Execute navigation promise and handle timeout fallback
|
||||||
|
try {
|
||||||
|
await navigationPromise;
|
||||||
|
} catch (error) {
|
||||||
|
if (isDevMode) {
|
||||||
|
setUrl(
|
||||||
|
`${url}${previousPath != null ? previousPath : ''}?theme=${themeMode}&time=${new Date().getMilliseconds()}&isManualNavigation=false`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setUrl(
|
||||||
|
`${getBaseApiReact()}/render/${app?.service}/${app?.name}${previousPath != null ? previousPath : ''}?theme=${themeMode}&identifier=${app?.identifier != null && app?.identifier != 'null' ? app?.identifier : ''}&time=${new Date().getMilliseconds()}&isManualNavigation=false`
|
||||||
|
);
|
||||||
|
// iframeRef.current.contentWindow.location.href = previousPath; // Fallback URL update
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Iframe not accessible or does not have a content window.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navigateBackAppFunc = (e) => {
|
||||||
|
navigateBackInIframe();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!app?.tabId) return;
|
||||||
|
subscribeToEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent(
|
||||||
|
`navigateBackApp-${app?.tabId}`,
|
||||||
|
navigateBackAppFunc
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}, [app, history]);
|
||||||
|
|
||||||
|
// Function to navigate back in iframe
|
||||||
|
const navigateForwardInIframe = async () => {
|
||||||
|
if (iframeRef.current && iframeRef.current.contentWindow) {
|
||||||
|
const targetOrigin = iframeRef.current
|
||||||
|
? new URL(iframeRef.current.src).origin
|
||||||
|
: '*';
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'NAVIGATE_FORWARD' },
|
||||||
|
targetOrigin
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log('Iframe not accessible or does not have a content window.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
ref={iframeRef}
|
||||||
|
style={{
|
||||||
|
height: '100vh',
|
||||||
|
border: 'none',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
id="browser-iframe"
|
||||||
|
src={defaultUrl}
|
||||||
|
sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals"
|
||||||
|
allow="fullscreen; clipboard-read; clipboard-write"
|
||||||
|
></iframe>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
|
|
||||||
<iframe ref={iframeRef} style={{
|
|
||||||
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
|
||||||
border: 'none',
|
|
||||||
width: '100%'
|
|
||||||
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals"
|
|
||||||
allow="fullscreen; clipboard-read; clipboard-write">
|
|
||||||
|
|
||||||
</iframe>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import React, { useContext, } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { AppViewer } from './AppViewer';
|
import { AppViewer } from './AppViewer';
|
||||||
import Frame from 'react-frame-component';
|
import Frame from 'react-frame-component';
|
||||||
import { MyContext, isMobile } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
|
|
||||||
const AppViewerContainer = React.forwardRef(({ app, isSelected, hide, isDevMode, customHeight, skipAuth }, ref) => {
|
const AppViewerContainer = React.forwardRef(
|
||||||
const { rootHeight } = useContext(MyContext);
|
({ app, isSelected, hide, isDevMode, customHeight, skipAuth }, ref) => {
|
||||||
|
const { rootHeight } = useContext(MyContext);
|
||||||
|
|
||||||
|
return (
|
||||||
return (
|
<Frame
|
||||||
<Frame
|
id={`browser-iframe-${app?.tabId}`}
|
||||||
id={`browser-iframe-${app?.tabId}`}
|
head={
|
||||||
|
<>
|
||||||
head={
|
<style>
|
||||||
<>
|
{`
|
||||||
<style>
|
|
||||||
{`
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -28,24 +27,31 @@ const AppViewerContainer = React.forwardRef(({ app, isSelected, hide, isDevMode,
|
|||||||
}
|
}
|
||||||
.frame-content {
|
.frame-content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: ${!isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px)`};
|
height: '100vh';
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
position: (!isSelected || hide) && 'fixed',
|
border: 'none',
|
||||||
left: (!isSelected || hide) && '-200vw',
|
height: '100vh',
|
||||||
height: customHeight ? customHeight : !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px)`,
|
left: (!isSelected || hide) && '-200vw',
|
||||||
border: 'none',
|
overflow: 'hidden',
|
||||||
width: '100%',
|
position: (!isSelected || hide) && 'fixed',
|
||||||
overflow: 'hidden',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppViewer skipAuth={skipAuth} app={app} ref={ref} hide={!isSelected || hide} isDevMode={isDevMode} />
|
<AppViewer
|
||||||
</Frame>
|
skipAuth={skipAuth}
|
||||||
);
|
app={app}
|
||||||
});
|
ref={ref}
|
||||||
|
hide={!isSelected || hide}
|
||||||
|
isDevMode={isDevMode}
|
||||||
|
/>
|
||||||
|
</Frame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default AppViewerContainer;
|
export default AppViewerContainer;
|
||||||
|
@ -137,9 +137,9 @@ export const AppCircle = styled(Box)(({ theme }) => ({
|
|||||||
theme.palette.mode === 'dark'
|
theme.palette.mode === 'dark'
|
||||||
? 'rgb(209, 209, 209)'
|
? 'rgb(209, 209, 209)'
|
||||||
: 'rgba(41, 41, 43, 1)',
|
: 'rgba(41, 41, 43, 1)',
|
||||||
borderWidth: '1px',
|
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
|
borderWidth: '1px',
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Add } from '@mui/icons-material';
|
import { Add } from '@mui/icons-material';
|
||||||
import { MyContext, getBaseApiReact, isMobile } from '../../App';
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
@ -279,7 +279,9 @@ export const AppsDevModeHome = ({
|
|||||||
Dev Mode Apps
|
Dev Mode Apps
|
||||||
</AppLibrarySubTitle>
|
</AppLibrarySubTitle>
|
||||||
</AppsContainer>
|
</AppsContainer>
|
||||||
|
|
||||||
<Spacer height="45px" />
|
<Spacer height="45px" />
|
||||||
|
|
||||||
<AppsContainer
|
<AppsContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: '75px',
|
gap: '75px',
|
||||||
@ -293,7 +295,7 @@ export const AppsDevModeHome = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
@ -302,6 +304,7 @@ export const AppsDevModeHome = ({
|
|||||||
<AppCircleLabel>Server</AppCircleLabel>
|
<AppCircleLabel>Server</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addPreviewApp();
|
addPreviewApp();
|
||||||
@ -309,15 +312,17 @@ export const AppsDevModeHome = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
<Add>+</Add>
|
<Add>+</Add>
|
||||||
</AppCircle>
|
</AppCircle>
|
||||||
|
|
||||||
<AppCircleLabel>Zip</AppCircleLabel>
|
<AppCircleLabel>Zip</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addPreviewAppWithDirectory();
|
addPreviewAppWithDirectory();
|
||||||
@ -325,7 +330,7 @@ export const AppsDevModeHome = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
@ -334,6 +339,7 @@ export const AppsDevModeHome = ({
|
|||||||
<AppCircleLabel>Directory</AppCircleLabel>
|
<AppCircleLabel>Directory</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent('appsDevModeAddTab', {
|
executeEvent('appsDevModeAddTab', {
|
||||||
@ -347,7 +353,7 @@ export const AppsDevModeHome = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
@ -371,9 +377,11 @@ export const AppsDevModeHome = ({
|
|||||||
/>
|
/>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</AppCircle>
|
</AppCircle>
|
||||||
|
|
||||||
<AppCircleLabel>Q-Sandbox</AppCircleLabel>
|
<AppCircleLabel>Q-Sandbox</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent('appsDevModeAddTab', {
|
executeEvent('appsDevModeAddTab', {
|
||||||
@ -387,7 +395,7 @@ export const AppsDevModeHome = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
@ -411,10 +419,12 @@ export const AppsDevModeHome = ({
|
|||||||
/>
|
/>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</AppCircle>
|
</AppCircle>
|
||||||
|
|
||||||
<AppCircleLabel>API</AppCircleLabel>
|
<AppCircleLabel>API</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</AppsContainer>
|
</AppsContainer>
|
||||||
|
|
||||||
{isShow && (
|
{isShow && (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isShow}
|
open={isShow}
|
||||||
@ -429,6 +439,7 @@ export const AppsDevModeHome = ({
|
|||||||
<DialogTitle id="alert-dialog-title">
|
<DialogTitle id="alert-dialog-title">
|
||||||
{'Add custom framework'}
|
{'Add custom framework'}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -460,6 +471,7 @@ export const AppsDevModeHome = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button variant="contained" onClick={onCancel}>
|
<Button variant="contained" onClick={onCancel}>
|
||||||
Close
|
Close
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
@ -8,7 +8,6 @@ import {
|
|||||||
} from './Apps-styles';
|
} from './Apps-styles';
|
||||||
import { Box, ButtonBase, Input, useTheme } from '@mui/material';
|
import { Box, ButtonBase, Input, useTheme } from '@mui/material';
|
||||||
import { Add } from '@mui/icons-material';
|
import { Add } from '@mui/icons-material';
|
||||||
import { isMobile } from '../../App';
|
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { SortablePinnedApps } from './SortablePinnedApps';
|
import { SortablePinnedApps } from './SortablePinnedApps';
|
||||||
@ -137,12 +136,13 @@ export const AppsHomeDesktop = ({
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
<Add>+</Add>
|
<Add>+</Add>
|
||||||
</AppCircle>
|
</AppCircle>
|
||||||
|
|
||||||
<AppCircleLabel>Library</AppCircleLabel>
|
<AppCircleLabel>Library</AppCircleLabel>
|
||||||
</AppCircleContainer>
|
</AppCircleContainer>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
@ -1,11 +1,4 @@
|
|||||||
import React, {
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import {
|
import {
|
||||||
AppCircle,
|
AppCircle,
|
||||||
AppCircleContainer,
|
AppCircleContainer,
|
||||||
@ -32,17 +25,14 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
styled,
|
styled,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Add } from '@mui/icons-material';
|
import { getBaseApiReact } from '../../App';
|
||||||
import { MyContext, getBaseApiReact } from '../../App';
|
|
||||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||||
import IconSearch from '../../assets/svgs/Search.svg';
|
import IconSearch from '../../assets/svgs/Search.svg';
|
||||||
import IconClearInput from '../../assets/svgs/ClearInput.svg';
|
import IconClearInput from '../../assets/svgs/ClearInput.svg';
|
||||||
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
|
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
|
||||||
import qappLibraryText from '../../assets/svgs/qappLibraryText.svg';
|
import qappLibraryText from '../../assets/svgs/qappLibraryText.svg';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
|
|
||||||
import qappDots from '../../assets/svgs/qappDots.svg';
|
import qappDots from '../../assets/svgs/qappDots.svg';
|
||||||
|
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { AppInfoSnippet } from './AppInfoSnippet';
|
import { AppInfoSnippet } from './AppInfoSnippet';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
@ -57,6 +47,7 @@ import {
|
|||||||
MailIconImg,
|
MailIconImg,
|
||||||
ShowMessageReturnButton,
|
ShowMessageReturnButton,
|
||||||
} from '../Group/Forum/Mail-styles';
|
} from '../Group/Forum/Mail-styles';
|
||||||
|
|
||||||
const officialAppList = [
|
const officialAppList = [
|
||||||
'q-tube',
|
'q-tube',
|
||||||
'q-blog',
|
'q-blog',
|
||||||
|
@ -6,7 +6,6 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
|
||||||
Input,
|
Input,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Select,
|
Select,
|
||||||
@ -32,7 +31,7 @@ import {
|
|||||||
PublishQAppInfo,
|
PublishQAppInfo,
|
||||||
} from './Apps-styles';
|
} from './Apps-styles';
|
||||||
import ImageUploader from '../../common/ImageUploader';
|
import ImageUploader from '../../common/ImageUploader';
|
||||||
import { isMobile, MyContext } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
import { fileToBase64 } from '../../utils/fileReading';
|
import { fileToBase64 } from '../../utils/fileReading';
|
||||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
@ -67,6 +66,7 @@ export const AppsPrivate = ({ myName }) => {
|
|||||||
(group) => groupsProperties[group?.groupId]?.isOpen === false
|
(group) => groupsProperties[group?.groupId]?.isOpen === false
|
||||||
);
|
);
|
||||||
}, [memberGroups, groupsProperties]);
|
}, [memberGroups, groupsProperties]);
|
||||||
|
|
||||||
const [privateAppValues, setPrivateAppValues] = useState({
|
const [privateAppValues, setPrivateAppValues] = useState({
|
||||||
name: '',
|
name: '',
|
||||||
service: 'DOCUMENT',
|
service: 'DOCUMENT',
|
||||||
@ -230,7 +230,7 @@ export const AppsPrivate = ({ myName }) => {
|
|||||||
>
|
>
|
||||||
<AppCircleContainer
|
<AppCircleContainer
|
||||||
sx={{
|
sx={{
|
||||||
gap: !isMobile ? '10px' : '5px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppCircle>
|
<AppCircle>
|
||||||
@ -267,9 +267,8 @@ export const AppsPrivate = ({ myName }) => {
|
|||||||
value={valueTabPrivateApp}
|
value={valueTabPrivateApp}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
aria-label="basic tabs example"
|
aria-label="basic tabs example"
|
||||||
variant={isMobile ? 'scrollable' : 'fullWidth'} // Scrollable on mobile, full width on desktop
|
variant={'fullWidth'}
|
||||||
scrollButtons="auto"
|
scrollButtons="auto"
|
||||||
allowScrollButtonsMobile
|
|
||||||
sx={{
|
sx={{
|
||||||
'& .MuiTabs-indicator': {
|
'& .MuiTabs-indicator': {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
@ -283,7 +282,7 @@ export const AppsPrivate = ({ myName }) => {
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
@ -293,7 +292,7 @@ export const AppsPrivate = ({ myName }) => {
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useContext, useEffect, useState } from 'react';
|
import { useContext, useEffect, useState } from 'react';
|
||||||
import { MyContext, isMobile } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
import { AdminSpaceInner } from './AdminSpaceInner';
|
import { AdminSpaceInner } from './AdminSpaceInner';
|
||||||
|
|
||||||
@ -29,10 +29,9 @@ export const AdminSpace = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
// reference to change height
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? `calc(${rootHeight} - 127px` : 'calc(100vh - 70px)',
|
height: 'calc(100vh - 70px)',
|
||||||
left: hide && '-1000px',
|
left: hide && '-1000px',
|
||||||
opacity: hide ? 0 : 1,
|
opacity: hide ? 0 : 1,
|
||||||
position: hide ? 'fixed' : 'relative',
|
position: hide ? 'fixed' : 'relative',
|
||||||
|
@ -21,7 +21,6 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|||||||
import {
|
import {
|
||||||
getArbitraryEndpointReact,
|
getArbitraryEndpointReact,
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
isMobile,
|
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
} from '../../App';
|
} from '../../App';
|
||||||
@ -56,12 +55,6 @@ export const AnnouncementDiscussion = ({
|
|||||||
const clearEditorContent = () => {
|
const clearEditorContent = () => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
editorRef.current.chain().focus().clearContent().run();
|
editorRef.current.chain().focus().clearContent().run();
|
||||||
if (isMobile) {
|
|
||||||
setTimeout(() => {
|
|
||||||
editorRef.current?.chain().blur().run();
|
|
||||||
setIsFocusedParent(false);
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,7 +271,7 @@ export const AnnouncementDiscussion = ({
|
|||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? '100%' : '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -20,7 +20,6 @@ import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
|||||||
import {
|
import {
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
getBaseApiReactSocket,
|
getBaseApiReactSocket,
|
||||||
isMobile,
|
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
} from '../../App';
|
} from '../../App';
|
||||||
@ -410,16 +409,6 @@ export const ChatDirect = ({
|
|||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
setMessageSize(0);
|
setMessageSize(0);
|
||||||
editorRef.current.chain().focus().clearContent().run();
|
editorRef.current.chain().focus().clearContent().run();
|
||||||
if (isMobile) {
|
|
||||||
setTimeout(() => {
|
|
||||||
editorRef.current?.chain().blur().run();
|
|
||||||
setIsFocusedParent(false);
|
|
||||||
executeEvent('sent-new-message-group', {});
|
|
||||||
setTimeout(() => {
|
|
||||||
triggerRerender();
|
|
||||||
}, 300);
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -547,108 +536,41 @@ export const ChatDirect = ({
|
|||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? '100%' : '100vh',
|
height: '100vh',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
<Box
|
||||||
<Box
|
onClick={close}
|
||||||
onClick={close}
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
|
alignSelf: 'center',
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
borderRadius: '3px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '5px',
|
||||||
|
margin: '10px 0px',
|
||||||
|
padding: '4px 6px',
|
||||||
|
width: 'fit-content',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowBackIcon
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
color: theme.palette.text.primary,
|
||||||
alignSelf: 'center',
|
fontSize: '20px',
|
||||||
background: theme.palette.background.default,
|
}}
|
||||||
borderRadius: '3px',
|
/>
|
||||||
cursor: 'pointer',
|
<Typography
|
||||||
display: 'flex',
|
sx={{
|
||||||
gap: '5px',
|
color: theme.palette.text.primary,
|
||||||
margin: '10px 0px',
|
fontSize: '14px',
|
||||||
padding: '4px 6px',
|
|
||||||
width: 'fit-content',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ArrowBackIcon
|
Close Direct Chat
|
||||||
sx={{
|
</Typography>
|
||||||
color: theme.palette.text.primary,
|
</Box>
|
||||||
fontSize: '20px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
fontSize: '14px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Close Direct Chat
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{isMobile && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
height: '15px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginTop: '14px',
|
|
||||||
width: '100%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
width: '320px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
width: '50px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ButtonBase
|
|
||||||
onClick={() => {
|
|
||||||
close();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ReturnIcon />
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: 600,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isNewChat
|
|
||||||
? ''
|
|
||||||
: selectedDirect?.name ||
|
|
||||||
selectedDirect?.address?.slice(0, 10) + '...'}
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
width: '50px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ButtonBase
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedDirect(null);
|
|
||||||
setMobileViewModeKeepOpen('');
|
|
||||||
setNewChat(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ExitIcon />
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{isNewChat && (
|
{isNewChat && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="30px" />
|
<Spacer height="30px" />
|
||||||
@ -685,7 +607,7 @@ export const ChatDirect = ({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
minHeight: '150px',
|
minHeight: '150px',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
padding: isMobile ? '10px' : '20px',
|
padding: '20px',
|
||||||
position: isFocusedParent ? 'fixed' : 'relative',
|
position: isFocusedParent ? 'fixed' : 'relative',
|
||||||
top: isFocusedParent ? '0px' : 'unset',
|
top: isFocusedParent ? '0px' : 'unset',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@ -753,7 +675,7 @@ export const ChatDirect = ({
|
|||||||
setEditorRef={setEditorRef}
|
setEditorRef={setEditorRef}
|
||||||
onEnter={sendMessage}
|
onEnter={sendMessage}
|
||||||
isChat
|
isChat
|
||||||
disableEnter={isMobile ? true : false}
|
disableEnter={false}
|
||||||
setIsFocusedParent={setIsFocusedParent}
|
setIsFocusedParent={setIsFocusedParent}
|
||||||
/>
|
/>
|
||||||
{messageSize > 750 && (
|
{messageSize > 750 && (
|
||||||
|
@ -20,7 +20,6 @@ import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
|||||||
import {
|
import {
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
getBaseApiReactSocket,
|
getBaseApiReactSocket,
|
||||||
isMobile,
|
|
||||||
MyContext,
|
MyContext,
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
@ -746,16 +745,6 @@ export const ChatGroup = ({
|
|||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
setMessageSize(0);
|
setMessageSize(0);
|
||||||
editorRef.current.chain().focus().clearContent().run();
|
editorRef.current.chain().focus().clearContent().run();
|
||||||
if (isMobile) {
|
|
||||||
setTimeout(() => {
|
|
||||||
editorRef.current?.chain().blur().run();
|
|
||||||
setIsFocusedParent(false);
|
|
||||||
executeEvent('sent-new-message-group', {});
|
|
||||||
setTimeout(() => {
|
|
||||||
triggerRerender();
|
|
||||||
}, 300);
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1109,7 +1098,7 @@ export const ChatGroup = ({
|
|||||||
setEditorRef={setEditorRef}
|
setEditorRef={setEditorRef}
|
||||||
onEnter={sendMessage}
|
onEnter={sendMessage}
|
||||||
isChat
|
isChat
|
||||||
disableEnter={isMobile ? true : false}
|
disableEnter={false}
|
||||||
isFocusedParent={isFocusedParent}
|
isFocusedParent={isFocusedParent}
|
||||||
setIsFocusedParent={setIsFocusedParent}
|
setIsFocusedParent={setIsFocusedParent}
|
||||||
membersWithNames={members}
|
membersWithNames={members}
|
||||||
|
@ -26,7 +26,6 @@ import {
|
|||||||
MyContext,
|
MyContext,
|
||||||
getArbitraryEndpointReact,
|
getArbitraryEndpointReact,
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
isMobile,
|
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
} from '../../App';
|
} from '../../App';
|
||||||
@ -262,15 +261,6 @@ export const GroupAnnouncements = ({
|
|||||||
const clearEditorContent = () => {
|
const clearEditorContent = () => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
editorRef.current.chain().focus().clearContent().run();
|
editorRef.current.chain().focus().clearContent().run();
|
||||||
if (isMobile) {
|
|
||||||
setTimeout(() => {
|
|
||||||
editorRef.current?.chain().blur().run();
|
|
||||||
setIsFocusedParent(false);
|
|
||||||
setTimeout(() => {
|
|
||||||
triggerRerender();
|
|
||||||
}, 300);
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -529,12 +519,9 @@ export const GroupAnnouncements = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
// reference to change height
|
|
||||||
height: isMobile
|
|
||||||
? `calc(${rootHeight} - 127px`
|
|
||||||
: 'calc(100vh - 70px)',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
height: 'calc(100vh - 70px)',
|
||||||
left: hide && '-1000px',
|
left: hide && '-1000px',
|
||||||
position: hide && 'fixed',
|
position: hide && 'fixed',
|
||||||
visibility: hide && 'hidden',
|
visibility: hide && 'hidden',
|
||||||
@ -576,26 +563,24 @@ export const GroupAnnouncements = ({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
<Box
|
||||||
<Box
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
fontSize: '20px',
|
||||||
|
gap: '20px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
padding: '25px',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CampaignIcon
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
fontSize: '30px',
|
||||||
display: 'flex',
|
|
||||||
fontSize: '20px',
|
|
||||||
gap: '20px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: '25px',
|
|
||||||
width: '100%',
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<CampaignIcon
|
Group Announcements
|
||||||
sx={{
|
</Box>
|
||||||
fontSize: '30px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Group Announcements
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Spacer height={'25px'} />
|
<Spacer height={'25px'} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useContext, useEffect, useState } from 'react';
|
import { useContext, useEffect, useState } from 'react';
|
||||||
import { GroupMail } from '../Group/Forum/GroupMail';
|
import { GroupMail } from '../Group/Forum/GroupMail';
|
||||||
import { MyContext, isMobile } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
|
|
||||||
export const GroupForum = ({
|
export const GroupForum = ({
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
|
@ -23,7 +23,6 @@ import DeveloperModeIcon from '@mui/icons-material/DeveloperMode';
|
|||||||
import Compressor from 'compressorjs';
|
import Compressor from 'compressorjs';
|
||||||
import Mention from '@tiptap/extension-mention';
|
import Mention from '@tiptap/extension-mention';
|
||||||
import ImageResize from 'tiptap-extension-resize-image'; // Import the ResizeImage extension
|
import ImageResize from 'tiptap-extension-resize-image'; // Import the ResizeImage extension
|
||||||
import { isMobile } from '../../App';
|
|
||||||
import tippy from 'tippy.js';
|
import tippy from 'tippy.js';
|
||||||
import 'tippy.js/dist/tippy.css';
|
import 'tippy.js/dist/tippy.css';
|
||||||
import { ReactRenderer } from '@tiptap/react';
|
import { ReactRenderer } from '@tiptap/react';
|
||||||
@ -137,7 +136,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('bold')
|
color: editor.isActive('bold')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatBoldIcon />
|
<FormatBoldIcon />
|
||||||
@ -149,7 +148,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('italic')
|
color: editor.isActive('italic')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatItalicIcon />
|
<FormatItalicIcon />
|
||||||
@ -161,7 +160,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('strike')
|
color: editor.isActive('strike')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StrikethroughSIcon />
|
<StrikethroughSIcon />
|
||||||
@ -173,7 +172,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('code')
|
color: editor.isActive('code')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CodeIcon />
|
<CodeIcon />
|
||||||
@ -188,7 +187,7 @@ const MenuBar = ({
|
|||||||
editor.isActive('code')
|
editor.isActive('code')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatClearIcon />
|
<FormatClearIcon />
|
||||||
@ -199,7 +198,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('bulletList')
|
color: editor.isActive('bulletList')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatListBulletedIcon />
|
<FormatListBulletedIcon />
|
||||||
@ -210,7 +209,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('orderedList')
|
color: editor.isActive('orderedList')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatListNumberedIcon />
|
<FormatListNumberedIcon />
|
||||||
@ -221,7 +220,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('codeBlock')
|
color: editor.isActive('codeBlock')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DeveloperModeIcon />
|
<DeveloperModeIcon />
|
||||||
@ -232,7 +231,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('blockquote')
|
color: editor.isActive('blockquote')
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatQuoteIcon />
|
<FormatQuoteIcon />
|
||||||
@ -240,7 +239,7 @@ const MenuBar = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => editor.chain().focus().setHorizontalRule().run()}
|
onClick={() => editor.chain().focus().setHorizontalRule().run()}
|
||||||
disabled={!editor.can().chain().focus().setHorizontalRule().run()}
|
disabled={!editor.can().chain().focus().setHorizontalRule().run()}
|
||||||
sx={{ color: 'gray', padding: isMobile ? '5px' : 'revert' }}
|
sx={{ color: 'gray', padding: 'revert' }}
|
||||||
>
|
>
|
||||||
<HorizontalRuleIcon />
|
<HorizontalRuleIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -252,7 +251,7 @@ const MenuBar = ({
|
|||||||
color: editor.isActive('heading', { level: 1 })
|
color: editor.isActive('heading', { level: 1 })
|
||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary,
|
: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormatHeadingIcon fontSize="small" />
|
<FormatHeadingIcon fontSize="small" />
|
||||||
@ -260,7 +259,7 @@ const MenuBar = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => editor.chain().focus().undo().run()}
|
onClick={() => editor.chain().focus().undo().run()}
|
||||||
disabled={!editor.can().chain().focus().undo().run()}
|
disabled={!editor.can().chain().focus().undo().run()}
|
||||||
sx={{ color: 'gray', padding: isMobile ? '5px' : 'revert' }}
|
sx={{ color: 'gray', padding: 'revert' }}
|
||||||
>
|
>
|
||||||
<UndoIcon />
|
<UndoIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -313,7 +312,7 @@ const MenuBar = ({
|
|||||||
onClick={triggerImageUpload}
|
onClick={triggerImageUpload}
|
||||||
sx={{
|
sx={{
|
||||||
color: theme.palette.text.secondary,
|
color: theme.palette.text.secondary,
|
||||||
padding: isMobile ? '5px' : 'revert',
|
padding: 'revert',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ImageIcon />
|
<ImageIcon />
|
||||||
@ -398,11 +397,6 @@ export default ({
|
|||||||
usersRef.current = users; // Keep users up-to-date
|
usersRef.current = users; // Keep users up-to-date
|
||||||
}, [users]);
|
}, [users]);
|
||||||
|
|
||||||
const handleFocus = () => {
|
|
||||||
if (!isMobile) return;
|
|
||||||
setIsFocusedParent(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
const htmlContent = editorRef.current.getHTML();
|
const htmlContent = editorRef.current.getHTML();
|
||||||
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') {
|
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') {
|
||||||
@ -499,7 +493,7 @@ export default ({
|
|||||||
>
|
>
|
||||||
<EditorProvider
|
<EditorProvider
|
||||||
slotBefore={
|
slotBefore={
|
||||||
(isFocusedParent || !isMobile || overrideMobile) && (
|
(isFocusedParent || overrideMobile) && (
|
||||||
<MenuBar
|
<MenuBar
|
||||||
setEditorRef={setEditorRefFunc}
|
setEditorRef={setEditorRefFunc}
|
||||||
isChat={isChat}
|
isChat={isChat}
|
||||||
@ -511,21 +505,15 @@ export default ({
|
|||||||
extensions={[...extensionsFiltered, ...additionalExtensions]}
|
extensions={[...extensionsFiltered, ...additionalExtensions]}
|
||||||
content={content}
|
content={content}
|
||||||
onCreate={({ editor }) => {
|
onCreate={({ editor }) => {
|
||||||
editor.on('focus', handleFocus); // Listen for focus event
|
|
||||||
editor.on('blur', handleBlur); // Listen for blur event
|
editor.on('blur', handleBlur); // Listen for blur event
|
||||||
}}
|
}}
|
||||||
onUpdate={({ editor }) => {
|
onUpdate={({ editor }) => {
|
||||||
editor.on('focus', handleFocus); // Ensure focus is updated
|
|
||||||
editor.on('blur', handleBlur); // Ensure blur is updated
|
editor.on('blur', handleBlur); // Ensure blur is updated
|
||||||
}}
|
}}
|
||||||
editorProps={{
|
editorProps={{
|
||||||
attributes: {
|
attributes: {
|
||||||
class: 'tiptap-prosemirror',
|
class: 'tiptap-prosemirror',
|
||||||
style: isMobile
|
style: `overflow: auto; max-height: 250px`,
|
||||||
? `overflow: auto; min-height: ${
|
|
||||||
customEditorHeight ? '200px' : '0px'
|
|
||||||
}; max-height:calc(100svh - ${customEditorHeight || '140px'})`
|
|
||||||
: `overflow: auto; max-height: 250px`,
|
|
||||||
},
|
},
|
||||||
handleKeyDown(view, event) {
|
handleKeyDown(view, event) {
|
||||||
if (
|
if (
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Drawer from '@mui/material/Drawer';
|
import Drawer from '@mui/material/Drawer';
|
||||||
import { isMobile } from '../../App';
|
|
||||||
export const DrawerComponent = ({ open, setOpen, children }) => {
|
export const DrawerComponent = ({ open, setOpen, children }) => {
|
||||||
const toggleDrawer = (newOpen: boolean) => () => {
|
const toggleDrawer = (newOpen: boolean) => () => {
|
||||||
setOpen(newOpen);
|
setOpen(newOpen);
|
||||||
@ -9,10 +8,7 @@ export const DrawerComponent = ({ open, setOpen, children }) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||||
<Box
|
<Box sx={{ width: '400px', height: '100%' }} role="presentation">
|
||||||
sx={{ width: isMobile ? '100vw' : '400px', height: '100%' }}
|
|
||||||
role="presentation"
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'
|
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom';
|
||||||
import { Box, IconButton, Slider } from '@mui/material'
|
import { Box, IconButton, Slider } from '@mui/material';
|
||||||
import { CircularProgress, Typography } from '@mui/material'
|
import { CircularProgress, Typography } from '@mui/material';
|
||||||
import { Key } from 'ts-key-enum'
|
import { Key } from 'ts-key-enum';
|
||||||
import {
|
import {
|
||||||
PlayArrow,
|
PlayArrow,
|
||||||
Pause,
|
Pause,
|
||||||
VolumeUp,
|
VolumeUp,
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
PictureInPicture, VolumeOff, Calculate
|
PictureInPicture,
|
||||||
} from '@mui/icons-material'
|
VolumeOff,
|
||||||
import { styled } from '@mui/system'
|
Calculate,
|
||||||
import { Refresh } from '@mui/icons-material'
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/system';
|
||||||
|
import { Refresh } from '@mui/icons-material';
|
||||||
|
|
||||||
import { Menu, MenuItem } from '@mui/material'
|
import { Menu, MenuItem } from '@mui/material';
|
||||||
import { MoreVert as MoreIcon } from '@mui/icons-material'
|
import { MoreVert as MoreIcon } from '@mui/icons-material';
|
||||||
import { GlobalContext, getBaseApiReact } from '../../App'
|
import { GlobalContext, getBaseApiReact } from '../../App';
|
||||||
import { resourceKeySelector } from '../../atoms/global'
|
import { resourceKeySelector } from '../../atoms/global';
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil';
|
||||||
const VideoContainer = styled(Box)`
|
const VideoContainer = styled(Box)`
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -28,14 +30,14 @@ const VideoContainer = styled(Box)`
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const VideoElement = styled('video')`
|
const VideoElement = styled('video')`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: calc(100vh - 150px);
|
max-height: calc(100vh - 150px);
|
||||||
background: rgb(33, 33, 33);
|
background: rgb(33, 33, 33);
|
||||||
`
|
`;
|
||||||
|
|
||||||
const ControlsContainer = styled(Box)`
|
const ControlsContainer = styled(Box)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -47,18 +49,18 @@ const ControlsContainer = styled(Box)`
|
|||||||
right: 0;
|
right: 0;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
`
|
`;
|
||||||
|
|
||||||
interface VideoPlayerProps {
|
interface VideoPlayerProps {
|
||||||
src?: string
|
src?: string;
|
||||||
poster?: string
|
poster?: string;
|
||||||
name?: string
|
name?: string;
|
||||||
identifier?: string
|
identifier?: string;
|
||||||
service?: string
|
service?: string;
|
||||||
autoplay?: boolean
|
autoplay?: boolean;
|
||||||
from?: string | null
|
from?: string | null;
|
||||||
customStyle?: any
|
customStyle?: any;
|
||||||
user?: string
|
user?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
||||||
@ -69,33 +71,30 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
autoplay = true,
|
autoplay = true,
|
||||||
from = null,
|
from = null,
|
||||||
customStyle = {},
|
customStyle = {},
|
||||||
node
|
node,
|
||||||
}) => {
|
}) => {
|
||||||
|
const keyIdentifier = useMemo(() => {
|
||||||
const keyIdentifier = useMemo(()=> {
|
if (name && identifier && service) {
|
||||||
|
return `${service}-${name}-${identifier}`;
|
||||||
if(name && identifier && service){
|
|
||||||
return `${service}-${name}-${identifier}`
|
|
||||||
} else {
|
} else {
|
||||||
return undefined
|
return undefined;
|
||||||
}
|
}
|
||||||
}, [service, name, identifier])
|
}, [service, name, identifier]);
|
||||||
const download = useRecoilValue(resourceKeySelector(keyIdentifier));
|
const download = useRecoilValue(resourceKeySelector(keyIdentifier));
|
||||||
const { downloadResource } = useContext(GlobalContext);
|
const { downloadResource } = useContext(GlobalContext);
|
||||||
|
|
||||||
const videoRef = useRef<HTMLVideoElement | null>(null)
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
const [playing, setPlaying] = useState(false)
|
const [playing, setPlaying] = useState(false);
|
||||||
const [volume, setVolume] = useState(1)
|
const [volume, setVolume] = useState(1);
|
||||||
const [mutedVolume, setMutedVolume] = useState(1)
|
const [mutedVolume, setMutedVolume] = useState(1);
|
||||||
const [isMuted, setIsMuted] = useState(false)
|
const [isMuted, setIsMuted] = useState(false);
|
||||||
const [progress, setProgress] = useState(0)
|
const [progress, setProgress] = useState(0);
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [canPlay, setCanPlay] = useState(false)
|
const [canPlay, setCanPlay] = useState(false);
|
||||||
const [startPlay, setStartPlay] = useState(false)
|
const [startPlay, setStartPlay] = useState(false);
|
||||||
const [isMobileView, setIsMobileView] = useState(false)
|
const [playbackRate, setPlaybackRate] = useState(1);
|
||||||
const [playbackRate, setPlaybackRate] = useState(1)
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const reDownload = useRef<boolean>(false);
|
||||||
const reDownload = useRef<boolean>(false)
|
|
||||||
|
|
||||||
const resetVideoState = () => {
|
const resetVideoState = () => {
|
||||||
// Reset all states to their initial values
|
// Reset all states to their initial values
|
||||||
@ -107,10 +106,9 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setCanPlay(false);
|
setCanPlay(false);
|
||||||
setStartPlay(false);
|
setStartPlay(false);
|
||||||
setIsMobileView(false);
|
|
||||||
setPlaybackRate(1);
|
setPlaybackRate(1);
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
|
|
||||||
// Reset refs to their initial values
|
// Reset refs to their initial values
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
videoRef.current.pause(); // Ensure the video is paused
|
videoRef.current.pause(); // Ensure the video is paused
|
||||||
@ -120,18 +118,19 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const src = useMemo(() => {
|
const src = useMemo(() => {
|
||||||
if(name && identifier && service){
|
if (name && identifier && service) {
|
||||||
return `${node || getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}`
|
return `${node || getBaseApiReact()}/arbitrary/${service}/${name}/${identifier}`;
|
||||||
}
|
}
|
||||||
return ''
|
return '';
|
||||||
}, [service, name, identifier])
|
}, [service, name, identifier]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
resetVideoState();
|
||||||
|
}, [keyIdentifier]);
|
||||||
|
|
||||||
useEffect(()=> {
|
|
||||||
resetVideoState()
|
|
||||||
}, [keyIdentifier])
|
|
||||||
const resourceStatus = useMemo(() => {
|
const resourceStatus = useMemo(() => {
|
||||||
return download?.status || {}
|
return download?.status || {};
|
||||||
}, [download])
|
}, [download]);
|
||||||
|
|
||||||
const minSpeed = 0.25;
|
const minSpeed = 0.25;
|
||||||
const maxSpeed = 4.0;
|
const maxSpeed = 4.0;
|
||||||
@ -139,306 +138,339 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
|
|
||||||
const updatePlaybackRate = (newSpeed: number) => {
|
const updatePlaybackRate = (newSpeed: number) => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
if (newSpeed > maxSpeed || newSpeed < minSpeed)
|
if (newSpeed > maxSpeed || newSpeed < minSpeed) newSpeed = minSpeed;
|
||||||
newSpeed = minSpeed
|
videoRef.current.playbackRate = newSpeed;
|
||||||
videoRef.current.playbackRate = newSpeed
|
setPlaybackRate(newSpeed);
|
||||||
setPlaybackRate(newSpeed)
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const increaseSpeed = (wrapOverflow = true) => {
|
const increaseSpeed = (wrapOverflow = true) => {
|
||||||
const changedSpeed = playbackRate + speedChange
|
const changedSpeed = playbackRate + speedChange;
|
||||||
let newSpeed = wrapOverflow ? changedSpeed : Math.min(changedSpeed, maxSpeed)
|
let newSpeed = wrapOverflow
|
||||||
|
? changedSpeed
|
||||||
|
: Math.min(changedSpeed, maxSpeed);
|
||||||
|
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
updatePlaybackRate(newSpeed);
|
updatePlaybackRate(newSpeed);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const decreaseSpeed = () => {
|
const decreaseSpeed = () => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
updatePlaybackRate(playbackRate - speedChange);
|
updatePlaybackRate(playbackRate - speedChange);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const togglePlay = async () => {
|
const togglePlay = async () => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
setStartPlay(true)
|
setStartPlay(true);
|
||||||
if (!src || resourceStatus?.status !== 'READY') {
|
if (!src || resourceStatus?.status !== 'READY') {
|
||||||
ReactDOM.flushSync(() => {
|
ReactDOM.flushSync(() => {
|
||||||
setIsLoading(true)
|
setIsLoading(true);
|
||||||
})
|
});
|
||||||
getSrc()
|
getSrc();
|
||||||
}
|
}
|
||||||
if (playing) {
|
if (playing) {
|
||||||
videoRef.current.pause()
|
videoRef.current.pause();
|
||||||
} else {
|
} else {
|
||||||
videoRef.current.play()
|
videoRef.current.play();
|
||||||
}
|
}
|
||||||
setPlaying(!playing)
|
setPlaying(!playing);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const onVolumeChange = (_: any, value: number | number[]) => {
|
const onVolumeChange = (_: any, value: number | number[]) => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
videoRef.current.volume = value as number
|
videoRef.current.volume = value as number;
|
||||||
setVolume(value as number)
|
setVolume(value as number);
|
||||||
setIsMuted(false)
|
setIsMuted(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const onProgressChange = (_: any, value: number | number[]) => {
|
const onProgressChange = (_: any, value: number | number[]) => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
videoRef.current.currentTime = value as number
|
videoRef.current.currentTime = value as number;
|
||||||
setProgress(value as number)
|
setProgress(value as number);
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
videoRef.current.play()
|
videoRef.current.play();
|
||||||
setPlaying(true)
|
setPlaying(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleEnded = () => {
|
const handleEnded = () => {
|
||||||
setPlaying(false)
|
setPlaying(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const updateProgress = () => {
|
const updateProgress = () => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
setProgress(videoRef.current.currentTime)
|
setProgress(videoRef.current.currentTime);
|
||||||
}
|
};
|
||||||
|
|
||||||
const [isFullscreen, setIsFullscreen] = useState(false)
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
const enterFullscreen = () => {
|
const enterFullscreen = () => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
if (videoRef.current.requestFullscreen) {
|
if (videoRef.current.requestFullscreen) {
|
||||||
videoRef.current.requestFullscreen()
|
videoRef.current.requestFullscreen();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const exitFullscreen = () => {
|
const exitFullscreen = () => {
|
||||||
if (document.exitFullscreen) {
|
if (document.exitFullscreen) {
|
||||||
document.exitFullscreen()
|
document.exitFullscreen();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const toggleFullscreen = () => {
|
const toggleFullscreen = () => {
|
||||||
isFullscreen ? exitFullscreen() : enterFullscreen()
|
isFullscreen ? exitFullscreen() : enterFullscreen();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleFullscreenChange = () => {
|
const handleFullscreenChange = () => {
|
||||||
setIsFullscreen(!!document.fullscreenElement)
|
setIsFullscreen(!!document.fullscreenElement);
|
||||||
}
|
};
|
||||||
|
|
||||||
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
||||||
}
|
};
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleCanPlay = () => {
|
const handleCanPlay = () => {
|
||||||
setIsLoading(false)
|
setIsLoading(false);
|
||||||
setCanPlay(true)
|
setCanPlay(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const getSrc = React.useCallback(async () => {
|
const getSrc = React.useCallback(async () => {
|
||||||
if (!name || !identifier || !service) return
|
if (!name || !identifier || !service) return;
|
||||||
try {
|
try {
|
||||||
downloadResource({
|
downloadResource({
|
||||||
name,
|
name,
|
||||||
service,
|
service,
|
||||||
identifier
|
identifier,
|
||||||
})
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error);
|
||||||
}
|
}
|
||||||
}, [identifier, name, service])
|
}, [identifier, name, service]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function formatTime(seconds: number): string {
|
function formatTime(seconds: number): string {
|
||||||
seconds = Math.floor(seconds)
|
seconds = Math.floor(seconds);
|
||||||
let minutes: number | string = Math.floor(seconds / 60)
|
let minutes: number | string = Math.floor(seconds / 60);
|
||||||
let hours: number | string = Math.floor(minutes / 60)
|
let hours: number | string = Math.floor(minutes / 60);
|
||||||
|
|
||||||
let remainingSeconds: number | string = seconds % 60
|
let remainingSeconds: number | string = seconds % 60;
|
||||||
let remainingMinutes: number | string = minutes % 60
|
let remainingMinutes: number | string = minutes % 60;
|
||||||
|
|
||||||
if (remainingSeconds < 10) {
|
if (remainingSeconds < 10) {
|
||||||
remainingSeconds = '0' + remainingSeconds
|
remainingSeconds = '0' + remainingSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingMinutes < 10) {
|
if (remainingMinutes < 10) {
|
||||||
remainingMinutes = '0' + remainingMinutes
|
remainingMinutes = '0' + remainingMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hours === 0) {
|
if (hours === 0) {
|
||||||
hours = ''
|
hours = '';
|
||||||
}
|
} else {
|
||||||
else {
|
hours = hours + ':';
|
||||||
hours = hours + ':'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hours + remainingMinutes + ':' + remainingSeconds
|
return hours + remainingMinutes + ':' + remainingSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reloadVideo = () => {
|
const reloadVideo = () => {
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return;
|
||||||
const currentTime = videoRef.current.currentTime
|
const currentTime = videoRef.current.currentTime;
|
||||||
videoRef.current.src = src
|
videoRef.current.src = src;
|
||||||
videoRef.current.load()
|
videoRef.current.load();
|
||||||
videoRef.current.currentTime = currentTime
|
videoRef.current.currentTime = currentTime;
|
||||||
if (playing) {
|
if (playing) {
|
||||||
videoRef.current.play()
|
videoRef.current.play();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
resourceStatus?.status === 'DOWNLOADED' &&
|
resourceStatus?.status === 'DOWNLOADED' &&
|
||||||
reDownload?.current === false
|
reDownload?.current === false
|
||||||
) {
|
) {
|
||||||
getSrc()
|
getSrc();
|
||||||
reDownload.current = true
|
reDownload.current = true;
|
||||||
}
|
}
|
||||||
}, [getSrc, resourceStatus])
|
}, [getSrc, resourceStatus]);
|
||||||
|
|
||||||
const handleMenuOpen = (event: any) => {
|
const handleMenuOpen = (event: any) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMenuClose = () => {
|
const handleMenuClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const videoWidth = videoRef?.current?.offsetWidth
|
const videoWidth = videoRef?.current?.offsetWidth;
|
||||||
if (videoWidth && videoWidth <= 600) {
|
}, [canPlay]);
|
||||||
setIsMobileView(true)
|
|
||||||
}
|
|
||||||
}, [canPlay])
|
|
||||||
|
|
||||||
const getDownloadProgress = (current: number, total: number) => {
|
const getDownloadProgress = (current: number, total: number) => {
|
||||||
const progress = current / total * 100;
|
const progress = (current / total) * 100;
|
||||||
return Number.isNaN(progress) ? '' : progress.toFixed(0) + '%'
|
return Number.isNaN(progress) ? '' : progress.toFixed(0) + '%';
|
||||||
}
|
};
|
||||||
const mute = () => {
|
const mute = () => {
|
||||||
setIsMuted(true)
|
setIsMuted(true);
|
||||||
setMutedVolume(volume)
|
setMutedVolume(volume);
|
||||||
setVolume(0)
|
setVolume(0);
|
||||||
if (videoRef.current) videoRef.current.volume = 0
|
if (videoRef.current) videoRef.current.volume = 0;
|
||||||
}
|
};
|
||||||
const unMute = () => {
|
const unMute = () => {
|
||||||
setIsMuted(false)
|
setIsMuted(false);
|
||||||
setVolume(mutedVolume)
|
setVolume(mutedVolume);
|
||||||
if (videoRef.current) videoRef.current.volume = mutedVolume
|
if (videoRef.current) videoRef.current.volume = mutedVolume;
|
||||||
}
|
};
|
||||||
|
|
||||||
const toggleMute = () => {
|
const toggleMute = () => {
|
||||||
isMuted ? unMute() : mute();
|
isMuted ? unMute() : mute();
|
||||||
}
|
};
|
||||||
|
|
||||||
const changeVolume = (volumeChange: number) => {
|
const changeVolume = (volumeChange: number) => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
const minVolume = 0;
|
const minVolume = 0;
|
||||||
const maxVolume = 1;
|
const maxVolume = 1;
|
||||||
|
|
||||||
|
let newVolume = volumeChange + volume;
|
||||||
|
|
||||||
let newVolume = volumeChange + volume
|
newVolume = Math.max(newVolume, minVolume);
|
||||||
|
newVolume = Math.min(newVolume, maxVolume);
|
||||||
|
|
||||||
newVolume = Math.max(newVolume, minVolume)
|
setIsMuted(false);
|
||||||
newVolume = Math.min(newVolume, maxVolume)
|
setMutedVolume(newVolume);
|
||||||
|
videoRef.current.volume = newVolume;
|
||||||
setIsMuted(false)
|
|
||||||
setMutedVolume(newVolume)
|
|
||||||
videoRef.current.volume = newVolume
|
|
||||||
setVolume(newVolume);
|
setVolume(newVolume);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
const setProgressRelative = (secondsChange: number) => {
|
const setProgressRelative = (secondsChange: number) => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
const currentTime = videoRef.current?.currentTime
|
const currentTime = videoRef.current?.currentTime;
|
||||||
const minTime = 0
|
const minTime = 0;
|
||||||
const maxTime = videoRef.current?.duration || 100
|
const maxTime = videoRef.current?.duration || 100;
|
||||||
|
|
||||||
let newTime = currentTime + secondsChange;
|
let newTime = currentTime + secondsChange;
|
||||||
newTime = Math.max(newTime, minTime)
|
newTime = Math.max(newTime, minTime);
|
||||||
newTime = Math.min(newTime, maxTime)
|
newTime = Math.min(newTime, maxTime);
|
||||||
videoRef.current.currentTime = newTime;
|
videoRef.current.currentTime = newTime;
|
||||||
setProgress(newTime);
|
setProgress(newTime);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const setProgressAbsolute = (videoPercent: number) => {
|
const setProgressAbsolute = (videoPercent: number) => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
videoPercent = Math.min(videoPercent, 100)
|
videoPercent = Math.min(videoPercent, 100);
|
||||||
videoPercent = Math.max(videoPercent, 0)
|
videoPercent = Math.max(videoPercent, 0);
|
||||||
const finalTime = videoRef.current?.duration * videoPercent / 100
|
const finalTime = (videoRef.current?.duration * videoPercent) / 100;
|
||||||
videoRef.current.currentTime = finalTime
|
videoRef.current.currentTime = finalTime;
|
||||||
setProgress(finalTime);
|
setProgress(finalTime);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const keyboardShortcutsDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
const keyboardShortcutsDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
|
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case Key.Add: increaseSpeed(false); break;
|
case Key.Add:
|
||||||
case '+': increaseSpeed(false); break;
|
increaseSpeed(false);
|
||||||
case '>': increaseSpeed(false); break;
|
break;
|
||||||
|
case '+':
|
||||||
|
increaseSpeed(false);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
increaseSpeed(false);
|
||||||
|
break;
|
||||||
|
|
||||||
case Key.Subtract: decreaseSpeed(); break;
|
case Key.Subtract:
|
||||||
case '-': decreaseSpeed(); break;
|
decreaseSpeed();
|
||||||
case '<': decreaseSpeed(); break;
|
break;
|
||||||
|
case '-':
|
||||||
|
decreaseSpeed();
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
decreaseSpeed();
|
||||||
|
break;
|
||||||
|
|
||||||
case Key.ArrowLeft: {
|
case Key.ArrowLeft:
|
||||||
if (e.shiftKey) setProgressRelative(-300);
|
{
|
||||||
else if (e.ctrlKey) setProgressRelative(-60);
|
if (e.shiftKey) setProgressRelative(-300);
|
||||||
else if (e.altKey) setProgressRelative(-10);
|
else if (e.ctrlKey) setProgressRelative(-60);
|
||||||
else setProgressRelative(-5);
|
else if (e.altKey) setProgressRelative(-10);
|
||||||
} break;
|
else setProgressRelative(-5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Key.ArrowRight: {
|
case Key.ArrowRight:
|
||||||
if (e.shiftKey) setProgressRelative(300);
|
{
|
||||||
else if (e.ctrlKey) setProgressRelative(60);
|
if (e.shiftKey) setProgressRelative(300);
|
||||||
else if (e.altKey) setProgressRelative(10);
|
else if (e.ctrlKey) setProgressRelative(60);
|
||||||
else setProgressRelative(5);
|
else if (e.altKey) setProgressRelative(10);
|
||||||
} break;
|
else setProgressRelative(5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Key.ArrowDown: changeVolume(-0.05); break;
|
case Key.ArrowDown:
|
||||||
case Key.ArrowUp: changeVolume(0.05); break;
|
changeVolume(-0.05);
|
||||||
|
break;
|
||||||
|
case Key.ArrowUp:
|
||||||
|
changeVolume(0.05);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const keyboardShortcutsUp = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
const keyboardShortcutsUp = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
|
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case ' ': togglePlay(); break;
|
case ' ':
|
||||||
case 'm': toggleMute(); break;
|
togglePlay();
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
toggleMute();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'f': enterFullscreen(); break;
|
case 'f':
|
||||||
case Key.Escape: exitFullscreen(); break;
|
enterFullscreen();
|
||||||
|
break;
|
||||||
|
case Key.Escape:
|
||||||
|
exitFullscreen();
|
||||||
|
break;
|
||||||
|
|
||||||
case '0': setProgressAbsolute(0); break;
|
case '0':
|
||||||
case '1': setProgressAbsolute(10); break;
|
setProgressAbsolute(0);
|
||||||
case '2': setProgressAbsolute(20); break;
|
break;
|
||||||
case '3': setProgressAbsolute(30); break;
|
case '1':
|
||||||
case '4': setProgressAbsolute(40); break;
|
setProgressAbsolute(10);
|
||||||
case '5': setProgressAbsolute(50); break;
|
break;
|
||||||
case '6': setProgressAbsolute(60); break;
|
case '2':
|
||||||
case '7': setProgressAbsolute(70); break;
|
setProgressAbsolute(20);
|
||||||
case '8': setProgressAbsolute(80); break;
|
break;
|
||||||
case '9': setProgressAbsolute(90); break;
|
case '3':
|
||||||
|
setProgressAbsolute(30);
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
setProgressAbsolute(40);
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
setProgressAbsolute(50);
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
setProgressAbsolute(60);
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
setProgressAbsolute(70);
|
||||||
|
break;
|
||||||
|
case '8':
|
||||||
|
setProgressAbsolute(80);
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
setProgressAbsolute(90);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VideoContainer
|
<VideoContainer
|
||||||
@ -451,7 +483,6 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<Box
|
<Box
|
||||||
position="absolute"
|
position="absolute"
|
||||||
@ -467,40 +498,44 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: '10px'
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CircularProgress color="secondary" />
|
<CircularProgress color="secondary" />
|
||||||
|
|
||||||
<Typography
|
|
||||||
variant="subtitle2"
|
|
||||||
component="div"
|
|
||||||
sx={{
|
|
||||||
color: 'white',
|
|
||||||
fontSize: '15px',
|
|
||||||
textAlign: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{resourceStatus?.status === 'REFETCHING' ? (
|
|
||||||
<>
|
|
||||||
<>
|
|
||||||
{getDownloadProgress(resourceStatus?.localChunkCount, resourceStatus?.totalChunkCount)}
|
|
||||||
</>
|
|
||||||
|
|
||||||
<> Refetching data in 25 seconds</>
|
<Typography
|
||||||
</>
|
variant="subtitle2"
|
||||||
) : resourceStatus?.status === 'DOWNLOADED' ? (
|
component="div"
|
||||||
<>Download Completed: building tutorial video...</>
|
sx={{
|
||||||
) : resourceStatus?.status !== 'READY' ? (
|
color: 'white',
|
||||||
|
fontSize: '15px',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{resourceStatus?.status === 'REFETCHING' ? (
|
||||||
|
<>
|
||||||
<>
|
<>
|
||||||
{getDownloadProgress(resourceStatus?.localChunkCount || 0, resourceStatus?.totalChunkCount || 100)}
|
{getDownloadProgress(
|
||||||
|
resourceStatus?.localChunkCount,
|
||||||
|
resourceStatus?.totalChunkCount
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<>Fetching tutorial from the Qortal Network...</>
|
<> Refetching data in 25 seconds</>
|
||||||
)}
|
</>
|
||||||
</Typography>
|
) : resourceStatus?.status === 'DOWNLOADED' ? (
|
||||||
|
<>Download Completed: building tutorial video...</>
|
||||||
|
) : resourceStatus?.status !== 'READY' ? (
|
||||||
|
<>
|
||||||
|
{getDownloadProgress(
|
||||||
|
resourceStatus?.localChunkCount || 0,
|
||||||
|
resourceStatus?.totalChunkCount || 100
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>Fetching tutorial from the Qortal Network...</>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{((!src && !isLoading) || !startPlay) && (
|
{((!src && !isLoading) || !startPlay) && (
|
||||||
@ -516,59 +551,61 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
zIndex={500}
|
zIndex={500}
|
||||||
bgcolor="rgba(0, 0, 0, 0.6)"
|
bgcolor="rgba(0, 0, 0, 0.6)"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
togglePlay()
|
togglePlay();
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
cursor: 'pointer'
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlayArrow
|
<PlayArrow
|
||||||
sx={{
|
sx={{
|
||||||
width: '50px',
|
width: '50px',
|
||||||
height: '50px',
|
height: '50px',
|
||||||
color: 'white'
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box sx={{
|
<Box
|
||||||
display: 'flex',
|
sx={{
|
||||||
flexGrow: 1,
|
display: 'flex',
|
||||||
width: '100%',
|
flexGrow: 1,
|
||||||
height: 'calc(100% - 60px)',
|
|
||||||
}}>
|
|
||||||
<VideoElement
|
|
||||||
id={identifier}
|
|
||||||
ref={videoRef}
|
|
||||||
src={!startPlay ? '' : resourceStatus?.status === 'READY' ? src : ''}
|
|
||||||
poster={!startPlay ? poster : ""}
|
|
||||||
onTimeUpdate={updateProgress}
|
|
||||||
autoPlay={autoplay}
|
|
||||||
onClick={togglePlay}
|
|
||||||
onEnded={handleEnded}
|
|
||||||
// onLoadedMetadata={handleLoadedMetadata}
|
|
||||||
onCanPlay={handleCanPlay}
|
|
||||||
preload="metadata"
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: 'calc(100% - 60px)',
|
||||||
...customStyle
|
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<VideoElement
|
||||||
|
id={identifier}
|
||||||
|
ref={videoRef}
|
||||||
|
src={!startPlay ? '' : resourceStatus?.status === 'READY' ? src : ''}
|
||||||
|
poster={!startPlay ? poster : ''}
|
||||||
|
onTimeUpdate={updateProgress}
|
||||||
|
autoPlay={autoplay}
|
||||||
|
onClick={togglePlay}
|
||||||
|
onEnded={handleEnded}
|
||||||
|
// onLoadedMetadata={handleLoadedMetadata}
|
||||||
|
onCanPlay={handleCanPlay}
|
||||||
|
preload="metadata"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
...customStyle,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<ControlsContainer
|
<ControlsContainer
|
||||||
sx={{
|
sx={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
background: 'var(--bg-primary)',
|
background: 'var(--bg-primary)',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
flexShrink: 0
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isMobileView && canPlay ? (
|
{canPlay ? (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)'
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
}}
|
}}
|
||||||
onClick={togglePlay}
|
onClick={togglePlay}
|
||||||
>
|
>
|
||||||
@ -577,77 +614,7 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
marginLeft: '15px'
|
marginLeft: '15px',
|
||||||
}}
|
|
||||||
onClick={reloadVideo}
|
|
||||||
>
|
|
||||||
<Refresh />
|
|
||||||
</IconButton>
|
|
||||||
<Slider
|
|
||||||
value={progress}
|
|
||||||
onChange={onProgressChange}
|
|
||||||
min={0}
|
|
||||||
max={videoRef.current?.duration || 100}
|
|
||||||
sx={{ flexGrow: 1, mx: 2 }}
|
|
||||||
/>
|
|
||||||
<IconButton
|
|
||||||
edge="end"
|
|
||||||
color="inherit"
|
|
||||||
aria-label="menu"
|
|
||||||
onClick={handleMenuOpen}
|
|
||||||
>
|
|
||||||
<MoreIcon />
|
|
||||||
</IconButton>
|
|
||||||
<Menu
|
|
||||||
id="simple-menu"
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
keepMounted
|
|
||||||
open={Boolean(anchorEl)}
|
|
||||||
onClose={handleMenuClose}
|
|
||||||
PaperProps={{
|
|
||||||
style: {
|
|
||||||
width: '250px'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem>
|
|
||||||
<VolumeUp />
|
|
||||||
<Slider
|
|
||||||
value={volume}
|
|
||||||
onChange={onVolumeChange}
|
|
||||||
min={0}
|
|
||||||
max={1}
|
|
||||||
step={0.01} />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem onClick={() => increaseSpeed()}>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
fontSize: '14px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Speed: {playbackRate}x
|
|
||||||
</Typography>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem onClick={toggleFullscreen}>
|
|
||||||
<Fullscreen />
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</>
|
|
||||||
) : canPlay ? (
|
|
||||||
<>
|
|
||||||
<IconButton
|
|
||||||
sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)'
|
|
||||||
}}
|
|
||||||
onClick={togglePlay}
|
|
||||||
>
|
|
||||||
{playing ? <Pause /> : <PlayArrow />}
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
marginLeft: '15px'
|
|
||||||
}}
|
}}
|
||||||
onClick={reloadVideo}
|
onClick={reloadVideo}
|
||||||
>
|
>
|
||||||
@ -669,7 +636,7 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
!videoRef.current?.duration || !progress
|
!videoRef.current?.duration || !progress
|
||||||
? 'hidden'
|
? 'hidden'
|
||||||
: 'visible',
|
: 'visible',
|
||||||
flexShrink: 0
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{progress && videoRef.current?.duration && formatTime(progress)}/
|
{progress && videoRef.current?.duration && formatTime(progress)}/
|
||||||
@ -680,7 +647,7 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
marginRight: '10px'
|
marginRight: '10px',
|
||||||
}}
|
}}
|
||||||
onClick={toggleMute}
|
onClick={toggleMute}
|
||||||
>
|
>
|
||||||
@ -694,14 +661,14 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
step={0.01}
|
step={0.01}
|
||||||
sx={{
|
sx={{
|
||||||
maxWidth: '100px',
|
maxWidth: '100px',
|
||||||
color: 'var(--Mail-Background)'
|
color: 'var(--Mail-Background)',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
marginLeft: '5px'
|
marginLeft: '5px',
|
||||||
}}
|
}}
|
||||||
onClick={(e) => increaseSpeed()}
|
onClick={(e) => increaseSpeed()}
|
||||||
>
|
>
|
||||||
@ -709,7 +676,7 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.7)'
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
}}
|
}}
|
||||||
onClick={toggleFullscreen}
|
onClick={toggleFullscreen}
|
||||||
>
|
>
|
||||||
@ -719,5 +686,5 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
) : null}
|
) : null}
|
||||||
</ControlsContainer>
|
</ControlsContainer>
|
||||||
</VideoContainer>
|
</VideoContainer>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -26,7 +26,7 @@ import { AddGroupList } from './AddGroupList';
|
|||||||
import { UserListOfInvites } from './UserListOfInvites';
|
import { UserListOfInvites } from './UserListOfInvites';
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { MyContext, isMobile } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||||
|
|
||||||
export const Label = styled('label')`
|
export const Label = styled('label')`
|
||||||
@ -231,7 +231,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
aria-label="basic tabs example"
|
aria-label="basic tabs example"
|
||||||
variant={isMobile ? 'scrollable' : 'fullWidth'} // Scrollable on mobile, full width on desktop
|
variant={'fullWidth'}
|
||||||
scrollButtons="auto"
|
scrollButtons="auto"
|
||||||
allowScrollButtonsMobile
|
allowScrollButtonsMobile
|
||||||
sx={{
|
sx={{
|
||||||
@ -247,7 +247,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
@ -257,7 +257,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
@ -267,7 +267,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -61,11 +61,7 @@ import {
|
|||||||
unsubscribeFromEvent,
|
unsubscribeFromEvent,
|
||||||
} from '../../../utils/events';
|
} from '../../../utils/events';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import {
|
import { getArbitraryEndpointReact, getBaseApiReact } from '../../../App';
|
||||||
getArbitraryEndpointReact,
|
|
||||||
getBaseApiReact,
|
|
||||||
isMobile,
|
|
||||||
} from '../../../App';
|
|
||||||
import { WrapperUserAction } from '../../WrapperUserAction';
|
import { WrapperUserAction } from '../../WrapperUserAction';
|
||||||
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group';
|
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group';
|
||||||
const filterOptions = ['Recently active', 'Newest', 'Oldest'];
|
const filterOptions = ['Recently active', 'Newest', 'Oldest'];
|
||||||
@ -754,7 +750,6 @@ export const GroupMail = ({
|
|||||||
<ThreadSingleTitle
|
<ThreadSingleTitle
|
||||||
sx={{
|
sx={{
|
||||||
fontWeight: shouldAppearLighter && 300,
|
fontWeight: shouldAppearLighter && 300,
|
||||||
fontSize: isMobile && '18px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{thread?.threadData?.title}
|
{thread?.threadData?.title}
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import { Box, CircularProgress, Input } from '@mui/material';
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
CircularProgress,
|
|
||||||
Input,
|
|
||||||
Typography,
|
|
||||||
} from '@mui/material';
|
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import ShortUniqueId from 'short-unique-id';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
|
||||||
import ModalCloseSVG from '../../../assets/svgs/ModalClose.svg';
|
import ModalCloseSVG from '../../../assets/svgs/ModalClose.svg';
|
||||||
|
|
||||||
import ComposeIconSVG from '../../../assets/svgs/ComposeIcon.svg';
|
import ComposeIconSVG from '../../../assets/svgs/ComposeIcon.svg';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AttachmentContainer,
|
AttachmentContainer,
|
||||||
CloseContainer,
|
CloseContainer,
|
||||||
@ -22,7 +13,6 @@ import {
|
|||||||
InstanceFooter,
|
InstanceFooter,
|
||||||
InstanceListContainer,
|
InstanceListContainer,
|
||||||
InstanceListHeader,
|
InstanceListHeader,
|
||||||
NewMessageAttachmentImg,
|
|
||||||
NewMessageCloseImg,
|
NewMessageCloseImg,
|
||||||
NewMessageHeaderP,
|
NewMessageHeaderP,
|
||||||
NewMessageInputRow,
|
NewMessageInputRow,
|
||||||
@ -32,16 +22,9 @@ import {
|
|||||||
|
|
||||||
import { ReusableModal } from './ReusableModal';
|
import { ReusableModal } from './ReusableModal';
|
||||||
import { Spacer } from '../../../common/Spacer';
|
import { Spacer } from '../../../common/Spacer';
|
||||||
import { formatBytes } from '../../../utils/Size';
|
|
||||||
import { CreateThreadIcon } from '../../../assets/Icons/CreateThreadIcon';
|
import { CreateThreadIcon } from '../../../assets/Icons/CreateThreadIcon';
|
||||||
import { SendNewMessage } from '../../../assets/Icons/SendNewMessage';
|
import { SendNewMessage } from '../../../assets/Icons/SendNewMessage';
|
||||||
import { TextEditor } from './TextEditor';
|
import { MyContext, pauseAllQueues, resumeAllQueues } from '../../../App';
|
||||||
import {
|
|
||||||
MyContext,
|
|
||||||
isMobile,
|
|
||||||
pauseAllQueues,
|
|
||||||
resumeAllQueues,
|
|
||||||
} from '../../../App';
|
|
||||||
import { getFee } from '../../../background';
|
import { getFee } from '../../../background';
|
||||||
import TipTap from '../../Chat/TipTap';
|
import TipTap from '../../Chat/TipTap';
|
||||||
import { MessageDisplay } from '../../Chat/MessageDisplay';
|
import { MessageDisplay } from '../../Chat/MessageDisplay';
|
||||||
@ -411,8 +394,8 @@ export const NewThread = ({
|
|||||||
>
|
>
|
||||||
<ComposeContainer
|
<ComposeContainer
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile ? '5px' : '15px',
|
padding: '15px',
|
||||||
justifyContent: isMobile ? 'flex-start' : 'revert',
|
justifyContent: 'revert',
|
||||||
}}
|
}}
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
@ -423,7 +406,7 @@ export const NewThread = ({
|
|||||||
<ReusableModal
|
<ReusableModal
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
customStyles={{
|
customStyles={{
|
||||||
maxHeight: isMobile ? '95svh' : '95vh',
|
maxHeight: '95vh',
|
||||||
maxWidth: '950px',
|
maxWidth: '950px',
|
||||||
height: '700px',
|
height: '700px',
|
||||||
borderRadius: '12px 12px 0px 0px',
|
borderRadius: '12px 12px 0px 0px',
|
||||||
@ -434,8 +417,8 @@ export const NewThread = ({
|
|||||||
>
|
>
|
||||||
<InstanceListHeader
|
<InstanceListHeader
|
||||||
sx={{
|
sx={{
|
||||||
height: isMobile ? 'auto' : '50px',
|
height: '50px',
|
||||||
padding: isMobile ? '5px' : '20px 42px',
|
padding: '20px 42px',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -457,7 +440,7 @@ export const NewThread = ({
|
|||||||
<InstanceListContainer
|
<InstanceListContainer
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: '#434448',
|
backgroundColor: '#434448',
|
||||||
padding: isMobile ? '5px' : '20px 42px',
|
padding: '20px 42px',
|
||||||
height: 'calc(100% - 165px)',
|
height: 'calc(100% - 165px)',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
@ -481,7 +464,7 @@ export const NewThread = ({
|
|||||||
color: 'white',
|
color: 'white',
|
||||||
'& .MuiInput-input::placeholder': {
|
'& .MuiInput-input::placeholder': {
|
||||||
color: 'rgba(255,255,255, 0.70) !important',
|
color: 'rgba(255,255,255, 0.70) !important',
|
||||||
fontSize: isMobile ? '14px' : '20px',
|
fontSize: '20px',
|
||||||
fontStyle: 'normal',
|
fontStyle: 'normal',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
lineHeight: '120%', // 24px
|
lineHeight: '120%', // 24px
|
||||||
@ -509,7 +492,9 @@ export const NewThread = ({
|
|||||||
<MessageDisplay htmlContent={postReply?.textContentV2} />
|
<MessageDisplay htmlContent={postReply?.textContentV2} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{!isMobile && <Spacer height="30px" />}
|
|
||||||
|
<Spacer height="30px" />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
maxHeight: '40vh',
|
maxHeight: '40vh',
|
||||||
@ -530,12 +515,13 @@ export const NewThread = ({
|
|||||||
/> */}
|
/> */}
|
||||||
</Box>
|
</Box>
|
||||||
</InstanceListContainer>
|
</InstanceListContainer>
|
||||||
|
|
||||||
<InstanceFooter
|
<InstanceFooter
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: '#434448',
|
backgroundColor: '#434448',
|
||||||
padding: isMobile ? '5px' : '20px 42px',
|
padding: '20px 42px',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
height: isMobile ? 'auto' : '90px',
|
height: '90px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NewMessageSendButton onClick={sendMail}>
|
<NewMessageSendButton onClick={sendMail}>
|
||||||
@ -553,9 +539,11 @@ export const NewThread = ({
|
|||||||
<CircularProgress sx={{}} size={'12px'} />
|
<CircularProgress sx={{}} size={'12px'} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<NewMessageSendP>
|
<NewMessageSendP>
|
||||||
{isMessage ? 'Post' : 'Create Thread'}
|
{isMessage ? 'Post' : 'Create Thread'}
|
||||||
</NewMessageSendP>
|
</NewMessageSendP>
|
||||||
|
|
||||||
{isMessage ? (
|
{isMessage ? (
|
||||||
<SendNewMessage opacity={1} height="25px" width="25px" />
|
<SendNewMessage opacity={1} height="25px" width="25px" />
|
||||||
) : (
|
) : (
|
||||||
@ -564,6 +552,7 @@ export const NewThread = ({
|
|||||||
</NewMessageSendButton>
|
</NewMessageSendButton>
|
||||||
</InstanceFooter>
|
</InstanceFooter>
|
||||||
</ReusableModal>
|
</ReusableModal>
|
||||||
|
|
||||||
<CustomizedSnackbars
|
<CustomizedSnackbars
|
||||||
open={openSnack}
|
open={openSnack}
|
||||||
setOpen={setOpenSnack}
|
setOpen={setOpenSnack}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { Box, Modal, useTheme } from '@mui/material'
|
import { Box, Modal, useTheme } from '@mui/material';
|
||||||
import { isMobile } from '../../../App'
|
|
||||||
|
|
||||||
interface MyModalProps {
|
interface MyModalProps {
|
||||||
open: boolean
|
open: boolean;
|
||||||
onClose?: () => void
|
onClose?: () => void;
|
||||||
onSubmit?: (obj: any) => Promise<void>
|
onSubmit?: (obj: any) => Promise<void>;
|
||||||
children: any
|
children: any;
|
||||||
customStyles?: any
|
customStyles?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ReusableModal: React.FC<MyModalProps> = ({
|
export const ReusableModal: React.FC<MyModalProps> = ({
|
||||||
@ -15,9 +14,10 @@ export const ReusableModal: React.FC<MyModalProps> = ({
|
|||||||
onClose,
|
onClose,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
children,
|
children,
|
||||||
customStyles = {}
|
customStyles = {},
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={open}
|
open={open}
|
||||||
@ -32,27 +32,27 @@ export const ReusableModal: React.FC<MyModalProps> = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
disableAutoFocus
|
disableAutoFocus
|
||||||
disableEnforceFocus
|
disableEnforceFocus
|
||||||
disableRestoreFocus
|
disableRestoreFocus
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
|
||||||
top: '50%',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translate(-50%, -50%)',
|
|
||||||
width: isMobile ? '95%' : '75%',
|
|
||||||
bgcolor: theme.palette.primary.main,
|
bgcolor: theme.palette.primary.main,
|
||||||
boxShadow: 24,
|
boxShadow: 24,
|
||||||
p: 4,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
...customStyles
|
left: '50%',
|
||||||
|
p: 4,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: '75%',
|
||||||
|
...customStyles,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -41,11 +41,7 @@ import {
|
|||||||
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
|
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../../utils/events';
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../../utils/events';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import {
|
import { getArbitraryEndpointReact, getBaseApiReact } from '../../../App';
|
||||||
getArbitraryEndpointReact,
|
|
||||||
getBaseApiReact,
|
|
||||||
isMobile,
|
|
||||||
} from '../../../App';
|
|
||||||
import {
|
import {
|
||||||
ArrowDownward as ArrowDownwardIcon,
|
ArrowDownward as ArrowDownwardIcon,
|
||||||
ArrowUpward as ArrowUpwardIcon,
|
ArrowUpward as ArrowUpwardIcon,
|
||||||
@ -602,23 +598,18 @@ export const Thread = ({
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: isMobile ? '45px' : '35px',
|
gap: '35px',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: isMobile && '5px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ShowMessageReturnButton
|
<ShowMessageReturnButton
|
||||||
sx={{
|
|
||||||
padding: isMobile && '5px',
|
|
||||||
minWidth: isMobile && '50px',
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
closeThread();
|
closeThread();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MailIconImg src={ReturnSVG} />
|
<MailIconImg src={ReturnSVG} />
|
||||||
{!isMobile && <ComposeP>Return to Threads</ComposeP>}
|
<ComposeP>Return to Threads</ComposeP>
|
||||||
</ShowMessageReturnButton>
|
</ShowMessageReturnButton>
|
||||||
{/* Conditionally render the scroll buttons */}
|
{/* Conditionally render the scroll buttons */}
|
||||||
{showScrollButton &&
|
{showScrollButton &&
|
||||||
@ -628,7 +619,7 @@ export const Thread = ({
|
|||||||
sx={{
|
sx={{
|
||||||
color: 'white',
|
color: 'white',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: isMobile ? '28px' : '36px',
|
fontSize: '36px',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
@ -638,7 +629,7 @@ export const Thread = ({
|
|||||||
sx={{
|
sx={{
|
||||||
color: 'white',
|
color: 'white',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: isMobile ? '28px' : '36px',
|
fontSize: '36px',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
@ -655,38 +646,30 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
<div ref={threadBeginningRef} />
|
<div ref={threadBeginningRef} />
|
||||||
<ThreadContainer>
|
<ThreadContainer>
|
||||||
<Spacer height={isMobile ? '10px' : '30px'} />
|
<Spacer height={'30px'} />
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<GroupNameP
|
<GroupNameP>{currentThread?.threadData?.title}</GroupNameP>
|
||||||
sx={{
|
|
||||||
fontSize: isMobile && '18px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{currentThread?.threadData?.title}
|
|
||||||
</GroupNameP>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height={'15px'} />
|
<Spacer height={'15px'} />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
|
||||||
gap: '5px',
|
gap: '5px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -705,8 +688,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -725,8 +706,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -745,8 +724,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -764,7 +741,9 @@ export const Thread = ({
|
|||||||
Last
|
Last
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height={isMobile ? '10px' : '30px'} />
|
|
||||||
|
<Spacer height={'30px'} />
|
||||||
|
|
||||||
{combinedListTempAndReal.map((message, index, list) => {
|
{combinedListTempAndReal.map((message, index, list) => {
|
||||||
let fullMessage = message;
|
let fullMessage = message;
|
||||||
|
|
||||||
@ -780,17 +759,17 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
|
flexDirection: 'column',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
flexDirection: 'column',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
|
display: 'flex',
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -812,6 +791,7 @@ export const Thread = ({
|
|||||||
{message?.name?.charAt(0)}
|
{message?.name?.charAt(0)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</WrapperUserAction>
|
</WrapperUserAction>
|
||||||
|
|
||||||
<ThreadInfoColumn>
|
<ThreadInfoColumn>
|
||||||
<WrapperUserAction
|
<WrapperUserAction
|
||||||
disabled={userInfo?.name === message?.name}
|
disabled={userInfo?.name === message?.name}
|
||||||
@ -822,18 +802,20 @@ export const Thread = ({
|
|||||||
{message?.name}
|
{message?.name}
|
||||||
</ThreadInfoColumnNameP>
|
</ThreadInfoColumnNameP>
|
||||||
</WrapperUserAction>
|
</WrapperUserAction>
|
||||||
|
|
||||||
<ThreadInfoColumnTime>
|
<ThreadInfoColumnTime>
|
||||||
{formatTimestampForum(message?.created)}
|
{formatTimestampForum(message?.created)}
|
||||||
</ThreadInfoColumnTime>
|
</ThreadInfoColumnTime>
|
||||||
</ThreadInfoColumn>
|
</ThreadInfoColumn>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -876,17 +858,17 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
|
flexDirection: 'column',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
flexDirection: 'column',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
|
display: 'flex',
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -908,6 +890,7 @@ export const Thread = ({
|
|||||||
{message?.name?.charAt(0)}
|
{message?.name?.charAt(0)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</WrapperUserAction>
|
</WrapperUserAction>
|
||||||
|
|
||||||
<ThreadInfoColumn>
|
<ThreadInfoColumn>
|
||||||
<WrapperUserAction
|
<WrapperUserAction
|
||||||
disabled={userInfo?.name === message?.name}
|
disabled={userInfo?.name === message?.name}
|
||||||
@ -918,18 +901,20 @@ export const Thread = ({
|
|||||||
{message?.name}
|
{message?.name}
|
||||||
</ThreadInfoColumnNameP>
|
</ThreadInfoColumnNameP>
|
||||||
</WrapperUserAction>
|
</WrapperUserAction>
|
||||||
|
|
||||||
<ThreadInfoColumnTime>
|
<ThreadInfoColumnTime>
|
||||||
{formatTimestampForum(message?.created)}
|
{formatTimestampForum(message?.created)}
|
||||||
</ThreadInfoColumnTime>
|
</ThreadInfoColumnTime>
|
||||||
</ThreadInfoColumn>
|
</ThreadInfoColumn>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CustomLoader />
|
<CustomLoader />
|
||||||
@ -952,9 +937,9 @@ export const Thread = ({
|
|||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@ -997,8 +982,6 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -1017,8 +1000,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -1037,8 +1018,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -1057,8 +1036,6 @@ export const Thread = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -37,7 +37,6 @@ import {
|
|||||||
clearAllQueues,
|
clearAllQueues,
|
||||||
getArbitraryEndpointReact,
|
getArbitraryEndpointReact,
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
isMobile,
|
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
} from '../../App';
|
} from '../../App';
|
||||||
@ -1096,12 +1095,8 @@ export const Group = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (findDirect) {
|
if (findDirect) {
|
||||||
if (!isMobile) {
|
setDesktopSideView('directs');
|
||||||
setDesktopSideView('directs');
|
setDesktopViewMode('home');
|
||||||
setDesktopViewMode('home');
|
|
||||||
} else {
|
|
||||||
setMobileViewModeKeepOpen('messaging');
|
|
||||||
}
|
|
||||||
setSelectedDirect(null);
|
setSelectedDirect(null);
|
||||||
|
|
||||||
setNewChat(false);
|
setNewChat(false);
|
||||||
@ -1136,11 +1131,7 @@ export const Group = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (findDirect) {
|
if (findDirect) {
|
||||||
if (!isMobile) {
|
setDesktopSideView('directs');
|
||||||
setDesktopSideView('directs');
|
|
||||||
} else {
|
|
||||||
setMobileViewModeKeepOpen('messaging');
|
|
||||||
}
|
|
||||||
setSelectedDirect(null);
|
setSelectedDirect(null);
|
||||||
|
|
||||||
setNewChat(false);
|
setNewChat(false);
|
||||||
@ -1162,11 +1153,7 @@ export const Group = ({
|
|||||||
getTimestampEnterChat();
|
getTimestampEnterChat();
|
||||||
}, 200);
|
}, 200);
|
||||||
} else {
|
} else {
|
||||||
if (!isMobile) {
|
setDesktopSideView('directs');
|
||||||
setDesktopSideView('directs');
|
|
||||||
} else {
|
|
||||||
setMobileViewModeKeepOpen('messaging');
|
|
||||||
}
|
|
||||||
setNewChat(true);
|
setNewChat(true);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
executeEvent('setDirectToValueNewChat', {
|
executeEvent('setDirectToValueNewChat', {
|
||||||
@ -1284,9 +1271,7 @@ export const Group = ({
|
|||||||
setupGroupWebsocketInterval.current = null;
|
setupGroupWebsocketInterval.current = null;
|
||||||
settimeoutForRefetchSecretKey.current = null;
|
settimeoutForRefetchSecretKey.current = null;
|
||||||
initiatedGetMembers.current = false;
|
initiatedGetMembers.current = false;
|
||||||
if (!isMobile) {
|
setDesktopViewMode('home');
|
||||||
setDesktopViewMode('home');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoutEventFunc = () => {
|
const logoutEventFunc = () => {
|
||||||
@ -1303,34 +1288,7 @@ export const Group = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const openAppsMode = () => {
|
const openAppsMode = () => {
|
||||||
if (isMobile) {
|
setDesktopViewMode('apps');
|
||||||
setMobileViewMode('apps');
|
|
||||||
}
|
|
||||||
if (!isMobile) {
|
|
||||||
setDesktopViewMode('apps');
|
|
||||||
}
|
|
||||||
if (isMobile) {
|
|
||||||
setIsOpenSideViewDirects(false);
|
|
||||||
setIsOpenSideViewGroups(false);
|
|
||||||
setGroupSection('default');
|
|
||||||
setSelectedGroup(null);
|
|
||||||
setNewChat(false);
|
|
||||||
setSelectedDirect(null);
|
|
||||||
setSecretKey(null);
|
|
||||||
setGroupOwner(null);
|
|
||||||
lastFetchedSecretKey.current = null;
|
|
||||||
initiatedGetMembers.current = false;
|
|
||||||
setSecretKeyPublishDate(null);
|
|
||||||
setAdmins([]);
|
|
||||||
setSecretKeyDetails(null);
|
|
||||||
setAdminsWithNames([]);
|
|
||||||
setMembers([]);
|
|
||||||
setMemberCountFromSecretKeyData(null);
|
|
||||||
setTriedToFetchSecretKey(false);
|
|
||||||
setFirstSecretKeyInCreation(false);
|
|
||||||
setIsOpenSideViewDirects(false);
|
|
||||||
setIsOpenSideViewGroups(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -1372,9 +1330,7 @@ export const Group = ({
|
|||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection('chat');
|
setGroupSection('chat');
|
||||||
if (!isMobile) {
|
setDesktopViewMode('chat');
|
||||||
setDesktopViewMode('chat');
|
|
||||||
}
|
|
||||||
|
|
||||||
window
|
window
|
||||||
.sendMessage('addTimestampEnterChat', {
|
.sendMessage('addTimestampEnterChat', {
|
||||||
@ -1430,9 +1386,7 @@ export const Group = ({
|
|||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection('announcement');
|
setGroupSection('announcement');
|
||||||
if (!isMobile) {
|
setDesktopViewMode('chat');
|
||||||
setDesktopViewMode('chat');
|
|
||||||
}
|
|
||||||
window
|
window
|
||||||
.sendMessage('addGroupNotificationTimestamp', {
|
.sendMessage('addGroupNotificationTimestamp', {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
@ -1496,9 +1450,7 @@ export const Group = ({
|
|||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection('forum');
|
setGroupSection('forum');
|
||||||
setDefaultThread(data);
|
setDefaultThread(data);
|
||||||
if (!isMobile) {
|
setDesktopViewMode('chat');
|
||||||
setDesktopViewMode('chat');
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setSelectedGroup(findGroup);
|
setSelectedGroup(findGroup);
|
||||||
setMobileViewMode('group');
|
setMobileViewMode('group');
|
||||||
@ -1521,12 +1473,6 @@ export const Group = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const goToHome = async () => {
|
const goToHome = async () => {
|
||||||
if (isMobile) {
|
|
||||||
setMobileViewMode('home');
|
|
||||||
}
|
|
||||||
if (!isMobile) {
|
|
||||||
// TODO: empty block. Check it!
|
|
||||||
}
|
|
||||||
setDesktopViewMode('home');
|
setDesktopViewMode('home');
|
||||||
|
|
||||||
await new Promise((res) => {
|
await new Promise((res) => {
|
||||||
@ -1614,26 +1560,38 @@ export const Group = ({
|
|||||||
borderRadius: '0px 15px 15px 0px',
|
borderRadius: '0px 15px 15px 0px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? `calc(${rootHeight} - 45px)` : '100%',
|
height: '100%',
|
||||||
width: isMobile ? '100%' : '380px',
|
width: '380px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
<Box
|
||||||
<Box
|
sx={{
|
||||||
sx={{
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
display: 'flex',
|
||||||
display: 'flex',
|
gap: '10px',
|
||||||
gap: '10px',
|
justifyContent: 'center',
|
||||||
justifyContent: 'center',
|
width: '100%',
|
||||||
width: '100%',
|
}}
|
||||||
|
>
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
setDesktopSideView('groups');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ButtonBase
|
<IconWrapper
|
||||||
onClick={() => {
|
color={
|
||||||
setDesktopSideView('groups');
|
groupChatHasUnread || groupsAnnHasUnread
|
||||||
}}
|
? 'var(--unread)'
|
||||||
|
: desktopSideView === 'groups'
|
||||||
|
? theme.palette.text.primary
|
||||||
|
: theme.palette.text.secondary
|
||||||
|
}
|
||||||
|
label="Groups"
|
||||||
|
selected={desktopSideView === 'groups'}
|
||||||
|
customWidth="75px"
|
||||||
>
|
>
|
||||||
<IconWrapper
|
<HubsIcon
|
||||||
|
height={24}
|
||||||
color={
|
color={
|
||||||
groupChatHasUnread || groupsAnnHasUnread
|
groupChatHasUnread || groupsAnnHasUnread
|
||||||
? 'var(--unread)'
|
? 'var(--unread)'
|
||||||
@ -1641,29 +1599,28 @@ export const Group = ({
|
|||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary
|
: theme.palette.text.secondary
|
||||||
}
|
}
|
||||||
label="Groups"
|
/>
|
||||||
selected={desktopSideView === 'groups'}
|
</IconWrapper>
|
||||||
customWidth="75px"
|
</ButtonBase>
|
||||||
>
|
<ButtonBase
|
||||||
<HubsIcon
|
onClick={() => {
|
||||||
height={24}
|
setDesktopSideView('directs');
|
||||||
color={
|
}}
|
||||||
groupChatHasUnread || groupsAnnHasUnread
|
>
|
||||||
? 'var(--unread)'
|
<IconWrapper
|
||||||
: desktopSideView === 'groups'
|
customWidth="75px"
|
||||||
? theme.palette.text.primary
|
color={
|
||||||
: theme.palette.text.secondary
|
directChatHasUnread
|
||||||
}
|
? 'var(--unread)'
|
||||||
/>
|
: desktopSideView === 'directs'
|
||||||
</IconWrapper>
|
? theme.palette.text.primary
|
||||||
</ButtonBase>
|
: theme.palette.text.secondary
|
||||||
<ButtonBase
|
}
|
||||||
onClick={() => {
|
label="Messaging"
|
||||||
setDesktopSideView('directs');
|
selected={desktopSideView === 'directs'}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IconWrapper
|
<MessagingIcon
|
||||||
customWidth="75px"
|
height={24}
|
||||||
color={
|
color={
|
||||||
directChatHasUnread
|
directChatHasUnread
|
||||||
? 'var(--unread)'
|
? 'var(--unread)'
|
||||||
@ -1671,23 +1628,10 @@ export const Group = ({
|
|||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary
|
: theme.palette.text.secondary
|
||||||
}
|
}
|
||||||
label="Messaging"
|
/>
|
||||||
selected={desktopSideView === 'directs'}
|
</IconWrapper>
|
||||||
>
|
</ButtonBase>
|
||||||
<MessagingIcon
|
</Box>
|
||||||
height={24}
|
|
||||||
color={
|
|
||||||
directChatHasUnread
|
|
||||||
? 'var(--unread)'
|
|
||||||
: desktopSideView === 'directs'
|
|
||||||
? theme.palette.text.primary
|
|
||||||
: theme.palette.text.secondary
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</IconWrapper>
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -1843,30 +1787,42 @@ export const Group = ({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
width: isMobile ? '100%' : '380px',
|
width: '380px',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
height: isMobile ? `calc(${rootHeight} - 45px)` : '100%',
|
height: '100%',
|
||||||
background: !isMobile && theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
borderRadius: !isMobile && '0px 15px 15px 0px',
|
borderRadius: '0px 15px 15px 0px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
<Box
|
||||||
<Box
|
sx={{
|
||||||
sx={{
|
width: '100%',
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
justifyContent: 'center',
|
||||||
justifyContent: 'center',
|
display: 'flex',
|
||||||
display: 'flex',
|
gap: '10px',
|
||||||
gap: '10px',
|
}}
|
||||||
|
>
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
setDesktopSideView('groups');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ButtonBase
|
<IconWrapper
|
||||||
onClick={() => {
|
color={
|
||||||
setDesktopSideView('groups');
|
groupChatHasUnread || groupsAnnHasUnread
|
||||||
}}
|
? 'var(--unread)'
|
||||||
|
: desktopSideView === 'groups'
|
||||||
|
? theme.palette.text.primary
|
||||||
|
: theme.palette.text.secondary
|
||||||
|
}
|
||||||
|
label="Groups"
|
||||||
|
selected={desktopSideView === 'groups'}
|
||||||
|
customWidth="75px"
|
||||||
>
|
>
|
||||||
<IconWrapper
|
<HubsIcon
|
||||||
|
height={24}
|
||||||
color={
|
color={
|
||||||
groupChatHasUnread || groupsAnnHasUnread
|
groupChatHasUnread || groupsAnnHasUnread
|
||||||
? 'var(--unread)'
|
? 'var(--unread)'
|
||||||
@ -1874,29 +1830,28 @@ export const Group = ({
|
|||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary
|
: theme.palette.text.secondary
|
||||||
}
|
}
|
||||||
label="Groups"
|
/>
|
||||||
selected={desktopSideView === 'groups'}
|
</IconWrapper>
|
||||||
customWidth="75px"
|
</ButtonBase>
|
||||||
>
|
<ButtonBase
|
||||||
<HubsIcon
|
onClick={() => {
|
||||||
height={24}
|
setDesktopSideView('directs');
|
||||||
color={
|
}}
|
||||||
groupChatHasUnread || groupsAnnHasUnread
|
>
|
||||||
? 'var(--unread)'
|
<IconWrapper
|
||||||
: desktopSideView === 'groups'
|
customWidth="75px"
|
||||||
? theme.palette.text.primary
|
color={
|
||||||
: theme.palette.text.secondary
|
directChatHasUnread
|
||||||
}
|
? 'var(--unread)'
|
||||||
/>
|
: desktopSideView === 'directs'
|
||||||
</IconWrapper>
|
? theme.palette.text.primary
|
||||||
</ButtonBase>
|
: theme.palette.text.secondary
|
||||||
<ButtonBase
|
}
|
||||||
onClick={() => {
|
label="Messaging"
|
||||||
setDesktopSideView('directs');
|
selected={desktopSideView === 'directs'}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IconWrapper
|
<MessagingIcon
|
||||||
customWidth="75px"
|
height={24}
|
||||||
color={
|
color={
|
||||||
directChatHasUnread
|
directChatHasUnread
|
||||||
? 'var(--unread)'
|
? 'var(--unread)'
|
||||||
@ -1904,23 +1859,10 @@ export const Group = ({
|
|||||||
? theme.palette.text.primary
|
? theme.palette.text.primary
|
||||||
: theme.palette.text.secondary
|
: theme.palette.text.secondary
|
||||||
}
|
}
|
||||||
label="Messaging"
|
/>
|
||||||
selected={desktopSideView === 'directs'}
|
</IconWrapper>
|
||||||
>
|
</ButtonBase>
|
||||||
<MessagingIcon
|
</Box>
|
||||||
height={24}
|
|
||||||
color={
|
|
||||||
directChatHasUnread
|
|
||||||
? 'var(--unread)'
|
|
||||||
: desktopSideView === 'directs'
|
|
||||||
? theme.palette.text.primary
|
|
||||||
: theme.palette.text.secondary
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</IconWrapper>
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -2181,38 +2123,35 @@ export const Group = ({
|
|||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
height: isMobile ? '100%' : '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile &&
|
{((desktopViewMode !== 'apps' && desktopViewMode !== 'dev') ||
|
||||||
((desktopViewMode !== 'apps' && desktopViewMode !== 'dev') ||
|
isOpenSideViewGroups) && (
|
||||||
isOpenSideViewGroups) && (
|
<DesktopSideBar
|
||||||
<DesktopSideBar
|
desktopViewMode={desktopViewMode}
|
||||||
desktopViewMode={desktopViewMode}
|
toggleSideViewGroups={toggleSideViewGroups}
|
||||||
toggleSideViewGroups={toggleSideViewGroups}
|
toggleSideViewDirects={toggleSideViewDirects}
|
||||||
toggleSideViewDirects={toggleSideViewDirects}
|
goToHome={goToHome}
|
||||||
goToHome={goToHome}
|
mode={appsMode}
|
||||||
mode={appsMode}
|
setMode={setAppsMode}
|
||||||
setMode={setAppsMode}
|
setDesktopSideView={setDesktopSideView}
|
||||||
setDesktopSideView={setDesktopSideView}
|
hasUnreadDirects={directChatHasUnread}
|
||||||
hasUnreadDirects={directChatHasUnread}
|
isApps={desktopViewMode === 'apps'}
|
||||||
isApps={desktopViewMode === 'apps'}
|
myName={userInfo?.name}
|
||||||
myName={userInfo?.name}
|
isGroups={isOpenSideViewGroups}
|
||||||
isGroups={isOpenSideViewGroups}
|
isDirects={isOpenSideViewDirects}
|
||||||
isDirects={isOpenSideViewDirects}
|
hasUnreadGroups={groupChatHasUnread || groupsAnnHasUnread}
|
||||||
hasUnreadGroups={groupChatHasUnread || groupsAnnHasUnread}
|
setDesktopViewMode={setDesktopViewMode}
|
||||||
setDesktopViewMode={setDesktopViewMode}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{!isMobile &&
|
{desktopViewMode === 'chat' &&
|
||||||
desktopViewMode === 'chat' &&
|
|
||||||
desktopSideView !== 'directs' &&
|
desktopSideView !== 'directs' &&
|
||||||
renderGroups()}
|
renderGroups()}
|
||||||
|
|
||||||
{!isMobile &&
|
{desktopViewMode === 'chat' &&
|
||||||
desktopViewMode === 'chat' &&
|
|
||||||
desktopSideView === 'directs' &&
|
desktopSideView === 'directs' &&
|
||||||
renderDirects()}
|
renderDirects()}
|
||||||
|
|
||||||
@ -2231,66 +2170,10 @@ export const Group = ({
|
|||||||
|
|
||||||
{newChat && (
|
{newChat && (
|
||||||
<>
|
<>
|
||||||
{isMobile && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
height: '15px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginTop: '14px',
|
|
||||||
width: '100%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
width: '320px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
width: '50px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ButtonBase
|
|
||||||
onClick={() => {
|
|
||||||
close();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ReturnIcon />
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
width: '50px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ButtonBase
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedDirect(null);
|
|
||||||
setMobileViewModeKeepOpen('');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ExitIcon />
|
|
||||||
</ButtonBase>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
bottom: !(desktopViewMode === 'chat') ? 'unset' : '0px',
|
bottom: !(desktopViewMode === 'chat') ? 'unset' : '0px',
|
||||||
height: isMobile && `calc(${rootHeight} - 45px)`,
|
|
||||||
left: !(desktopViewMode === 'chat') ? '-100000px' : '0px',
|
left: !(desktopViewMode === 'chat') ? '-100000px' : '0px',
|
||||||
opacity: !(desktopViewMode === 'chat') ? 0 : 1,
|
opacity: !(desktopViewMode === 'chat') ? 0 : 1,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -2352,7 +2235,7 @@ export const Group = ({
|
|||||||
: '0px',
|
: '0px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
{
|
||||||
<DesktopHeader
|
<DesktopHeader
|
||||||
isPrivate={isPrivate}
|
isPrivate={isPrivate}
|
||||||
selectedGroup={selectedGroup}
|
selectedGroup={selectedGroup}
|
||||||
@ -2387,15 +2270,14 @@ export const Group = ({
|
|||||||
setGroupSection={setGroupSection}
|
setGroupSection={setGroupSection}
|
||||||
isForum={groupSection === 'forum'}
|
isForum={groupSection === 'forum'}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'relative',
|
|
||||||
flexGrow: 1,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
// reference to change height
|
flexGrow: 1,
|
||||||
height: isMobile ? 'calc(100% - 82px)' : 'calc(100vh - 70px)',
|
height: 'calc(100vh - 70px)',
|
||||||
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{triedToFetchSecretKey && (
|
{triedToFetchSecretKey && (
|
||||||
@ -2449,15 +2331,13 @@ export const Group = ({
|
|||||||
(!secretKeyPublishDate && !firstSecretKeyInCreation) ? (
|
(!secretKeyPublishDate && !firstSecretKeyInCreation) ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
height: isMobile
|
|
||||||
? `calc(${rootHeight} - 113px)`
|
|
||||||
: 'calc(100vh - 70px)',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
padding: '20px',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: 'calc(100vh - 70px)',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
|
padding: '20px',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{' '}
|
{' '}
|
||||||
@ -2605,7 +2485,6 @@ export const Group = ({
|
|||||||
sx={{
|
sx={{
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
bottom: !(desktopViewMode === 'chat') ? 'unset' : '0px',
|
bottom: !(desktopViewMode === 'chat') ? 'unset' : '0px',
|
||||||
height: isMobile && `calc(${rootHeight} - 45px)`,
|
|
||||||
left: !(desktopViewMode === 'chat') ? '-100000px' : '0px',
|
left: !(desktopViewMode === 'chat') ? '-100000px' : '0px',
|
||||||
opacity: !(desktopViewMode === 'chat') ? 0 : 1,
|
opacity: !(desktopViewMode === 'chat') ? 0 : 1,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -2642,7 +2521,7 @@ export const Group = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isMobile && (
|
{
|
||||||
<AppsDesktop
|
<AppsDesktop
|
||||||
toggleSideViewGroups={toggleSideViewGroups}
|
toggleSideViewGroups={toggleSideViewGroups}
|
||||||
toggleSideViewDirects={toggleSideViewDirects}
|
toggleSideViewDirects={toggleSideViewDirects}
|
||||||
@ -2660,8 +2539,8 @@ export const Group = ({
|
|||||||
isApps={desktopViewMode === 'apps'}
|
isApps={desktopViewMode === 'apps'}
|
||||||
desktopViewMode={desktopViewMode}
|
desktopViewMode={desktopViewMode}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
{!isMobile && (
|
{
|
||||||
<AppsDevMode
|
<AppsDevMode
|
||||||
toggleSideViewGroups={toggleSideViewGroups}
|
toggleSideViewGroups={toggleSideViewGroups}
|
||||||
toggleSideViewDirects={toggleSideViewDirects}
|
toggleSideViewDirects={toggleSideViewDirects}
|
||||||
@ -2679,9 +2558,9 @@ export const Group = ({
|
|||||||
desktopViewMode={desktopViewMode}
|
desktopViewMode={desktopViewMode}
|
||||||
isApps={desktopViewMode === 'apps'}
|
isApps={desktopViewMode === 'apps'}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
|
|
||||||
{!isMobile && (
|
{
|
||||||
<HomeDesktop
|
<HomeDesktop
|
||||||
name={userInfo?.name}
|
name={userInfo?.name}
|
||||||
refreshHomeDataFunc={refreshHomeDataFunc}
|
refreshHomeDataFunc={refreshHomeDataFunc}
|
||||||
@ -2699,7 +2578,7 @@ export const Group = ({
|
|||||||
setDesktopViewMode={setDesktopViewMode}
|
setDesktopViewMode={setDesktopViewMode}
|
||||||
desktopViewMode={desktopViewMode}
|
desktopViewMode={desktopViewMode}
|
||||||
/>
|
/>
|
||||||
)}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<AuthenticatedContainerInnerRight
|
<AuthenticatedContainerInnerRight
|
||||||
@ -2708,7 +2587,6 @@ export const Group = ({
|
|||||||
width: '31px',
|
width: '31px',
|
||||||
padding: '5px',
|
padding: '5px',
|
||||||
display:
|
display:
|
||||||
isMobile ||
|
|
||||||
desktopViewMode === 'apps' ||
|
desktopViewMode === 'apps' ||
|
||||||
desktopViewMode === 'dev' ||
|
desktopViewMode === 'dev' ||
|
||||||
desktopViewMode === 'chat'
|
desktopViewMode === 'chat'
|
||||||
|
@ -9,7 +9,7 @@ import { executeEvent } from '../../utils/events';
|
|||||||
import { Box, ButtonBase, Collapse, Typography, useTheme } from '@mui/material';
|
import { Box, ButtonBase, Collapse, Typography, useTheme } from '@mui/material';
|
||||||
import { getGroupNames } from './UserListOfInvites';
|
import { getGroupNames } from './UserListOfInvites';
|
||||||
import { CustomLoader } from '../../common/CustomLoader';
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
import { getBaseApiReact, isMobile } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
|||||||
borderRadius: '19px',
|
borderRadius: '19px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? '165px' : '250px',
|
height: '250px',
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
width: '322px',
|
width: '322px',
|
||||||
}}
|
}}
|
||||||
|
@ -1,244 +1,277 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import List from "@mui/material/List";
|
import List from '@mui/material/List';
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemButton from "@mui/material/ListItemButton";
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
||||||
import IconButton from "@mui/material/IconButton";
|
|
||||||
import CommentIcon from "@mui/icons-material/Comment";
|
|
||||||
import InfoIcon from "@mui/icons-material/Info";
|
|
||||||
import { RequestQueueWithPromise } from "../../utils/queue/queue";
|
|
||||||
import GroupAddIcon from '@mui/icons-material/GroupAdd';
|
import GroupAddIcon from '@mui/icons-material/GroupAdd';
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent } from '../../utils/events';
|
||||||
import { Box, ButtonBase, Collapse, Typography } from "@mui/material";
|
import { Box, ButtonBase, Collapse, Typography } from '@mui/material';
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
import { CustomLoader } from "../../common/CustomLoader";
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
import { getBaseApi } from "../../background";
|
import { myGroupsWhereIAmAdminAtom } from '../../atoms/global';
|
||||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { myGroupsWhereIAmAdminAtom } from "../../atoms/global";
|
|
||||||
import { useSetRecoilState } from "recoil";
|
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||||
export const requestQueueGroupJoinRequests = new RequestQueueWithPromise(2)
|
export const requestQueueGroupJoinRequests = new RequestQueueWithPromise(2);
|
||||||
|
|
||||||
export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, getTimestampEnterChat, setSelectedGroup, setGroupSection, setMobileViewMode, setDesktopViewMode }) => {
|
export const GroupJoinRequests = ({
|
||||||
const [isExpanded, setIsExpanded] = React.useState(false)
|
myAddress,
|
||||||
|
groups,
|
||||||
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState([])
|
setOpenManageMembers,
|
||||||
const [loading, setLoading] = React.useState(true)
|
getTimestampEnterChat,
|
||||||
const {txList, setTxList} = React.useContext(MyContext)
|
setSelectedGroup,
|
||||||
const setMyGroupsWhereIAmAdmin = useSetRecoilState(
|
setGroupSection,
|
||||||
myGroupsWhereIAmAdminAtom
|
setMobileViewMode,
|
||||||
|
setDesktopViewMode,
|
||||||
|
}) => {
|
||||||
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||||
|
|
||||||
|
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState(
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
const { txList, setTxList } = React.useContext(MyContext);
|
||||||
|
const setMyGroupsWhereIAmAdmin = useSetRecoilState(myGroupsWhereIAmAdminAtom);
|
||||||
|
|
||||||
|
const getJoinRequests = async () => {
|
||||||
const getJoinRequests = async ()=> {
|
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
|
|
||||||
let groupsAsAdmin = []
|
let groupsAsAdmin = [];
|
||||||
const getAllGroupsAsAdmin = groups.filter((item)=> item.groupId !== '0').map(async (group)=> {
|
const getAllGroupsAsAdmin = groups
|
||||||
|
.filter((item) => item.groupId !== '0')
|
||||||
const isAdminResponse = await requestQueueGroupJoinRequests.enqueue(()=> {
|
.map(async (group) => {
|
||||||
return fetch(
|
const isAdminResponse = await requestQueueGroupJoinRequests.enqueue(
|
||||||
`${getBaseApiReact()}/groups/members/${group.groupId}?limit=0&onlyAdmins=true`
|
() => {
|
||||||
|
return fetch(
|
||||||
|
`${getBaseApiReact()}/groups/members/${group.groupId}?limit=0&onlyAdmins=true`
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
})
|
const isAdminData = await isAdminResponse.json();
|
||||||
const isAdminData = await isAdminResponse.json()
|
|
||||||
|
|
||||||
|
|
||||||
const findMyself = isAdminData?.members?.find((member)=> member.member === myAddress)
|
const findMyself = isAdminData?.members?.find(
|
||||||
|
(member) => member.member === myAddress
|
||||||
if(findMyself){
|
);
|
||||||
groupsAsAdmin.push(group)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
|
if (findMyself) {
|
||||||
await Promise.all(getAllGroupsAsAdmin)
|
groupsAsAdmin.push(group);
|
||||||
setMyGroupsWhereIAmAdmin(groupsAsAdmin)
|
}
|
||||||
const res = await Promise.all(groupsAsAdmin.map(async (group)=> {
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
const joinRequestResponse = await requestQueueGroupJoinRequests.enqueue(()=> {
|
await Promise.all(getAllGroupsAsAdmin);
|
||||||
return fetch(
|
setMyGroupsWhereIAmAdmin(groupsAsAdmin);
|
||||||
`${getBaseApiReact()}/groups/joinrequests/${group.groupId}`
|
const res = await Promise.all(
|
||||||
);
|
groupsAsAdmin.map(async (group) => {
|
||||||
})
|
const joinRequestResponse =
|
||||||
|
await requestQueueGroupJoinRequests.enqueue(() => {
|
||||||
|
return fetch(
|
||||||
|
`${getBaseApiReact()}/groups/joinrequests/${group.groupId}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const joinRequestData = await joinRequestResponse.json()
|
const joinRequestData = await joinRequestResponse.json();
|
||||||
return {
|
return {
|
||||||
group,
|
group,
|
||||||
data: joinRequestData
|
data: joinRequestData,
|
||||||
}
|
};
|
||||||
}))
|
})
|
||||||
setGroupsWithJoinRequests(res)
|
);
|
||||||
|
setGroupsWithJoinRequests(res);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (myAddress && groups.length > 0) {
|
if (myAddress && groups.length > 0) {
|
||||||
getJoinRequests()
|
getJoinRequests();
|
||||||
} else {
|
} else {
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [myAddress, groups]);
|
}, [myAddress, groups]);
|
||||||
|
|
||||||
const filteredJoinRequests = React.useMemo(()=> {
|
const filteredJoinRequests = React.useMemo(() => {
|
||||||
return groupsWithJoinRequests.map((group)=> {
|
return groupsWithJoinRequests.map((group) => {
|
||||||
const filteredGroupRequests = group?.data?.filter((gd)=> {
|
const filteredGroupRequests = group?.data?.filter((gd) => {
|
||||||
const findJoinRequsetInTxList = txList?.find((tx)=> tx?.groupId === group?.group?.groupId && tx?.qortalAddress === gd?.joiner && tx?.type === 'join-request-accept')
|
const findJoinRequsetInTxList = txList?.find(
|
||||||
|
(tx) =>
|
||||||
|
tx?.groupId === group?.group?.groupId &&
|
||||||
|
tx?.qortalAddress === gd?.joiner &&
|
||||||
|
tx?.type === 'join-request-accept'
|
||||||
|
);
|
||||||
|
|
||||||
if(findJoinRequsetInTxList) return false
|
if (findJoinRequsetInTxList) return false;
|
||||||
return true
|
return true;
|
||||||
})
|
});
|
||||||
return {
|
return {
|
||||||
...group,
|
...group,
|
||||||
data: filteredGroupRequests
|
data: filteredGroupRequests,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
}, [groupsWithJoinRequests, txList])
|
}, [groupsWithJoinRequests, txList]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{
|
<Box
|
||||||
width: "100%",
|
sx={{
|
||||||
display: "flex",
|
width: '100%',
|
||||||
flexDirection: "column",
|
display: 'flex',
|
||||||
alignItems: 'center'
|
flexDirection: 'column',
|
||||||
}}>
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
sx={{
|
sx={{
|
||||||
width: "322px",
|
width: '322px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "row",
|
flexDirection: 'row',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
justifyContent: 'flex-start'
|
justifyContent: 'flex-start',
|
||||||
}}
|
}}
|
||||||
onClick={()=> setIsExpanded((prev)=> !prev)}
|
onClick={() => setIsExpanded((prev) => !prev)}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "1rem",
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Join Requests {filteredJoinRequests?.filter((group)=> group?.data?.length > 0)?.length > 0 && ` (${filteredJoinRequests?.filter((group)=> group?.data?.length > 0)?.length})`}
|
Join Requests{' '}
|
||||||
|
{filteredJoinRequests?.filter((group) => group?.data?.length > 0)
|
||||||
|
?.length > 0 &&
|
||||||
|
` (${filteredJoinRequests?.filter((group) => group?.data?.length > 0)?.length})`}
|
||||||
</Typography>
|
</Typography>
|
||||||
{isExpanded ? <ExpandLessIcon sx={{
|
{isExpanded ? (
|
||||||
marginLeft: 'auto'
|
<ExpandLessIcon
|
||||||
}} /> : (
|
sx={{
|
||||||
<ExpandMoreIcon sx={{
|
marginLeft: 'auto',
|
||||||
marginLeft: 'auto'
|
}}
|
||||||
}}/>
|
/>
|
||||||
)}
|
) : (
|
||||||
|
<ExpandMoreIcon
|
||||||
|
sx={{
|
||||||
|
marginLeft: 'auto',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<Collapse in={isExpanded} timeout="auto" unmountOnExit>
|
<Collapse in={isExpanded} timeout="auto" unmountOnExit>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
|
||||||
width: "322px",
|
|
||||||
height: isMobile ? "165px" : "250px",
|
|
||||||
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
bgcolor: "background.paper",
|
|
||||||
padding: "20px",
|
|
||||||
borderRadius: '19px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{loading && filteredJoinRequests.length === 0 && (
|
|
||||||
<Box sx={{
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}>
|
|
||||||
<CustomLoader />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{!loading && (filteredJoinRequests.length === 0 || filteredJoinRequests?.filter((group)=> group?.data?.length > 0).length === 0) && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: 'center',
|
|
||||||
height: '100%',
|
|
||||||
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
fontSize: "11px",
|
|
||||||
fontWeight: 400,
|
|
||||||
color: 'rgba(255, 255, 255, 0.2)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Nothing to display
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<List className="scrollable-container" sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper", maxHeight: '300px', overflow: 'auto' }}>
|
|
||||||
{filteredJoinRequests?.map((group)=> {
|
|
||||||
if(group?.data?.length === 0) return null
|
|
||||||
return (
|
|
||||||
<ListItem
|
|
||||||
key={group?.groupId}
|
|
||||||
onClick={()=> {
|
|
||||||
setSelectedGroup(group?.group)
|
|
||||||
setMobileViewMode('group')
|
|
||||||
getTimestampEnterChat()
|
|
||||||
setGroupSection("announcement")
|
|
||||||
setOpenManageMembers(true)
|
|
||||||
if(!isMobile){
|
|
||||||
setDesktopViewMode('chat')
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
executeEvent("openGroupJoinRequest", {});
|
|
||||||
|
|
||||||
}, 300);
|
|
||||||
}}
|
|
||||||
sx={{
|
sx={{
|
||||||
marginBottom: '20px'
|
width: '322px',
|
||||||
}}
|
height: '250px',
|
||||||
disablePadding
|
|
||||||
secondaryAction={
|
|
||||||
<IconButton edge="end" aria-label="comments">
|
|
||||||
<GroupAddIcon
|
|
||||||
sx={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: '18px'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ListItemButton sx={{
|
|
||||||
padding: "0px",
|
|
||||||
}} disableRipple role={undefined} dense>
|
|
||||||
|
|
||||||
<ListItemText sx={{
|
|
||||||
"& .MuiTypography-root": {
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: 400,
|
|
||||||
},
|
|
||||||
}} primary={`${group?.group?.groupName} has ${group?.data?.length} pending join requests.`} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
)
|
|
||||||
|
|
||||||
})}
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
padding: '20px',
|
||||||
</List>
|
borderRadius: '19px',
|
||||||
</Box>
|
}}
|
||||||
</Collapse>
|
>
|
||||||
|
{loading && filteredJoinRequests.length === 0 && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CustomLoader />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{!loading &&
|
||||||
|
(filteredJoinRequests.length === 0 ||
|
||||||
|
filteredJoinRequests?.filter((group) => group?.data?.length > 0)
|
||||||
|
.length === 0) && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: '11px',
|
||||||
|
fontWeight: 400,
|
||||||
|
color: 'rgba(255, 255, 255, 0.2)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Nothing to display
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<List
|
||||||
|
className="scrollable-container"
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 360,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
maxHeight: '300px',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{filteredJoinRequests?.map((group) => {
|
||||||
|
if (group?.data?.length === 0) return null;
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
key={group?.groupId}
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedGroup(group?.group);
|
||||||
|
setMobileViewMode('group');
|
||||||
|
getTimestampEnterChat();
|
||||||
|
setGroupSection('announcement');
|
||||||
|
setOpenManageMembers(true);
|
||||||
|
setDesktopViewMode('chat');
|
||||||
|
setTimeout(() => {
|
||||||
|
executeEvent('openGroupJoinRequest', {});
|
||||||
|
}, 300);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
marginBottom: '20px',
|
||||||
|
}}
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<IconButton edge="end" aria-label="comments">
|
||||||
|
<GroupAddIcon
|
||||||
|
sx={{
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '18px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton
|
||||||
|
sx={{
|
||||||
|
padding: '0px',
|
||||||
|
}}
|
||||||
|
disableRipple
|
||||||
|
role={undefined}
|
||||||
|
dense
|
||||||
|
>
|
||||||
|
<ListItemText
|
||||||
|
sx={{
|
||||||
|
'& .MuiTypography-root': {
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 400,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
primary={`${group?.group?.groupName} has ${group?.data?.length} pending join requests.`}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -16,19 +16,12 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
DialogContentText,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
ListItem,
|
|
||||||
ListItemAvatar,
|
|
||||||
ListItemButton,
|
|
||||||
ListItemText,
|
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Popover,
|
Popover,
|
||||||
Select,
|
Select,
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import { getNameInfo } from './Group';
|
|
||||||
import { getBaseApi, getFee } from '../../background';
|
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
||||||
@ -36,7 +29,6 @@ import {
|
|||||||
MyContext,
|
MyContext,
|
||||||
getArbitraryEndpointReact,
|
getArbitraryEndpointReact,
|
||||||
getBaseApiReact,
|
getBaseApiReact,
|
||||||
isMobile,
|
|
||||||
} from '../../App';
|
} from '../../App';
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { CustomLoader } from '../../common/CustomLoader';
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
@ -51,7 +43,6 @@ import { Label } from './AddGroup';
|
|||||||
import ShortUniqueId from 'short-unique-id';
|
import ShortUniqueId from 'short-unique-id';
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { getGroupNames } from './UserListOfInvites';
|
import { getGroupNames } from './UserListOfInvites';
|
||||||
import { WrapperUserAction } from '../WrapperUserAction';
|
|
||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import ErrorBoundary from '../../common/ErrorBoundary';
|
import ErrorBoundary from '../../common/ErrorBoundary';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
@ -390,6 +381,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: '330px',
|
width: '330px',
|
||||||
@ -401,7 +393,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: isMobile ? '320px' : '750px',
|
width: '750px',
|
||||||
maxWidth: '90%',
|
maxWidth: '90%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -422,6 +414,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
></Typography>
|
></Typography>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => setIsShowModal(true)}
|
onClick={() => setIsShowModal(true)}
|
||||||
@ -432,18 +425,19 @@ export const ListOfGroupPromotions = () => {
|
|||||||
Add Promotion
|
Add Promotion
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: isMobile ? '320px' : '750px',
|
bgcolor: 'background.paper',
|
||||||
maxWidth: '90%',
|
borderRadius: '19px',
|
||||||
maxHeight: '700px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
bgcolor: 'background.paper',
|
maxHeight: '700px',
|
||||||
|
maxWidth: '90%',
|
||||||
padding: '20px 0px',
|
padding: '20px 0px',
|
||||||
borderRadius: '19px',
|
width: '750px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{loading && promotions.length === 0 && (
|
{loading && promotions.length === 0 && (
|
||||||
@ -589,6 +583,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
>
|
>
|
||||||
Group name: {` ${promotion?.groupName}`}
|
Group name: {` ${promotion?.groupName}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
@ -598,6 +593,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
Number of members:{' '}
|
Number of members:{' '}
|
||||||
{` ${promotion?.memberCount}`}
|
{` ${promotion?.memberCount}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{promotion?.description && (
|
{promotion?.description && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
@ -608,6 +604,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
{promotion?.description}
|
{promotion?.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{promotion?.isOpen === false && (
|
{promotion?.isOpen === false && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
@ -620,7 +617,9 @@ export const ListOfGroupPromotions = () => {
|
|||||||
your request
|
your request
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -638,6 +637,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={isLoadingJoinGroup}
|
loading={isLoadingJoinGroup}
|
||||||
loadingPosition="start"
|
loadingPosition="start"
|
||||||
@ -682,6 +682,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
>
|
>
|
||||||
{promotion?.name?.charAt(0)}
|
{promotion?.name?.charAt(0)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontWight: 600,
|
fontWight: 600,
|
||||||
@ -692,6 +693,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
{promotion?.name}
|
{promotion?.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontWight: 600,
|
fontWight: 600,
|
||||||
@ -702,7 +704,9 @@ export const ListOfGroupPromotions = () => {
|
|||||||
{promotion?.groupName}
|
{promotion?.groupName}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -735,7 +739,9 @@ export const ListOfGroupPromotions = () => {
|
|||||||
: 'Private group'}
|
: 'Private group'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontWight: 600,
|
fontWight: 600,
|
||||||
@ -745,7 +751,9 @@ export const ListOfGroupPromotions = () => {
|
|||||||
>
|
>
|
||||||
{promotion?.data}
|
{promotion?.data}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -767,6 +775,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="50px" />
|
<Spacer height="50px" />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
@ -779,6 +788,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
{isShowModal && (
|
{isShowModal && (
|
||||||
|
@ -1,21 +1,14 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import List from "@mui/material/List";
|
import List from '@mui/material/List';
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemButton from "@mui/material/ListItemButton";
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import { executeEvent } from '../../utils/events';
|
||||||
import IconButton from "@mui/material/IconButton";
|
import { Box, Typography } from '@mui/material';
|
||||||
import CommentIcon from "@mui/icons-material/Comment";
|
import { Spacer } from '../../common/Spacer';
|
||||||
import InfoIcon from "@mui/icons-material/Info";
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
import GroupAddIcon from "@mui/icons-material/GroupAdd";
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
import { executeEvent } from "../../utils/events";
|
|
||||||
import { Box, Typography } from "@mui/material";
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
|
||||||
import { getGroupNames } from "./UserListOfInvites";
|
|
||||||
import { CustomLoader } from "../../common/CustomLoader";
|
|
||||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
|
||||||
import { isMobile } from "../../App";
|
|
||||||
|
|
||||||
export const ListOfThreadPostsWatched = () => {
|
export const ListOfThreadPostsWatched = () => {
|
||||||
const [posts, setPosts] = React.useState([]);
|
const [posts, setPosts] = React.useState([]);
|
||||||
@ -24,33 +17,33 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
const getPosts = async () => {
|
const getPosts = async () => {
|
||||||
try {
|
try {
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window.sendMessage("getThreadActivity", {})
|
window
|
||||||
.then((response) => {
|
.sendMessage('getThreadActivity', {})
|
||||||
if (!response?.error) {
|
.then((response) => {
|
||||||
if (!response) {
|
if (!response?.error) {
|
||||||
res(null);
|
if (!response) {
|
||||||
|
res(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uniquePosts = response.reduce((acc, current) => {
|
||||||
|
const x = acc.find(
|
||||||
|
(item) => item?.thread?.threadId === current?.thread?.threadId
|
||||||
|
);
|
||||||
|
if (!x) {
|
||||||
|
return acc.concat([current]);
|
||||||
|
} else {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
setPosts(uniquePosts);
|
||||||
|
res(uniquePosts);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const uniquePosts = response.reduce((acc, current) => {
|
rej(response.error);
|
||||||
const x = acc.find(
|
})
|
||||||
(item) => item?.thread?.threadId === current?.thread?.threadId
|
.catch((error) => {
|
||||||
);
|
rej(error.message || 'An error occurred');
|
||||||
if (!x) {
|
});
|
||||||
return acc.concat([current]);
|
|
||||||
} else {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
setPosts(uniquePosts);
|
|
||||||
res(uniquePosts);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rej(response.error);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
rej(error.message || "An error occurred");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
@ -63,49 +56,50 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{
|
<Box
|
||||||
width: "100%",
|
sx={{
|
||||||
display: "flex",
|
width: '100%',
|
||||||
flexDirection: "column",
|
display: 'flex',
|
||||||
alignItems: 'center'
|
flexDirection: 'column',
|
||||||
}}>
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "322px",
|
width: '322px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "13px",
|
fontSize: '13px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
New Thread Posts:
|
New Thread Posts:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "322px",
|
bgcolor: 'background.paper',
|
||||||
height: isMobile ? "165px" : "250px",
|
borderRadius: '19px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
bgcolor: "background.paper",
|
height: '250px',
|
||||||
padding: "20px",
|
padding: '20px',
|
||||||
borderRadius: '19px'
|
width: '322px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{loading && posts.length === 0 && (
|
{loading && posts.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CustomLoader />
|
<CustomLoader />
|
||||||
@ -114,19 +108,18 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
{!loading && posts.length === 0 && (
|
{!loading && posts.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "11px",
|
fontSize: '11px',
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
color: 'rgba(255, 255, 255, 0.2)'
|
color: 'rgba(255, 255, 255, 0.2)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Nothing to display
|
Nothing to display
|
||||||
@ -134,47 +127,46 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{posts?.length > 0 && (
|
{posts?.length > 0 && (
|
||||||
<List
|
<List
|
||||||
className="scrollable-container"
|
className="scrollable-container"
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
maxWidth: 360,
|
maxWidth: 360,
|
||||||
bgcolor: "background.paper",
|
bgcolor: 'background.paper',
|
||||||
maxHeight: "300px",
|
maxHeight: '300px',
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{posts?.map((post) => {
|
{posts?.map((post) => {
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={post?.thread?.threadId}
|
key={post?.thread?.threadId}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent("openThreadNewPost", {
|
executeEvent('openThreadNewPost', {
|
||||||
data: post,
|
data: post,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
disablePadding
|
disablePadding
|
||||||
secondaryAction={
|
secondaryAction={
|
||||||
<IconButton edge="end" aria-label="comments">
|
<IconButton edge="end" aria-label="comments">
|
||||||
<VisibilityIcon
|
<VisibilityIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: "red",
|
color: 'red',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ListItemButton disableRipple role={undefined} dense>
|
<ListItemButton disableRipple role={undefined} dense>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={`New post in ${post?.thread?.threadData?.title}`}
|
primary={`New post in ${post?.thread?.threadData?.title}`}
|
||||||
/>
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import Dialog from '@mui/material/Dialog';
|
import Dialog from '@mui/material/Dialog';
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
|
||||||
import ListItemButton from '@mui/material/ListItemButton';
|
|
||||||
import List from '@mui/material/List';
|
|
||||||
import Divider from '@mui/material/Divider';
|
|
||||||
import AppBar from '@mui/material/AppBar';
|
import AppBar from '@mui/material/AppBar';
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
@ -19,7 +15,7 @@ import { ListOfBans } from './ListOfBans';
|
|||||||
import { ListOfJoinRequests } from './ListOfJoinRequests';
|
import { ListOfJoinRequests } from './ListOfJoinRequests';
|
||||||
import { Box, ButtonBase, Card, Tab, Tabs } from '@mui/material';
|
import { Box, ButtonBase, Card, Tab, Tabs } from '@mui/material';
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { MyContext, getBaseApiReact, isMobile } from '../../App';
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
import { getGroupMembers, getNames } from './Group';
|
import { getGroupMembers, getNames } from './Group';
|
||||||
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
@ -27,6 +23,7 @@ import { LoadingButton } from '@mui/lab';
|
|||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import InsertLinkIcon from '@mui/icons-material/InsertLink';
|
import InsertLinkIcon from '@mui/icons-material/InsertLink';
|
||||||
|
|
||||||
function a11yProps(index: number) {
|
function a11yProps(index: number) {
|
||||||
return {
|
return {
|
||||||
id: `simple-tab-${index}`,
|
id: `simple-tab-${index}`,
|
||||||
@ -193,9 +190,9 @@ export const ManageMembers = ({
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: '#27282c',
|
bgcolor: '#27282c',
|
||||||
|
color: 'white',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
color: 'white',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||||
@ -221,9 +218,10 @@ export const ManageMembers = ({
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem', // Adjust font size for mobile
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="Invite new member"
|
label="Invite new member"
|
||||||
{...a11yProps(1)}
|
{...a11yProps(1)}
|
||||||
@ -231,9 +229,10 @@ export const ManageMembers = ({
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem',
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="List of invites"
|
label="List of invites"
|
||||||
{...a11yProps(2)}
|
{...a11yProps(2)}
|
||||||
@ -241,9 +240,10 @@ export const ManageMembers = ({
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem',
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="List of bans"
|
label="List of bans"
|
||||||
{...a11yProps(3)}
|
{...a11yProps(3)}
|
||||||
@ -251,9 +251,10 @@ export const ManageMembers = ({
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem',
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label="Join requests"
|
label="Join requests"
|
||||||
{...a11yProps(4)}
|
{...a11yProps(4)}
|
||||||
@ -261,11 +262,12 @@ export const ManageMembers = ({
|
|||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
fontSize: isMobile ? '0.75rem' : '1rem',
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
@ -274,10 +276,13 @@ export const ManageMembers = ({
|
|||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography>GroupId: {groupInfo?.groupId}</Typography>
|
<Typography>GroupId: {groupInfo?.groupId}</Typography>
|
||||||
|
|
||||||
<Typography>GroupName: {groupInfo?.groupName}</Typography>
|
<Typography>GroupName: {groupInfo?.groupName}</Typography>
|
||||||
|
|
||||||
<Typography>
|
<Typography>
|
||||||
Number of members: {groupInfo?.memberCount}
|
Number of members: {groupInfo?.memberCount}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
sx={{
|
sx={{
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
@ -290,7 +295,9 @@ export const ManageMembers = ({
|
|||||||
<InsertLinkIcon /> <Typography>Join Group Link</Typography>
|
<InsertLinkIcon /> <Typography>Join Group Link</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
{selectedGroup?.groupId && !isOwner && (
|
{selectedGroup?.groupId && !isOwner && (
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
size="small"
|
size="small"
|
||||||
@ -317,7 +324,9 @@ export const ManageMembers = ({
|
|||||||
>
|
>
|
||||||
Load members with names
|
Load members with names
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
|
|
||||||
<ListOfMembers
|
<ListOfMembers
|
||||||
members={membersWithNames || []}
|
members={membersWithNames || []}
|
||||||
groupId={selectedGroup?.groupId}
|
groupId={selectedGroup?.groupId}
|
||||||
@ -397,12 +406,14 @@ export const ManageMembers = ({
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<CustomizedSnackbars
|
<CustomizedSnackbars
|
||||||
open={openSnack}
|
open={openSnack}
|
||||||
setOpen={setOpenSnack}
|
setOpen={setOpenSnack}
|
||||||
info={infoSnack}
|
info={infoSnack}
|
||||||
setInfo={setInfoSnack}
|
setInfo={setInfoSnack}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoadingMembers}
|
open={isLoadingMembers}
|
||||||
info={{
|
info={{
|
||||||
|
@ -6,7 +6,7 @@ import ListItemIcon from '@mui/material/ListItemIcon';
|
|||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Box, ButtonBase, Collapse, Typography, useTheme } from '@mui/material';
|
import { Box, ButtonBase, Collapse, Typography, useTheme } from '@mui/material';
|
||||||
import { getBaseApiReact, isMobile } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
import MailIcon from '@mui/icons-material/Mail';
|
import MailIcon from '@mui/icons-material/Mail';
|
||||||
import MailOutlineIcon from '@mui/icons-material/MailOutline';
|
import MailOutlineIcon from '@mui/icons-material/MailOutline';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
@ -180,7 +180,7 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
borderRadius: '19px',
|
borderRadius: '19px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: isMobile ? '165px' : '250px',
|
height: '250px',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
width: '322px',
|
width: '322px',
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import List from "@mui/material/List";
|
import List from '@mui/material/List';
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemButton from "@mui/material/ListItemButton";
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import { Box, Typography } from '@mui/material';
|
||||||
import IconButton from "@mui/material/IconButton";
|
import { Spacer } from '../../common/Spacer';
|
||||||
import CommentIcon from "@mui/icons-material/Comment";
|
import { QMailMessages } from './QMailMessages';
|
||||||
import InfoIcon from "@mui/icons-material/Info";
|
import { executeEvent } from '../../utils/events';
|
||||||
import { Box, Typography } from "@mui/material";
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
|
||||||
import { isMobile } from "../../App";
|
|
||||||
import { QMailMessages } from "./QMailMessages";
|
|
||||||
import { executeEvent } from "../../utils/events";
|
|
||||||
|
|
||||||
export const ThingsToDoInitial = ({ myAddress, name, hasGroups, balance, userInfo }) => {
|
export const ThingsToDoInitial = ({
|
||||||
|
myAddress,
|
||||||
|
name,
|
||||||
|
hasGroups,
|
||||||
|
balance,
|
||||||
|
userInfo,
|
||||||
|
}) => {
|
||||||
const [checked1, setChecked1] = React.useState(false);
|
const [checked1, setChecked1] = React.useState(false);
|
||||||
const [checked2, setChecked2] = React.useState(false);
|
const [checked2, setChecked2] = React.useState(false);
|
||||||
// const [checked3, setChecked3] = React.useState(false);
|
|
||||||
|
|
||||||
// React.useEffect(() => {
|
|
||||||
// if (hasGroups) setChecked3(true);
|
|
||||||
// }, [hasGroups]);
|
|
||||||
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (balance && +balance >= 6) {
|
if (balance && +balance >= 6) {
|
||||||
@ -30,111 +25,114 @@ export const ThingsToDoInitial = ({ myAddress, name, hasGroups, balance, userInf
|
|||||||
}
|
}
|
||||||
}, [balance]);
|
}, [balance]);
|
||||||
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (name) setChecked2(true);
|
if (name) setChecked2(true);
|
||||||
}, [name]);
|
}, [name]);
|
||||||
|
|
||||||
|
const isLoaded = React.useMemo(() => {
|
||||||
|
if (userInfo !== null) return true;
|
||||||
|
return false;
|
||||||
|
}, [userInfo]);
|
||||||
|
|
||||||
const isLoaded = React.useMemo(()=> {
|
const hasDoneNameAndBalanceAndIsLoaded = React.useMemo(() => {
|
||||||
if(userInfo !== null) return true
|
if (isLoaded && checked1 && checked2) return true;
|
||||||
return false
|
return false;
|
||||||
}, [ userInfo])
|
}, [checked1, isLoaded, checked2]);
|
||||||
|
|
||||||
const hasDoneNameAndBalanceAndIsLoaded = React.useMemo(()=> {
|
if (hasDoneNameAndBalanceAndIsLoaded) {
|
||||||
if(isLoaded && checked1 && checked2) return true
|
return (
|
||||||
return false
|
<QMailMessages
|
||||||
}, [checked1, isLoaded, checked2])
|
userAddress={userInfo?.address}
|
||||||
|
userName={userInfo?.name}
|
||||||
if(hasDoneNameAndBalanceAndIsLoaded){
|
/>
|
||||||
return (
|
);
|
||||||
<QMailMessages userAddress={userInfo?.address} userName={userInfo?.name} />
|
}
|
||||||
);
|
if (!isLoaded) return null;
|
||||||
}
|
|
||||||
if(!isLoaded) return null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "322px",
|
width: '322px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
padding: "0px 20px",
|
padding: '0px 20px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "1rem",
|
fontSize: '1rem',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isLoaded ? 'Loading...' : 'Getting Started' }
|
{!isLoaded ? 'Loading...' : 'Getting Started'}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "322px",
|
width: '322px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
bgcolor: "background.paper",
|
bgcolor: 'background.paper',
|
||||||
padding: "20px",
|
padding: '20px',
|
||||||
borderRadius: "19px",
|
borderRadius: '19px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoaded && (
|
{isLoaded && (
|
||||||
<List sx={{ width: "100%", maxWidth: 360 }}>
|
<List sx={{ width: '100%', maxWidth: 360 }}>
|
||||||
<ListItem
|
<ListItem
|
||||||
|
disablePadding
|
||||||
disablePadding
|
sx={{
|
||||||
sx={{
|
marginBottom: '20px',
|
||||||
marginBottom: '20px'
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ListItemButton
|
||||||
<ListItemButton
|
sx={{
|
||||||
sx={{
|
padding: '0px',
|
||||||
padding: "0px",
|
}}
|
||||||
}}
|
disableRipple
|
||||||
disableRipple
|
role={undefined}
|
||||||
role={undefined}
|
dense
|
||||||
dense
|
onClick={() => {
|
||||||
onClick={()=> {
|
executeEvent('openBuyQortInfo', {});
|
||||||
executeEvent("openBuyQortInfo", {})
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ListItemText
|
||||||
<ListItemText
|
sx={{
|
||||||
sx={{
|
'& .MuiTypography-root': {
|
||||||
"& .MuiTypography-root": {
|
fontSize: '1rem',
|
||||||
fontSize: "1rem",
|
fontWeight: 400,
|
||||||
fontWeight: 400,
|
},
|
||||||
},
|
}}
|
||||||
}}
|
primary={`Have at least 6 QORT in your wallet`}
|
||||||
primary={`Have at least 6 QORT in your wallet`}
|
/>
|
||||||
/>
|
<ListItemIcon
|
||||||
<ListItemIcon
|
sx={{
|
||||||
sx={{
|
justifyContent: 'flex-end',
|
||||||
justifyContent: "flex-end",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<Box
|
||||||
<Box
|
sx={{
|
||||||
sx={{
|
height: '18px',
|
||||||
height: "18px",
|
width: '18px',
|
||||||
width: "18px",
|
borderRadius: '50%',
|
||||||
borderRadius: "50%",
|
backgroundColor: checked1
|
||||||
backgroundColor: checked1 ? "rgba(9, 182, 232, 1)" : "transparent",
|
? 'rgba(9, 182, 232, 1)'
|
||||||
outline: "1px solid rgba(9, 182, 232, 1)",
|
: 'transparent',
|
||||||
}}
|
outline: '1px solid rgba(9, 182, 232, 1)',
|
||||||
/>
|
}}
|
||||||
{/* <Checkbox
|
/>
|
||||||
|
{/* <Checkbox
|
||||||
edge="start"
|
edge="start"
|
||||||
checked={checked1}
|
checked={checked1}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
@ -149,52 +147,64 @@ if(!isLoaded) return null
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/> */}
|
/> */}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem
|
<ListItem
|
||||||
sx={{
|
sx={{
|
||||||
marginBottom: '20px'
|
marginBottom: '20px',
|
||||||
}}
|
}}
|
||||||
// secondaryAction={
|
// secondaryAction={
|
||||||
// <IconButton edge="end" aria-label="comments">
|
// <IconButton edge="end" aria-label="comments">
|
||||||
// <InfoIcon
|
// <InfoIcon
|
||||||
// sx={{
|
// sx={{
|
||||||
// color: "white",
|
// color: "white",
|
||||||
// }}
|
// }}
|
||||||
// />
|
// />
|
||||||
// </IconButton>
|
// </IconButton>
|
||||||
// }
|
// }
|
||||||
disablePadding
|
disablePadding
|
||||||
>
|
>
|
||||||
<ListItemButton sx={{
|
<ListItemButton
|
||||||
padding: "0px",
|
sx={{
|
||||||
}} disableRipple role={undefined} dense>
|
padding: '0px',
|
||||||
|
}}
|
||||||
<ListItemText onClick={() => {
|
disableRipple
|
||||||
executeEvent('openRegisterName', {})
|
role={undefined}
|
||||||
}} sx={{
|
dense
|
||||||
"& .MuiTypography-root": {
|
>
|
||||||
fontSize: "1rem",
|
<ListItemText
|
||||||
fontWeight: 400,
|
onClick={() => {
|
||||||
},
|
executeEvent('openRegisterName', {});
|
||||||
}} primary={`Register a name`} />
|
}}
|
||||||
<ListItemIcon sx={{
|
sx={{
|
||||||
justifyContent: "flex-end",
|
'& .MuiTypography-root': {
|
||||||
}}>
|
fontSize: '1rem',
|
||||||
<Box
|
fontWeight: 400,
|
||||||
sx={{
|
},
|
||||||
height: "18px",
|
}}
|
||||||
width: "18px",
|
primary={`Register a name`}
|
||||||
borderRadius: "50%",
|
/>
|
||||||
backgroundColor: checked2 ? "rgba(9, 182, 232, 1)" : "transparent",
|
<ListItemIcon
|
||||||
outline: "1px solid rgba(9, 182, 232, 1)",
|
sx={{
|
||||||
}}
|
justifyContent: 'flex-end',
|
||||||
/>
|
}}
|
||||||
</ListItemIcon>
|
>
|
||||||
</ListItemButton>
|
<Box
|
||||||
</ListItem>
|
sx={{
|
||||||
{/* <ListItem
|
height: '18px',
|
||||||
|
width: '18px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: checked2
|
||||||
|
? 'rgba(9, 182, 232, 1)'
|
||||||
|
: 'transparent',
|
||||||
|
outline: '1px solid rgba(9, 182, 232, 1)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
{/* <ListItem
|
||||||
disablePadding
|
disablePadding
|
||||||
>
|
>
|
||||||
<ListItemButton sx={{
|
<ListItemButton sx={{
|
||||||
@ -222,9 +232,8 @@ if(!isLoaded) return null
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem> */}
|
</ListItem> */}
|
||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import Picker, { EmojiStyle, Theme } from 'emoji-picker-react';
|
import Picker, { EmojiStyle, Theme } from 'emoji-picker-react';
|
||||||
import './ReactionPicker.css';
|
import './ReactionPicker.css';
|
||||||
import { ButtonBase } from '@mui/material';
|
import { ButtonBase } from '@mui/material';
|
||||||
import { isMobile } from '../App';
|
|
||||||
|
|
||||||
export const ReactionPicker = ({ onReaction }) => {
|
export const ReactionPicker = ({ onReaction }) => {
|
||||||
const [showPicker, setShowPicker] = useState(false);
|
const [showPicker, setShowPicker] = useState(false);
|
||||||
@ -30,7 +29,7 @@ export const ReactionPicker = ({ onReaction }) => {
|
|||||||
} else {
|
} else {
|
||||||
// Get the button's position
|
// Get the button's position
|
||||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||||
const pickerWidth = isMobile ? 300 : 350; // Adjust based on picker width
|
const pickerWidth = 350;
|
||||||
|
|
||||||
// Calculate position to align the right edge of the picker with the button's right edge
|
// Calculate position to align the right edge of the picker with the button's right edge
|
||||||
setPickerPosition({
|
setPickerPosition({
|
||||||
@ -90,15 +89,15 @@ export const ReactionPicker = ({ onReaction }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Picker
|
<Picker
|
||||||
height={isMobile ? 350 : 450}
|
|
||||||
width={isMobile ? 300 : 350}
|
|
||||||
reactionsDefaultOpen={true}
|
|
||||||
onReactionClick={handleReaction}
|
|
||||||
onEmojiClick={handlePicker}
|
|
||||||
allowExpandReactions={true}
|
allowExpandReactions={true}
|
||||||
autoFocusSearch={false}
|
autoFocusSearch={false}
|
||||||
theme={Theme.DARK}
|
|
||||||
emojiStyle={EmojiStyle.NATIVE}
|
emojiStyle={EmojiStyle.NATIVE}
|
||||||
|
height="450"
|
||||||
|
onEmojiClick={handlePicker}
|
||||||
|
onReactionClick={handleReaction}
|
||||||
|
reactionsDefaultOpen={true}
|
||||||
|
theme={Theme.DARK}
|
||||||
|
width="350"
|
||||||
/>
|
/>
|
||||||
</div>,
|
</div>,
|
||||||
document.body
|
document.body
|
||||||
|
@ -12,7 +12,7 @@ import PendingIcon from '@mui/icons-material/Pending';
|
|||||||
import TaskAltIcon from '@mui/icons-material/TaskAlt';
|
import TaskAltIcon from '@mui/icons-material/TaskAlt';
|
||||||
import ExpandLess from '@mui/icons-material/ExpandLess';
|
import ExpandLess from '@mui/icons-material/ExpandLess';
|
||||||
import ExpandMore from '@mui/icons-material/ExpandMore';
|
import ExpandMore from '@mui/icons-material/ExpandMore';
|
||||||
import { MyContext, getBaseApiReact, isMobile } from '../../App';
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
import { executeEvent } from '../../utils/events';
|
import { executeEvent } from '../../utils/events';
|
||||||
|
|
||||||
export const TaskManager = ({ getUserInfo }) => {
|
export const TaskManager = ({ getUserInfo }) => {
|
||||||
@ -141,8 +141,7 @@ export const TaskManager = ({ getUserInfo }) => {
|
|||||||
});
|
});
|
||||||
}, [txList]);
|
}, [txList]);
|
||||||
|
|
||||||
if (isMobile || txList?.length === 0 || txList.every((item) => item?.done))
|
if (txList?.length === 0 || txList.every((item) => item?.done)) return null;
|
||||||
return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,72 +1,103 @@
|
|||||||
import React, { useContext, useState } from 'react'
|
import { useContext, useState } from 'react';
|
||||||
import { GlobalContext, MyContext } from '../../App';
|
import { GlobalContext } from '../../App';
|
||||||
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Tab, Tabs, Typography } from '@mui/material';
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
IconButton,
|
||||||
|
Tab,
|
||||||
|
Tabs,
|
||||||
|
useTheme,
|
||||||
|
} from '@mui/material';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import { VideoPlayer } from '../Embeds/VideoPlayer';
|
import { VideoPlayer } from '../Embeds/VideoPlayer';
|
||||||
|
|
||||||
export const Tutorials = () => {
|
export const Tutorials = () => {
|
||||||
const { openTutorialModal, setOpenTutorialModal } = useContext(GlobalContext);
|
const { openTutorialModal, setOpenTutorialModal } = useContext(GlobalContext);
|
||||||
const [multiNumber, setMultiNumber] = useState(0)
|
const [multiNumber, setMultiNumber] = useState(0);
|
||||||
const handleClose = ()=> {
|
const theme = useTheme();
|
||||||
setOpenTutorialModal(null)
|
|
||||||
setMultiNumber(0)
|
const handleClose = () => {
|
||||||
}
|
setOpenTutorialModal(null);
|
||||||
if(!openTutorialModal) return null
|
setMultiNumber(0);
|
||||||
if(openTutorialModal?.multi){
|
};
|
||||||
const selectedTutorial = openTutorialModal?.multi[multiNumber]
|
|
||||||
return (
|
if (!openTutorialModal) return null;
|
||||||
<Dialog
|
|
||||||
|
if (openTutorialModal?.multi) {
|
||||||
|
const selectedTutorial = openTutorialModal?.multi[multiNumber];
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
aria-labelledby="customized-dialog-title"
|
aria-labelledby="customized-dialog-title"
|
||||||
open={!!openTutorialModal}
|
open={!!openTutorialModal}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
maxWidth="xl"
|
maxWidth="xl"
|
||||||
>
|
>
|
||||||
<Tabs sx={{
|
<Tabs
|
||||||
"& .MuiTabs-indicator": {
|
sx={{
|
||||||
backgroundColor: "white",
|
'& .MuiTabs-indicator': {
|
||||||
},
|
backgroundColor: theme.palette.background.default,
|
||||||
}} value={multiNumber} onChange={(e, value)=> setMultiNumber(value)} aria-label="basic tabs example">
|
},
|
||||||
{openTutorialModal?.multi?.map((item, index)=> {
|
}}
|
||||||
return (
|
value={multiNumber}
|
||||||
<Tab sx={{
|
onChange={(e, value) => setMultiNumber(value)}
|
||||||
"&.Mui-selected": {
|
aria-label="basic tabs example"
|
||||||
color: "white",
|
>
|
||||||
},
|
{openTutorialModal?.multi?.map((item, index) => {
|
||||||
}} label={item?.title} value={index} />
|
return (
|
||||||
|
<Tab
|
||||||
)
|
sx={{
|
||||||
})}
|
'&.Mui-selected': {
|
||||||
</Tabs>
|
color: theme.palette.text.primary,
|
||||||
<DialogTitle sx={{ m: 0, p: 2 }} >
|
},
|
||||||
|
}}
|
||||||
|
label={item?.title}
|
||||||
|
value={index}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<DialogTitle sx={{ m: 0, p: 2 }}>
|
||||||
{selectedTutorial?.title} {` Tutorial`}
|
{selectedTutorial?.title} {` Tutorial`}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
sx={(theme) => ({
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 8,
|
top: 8,
|
||||||
color: theme.palette.grey[500],
|
color: theme.palette.text.primary,
|
||||||
})}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent dividers sx={{
|
|
||||||
height: '85vh'
|
|
||||||
}}>
|
|
||||||
|
|
||||||
<VideoPlayer node="https://ext-node.qortal.link" {...selectedTutorial?.resource || {}} />
|
<DialogContent
|
||||||
|
dividers
|
||||||
|
sx={{
|
||||||
|
height: '85vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VideoPlayer
|
||||||
|
node="https://ext-node.qortal.link"
|
||||||
|
{...(selectedTutorial?.resource || {})}
|
||||||
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button variant="contained" onClick={handleClose}>
|
<Button variant="contained" onClick={handleClose}>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog
|
<Dialog
|
||||||
@ -76,33 +107,41 @@ export const Tutorials = () => {
|
|||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
maxWidth="xl"
|
maxWidth="xl"
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ m: 0, p: 2 }} >
|
<DialogTitle sx={{ m: 0, p: 2 }}>
|
||||||
{openTutorialModal?.title} {` Tutorial`}
|
{openTutorialModal?.title} {` Tutorial`}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
sx={(theme) => ({
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 8,
|
top: 8,
|
||||||
color: theme.palette.grey[500],
|
color: theme.palette.text.primary,
|
||||||
})}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent dividers sx={{
|
|
||||||
height: '85vh'
|
|
||||||
}}>
|
|
||||||
|
|
||||||
<VideoPlayer node="https://ext-node.qortal.link" {...openTutorialModal?.resource || {}} />
|
<DialogContent
|
||||||
|
dividers
|
||||||
|
sx={{
|
||||||
|
height: '85vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VideoPlayer
|
||||||
|
node="https://ext-node.qortal.link"
|
||||||
|
{...(openTutorialModal?.resource || {})}
|
||||||
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button variant="contained" onClick={handleClose}>
|
<Button variant="contained" onClick={handleClose}>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,67 +1,85 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { isMobile } from './App';
|
|
||||||
|
|
||||||
export const useAppFullScreen = (setFullScreen) => {
|
export const useAppFullScreen = (setFullScreen) => {
|
||||||
const enterFullScreen = useCallback(() => {
|
const enterFullScreen = useCallback(() => {
|
||||||
const element = document.documentElement; // Target the entire HTML document
|
const element = document.documentElement; // Target the entire HTML document
|
||||||
if (element.requestFullscreen) {
|
if (element.requestFullscreen) {
|
||||||
element.requestFullscreen();
|
element.requestFullscreen();
|
||||||
} else if (element.mozRequestFullScreen) { // Firefox
|
} else if (element.mozRequestFullScreen) {
|
||||||
element.mozRequestFullScreen();
|
// Firefox
|
||||||
} else if (element.webkitRequestFullscreen) { // Chrome, Safari and Opera
|
element.mozRequestFullScreen();
|
||||||
element.webkitRequestFullscreen();
|
} else if (element.webkitRequestFullscreen) {
|
||||||
} else if (element.msRequestFullscreen) { // IE/Edge
|
// Chrome, Safari and Opera
|
||||||
element.msRequestFullscreen();
|
element.webkitRequestFullscreen();
|
||||||
}
|
} else if (element.msRequestFullscreen) {
|
||||||
}, []);
|
// IE/Edge
|
||||||
|
element.msRequestFullscreen();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const exitFullScreen = useCallback(() => {
|
const exitFullScreen = useCallback(() => {
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
document.exitFullscreen();
|
document.exitFullscreen();
|
||||||
} else if (document.mozFullScreenElement) {
|
} else if (document.mozFullScreenElement) {
|
||||||
document.mozCancelFullScreen();
|
document.mozCancelFullScreen();
|
||||||
} else if (document.webkitFullscreenElement) {
|
} else if (document.webkitFullscreenElement) {
|
||||||
document.webkitExitFullscreen();
|
document.webkitExitFullscreen();
|
||||||
} else if (document.msFullscreenElement) {
|
} else if (document.msFullscreenElement) {
|
||||||
document.msExitFullscreen();
|
document.msExitFullscreen();
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleFullScreen = useCallback(() => {
|
const toggleFullScreen = useCallback(() => {
|
||||||
if(!isMobile || isMobile) return
|
if (
|
||||||
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
|
document.fullscreenElement ||
|
||||||
exitFullScreen();
|
document.mozFullScreenElement ||
|
||||||
setFullScreen(false)
|
document.webkitFullscreenElement ||
|
||||||
} else {
|
document.msFullscreenElement
|
||||||
enterFullScreen();
|
) {
|
||||||
setFullScreen(true)
|
exitFullScreen();
|
||||||
}
|
setFullScreen(false);
|
||||||
}, [enterFullScreen, exitFullScreen]);
|
} else {
|
||||||
|
enterFullScreen();
|
||||||
|
setFullScreen(true);
|
||||||
|
}
|
||||||
|
}, [enterFullScreen, exitFullScreen]);
|
||||||
|
|
||||||
// Listen for changes to fullscreen state
|
// Listen for changes to fullscreen state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleFullScreenChange = () => {
|
const handleFullScreenChange = () => {
|
||||||
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
|
if (
|
||||||
|
document.fullscreenElement ||
|
||||||
} else {
|
document.mozFullScreenElement ||
|
||||||
setFullScreen(false);
|
document.webkitFullscreenElement ||
|
||||||
}
|
document.msFullscreenElement
|
||||||
};
|
) {
|
||||||
|
// TODO check empty block
|
||||||
|
} else {
|
||||||
|
setFullScreen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener('fullscreenchange', handleFullScreenChange);
|
document.addEventListener('fullscreenchange', handleFullScreenChange);
|
||||||
document.addEventListener('webkitfullscreenchange', handleFullScreenChange); // Safari
|
document.addEventListener('webkitfullscreenchange', handleFullScreenChange); // Safari
|
||||||
document.addEventListener('mozfullscreenchange', handleFullScreenChange); // Firefox
|
document.addEventListener('mozfullscreenchange', handleFullScreenChange); // Firefox
|
||||||
document.addEventListener('MSFullscreenChange', handleFullScreenChange); // IE/Edge
|
document.addEventListener('MSFullscreenChange', handleFullScreenChange); // IE/Edge
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('fullscreenchange', handleFullScreenChange);
|
document.removeEventListener('fullscreenchange', handleFullScreenChange);
|
||||||
document.removeEventListener('webkitfullscreenchange', handleFullScreenChange);
|
document.removeEventListener(
|
||||||
document.removeEventListener('mozfullscreenchange', handleFullScreenChange);
|
'webkitfullscreenchange',
|
||||||
document.removeEventListener('MSFullscreenChange', handleFullScreenChange);
|
handleFullScreenChange
|
||||||
};
|
);
|
||||||
}, []);
|
document.removeEventListener(
|
||||||
|
'mozfullscreenchange',
|
||||||
|
handleFullScreenChange
|
||||||
|
);
|
||||||
|
document.removeEventListener(
|
||||||
|
'MSFullscreenChange',
|
||||||
|
handleFullScreenChange
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return { enterFullScreen, exitFullScreen, toggleFullScreen };
|
return { enterFullScreen, exitFullScreen, toggleFullScreen };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user