mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-29 14:27:52 +00:00
Refactor sReturn icon and set theme styles
This commit is contained in:
parent
c5cfaf3722
commit
dcfa7b258e
2038
src/App.tsx
2038
src/App.tsx
File diff suppressed because it is too large
Load Diff
355
src/Wallets.tsx
355
src/Wallets.tsx
@ -1,48 +1,58 @@
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Box, Button, ButtonBase, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Input } from "@mui/material";
|
||||
import { CustomButton } from "./App-styles";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { Label } from "./components/Group/AddGroup";
|
||||
import { Spacer } from "./common/Spacer";
|
||||
import { getWallets, storeWallets, walletVersion } from "./background";
|
||||
import { useModal } from "./common/useModal";
|
||||
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
|
||||
import { decryptStoredWalletFromSeedPhrase } from "./utils/decryptWallet";
|
||||
import { crypto } from "./constants/decryptWallet";
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { PasswordField } from "./components";
|
||||
import { HtmlTooltip } from "./ExtStates/NotAuthenticated";
|
||||
import { GlobalContext } from "./App";
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import ListItemAvatar from '@mui/material/ListItemAvatar';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
IconButton,
|
||||
Input,
|
||||
} from '@mui/material';
|
||||
import { CustomButton } from './App-styles';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import { Label } from './components/Group/AddGroup';
|
||||
import { Spacer } from './common/Spacer';
|
||||
import { getWallets, storeWallets, walletVersion } from './background';
|
||||
import { useModal } from './common/useModal';
|
||||
import PhraseWallet from './utils/generateWallet/phrase-wallet';
|
||||
import { decryptStoredWalletFromSeedPhrase } from './utils/decryptWallet';
|
||||
import { crypto } from './constants/decryptWallet';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { PasswordField } from './components';
|
||||
import { HtmlTooltip } from './ExtStates/NotAuthenticated';
|
||||
import { GlobalContext } from './App';
|
||||
|
||||
const parsefilenameQortal = (filename) => {
|
||||
return filename.startsWith("qortal_backup_") ? filename.slice(14) : filename;
|
||||
}
|
||||
return filename.startsWith('qortal_backup_') ? filename.slice(14) : filename;
|
||||
};
|
||||
|
||||
export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
const [wallets, setWallets] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [seedValue, setSeedValue] = useState("");
|
||||
const [seedName, setSeedName] = useState("");
|
||||
const [seedError, setSeedError] = useState("");
|
||||
const [seedValue, setSeedValue] = useState('');
|
||||
const [seedName, setSeedName] = useState('');
|
||||
const [seedError, setSeedError] = useState('');
|
||||
const { hasSeenGettingStarted } = useContext(GlobalContext);
|
||||
|
||||
const [password, setPassword] = useState("");
|
||||
const [password, setPassword] = useState('');
|
||||
const [isOpenSeedModal, setIsOpenSeedModal] = useState(false);
|
||||
const [isLoadingEncryptSeed, setIsLoadingEncryptSeed] = useState(false);
|
||||
|
||||
const { isShow, onCancel, onOk, show, } = useModal();
|
||||
const { isShow, onCancel, onOk, show } = useModal();
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept: {
|
||||
"application/json": [".json"], // Only accept JSON files
|
||||
'application/json': ['.json'], // Only accept JSON files
|
||||
},
|
||||
onDrop: async (acceptedFiles) => {
|
||||
const files: any = acceptedFiles;
|
||||
@ -53,8 +63,8 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
const fileContents = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onabort = () => reject("File reading was aborted");
|
||||
reader.onerror = () => reject("File reading has failed");
|
||||
reader.onabort = () => reject('File reading was aborted');
|
||||
reader.onerror = () => reject('File reading has failed');
|
||||
reader.onload = () => {
|
||||
// Resolve the promise with the reader result when reading completes
|
||||
resolve(reader.result);
|
||||
@ -63,8 +73,8 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
// Read the file as text
|
||||
reader.readAsText(file);
|
||||
});
|
||||
if (typeof fileContents !== "string") continue;
|
||||
const parsedData = JSON.parse(fileContents)
|
||||
if (typeof fileContents !== 'string') continue;
|
||||
const parsedData = JSON.parse(fileContents);
|
||||
importedWallets.push({ ...parsedData, filename: file?.name });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@ -110,13 +120,13 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
|
||||
const handleSetSeedValue = async () => {
|
||||
try {
|
||||
setIsOpenSeedModal(true)
|
||||
setIsOpenSeedModal(true);
|
||||
const { seedValue, seedName, password } = await show({
|
||||
message: "",
|
||||
publishFee: "",
|
||||
message: '',
|
||||
publishFee: '',
|
||||
});
|
||||
setIsLoadingEncryptSeed(true)
|
||||
const res = await decryptStoredWalletFromSeedPhrase(seedValue)
|
||||
setIsLoadingEncryptSeed(true);
|
||||
const res = await decryptStoredWalletFromSeedPhrase(seedValue);
|
||||
const wallet2 = new PhraseWallet(res, walletVersion);
|
||||
const wallet = await wallet2.generateSaveWalletData(
|
||||
password,
|
||||
@ -124,57 +134,59 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
() => {}
|
||||
);
|
||||
if (wallet?.address0) {
|
||||
setWallets([...wallets, {
|
||||
setWallets([
|
||||
...wallets,
|
||||
{
|
||||
...wallet,
|
||||
name: seedName
|
||||
}]);
|
||||
setIsOpenSeedModal(false)
|
||||
setSeedValue('')
|
||||
setSeedName('')
|
||||
setPassword('')
|
||||
setSeedError('')
|
||||
name: seedName,
|
||||
},
|
||||
]);
|
||||
setIsOpenSeedModal(false);
|
||||
setSeedValue('');
|
||||
setSeedName('');
|
||||
setPassword('');
|
||||
setSeedError('');
|
||||
} else {
|
||||
setSeedError('Could not create account.')
|
||||
setSeedError('Could not create account.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
setSeedError(error?.message || 'Could not create account.')
|
||||
setSeedError(error?.message || 'Could not create account.');
|
||||
} finally {
|
||||
setIsLoadingEncryptSeed(false)
|
||||
}
|
||||
setIsLoadingEncryptSeed(false);
|
||||
}
|
||||
};
|
||||
|
||||
const selectedWalletFunc = (wallet) => {
|
||||
setRawWallet(wallet);
|
||||
setExtState("wallet-dropped");
|
||||
setExtState('wallet-dropped');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
getWallets().then((res)=> {
|
||||
|
||||
setIsLoading(true);
|
||||
getWallets()
|
||||
.then((res) => {
|
||||
if (res && Array.isArray(res)) {
|
||||
setWallets(res)
|
||||
setWallets(res);
|
||||
}
|
||||
setIsLoading(false)
|
||||
}).catch((error)=> {
|
||||
console.error(error)
|
||||
setIsLoading(false)
|
||||
setIsLoading(false);
|
||||
})
|
||||
}, [])
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && wallets && Array.isArray(wallets)) {
|
||||
storeWallets(wallets)
|
||||
storeWallets(wallets);
|
||||
}
|
||||
}, [wallets, isLoading])
|
||||
}, [wallets, isLoading]);
|
||||
|
||||
if(isLoading) return null
|
||||
if (isLoading) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(wallets?.length === 0 ||
|
||||
!wallets) ? (
|
||||
{wallets?.length === 0 || !wallets ? (
|
||||
<>
|
||||
<Typography>No accounts saved</Typography>
|
||||
<Spacer height="75px" />
|
||||
@ -198,13 +210,12 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
{wallets?.length > 0 && (
|
||||
<List
|
||||
sx={{
|
||||
width: "100%",
|
||||
maxWidth: "500px",
|
||||
maxHeight: "60vh",
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
backgroundColor: "rgb(30 30 32 / 70%)",
|
||||
|
||||
width: '100%',
|
||||
maxWidth: '500px',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden',
|
||||
backgroundColor: 'rgb(30 30 32 / 70%)',
|
||||
}}
|
||||
>
|
||||
{wallets?.map((wallet, idx) => {
|
||||
@ -226,46 +237,64 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
alignItems: 'center',
|
||||
position: wallets?.length === 0 ? 'relative' : 'fixed',
|
||||
bottom: wallets?.length === 0 ? 'unset' : '20px',
|
||||
right: wallets?.length === 0 ? 'unset' : '20px'
|
||||
right: wallets?.length === 0 ? 'unset' : '20px',
|
||||
}}
|
||||
>
|
||||
<HtmlTooltip
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography color="inherit" sx={{
|
||||
fontSize: '16px'
|
||||
}}>Already have a Qortal account? Enter your secret backup phrase here to access it. This phrase is one of the ways to recover your account.</Typography>
|
||||
<Typography
|
||||
color="inherit"
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
}}
|
||||
>
|
||||
Already have a Qortal account? Enter your secret backup phrase
|
||||
here to access it. This phrase is one of the ways to recover
|
||||
your account.
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<CustomButton onClick={handleSetSeedValue} sx={{
|
||||
padding: '10px'
|
||||
}} >
|
||||
|
||||
<CustomButton
|
||||
onClick={handleSetSeedValue}
|
||||
sx={{
|
||||
padding: '10px',
|
||||
}}
|
||||
>
|
||||
Add seed-phrase
|
||||
</CustomButton>
|
||||
</HtmlTooltip>
|
||||
|
||||
<HtmlTooltip
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography color="inherit" sx={{
|
||||
fontSize: '16px'
|
||||
}}>Use this option to connect additional Qortal wallets you've already made, in order to login with them afterwards. You will need access to your backup JSON file in order to do so.</Typography>
|
||||
<Typography
|
||||
color="inherit"
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
}}
|
||||
>
|
||||
Use this option to connect additional Qortal wallets you've
|
||||
already made, in order to login with them afterwards. You will
|
||||
need access to your backup JSON file in order to do so.
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<CustomButton sx={{
|
||||
padding: '10px'
|
||||
}} {...getRootProps()}>
|
||||
<CustomButton
|
||||
sx={{
|
||||
padding: '10px',
|
||||
}}
|
||||
{...getRootProps()}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
Add account
|
||||
</CustomButton>
|
||||
@ -285,12 +314,12 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
Type or paste in your seed-phrase
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Label>Name</Label>
|
||||
@ -299,7 +328,9 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
value={seedName}
|
||||
onChange={(e) => setSeedName(e.target.value)}
|
||||
/>
|
||||
|
||||
<Spacer height="7px" />
|
||||
|
||||
<Label>Seed-phrase</Label>
|
||||
<PasswordField
|
||||
placeholder="Seed-phrase"
|
||||
@ -308,9 +339,10 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
onChange={(e) => setSeedValue(e.target.value)}
|
||||
autoComplete="off"
|
||||
sx={{
|
||||
width: '100%'
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Spacer height="7px" />
|
||||
|
||||
<Label>Choose new password</Label>
|
||||
@ -320,21 +352,23 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="off"
|
||||
sx={{
|
||||
width: '100%'
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
|
||||
</Box>
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button disabled={isLoadingEncryptSeed} variant="contained" onClick={()=> {
|
||||
setIsOpenSeedModal(false)
|
||||
setSeedValue('')
|
||||
setSeedName('')
|
||||
setPassword('')
|
||||
setSeedError('')
|
||||
}}>
|
||||
<Button
|
||||
disabled={isLoadingEncryptSeed}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setIsOpenSeedModal(false);
|
||||
setSeedValue('');
|
||||
setSeedName('');
|
||||
setPassword('');
|
||||
setSeedError('');
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<LoadingButton
|
||||
@ -342,28 +376,30 @@ export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => {
|
||||
disabled={!seedValue || !seedName || !password}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
if(!seedValue || !seedName || !password) return
|
||||
if (!seedValue || !seedName || !password) return;
|
||||
onOk({ seedValue, seedName, password });
|
||||
}}
|
||||
autoFocus
|
||||
>
|
||||
Add
|
||||
</LoadingButton>
|
||||
<Typography sx={{
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
visibility: seedError ? 'visible' : 'hidden'
|
||||
}}>{seedError}</Typography>
|
||||
visibility: seedError ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
{seedError}
|
||||
</Typography>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
const [name, setName] = useState("");
|
||||
const [note, setNote] = useState("");
|
||||
const [name, setName] = useState('');
|
||||
const [note, setNote] = useState('');
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@ -382,52 +418,62 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
}}
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '10px'
|
||||
padding: '10px',
|
||||
}}
|
||||
|
||||
>
|
||||
<ListItem
|
||||
sx={{
|
||||
bgcolor: "background.paper",
|
||||
bgcolor: 'background.paper',
|
||||
flexGrow: 1,
|
||||
"&:hover": { backgroundColor: "secondary.main", transform: "scale(1.01)" },
|
||||
transition: "all 0.1s ease-in-out",
|
||||
'&:hover': {
|
||||
backgroundColor: 'secondary.main',
|
||||
transform: 'scale(1.01)',
|
||||
},
|
||||
transition: 'all 0.1s ease-in-out',
|
||||
}}
|
||||
|
||||
alignItems="flex-start"
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="" src="/static/images/avatar/1.jpg" />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
|
||||
primary={wallet?.name ? wallet.name : wallet?.filename ? parsefilenameQortal(wallet?.filename) : "No name"}
|
||||
primary={
|
||||
wallet?.name
|
||||
? wallet.name
|
||||
: wallet?.filename
|
||||
? parsefilenameQortal(wallet?.filename)
|
||||
: 'No name'
|
||||
}
|
||||
secondary={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
variant="body2"
|
||||
sx={{ color: "text.primary", display: "inline" }}
|
||||
sx={{ color: 'text.primary', display: 'inline' }}
|
||||
>
|
||||
{wallet?.address0}
|
||||
</Typography>
|
||||
{wallet?.note}
|
||||
<Typography sx={{
|
||||
<Typography
|
||||
sx={{
|
||||
textAlign: 'end',
|
||||
marginTop: '5px'
|
||||
}}>Login</Typography>
|
||||
marginTop: '5px',
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<IconButton
|
||||
sx={{
|
||||
alignSelf: 'flex-start'
|
||||
alignSelf: 'flex-start',
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@ -438,7 +484,7 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
>
|
||||
<EditIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
@ -446,7 +492,7 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
{isEdit && (
|
||||
<Box
|
||||
sx={{
|
||||
padding: "8px",
|
||||
padding: '8px',
|
||||
}}
|
||||
>
|
||||
<Label>Name</Label>
|
||||
@ -455,10 +501,12 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
sx={{
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Spacer height="10px" />
|
||||
|
||||
<Label>Note</Label>
|
||||
<Input
|
||||
placeholder="Note"
|
||||
@ -468,29 +516,35 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
maxLength: 100,
|
||||
}}
|
||||
sx={{
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Spacer height="10px" />
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
justifyContent: "flex-end",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
justifyContent: 'flex-end',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Button size="small" variant="contained" onClick={() => setIsEdit(false)}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
onClick={() => setIsEdit(false)}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: 'var(--danger)',
|
||||
"&:hover": {
|
||||
backgroundColor: "var(--danger)",
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--danger)',
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "var(--danger)",
|
||||
'&:focus': {
|
||||
backgroundColor: 'var(--danger)',
|
||||
},
|
||||
}}
|
||||
size="small"
|
||||
@ -501,12 +555,12 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: "#5EB049",
|
||||
"&:hover": {
|
||||
backgroundColor: "#5EB049",
|
||||
backgroundColor: '#5EB049',
|
||||
'&:hover': {
|
||||
backgroundColor: '#5EB049',
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "#5EB049",
|
||||
'&:focus': {
|
||||
backgroundColor: '#5EB049',
|
||||
},
|
||||
}}
|
||||
size="small"
|
||||
@ -525,9 +579,6 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
import { styled } from "@mui/system";
|
||||
import { SVGProps } from "./interfaces";
|
||||
import React from 'react';
|
||||
import { styled } from '@mui/system';
|
||||
import { SVGProps } from './interfaces';
|
||||
|
||||
// Create a styled container with hover effects
|
||||
const SvgContainer = styled("svg")({
|
||||
"& path": {
|
||||
fill: "rgba(41, 41, 43, 1)", // Default to red if no color prop
|
||||
const SvgContainer = styled('svg')({
|
||||
'& path': {
|
||||
fill: 'rgba(41, 41, 43, 1)', // Default to red if no color prop
|
||||
},
|
||||
});
|
||||
|
||||
@ -20,7 +20,7 @@ export const CreateThreadIcon: React.FC<SVGProps> = ({ color, opacity }) => {
|
||||
>
|
||||
<path
|
||||
d="M0 9.80209V9.0205C0.0460138 8.67679 0.080024 8.31425 0.144043 7.98466C0.469856 6.30568 1.25577 4.79934 2.38071 3.6977C4.13924 1.88262 6.22987 0.985679 8.52256 0.674927C9.9086 0.485649 11.3116 0.565177 12.6758 0.910345C14.5124 1.34351 16.1889 2.2075 17.6053 3.67886C18.7276 4.84183 19.5319 6.24257 19.858 7.98466C19.918 8.31189 19.952 8.64383 20 8.97577V9.80209C19.9827 9.8676 19.9693 9.93447 19.96 10.0022C19.8708 11.2186 19.5113 12.3861 18.9177 13.3875C17.961 15.0025 16.6297 16.2594 15.0825 17.0082C12.4657 18.3525 9.75693 18.5667 6.98209 17.8346C6.8589 17.8074 6.73157 17.8264 6.61799 17.8887C5.15955 18.7339 3.70511 19.5908 2.24867 20.4501C2.18866 20.4854 2.12464 20.5183 2.0146 20.5748L3.78714 16.3703C3.37301 16.0148 2.96889 15.7017 2.60078 15.3415C1.42243 14.1879 0.556167 12.7895 0.182055 11.0192C0.0980294 10.6213 0.060018 10.2094 0 9.80209ZM14.0042 10.5931C14.1362 10.5968 14.2676 10.5698 14.3907 10.5135C14.5138 10.4572 14.6262 10.3728 14.7214 10.2651C14.8167 10.1574 14.8928 10.0286 14.9455 9.8861C14.9982 9.7436 15.0264 9.59023 15.0285 9.43484V9.4113C15.0285 9.25517 15.0024 9.10058 14.9516 8.95634C14.9008 8.8121 14.8264 8.68104 14.7326 8.57064C14.6388 8.46025 14.5274 8.37268 14.4048 8.31293C14.2823 8.25319 14.1509 8.22243 14.0182 8.22243C13.8855 8.22243 13.7542 8.25319 13.6316 8.31293C13.509 8.37268 13.3976 8.46025 13.3038 8.57064C13.21 8.68104 13.1356 8.8121 13.0848 8.95634C13.034 9.10058 13.0079 9.25517 13.0079 9.4113C13.0074 9.56588 13.0327 9.71906 13.0825 9.86211C13.1323 10.0052 13.2055 10.1353 13.2981 10.245C13.3906 10.3547 13.5005 10.442 13.6217 10.5017C13.7429 10.5614 13.8728 10.5925 14.0042 10.5931ZM10.003 10.5931C10.203 10.5926 10.3983 10.5225 10.5644 10.3915C10.7306 10.2606 10.86 10.0746 10.9364 9.85719C11.0129 9.63976 11.0329 9.40056 10.9939 9.16977C10.9549 8.93898 10.8588 8.72694 10.7175 8.5604C10.5763 8.39385 10.3962 8.28026 10.2002 8.23396C10.0041 8.18765 9.80084 8.21071 9.61591 8.30022C9.43099 8.38973 9.27273 8.54168 9.1611 8.7369C9.04948 8.93212 8.98949 9.16187 8.9887 9.39717C8.98975 9.71356 9.09688 10.0167 9.28682 10.2406C9.47675 10.4646 9.73413 10.5912 10.003 10.5931ZM4.98349 9.3854C4.9836 9.61979 5.04316 9.8488 5.15456 10.0431C5.26595 10.2374 5.42411 10.3882 5.60876 10.476C5.79341 10.5639 5.99616 10.5849 6.19102 10.5364C6.38588 10.4878 6.56399 10.3719 6.70252 10.2035C6.84105 10.0351 6.93371 9.82183 6.96861 9.59108C7.00352 9.36032 6.97909 9.12255 6.89845 8.90823C6.8178 8.69392 6.68463 8.51281 6.51597 8.38811C6.34732 8.26342 6.15087 8.20081 5.95179 8.20831C5.69208 8.21809 5.44579 8.34641 5.26507 8.56611C5.08434 8.78581 4.98336 9.07963 4.98349 9.3854Z"
|
||||
fill="#29292B"
|
||||
fill={color}
|
||||
/>
|
||||
</SvgContainer>
|
||||
);
|
||||
|
27
src/assets/svgs/Return.tsx
Normal file
27
src/assets/svgs/Return.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { useTheme } from '@mui/material';
|
||||
import { SVGProps } from './interfaces';
|
||||
|
||||
export const Return: React.FC<SVGProps> = ({ color, opacity, ...children }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const setColor = color ? color : theme.palette.text.primary;
|
||||
|
||||
return (
|
||||
<svg
|
||||
{...children}
|
||||
width="20"
|
||||
height="16"
|
||||
viewBox="0 0 20 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2.645 5.81803H15C15.9471 5.81803 16.8557 6.20131 17.5257 6.88278C18.195 7.56497 18.5714 8.49007 18.5714 9.45445V10.909C18.5714 11.8734 18.195 12.7985 17.5257 13.4807C16.8557 14.1622 15.9471 14.5454 15 14.5454C12.0164 14.5454 8.57143 14.5454 8.57143 14.5454C8.17714 14.5454 7.85714 14.8713 7.85714 15.2727C7.85714 15.6742 8.17714 16 8.57143 16H15C16.3264 16 17.5979 15.464 18.5357 14.5091C19.4736 13.5541 20 12.2596 20 10.909C20 10.4268 20 9.93664 20 9.45445C20 8.10461 19.4736 6.80932 18.5357 5.8544C17.5979 4.9002 16.3264 4.36347 15 4.36347H2.645L6.17929 1.27906C6.47857 1.01797 6.51286 0.55832 6.25643 0.253588C6 -0.0511433 5.54857 -0.0860541 5.24929 0.175041L0.249285 4.53874C0.0914279 4.67692 0 4.87838 0 5.09075C0 5.30312 0.0914279 5.50458 0.249285 5.64276L5.24929 10.0065C5.54857 10.2676 6 10.2326 6.25643 9.92791C6.51286 9.62318 6.47857 9.16353 6.17929 8.90244L2.645 5.81803Z"
|
||||
fill={setColor}
|
||||
fill-opacity={opacity}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
@ -1,9 +1,10 @@
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useTheme } from '@mui/material';
|
||||
|
||||
// TODO: extend interface
|
||||
export const SaveIcon = ({ color }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const setColor = color ? color : theme.palette.text.primary
|
||||
const setColor = color ? color : theme.palette.text.primary;
|
||||
|
||||
return (
|
||||
<svg
|
||||
|
@ -6,14 +6,23 @@ import { SVGProps } from './interfaces';
|
||||
const SvgContainer = styled('svg')({
|
||||
'& path': {
|
||||
fill: 'rgba(41, 41, 43, 1)', // Default to red if no color prop
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const SendNewMessage: React.FC<SVGProps> = ({ color, opacity }) => {
|
||||
return (
|
||||
<SvgContainer width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M3.33271 10.2306C2.88006 10.001 2.89088 9.65814 3.3554 9.46527L16.3563 4.06742C16.8214 3.87427 17.0961 4.11004 16.9689 4.59692L14.1253 15.4847C13.9985 15.9703 13.5515 16.1438 13.1241 15.8705L10.0773 13.9219C9.8629 13.7848 9.56272 13.8345 9.40985 14.0292L8.41215 15.2997C8.10197 15.6946 7.71724 15.6311 7.5525 15.1567L6.67584 12.6326C6.51125 12.1587 6.01424 11.5902 5.55821 11.359L3.33271 10.2306Z" />
|
||||
<SvgContainer
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M3.33271 10.2306C2.88006 10.001 2.89088 9.65814 3.3554 9.46527L16.3563 4.06742C16.8214 3.87427 17.0961 4.11004 16.9689 4.59692L14.1253 15.4847C13.9985 15.9703 13.5515 16.1438 13.1241 15.8705L10.0773 13.9219C9.8629 13.7848 9.56272 13.8345 9.40985 14.0292L8.41215 15.2997C8.10197 15.6946 7.71724 15.6311 7.5525 15.1567L6.67584 12.6326C6.51125 12.1587 6.01424 11.5902 5.55821 11.359L3.33271 10.2306Z"
|
||||
/>
|
||||
</SvgContainer>
|
||||
|
||||
);
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
|
||||
|
||||
|
||||
import React from 'react';
|
||||
|
||||
|
||||
export const StarEmptyIcon = () => {
|
||||
return (
|
||||
<svg width="12" height="11" viewBox="0 0 12 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.2726 0.162533L7.89126 3.31595C7.9357 3.40243 8.02078 3.46234 8.11994 3.47588L11.7399 3.98173C11.8542 3.99736 11.9496 4.07446 11.9853 4.18022C12.0206 4.28598 11.9913 4.40215 11.9084 4.47977L9.28882 6.93449V6.93397C9.21729 7.00117 9.18478 7.09807 9.20157 7.19288L9.81988 10.6588C9.83939 10.7682 9.79278 10.8786 9.69903 10.9443C9.60529 11.0094 9.48119 11.0182 9.37931 10.9667L6.14144 9.32987C6.05311 9.28559 5.9469 9.28559 5.85856 9.32987L2.62069 10.9667C2.51881 11.0182 2.39472 11.0094 2.30096 10.9443C2.20722 10.8786 2.16062 10.7682 2.18012 10.6588L2.79842 7.19288C2.81522 7.09807 2.78271 7.00117 2.71118 6.93397L0.0916083 4.47978C0.0086971 4.40216 -0.0205644 4.28599 0.0146582 4.18023C0.0504232 4.07448 0.145798 3.99738 0.260135 3.98175L3.88006 3.47589C3.97923 3.46235 4.0643 3.40244 4.10874 3.31596L5.7274 0.162545C5.77888 0.0630431 5.88455 0 5.99997 0C6.11539 0 6.22113 0.0630238 6.2726 0.162533Z" fill="#727376"/>
|
||||
<svg
|
||||
width="12"
|
||||
height="11"
|
||||
viewBox="0 0 12 11"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.2726 0.162533L7.89126 3.31595C7.9357 3.40243 8.02078 3.46234 8.11994 3.47588L11.7399 3.98173C11.8542 3.99736 11.9496 4.07446 11.9853 4.18022C12.0206 4.28598 11.9913 4.40215 11.9084 4.47977L9.28882 6.93449V6.93397C9.21729 7.00117 9.18478 7.09807 9.20157 7.19288L9.81988 10.6588C9.83939 10.7682 9.79278 10.8786 9.69903 10.9443C9.60529 11.0094 9.48119 11.0182 9.37931 10.9667L6.14144 9.32987C6.05311 9.28559 5.9469 9.28559 5.85856 9.32987L2.62069 10.9667C2.51881 11.0182 2.39472 11.0094 2.30096 10.9443C2.20722 10.8786 2.16062 10.7682 2.18012 10.6588L2.79842 7.19288C2.81522 7.09807 2.78271 7.00117 2.71118 6.93397L0.0916083 4.47978C0.0086971 4.40216 -0.0205644 4.28599 0.0146582 4.18023C0.0504232 4.07448 0.145798 3.99738 0.260135 3.98175L3.88006 3.47589C3.97923 3.46235 4.0643 3.40244 4.10874 3.31596L5.7274 0.162545C5.77888 0.0630431 5.88455 0 5.99997 0C6.11539 0 6.22113 0.0630238 6.2726 0.162533Z"
|
||||
fill="#727376"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
|
||||
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,3 @@
|
||||
import React from "react";
|
||||
|
||||
export const StarFilledIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
|
@ -1,4 +1,11 @@
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
@ -16,49 +23,53 @@ import {
|
||||
PublishQAppCTAParent,
|
||||
PublishQAppCTARight,
|
||||
PublishQAppDotsBG,
|
||||
} from "./Apps-styles";
|
||||
import { Avatar, Box, ButtonBase, InputBase, styled } from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { MyContext, getBaseApiReact } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import IconSearch from "../../assets/svgs/Search.svg";
|
||||
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
||||
import qappDots from "../../assets/svgs/qappDots.svg";
|
||||
import ReturnSVG from '../../assets/svgs/Return.svg'
|
||||
} from './Apps-styles';
|
||||
import { Avatar, Box, ButtonBase, InputBase, styled } from '@mui/material';
|
||||
import { Add } from '@mui/icons-material';
|
||||
import { MyContext, getBaseApiReact } from '../../App';
|
||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||
import IconSearch from '../../assets/svgs/Search.svg';
|
||||
import IconClearInput from '../../assets/svgs/ClearInput.svg';
|
||||
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
|
||||
import qappDots from '../../assets/svgs/qappDots.svg';
|
||||
import ReturnSVG from '../../assets/svgs/Return.svg';
|
||||
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { AppInfoSnippet } from "./AppInfoSnippet";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
|
||||
import { Spacer } from '../../common/Spacer';
|
||||
import { AppInfoSnippet } from './AppInfoSnippet';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { executeEvent } from '../../utils/events';
|
||||
import {
|
||||
ComposeP,
|
||||
MailIconImg,
|
||||
ShowMessageReturnButton,
|
||||
} from '../Group/Forum/Mail-styles';
|
||||
const officialAppList = [
|
||||
"q-tube",
|
||||
"q-blog",
|
||||
"q-share",
|
||||
"q-support",
|
||||
"q-mail",
|
||||
"q-fund",
|
||||
"q-shop",
|
||||
"q-trade",
|
||||
"q-support",
|
||||
"q-manager",
|
||||
"q-wallets",
|
||||
"q-search"
|
||||
'q-tube',
|
||||
'q-blog',
|
||||
'q-share',
|
||||
'q-support',
|
||||
'q-mail',
|
||||
'q-fund',
|
||||
'q-shop',
|
||||
'q-trade',
|
||||
'q-support',
|
||||
'q-manager',
|
||||
'q-wallets',
|
||||
'q-search',
|
||||
];
|
||||
|
||||
const ScrollerStyled = styled('div')({
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
'::-webkit-scrollbar': {
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-msOverflowStyle": "none",
|
||||
'-msOverflowStyle': 'none',
|
||||
});
|
||||
|
||||
const StyledVirtuosoContainer = styled('div')({
|
||||
@ -68,32 +79,39 @@ const ScrollerStyled = styled('div')({
|
||||
flexDirection: 'column',
|
||||
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
'::-webkit-scrollbar': {
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-msOverflowStyle": "none",
|
||||
'-msOverflowStyle': 'none',
|
||||
});
|
||||
|
||||
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories={categories} }) => {
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
export const AppsLibrary = ({
|
||||
availableQapps,
|
||||
setMode,
|
||||
myName,
|
||||
hasPublishApp,
|
||||
isShow,
|
||||
categories = { categories },
|
||||
}) => {
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const virtuosoRef = useRef();
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
|
||||
const officialApps = useMemo(() => {
|
||||
return availableQapps.filter(
|
||||
(app) =>
|
||||
app.service === "APP" &&
|
||||
app.service === 'APP' &&
|
||||
officialAppList.includes(app?.name?.toLowerCase())
|
||||
);
|
||||
}, [availableQapps]);
|
||||
|
||||
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
|
||||
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
|
||||
|
||||
// Debounce logic
|
||||
useEffect(() => {
|
||||
@ -117,23 +135,28 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
}, [debouncedValue]);
|
||||
|
||||
const rowRenderer = (index) => {
|
||||
|
||||
let app = searchedList[index];
|
||||
return <AppInfoSnippet key={`${app?.service}-${app?.name}`} app={app} myName={myName} />;
|
||||
return (
|
||||
<AppInfoSnippet
|
||||
key={`${app?.service}-${app?.name}`}
|
||||
app={app}
|
||||
myName={myName}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<AppsLibraryContainer sx={{
|
||||
display: !isShow && 'none'
|
||||
}}>
|
||||
<AppsLibraryContainer
|
||||
sx={{
|
||||
display: !isShow && 'none',
|
||||
}}
|
||||
>
|
||||
<AppsWidthLimiter>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<AppsSearchContainer>
|
||||
@ -145,8 +168,8 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
sx={{ ml: 1, flex: 1 }}
|
||||
placeholder="Search for apps"
|
||||
inputProps={{
|
||||
"aria-label": "Search for apps",
|
||||
fontSize: "16px",
|
||||
'aria-label': 'Search for apps',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
}}
|
||||
/>
|
||||
@ -155,7 +178,7 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
{searchValue && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setSearchValue("");
|
||||
setSearchValue('');
|
||||
}}
|
||||
>
|
||||
<img src={IconClearInput} />
|
||||
@ -166,21 +189,25 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
</Box>
|
||||
</AppsWidthLimiter>
|
||||
<Spacer height="25px" />
|
||||
<ShowMessageReturnButton sx={{
|
||||
padding: '2px'
|
||||
}} onClick={() => {
|
||||
executeEvent("navigateBack", {});
|
||||
|
||||
}}>
|
||||
<ShowMessageReturnButton
|
||||
sx={{
|
||||
padding: '2px',
|
||||
}}
|
||||
onClick={() => {
|
||||
executeEvent('navigateBack', {});
|
||||
}}
|
||||
>
|
||||
<MailIconImg src={ReturnSVG} />
|
||||
<ComposeP>Return to Apps Dashboard</ComposeP>
|
||||
</ShowMessageReturnButton>
|
||||
<Spacer height="25px" />
|
||||
{searchedList?.length > 0 ? (
|
||||
<AppsWidthLimiter>
|
||||
<StyledVirtuosoContainer sx={{
|
||||
height: rootHeight
|
||||
}}>
|
||||
<StyledVirtuosoContainer
|
||||
sx={{
|
||||
height: rootHeight,
|
||||
}}
|
||||
>
|
||||
<Virtuoso
|
||||
ref={virtuosoRef}
|
||||
data={searchedList}
|
||||
@ -188,7 +215,7 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
atBottomThreshold={50}
|
||||
followOutput="smooth"
|
||||
components={{
|
||||
Scroller: ScrollerStyled // Use the styled scroller component
|
||||
Scroller: ScrollerStyled, // Use the styled scroller component
|
||||
}}
|
||||
/>
|
||||
</StyledVirtuosoContainer>
|
||||
@ -203,14 +230,14 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
return (
|
||||
<ButtonBase
|
||||
sx={{
|
||||
height: "80px",
|
||||
width: "60px",
|
||||
height: '80px',
|
||||
width: '60px',
|
||||
}}
|
||||
onClick={() => {
|
||||
// executeEvent("addTab", {
|
||||
// data: qapp
|
||||
// })
|
||||
executeEvent("selectedAppInfo", {
|
||||
executeEvent('selectedAppInfo', {
|
||||
data: qapp,
|
||||
});
|
||||
}}
|
||||
@ -218,13 +245,13 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
<AppCircleContainer>
|
||||
<AppCircle
|
||||
sx={{
|
||||
border: "none",
|
||||
border: 'none',
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: "31px",
|
||||
width: "31px",
|
||||
height: '31px',
|
||||
width: '31px',
|
||||
}}
|
||||
alt={qapp?.name}
|
||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||
@ -233,8 +260,8 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "31px",
|
||||
height: "auto",
|
||||
width: '31px',
|
||||
height: 'auto',
|
||||
}}
|
||||
src={LogoSelected}
|
||||
alt="center-icon"
|
||||
@ -250,21 +277,24 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
})}
|
||||
</AppsContainer>
|
||||
<Spacer height="30px" />
|
||||
<AppLibrarySubTitle>{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}</AppLibrarySubTitle>
|
||||
<AppLibrarySubTitle>
|
||||
{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}
|
||||
</AppLibrarySubTitle>
|
||||
<Spacer height="18px" />
|
||||
</AppsWidthLimiter>
|
||||
<PublishQAppCTAParent>
|
||||
<PublishQAppCTALeft>
|
||||
<PublishQAppDotsBG>
|
||||
|
||||
<img src={qappDots} />
|
||||
</PublishQAppDotsBG>
|
||||
<Spacer width="29px" />
|
||||
<img src={qappDevelopText} />
|
||||
</PublishQAppCTALeft>
|
||||
<PublishQAppCTARight onClick={()=> {
|
||||
setMode('publish')
|
||||
}}>
|
||||
<PublishQAppCTARight
|
||||
onClick={() => {
|
||||
setMode('publish');
|
||||
}}
|
||||
>
|
||||
<PublishQAppCTAButton>
|
||||
{hasPublishApp ? 'Update' : 'Publish'}
|
||||
</PublishQAppCTAButton>
|
||||
@ -272,50 +302,57 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
</PublishQAppCTARight>
|
||||
</PublishQAppCTAParent>
|
||||
<AppsWidthLimiter>
|
||||
|
||||
<Spacer height="18px" />
|
||||
<AppLibrarySubTitle>Categories</AppLibrarySubTitle>
|
||||
<Spacer height="18px" />
|
||||
<AppsWidthLimiter sx={{
|
||||
<AppsWidthLimiter
|
||||
sx={{
|
||||
flexDirection: 'row',
|
||||
overflowX: 'auto',
|
||||
width: '100%',
|
||||
gap: '5px',
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
'::-webkit-scrollbar': {
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-msOverflowStyle": "none",
|
||||
}}>
|
||||
'-msOverflowStyle': 'none',
|
||||
}}
|
||||
>
|
||||
{categories?.map((category) => {
|
||||
return (
|
||||
<ButtonBase key={category?.id} onClick={()=> {
|
||||
<ButtonBase
|
||||
key={category?.id}
|
||||
onClick={() => {
|
||||
executeEvent('selectedCategory', {
|
||||
data: category
|
||||
})
|
||||
}}>
|
||||
<Box sx={{
|
||||
data: category,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '110px',
|
||||
width: '110px',
|
||||
background: 'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
|
||||
background:
|
||||
'linear-gradient(163.47deg, #4BBCFE 27.55%, #1386C9 86.56%)',
|
||||
color: '#1D1D1E',
|
||||
fontWeight: 700,
|
||||
fontSize: '16px',
|
||||
flexShrink: 0,
|
||||
borderRadius: '11px'
|
||||
}}>
|
||||
borderRadius: '11px',
|
||||
}}
|
||||
>
|
||||
{category?.name}
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</AppsWidthLimiter>
|
||||
</AppsWidthLimiter>
|
||||
|
@ -5,7 +5,7 @@ import React, {
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
} from 'react';
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
@ -23,77 +23,87 @@ import {
|
||||
PublishQAppCTAParent,
|
||||
PublishQAppCTARight,
|
||||
PublishQAppDotsBG,
|
||||
} from "./Apps-styles";
|
||||
import { Avatar, Box, ButtonBase, InputBase, Typography, styled } from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { MyContext, getBaseApiReact } from "../../App";
|
||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||
import IconSearch from "../../assets/svgs/Search.svg";
|
||||
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
||||
import qappLibraryText from "../../assets/svgs/qappLibraryText.svg";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
} from './Apps-styles';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
ButtonBase,
|
||||
InputBase,
|
||||
Typography,
|
||||
styled,
|
||||
} from '@mui/material';
|
||||
import { Add } from '@mui/icons-material';
|
||||
import { MyContext, getBaseApiReact } from '../../App';
|
||||
import LogoSelected from '../../assets/svgs/LogoSelected.svg';
|
||||
import IconSearch from '../../assets/svgs/Search.svg';
|
||||
import IconClearInput from '../../assets/svgs/ClearInput.svg';
|
||||
import qappDevelopText from '../../assets/svgs/qappDevelopText.svg';
|
||||
import qappLibraryText from '../../assets/svgs/qappLibraryText.svg';
|
||||
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 { AppInfoSnippet } from "./AppInfoSnippet";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
import { Spacer } from '../../common/Spacer';
|
||||
import { AppInfoSnippet } from './AppInfoSnippet';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { executeEvent } from '../../utils/events';
|
||||
import {
|
||||
AppsDesktopLibraryBody,
|
||||
AppsDesktopLibraryHeader,
|
||||
} from "./AppsDesktop-styles";
|
||||
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
||||
import ReturnSVG from '../../assets/svgs/Return.svg'
|
||||
import { ComposeP, MailIconImg, ShowMessageReturnButton } from "../Group/Forum/Mail-styles";
|
||||
} from './AppsDesktop-styles';
|
||||
import ReturnSVG from '../../assets/svgs/Return.svg';
|
||||
import {
|
||||
ComposeP,
|
||||
MailIconImg,
|
||||
ShowMessageReturnButton,
|
||||
} from '../Group/Forum/Mail-styles';
|
||||
const officialAppList = [
|
||||
"q-tube",
|
||||
"q-blog",
|
||||
"q-share",
|
||||
"q-support",
|
||||
"q-mail",
|
||||
"q-fund",
|
||||
"q-shop",
|
||||
"q-trade",
|
||||
"q-support",
|
||||
"q-manager",
|
||||
"q-mintership",
|
||||
"q-wallets",
|
||||
"q-search"
|
||||
'q-tube',
|
||||
'q-blog',
|
||||
'q-share',
|
||||
'q-support',
|
||||
'q-mail',
|
||||
'q-fund',
|
||||
'q-shop',
|
||||
'q-trade',
|
||||
'q-support',
|
||||
'q-manager',
|
||||
'q-mintership',
|
||||
'q-wallets',
|
||||
'q-search',
|
||||
];
|
||||
|
||||
const ScrollerStyled = styled("div")({
|
||||
const ScrollerStyled = styled('div')({
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
'::-webkit-scrollbar': {
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-msOverflowStyle": "none",
|
||||
'-msOverflowStyle': 'none',
|
||||
});
|
||||
|
||||
const StyledVirtuosoContainer = styled("div")({
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
const StyledVirtuosoContainer = styled('div')({
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
|
||||
// Hide scrollbar for WebKit browsers (Chrome, Safari)
|
||||
"::-webkit-scrollbar": {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
'::-webkit-scrollbar': {
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
},
|
||||
|
||||
// Hide scrollbar for Firefox
|
||||
scrollbarWidth: "none",
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
// Hide scrollbar for IE and older Edge
|
||||
"-msOverflowStyle": "none",
|
||||
'-msOverflowStyle': 'none',
|
||||
});
|
||||
|
||||
export const AppsLibraryDesktop = ({
|
||||
@ -103,20 +113,20 @@ export const AppsLibraryDesktop = ({
|
||||
hasPublishApp,
|
||||
isShow,
|
||||
categories,
|
||||
getQapps
|
||||
getQapps,
|
||||
}) => {
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const virtuosoRef = useRef();
|
||||
|
||||
const officialApps = useMemo(() => {
|
||||
return availableQapps.filter(
|
||||
(app) =>
|
||||
app.service === "APP" &&
|
||||
app.service === 'APP' &&
|
||||
officialAppList.includes(app?.name?.toLowerCase())
|
||||
);
|
||||
}, [availableQapps]);
|
||||
|
||||
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
|
||||
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
|
||||
|
||||
// Debounce logic
|
||||
useEffect(() => {
|
||||
@ -125,7 +135,7 @@ export const AppsLibraryDesktop = ({
|
||||
}, 350);
|
||||
setTimeout(() => {
|
||||
virtuosoRef.current.scrollToIndex({
|
||||
index: 0
|
||||
index: 0,
|
||||
});
|
||||
}, 500);
|
||||
// Cleanup timeout if searchValue changes before the timeout completes
|
||||
@ -138,8 +148,13 @@ export const AppsLibraryDesktop = ({
|
||||
|
||||
const searchedList = useMemo(() => {
|
||||
if (!debouncedValue) return [];
|
||||
return availableQapps.filter((app) =>
|
||||
app.name.toLowerCase().includes(debouncedValue.toLowerCase()) || (app?.metadata?.title && app?.metadata?.title?.toLowerCase().includes(debouncedValue.toLowerCase()))
|
||||
return availableQapps.filter(
|
||||
(app) =>
|
||||
app.name.toLowerCase().includes(debouncedValue.toLowerCase()) ||
|
||||
(app?.metadata?.title &&
|
||||
app?.metadata?.title
|
||||
?.toLowerCase()
|
||||
.includes(debouncedValue.toLowerCase()))
|
||||
);
|
||||
}, [debouncedValue]);
|
||||
|
||||
@ -151,7 +166,7 @@ export const AppsLibraryDesktop = ({
|
||||
app={app}
|
||||
myName={myName}
|
||||
parentStyles={{
|
||||
padding: '0px 10px'
|
||||
padding: '0px 10px',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@ -160,37 +175,38 @@ export const AppsLibraryDesktop = ({
|
||||
return (
|
||||
<AppsLibraryContainer
|
||||
sx={{
|
||||
display: !isShow && "none",
|
||||
padding: "0px",
|
||||
height: "100vh",
|
||||
overflow: "hidden",
|
||||
paddingTop: '30px'
|
||||
display: !isShow && 'none',
|
||||
padding: '0px',
|
||||
height: '100vh',
|
||||
overflow: 'hidden',
|
||||
paddingTop: '30px',
|
||||
}}
|
||||
>
|
||||
|
||||
<AppsDesktopLibraryHeader
|
||||
sx={{
|
||||
maxWidth: "1500px",
|
||||
width: "90%",
|
||||
maxWidth: '1500px',
|
||||
width: '90%',
|
||||
}}
|
||||
>
|
||||
<AppsWidthLimiter>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<img src={qappLibraryText} />
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<AppsSearchContainer
|
||||
sx={{
|
||||
width: "412px",
|
||||
width: '412px',
|
||||
}}
|
||||
>
|
||||
<AppsSearchLeft>
|
||||
@ -201,8 +217,8 @@ export const AppsLibraryDesktop = ({
|
||||
sx={{ ml: 1, flex: 1 }}
|
||||
placeholder="Search for apps"
|
||||
inputProps={{
|
||||
"aria-label": "Search for apps",
|
||||
fontSize: "16px",
|
||||
'aria-label': 'Search for apps',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
}}
|
||||
/>
|
||||
@ -211,7 +227,7 @@ export const AppsLibraryDesktop = ({
|
||||
{searchValue && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setSearchValue("");
|
||||
setSearchValue('');
|
||||
}}
|
||||
>
|
||||
<img src={IconClearInput} />
|
||||
@ -221,46 +237,46 @@ export const AppsLibraryDesktop = ({
|
||||
</AppsSearchContainer>
|
||||
<ButtonBase
|
||||
onClick={(e) => {
|
||||
getQapps()
|
||||
getQapps();
|
||||
}}
|
||||
>
|
||||
<RefreshIcon
|
||||
|
||||
sx={{
|
||||
color: "rgba(250, 250, 250, 0.5)",
|
||||
color: 'rgba(250, 250, 250, 0.5)',
|
||||
width: '40px',
|
||||
height: 'auto'
|
||||
height: 'auto',
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
</AppsWidthLimiter>
|
||||
</AppsDesktopLibraryHeader>
|
||||
<AppsDesktopLibraryBody
|
||||
sx={{
|
||||
height: `calc(100vh - 36px)`,
|
||||
overflow: "auto",
|
||||
padding: "0px",
|
||||
alignItems: "center",
|
||||
overflow: 'auto',
|
||||
padding: '0px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<AppsDesktopLibraryBody
|
||||
sx={{
|
||||
height: `calc(100vh - 36px)`,
|
||||
flexGrow: "unset",
|
||||
maxWidth: "1500px",
|
||||
width: "90%",
|
||||
flexGrow: 'unset',
|
||||
maxWidth: '1500px',
|
||||
width: '90%',
|
||||
}}
|
||||
>
|
||||
|
||||
<Spacer height="70px" />
|
||||
<ShowMessageReturnButton sx={{
|
||||
padding: '2px'
|
||||
}} onClick={() => {
|
||||
executeEvent("navigateBack", {});
|
||||
}}>
|
||||
<ShowMessageReturnButton
|
||||
sx={{
|
||||
padding: '2px',
|
||||
}}
|
||||
onClick={() => {
|
||||
executeEvent('navigateBack', {});
|
||||
}}
|
||||
>
|
||||
<MailIconImg src={ReturnSVG} />
|
||||
<ComposeP>Return to Apps Dashboard</ComposeP>
|
||||
</ShowMessageReturnButton>
|
||||
@ -292,46 +308,48 @@ export const AppsLibraryDesktop = ({
|
||||
<>
|
||||
<AppLibrarySubTitle
|
||||
sx={{
|
||||
fontSize: "30px",
|
||||
fontSize: '30px',
|
||||
}}
|
||||
>
|
||||
Official Apps
|
||||
</AppLibrarySubTitle>
|
||||
<Spacer height="45px" />
|
||||
<AppsContainer sx={{
|
||||
<AppsContainer
|
||||
sx={{
|
||||
gap: '50px',
|
||||
justifyContent: 'flex-start'
|
||||
}}>
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{officialApps?.map((qapp) => {
|
||||
return (
|
||||
<ButtonBase
|
||||
sx={{
|
||||
// height: "80px",
|
||||
width: "80px",
|
||||
width: '80px',
|
||||
}}
|
||||
onClick={() => {
|
||||
// executeEvent("addTab", {
|
||||
// data: qapp
|
||||
// })
|
||||
executeEvent("selectedAppInfo", {
|
||||
executeEvent('selectedAppInfo', {
|
||||
data: qapp,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<AppCircleContainer
|
||||
sx={{
|
||||
gap: "10px",
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<AppCircle
|
||||
sx={{
|
||||
border: "none",
|
||||
border: 'none',
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: "42px",
|
||||
width: "42px",
|
||||
height: '42px',
|
||||
width: '42px',
|
||||
}}
|
||||
alt={qapp?.name}
|
||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||
@ -340,8 +358,8 @@ export const AppsLibraryDesktop = ({
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "31px",
|
||||
height: "auto",
|
||||
width: '31px',
|
||||
height: 'auto',
|
||||
}}
|
||||
src={LogoSelected}
|
||||
alt="center-icon"
|
||||
@ -359,30 +377,30 @@ export const AppsLibraryDesktop = ({
|
||||
<Spacer height="80px" />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
gap: "250px",
|
||||
display: "flex",
|
||||
width: '100%',
|
||||
gap: '250px',
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<AppLibrarySubTitle
|
||||
sx={{
|
||||
fontSize: "30px",
|
||||
width: "100%",
|
||||
textAlign: "start",
|
||||
fontSize: '30px',
|
||||
width: '100%',
|
||||
textAlign: 'start',
|
||||
}}
|
||||
>
|
||||
{hasPublishApp ? "Update Apps!" : "Create Apps!"}
|
||||
{hasPublishApp ? 'Update Apps!' : 'Create Apps!'}
|
||||
</AppLibrarySubTitle>
|
||||
<Spacer height="18px" />
|
||||
<PublishQAppCTAParent
|
||||
sx={{
|
||||
gap: "25px",
|
||||
gap: '25px',
|
||||
}}
|
||||
>
|
||||
<PublishQAppCTALeft>
|
||||
@ -394,11 +412,11 @@ export const AppsLibraryDesktop = ({
|
||||
</PublishQAppCTALeft>
|
||||
<PublishQAppCTARight
|
||||
onClick={() => {
|
||||
setMode("publish");
|
||||
setMode('publish');
|
||||
}}
|
||||
>
|
||||
<PublishQAppCTAButton>
|
||||
{hasPublishApp ? "Update" : "Publish"}
|
||||
{hasPublishApp ? 'Update' : 'Publish'}
|
||||
</PublishQAppCTAButton>
|
||||
<Spacer width="20px" />
|
||||
</PublishQAppCTARight>
|
||||
@ -406,13 +424,13 @@ export const AppsLibraryDesktop = ({
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<AppLibrarySubTitle
|
||||
sx={{
|
||||
fontSize: "30px",
|
||||
fontSize: '30px',
|
||||
}}
|
||||
>
|
||||
Categories
|
||||
@ -420,33 +438,32 @@ export const AppsLibraryDesktop = ({
|
||||
<Spacer height="18px" />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
flexWrap: "wrap",
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
|
||||
onClick={() => {
|
||||
executeEvent("selectedCategory", {
|
||||
executeEvent('selectedCategory', {
|
||||
data: {
|
||||
id: 'all',
|
||||
name: 'All'
|
||||
name: 'All',
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "60px",
|
||||
padding: "0px 24px",
|
||||
border: "4px solid #10242F",
|
||||
borderRadius: "6px",
|
||||
boxShadow: "2px 4px 0px 0px #000000",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '60px',
|
||||
padding: '0px 24px',
|
||||
border: '4px solid #10242F',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '2px 4px 0px 0px #000000',
|
||||
}}
|
||||
>
|
||||
All
|
||||
@ -457,21 +474,21 @@ export const AppsLibraryDesktop = ({
|
||||
<ButtonBase
|
||||
key={category?.id}
|
||||
onClick={() => {
|
||||
executeEvent("selectedCategory", {
|
||||
executeEvent('selectedCategory', {
|
||||
data: category,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "60px",
|
||||
padding: "0px 24px",
|
||||
border: "4px solid #10242F",
|
||||
borderRadius: "6px",
|
||||
boxShadow: "2px 4px 0px 0px #000000",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '60px',
|
||||
padding: '0px 24px',
|
||||
border: '4px solid #10242F',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '2px 4px 0px 0px #000000',
|
||||
}}
|
||||
>
|
||||
{category?.name}
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { ButtonBase, Typography, useTheme } from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import { HubsIcon } from "../../assets/Icons/HubsIcon";
|
||||
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
|
||||
import AppIcon from "../../assets/svgs/AppIcon.svg";
|
||||
import { ButtonBase, Typography, useTheme } from '@mui/material';
|
||||
import Box from '@mui/material/Box';
|
||||
import { HubsIcon } from '../../assets/Icons/HubsIcon';
|
||||
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
|
||||
import AppIcon from '../../assets/svgs/AppIcon.svg';
|
||||
|
||||
import { HomeIcon } from "../../assets/Icons/HomeIcon";
|
||||
import { Save } from "../Save/Save";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { enabledDevModeAtom } from "../../atoms/global";
|
||||
import { HomeIcon } from '../../assets/Icons/HomeIcon';
|
||||
import { Save } from '../Save/Save';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { enabledDevModeAtom } from '../../atoms/global';
|
||||
|
||||
export const IconWrapper = ({
|
||||
children,
|
||||
@ -22,25 +22,25 @@ export const IconWrapper = ({
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
flexDirection: "column",
|
||||
height: customWidth ? customWidth : disableWidth ? "auto" : "89px",
|
||||
width: customWidth ? customWidth : disableWidth ? "auto" : "89px",
|
||||
borderRadius: "50%",
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
flexDirection: 'column',
|
||||
height: customWidth ? customWidth : disableWidth ? 'auto' : '89px',
|
||||
width: customWidth ? customWidth : disableWidth ? 'auto' : '89px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: selected
|
||||
? theme.palette.background.default
|
||||
: "transparent",
|
||||
: 'transparent',
|
||||
color: color ? color : theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<Typography
|
||||
sx={{
|
||||
fontFamily: "Inter",
|
||||
fontSize: "12px",
|
||||
fontFamily: 'Inter',
|
||||
fontSize: '12px',
|
||||
fontWeight: 500,
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
@ -72,20 +72,20 @@ export const DesktopFooter = ({
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
width: '100%',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
height: "100px", // Footer height
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
height: '100px', // Footer height
|
||||
zIndex: 1,
|
||||
justifyContent: "center",
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
@ -94,15 +94,13 @@ export const DesktopFooter = ({
|
||||
}}
|
||||
>
|
||||
<IconWrapper label="Home" selected={isHome}>
|
||||
<HomeIcon
|
||||
height={30}
|
||||
/>
|
||||
<HomeIcon height={30} />
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode("apps");
|
||||
setDesktopViewMode('apps');
|
||||
setIsOpenSideViewDirects(false);
|
||||
setIsOpenSideViewGroups(false);
|
||||
}}
|
||||
@ -114,7 +112,7 @@ export const DesktopFooter = ({
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopSideView("groups");
|
||||
setDesktopSideView('groups');
|
||||
}}
|
||||
>
|
||||
<IconWrapper label="Groups" selected={isGroups}>
|
||||
@ -122,10 +120,10 @@ export const DesktopFooter = ({
|
||||
height={30}
|
||||
color={
|
||||
hasUnreadGroups
|
||||
? "var(--danger)"
|
||||
? 'var(--danger)'
|
||||
: isGroups
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
? 'white'
|
||||
: 'rgba(250, 250, 250, 0.5)'
|
||||
}
|
||||
/>
|
||||
</IconWrapper>
|
||||
@ -133,7 +131,7 @@ export const DesktopFooter = ({
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopSideView("directs");
|
||||
setDesktopSideView('directs');
|
||||
}}
|
||||
>
|
||||
<IconWrapper label="Messaging" selected={isDirects}>
|
||||
@ -141,10 +139,10 @@ export const DesktopFooter = ({
|
||||
height={30}
|
||||
color={
|
||||
hasUnreadDirects
|
||||
? "var(--danger)"
|
||||
? 'var(--danger)'
|
||||
: isDirects
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
? 'white'
|
||||
: 'rgba(250, 250, 250, 0.5)'
|
||||
}
|
||||
/>
|
||||
</IconWrapper>
|
||||
@ -154,7 +152,7 @@ export const DesktopFooter = ({
|
||||
{isEnabledDevMode && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode("dev");
|
||||
setDesktopViewMode('dev');
|
||||
setIsOpenSideViewDirects(false);
|
||||
setIsOpenSideViewGroups(false);
|
||||
}}
|
||||
|
@ -5,7 +5,7 @@ import React, {
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
} from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
@ -14,8 +14,8 @@ import {
|
||||
IconButton,
|
||||
Skeleton,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { ShowMessage } from "./ShowMessageWithoutModal";
|
||||
} from '@mui/material';
|
||||
import { ShowMessage } from './ShowMessageWithoutModal';
|
||||
import {
|
||||
ComposeP,
|
||||
GroupContainer,
|
||||
@ -28,34 +28,33 @@ import {
|
||||
ThreadInfoColumn,
|
||||
ThreadInfoColumnNameP,
|
||||
ThreadInfoColumnTime,
|
||||
} from "./Mail-styles";
|
||||
import { Spacer } from "../../../common/Spacer";
|
||||
import { threadIdentifier } from "./GroupMail";
|
||||
import LazyLoad from "../../../common/LazyLoad";
|
||||
import ReturnSVG from "../../../assets/svgs/Return.svg";
|
||||
import { NewThread } from "./NewThread";
|
||||
} from './Mail-styles';
|
||||
import { Spacer } from '../../../common/Spacer';
|
||||
import { threadIdentifier } from './GroupMail';
|
||||
import ReturnSVG from '../../../assets/svgs/Return.svg';
|
||||
import { NewThread } from './NewThread';
|
||||
import {
|
||||
decryptPublishes,
|
||||
getTempPublish,
|
||||
handleUnencryptedPublishes,
|
||||
} from "../../Chat/GroupAnnouncements";
|
||||
import { LoadingSnackbar } from "../../Snackbar/LoadingSnackbar";
|
||||
import { subscribeToEvent, unsubscribeFromEvent } from "../../../utils/events";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
} from '../../Chat/GroupAnnouncements';
|
||||
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
|
||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../../utils/events';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import {
|
||||
getArbitraryEndpointReact,
|
||||
getBaseApiReact,
|
||||
isMobile,
|
||||
} from "../../../App";
|
||||
} from '../../../App';
|
||||
import {
|
||||
ArrowDownward as ArrowDownwardIcon,
|
||||
ArrowUpward as ArrowUpwardIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group";
|
||||
import { RequestQueueWithPromise } from "../../../utils/queue/queue";
|
||||
import { CustomLoader } from "../../../common/CustomLoader";
|
||||
import { WrapperUserAction } from "../../WrapperUserAction";
|
||||
import { formatTimestampForum } from "../../../utils/time";
|
||||
} from '@mui/icons-material';
|
||||
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group';
|
||||
import { RequestQueueWithPromise } from '../../../utils/queue/queue';
|
||||
import { CustomLoader } from '../../../common/CustomLoader';
|
||||
import { WrapperUserAction } from '../../WrapperUserAction';
|
||||
import { formatTimestampForum } from '../../../utils/time';
|
||||
const requestQueueSaveToLocal = new RequestQueueWithPromise(1);
|
||||
const requestQueueDownloadPost = new RequestQueueWithPromise(3);
|
||||
interface ThreadProps {
|
||||
@ -65,14 +64,10 @@ interface ThreadProps {
|
||||
members: any;
|
||||
}
|
||||
|
||||
const getEncryptedResource = async ({
|
||||
name,
|
||||
identifier,
|
||||
secretKey,
|
||||
resource,
|
||||
groupId,
|
||||
dataPublishes,
|
||||
}, isPrivate) => {
|
||||
const getEncryptedResource = async (
|
||||
{ name, identifier, secretKey, resource, groupId, dataPublishes },
|
||||
isPrivate
|
||||
) => {
|
||||
let data = dataPublishes[`${name}-${identifier}`];
|
||||
if (
|
||||
!data ||
|
||||
@ -93,14 +88,17 @@ const getEncryptedResource = async ({
|
||||
}
|
||||
data = await res.text();
|
||||
|
||||
if (data?.error || typeof data !== "string") return;
|
||||
if (data?.error || typeof data !== 'string') return;
|
||||
await requestQueueSaveToLocal.enqueue(() => {
|
||||
return addDataPublishesFunc({ ...resource, data }, groupId, "thmsg");
|
||||
return addDataPublishesFunc({ ...resource, data }, groupId, 'thmsg');
|
||||
});
|
||||
} else {
|
||||
data = data.data;
|
||||
}
|
||||
const response = isPrivate === false ? handleUnencryptedPublishes([data]) : await decryptPublishes([{ data }], secretKey);
|
||||
const response =
|
||||
isPrivate === false
|
||||
? handleUnencryptedPublishes([data])
|
||||
: await decryptPublishes([{ data }], secretKey);
|
||||
|
||||
const messageData = response[0];
|
||||
return messageData.decryptedData;
|
||||
@ -115,7 +113,7 @@ export const Thread = ({
|
||||
secretKey,
|
||||
getSecretKey,
|
||||
updateThreadActivityCurrentThread,
|
||||
isPrivate
|
||||
isPrivate,
|
||||
}: ThreadProps) => {
|
||||
const [tempPublishedList, setTempPublishedList] = useState([]);
|
||||
const [messages, setMessages] = useState<any[]>([]);
|
||||
@ -129,7 +127,7 @@ export const Thread = ({
|
||||
|
||||
// Update: Use a new ref for the scrollable container
|
||||
const threadContainerRef = useRef(null);
|
||||
const threadBeginningRef = useRef(null)
|
||||
const threadBeginningRef = useRef(null);
|
||||
// New state variables
|
||||
const [showScrollButton, setShowScrollButton] = useState(false);
|
||||
const [isAtBottom, setIsAtBottom] = useState(false);
|
||||
@ -140,7 +138,7 @@ export const Thread = ({
|
||||
const dataPublishes = useRef({});
|
||||
|
||||
const getSavedData = useCallback(async (groupId) => {
|
||||
const res = await getDataPublishesFunc(groupId, "thmsg");
|
||||
const res = await getDataPublishesFunc(groupId, 'thmsg');
|
||||
dataPublishes.current = res || {};
|
||||
}, []);
|
||||
|
||||
@ -159,14 +157,17 @@ export const Thread = ({
|
||||
|
||||
const getIndividualMsg = async (message: any) => {
|
||||
try {
|
||||
const responseDataMessage = await getEncryptedResource({
|
||||
const responseDataMessage = await getEncryptedResource(
|
||||
{
|
||||
identifier: message.identifier,
|
||||
name: message.name,
|
||||
secretKey,
|
||||
resource: message,
|
||||
groupId: groupInfo?.groupId,
|
||||
dataPublishes: dataPublishes.current,
|
||||
}, isPrivate);
|
||||
},
|
||||
isPrivate
|
||||
);
|
||||
|
||||
if (responseDataMessage?.error) {
|
||||
const fullObject = {
|
||||
@ -201,7 +202,7 @@ export const Thread = ({
|
||||
try {
|
||||
let threadId = currentThread.threadId;
|
||||
|
||||
const keyTemp = "thread-post";
|
||||
const keyTemp = 'thread-post';
|
||||
const getTempAnnouncements = await getTempPublish();
|
||||
|
||||
if (getTempAnnouncements?.[keyTemp]) {
|
||||
@ -232,10 +233,10 @@ export const Thread = ({
|
||||
const identifier = `thmsg-${threadId}`;
|
||||
let url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=20&includemetadata=false&prefix=true`;
|
||||
if (!isReverse) {
|
||||
url = url + "&reverse=false";
|
||||
url = url + '&reverse=false';
|
||||
}
|
||||
if (isReverse) {
|
||||
url = url + "&reverse=true";
|
||||
url = url + '&reverse=true';
|
||||
}
|
||||
if (after) {
|
||||
url = url + `&after=${after}`;
|
||||
@ -245,9 +246,9 @@ export const Thread = ({
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
@ -263,14 +264,13 @@ export const Thread = ({
|
||||
setMessages(fullArrayMsg);
|
||||
if (before === null && after === null && isReverse) {
|
||||
setTimeout(() => {
|
||||
containerRef.current.scrollIntoView({ behavior: "smooth" });
|
||||
containerRef.current.scrollIntoView({ behavior: 'smooth' });
|
||||
}, 300);
|
||||
}
|
||||
if(after || before === null && after === null && !isReverse){
|
||||
if (after || (before === null && after === null && !isReverse)) {
|
||||
setTimeout(() => {
|
||||
threadBeginningRef.current.scrollIntoView();
|
||||
}, 100);
|
||||
|
||||
}
|
||||
|
||||
if (fullArrayMsg.length === 0) {
|
||||
@ -282,9 +282,9 @@ export const Thread = ({
|
||||
fullArrayMsg[0].created
|
||||
}`;
|
||||
const responseNewer = await fetch(urlNewer, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataNewer = await responseNewer.json();
|
||||
@ -300,9 +300,9 @@ export const Thread = ({
|
||||
fullArrayMsg[fullArrayMsg.length - 1].created
|
||||
}`;
|
||||
const responseOlder = await fetch(urlOlder, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataOlder = await responseOlder.json();
|
||||
@ -316,7 +316,7 @@ export const Thread = ({
|
||||
updateThreadActivityCurrentThread();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
getSavedData(groupId);
|
||||
@ -325,9 +325,21 @@ export const Thread = ({
|
||||
[messages, secretKey]
|
||||
);
|
||||
const getMessages = React.useCallback(async () => {
|
||||
if (!currentThread || (!secretKey && isPrivate) || !groupInfo?.groupId || isPrivate === null) return;
|
||||
if (
|
||||
!currentThread ||
|
||||
(!secretKey && isPrivate) ||
|
||||
!groupInfo?.groupId ||
|
||||
isPrivate === null
|
||||
)
|
||||
return;
|
||||
await getMailMessages(currentThread, null, null, false, groupInfo?.groupId);
|
||||
}, [getMailMessages, currentThread, secretKey, groupInfo?.groupId, isPrivate]);
|
||||
}, [
|
||||
getMailMessages,
|
||||
currentThread,
|
||||
secretKey,
|
||||
groupInfo?.groupId,
|
||||
isPrivate,
|
||||
]);
|
||||
const firstMount = useRef(false);
|
||||
|
||||
const saveTimestamp = useCallback((currentThread: any, username?: string) => {
|
||||
@ -339,7 +351,7 @@ export const Thread = ({
|
||||
return;
|
||||
const threadIdForLocalStorage = `qmail_threads_${currentThread?.threadData?.groupId}_${currentThread?.threadId}`;
|
||||
const threads = JSON.parse(
|
||||
localStorage.getItem(`qmail_threads_viewedtimestamp_${username}`) || "{}"
|
||||
localStorage.getItem(`qmail_threads_viewedtimestamp_${username}`) || '{}'
|
||||
);
|
||||
// Convert to an array of objects with identifier and all fields
|
||||
let dataArray = Object.entries(threads).map(([identifier, value]) => ({
|
||||
@ -382,7 +394,7 @@ export const Thread = ({
|
||||
if (currentThreadRef.current?.threadId !== currentThread?.threadId) {
|
||||
firstMount.current = false;
|
||||
}
|
||||
if(!secretKey && isPrivate) return
|
||||
if (!secretKey && isPrivate) return;
|
||||
if (currentThread && !firstMount.current && isPrivate !== null) {
|
||||
getMessagesMiddleware();
|
||||
}
|
||||
@ -402,9 +414,9 @@ export const Thread = ({
|
||||
const identifier = `thmsg-${threadId}`;
|
||||
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=20&includemetadata=false&offset=${0}&reverse=true&prefix=true`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
@ -469,17 +481,17 @@ export const Thread = ({
|
||||
|
||||
const threadFetchModeFunc = (e) => {
|
||||
const mode = e.detail?.mode;
|
||||
if (mode === "last-page") {
|
||||
if (mode === 'last-page') {
|
||||
getMailMessages(currentThread, null, null, true, groupInfo?.groupId);
|
||||
}
|
||||
firstMount.current = true;
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
subscribeToEvent("threadFetchMode", threadFetchModeFunc);
|
||||
subscribeToEvent('threadFetchMode', threadFetchModeFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("threadFetchMode", threadFetchModeFunc);
|
||||
unsubscribeFromEvent('threadFetchMode', threadFetchModeFunc);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@ -526,11 +538,11 @@ export const Thread = ({
|
||||
handleScroll();
|
||||
}, 400);
|
||||
|
||||
container.addEventListener("scroll", handleScroll);
|
||||
container.addEventListener('scroll', handleScroll);
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
container.removeEventListener("scroll", handleScroll);
|
||||
container.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, [messages]);
|
||||
|
||||
@ -540,9 +552,9 @@ export const Thread = ({
|
||||
if (!container) return;
|
||||
|
||||
if (isAtBottom) {
|
||||
container.scrollTo({ top: 0, behavior: "smooth" }); // Scroll to top
|
||||
container.scrollTo({ top: 0, behavior: 'smooth' }); // Scroll to top
|
||||
} else {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: "smooth" }); // Scroll to bottom
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); // Scroll to bottom
|
||||
}
|
||||
};
|
||||
|
||||
@ -550,19 +562,19 @@ export const Thread = ({
|
||||
return (
|
||||
<GroupContainer
|
||||
sx={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
// Removed the ref from here since the scrollable area has changed
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
flexShrink: 0, // Corrected property name
|
||||
}}
|
||||
>
|
||||
@ -583,16 +595,16 @@ export const Thread = ({
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: isMobile ? "45px" : "35px",
|
||||
alignItems: "center",
|
||||
padding: isMobile && "5px",
|
||||
display: 'flex',
|
||||
gap: isMobile ? '45px' : '35px',
|
||||
alignItems: 'center',
|
||||
padding: isMobile && '5px',
|
||||
}}
|
||||
>
|
||||
<ShowMessageReturnButton
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
minWidth: isMobile && "50px",
|
||||
padding: isMobile && '5px',
|
||||
minWidth: isMobile && '50px',
|
||||
}}
|
||||
onClick={() => {
|
||||
setMessages([]);
|
||||
@ -608,9 +620,9 @@ export const Thread = ({
|
||||
<ButtonBase onClick={scrollToPosition}>
|
||||
<ArrowUpwardIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
fontSize: isMobile ? "28px" : "36px",
|
||||
color: 'white',
|
||||
cursor: 'pointer',
|
||||
fontSize: isMobile ? '28px' : '36px',
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
@ -618,9 +630,9 @@ export const Thread = ({
|
||||
<ButtonBase onClick={scrollToPosition}>
|
||||
<ArrowDownwardIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
cursor: "pointer",
|
||||
fontSize: isMobile ? "28px" : "36px",
|
||||
color: 'white',
|
||||
cursor: 'pointer',
|
||||
fontSize: isMobile ? '28px' : '36px',
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
@ -631,45 +643,45 @@ export const Thread = ({
|
||||
<ThreadContainerFullWidth
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
overflow: "auto",
|
||||
overflow: 'auto',
|
||||
}}
|
||||
ref={threadContainerRef} // Updated ref attached here
|
||||
>
|
||||
<div ref={threadBeginningRef} />
|
||||
<ThreadContainer>
|
||||
<Spacer height={isMobile ? "10px" : "30px"} />
|
||||
<Spacer height={isMobile ? '10px' : '30px'} />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<GroupNameP
|
||||
sx={{
|
||||
fontSize: isMobile && "18px",
|
||||
fontSize: isMobile && '18px',
|
||||
}}
|
||||
>
|
||||
{currentThread?.threadData?.title}
|
||||
</GroupNameP>
|
||||
</Box>
|
||||
<Spacer height={"15px"} />
|
||||
<Spacer height={'15px'} />
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: "5px",
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: '5px',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -687,9 +699,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -707,9 +719,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -727,9 +739,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -746,35 +758,34 @@ export const Thread = ({
|
||||
Last
|
||||
</Button>
|
||||
</Box>
|
||||
<Spacer height={isMobile ? "10px" : "30px"} />
|
||||
<Spacer height={isMobile ? '10px' : '30px'} />
|
||||
{combinedListTempAndReal.map((message, index, list) => {
|
||||
let fullMessage = message;
|
||||
|
||||
if (hashMapMailMessages[message?.identifier]) {
|
||||
fullMessage = hashMapMailMessages[message.identifier];
|
||||
|
||||
|
||||
if (fullMessage?.error) {
|
||||
return (
|
||||
<SingleThreadParent
|
||||
sx={{
|
||||
height: "auto",
|
||||
height: 'auto',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: "8px",
|
||||
overflow: "hidden",
|
||||
position: "relative",
|
||||
flexDirection: "column",
|
||||
width: '100%',
|
||||
borderRadius: '8px',
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
gap: "10px",
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<WrapperUserAction
|
||||
@ -784,8 +795,8 @@ export const Thread = ({
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: "50px",
|
||||
width: "50px",
|
||||
height: '50px',
|
||||
width: '50px',
|
||||
}}
|
||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||
message?.name
|
||||
@ -812,23 +823,22 @@ export const Thread = ({
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
color: "white",
|
||||
fontSize: '18px',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{fullMessage?.error}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
</SingleThreadParent>
|
||||
);
|
||||
@ -855,23 +865,23 @@ export const Thread = ({
|
||||
return (
|
||||
<SingleThreadParent
|
||||
sx={{
|
||||
height: "auto",
|
||||
height: 'auto',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: "8px",
|
||||
overflow: "hidden",
|
||||
position: "relative",
|
||||
flexDirection: "column",
|
||||
width: '100%',
|
||||
borderRadius: '8px',
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
gap: "10px",
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<WrapperUserAction
|
||||
@ -881,8 +891,8 @@ export const Thread = ({
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: "50px",
|
||||
width: "50px",
|
||||
height: '50px',
|
||||
width: '50px',
|
||||
}}
|
||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||
message?.name
|
||||
@ -909,24 +919,23 @@ export const Thread = ({
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<CustomLoader />
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
color: "white",
|
||||
fontSize: '18px',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
Downloading from QDN
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
</SingleThreadParent>
|
||||
);
|
||||
@ -937,9 +946,9 @@ export const Thread = ({
|
||||
<Spacer height="20px" />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@ -955,7 +964,7 @@ export const Thread = ({
|
||||
);
|
||||
}}
|
||||
sx={{
|
||||
color: "white",
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
Refetch page
|
||||
@ -964,26 +973,27 @@ export const Thread = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
visibility: messages?.length > 4 ? 'visible' : 'hidden'
|
||||
}}>
|
||||
visibility: messages?.length > 4 ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<Spacer height="30px" />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: "5px",
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: '5px',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -1001,9 +1011,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -1021,9 +1031,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -1041,9 +1051,9 @@ export const Thread = ({
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
padding: isMobile && "5px",
|
||||
fontSize: isMobile && "14px",
|
||||
textTransformation: "capitalize",
|
||||
padding: isMobile && '5px',
|
||||
fontSize: isMobile && '14px',
|
||||
textTransformation: 'capitalize',
|
||||
}}
|
||||
onClick={() => {
|
||||
getMailMessages(
|
||||
@ -1069,7 +1079,7 @@ export const Thread = ({
|
||||
<LoadingSnackbar
|
||||
open={isLoading}
|
||||
info={{
|
||||
message: "Loading posts... please wait.",
|
||||
message: 'Loading posts... please wait.',
|
||||
}}
|
||||
/>
|
||||
</GroupContainer>
|
||||
|
@ -4,56 +4,59 @@ import {
|
||||
TextField,
|
||||
TextFieldProps,
|
||||
styled,
|
||||
} from "@mui/material";
|
||||
import { forwardRef, useState } from "react";
|
||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import { forwardRef, useState } from 'react';
|
||||
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
|
||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||
|
||||
export const CustomInput = styled(TextField)(({ theme }) => ({
|
||||
width: "183px",
|
||||
borderRadius: "5px",
|
||||
width: '183px',
|
||||
borderRadius: '5px',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
outline: "none",
|
||||
outline: 'none',
|
||||
input: {
|
||||
fontSize: 10,
|
||||
fontFamily: "Inter",
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: 400,
|
||||
color: theme.palette.text.primary,
|
||||
"&::placeholder": {
|
||||
'&::placeholder': {
|
||||
fontSize: 16,
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
outline: "none",
|
||||
padding: "10px",
|
||||
outline: 'none',
|
||||
padding: '10px',
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
border: `0.5px solid ${theme.palette.divider}`,
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
'&:hover fieldset': {
|
||||
border: `0.5px solid ${theme.palette.divider}`,
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
'&.Mui-focused fieldset': {
|
||||
border: `0.5px solid ${theme.palette.divider}`,
|
||||
},
|
||||
},
|
||||
"& .MuiInput-underline:before": {
|
||||
borderBottom: "none",
|
||||
'& .MuiInput-underline:before': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
|
||||
borderBottom: "none",
|
||||
'& .MuiInput-underline:hover:not(.Mui-disabled):before': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"& .MuiInput-underline:after": {
|
||||
borderBottom: "none",
|
||||
'& .MuiInput-underline:after': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
({ ...props }, ref) => {
|
||||
const [canViewPassword, setCanViewPassword] = useState(false);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<CustomInput
|
||||
type={canViewPassword ? "text" : "password"}
|
||||
type={canViewPassword ? 'text' : 'password'}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment
|
||||
@ -70,7 +73,10 @@ export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
>
|
||||
<VisibilityOffIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
color:
|
||||
theme.palette.mode === 'dark'
|
||||
? 'rgba(255, 255, 255, 0.5)'
|
||||
: 'rgba(0, 0, 0, 0.3)',
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
@ -81,7 +87,10 @@ export const PasswordField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
>
|
||||
<VisibilityIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
color:
|
||||
theme.palette.mode === 'dark'
|
||||
? 'rgba(255, 255, 255, 0.5)'
|
||||
: 'rgba(0, 0, 0, 0.3)',
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
|
Loading…
x
Reference in New Issue
Block a user