mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-24 03:47:53 +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 { QMailStatus } from "./components/QMailStatus";
|
||||
import { GlobalActions } from "./components/GlobalActions/GlobalActions";
|
||||
import { useBlockedAddresses } from "./components/Group/useBlockUsers";
|
||||
|
||||
type extStates =
|
||||
| "not-authenticated"
|
||||
@ -402,6 +403,9 @@ function App() {
|
||||
const [isOpenSendQort, setIsOpenSendQort] = useState(false);
|
||||
const [isOpenSendQortSuccess, setIsOpenSendQortSuccess] = useState(false);
|
||||
const [rootHeight, setRootHeight] = useState("100%");
|
||||
const {isUserBlocked,
|
||||
addToBlockList,
|
||||
removeBlockFromList, getAllBlockedUsers} = useBlockedAddresses()
|
||||
const [currentNode, setCurrentNode] = useState({
|
||||
url: "http://127.0.0.1:12391",
|
||||
});
|
||||
@ -1630,7 +1634,11 @@ function App() {
|
||||
infoSnackCustom: infoSnack,
|
||||
setInfoSnackCustom: setInfoSnack,
|
||||
downloadResource,
|
||||
getIndividualUserInfo
|
||||
getIndividualUserInfo,
|
||||
isUserBlocked,
|
||||
addToBlockList,
|
||||
removeBlockFromList,
|
||||
getAllBlockedUsers
|
||||
}}
|
||||
>
|
||||
<TaskManager getUserInfo={getUserInfo} />
|
||||
@ -1751,7 +1759,11 @@ function App() {
|
||||
infoSnackCustom: infoSnack,
|
||||
setInfoSnackCustom: setInfoSnack,
|
||||
downloadResource,
|
||||
getIndividualUserInfo
|
||||
getIndividualUserInfo,
|
||||
isUserBlocked,
|
||||
addToBlockList,
|
||||
removeBlockFromList,
|
||||
getAllBlockedUsers
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
checkNewMessages,
|
||||
checkThreads,
|
||||
clearAllNotifications,
|
||||
createEndpoint,
|
||||
createGroup,
|
||||
decryptDirectFunc,
|
||||
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) {
|
||||
try {
|
||||
const response = await getTimestampMention();
|
||||
|
@ -74,6 +74,7 @@ import {
|
||||
joinGroupCase,
|
||||
kickFromGroupCase,
|
||||
leaveGroupCase,
|
||||
listActionsCase,
|
||||
ltcBalanceCase,
|
||||
makeAdminCase,
|
||||
nameCase,
|
||||
@ -3022,6 +3023,9 @@ function setupMessageListener() {
|
||||
case "getTimestampEnterChat":
|
||||
getTimestampEnterChatCase(request, event);
|
||||
break;
|
||||
case "listActions":
|
||||
listActionsCase(request, event);
|
||||
break;
|
||||
case "addTimestampMention":
|
||||
addTimestampMentionCase(request, event);
|
||||
break;
|
||||
@ -3154,9 +3158,16 @@ const checkGroupList = async () => {
|
||||
},
|
||||
});
|
||||
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(
|
||||
(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 { reusableGet } from '../../qdn/publish/pubish'
|
||||
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'
|
||||
@ -10,11 +10,11 @@ import Tiptap from './TipTap'
|
||||
import { CustomButton } from '../../App-styles'
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
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 { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/codes'
|
||||
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 ShortUniqueId from "short-unique-id";
|
||||
import { ReplyPreview } from './MessageItem'
|
||||
@ -28,6 +28,7 @@ import { throttle } from 'lodash'
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
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 [chatReferences, setChatReferences] = useState({})
|
||||
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) => {
|
||||
try {
|
||||
if (hasInitialized.current) {
|
||||
decryptMessages(data, true);
|
||||
const dataRemovedBlock = data?.filter((item)=> !isUserBlocked(item?.sender, item?.senderName))
|
||||
|
||||
decryptMessages(dataRemovedBlock, true);
|
||||
return;
|
||||
}
|
||||
hasInitialized.current = true;
|
||||
@ -173,7 +192,11 @@ const [messageSize, setMessageSize] = useState(0)
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
decryptMessages(responseData, false);
|
||||
const dataRemovedBlock = responseData?.filter((item)=> {
|
||||
return !isUserBlocked(item?.sender, item?.senderName)
|
||||
})
|
||||
|
||||
decryptMessages(dataRemovedBlock, false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
@ -132,13 +132,16 @@ const onSeenFunc = useCallback(()=> {
|
||||
|
||||
|
||||
return (
|
||||
<MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}>
|
||||
|
||||
{message?.divide && (
|
||||
<>
|
||||
{message?.divide && (
|
||||
<div className="unread-divider" id="unread-divider-id">
|
||||
Unread messages below
|
||||
</div>
|
||||
)}
|
||||
|
||||
<MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}>
|
||||
|
||||
|
||||
<div
|
||||
style={{
|
||||
padding: "10px",
|
||||
@ -492,6 +495,7 @@ const onSeenFunc = useCallback(()=> {
|
||||
|
||||
</div>
|
||||
</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 { addressInfoControllerAtom, selectedGroupIdAtom } from "../../atoms/global";
|
||||
import { sortArrayByTimestampAndGroupName } from "../../utils/time";
|
||||
|
||||
import BlockIcon from '@mui/icons-material/Block';
|
||||
import LockIcon from '@mui/icons-material/Lock';
|
||||
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
||||
import { BlockedUsersModal } from "./BlockedUsersModal";
|
||||
|
||||
|
||||
export const getPublishesFromAdmins = async (admins: string[], groupId) => {
|
||||
@ -419,6 +420,8 @@ export const Group = ({
|
||||
const [groupAnnouncements, setGroupAnnouncements] = React.useState({});
|
||||
const [defaultThread, setDefaultThread] = React.useState(null);
|
||||
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
|
||||
const [isOpenBlockedUserModal, setIsOpenBlockedUserModal] = React.useState(false);
|
||||
|
||||
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
|
||||
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState("");
|
||||
const [drawerMode, setDrawerMode] = React.useState("groups");
|
||||
@ -768,7 +771,10 @@ export const Group = ({
|
||||
}
|
||||
if(isPrivate === false){
|
||||
setTriedToFetchSecretKey(true);
|
||||
getAdminsForPublic(selectedGroup)
|
||||
if(selectedGroup?.groupId !== '0'){
|
||||
getAdminsForPublic(selectedGroup)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}, [selectedGroup, isPrivate]);
|
||||
@ -853,7 +859,7 @@ export const Group = ({
|
||||
// Update the component state with the received 'sendqort' state
|
||||
setGroups(sortArrayByTimestampAndGroupName(message.payload));
|
||||
getLatestRegularChat(message.payload);
|
||||
setMemberGroups(message.payload);
|
||||
setMemberGroups(message.payload?.filter((item)=> item?.groupId !== '0'));
|
||||
|
||||
if (selectedGroupRef.current && groupSectionRef.current === "chat") {
|
||||
window.sendMessage("addTimestampEnterChat", {
|
||||
@ -944,7 +950,7 @@ export const Group = ({
|
||||
!initiatedGetMembers.current &&
|
||||
selectedGroup?.groupId &&
|
||||
secretKey &&
|
||||
admins.includes(myAddress)
|
||||
admins.includes(myAddress) && selectedGroup?.groupId !== '0'
|
||||
) {
|
||||
// getAdmins(selectedGroup?.groupId);
|
||||
getMembers(selectedGroup?.groupId);
|
||||
@ -1998,9 +2004,11 @@ export const Group = ({
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
padding: "10px",
|
||||
gap: '10px'
|
||||
}}
|
||||
>
|
||||
{chatMode === "groups" && (
|
||||
<>
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
setOpenAddGroup(true);
|
||||
@ -2013,6 +2021,22 @@ export const Group = ({
|
||||
/>
|
||||
Group Mgmt
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
setIsOpenBlockedUserModal(true);
|
||||
}}
|
||||
sx={{
|
||||
minWidth: 'unset',
|
||||
padding: '10px'
|
||||
}}
|
||||
>
|
||||
<BlockIcon
|
||||
sx={{
|
||||
color: "white",
|
||||
}}
|
||||
/>
|
||||
</CustomButton>
|
||||
</>
|
||||
)}
|
||||
{chatMode === "directs" && (
|
||||
<CustomButton
|
||||
@ -2438,7 +2462,11 @@ export const Group = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOpenBlockedUserModal && (
|
||||
<BlockedUsersModal close={()=> {
|
||||
setIsOpenBlockedUserModal(false)
|
||||
}} />
|
||||
)}
|
||||
|
||||
{selectedDirect && !newChat && (
|
||||
<>
|
||||
|
@ -91,7 +91,7 @@ export const WebSocketActive = ({ myAddress, setIsLoadingGroups }) => {
|
||||
const sortedDirects = (data?.direct || []).filter(item =>
|
||||
item?.name !== 'extension-proxy' && item?.address !== 'QSMMGSgysEuqDCuLw3S4cHrQkBrh3vP3VH'
|
||||
).sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
|
||||
|
||||
|
||||
window.sendMessage("handleActiveGroupDataFromSocket", {
|
||||
groups: sortedGroups,
|
||||
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 { Popover, Button, Box } from '@mui/material';
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { Popover, Button, Box, CircularProgress } from '@mui/material';
|
||||
import { executeEvent } from '../utils/events';
|
||||
import { MyContext } from '../App';
|
||||
|
||||
export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
@ -12,9 +13,9 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
};
|
||||
|
||||
// Handle closing the Popover
|
||||
const handleClose = () => {
|
||||
const handleClose = useCallback(() => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Determine if the popover is open
|
||||
const open = Boolean(anchorEl);
|
||||
@ -120,9 +121,63 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
>
|
||||
Copy address
|
||||
</Button>
|
||||
<BlockUser handleClose={handleClose} address={address} name={name} />
|
||||
</Box>
|
||||
</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