mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-05-15 22:26:58 +00:00
Merge remote-tracking branch 'upstream/develop' into fix/changing-languages
This commit is contained in:
commit
f1907142db
@ -1,10 +1,9 @@
|
|||||||
import { useTheme } from '@mui/material';
|
import { useTheme } from '@mui/material';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export const CopyIcon = ({ color, height = 11, width = 10 }) => {
|
export const CopyIcon = ({ color, height = 11, width = 10 }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const setColor = color ? color : theme.palette.text.primary;
|
const setColor = color ? color : theme.palette.text.primary;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width={width}
|
width={width}
|
||||||
@ -14,11 +13,11 @@ export const CopyIcon = ({ color, height = 11, width = 10 }) => {
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="evenodd"
|
clipRule="evenodd"
|
||||||
d="M3.92857 0.5H8.57143C9.36071 0.5 10 1.13929 10 1.92857V6.57143C10 7.36071 9.36071 8 8.57143 8H8.21429V4.42857C8.21429 3.24643 7.25357 2.28571 6.07143 2.28571H2.5V1.92857C2.5 1.13929 3.13929 0.5 3.92857 0.5ZM1.42857 3H6.07143C6.86041 3 7.5 3.63959 7.5 4.42857V9.07143C7.5 9.86041 6.86041 10.5 6.07143 10.5H1.42857C0.639593 10.5 0 9.86041 0 9.07143V4.42857C0 3.63959 0.639593 3 1.42857 3Z"
|
d="M3.92857 0.5H8.57143C9.36071 0.5 10 1.13929 10 1.92857V6.57143C10 7.36071 9.36071 8 8.57143 8H8.21429V4.42857C8.21429 3.24643 7.25357 2.28571 6.07143 2.28571H2.5V1.92857C2.5 1.13929 3.13929 0.5 3.92857 0.5ZM1.42857 3H6.07143C6.86041 3 7.5 3.63959 7.5 4.42857V9.07143C7.5 9.86041 6.86041 10.5 6.07143 10.5H1.42857C0.639593 10.5 0 9.86041 0 9.07143V4.42857C0 3.63959 0.639593 3 1.42857 3Z"
|
||||||
fill={setColor}
|
fill={setColor}
|
||||||
fill-opacity="0.5"
|
fillOpacity="0.5"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import './customloader.css';
|
import './customloader.css';
|
||||||
import { Box, useTheme } from '@mui/material';
|
import { Box, useTheme } from '@mui/material';
|
||||||
|
|
||||||
export const CustomLoader = () => {
|
export const CustomLoader = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
export const CustomSvg = ({ src, color = 'black', size = 24 }) => {
|
export const CustomSvg = ({ src, color = 'black', size = 24 }) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width={size}
|
width={size}
|
||||||
height={size}
|
height={size}
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
style={{ fill: color }}
|
style={{ fill: color }}
|
||||||
>
|
>
|
||||||
{src}
|
{src}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
left: 56px;
|
left: 56px;
|
||||||
animation: lds-ellipsis3 0.6s infinite;
|
animation: lds-ellipsis3 0.6s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes lds-ellipsis1 {
|
@keyframes lds-ellipsis1 {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useRef } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { resourceDownloadControllerAtom } from '../atoms/global';
|
import { resourceDownloadControllerAtom } from '../atoms/global';
|
||||||
import { getBaseApiReact } from '../App';
|
import { getBaseApiReact } from '../App';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
|
@ -56,7 +56,7 @@ export const AppsCategoryDesktop = ({
|
|||||||
isShow,
|
isShow,
|
||||||
}) => {
|
}) => {
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const virtuosoRef = useRef();
|
const virtuosoRef = useRef(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const categoryList = useMemo(() => {
|
const categoryList = useMemo(() => {
|
||||||
|
@ -102,7 +102,7 @@ export const AppsLibraryDesktop = ({
|
|||||||
getQapps,
|
getQapps,
|
||||||
}) => {
|
}) => {
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const virtuosoRef = useRef();
|
const virtuosoRef = useRef(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const officialApps = useMemo(() => {
|
const officialApps = useMemo(() => {
|
||||||
|
@ -63,6 +63,7 @@ export const DownloadWallet = ({
|
|||||||
wallet,
|
wallet,
|
||||||
qortAddress: rawWallet.address0,
|
qortAddress: rawWallet.address0,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wallet,
|
wallet,
|
||||||
qortAddress: rawWallet.address0,
|
qortAddress: rawWallet.address0,
|
||||||
|
@ -18,7 +18,7 @@ export const AnnouncementList = ({
|
|||||||
loadMore,
|
loadMore,
|
||||||
myName,
|
myName,
|
||||||
}) => {
|
}) => {
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
const [messages, setMessages] = useState(initialMessages);
|
const [messages, setMessages] = useState(initialMessages);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -23,7 +23,7 @@ export const ChatList = ({
|
|||||||
hasSecretKey,
|
hasSecretKey,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
}) => {
|
}) => {
|
||||||
const parentRef = useRef();
|
const parentRef = useRef(null);
|
||||||
const [messages, setMessages] = useState(initialMessages);
|
const [messages, setMessages] = useState(initialMessages);
|
||||||
const [showScrollButton, setShowScrollButton] = useState(false);
|
const [showScrollButton, setShowScrollButton] = useState(false);
|
||||||
const [showScrollDownButton, setShowScrollDownButton] = useState(false);
|
const [showScrollDownButton, setShowScrollDownButton] = useState(false);
|
||||||
|
@ -60,8 +60,8 @@ export const ChatOptions = ({
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [selectedMember, setSelectedMember] = useState(0);
|
const [selectedMember, setSelectedMember] = useState(0);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const parentRef = useRef();
|
const parentRef = useRef(null);
|
||||||
const parentRefMentions = useRef();
|
const parentRefMentions = useRef(null);
|
||||||
const [lastMentionTimestamp, setLastMentionTimestamp] = useState(null);
|
const [lastMentionTimestamp, setLastMentionTimestamp] = useState(null);
|
||||||
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
|
const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value
|
||||||
const messages = useMemo(() => {
|
const messages = useMemo(() => {
|
||||||
|
@ -31,6 +31,7 @@ import {
|
|||||||
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group/Group';
|
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group/Group';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 8 });
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleUnencryptedPublishes = (publishes) => {
|
export const handleUnencryptedPublishes = (publishes) => {
|
||||||
let publishesData = [];
|
let publishesData = [];
|
||||||
publishes.forEach((pub) => {
|
publishes.forEach((pub) => {
|
||||||
@ -149,6 +151,7 @@ export const GroupAnnouncements = ({
|
|||||||
editorRef.current = editorInstance;
|
editorRef.current = editorInstance;
|
||||||
};
|
};
|
||||||
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const triggerRerender = () => {
|
const triggerRerender = () => {
|
||||||
forceUpdate(); // Trigger re-render by updating the state
|
forceUpdate(); // Trigger re-render by updating the state
|
||||||
@ -209,7 +212,6 @@ export const GroupAnnouncements = ({
|
|||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// initWebsocketMessageGroup()
|
|
||||||
hasInitializedWebsocket.current = true;
|
hasInitializedWebsocket.current = true;
|
||||||
}, [secretKey, isPrivate]);
|
}, [secretKey, isPrivate]);
|
||||||
|
|
||||||
@ -287,7 +289,10 @@ export const GroupAnnouncements = ({
|
|||||||
const fee = await getFee('ARBITRARY');
|
const fee = await getFee('ARBITRARY');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a ARBITRARY transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'ARBITRARY',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -329,7 +334,7 @@ export const GroupAnnouncements = ({
|
|||||||
setTempData(selectedGroup);
|
setTempData(selectedGroup);
|
||||||
clearEditorContent();
|
clearEditorContent();
|
||||||
}
|
}
|
||||||
// send chat message
|
// TODO send chat message
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!error) return;
|
if (!error) return;
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
|
@ -114,7 +114,7 @@ export const CoreSyncStatus = () => {
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="bottom"
|
className="core-panel"
|
||||||
style={{
|
style={{
|
||||||
right: 'unset',
|
right: 'unset',
|
||||||
left: '55px',
|
left: '55px',
|
||||||
@ -122,29 +122,35 @@ export const CoreSyncStatus = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3>{t('core:core.information', { postProcess: 'capitalize' })}</h3>
|
<h3>{t('core:core.information', { postProcess: 'capitalize' })}</h3>
|
||||||
|
|
||||||
<h4 className="lineHeight">
|
<h4 className="lineHeight">
|
||||||
{t('core:core.version', { postProcess: 'capitalize' })}:{' '}
|
{t('core:core.version', { postProcess: 'capitalize' })}:{' '}
|
||||||
<span style={{ color: '#03a9f4' }}>{buildVersion}</span>
|
<span style={{ color: '#03a9f4' }}>{buildVersion}</span>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<h4 className="lineHeight">{message}</h4>
|
<h4 className="lineHeight">{message}</h4>
|
||||||
|
|
||||||
<h4 className="lineHeight">
|
<h4 className="lineHeight">
|
||||||
{t('core:core.block_height', { postProcess: 'capitalize' })}:{' '}
|
{t('core:core.block_height', { postProcess: 'capitalize' })}:{' '}
|
||||||
<span style={{ color: '#03a9f4' }}>{height || ''}</span>
|
<span style={{ color: '#03a9f4' }}>{height || ''}</span>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<h4 className="lineHeight">
|
<h4 className="lineHeight">
|
||||||
{t('core:core.peers', { postProcess: 'capitalize' })}:{' '}
|
{t('core:core.peers', { postProcess: 'capitalize' })}:{' '}
|
||||||
<span style={{ color: '#03a9f4' }}>
|
<span style={{ color: '#03a9f4' }}>
|
||||||
{numberOfConnections || ''}
|
{numberOfConnections || ''}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<h4 className="lineHeight">
|
<h4 className="lineHeight">
|
||||||
{t('auth:node.using_public', { postProcess: 'capitalize' })}:{' '}
|
{t('auth:node.using_public', { postProcess: 'capitalize' })}:{' '}
|
||||||
<span style={{ color: '#03a9f4' }}>
|
<span style={{ color: '#03a9f4' }}>
|
||||||
{isUsingGateway?.toString()}
|
{isUsingGateway?.toString()}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<h4 className="lineHeight">
|
<h4 className="lineHeight">
|
||||||
{t('core:ui.version')}:{' '}
|
{t('core:ui.version', { postProcess: 'capitalize' })}:{' '}
|
||||||
<span style={{ color: '#03a9f4' }}>{manifestData.version}</span>
|
<span style={{ color: '#03a9f4' }}>{manifestData.version}</span>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,10 +3,8 @@ import Box from '@mui/material/Box';
|
|||||||
import { HubsIcon } from '../../assets/Icons/HubsIcon';
|
import { HubsIcon } from '../../assets/Icons/HubsIcon';
|
||||||
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
|
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
|
||||||
import AppIcon from '../../assets/svgs/AppIcon.svg';
|
import AppIcon from '../../assets/svgs/AppIcon.svg';
|
||||||
|
|
||||||
import { HomeIcon } from '../../assets/Icons/HomeIcon';
|
import { HomeIcon } from '../../assets/Icons/HomeIcon';
|
||||||
import { Save } from '../Save/Save';
|
import { Save } from '../Save/Save';
|
||||||
|
|
||||||
import { enabledDevModeAtom } from '../../atoms/global';
|
import { enabledDevModeAtom } from '../../atoms/global';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as React from 'react';
|
import { useState } from 'react';
|
||||||
import { ButtonBase, Typography, useTheme } from '@mui/material';
|
import { ButtonBase, Typography, useTheme } from '@mui/material';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { NotificationIcon2 } from '../../assets/Icons/NotificationIcon2';
|
import { NotificationIcon2 } from '../../assets/Icons/NotificationIcon2';
|
||||||
@ -81,18 +81,18 @@ export const DesktopHeader = ({
|
|||||||
setGroupSection,
|
setGroupSection,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
}) => {
|
}) => {
|
||||||
const [value, setValue] = React.useState(0);
|
const [value, setValue] = useState(0);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
height: '70px', // Footer height
|
height: '70px', // Footer height
|
||||||
zIndex: 1,
|
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '100%',
|
||||||
|
zIndex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@ -126,11 +126,12 @@ export const DesktopHeader = ({
|
|||||||
: selectedGroup?.groupName}
|
: selectedGroup?.groupName}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: '20px',
|
gap: '20px',
|
||||||
alignItems: 'center',
|
|
||||||
visibility: selectedGroup?.groupId === '0' ? 'hidden' : 'visibile',
|
visibility: selectedGroup?.groupId === '0' ? 'hidden' : 'visibile',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -219,6 +220,7 @@ export const DesktopHeader = ({
|
|||||||
/>
|
/>
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenManageMembers(true);
|
setOpenManageMembers(true);
|
||||||
@ -226,17 +228,18 @@ export const DesktopHeader = ({
|
|||||||
>
|
>
|
||||||
<IconWrapper
|
<IconWrapper
|
||||||
color={theme.palette.text.secondary}
|
color={theme.palette.text.secondary}
|
||||||
|
customHeight="55px"
|
||||||
label="Members"
|
label="Members"
|
||||||
selected={false}
|
selected={false}
|
||||||
customHeight="55px"
|
|
||||||
>
|
>
|
||||||
<MembersIcon
|
<MembersIcon
|
||||||
|
color={theme.palette.text.secondary}
|
||||||
height={25}
|
height={25}
|
||||||
width={20}
|
width={20}
|
||||||
color={theme.palette.text.secondary}
|
|
||||||
/>
|
/>
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setGroupSection('adminSpace');
|
setGroupSection('adminSpace');
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Drawer from '@mui/material/Drawer';
|
import Drawer from '@mui/material/Drawer';
|
||||||
|
|
||||||
export const DrawerComponent = ({ open, setOpen, children }) => {
|
export const DrawerComponent = ({ open, setOpen, children }) => {
|
||||||
const toggleDrawer = (newOpen: boolean) => () => {
|
const toggleDrawer = (newOpen: boolean) => () => {
|
||||||
setOpen(newOpen);
|
setOpen(newOpen);
|
||||||
|
@ -40,6 +40,7 @@ export const Explore = ({ setDesktopViewMode }) => {
|
|||||||
}}
|
}}
|
||||||
src={qTradeLogo}
|
src={qTradeLogo}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
@ -66,6 +67,7 @@ export const Explore = ({ setDesktopViewMode }) => {
|
|||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
@ -94,6 +96,7 @@ export const Explore = ({ setDesktopViewMode }) => {
|
|||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
@ -102,6 +105,7 @@ export const Explore = ({ setDesktopViewMode }) => {
|
|||||||
{t('tutorial:initial.general_chat', { postProcess: 'capitalize' })}
|
{t('tutorial:initial.general_chat', { postProcess: 'capitalize' })}
|
||||||
</Typography>
|
</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
sx={{
|
sx={{
|
||||||
'&:hover': { backgroundColor: theme.palette.background.paper },
|
'&:hover': { backgroundColor: theme.palette.background.paper },
|
||||||
@ -119,6 +123,7 @@ export const Explore = ({ setDesktopViewMode }) => {
|
|||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import React from 'react';
|
|
||||||
import { JoinGroup } from './JoinGroup';
|
import { JoinGroup } from './JoinGroup';
|
||||||
|
|
||||||
export const GlobalActions = () => {
|
export const GlobalActions = () => {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
import { useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
ButtonBase,
|
ButtonBase,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -11,13 +10,14 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { CustomButton, CustomButtonAccept } from '../../styles/App-styles';
|
import { CustomButtonAccept } from '../../styles/App-styles';
|
||||||
import { getBaseApiReact, MyContext } from '../../App';
|
import { getBaseApiReact, MyContext } from '../../App';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { FidgetSpinner } from 'react-loader-spinner';
|
import { FidgetSpinner } from 'react-loader-spinner';
|
||||||
import { useAtom, useSetAtom } from 'jotai';
|
import { useAtom, useSetAtom } from 'jotai';
|
||||||
import { memberGroupsAtom, txListAtom } from '../../atoms/global';
|
import { memberGroupsAtom, txListAtom } from '../../atoms/global';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const JoinGroup = () => {
|
export const JoinGroup = () => {
|
||||||
const { show } = useContext(MyContext);
|
const { show } = useContext(MyContext);
|
||||||
@ -29,7 +29,9 @@ export const JoinGroup = () => {
|
|||||||
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
|
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
|
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
|
||||||
|
|
||||||
const handleJoinGroup = async (e) => {
|
const handleJoinGroup = async (e) => {
|
||||||
setGroupInfo(null);
|
setGroupInfo(null);
|
||||||
const groupId = e?.detail?.groupId;
|
const groupId = e?.detail?.groupId;
|
||||||
@ -41,6 +43,7 @@ export const JoinGroup = () => {
|
|||||||
const groupData = await response.json();
|
const groupData = await response.json();
|
||||||
setGroupInfo(groupData);
|
setGroupInfo(groupData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingInfo(false);
|
setIsLoadingInfo(false);
|
||||||
}
|
}
|
||||||
@ -60,15 +63,22 @@ export const JoinGroup = () => {
|
|||||||
(item) => +item?.groupId === +groupInfo?.groupId
|
(item) => +item?.groupId === +groupInfo?.groupId
|
||||||
);
|
);
|
||||||
}, [memberGroups, groupInfo]);
|
}, [memberGroups, groupInfo]);
|
||||||
|
|
||||||
const joinGroup = async (group, isOpen) => {
|
const joinGroup = async (group, isOpen) => {
|
||||||
try {
|
try {
|
||||||
const groupId = group.groupId;
|
const groupId = group.groupId;
|
||||||
const fee = await getFee('JOIN_GROUP');
|
const fee = await getFee('JOIN_GROUP');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform an JOIN_GROUP transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'JOIN_GROUP',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsLoadingJoinGroup(true);
|
setIsLoadingJoinGroup(true);
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage('joinGroup', {
|
.sendMessage('joinGroup', {
|
||||||
@ -78,8 +88,9 @@ export const JoinGroup = () => {
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_join', {
|
||||||
'Successfully requested to join group. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
@ -87,8 +98,14 @@ export const JoinGroup = () => {
|
|||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: 'joined-group',
|
type: 'joined-group',
|
||||||
label: `Joined Group ${group?.groupName}: awaiting confirmation`,
|
label: t('group:message.success.group_join_label', {
|
||||||
labelDone: `Joined Group ${group?.groupName}: success!`,
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
|
labelDone: t('group:message.success.group_join_label', {
|
||||||
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
done: false,
|
done: false,
|
||||||
groupId,
|
groupId,
|
||||||
},
|
},
|
||||||
@ -99,15 +116,20 @@ export const JoinGroup = () => {
|
|||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: 'joined-group-request',
|
type: 'joined-group-request',
|
||||||
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
|
label: t('group:message.success.group_join_request', {
|
||||||
labelDone: `Requested to join Group ${group?.groupName}: success!`,
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
|
labelDone: t('group:message.success.group_join_outcome', {
|
||||||
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
done: false,
|
done: false,
|
||||||
groupId,
|
groupId,
|
||||||
},
|
},
|
||||||
...prev,
|
...prev,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
res(response);
|
res(response);
|
||||||
return;
|
return;
|
||||||
@ -123,7 +145,9 @@ export const JoinGroup = () => {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
@ -131,10 +155,12 @@ export const JoinGroup = () => {
|
|||||||
});
|
});
|
||||||
setIsLoadingJoinGroup(false);
|
setIsLoadingJoinGroup(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingJoinGroup(false);
|
setIsLoadingJoinGroup(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog
|
<Dialog
|
||||||
@ -146,32 +172,31 @@ export const JoinGroup = () => {
|
|||||||
{!groupInfo && (
|
{!groupInfo && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
|
||||||
height: '150px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
height: '150px',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{' '}
|
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
size={25}
|
size={25}
|
||||||
sx={{
|
sx={{
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}}
|
}}
|
||||||
/>{' '}
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
alignItems: 'center',
|
||||||
height: 'auto',
|
|
||||||
maxHeight: '400px',
|
|
||||||
display: !groupInfo ? 'none' : 'flex',
|
display: !groupInfo ? 'none' : 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: 'auto',
|
||||||
|
maxHeight: '400px',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -180,16 +205,20 @@ export const JoinGroup = () => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Group name: {` ${groupInfo?.groupName}`}
|
{t('group:group.name', { postProcess: 'capitalize' })}:{' '}
|
||||||
|
{` ${groupInfo?.groupName}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '15px',
|
fontSize: '15px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Number of members: {` ${groupInfo?.memberCount}`}
|
{t('group:group.member_number', { postProcess: 'capitalize' })}:{' '}
|
||||||
|
{` ${groupInfo?.memberCount}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{groupInfo?.description && (
|
{groupInfo?.description && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
@ -207,7 +236,9 @@ export const JoinGroup = () => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
*You are already in this group!
|
{t('group:message.generic.already_in_group', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{!isInGroup && groupInfo?.isOpen === false && (
|
{!isInGroup && groupInfo?.isOpen === false && (
|
||||||
@ -217,12 +248,14 @@ export const JoinGroup = () => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
*This is a closed/private group, so you will need to wait until
|
{t('group:message.generic.closed_group', {
|
||||||
an admin accepts your request
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -242,7 +275,9 @@ export const JoinGroup = () => {
|
|||||||
opacity: isInGroup ? 0.1 : 1,
|
opacity: isInGroup ? 0.1 : 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Join
|
{t('core:action.join', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</CustomButtonAccept>
|
</CustomButtonAccept>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
@ -255,7 +290,9 @@ export const JoinGroup = () => {
|
|||||||
}}
|
}}
|
||||||
onClick={() => setIsOpen(false)}
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
Close
|
{t('core:action.close', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</CustomButtonAccept>
|
</CustomButtonAccept>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@ -269,14 +306,14 @@ export const JoinGroup = () => {
|
|||||||
{isLoadingJoinGroup && (
|
{isLoadingJoinGroup && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
alignItems: 'center',
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
left: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FidgetSpinner
|
<FidgetSpinner
|
||||||
|
@ -118,7 +118,8 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
const fee = await getFee('CREATE_GROUP');
|
const fee = await getFee('CREATE_GROUP');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: t('group:question.create_group', {
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'CREATE_GROUP',
|
||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
}),
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
@ -330,6 +331,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
})}
|
})}
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('group:group.name', {
|
placeholder={t('group:group.name', {
|
||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
@ -338,6 +340,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -449,6 +452,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
<MenuItem value={100}>100%</MenuItem>
|
<MenuItem value={100}>100%</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -461,6 +465,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
})}
|
})}
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
labelId="demo-simple-select-label"
|
labelId="demo-simple-select-label"
|
||||||
id="demo-simple-select"
|
id="demo-simple-select"
|
||||||
@ -506,6 +511,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -518,6 +524,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
})}
|
})}
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
labelId="demo-simple-select-label"
|
labelId="demo-simple-select-label"
|
||||||
id="demo-simple-select"
|
id="demo-simple-select"
|
||||||
@ -561,6 +568,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
|||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -48,7 +48,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
|||||||
const [groups, setGroups] = useState([]);
|
const [groups, setGroups] = useState([]);
|
||||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [filteredItems, setFilteredItems] = useState(groups);
|
const [filteredItems, setFilteredItems] = useState(groups);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@ -113,7 +113,8 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
|||||||
const fee = await getFee('JOIN_GROUP');
|
const fee = await getFee('JOIN_GROUP');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: t('group:question.join_group', {
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'JOIN_GROUP',
|
||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
}),
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
@ -157,8 +158,14 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
|||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: 'joined-group-request',
|
type: 'joined-group-request',
|
||||||
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
|
label: t('group:message.success.group_join_request', {
|
||||||
labelDone: `Requested to join Group ${group?.groupName}: success!`,
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
|
labelDone: t('group:message.success.group_join_outcome', {
|
||||||
|
group_name: group?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
done: false,
|
done: false,
|
||||||
groupId,
|
groupId,
|
||||||
},
|
},
|
||||||
|
@ -1,26 +1,17 @@
|
|||||||
import React, {
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { Avatar, Box, Popover, Typography, useTheme } from '@mui/material';
|
import { Avatar, Box, Popover, Typography, useTheme } from '@mui/material';
|
||||||
// import { MAIL_SERVICE_TYPE, THREAD_SERVICE_TYPE } from "../../constants/mail";
|
|
||||||
import { Thread } from './Thread';
|
import { Thread } from './Thread';
|
||||||
import {
|
import {
|
||||||
AllThreadP,
|
AllThreadP,
|
||||||
ArrowDownIcon,
|
ArrowDownIcon,
|
||||||
ComposeContainer,
|
ComposeContainer,
|
||||||
ComposeContainerBlank,
|
ComposeContainerBlank,
|
||||||
ComposeIcon,
|
|
||||||
ComposeP,
|
ComposeP,
|
||||||
GroupContainer,
|
GroupContainer,
|
||||||
InstanceFooter,
|
InstanceFooter,
|
||||||
InstanceListContainer,
|
InstanceListContainer,
|
||||||
InstanceListContainerRow,
|
InstanceListContainerRow,
|
||||||
InstanceListContainerRowCheck,
|
InstanceListContainerRowCheck,
|
||||||
InstanceListContainerRowCheckIcon,
|
|
||||||
InstanceListContainerRowMain,
|
InstanceListContainerRowMain,
|
||||||
InstanceListContainerRowMainP,
|
InstanceListContainerRowMainP,
|
||||||
InstanceListHeader,
|
InstanceListHeader,
|
||||||
@ -48,7 +39,6 @@ import {
|
|||||||
getTempPublish,
|
getTempPublish,
|
||||||
handleUnencryptedPublishes,
|
handleUnencryptedPublishes,
|
||||||
} from '../../Chat/GroupAnnouncements';
|
} from '../../Chat/GroupAnnouncements';
|
||||||
import CheckSVG from '../../../assets/svgs/Check.svg';
|
|
||||||
import ArrowDownSVG from '../../../assets/svgs/ArrowDown.svg';
|
import ArrowDownSVG from '../../../assets/svgs/ArrowDown.svg';
|
||||||
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
|
import { LoadingSnackbar } from '../../Snackbar/LoadingSnackbar';
|
||||||
import { executeEvent } from '../../../utils/events';
|
import { executeEvent } from '../../../utils/events';
|
||||||
@ -73,9 +63,9 @@ export const GroupMail = ({
|
|||||||
hide,
|
hide,
|
||||||
isPrivate,
|
isPrivate,
|
||||||
}) => {
|
}) => {
|
||||||
const [viewedThreads, setViewedThreads] = React.useState<any>({});
|
const [viewedThreads, setViewedThreads] = useState<any>({});
|
||||||
const [filterMode, setFilterMode] = useState<string>('Recently active');
|
const [filterMode, setFilterMode] = useState<string>('Recently active');
|
||||||
const [currentThread, setCurrentThread] = React.useState(null);
|
const [currentThread, setCurrentThread] = useState(null);
|
||||||
const [recentThreads, setRecentThreads] = useState<any[]>([]);
|
const [recentThreads, setRecentThreads] = useState<any[]>([]);
|
||||||
const [allThreads, setAllThreads] = useState<any[]>([]);
|
const [allThreads, setAllThreads] = useState<any[]>([]);
|
||||||
const [members, setMembers] = useState<any>(null);
|
const [members, setMembers] = useState<any>(null);
|
||||||
@ -178,7 +168,10 @@ export const GroupMail = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -186,7 +179,7 @@ export const GroupMail = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAllThreads = React.useCallback(
|
const getAllThreads = useCallback(
|
||||||
async (groupId: string, mode: string, isInitial?: boolean) => {
|
async (groupId: string, mode: string, isInitial?: boolean) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -206,7 +199,7 @@ export const GroupMail = ({
|
|||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
|
|
||||||
let fullArrayMsg = isInitial ? [] : [...allThreads];
|
const fullArrayMsg = isInitial ? [] : [...allThreads];
|
||||||
const getMessageForThreads = responseData.map(async (message: any) => {
|
const getMessageForThreads = responseData.map(async (message: any) => {
|
||||||
let fullObject: any = null;
|
let fullObject: any = null;
|
||||||
if (message?.metadata?.description) {
|
if (message?.metadata?.description) {
|
||||||
@ -271,13 +264,12 @@ export const GroupMail = ({
|
|||||||
} finally {
|
} finally {
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
// dispatch(setIsLoadingCustom(null));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[allThreads, isPrivate]
|
[allThreads, isPrivate]
|
||||||
);
|
);
|
||||||
const getMailMessages = React.useCallback(
|
const getMailMessages = useCallback(
|
||||||
async (groupId: string, members: any) => {
|
async (groupId: string, members: any) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -315,7 +307,7 @@ export const GroupMail = ({
|
|||||||
.sort((a, b) => b.created - a.created)
|
.sort((a, b) => b.created - a.created)
|
||||||
.slice(0, 10);
|
.slice(0, 10);
|
||||||
|
|
||||||
let fullThreadArray: any = [];
|
const fullThreadArray: any = [];
|
||||||
const getMessageForThreads = newArray.map(async (message: any) => {
|
const getMessageForThreads = newArray.map(async (message: any) => {
|
||||||
try {
|
try {
|
||||||
const identifierQuery = message.threadId;
|
const identifierQuery = message.threadId;
|
||||||
@ -327,6 +319,7 @@ export const GroupMail = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
|
|
||||||
if (responseData.length > 0) {
|
if (responseData.length > 0) {
|
||||||
const thread = responseData[0];
|
const thread = responseData[0];
|
||||||
if (thread?.metadata?.description) {
|
if (thread?.metadata?.description) {
|
||||||
@ -342,7 +335,7 @@ export const GroupMail = ({
|
|||||||
};
|
};
|
||||||
fullThreadArray.push(fullObject);
|
fullThreadArray.push(fullObject);
|
||||||
} else {
|
} else {
|
||||||
let threadRes = await Promise.race([
|
const threadRes = await Promise.race([
|
||||||
getEncryptedResource(
|
getEncryptedResource(
|
||||||
{
|
{
|
||||||
name: thread.name,
|
name: thread.name,
|
||||||
@ -377,13 +370,12 @@ export const GroupMail = ({
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
// dispatch(setIsLoadingCustom(null));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[secretKey, isPrivate]
|
[secretKey, isPrivate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getMessages = React.useCallback(async () => {
|
const getMessages = useCallback(async () => {
|
||||||
// if ( !groupId || members?.length === 0) return;
|
// if ( !groupId || members?.length === 0) return;
|
||||||
if (!groupId || isPrivate === null) return;
|
if (!groupId || isPrivate === null) return;
|
||||||
|
|
||||||
@ -400,7 +392,6 @@ export const GroupMail = ({
|
|||||||
if (filterModeRef.current !== filterMode) {
|
if (filterModeRef.current !== filterMode) {
|
||||||
firstMount.current = false;
|
firstMount.current = false;
|
||||||
}
|
}
|
||||||
// if (groupId && !firstMount.current && members.length > 0) {
|
|
||||||
if (groupId && !firstMount.current && isPrivate !== null) {
|
if (groupId && !firstMount.current && isPrivate !== null) {
|
||||||
if (filterMode === 'Recently active') {
|
if (filterMode === 'Recently active') {
|
||||||
getMessages();
|
getMessages();
|
||||||
@ -427,11 +418,6 @@ export const GroupMail = ({
|
|||||||
if (groupData && Array.isArray(groupData?.members)) {
|
if (groupData && Array.isArray(groupData?.members)) {
|
||||||
for (const member of groupData.members) {
|
for (const member of groupData.members) {
|
||||||
if (member.member) {
|
if (member.member) {
|
||||||
// const res = await getNameInfo(member.member);
|
|
||||||
// const resAddress = await qortalRequest({
|
|
||||||
// action: "GET_ACCOUNT_DATA",
|
|
||||||
// address: member.member,
|
|
||||||
// });
|
|
||||||
const name = res;
|
const name = res;
|
||||||
const publicKey = resAddress.publicKey;
|
const publicKey = resAddress.publicKey;
|
||||||
if (name) {
|
if (name) {
|
||||||
@ -465,16 +451,6 @@ export const GroupMail = ({
|
|||||||
[filterMode]
|
[filterMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
// useEffect(()=> {
|
|
||||||
// if(user?.name){
|
|
||||||
// const threads = JSON.parse(
|
|
||||||
// localStorage.getItem(`qmail_threads_viewedtimestamp_${user.name}`) || "{}"
|
|
||||||
// );
|
|
||||||
// setViewedThreads(threads)
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }, [user?.name, currentThread])
|
|
||||||
|
|
||||||
const handleCloseThreadFilterList = () => {
|
const handleCloseThreadFilterList = () => {
|
||||||
setIsOpenFilterList(false);
|
setIsOpenFilterList(false);
|
||||||
};
|
};
|
||||||
@ -596,7 +572,7 @@ export const GroupMail = ({
|
|||||||
padding: '0px',
|
padding: '0px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<InstanceListHeader></InstanceListHeader>
|
<InstanceListHeader />
|
||||||
<InstanceListContainer>
|
<InstanceListContainer>
|
||||||
{filterOptions?.map((filter) => {
|
{filterOptions?.map((filter) => {
|
||||||
return (
|
return (
|
||||||
@ -621,6 +597,7 @@ export const GroupMail = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</InstanceListContainerRowCheck>
|
</InstanceListContainerRowCheck>
|
||||||
|
|
||||||
<InstanceListContainerRowMain>
|
<InstanceListContainerRowMain>
|
||||||
<InstanceListContainerRowMainP>
|
<InstanceListContainerRowMainP>
|
||||||
{filter}
|
{filter}
|
||||||
@ -630,9 +607,10 @@ export const GroupMail = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</InstanceListContainer>
|
</InstanceListContainer>
|
||||||
<InstanceFooter></InstanceFooter>
|
<InstanceFooter />
|
||||||
</InstanceListParent>
|
</InstanceListParent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<ThreadContainerFullWidth>
|
<ThreadContainerFullWidth>
|
||||||
<ThreadContainer>
|
<ThreadContainer>
|
||||||
<Box
|
<Box
|
||||||
@ -674,7 +652,9 @@ export const GroupMail = ({
|
|||||||
)}
|
)}
|
||||||
</ComposeContainerBlank>
|
</ComposeContainerBlank>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="30px" />
|
<Spacer height="30px" />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -700,10 +680,12 @@ export const GroupMail = ({
|
|||||||
viewedThreads[
|
viewedThreads[
|
||||||
`qmail_threads_${thread?.threadData?.groupId}_${thread?.threadId}`
|
`qmail_threads_${thread?.threadData?.groupId}_${thread?.threadId}`
|
||||||
];
|
];
|
||||||
|
|
||||||
const shouldAppearLighter =
|
const shouldAppearLighter =
|
||||||
hasViewedRecent &&
|
hasViewedRecent &&
|
||||||
filterMode === 'Recently active' &&
|
filterMode === 'Recently active' &&
|
||||||
thread?.threadData?.createdAt < hasViewedRecent?.timestamp;
|
thread?.threadData?.createdAt < hasViewedRecent?.timestamp;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleThreadParent
|
<SingleThreadParent
|
||||||
sx={{
|
sx={{
|
||||||
@ -771,13 +753,17 @@ export const GroupMail = ({
|
|||||||
>
|
>
|
||||||
<ThreadSingleLastMessageP>
|
<ThreadSingleLastMessageP>
|
||||||
<ThreadSingleLastMessageSpanP>
|
<ThreadSingleLastMessageSpanP>
|
||||||
last message:{' '}
|
{t('group:last_message', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
:{' '}
|
||||||
</ThreadSingleLastMessageSpanP>
|
</ThreadSingleLastMessageSpanP>
|
||||||
{formatDate(thread?.created)}
|
{formatDate(thread?.created)}
|
||||||
</ThreadSingleLastMessageP>
|
</ThreadSingleLastMessageP>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CustomButton
|
<CustomButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -834,6 +820,7 @@ export const GroupMail = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</ThreadContainer>
|
</ThreadContainer>
|
||||||
</ThreadContainerFullWidth>
|
</ThreadContainerFullWidth>
|
||||||
|
|
||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoading}
|
open={isLoading}
|
||||||
info={{
|
info={{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import { useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { Box, CircularProgress, Input, useTheme } from '@mui/material';
|
import { Box, CircularProgress, Input, useTheme } from '@mui/material';
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import ShortUniqueId from 'short-unique-id';
|
||||||
import {
|
import {
|
||||||
@ -8,7 +8,6 @@ import {
|
|||||||
InstanceFooter,
|
InstanceFooter,
|
||||||
InstanceListContainer,
|
InstanceListContainer,
|
||||||
InstanceListHeader,
|
InstanceListHeader,
|
||||||
NewMessageCloseImg,
|
|
||||||
NewMessageHeaderP,
|
NewMessageHeaderP,
|
||||||
NewMessageInputRow,
|
NewMessageInputRow,
|
||||||
NewMessageSendButton,
|
NewMessageSendButton,
|
||||||
@ -143,13 +142,13 @@ export const NewThread = ({
|
|||||||
isPrivate,
|
isPrivate,
|
||||||
}: NewMessageProps) => {
|
}: NewMessageProps) => {
|
||||||
const { t } = useTranslation(['core', 'group']);
|
const { t } = useTranslation(['core', 'group']);
|
||||||
const { show } = React.useContext(MyContext);
|
const { show } = useContext(MyContext);
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
const [isSending, setIsSending] = useState(false);
|
const [isSending, setIsSending] = useState(false);
|
||||||
const [threadTitle, setThreadTitle] = useState<string>('');
|
const [threadTitle, setThreadTitle] = useState<string>('');
|
||||||
const [openSnack, setOpenSnack] = React.useState(false);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [infoSnack, setInfoSnack] = React.useState(null);
|
const [infoSnack, setInfoSnack] = useState(null);
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const setEditorRef = (editorInstance) => {
|
const setEditorRef = (editorInstance) => {
|
||||||
@ -203,31 +202,37 @@ export const NewThread = ({
|
|||||||
// if (!description) missingFields.push('subject')
|
// if (!description) missingFields.push('subject')
|
||||||
if (missingFields.length > 0) {
|
if (missingFields.length > 0) {
|
||||||
const missingFieldsString = missingFields.join(', ');
|
const missingFieldsString = missingFields.join(', ');
|
||||||
const errMsg = `Missing: ${missingFieldsString}`;
|
const errMsg = t('group:message.error.missing_field', {
|
||||||
errorMsg = errMsg; // TODO translate
|
field: missingFieldsString,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
});
|
||||||
|
errorMsg = errMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorMsg) {
|
if (errorMsg) {
|
||||||
// dispatch(
|
|
||||||
// setNotification({
|
|
||||||
// msg: errorMsg,
|
|
||||||
// alertType: "error",
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const htmlContent = editorRef.current.getHTML();
|
const htmlContent = editorRef.current.getHTML();
|
||||||
|
|
||||||
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>')
|
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') {
|
||||||
throw new Error('Please provide a first message to the thread');
|
const errMsg = t('group:message.generic.provide_message', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
});
|
||||||
|
throw new Error(errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
const fee = await getFee('ARBITRARY');
|
const fee = await getFee('ARBITRARY');
|
||||||
let feeToShow = fee.fee;
|
let feeToShow = fee.fee;
|
||||||
|
|
||||||
if (!isMessage) {
|
if (!isMessage) {
|
||||||
feeToShow = +feeToShow * 2;
|
feeToShow = +feeToShow * 2;
|
||||||
}
|
}
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a ARBITRARY transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'ARBITRARY',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: feeToShow + ' QORT',
|
publishFee: feeToShow + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -238,6 +243,7 @@ export const NewThread = ({
|
|||||||
delete reply.reply;
|
delete reply.reply;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mailObject: any = {
|
const mailObject: any = {
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
version: 1,
|
version: 1,
|
||||||
@ -250,7 +256,10 @@ export const NewThread = ({
|
|||||||
const secretKey =
|
const secretKey =
|
||||||
isPrivate === false ? null : await getSecretKey(false, true);
|
isPrivate === false ? null : await getSecretKey(false, true);
|
||||||
if (!secretKey && isPrivate) {
|
if (!secretKey && isPrivate) {
|
||||||
throw new Error('Cannot get group secret key');
|
const errMsg = t('group:message.error.group_secret_key', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
});
|
||||||
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isMessage) {
|
if (!isMessage) {
|
||||||
@ -273,17 +282,18 @@ export const NewThread = ({
|
|||||||
isPrivate === false
|
isPrivate === false
|
||||||
? threadToBase64
|
? threadToBase64
|
||||||
: await encryptSingleFunc(threadToBase64, secretKey);
|
: await encryptSingleFunc(threadToBase64, secretKey);
|
||||||
let identifierThread = `grp-${groupInfo.groupId}-thread-${idThread}`;
|
const identifierThread = `grp-${groupInfo.groupId}-thread-${idThread}`;
|
||||||
await publishGroupEncryptedResource({
|
await publishGroupEncryptedResource({
|
||||||
identifier: identifierThread,
|
identifier: identifierThread,
|
||||||
encryptedData: encryptSingleThread,
|
encryptedData: encryptSingleThread,
|
||||||
});
|
});
|
||||||
|
|
||||||
let identifierPost = `thmsg-${identifierThread}-${idMsg}`;
|
const identifierPost = `thmsg-${identifierThread}-${idMsg}`;
|
||||||
await publishGroupEncryptedResource({
|
await publishGroupEncryptedResource({
|
||||||
identifier: identifierPost,
|
identifier: identifierPost,
|
||||||
encryptedData: encryptSingleFirstPost,
|
encryptedData: encryptSingleFirstPost,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataToSaveToStorage = {
|
const dataToSaveToStorage = {
|
||||||
name: myName,
|
name: myName,
|
||||||
identifier: identifierThread,
|
identifier: identifierThread,
|
||||||
@ -292,6 +302,7 @@ export const NewThread = ({
|
|||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
groupId: groupInfo.groupId,
|
groupId: groupInfo.groupId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const dataToSaveToStoragePost = {
|
const dataToSaveToStoragePost = {
|
||||||
name: myName,
|
name: myName,
|
||||||
identifier: identifierPost,
|
identifier: identifierPost,
|
||||||
@ -300,6 +311,7 @@ export const NewThread = ({
|
|||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
threadId: identifierThread,
|
threadId: identifierThread,
|
||||||
};
|
};
|
||||||
|
|
||||||
await saveTempPublish({ data: dataToSaveToStorage, key: 'thread' });
|
await saveTempPublish({ data: dataToSaveToStorage, key: 'thread' });
|
||||||
await saveTempPublish({
|
await saveTempPublish({
|
||||||
data: dataToSaveToStoragePost,
|
data: dataToSaveToStoragePost,
|
||||||
@ -307,36 +319,32 @@ export const NewThread = ({
|
|||||||
});
|
});
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.thread_creation', {
|
||||||
'Successfully created thread. It may take some time for the publish to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
|
|
||||||
// dispatch(
|
|
||||||
// setNotification({
|
|
||||||
// msg: "Message sent",
|
|
||||||
// alertType: "success",
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
if (publishCallback) {
|
if (publishCallback) {
|
||||||
publishCallback();
|
publishCallback();
|
||||||
}
|
}
|
||||||
closeModal();
|
closeModal();
|
||||||
} else {
|
} else {
|
||||||
if (!currentThread) throw new Error('unable to locate thread Id');
|
if (!currentThread) {
|
||||||
|
const errMsg = t('group:message.error.thread_id', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
});
|
||||||
|
throw new Error(errMsg);
|
||||||
|
}
|
||||||
const idThread = currentThread.threadId;
|
const idThread = currentThread.threadId;
|
||||||
const messageToBase64 = await objectToBase64(mailObject);
|
const messageToBase64 = await objectToBase64(mailObject);
|
||||||
const encryptSinglePost =
|
const encryptSinglePost =
|
||||||
isPrivate === false
|
isPrivate === false
|
||||||
? messageToBase64
|
? messageToBase64
|
||||||
: await encryptSingleFunc(messageToBase64, secretKey);
|
: await encryptSingleFunc(messageToBase64, secretKey);
|
||||||
const idMsg = uid.rnd();
|
|
||||||
let identifier = `thmsg-${idThread}-${idMsg}`;
|
|
||||||
const res = await publishGroupEncryptedResource({
|
|
||||||
identifier: identifier,
|
|
||||||
encryptedData: encryptSinglePost,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const idMsg = uid.rnd();
|
||||||
|
const identifier = `thmsg-${idThread}-${idMsg}`;
|
||||||
const dataToSaveToStoragePost = {
|
const dataToSaveToStoragePost = {
|
||||||
threadId: idThread,
|
threadId: idThread,
|
||||||
name: myName,
|
name: myName,
|
||||||
@ -349,32 +357,17 @@ export const NewThread = ({
|
|||||||
data: dataToSaveToStoragePost,
|
data: dataToSaveToStoragePost,
|
||||||
key: 'thread-post',
|
key: 'thread-post',
|
||||||
});
|
});
|
||||||
// await qortalRequest(multiplePublishMsg);
|
|
||||||
// dispatch(
|
|
||||||
// setNotification({
|
|
||||||
// msg: "Message sent",
|
|
||||||
// alertType: "success",
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.post_creation', {
|
||||||
'Successfully created post. It may take some time for the publish to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
if (publishCallback) {
|
if (publishCallback) {
|
||||||
publishCallback();
|
publishCallback();
|
||||||
}
|
}
|
||||||
// messageCallback({
|
|
||||||
// identifier,
|
|
||||||
// id: identifier,
|
|
||||||
// name,
|
|
||||||
// service: MAIL_SERVICE_TYPE,
|
|
||||||
// created: Date.now(),
|
|
||||||
// ...mailObject,
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closeModal();
|
closeModal();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error?.message) {
|
if (error?.message) {
|
||||||
@ -393,6 +386,7 @@ export const NewThread = ({
|
|||||||
const sendMail = () => {
|
const sendMail = () => {
|
||||||
publishQDNResource();
|
publishQDNResource();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -407,7 +401,15 @@ export const NewThread = ({
|
|||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<ComposeIcon />
|
<ComposeIcon />
|
||||||
<ComposeP>{currentThread ? 'New Post' : 'New Thread'}</ComposeP>
|
<ComposeP>
|
||||||
|
{currentThread
|
||||||
|
? t('core:action.new.post', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})
|
||||||
|
: t('core:action.new.thread', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
</ComposeP>
|
||||||
</ComposeContainer>
|
</ComposeContainer>
|
||||||
|
|
||||||
<ReusableModal
|
<ReusableModal
|
||||||
@ -433,8 +435,15 @@ export const NewThread = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NewMessageHeaderP>
|
<NewMessageHeaderP>
|
||||||
{isMessage ? 'Post Message' : 'New Thread'}
|
{isMessage
|
||||||
|
? t('core:action.post_message', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})
|
||||||
|
: t('core:action.new.thread', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</NewMessageHeaderP>
|
</NewMessageHeaderP>
|
||||||
|
|
||||||
<CloseContainer
|
<CloseContainer
|
||||||
sx={{
|
sx={{
|
||||||
height: '40px',
|
height: '40px',
|
||||||
@ -448,6 +457,7 @@ export const NewThread = ({
|
|||||||
/>
|
/>
|
||||||
</CloseContainer>
|
</CloseContainer>
|
||||||
</InstanceListHeader>
|
</InstanceListHeader>
|
||||||
|
|
||||||
<InstanceListContainer
|
<InstanceListContainer
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
@ -459,6 +469,7 @@ export const NewThread = ({
|
|||||||
{!isMessage && (
|
{!isMessage && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
|
|
||||||
<NewMessageInputRow>
|
<NewMessageInputRow>
|
||||||
<Input
|
<Input
|
||||||
id="standard-adornment-name"
|
id="standard-adornment-name"
|
||||||
@ -516,28 +527,27 @@ export const NewThread = ({
|
|||||||
overrideMobile
|
overrideMobile
|
||||||
customEditorHeight="240px"
|
customEditorHeight="240px"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
</InstanceListContainer>
|
</InstanceListContainer>
|
||||||
|
|
||||||
<InstanceFooter
|
<InstanceFooter
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
padding: '20px 42px',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
height: '90px',
|
height: '90px',
|
||||||
|
padding: '20px 42px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NewMessageSendButton onClick={sendMail}>
|
<NewMessageSendButton onClick={sendMail}>
|
||||||
{isSending && (
|
{isSending && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
@ -550,7 +560,13 @@ export const NewThread = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<NewMessageSendP>
|
<NewMessageSendP>
|
||||||
{isMessage ? 'Post' : 'Create Thread'}
|
{isMessage
|
||||||
|
? t('core:action.post', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})
|
||||||
|
: t('core:action.create_thread', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</NewMessageSendP>
|
</NewMessageSendP>
|
||||||
|
|
||||||
{isMessage ? (
|
{isMessage ? (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { createEditor } from 'slate';
|
import { createEditor } from 'slate';
|
||||||
import {
|
import {
|
||||||
withReact,
|
withReact,
|
||||||
@ -96,7 +96,7 @@ interface ReadOnlySlateProps {
|
|||||||
content: any;
|
content: any;
|
||||||
mode?: string;
|
mode?: string;
|
||||||
}
|
}
|
||||||
const ReadOnlySlate: React.FC<ReadOnlySlateProps> = ({ content, mode }) => {
|
const ReadOnlySlate: FC<ReadOnlySlateProps> = ({ content, mode }) => {
|
||||||
const [load, setLoad] = useState(false);
|
const [load, setLoad] = useState(false);
|
||||||
const editor = useMemo(() => withReact(createEditor()), []);
|
const editor = useMemo(() => withReact(createEditor()), []);
|
||||||
const value = useMemo(() => content, [content]);
|
const value = useMemo(() => content, [content]);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import { FC } from 'react';
|
||||||
import { Box, Modal, useTheme } from '@mui/material';
|
import { Box, Modal, useTheme } from '@mui/material';
|
||||||
|
|
||||||
interface MyModalProps {
|
interface MyModalProps {
|
||||||
@ -9,7 +9,7 @@ interface MyModalProps {
|
|||||||
customStyles?: any;
|
customStyles?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ReusableModal: React.FC<MyModalProps> = ({
|
export const ReusableModal: FC<MyModalProps> = ({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
@ -118,27 +118,6 @@ export const ShowMessage = ({ message, openNewPostWithQuote, myName }: any) => {
|
|||||||
width: 'auto',
|
width: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* <FileElement
|
|
||||||
fileInfo={{ ...file, mimeTypeSaved: file?.type }}
|
|
||||||
title={file?.filename}
|
|
||||||
mode="mail"
|
|
||||||
otherUser={message?.user}
|
|
||||||
>
|
|
||||||
<MailAttachmentImg src={AttachmentMailSVG} />
|
|
||||||
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
fontSize: "16px",
|
|
||||||
transition: '0.2s all',
|
|
||||||
"&:hover": {
|
|
||||||
color: 'rgba(255, 255, 255, 0.90)',
|
|
||||||
textDecoration: 'underline'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{file?.originalFilename || file?.filename}
|
|
||||||
</Typography>
|
|
||||||
</FileElement> */}
|
|
||||||
{message?.attachments?.length > 1 && isFirst && (
|
{message?.attachments?.length > 1 && isFirst && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
import React, {
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
Box,
|
||||||
@ -18,7 +12,6 @@ import {
|
|||||||
ComposeP,
|
ComposeP,
|
||||||
GroupContainer,
|
GroupContainer,
|
||||||
GroupNameP,
|
GroupNameP,
|
||||||
MailIconImg,
|
|
||||||
ShowMessageReturnButton,
|
ShowMessageReturnButton,
|
||||||
SingleThreadParent,
|
SingleThreadParent,
|
||||||
ThreadContainer,
|
ThreadContainer,
|
||||||
@ -222,7 +215,7 @@ export const Thread = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMailMessages = React.useCallback(
|
const getMailMessages = useCallback(
|
||||||
async (groupInfo: any, before, after, isReverse, groupId) => {
|
async (groupInfo: any, before, after, isReverse, groupId) => {
|
||||||
try {
|
try {
|
||||||
setTempPublishedList([]);
|
setTempPublishedList([]);
|
||||||
@ -328,7 +321,7 @@ export const Thread = ({
|
|||||||
},
|
},
|
||||||
[messages, secretKey]
|
[messages, secretKey]
|
||||||
);
|
);
|
||||||
const getMessages = React.useCallback(async () => {
|
const getMessages = useCallback(async () => {
|
||||||
if (
|
if (
|
||||||
!currentThread ||
|
!currentThread ||
|
||||||
(!secretKey && isPrivate) ||
|
(!secretKey && isPrivate) ||
|
||||||
@ -410,7 +403,7 @@ export const Thread = ({
|
|||||||
|
|
||||||
const interval = useRef<any>(null);
|
const interval = useRef<any>(null);
|
||||||
|
|
||||||
const checkNewMessages = React.useCallback(
|
const checkNewMessages = useCallback(
|
||||||
async (groupInfo: any) => {
|
async (groupInfo: any) => {
|
||||||
try {
|
try {
|
||||||
let threadId = groupInfo.threadId;
|
let threadId = groupInfo.threadId;
|
||||||
@ -494,7 +487,7 @@ export const Thread = ({
|
|||||||
firstMount.current = true;
|
firstMount.current = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent('threadFetchMode', threadFetchModeFunc);
|
subscribeToEvent('threadFetchMode', threadFetchModeFunc);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@ -656,6 +649,7 @@ export const Thread = ({
|
|||||||
<div ref={threadBeginningRef} />
|
<div ref={threadBeginningRef} />
|
||||||
<ThreadContainer>
|
<ThreadContainer>
|
||||||
<Spacer height={'30px'} />
|
<Spacer height={'30px'} />
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -715,6 +709,7 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
{t('core:page.previous', { postProcess: 'capitalize' })}
|
{t('core:page.previous', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
@ -733,6 +728,7 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
{t('core:page.next', { postProcess: 'capitalize' })}
|
{t('core:page.next', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
@ -1006,6 +1002,7 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
{t('core:page.first', { postProcess: 'capitalize' })}
|
{t('core:page.first', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
@ -1024,6 +1021,7 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
{t('core:page.previous', { postProcess: 'capitalize' })}
|
{t('core:page.previous', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
@ -1042,6 +1040,7 @@ export const Thread = ({
|
|||||||
>
|
>
|
||||||
{t('core:page.next', { postProcess: 'capitalize' })}
|
{t('core:page.next', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
textTransformation: 'capitalize',
|
textTransformation: 'capitalize',
|
||||||
@ -1061,12 +1060,14 @@ export const Thread = ({
|
|||||||
{t('core:page.last', { postProcess: 'capitalize' })}
|
{t('core:page.last', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="30px" />
|
<Spacer height="30px" />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<div ref={containerRef} />
|
<div ref={containerRef} />
|
||||||
</ThreadContainer>
|
</ThreadContainer>
|
||||||
</ThreadContainerFullWidth>
|
</ThreadContainerFullWidth>
|
||||||
|
|
||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoading}
|
open={isLoading}
|
||||||
info={{
|
info={{
|
||||||
|
@ -9,20 +9,12 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import React, {
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { ChatGroup } from '../Chat/ChatGroup';
|
import { ChatGroup } from '../Chat/ChatGroup';
|
||||||
import { CreateCommonSecret } from '../Chat/CreateCommonSecret';
|
import { CreateCommonSecret } from '../Chat/CreateCommonSecret';
|
||||||
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
|
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
|
||||||
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
|
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
|
||||||
import CampaignIcon from '@mui/icons-material/Campaign';
|
|
||||||
import { AddGroup } from './AddGroup';
|
import { AddGroup } from './AddGroup';
|
||||||
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
|
|
||||||
import CreateIcon from '@mui/icons-material/Create';
|
import CreateIcon from '@mui/icons-material/Create';
|
||||||
import {
|
import {
|
||||||
AuthenticatedContainerInnerRight,
|
AuthenticatedContainerInnerRight,
|
||||||
@ -52,7 +44,6 @@ import {
|
|||||||
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
||||||
import { WebSocketActive } from './WebsocketActive';
|
import { WebSocketActive } from './WebsocketActive';
|
||||||
import { useMessageQueue } from '../../MessageQueueContext';
|
import { useMessageQueue } from '../../MessageQueueContext';
|
||||||
import { ContextMenu } from '../ContextMenu';
|
|
||||||
import { HomeDesktop } from './HomeDesktop';
|
import { HomeDesktop } from './HomeDesktop';
|
||||||
import { IconWrapper } from '../Desktop/DesktopFooter';
|
import { IconWrapper } from '../Desktop/DesktopFooter';
|
||||||
import { DesktopHeader } from '../Desktop/DesktopHeader';
|
import { DesktopHeader } from '../Desktop/DesktopHeader';
|
||||||
@ -63,7 +54,6 @@ import { HubsIcon } from '../../assets/Icons/HubsIcon';
|
|||||||
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
|
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
|
||||||
import { formatEmailDate } from './QMailMessages';
|
import { formatEmailDate } from './QMailMessages';
|
||||||
import { AdminSpace } from '../Chat/AdminSpace';
|
import { AdminSpace } from '../Chat/AdminSpace';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addressInfoControllerAtom,
|
addressInfoControllerAtom,
|
||||||
groupAnnouncementsAtom,
|
groupAnnouncementsAtom,
|
||||||
@ -77,9 +67,6 @@ import {
|
|||||||
timestampEnterDataAtom,
|
timestampEnterDataAtom,
|
||||||
} from '../../atoms/global';
|
} from '../../atoms/global';
|
||||||
import { sortArrayByTimestampAndGroupName } from '../../utils/time';
|
import { sortArrayByTimestampAndGroupName } from '../../utils/time';
|
||||||
import PersonOffIcon from '@mui/icons-material/PersonOff';
|
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
|
||||||
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
|
||||||
import { BlockedUsersModal } from './BlockedUsersModal';
|
import { BlockedUsersModal } from './BlockedUsersModal';
|
||||||
import { WalletsAppWrapper } from './WalletsAppWrapper';
|
import { WalletsAppWrapper } from './WalletsAppWrapper';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -92,6 +79,7 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
|||||||
groupId
|
groupId
|
||||||
}&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`;
|
}&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('network error');
|
throw new Error('network error');
|
||||||
}
|
}
|
||||||
@ -100,9 +88,11 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
|||||||
const filterId = adminData.filter(
|
const filterId = adminData.filter(
|
||||||
(data: any) => data.identifier === `symmetric-qchat-group-${groupId}`
|
(data: any) => data.identifier === `symmetric-qchat-group-${groupId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (filterId?.length === 0) {
|
if (filterId?.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedData = filterId.sort((a: any, b: any) => {
|
const sortedData = filterId.sort((a: any, b: any) => {
|
||||||
// Get the most recent date for both a and b
|
// Get the most recent date for both a and b
|
||||||
const dateA = a.updated ? new Date(a.updated) : new Date(a.created);
|
const dateA = a.updated ? new Date(a.updated) : new Date(a.created);
|
||||||
@ -114,24 +104,18 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
|||||||
|
|
||||||
return sortedData[0];
|
return sortedData[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
interface GroupProps {
|
interface GroupProps {
|
||||||
myAddress: string;
|
|
||||||
isFocused: boolean;
|
|
||||||
userInfo: any;
|
|
||||||
balance: number;
|
balance: number;
|
||||||
|
isFocused: boolean;
|
||||||
|
myAddress: string;
|
||||||
|
userInfo: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const timeDifferenceForNotificationChats = 900000;
|
export const timeDifferenceForNotificationChats = 900000;
|
||||||
|
|
||||||
export const requestQueueMemberNames = new RequestQueueWithPromise(5);
|
export const requestQueueMemberNames = new RequestQueueWithPromise(5);
|
||||||
export const requestQueueAdminMemberNames = new RequestQueueWithPromise(5);
|
export const requestQueueAdminMemberNames = new RequestQueueWithPromise(5);
|
||||||
|
|
||||||
// const audio = new Audio(chrome.runtime?.getURL("msg-not1.wav"));
|
|
||||||
|
|
||||||
export const getGroupAdminsAddress = async (groupNumber: number) => {
|
export const getGroupAdminsAddress = async (groupNumber: number) => {
|
||||||
// const validApi = await findUsableApi();
|
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${getBaseApiReact()}/groups/members/${groupNumber}?limit=0&onlyAdmins=true`
|
`${getBaseApiReact()}/groups/members/${groupNumber}?limit=0&onlyAdmins=true`
|
||||||
);
|
);
|
||||||
@ -422,27 +406,24 @@ export const Group = ({
|
|||||||
|
|
||||||
const [chatMode, setChatMode] = useState('groups');
|
const [chatMode, setChatMode] = useState('groups');
|
||||||
const [newChat, setNewChat] = useState(false);
|
const [newChat, setNewChat] = useState(false);
|
||||||
const [openSnack, setOpenSnack] = React.useState(false);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [infoSnack, setInfoSnack] = React.useState(null);
|
const [infoSnack, setInfoSnack] = useState(null);
|
||||||
const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = React.useState(false);
|
const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = useState(false);
|
||||||
const [isLoadingGroups, setIsLoadingGroups] = React.useState(true);
|
const [isLoadingGroups, setIsLoadingGroups] = useState(true);
|
||||||
const [isLoadingGroup, setIsLoadingGroup] = React.useState(false);
|
const [isLoadingGroup, setIsLoadingGroup] = useState(false);
|
||||||
const [firstSecretKeyInCreation, setFirstSecretKeyInCreation] =
|
const [firstSecretKeyInCreation, setFirstSecretKeyInCreation] =
|
||||||
React.useState(false);
|
useState(false);
|
||||||
const [groupSection, setGroupSection] = React.useState('home');
|
const [groupSection, setGroupSection] = useState('home');
|
||||||
const [groupAnnouncements, setGroupAnnouncements] = useAtom(
|
const [groupAnnouncements, setGroupAnnouncements] = useAtom(
|
||||||
groupAnnouncementsAtom
|
groupAnnouncementsAtom
|
||||||
);
|
);
|
||||||
|
const [defaultThread, setDefaultThread] = useState(null);
|
||||||
const [defaultThread, setDefaultThread] = React.useState(null);
|
const [isOpenDrawer, setIsOpenDrawer] = useState(false);
|
||||||
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
|
|
||||||
const setIsOpenBlockedUserModal = useSetAtom(isOpenBlockedModalAtom);
|
const setIsOpenBlockedUserModal = useSetAtom(isOpenBlockedModalAtom);
|
||||||
|
const [hideCommonKeyPopup, setHideCommonKeyPopup] = useState(false);
|
||||||
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
|
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = useState('');
|
||||||
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState('');
|
const [drawerMode, setDrawerMode] = useState('groups');
|
||||||
const [drawerMode, setDrawerMode] = React.useState('groups');
|
|
||||||
const setMutedGroups = useSetAtom(mutedGroupsAtom);
|
const setMutedGroups = useSetAtom(mutedGroupsAtom);
|
||||||
|
|
||||||
const [mobileViewMode, setMobileViewMode] = useState('home');
|
const [mobileViewMode, setMobileViewMode] = useState('home');
|
||||||
const [mobileViewModeKeepOpen, setMobileViewModeKeepOpen] = useState('');
|
const [mobileViewModeKeepOpen, setMobileViewModeKeepOpen] = useState('');
|
||||||
const isFocusedRef = useRef(true);
|
const isFocusedRef = useRef(true);
|
||||||
@ -531,7 +512,10 @@ export const Group = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -557,7 +541,10 @@ export const Group = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -586,7 +573,10 @@ export const Group = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1106,7 +1096,10 @@ export const Group = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
|
@ -16,7 +16,8 @@ export const InviteMember = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
|||||||
try {
|
try {
|
||||||
const fee = await getFee('GROUP_INVITE');
|
const fee = await getFee('GROUP_INVITE');
|
||||||
await show({
|
await show({
|
||||||
message: t('group:question.group_invite', {
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'GROUP_INVITE',
|
||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
}),
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
|
@ -54,7 +54,7 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
|||||||
const [bans, setBans] = useState([]);
|
const [bans, setBans] = useState([]);
|
||||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
const [isLoadingUnban, setIsLoadingUnban] = useState(false);
|
const [isLoadingUnban, setIsLoadingUnban] = useState(false);
|
||||||
const { t } = useTranslation(['core', 'group']);
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
@ -88,7 +88,10 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
|||||||
try {
|
try {
|
||||||
const fee = await getFee('CANCEL_GROUP_BAN');
|
const fee = await getFee('CANCEL_GROUP_BAN');
|
||||||
await show({
|
await show({
|
||||||
message: t('group:question.cancel_ban', { postProcess: 'capitalize' }),
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'CANCEL_GROUP_BAN',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoadingUnban(true);
|
setIsLoadingUnban(true);
|
||||||
@ -165,13 +168,13 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
alignItems: 'center',
|
||||||
height: '250px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: '250px',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
@ -214,12 +217,12 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
|||||||
<p>{t('group:ban_list', { postProcess: 'capitalize' })}</p>
|
<p>{t('group:ban_list', { postProcess: 'capitalize' })}</p>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
|
||||||
height: '500px',
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
|
height: '500px',
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
|
@ -51,6 +51,11 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|||||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { useAtom, useSetAtom } from 'jotai';
|
import { useAtom, useSetAtom } from 'jotai';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const THIRTY_MINUTES = 30 * 60 * 1000; // 30 minutes in milliseconds
|
||||||
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
|
|
||||||
export const requestQueuePromos = new RequestQueueWithPromise(3);
|
export const requestQueuePromos = new RequestQueueWithPromise(3);
|
||||||
|
|
||||||
export function utf8ToBase64(inputString: string): string {
|
export function utf8ToBase64(inputString: string): string {
|
||||||
@ -65,13 +70,11 @@ export function utf8ToBase64(inputString: string): string {
|
|||||||
return base64String;
|
return base64String;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 8 });
|
|
||||||
|
|
||||||
export function getGroupId(str) {
|
export function getGroupId(str) {
|
||||||
const match = str.match(/group-(\d+)-/);
|
const match = str.match(/group-(\d+)-/);
|
||||||
return match ? match[1] : null;
|
return match ? match[1] : null;
|
||||||
}
|
}
|
||||||
const THIRTY_MINUTES = 30 * 60 * 1000; // 30 minutes in milliseconds
|
|
||||||
export const ListOfGroupPromotions = () => {
|
export const ListOfGroupPromotions = () => {
|
||||||
const [popoverAnchor, setPopoverAnchor] = useState(null);
|
const [popoverAnchor, setPopoverAnchor] = useState(null);
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null);
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null);
|
||||||
@ -98,7 +101,8 @@ export const ListOfGroupPromotions = () => {
|
|||||||
const setTxList = useSetAtom(txListAtom);
|
const setTxList = useSetAtom(txListAtom);
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const listRef = useRef();
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
const listRef = useRef(null);
|
||||||
const rowVirtualizer = useVirtualizer({
|
const rowVirtualizer = useVirtualizer({
|
||||||
count: promotions.length,
|
count: promotions.length,
|
||||||
getItemKey: React.useCallback(
|
getItemKey: React.useCallback(
|
||||||
@ -120,6 +124,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getPromotions = useCallback(async () => {
|
const getPromotions = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setPromotionTimeInterval(Date.now());
|
setPromotionTimeInterval(Date.now());
|
||||||
@ -135,6 +140,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
let data: any[] = [];
|
let data: any[] = [];
|
||||||
const uniqueGroupIds = new Set();
|
const uniqueGroupIds = new Set();
|
||||||
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
const getPromos = responseData?.map(async (promo: any) => {
|
const getPromos = responseData?.map(async (promo: any) => {
|
||||||
if (promo?.size < 200 && promo.created > oneWeekAgo) {
|
if (promo?.size < 200 && promo.created > oneWeekAgo) {
|
||||||
const name = await requestQueuePromos.enqueue(async () => {
|
const name = await requestQueuePromos.enqueue(async () => {
|
||||||
@ -213,6 +219,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
setPopoverAnchor(null);
|
setPopoverAnchor(null);
|
||||||
setOpenPopoverIndex(null);
|
setOpenPopoverIndex(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const publishPromo = async () => {
|
const publishPromo = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoadingPublish(true);
|
setIsLoadingPublish(true);
|
||||||
@ -235,9 +242,12 @@ export const ListOfGroupPromotions = () => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}); // TODO translate
|
});
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message:
|
||||||
@ -264,7 +274,10 @@ export const ListOfGroupPromotions = () => {
|
|||||||
const groupId = group.groupId;
|
const groupId = group.groupId;
|
||||||
const fee = await getFee('JOIN_GROUP');
|
const fee = await getFee('JOIN_GROUP');
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform an JOIN_GROUP transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'JOIN_GROUP',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoadingJoinGroup(true);
|
setIsLoadingJoinGroup(true);
|
||||||
@ -331,6 +344,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
});
|
});
|
||||||
setIsLoadingJoinGroup(false);
|
setIsLoadingJoinGroup(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingJoinGroup(false);
|
setIsLoadingJoinGroup(false);
|
||||||
}
|
}
|
||||||
@ -339,30 +353,30 @@ export const ListOfGroupPromotions = () => {
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
marginTop: '20px',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
marginTop: '20px',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: '20px',
|
gap: '20px',
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
sx={{
|
sx={{
|
||||||
|
alignSelf: isExpanded && 'flex-start',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
padding: `0px ${isExpanded ? '24px' : '20px'}`,
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
alignSelf: isExpanded && 'flex-start',
|
padding: `0px ${isExpanded ? '24px' : '20px'}`,
|
||||||
}}
|
}}
|
||||||
onClick={() => setIsExpanded((prev) => !prev)}
|
onClick={() => setIsExpanded((prev) => !prev)}
|
||||||
>
|
>
|
||||||
@ -374,6 +388,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
Group promotions{' '}
|
Group promotions{' '}
|
||||||
{promotions.length > 0 && ` (${promotions.length})`}
|
{promotions.length > 0 && ` (${promotions.length})`}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
<ExpandLessIcon
|
<ExpandLessIcon
|
||||||
sx={{
|
sx={{
|
||||||
@ -400,19 +415,19 @@ export const ListOfGroupPromotions = () => {
|
|||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '750px',
|
|
||||||
maxWidth: '90%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
maxWidth: '90%',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
|
width: '750px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -18,6 +18,7 @@ import { getNameInfo } from './Group';
|
|||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
import { getBaseApiReact } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const getMemberInvites = async (groupNumber) => {
|
export const getMemberInvites = async (groupNumber) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@ -59,8 +60,8 @@ export const ListOfInvites = ({
|
|||||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
||||||
const [isLoadingCancelInvite, setIsLoadingCancelInvite] = useState(false);
|
const [isLoadingCancelInvite, setIsLoadingCancelInvite] = useState(false);
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
|
|
||||||
const getInvites = async (groupId) => {
|
const getInvites = async (groupId) => {
|
||||||
try {
|
try {
|
||||||
@ -90,13 +91,18 @@ export const ListOfInvites = ({
|
|||||||
|
|
||||||
const handleCancelInvitation = async (address) => {
|
const handleCancelInvitation = async (address) => {
|
||||||
try {
|
try {
|
||||||
// TODO translate
|
|
||||||
const fee = await getFee('CANCEL_GROUP_INVITE');
|
const fee = await getFee('CANCEL_GROUP_INVITE');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a CANCEL_GROUP_INVITE transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'CANCEL_GROUP_INVITE',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsLoadingCancelInvite(true);
|
setIsLoadingCancelInvite(true);
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage('cancelInvitationToGroup', {
|
.sendMessage('cancelInvitationToGroup', {
|
||||||
@ -107,8 +113,9 @@ export const ListOfInvites = ({
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.invitation_cancellation', {
|
||||||
'Successfully canceled invitation. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -126,13 +133,18 @@ export const ListOfInvites = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingCancelInvite(false);
|
setIsLoadingCancelInvite(false);
|
||||||
}
|
}
|
||||||
@ -168,13 +180,13 @@ export const ListOfInvites = ({
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
alignItems: 'center',
|
||||||
height: '250px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: '250px',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
@ -183,10 +195,13 @@ export const ListOfInvites = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => handleCancelInvitation(member?.invitee)}
|
onClick={() => handleCancelInvitation(member?.invitee)}
|
||||||
>
|
>
|
||||||
Cancel Invitation
|
{t('core:action.cancel_invitation', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={(event) => handlePopoverOpen(event, index)}
|
onClick={(event) => handlePopoverOpen(event, index)}
|
||||||
>
|
>
|
||||||
@ -200,6 +215,7 @@ export const ListOfInvites = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
|
|
||||||
<ListItemText primary={member?.name || member?.invitee} />
|
<ListItemText primary={member?.name || member?.invitee} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@ -211,15 +227,19 @@ export const ListOfInvites = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Invitees list</p>
|
<p>
|
||||||
|
{t('group:invitees_list', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
|
||||||
height: '500px',
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
|
height: '500px',
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
|
@ -15,11 +15,12 @@ import {
|
|||||||
List,
|
List,
|
||||||
} from 'react-virtualized';
|
} from 'react-virtualized';
|
||||||
import { getNameInfo } from './Group';
|
import { getNameInfo } from './Group';
|
||||||
import { getBaseApi, getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
import { getBaseApiReact } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
import { txListAtom } from '../../atoms/global';
|
import { txListAtom } from '../../atoms/global';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const getMemberInvites = async (groupNumber) => {
|
export const getMemberInvites = async (groupNumber) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@ -59,11 +60,11 @@ export const ListOfJoinRequests = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [invites, setInvites] = useState([]);
|
const [invites, setInvites] = useState([]);
|
||||||
const [txList, setTxList] = useAtom(txListAtom);
|
const [txList, setTxList] = useAtom(txListAtom);
|
||||||
|
|
||||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
const [isLoadingAccept, setIsLoadingAccept] = useState(false);
|
const [isLoadingAccept, setIsLoadingAccept] = useState(false);
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const getInvites = async (groupId) => {
|
const getInvites = async (groupId) => {
|
||||||
try {
|
try {
|
||||||
@ -93,12 +94,18 @@ export const ListOfJoinRequests = ({
|
|||||||
|
|
||||||
const handleAcceptJoinRequest = async (address) => {
|
const handleAcceptJoinRequest = async (address) => {
|
||||||
try {
|
try {
|
||||||
const fee = await getFee('GROUP_INVITE'); // TODO translate
|
const fee = await getFee('GROUP_INVITE');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a GROUP_INVITE transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'GROUP_INVITE',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsLoadingAccept(true);
|
setIsLoadingAccept(true);
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage('inviteToGroup', {
|
.sendMessage('inviteToGroup', {
|
||||||
@ -111,19 +118,23 @@ export const ListOfJoinRequests = ({
|
|||||||
setIsLoadingAccept(false);
|
setIsLoadingAccept(false);
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success,group_join', {
|
||||||
'Successfully accepted join request. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
res(response);
|
res(response);
|
||||||
|
|
||||||
setTxList((prev) => [
|
setTxList((prev) => [
|
||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: 'join-request-accept',
|
type: 'join-request-accept',
|
||||||
label: `Accepted join request: awaiting confirmation`,
|
label: t('group:message.success,invitation_request', {
|
||||||
labelDone: `User successfully joined!`,
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
|
labelDone: t('group:message.success,user_joined', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
done: false,
|
done: false,
|
||||||
groupId,
|
groupId,
|
||||||
qortalAddress: address,
|
qortalAddress: address,
|
||||||
@ -144,13 +155,16 @@ export const ListOfJoinRequests = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error?.message || 'An error occurred',
|
message:
|
||||||
|
error?.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingAccept(false);
|
setIsLoadingAccept(false);
|
||||||
}
|
}
|
||||||
@ -158,13 +172,15 @@ export const ListOfJoinRequests = ({
|
|||||||
|
|
||||||
const rowRenderer = ({ index, key, parent, style }) => {
|
const rowRenderer = ({ index, key, parent, style }) => {
|
||||||
const member = invites[index];
|
const member = invites[index];
|
||||||
const findJoinRequsetInTxList = txList?.find(
|
const findJoinRequestInTxList = txList?.find(
|
||||||
(tx) =>
|
(tx) =>
|
||||||
tx?.groupId === groupId &&
|
tx?.groupId === groupId &&
|
||||||
tx?.qortalAddress === member?.joiner &&
|
tx?.qortalAddress === member?.joiner &&
|
||||||
tx?.type === 'join-request-accept'
|
tx?.type === 'join-request-accept'
|
||||||
);
|
);
|
||||||
if (findJoinRequsetInTxList) return null;
|
|
||||||
|
if (findJoinRequestInTxList) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CellMeasurer
|
<CellMeasurer
|
||||||
key={key}
|
key={key}
|
||||||
@ -207,10 +223,11 @@ export const ListOfJoinRequests = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => handleAcceptJoinRequest(member?.joiner)}
|
onClick={() => handleAcceptJoinRequest(member?.joiner)}
|
||||||
>
|
>
|
||||||
Accept
|
{t('core:action.accept', { postProcess: 'capitalize' })}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={(event) => handlePopoverOpen(event, index)}
|
onClick={(event) => handlePopoverOpen(event, index)}
|
||||||
>
|
>
|
||||||
@ -235,7 +252,7 @@ export const ListOfJoinRequests = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Join request list</p>
|
<p>{t('core:list.join_request', { postProcess: 'capitalize' })}</p>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
import { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
import { getBaseApiReact } from '../../App';
|
import { getBaseApiReact } from '../../App';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const cache = new CellMeasurerCache({
|
const cache = new CellMeasurerCache({
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
@ -41,7 +42,8 @@ const ListOfMembers = ({
|
|||||||
const [isLoadingMakeAdmin, setIsLoadingMakeAdmin] = useState(false);
|
const [isLoadingMakeAdmin, setIsLoadingMakeAdmin] = useState(false);
|
||||||
const [isLoadingRemoveAdmin, setIsLoadingRemoveAdmin] = useState(false);
|
const [isLoadingRemoveAdmin, setIsLoadingRemoveAdmin] = useState(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const listRef = useRef();
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
const listRef = useRef(null);
|
||||||
|
|
||||||
const handlePopoverOpen = (event, index) => {
|
const handlePopoverOpen = (event, index) => {
|
||||||
setPopoverAnchor(event.currentTarget);
|
setPopoverAnchor(event.currentTarget);
|
||||||
@ -57,7 +59,10 @@ const ListOfMembers = ({
|
|||||||
try {
|
try {
|
||||||
const fee = await getFee('GROUP_KICK');
|
const fee = await getFee('GROUP_KICK');
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a GROUP_KICK transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'GROUP_KICK',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,8 +77,9 @@ const ListOfMembers = ({
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_kick', {
|
||||||
'Successfully kicked member from group. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -90,7 +96,9 @@ const ListOfMembers = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
@ -104,12 +112,18 @@ const ListOfMembers = ({
|
|||||||
};
|
};
|
||||||
const handleBan = async (address) => {
|
const handleBan = async (address) => {
|
||||||
try {
|
try {
|
||||||
const fee = await getFee('GROUP_BAN'); // TODO translate
|
const fee = await getFee('GROUP_BAN');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a GROUP_BAN transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'GROUP_BAN',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsLoadingBan(true);
|
setIsLoadingBan(true);
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage('banFromGroup', {
|
.sendMessage('banFromGroup', {
|
||||||
@ -121,8 +135,9 @@ const ListOfMembers = ({
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_ban', {
|
||||||
'Successfully banned member from group. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -139,13 +154,16 @@ const ListOfMembers = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingBan(false);
|
setIsLoadingBan(false);
|
||||||
}
|
}
|
||||||
@ -155,7 +173,10 @@ const ListOfMembers = ({
|
|||||||
try {
|
try {
|
||||||
const fee = await getFee('ADD_GROUP_ADMIN');
|
const fee = await getFee('ADD_GROUP_ADMIN');
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a ADD_GROUP_ADMIN transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'ADD_GROUP_ADMIN',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoadingMakeAdmin(true);
|
setIsLoadingMakeAdmin(true);
|
||||||
@ -169,8 +190,9 @@ const ListOfMembers = ({
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_member_admin', {
|
||||||
'Successfully made member an admin. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -187,13 +209,16 @@ const ListOfMembers = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingMakeAdmin(false);
|
setIsLoadingMakeAdmin(false);
|
||||||
}
|
}
|
||||||
@ -203,7 +228,10 @@ const ListOfMembers = ({
|
|||||||
try {
|
try {
|
||||||
const fee = await getFee('REMOVE_GROUP_ADMIN');
|
const fee = await getFee('REMOVE_GROUP_ADMIN');
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform a REMOVE_GROUP_ADMIN transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'REMOVE_GROUP_ADMIN',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoadingRemoveAdmin(true);
|
setIsLoadingRemoveAdmin(true);
|
||||||
@ -217,8 +245,9 @@ const ListOfMembers = ({
|
|||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_remove_member', {
|
||||||
'Successfully removed member as an admin. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -235,13 +264,16 @@ const ListOfMembers = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingRemoveAdmin(false);
|
setIsLoadingRemoveAdmin(false);
|
||||||
}
|
}
|
||||||
@ -276,13 +308,13 @@ const ListOfMembers = ({
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
alignItems: 'center',
|
||||||
height: '250px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: '250px',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isOwner && (
|
{isOwner && (
|
||||||
@ -293,48 +325,49 @@ const ListOfMembers = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => handleKick(member?.member)}
|
onClick={() => handleKick(member?.member)}
|
||||||
>
|
>
|
||||||
Kick member from group
|
{t('group:action.kick_member', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={isLoadingBan}
|
loading={isLoadingBan}
|
||||||
loadingPosition="start"
|
loadingPosition="start"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => handleBan(member?.member)}
|
onClick={() => handleBan(member?.member)}
|
||||||
>
|
>
|
||||||
Ban member from group
|
{t('group:action.ban', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={isLoadingMakeAdmin}
|
loading={isLoadingMakeAdmin}
|
||||||
loadingPosition="start"
|
loadingPosition="start"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => makeAdmin(member?.member)}
|
onClick={() => makeAdmin(member?.member)}
|
||||||
>
|
>
|
||||||
Make an admin
|
{t('group:action.make_admin', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={isLoadingRemoveAdmin}
|
loading={isLoadingRemoveAdmin}
|
||||||
loadingPosition="start"
|
loadingPosition="start"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => removeAdmin(member?.member)}
|
onClick={() => removeAdmin(member?.member)}
|
||||||
>
|
>
|
||||||
Remove as admin
|
{t('group:action.remove_admin', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
<ListItem
|
|
||||||
key={member?.member}
|
<ListItem key={member?.member} disablePadding>
|
||||||
// secondaryAction={
|
|
||||||
// <Checkbox
|
|
||||||
// edge="end"
|
|
||||||
// onChange={handleToggle(value)}
|
|
||||||
// checked={checked.indexOf(value) !== -1}
|
|
||||||
// inputProps={{ 'aria-labelledby': labelId }}
|
|
||||||
// />
|
|
||||||
// }
|
|
||||||
disablePadding
|
|
||||||
>
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={(event) => handlePopoverOpen(event, index)}
|
onClick={(event) => handlePopoverOpen(event, index)}
|
||||||
>
|
>
|
||||||
@ -348,6 +381,7 @@ const ListOfMembers = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
|
|
||||||
<ListItemText
|
<ListItemText
|
||||||
id={''}
|
id={''}
|
||||||
primary={member?.name || member?.member}
|
primary={member?.name || member?.member}
|
||||||
@ -359,7 +393,9 @@ const ListOfMembers = ({
|
|||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Admin
|
{t('core:admin', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
@ -372,28 +408,31 @@ const ListOfMembers = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Member list</p>
|
<p>
|
||||||
|
{t('core:list.member', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
|
||||||
height: '500px',
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
|
height: '500px',
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ height, width }) => (
|
{({ height, width }) => (
|
||||||
<List
|
<List
|
||||||
ref={listRef}
|
deferredMeasurementCache={cache}
|
||||||
width={width}
|
|
||||||
height={height}
|
height={height}
|
||||||
|
ref={listRef}
|
||||||
rowCount={members.length}
|
rowCount={members.length}
|
||||||
rowHeight={cache.rowHeight}
|
rowHeight={cache.rowHeight}
|
||||||
rowRenderer={rowRenderer}
|
rowRenderer={rowRenderer}
|
||||||
// onScroll={handleScroll}
|
width={width}
|
||||||
deferredMeasurementCache={cache}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</AutoSizer>
|
</AutoSizer>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as React from 'react';
|
import { useEffect, useState } 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';
|
||||||
@ -9,10 +9,12 @@ import { Box, Typography } from '@mui/material';
|
|||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { CustomLoader } from '../../common/CustomLoader';
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const ListOfThreadPostsWatched = () => {
|
export const ListOfThreadPostsWatched = () => {
|
||||||
const [posts, setPosts] = React.useState([]);
|
const [posts, setPosts] = useState([]);
|
||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const getPosts = async () => {
|
const getPosts = async () => {
|
||||||
try {
|
try {
|
||||||
@ -42,34 +44,38 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred'); // TODO translate
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
getPosts();
|
getPosts();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '322px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
|
width: '322px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -78,8 +84,12 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
New Thread Posts:
|
{t('group:thread_posts', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
:
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@ -97,9 +107,9 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
{loading && posts.length === 0 && (
|
{loading && posts.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CustomLoader />
|
<CustomLoader />
|
||||||
@ -108,11 +118,11 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
{!loading && posts.length === 0 && (
|
{!loading && posts.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -122,7 +132,9 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
color: 'rgba(255, 255, 255, 0.2)',
|
color: 'rgba(255, 255, 255, 0.2)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Nothing to display
|
{t('group:message.generic.no_display', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
@ -130,11 +142,11 @@ export const ListOfThreadPostsWatched = () => {
|
|||||||
<List
|
<List
|
||||||
className="scrollable-container"
|
className="scrollable-container"
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
maxWidth: 360,
|
|
||||||
bgcolor: 'background.paper',
|
bgcolor: 'background.paper',
|
||||||
maxHeight: '300px',
|
maxHeight: '300px',
|
||||||
|
maxWidth: 360,
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{posts?.map((post) => {
|
{posts?.map((post) => {
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
import * as React from 'react';
|
import {
|
||||||
|
forwardRef,
|
||||||
|
Fragment,
|
||||||
|
ReactElement,
|
||||||
|
Ref,
|
||||||
|
SyntheticEvent,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} 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 AppBar from '@mui/material/AppBar';
|
import AppBar from '@mui/material/AppBar';
|
||||||
@ -25,6 +35,7 @@ import { Spacer } from '../../common/Spacer';
|
|||||||
import InsertLinkIcon from '@mui/icons-material/InsertLink';
|
import InsertLinkIcon from '@mui/icons-material/InsertLink';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { txListAtom } from '../../atoms/global';
|
import { txListAtom } from '../../atoms/global';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
function a11yProps(index: number) {
|
function a11yProps(index: number) {
|
||||||
return {
|
return {
|
||||||
@ -33,37 +44,35 @@ function a11yProps(index: number) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transition = React.forwardRef(function Transition(
|
const Transition = forwardRef(function Transition(
|
||||||
props: TransitionProps & {
|
props: TransitionProps & {
|
||||||
children: React.ReactElement;
|
children: ReactElement;
|
||||||
},
|
},
|
||||||
ref: React.Ref<unknown>
|
ref: Ref<unknown>
|
||||||
) {
|
) {
|
||||||
return <Slide direction="up" ref={ref} {...props} />;
|
return <Slide direction="up" ref={ref} {...props} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ManageMembers = ({
|
export const ManageMembers = ({
|
||||||
address,
|
|
||||||
open,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
|
|
||||||
isAdmin,
|
isAdmin,
|
||||||
isOwner,
|
isOwner,
|
||||||
}) => {
|
}) => {
|
||||||
const [membersWithNames, setMembersWithNames] = React.useState([]);
|
const [membersWithNames, setMembersWithNames] = useState([]);
|
||||||
const [tab, setTab] = React.useState('create');
|
const [value, setValue] = useState(0);
|
||||||
const [value, setValue] = React.useState(0);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [openSnack, setOpenSnack] = React.useState(false);
|
const [infoSnack, setInfoSnack] = useState(null);
|
||||||
const [infoSnack, setInfoSnack] = React.useState(null);
|
const [isLoadingMembers, setIsLoadingMembers] = useState(false);
|
||||||
const [isLoadingMembers, setIsLoadingMembers] = React.useState(false);
|
const [isLoadingLeave, setIsLoadingLeave] = useState(false);
|
||||||
const [isLoadingLeave, setIsLoadingLeave] = React.useState(false);
|
const [groupInfo, setGroupInfo] = useState(null);
|
||||||
const [groupInfo, setGroupInfo] = React.useState(null);
|
const handleChange = (event: SyntheticEvent, newValue: number) => {
|
||||||
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
|
|
||||||
setValue(newValue);
|
setValue(newValue);
|
||||||
};
|
};
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { show } = React.useContext(MyContext);
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
const { show } = useContext(MyContext);
|
||||||
const setTxList = useSetAtom(txListAtom);
|
const setTxList = useSetAtom(txListAtom);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@ -75,7 +84,10 @@ export const ManageMembers = ({
|
|||||||
setIsLoadingLeave(true);
|
setIsLoadingLeave(true);
|
||||||
const fee = await getFee('LEAVE_GROUP');
|
const fee = await getFee('LEAVE_GROUP');
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform an LEAVE_GROUP transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'LEAVE_GROUP',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,8 +102,14 @@ export const ManageMembers = ({
|
|||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: 'leave-group',
|
type: 'leave-group',
|
||||||
label: `Left Group ${selectedGroup?.groupName}: awaiting confirmation`,
|
label: t('group:message.success.group_leave_name', {
|
||||||
labelDone: `Left Group ${selectedGroup?.groupName}: success!`,
|
group_name: selectedGroup?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
|
labelDone: t('group:message.success.group_leave_label', {
|
||||||
|
group_name: selectedGroup?.groupName,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
done: false,
|
done: false,
|
||||||
groupId: selectedGroup?.groupId,
|
groupId: selectedGroup?.groupId,
|
||||||
},
|
},
|
||||||
@ -100,8 +118,9 @@ export const ManageMembers = ({
|
|||||||
res(response);
|
res(response);
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_leave', {
|
||||||
'Successfully requested to leave group. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
return;
|
return;
|
||||||
@ -109,7 +128,10 @@ export const ManageMembers = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred'); // TODO translate
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -119,7 +141,7 @@ export const ManageMembers = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMembersWithNames = React.useCallback(async (groupId) => {
|
const getMembersWithNames = useCallback(async (groupId) => {
|
||||||
try {
|
try {
|
||||||
setIsLoadingMembers(true);
|
setIsLoadingMembers(true);
|
||||||
const res = await getGroupMembers(groupId);
|
const res = await getGroupMembers(groupId);
|
||||||
@ -139,6 +161,7 @@ export const ManageMembers = ({
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGroupInfo = async (groupId) => {
|
const getGroupInfo = async (groupId) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${getBaseApiReact()}/groups/${groupId}`);
|
const response = await fetch(`${getBaseApiReact()}/groups/${groupId}`);
|
||||||
@ -149,7 +172,7 @@ export const ManageMembers = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedGroup?.groupId) {
|
if (selectedGroup?.groupId) {
|
||||||
getMembers(selectedGroup?.groupId);
|
getMembers(selectedGroup?.groupId);
|
||||||
getGroupInfo(selectedGroup?.groupId);
|
getGroupInfo(selectedGroup?.groupId);
|
||||||
@ -160,7 +183,7 @@ export const ManageMembers = ({
|
|||||||
setValue(4);
|
setValue(4);
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent('openGroupJoinRequest', openGroupJoinRequestFunc);
|
subscribeToEvent('openGroupJoinRequest', openGroupJoinRequestFunc);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@ -169,7 +192,7 @@ export const ManageMembers = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<Fragment>
|
||||||
<Dialog
|
<Dialog
|
||||||
fullScreen
|
fullScreen
|
||||||
open={open}
|
open={open}
|
||||||
@ -184,18 +207,20 @@ export const ManageMembers = ({
|
|||||||
>
|
>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
|
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
|
||||||
Manage Members
|
{t('group:action.manage_members', { postProcess: 'capitalize' })}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
edge="start"
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleClose}
|
|
||||||
aria-label="close"
|
aria-label="close"
|
||||||
|
color="inherit"
|
||||||
|
edge="start"
|
||||||
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: theme.palette.background.default,
|
bgcolor: theme.palette.background.default,
|
||||||
@ -284,12 +309,19 @@ export const ManageMembers = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography>GroupId: {groupInfo?.groupId}</Typography>
|
<Typography>
|
||||||
|
{t('group:group.id', { postProcess: 'capitalize' })}:{' '}
|
||||||
<Typography>GroupName: {groupInfo?.groupName}</Typography>
|
{groupInfo?.groupId}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<Typography>
|
<Typography>
|
||||||
Number of members: {groupInfo?.memberCount}
|
{t('group:group.name', { postProcess: 'capitalize' })}:{' '}
|
||||||
|
{groupInfo?.groupName}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography>
|
||||||
|
{t('group:group.member_number', { postProcess: 'capitalize' })}:{' '}
|
||||||
|
{groupInfo?.memberCount}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
@ -301,7 +333,11 @@ export const ManageMembers = ({
|
|||||||
await navigator.clipboard.writeText(link);
|
await navigator.clipboard.writeText(link);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<InsertLinkIcon /> <Typography>Join Group Link</Typography>
|
<InsertLinkIcon />
|
||||||
|
|
||||||
|
<Typography>
|
||||||
|
{t('group:join_link', { postProcess: 'capitalize' })}
|
||||||
|
</Typography>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@ -315,10 +351,11 @@ export const ManageMembers = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleLeaveGroup}
|
onClick={handleLeaveGroup}
|
||||||
>
|
>
|
||||||
Leave Group
|
{t('group:action.leave_group', { postProcess: 'capitalize' })}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{value === 0 && (
|
{value === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -331,7 +368,7 @@ export const ManageMembers = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => getMembersWithNames(selectedGroup?.groupId)}
|
onClick={() => getMembersWithNames(selectedGroup?.groupId)}
|
||||||
>
|
>
|
||||||
Load members with names
|
{t('group:action.load_members', { postProcess: 'capitalize' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
@ -347,6 +384,7 @@ export const ManageMembers = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{value === 1 && (
|
{value === 1 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -426,10 +464,12 @@ export const ManageMembers = ({
|
|||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoadingMembers}
|
open={isLoadingMembers}
|
||||||
info={{
|
info={{
|
||||||
message: 'Loading member list with names... please wait.',
|
message: t('group:message.generic.loading_members', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</React.Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -11,12 +11,12 @@ 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';
|
||||||
import { CustomLoader } from '../../common/CustomLoader';
|
import { CustomLoader } from '../../common/CustomLoader';
|
||||||
|
|
||||||
import { mailsAtom, qMailLastEnteredTimestampAtom } from '../../atoms/global';
|
import { mailsAtom, qMailLastEnteredTimestampAtom } from '../../atoms/global';
|
||||||
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';
|
||||||
import MarkEmailUnreadIcon from '@mui/icons-material/MarkEmailUnread';
|
import MarkEmailUnreadIcon from '@mui/icons-material/MarkEmailUnread';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const isLessThanOneWeekOld = (timestamp) => {
|
export const isLessThanOneWeekOld = (timestamp) => {
|
||||||
// Current time in milliseconds
|
// Current time in milliseconds
|
||||||
@ -54,6 +54,7 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const getMails = useCallback(async () => {
|
const getMails = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -89,7 +90,10 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred'); // TODO translate
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -129,20 +133,20 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
sx={{
|
sx={{
|
||||||
width: '322px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
padding: '0px 20px',
|
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
|
padding: '0px 20px',
|
||||||
|
width: '322px',
|
||||||
}}
|
}}
|
||||||
onClick={() => setIsExpanded((prev) => !prev)}
|
onClick={() => setIsExpanded((prev) => !prev)}
|
||||||
>
|
>
|
||||||
@ -151,8 +155,9 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Latest Q-Mails
|
{t('group:latest_mails', { postProcess: 'capitalize' })}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<MarkEmailUnreadIcon
|
<MarkEmailUnreadIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: anyUnread
|
color: anyUnread
|
||||||
@ -195,9 +200,9 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
{loading && mails.length === 0 && (
|
{loading && mails.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CustomLoader />
|
<CustomLoader />
|
||||||
@ -206,11 +211,11 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
{!loading && mails.length === 0 && (
|
{!loading && mails.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -220,7 +225,9 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
|||||||
color: theme.palette.primary,
|
color: theme.palette.primary,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Nothing to display
|
{t('group:message.generic.no_display', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
@ -20,7 +20,6 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
ButtonBase,
|
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
DialogContentText,
|
||||||
@ -32,7 +31,6 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { enabledDevModeAtom } from '../../atoms/global';
|
import { enabledDevModeAtom } from '../../atoms/global';
|
||||||
|
|
||||||
import ThemeManager from '../Theme/ThemeManager';
|
import ThemeManager from '../Theme/ThemeManager';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { decryptStoredWallet } from '../../utils/decryptWallet';
|
import { decryptStoredWallet } from '../../utils/decryptWallet';
|
||||||
@ -41,6 +39,7 @@ import PhraseWallet from '../../utils/generateWallet/phrase-wallet';
|
|||||||
import { walletVersion } from '../../background';
|
import { walletVersion } from '../../background';
|
||||||
import Base58 from '../../deps/Base58';
|
import Base58 from '../../deps/Base58';
|
||||||
import { MyContext } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
|
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
|
||||||
padding: 8,
|
padding: 8,
|
||||||
@ -87,8 +86,8 @@ const Transition = forwardRef(function Transition(
|
|||||||
export const Settings = ({ open, setOpen, rawWallet }) => {
|
export const Settings = ({ open, setOpen, rawWallet }) => {
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
|
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
setChecked(event.target.checked);
|
setChecked(event.target.checked);
|
||||||
@ -103,7 +102,7 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
console.error('Error adding user settings:', response.error);
|
console.error('Error adding user settings:', response.error);
|
||||||
} else {
|
} else {
|
||||||
console.log('User settings added successfully'); // TODO translate
|
console.log('User settings added successfully');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -134,7 +133,10 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || 'An error occurred');
|
rej(
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' })
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -157,7 +159,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
<AppBar sx={{ position: 'relative' }}>
|
<AppBar sx={{ position: 'relative' }}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
|
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
|
||||||
General Settings
|
{t('core:general_settings', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -173,13 +177,13 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
flexGrow: 1,
|
|
||||||
overflowY: 'auto',
|
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
padding: '20px',
|
|
||||||
flexDirection: 'column',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexGrow: 1,
|
||||||
gap: '20px',
|
gap: '20px',
|
||||||
|
overflowY: 'auto',
|
||||||
|
padding: '20px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
@ -189,7 +193,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
control={
|
control={
|
||||||
<LocalNodeSwitch checked={checked} onChange={handleChange} />
|
<LocalNodeSwitch checked={checked} onChange={handleChange} />
|
||||||
}
|
}
|
||||||
label="Disable all push notifications"
|
label={t('group:action.disable_push_notifications', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
{window?.electronAPI && (
|
{window?.electronAPI && (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
@ -205,7 +211,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label="Enable dev mode"
|
label={t('group:action.enable_dev_mode', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isEnabledDevMode && <ExportPrivateKey rawWallet={rawWallet} />}
|
{isEnabledDevMode && <ExportPrivateKey rawWallet={rawWallet} />}
|
||||||
@ -220,13 +228,16 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [privateKey, setPrivateKey] = useState('');
|
const [privateKey, setPrivateKey] = useState('');
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext);
|
const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext);
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const exportPrivateKeyFunc = async () => {
|
const exportPrivateKeyFunc = async () => {
|
||||||
try {
|
try {
|
||||||
setInfoSnackCustom({
|
setInfoSnackCustom({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'Decrypting wallet...',
|
message: t('group:message.generic.descrypt_wallet', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
setOpenSnackGlobal(true);
|
setOpenSnackGlobal(true);
|
||||||
@ -247,13 +258,19 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
setInfoSnackCustom({
|
setInfoSnackCustom({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error?.message
|
message: error?.message
|
||||||
? `Error decrypting wallet: ${error?.message}`
|
? t('group:message.error.decrypt_wallet', {
|
||||||
: 'Error decrypting wallet',
|
errorMessage: error?.message,
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})
|
||||||
|
: t('group:message.error.descrypt_wallet', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
setOpenSnackGlobal(true);
|
setOpenSnackGlobal(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
@ -263,14 +280,22 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
}}
|
}}
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
Export private key
|
{t('group:action.export_private_key', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
aria-labelledby="alert-dialog-title"
|
aria-labelledby="alert-dialog-title"
|
||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">Export password</DialogTitle>
|
<DialogTitle id="alert-dialog-title">
|
||||||
|
{t('group:action.export_password', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -279,9 +304,13 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
Keep your private key in a secure place. Do not share!
|
{t('group:message.generic.secure_place', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
autoFocus
|
autoFocus
|
||||||
type="password"
|
type="password"
|
||||||
@ -296,17 +325,22 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
navigator.clipboard.writeText(privateKey);
|
navigator.clipboard.writeText(privateKey);
|
||||||
setInfoSnackCustom({
|
setInfoSnackCustom({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: 'Copied privated key',
|
message: t('group:message.generic.private_key_copied', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
setOpenSnackGlobal(true);
|
setOpenSnackGlobal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`Copy private key `}
|
{t('group:action.copy_private_key', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}{' '}
|
||||||
<ContentCopyIcon color="primary" />
|
<ContentCopyIcon color="primary" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
@ -316,10 +350,15 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
|||||||
setPrivateKey('');
|
setPrivateKey('');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Cancel
|
{t('group:action.cancel', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button variant="contained" onClick={exportPrivateKeyFunc}>
|
<Button variant="contained" onClick={exportPrivateKeyFunc}>
|
||||||
Decrypt
|
{t('group:action.decrypt', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as React from 'react';
|
import { useEffect, useMemo, useState } 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';
|
||||||
@ -17,27 +17,27 @@ export const ThingsToDoInitial = ({
|
|||||||
balance,
|
balance,
|
||||||
userInfo,
|
userInfo,
|
||||||
}) => {
|
}) => {
|
||||||
const [checked1, setChecked1] = React.useState(false);
|
const [checked1, setChecked1] = useState(false);
|
||||||
const [checked2, setChecked2] = React.useState(false);
|
const [checked2, setChecked2] = useState(false);
|
||||||
const { t } = useTranslation(['core', 'tutorial']);
|
const { t } = useTranslation(['core', 'tutorial']);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (balance && +balance >= 6) {
|
if (balance && +balance >= 6) {
|
||||||
setChecked1(true);
|
setChecked1(true);
|
||||||
}
|
}
|
||||||
}, [balance]);
|
}, [balance]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (name) setChecked2(true);
|
if (name) setChecked2(true);
|
||||||
}, [name]);
|
}, [name]);
|
||||||
|
|
||||||
const isLoaded = React.useMemo(() => {
|
const isLoaded = useMemo(() => {
|
||||||
if (userInfo !== null) return true;
|
if (userInfo !== null) return true;
|
||||||
return false;
|
return false;
|
||||||
}, [userInfo]);
|
}, [userInfo]);
|
||||||
|
|
||||||
const hasDoneNameAndBalanceAndIsLoaded = React.useMemo(() => {
|
const hasDoneNameAndBalanceAndIsLoaded = useMemo(() => {
|
||||||
if (isLoaded && checked1 && checked2) return true;
|
if (isLoaded && checked1 && checked2) return true;
|
||||||
return false;
|
return false;
|
||||||
}, [checked1, isLoaded, checked2]);
|
}, [checked1, isLoaded, checked2]);
|
||||||
@ -55,18 +55,18 @@ export const ThingsToDoInitial = ({
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '322px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: '0px 20px',
|
padding: '0px 20px',
|
||||||
|
width: '322px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -125,6 +125,7 @@ export const ThingsToDoInitial = ({
|
|||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ListItemIcon
|
<ListItemIcon
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
@ -144,6 +145,7 @@ export const ThingsToDoInitial = ({
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<ListItem
|
<ListItem
|
||||||
sx={{
|
sx={{
|
||||||
marginBottom: '20px',
|
marginBottom: '20px',
|
||||||
|
@ -22,6 +22,7 @@ import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmail
|
|||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { txListAtom } from '../../atoms/global';
|
import { txListAtom } from '../../atoms/global';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const cache = new CellMeasurerCache({
|
const cache = new CellMeasurerCache({
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
@ -60,9 +61,10 @@ export const UserListOfInvites = ({
|
|||||||
const [invites, setInvites] = useState<any[]>([]);
|
const [invites, setInvites] = useState<any[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation(['core', 'group']);
|
||||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
|
||||||
const listRef = useRef();
|
const listRef = useRef(null);
|
||||||
|
|
||||||
const getRequests = async () => {
|
const getRequests = async () => {
|
||||||
try {
|
try {
|
||||||
@ -94,9 +96,13 @@ export const UserListOfInvites = ({
|
|||||||
|
|
||||||
const handleJoinGroup = async (groupId, groupName) => {
|
const handleJoinGroup = async (groupId, groupName) => {
|
||||||
try {
|
try {
|
||||||
const fee = await getFee('JOIN_GROUP'); // TODO translate
|
const fee = await getFee('JOIN_GROUP');
|
||||||
|
|
||||||
await show({
|
await show({
|
||||||
message: 'Would you like to perform an JOIN_GROUP transaction?',
|
message: t('group:question.perform_transaction', {
|
||||||
|
action: 'JOIN_GROUP',
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
publishFee: fee.fee + ' QORT',
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,8 +129,9 @@ export const UserListOfInvites = ({
|
|||||||
res(response);
|
res(response);
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message:
|
message: t('group:message.success.group_join', {
|
||||||
'Successfully requested to join group. It may take a couple of minutes for the changes to propagate',
|
postProcess: 'capitalize',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
handlePopoverClose();
|
handlePopoverClose();
|
||||||
@ -140,13 +147,16 @@ export const UserListOfInvites = ({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: error.message || 'An error occurred',
|
message:
|
||||||
|
error.message ||
|
||||||
|
t('core:message.error.generic', { postProcess: 'capitalize' }),
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@ -182,16 +192,22 @@ export const UserListOfInvites = ({
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '325px',
|
alignItems: 'center',
|
||||||
height: '250px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: '250px',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '325px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>Join {invite?.groupName}</Typography>
|
<Typography>
|
||||||
|
{t('core:action.join', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}{' '}
|
||||||
|
{invite?.groupName}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
loadingPosition="start"
|
loadingPosition="start"
|
||||||
@ -200,10 +216,13 @@ export const UserListOfInvites = ({
|
|||||||
handleJoinGroup(invite?.groupId, invite?.groupName)
|
handleJoinGroup(invite?.groupId, invite?.groupName)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Join group
|
{t('group:action.join_group', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={(event) => handlePopoverOpen(event, index)}
|
onClick={(event) => handlePopoverOpen(event, index)}
|
||||||
>
|
>
|
||||||
@ -221,7 +240,9 @@ export const UserListOfInvites = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Spacer width="15px" />
|
<Spacer width="15px" />
|
||||||
|
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={invite?.groupName}
|
primary={invite?.groupName}
|
||||||
secondary={invite?.description}
|
secondary={invite?.description}
|
||||||
@ -242,14 +263,19 @@ export const UserListOfInvites = ({
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>Invite list</p>
|
<p>
|
||||||
|
{t('core:list.invite', {
|
||||||
|
postProcess: 'capitalize',
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
position: 'relative',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Box, ButtonBase, Divider, Typography, useTheme } from '@mui/material';
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { Box, ButtonBase, Divider, Typography, useTheme } from '@mui/material';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import AppViewerContainer from '../Apps/AppViewerContainer';
|
import AppViewerContainer from '../Apps/AppViewerContainer';
|
||||||
import {
|
import {
|
||||||
@ -19,7 +19,6 @@ export const WalletsAppWrapper = () => {
|
|||||||
const [navigationController, setNavigationController] = useAtom(
|
const [navigationController, setNavigationController] = useAtom(
|
||||||
navigationControllerAtom
|
navigationControllerAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
const [selectedTab, setSelectedTab] = useState({
|
const [selectedTab, setSelectedTab] = useState({
|
||||||
tabId: '5558589',
|
tabId: '5558589',
|
||||||
name: 'Q-Wallets',
|
name: 'Q-Wallets',
|
||||||
@ -60,17 +59,17 @@ export const WalletsAppWrapper = () => {
|
|||||||
{isOpen && (
|
{isOpen && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'fixed',
|
backgroundColor: theme.palette.background.paper,
|
||||||
height: '100vh',
|
|
||||||
width: '100vw',
|
|
||||||
backgroundColor: theme.palette.background.paper, // TODO: set color theme
|
|
||||||
zIndex: 100,
|
|
||||||
bottom: 0,
|
|
||||||
right: 0,
|
|
||||||
overflow: 'hidden',
|
|
||||||
borderTopLeftRadius: '10px',
|
borderTopLeftRadius: '10px',
|
||||||
borderTopRightRadius: '10px',
|
borderTopRightRadius: '10px',
|
||||||
|
bottom: 0,
|
||||||
boxShadow: 4,
|
boxShadow: 4,
|
||||||
|
height: '100vh',
|
||||||
|
overflow: 'hidden',
|
||||||
|
position: 'fixed',
|
||||||
|
right: 0,
|
||||||
|
width: '100vw',
|
||||||
|
zIndex: 100,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@ -85,11 +84,11 @@ export const WalletsAppWrapper = () => {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '5px',
|
padding: '5px',
|
||||||
|
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>Q-Wallets</Typography>
|
<Typography>Q-Wallets</Typography>
|
||||||
|
|
||||||
<ButtonBase onClick={handleClose}>
|
<ButtonBase onClick={handleClose}>
|
||||||
<CloseIcon
|
<CloseIcon
|
||||||
sx={{
|
sx={{
|
||||||
@ -108,6 +107,7 @@ export const WalletsAppWrapper = () => {
|
|||||||
ref={iframeRef}
|
ref={iframeRef}
|
||||||
skipAuth={true}
|
skipAuth={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AppsNavBarParent>
|
<AppsNavBarParent>
|
||||||
<AppsNavBarLeft
|
<AppsNavBarLeft
|
||||||
sx={{
|
sx={{
|
||||||
@ -126,6 +126,7 @@ export const WalletsAppWrapper = () => {
|
|||||||
>
|
>
|
||||||
<NavBack />
|
<NavBack />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (selectedTab?.refreshFunc) {
|
if (selectedTab?.refreshFunc) {
|
||||||
|
@ -164,6 +164,7 @@ export const useBlockedAddresses = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address) {
|
if (address) {
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
import { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
import Logo2 from '../assets/svgs/Logo2.svg';
|
import Logo2 from '../assets/svgs/Logo2.svg';
|
||||||
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
|
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
|
||||||
import {
|
import {
|
||||||
|
@ -36,7 +36,7 @@ export const NewUsersCTA = ({ balance }) => {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('core:new_user', { postProcess: 'capitalize' })}
|
{t('core:question.new_user', { postProcess: 'capitalize' })}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
@ -168,6 +168,7 @@ export const QortPrice = () => {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -198,6 +199,7 @@ export const QortPrice = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<span style={{ fontSize: '14px', fontWeight: 700 }}>
|
<span style={{ fontSize: '14px', fontWeight: 700 }}>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import { Box, CircularProgress } from '@mui/material';
|
||||||
import { Box, CircularProgress } from "@mui/material";
|
|
||||||
|
|
||||||
export const Loader = () => {
|
export const Loader = () => {
|
||||||
return (
|
return (
|
||||||
<Box sx={{
|
<Box
|
||||||
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -11,13 +11,14 @@ export const Loader = () => {
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: '0px',
|
top: '0px',
|
||||||
left:'0px',
|
left: '0px',
|
||||||
right: '0px',
|
right: '0px',
|
||||||
bottom: '0px',
|
bottom: '0px',
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
background: 'rgba(0, 0, 0, 0.4)'
|
background: 'rgba(0, 0, 0, 0.4)',
|
||||||
}}>
|
}}
|
||||||
<CircularProgress color="success" size={25} />
|
>
|
||||||
|
<CircularProgress color="success" size={25} />
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import { useContext, useEffect, useState } from 'react';
|
||||||
import Logo2 from '../assets/svgs/Logo2.svg';
|
import Logo2 from '../assets/svgs/Logo2.svg';
|
||||||
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
|
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
|
||||||
import {
|
import {
|
||||||
|
@ -1,33 +1,22 @@
|
|||||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
ButtonBase,
|
|
||||||
Collapse,
|
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Input,
|
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemAvatar,
|
|
||||||
ListItemButton,
|
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
List,
|
List,
|
||||||
MenuItem,
|
|
||||||
Popover,
|
|
||||||
Select,
|
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Label } from './Group/AddGroup';
|
import { Label } from './Group/AddGroup';
|
||||||
import { Spacer } from '../common/Spacer';
|
import { Spacer } from '../common/Spacer';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { getBaseApiReact } from '../App';
|
||||||
import { getBaseApiReact, MyContext } from '../App';
|
|
||||||
import { getFee } from '../background';
|
import { getFee } from '../background';
|
||||||
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
|
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
|
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
|
||||||
@ -43,6 +32,7 @@ enum Availability {
|
|||||||
AVAILABLE = 'available',
|
AVAILABLE = 'available',
|
||||||
NOT_AVAILABLE = 'not-available',
|
NOT_AVAILABLE = 'not-available',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RegisterName = ({
|
export const RegisterName = ({
|
||||||
setOpenSnack,
|
setOpenSnack,
|
||||||
setInfoSnack,
|
setInfoSnack,
|
||||||
@ -77,7 +67,6 @@ export const RegisterName = ({
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
} finally {
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Debounce logic
|
// Debounce logic
|
||||||
@ -195,21 +184,22 @@ export const RegisterName = ({
|
|||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle>
|
<DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle>
|
||||||
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '400px',
|
alignItems: 'center',
|
||||||
maxWidth: '90vw',
|
|
||||||
height: '500px',
|
|
||||||
maxHeight: '90vh',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
|
||||||
gap: '10px',
|
gap: '10px',
|
||||||
|
height: '500px',
|
||||||
|
maxHeight: '90vh',
|
||||||
|
maxWidth: '90vw',
|
||||||
padding: '10px',
|
padding: '10px',
|
||||||
|
width: '400px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Label>Choose a name</Label>
|
<Label>Choose a name</Label> // TODO: translate
|
||||||
<TextField
|
<TextField
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
@ -237,6 +227,7 @@ export const RegisterName = ({
|
|||||||
requires a {nameFee} QORT fee
|
requires a {nameFee} QORT fee
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Spacer height="10px" />
|
<Spacer height="10px" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -307,6 +298,7 @@ export const RegisterName = ({
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
|
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<RadioButtonCheckedIcon
|
<RadioButtonCheckedIcon
|
||||||
@ -320,6 +312,7 @@ export const RegisterName = ({
|
|||||||
</List>
|
</List>
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
disabled={isLoadingRegisterName}
|
disabled={isLoadingRegisterName}
|
||||||
@ -331,6 +324,7 @@ export const RegisterName = ({
|
|||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
disabled={
|
disabled={
|
||||||
!registerNameValue.trim() ||
|
!registerNameValue.trim() ||
|
||||||
|
@ -8,15 +8,14 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip .bottom {
|
.tooltip .core-panel {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--black);
|
border: 1px solid var(--black);
|
||||||
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.5);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
max-width: 250px;
|
width: max-content;
|
||||||
min-width: 225px;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
padding: 10px 10px;
|
padding: 10px 10px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -27,23 +26,23 @@
|
|||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip[data-theme='light'] .bottom {
|
.tooltip[data-theme='light'] .core-panel {
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip[data-theme='dark'] .bottom {
|
.tooltip[data-theme='dark'] .core-panel {
|
||||||
background-color: var(--bg-2);
|
background-color: var(--bg-2);
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip:hover .bottom {
|
.tooltip:hover .core-panel {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip .bottom i {
|
.tooltip .core-panel i {
|
||||||
bottom: 100%;
|
bottom: 100%;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
@ -56,6 +56,7 @@ const commonThemeOptions = {
|
|||||||
xl: 1536,
|
xl: 1536,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
MuiButton: {
|
MuiButton: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
@ -72,6 +73,7 @@ const commonThemeOptions = {
|
|||||||
disableRipple: true,
|
disableRipple: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiModal: {
|
MuiModal: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
|
@ -48,6 +48,7 @@ export const darkThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiCssBaseline: {
|
MuiCssBaseline: {
|
||||||
styleOverrides: (theme) => ({
|
styleOverrides: (theme) => ({
|
||||||
':root': {
|
':root': {
|
||||||
@ -61,13 +62,16 @@ export const darkThemeOptions: ThemeOptions = {
|
|||||||
'--background-paper': theme.palette.background.paper,
|
'--background-paper': theme.palette.background.paper,
|
||||||
'--background-surface': theme.palette.background.surface,
|
'--background-surface': theme.palette.background.surface,
|
||||||
},
|
},
|
||||||
|
|
||||||
'*, *::before, *::after': {
|
'*, *::before, *::after': {
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
},
|
},
|
||||||
|
|
||||||
html: {
|
html: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
body: {
|
body: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
@ -100,6 +104,7 @@ export const darkThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiIcon: {
|
MuiIcon: {
|
||||||
defaultProps: {
|
defaultProps: {
|
||||||
style: {
|
style: {
|
||||||
@ -108,6 +113,7 @@ export const darkThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiDialog: {
|
MuiDialog: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
paper: {
|
paper: {
|
||||||
@ -115,6 +121,7 @@ export const darkThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiPopover: {
|
MuiPopover: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
paper: {
|
paper: {
|
||||||
|
@ -32,6 +32,7 @@ export const lightThemeOptions: ThemeOptions = {
|
|||||||
unread: 'rgb(66, 151, 226)',
|
unread: 'rgb(66, 151, 226)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
MuiCard: {
|
MuiCard: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
@ -48,6 +49,7 @@ export const lightThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiCssBaseline: {
|
MuiCssBaseline: {
|
||||||
styleOverrides: (theme) => ({
|
styleOverrides: (theme) => ({
|
||||||
':root': {
|
':root': {
|
||||||
@ -113,6 +115,7 @@ export const lightThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiDialog: {
|
MuiDialog: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
paper: {
|
paper: {
|
||||||
@ -120,6 +123,7 @@ export const lightThemeOptions: ThemeOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
MuiPopover: {
|
MuiPopover: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
paper: {
|
paper: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user