mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-23 19:37:52 +00:00
blocking
This commit is contained in:
parent
19b183aabf
commit
ce530293ab
16
src/App.tsx
16
src/App.tsx
@ -143,6 +143,7 @@ import { Minting } from "./components/Minting/Minting";
|
|||||||
import { isRunningGateway } from "./qortalRequests";
|
import { isRunningGateway } from "./qortalRequests";
|
||||||
import { QMailStatus } from "./components/QMailStatus";
|
import { QMailStatus } from "./components/QMailStatus";
|
||||||
import { GlobalActions } from "./components/GlobalActions/GlobalActions";
|
import { GlobalActions } from "./components/GlobalActions/GlobalActions";
|
||||||
|
import { useBlockedAddresses } from "./components/Group/useBlockUsers";
|
||||||
|
|
||||||
type extStates =
|
type extStates =
|
||||||
| "not-authenticated"
|
| "not-authenticated"
|
||||||
@ -402,6 +403,9 @@ function App() {
|
|||||||
const [isOpenSendQort, setIsOpenSendQort] = useState(false);
|
const [isOpenSendQort, setIsOpenSendQort] = useState(false);
|
||||||
const [isOpenSendQortSuccess, setIsOpenSendQortSuccess] = useState(false);
|
const [isOpenSendQortSuccess, setIsOpenSendQortSuccess] = useState(false);
|
||||||
const [rootHeight, setRootHeight] = useState("100%");
|
const [rootHeight, setRootHeight] = useState("100%");
|
||||||
|
const {isUserBlocked,
|
||||||
|
addToBlockList,
|
||||||
|
removeBlockFromList, getAllBlockedUsers} = useBlockedAddresses()
|
||||||
const [currentNode, setCurrentNode] = useState({
|
const [currentNode, setCurrentNode] = useState({
|
||||||
url: "http://127.0.0.1:12391",
|
url: "http://127.0.0.1:12391",
|
||||||
});
|
});
|
||||||
@ -1630,7 +1634,11 @@ function App() {
|
|||||||
infoSnackCustom: infoSnack,
|
infoSnackCustom: infoSnack,
|
||||||
setInfoSnackCustom: setInfoSnack,
|
setInfoSnackCustom: setInfoSnack,
|
||||||
downloadResource,
|
downloadResource,
|
||||||
getIndividualUserInfo
|
getIndividualUserInfo,
|
||||||
|
isUserBlocked,
|
||||||
|
addToBlockList,
|
||||||
|
removeBlockFromList,
|
||||||
|
getAllBlockedUsers
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TaskManager getUserInfo={getUserInfo} />
|
<TaskManager getUserInfo={getUserInfo} />
|
||||||
@ -1751,7 +1759,11 @@ function App() {
|
|||||||
infoSnackCustom: infoSnack,
|
infoSnackCustom: infoSnack,
|
||||||
setInfoSnackCustom: setInfoSnack,
|
setInfoSnackCustom: setInfoSnack,
|
||||||
downloadResource,
|
downloadResource,
|
||||||
getIndividualUserInfo
|
getIndividualUserInfo,
|
||||||
|
isUserBlocked,
|
||||||
|
addToBlockList,
|
||||||
|
removeBlockFromList,
|
||||||
|
getAllBlockedUsers
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
checkNewMessages,
|
checkNewMessages,
|
||||||
checkThreads,
|
checkThreads,
|
||||||
clearAllNotifications,
|
clearAllNotifications,
|
||||||
|
createEndpoint,
|
||||||
createGroup,
|
createGroup,
|
||||||
decryptDirectFunc,
|
decryptDirectFunc,
|
||||||
decryptSingleForPublishes,
|
decryptSingleForPublishes,
|
||||||
@ -1284,6 +1285,85 @@ export async function getTimestampEnterChatCase(request, event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listActionsCase(request, event) {
|
||||||
|
try {
|
||||||
|
const { type, listName = '', items = [] } = request.payload;
|
||||||
|
let responseData
|
||||||
|
|
||||||
|
if(type === 'get'){
|
||||||
|
const url = await createEndpoint(`/lists/${listName}`);
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) throw new Error("Failed to fetch");
|
||||||
|
|
||||||
|
responseData = await response.json();
|
||||||
|
} else if(type === 'remove'){
|
||||||
|
const url = await createEndpoint(`/lists/${listName}`);
|
||||||
|
const body = {
|
||||||
|
items: items ,
|
||||||
|
};
|
||||||
|
const bodyToString = JSON.stringify(body);
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: bodyToString,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error("Failed to remove from list");
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await response.clone().json();
|
||||||
|
} catch (e) {
|
||||||
|
res = await response.text();
|
||||||
|
}
|
||||||
|
responseData = res;
|
||||||
|
} else if(type === 'add'){
|
||||||
|
const url = await createEndpoint(`/lists/${listName}`);
|
||||||
|
const body = {
|
||||||
|
items: items ,
|
||||||
|
};
|
||||||
|
const bodyToString = JSON.stringify(body);
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: bodyToString,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error("Failed to add to list");
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await response.clone().json();
|
||||||
|
} catch (e) {
|
||||||
|
res = await response.text();
|
||||||
|
}
|
||||||
|
responseData = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "listActions",
|
||||||
|
payload: responseData,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "listActions",
|
||||||
|
error: error?.message,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTimestampMentionCase(request, event) {
|
export async function getTimestampMentionCase(request, event) {
|
||||||
try {
|
try {
|
||||||
const response = await getTimestampMention();
|
const response = await getTimestampMention();
|
||||||
|
@ -74,6 +74,7 @@ import {
|
|||||||
joinGroupCase,
|
joinGroupCase,
|
||||||
kickFromGroupCase,
|
kickFromGroupCase,
|
||||||
leaveGroupCase,
|
leaveGroupCase,
|
||||||
|
listActionsCase,
|
||||||
ltcBalanceCase,
|
ltcBalanceCase,
|
||||||
makeAdminCase,
|
makeAdminCase,
|
||||||
nameCase,
|
nameCase,
|
||||||
@ -3022,6 +3023,9 @@ function setupMessageListener() {
|
|||||||
case "getTimestampEnterChat":
|
case "getTimestampEnterChat":
|
||||||
getTimestampEnterChatCase(request, event);
|
getTimestampEnterChatCase(request, event);
|
||||||
break;
|
break;
|
||||||
|
case "listActions":
|
||||||
|
listActionsCase(request, event);
|
||||||
|
break;
|
||||||
case "addTimestampMention":
|
case "addTimestampMention":
|
||||||
addTimestampMentionCase(request, event);
|
addTimestampMentionCase(request, event);
|
||||||
break;
|
break;
|
||||||
@ -3154,9 +3158,16 @@ const checkGroupList = async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
const copyGroups = [...(data?.groups || [])]
|
||||||
|
const findIndex = copyGroups?.findIndex(item => item?.groupId === 0)
|
||||||
|
if(findIndex !== -1){
|
||||||
|
copyGroups[findIndex] = {
|
||||||
|
...(copyGroups[findIndex] || {}),
|
||||||
|
groupId: "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const filteredGroups = copyGroups
|
||||||
|
|
||||||
const filteredGroups =
|
|
||||||
data.groups?.filter((item) => item?.groupId !== 0) || [];
|
|
||||||
const sortedGroups = filteredGroups.sort(
|
const sortedGroups = filteredGroups.sort(
|
||||||
(a, b) => (b.timestamp || 0) - (a.timestamp || 0)
|
(a, b) => (b.timestamp || 0) - (a.timestamp || 0)
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'
|
import React, { useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react'
|
||||||
import { CreateCommonSecret } from './CreateCommonSecret'
|
import { CreateCommonSecret } from './CreateCommonSecret'
|
||||||
import { reusableGet } from '../../qdn/publish/pubish'
|
import { reusableGet } from '../../qdn/publish/pubish'
|
||||||
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'
|
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'
|
||||||
@ -10,11 +10,11 @@ import Tiptap from './TipTap'
|
|||||||
import { CustomButton } from '../../App-styles'
|
import { CustomButton } from '../../App-styles'
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar'
|
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar'
|
||||||
import { getBaseApiReact, getBaseApiReactSocket, isMobile, pauseAllQueues, resumeAllQueues } from '../../App'
|
import { getBaseApiReact, getBaseApiReactSocket, isMobile, MyContext, pauseAllQueues, resumeAllQueues } from '../../App'
|
||||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar'
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar'
|
||||||
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/codes'
|
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/codes'
|
||||||
import { useMessageQueue } from '../../MessageQueueContext'
|
import { useMessageQueue } from '../../MessageQueueContext'
|
||||||
import { executeEvent } from '../../utils/events'
|
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events'
|
||||||
import { Box, ButtonBase, Divider, Typography } from '@mui/material'
|
import { Box, ButtonBase, Divider, Typography } from '@mui/material'
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import { ReplyPreview } from './MessageItem'
|
import { ReplyPreview } from './MessageItem'
|
||||||
@ -28,6 +28,7 @@ import { throttle } from 'lodash'
|
|||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
||||||
export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey, myAddress, handleNewEncryptionNotification, hide, handleSecretKeyCreationInProgress, triedToFetchSecretKey, myName, balance, getTimestampEnterChatParent, hideView, isPrivate}) => {
|
export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey, myAddress, handleNewEncryptionNotification, hide, handleSecretKeyCreationInProgress, triedToFetchSecretKey, myName, balance, getTimestampEnterChatParent, hideView, isPrivate}) => {
|
||||||
|
const {isUserBlocked} = useContext(MyContext)
|
||||||
const [messages, setMessages] = useState([])
|
const [messages, setMessages] = useState([])
|
||||||
const [chatReferences, setChatReferences] = useState({})
|
const [chatReferences, setChatReferences] = useState({})
|
||||||
const [isSending, setIsSending] = useState(false)
|
const [isSending, setIsSending] = useState(false)
|
||||||
@ -158,10 +159,28 @@ const [messageSize, setMessageSize] = useState(0)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateChatMessagesWithBlocksFunc = (e) => {
|
||||||
|
if(e.detail){
|
||||||
|
setMessages((prev)=> prev?.filter((item)=> {
|
||||||
|
return !isUserBlocked(item?.sender, item?.senderName)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent("updateChatMessagesWithBlocks", updateChatMessagesWithBlocksFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent("updateChatMessagesWithBlocks", updateChatMessagesWithBlocksFunc);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const middletierFunc = async (data: any, groupId: string) => {
|
const middletierFunc = async (data: any, groupId: string) => {
|
||||||
try {
|
try {
|
||||||
if (hasInitialized.current) {
|
if (hasInitialized.current) {
|
||||||
decryptMessages(data, true);
|
const dataRemovedBlock = data?.filter((item)=> !isUserBlocked(item?.sender, item?.senderName))
|
||||||
|
|
||||||
|
decryptMessages(dataRemovedBlock, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
@ -173,7 +192,11 @@ const [messageSize, setMessageSize] = useState(0)
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
decryptMessages(responseData, false);
|
const dataRemovedBlock = responseData?.filter((item)=> {
|
||||||
|
return !isUserBlocked(item?.sender, item?.senderName)
|
||||||
|
})
|
||||||
|
|
||||||
|
decryptMessages(dataRemovedBlock, false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
@ -132,13 +132,16 @@ const onSeenFunc = useCallback(()=> {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}>
|
<>
|
||||||
|
{message?.divide && (
|
||||||
{message?.divide && (
|
|
||||||
<div className="unread-divider" id="unread-divider-id">
|
<div className="unread-divider" id="unread-divider-id">
|
||||||
Unread messages below
|
Unread messages below
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}>
|
||||||
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "10px",
|
padding: "10px",
|
||||||
@ -492,6 +495,7 @@ const onSeenFunc = useCallback(()=> {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</MessageWragger>
|
</MessageWragger>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
190
src/components/Group/BlockedUsersModal.tsx
Normal file
190
src/components/Group/BlockedUsersModal.tsx
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
|
import { MyContext } from "../../App";
|
||||||
|
import { Spacer } from "../../common/Spacer";
|
||||||
|
import { executeEvent } from "../../utils/events";
|
||||||
|
|
||||||
|
export const BlockedUsersModal = ({ close }) => {
|
||||||
|
const [hasChanged, setHasChanged] = useState(false);
|
||||||
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
|
const { getAllBlockedUsers, removeBlockFromList, addToBlockList } = useContext(MyContext);
|
||||||
|
const [blockedUsers, setBlockedUsers] = useState({
|
||||||
|
addresses: {},
|
||||||
|
names: {},
|
||||||
|
});
|
||||||
|
const fetchBlockedUsers = () => {
|
||||||
|
setBlockedUsers(getAllBlockedUsers());
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchBlockedUsers();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={true}
|
||||||
|
aria-labelledby="alert-dialog-title"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
>
|
||||||
|
<DialogTitle>Blocked Users</DialogTitle>
|
||||||
|
<DialogContent sx={{
|
||||||
|
padding: '20px'
|
||||||
|
}}>
|
||||||
|
<Box
|
||||||
|
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
placeholder="Name"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
setValue(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button variant="contained" onClick={async ()=> {
|
||||||
|
try {
|
||||||
|
if(!value) return
|
||||||
|
await addToBlockList(undefined, value)
|
||||||
|
fetchBlockedUsers()
|
||||||
|
setHasChanged(true)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}}>Block</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{Object.entries(blockedUsers?.addresses).length > 0 && (
|
||||||
|
<>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
Blocked Users for Chat ( addresses )
|
||||||
|
</DialogContentText>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '10px'
|
||||||
|
}}>
|
||||||
|
{Object.entries(blockedUsers?.addresses || {})?.map(
|
||||||
|
([key, value]) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "10px",
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>{key}</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
await removeBlockFromList(key, undefined);
|
||||||
|
setHasChanged(true);
|
||||||
|
setValue('')
|
||||||
|
fetchBlockedUsers();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Unblock
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{Object.entries(blockedUsers?.names).length > 0 && (
|
||||||
|
<>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
Blocked Users for QDN and Chat (names)
|
||||||
|
</DialogContentText>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '10px'
|
||||||
|
}}>
|
||||||
|
{Object.entries(blockedUsers?.names || {})?.map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "10px",
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>{key}</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
await removeBlockFromList(undefined, key);
|
||||||
|
setHasChanged(true);
|
||||||
|
fetchBlockedUsers();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Unblock
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "var(--green)",
|
||||||
|
color: "black",
|
||||||
|
fontWeight: "bold",
|
||||||
|
opacity: 0.7,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "var(--green)",
|
||||||
|
color: "black",
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
onClick={()=> {
|
||||||
|
if(hasChanged){
|
||||||
|
executeEvent('updateChatMessagesWithBlocks', true)
|
||||||
|
}
|
||||||
|
close()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
close
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@ -77,9 +77,10 @@ import { AdminSpace } from "../Chat/AdminSpace";
|
|||||||
import { useSetRecoilState } from "recoil";
|
import { useSetRecoilState } from "recoil";
|
||||||
import { addressInfoControllerAtom, selectedGroupIdAtom } from "../../atoms/global";
|
import { addressInfoControllerAtom, selectedGroupIdAtom } from "../../atoms/global";
|
||||||
import { sortArrayByTimestampAndGroupName } from "../../utils/time";
|
import { sortArrayByTimestampAndGroupName } from "../../utils/time";
|
||||||
|
import BlockIcon from '@mui/icons-material/Block';
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
||||||
|
import { BlockedUsersModal } from "./BlockedUsersModal";
|
||||||
|
|
||||||
|
|
||||||
export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
||||||
@ -419,6 +420,8 @@ export const Group = ({
|
|||||||
const [groupAnnouncements, setGroupAnnouncements] = React.useState({});
|
const [groupAnnouncements, setGroupAnnouncements] = React.useState({});
|
||||||
const [defaultThread, setDefaultThread] = React.useState(null);
|
const [defaultThread, setDefaultThread] = React.useState(null);
|
||||||
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
|
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
|
||||||
|
const [isOpenBlockedUserModal, setIsOpenBlockedUserModal] = React.useState(false);
|
||||||
|
|
||||||
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
|
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
|
||||||
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState("");
|
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState("");
|
||||||
const [drawerMode, setDrawerMode] = React.useState("groups");
|
const [drawerMode, setDrawerMode] = React.useState("groups");
|
||||||
@ -768,7 +771,10 @@ export const Group = ({
|
|||||||
}
|
}
|
||||||
if(isPrivate === false){
|
if(isPrivate === false){
|
||||||
setTriedToFetchSecretKey(true);
|
setTriedToFetchSecretKey(true);
|
||||||
getAdminsForPublic(selectedGroup)
|
if(selectedGroup?.groupId !== '0'){
|
||||||
|
getAdminsForPublic(selectedGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [selectedGroup, isPrivate]);
|
}, [selectedGroup, isPrivate]);
|
||||||
@ -853,7 +859,7 @@ export const Group = ({
|
|||||||
// Update the component state with the received 'sendqort' state
|
// Update the component state with the received 'sendqort' state
|
||||||
setGroups(sortArrayByTimestampAndGroupName(message.payload));
|
setGroups(sortArrayByTimestampAndGroupName(message.payload));
|
||||||
getLatestRegularChat(message.payload);
|
getLatestRegularChat(message.payload);
|
||||||
setMemberGroups(message.payload);
|
setMemberGroups(message.payload?.filter((item)=> item?.groupId !== '0'));
|
||||||
|
|
||||||
if (selectedGroupRef.current && groupSectionRef.current === "chat") {
|
if (selectedGroupRef.current && groupSectionRef.current === "chat") {
|
||||||
window.sendMessage("addTimestampEnterChat", {
|
window.sendMessage("addTimestampEnterChat", {
|
||||||
@ -944,7 +950,7 @@ export const Group = ({
|
|||||||
!initiatedGetMembers.current &&
|
!initiatedGetMembers.current &&
|
||||||
selectedGroup?.groupId &&
|
selectedGroup?.groupId &&
|
||||||
secretKey &&
|
secretKey &&
|
||||||
admins.includes(myAddress)
|
admins.includes(myAddress) && selectedGroup?.groupId !== '0'
|
||||||
) {
|
) {
|
||||||
// getAdmins(selectedGroup?.groupId);
|
// getAdmins(selectedGroup?.groupId);
|
||||||
getMembers(selectedGroup?.groupId);
|
getMembers(selectedGroup?.groupId);
|
||||||
@ -1998,9 +2004,11 @@ export const Group = ({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
padding: "10px",
|
padding: "10px",
|
||||||
|
gap: '10px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{chatMode === "groups" && (
|
{chatMode === "groups" && (
|
||||||
|
<>
|
||||||
<CustomButton
|
<CustomButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenAddGroup(true);
|
setOpenAddGroup(true);
|
||||||
@ -2013,6 +2021,22 @@ export const Group = ({
|
|||||||
/>
|
/>
|
||||||
Group Mgmt
|
Group Mgmt
|
||||||
</CustomButton>
|
</CustomButton>
|
||||||
|
<CustomButton
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpenBlockedUserModal(true);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
minWidth: 'unset',
|
||||||
|
padding: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BlockIcon
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</CustomButton>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{chatMode === "directs" && (
|
{chatMode === "directs" && (
|
||||||
<CustomButton
|
<CustomButton
|
||||||
@ -2438,7 +2462,11 @@ export const Group = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{isOpenBlockedUserModal && (
|
||||||
|
<BlockedUsersModal close={()=> {
|
||||||
|
setIsOpenBlockedUserModal(false)
|
||||||
|
}} />
|
||||||
|
)}
|
||||||
|
|
||||||
{selectedDirect && !newChat && (
|
{selectedDirect && !newChat && (
|
||||||
<>
|
<>
|
||||||
|
@ -91,7 +91,7 @@ export const WebSocketActive = ({ myAddress, setIsLoadingGroups }) => {
|
|||||||
const sortedDirects = (data?.direct || []).filter(item =>
|
const sortedDirects = (data?.direct || []).filter(item =>
|
||||||
item?.name !== 'extension-proxy' && item?.address !== 'QSMMGSgysEuqDCuLw3S4cHrQkBrh3vP3VH'
|
item?.name !== 'extension-proxy' && item?.address !== 'QSMMGSgysEuqDCuLw3S4cHrQkBrh3vP3VH'
|
||||||
).sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
|
).sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
|
||||||
|
|
||||||
window.sendMessage("handleActiveGroupDataFromSocket", {
|
window.sendMessage("handleActiveGroupDataFromSocket", {
|
||||||
groups: sortedGroups,
|
groups: sortedGroups,
|
||||||
directs: sortedDirects,
|
directs: sortedDirects,
|
||||||
|
192
src/components/Group/useBlockUsers.tsx
Normal file
192
src/components/Group/useBlockUsers.tsx
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import React, { useCallback, useEffect, useRef } from "react";
|
||||||
|
import { getBaseApiReact } from "../../App";
|
||||||
|
import { truncate } from "lodash";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const useBlockedAddresses = () => {
|
||||||
|
const userBlockedRef = useRef({})
|
||||||
|
const userNamesBlockedRef = useRef({})
|
||||||
|
|
||||||
|
const getAllBlockedUsers = useCallback(()=> {
|
||||||
|
|
||||||
|
return {
|
||||||
|
names: userNamesBlockedRef.current,
|
||||||
|
addresses: userBlockedRef.current
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const isUserBlocked = useCallback((address, name)=> {
|
||||||
|
try {
|
||||||
|
if(!address) return false
|
||||||
|
if(userBlockedRef.current[address] || userNamesBlockedRef.current[name]) return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
//error
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
const fetchBlockedList = async ()=> {
|
||||||
|
try {
|
||||||
|
const response = await new Promise((res, rej) => {
|
||||||
|
window.sendMessage("listActions", {
|
||||||
|
|
||||||
|
type: 'get',
|
||||||
|
listName: `blockedAddresses`,
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
rej(response?.message);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
res(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed qortalRequest", error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
const blockedUsers = {}
|
||||||
|
response?.forEach((item)=> {
|
||||||
|
blockedUsers[item] = true
|
||||||
|
})
|
||||||
|
userBlockedRef.current = blockedUsers
|
||||||
|
|
||||||
|
const response2 = await new Promise((res, rej) => {
|
||||||
|
window.sendMessage("listActions", {
|
||||||
|
|
||||||
|
type: 'get',
|
||||||
|
listName: `blockedNames`,
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
rej(response?.message);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
res(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed qortalRequest", error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
const blockedUsers2 = {}
|
||||||
|
response2?.forEach((item)=> {
|
||||||
|
blockedUsers2[item] = true
|
||||||
|
})
|
||||||
|
userNamesBlockedRef.current = blockedUsers2
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchBlockedList()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const removeBlockFromList = useCallback(async (address, name)=> {
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
window.sendMessage("listActions", {
|
||||||
|
|
||||||
|
type: 'remove',
|
||||||
|
items: name ? [name] : [address],
|
||||||
|
listName: name ? 'blockedNames' : 'blockedAddresses'
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
rej(response?.message);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if(!name){
|
||||||
|
const copyObject = {...userBlockedRef.current}
|
||||||
|
delete copyObject[address]
|
||||||
|
userBlockedRef.current = copyObject
|
||||||
|
} else {
|
||||||
|
const copyObject = {...userNamesBlockedRef.current}
|
||||||
|
delete copyObject[name]
|
||||||
|
userNamesBlockedRef.current = copyObject
|
||||||
|
}
|
||||||
|
|
||||||
|
res(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed qortalRequest", error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
if(name && userBlockedRef.current[address]){
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
window.sendMessage("listActions", {
|
||||||
|
|
||||||
|
type: 'remove',
|
||||||
|
items: !name ? [name] : [address],
|
||||||
|
listName: !name ? 'blockedNames' : 'blockedAddresses'
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
rej(response?.message);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const copyObject = {...userBlockedRef.current}
|
||||||
|
delete copyObject[address]
|
||||||
|
userBlockedRef.current = copyObject
|
||||||
|
res(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed qortalRequest", error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const addToBlockList = useCallback(async (address, name)=> {
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
window.sendMessage("listActions", {
|
||||||
|
|
||||||
|
type: 'add',
|
||||||
|
items: name ? [name] : [address],
|
||||||
|
listName: name ? 'blockedNames' : 'blockedAddresses'
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
rej(response?.message);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if(name){
|
||||||
|
|
||||||
|
const copyObject = {...userNamesBlockedRef.current}
|
||||||
|
copyObject[name] = true
|
||||||
|
userNamesBlockedRef.current = copyObject
|
||||||
|
}else {
|
||||||
|
const copyObject = {...userBlockedRef.current}
|
||||||
|
copyObject[address] = true
|
||||||
|
userBlockedRef.current = copyObject
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
res(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed qortalRequest", error);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
isUserBlocked,
|
||||||
|
addToBlockList,
|
||||||
|
removeBlockFromList,
|
||||||
|
getAllBlockedUsers
|
||||||
|
};
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
import { Popover, Button, Box } from '@mui/material';
|
import { Popover, Button, Box, CircularProgress } from '@mui/material';
|
||||||
import { executeEvent } from '../utils/events';
|
import { executeEvent } from '../utils/events';
|
||||||
|
import { MyContext } from '../App';
|
||||||
|
|
||||||
export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
@ -12,9 +13,9 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handle closing the Popover
|
// Handle closing the Popover
|
||||||
const handleClose = () => {
|
const handleClose = useCallback(() => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
// Determine if the popover is open
|
// Determine if the popover is open
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
@ -120,9 +121,63 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
|||||||
>
|
>
|
||||||
Copy address
|
Copy address
|
||||||
</Button>
|
</Button>
|
||||||
|
<BlockUser handleClose={handleClose} address={address} name={name} />
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const BlockUser = ({address, name, handleClose})=> {
|
||||||
|
const [isAlreadyBlocked, setIsAlreadyBlocked] = useState(null)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const {isUserBlocked,
|
||||||
|
addToBlockList,
|
||||||
|
removeBlockFromList} = useContext(MyContext)
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(!address) return
|
||||||
|
setIsAlreadyBlocked(isUserBlocked(address, name))
|
||||||
|
}, [address, setIsAlreadyBlocked, isUserBlocked, name])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true)
|
||||||
|
if(isAlreadyBlocked === true){
|
||||||
|
await removeBlockFromList(address, name)
|
||||||
|
} else if(isAlreadyBlocked === false) {
|
||||||
|
await addToBlockList(address, name)
|
||||||
|
}
|
||||||
|
executeEvent('updateChatMessagesWithBlocks', true)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
handleClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
color: 'white',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
gap: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(isAlreadyBlocked === null || isLoading) && (
|
||||||
|
<CircularProgress color="secondary" size={24} />
|
||||||
|
)}
|
||||||
|
{isAlreadyBlocked && (
|
||||||
|
'Unblock name'
|
||||||
|
)}
|
||||||
|
{isAlreadyBlocked === false && (
|
||||||
|
'Block name'
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user