give more info on block users

This commit is contained in:
PhilReact 2025-04-11 15:56:46 +03:00
parent 7e7e914cf9
commit 534301294e
5 changed files with 338 additions and 141 deletions

View File

@ -177,4 +177,9 @@ export const mailsAtom = atom({
export const groupsPropertiesAtom = atom({ export const groupsPropertiesAtom = atom({
key: 'groupsPropertiesAtom', key: 'groupsPropertiesAtom',
default: {}, default: {},
});
export const isOpenBlockedModalAtom = atom({
key: 'isOpenBlockedModalAtom',
default: false,
}); });

View File

@ -10,15 +10,23 @@ import {
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import { MyContext } from "../../App"; import { getBaseApiReact, MyContext } from "../../App";
import { Spacer } from "../../common/Spacer"; import { Spacer } from "../../common/Spacer";
import { executeEvent } from "../../utils/events"; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import { validateAddress } from "../../utils/validateAddress";
export const BlockedUsersModal = ({ close }) => { import { getNameInfo, requestQueueMemberNames } from "./Group";
import { useModal } from "../../common/useModal";
import { useRecoilState } from "recoil";
import { isOpenBlockedModalAtom } from "../../atoms/global";
import InfoIcon from '@mui/icons-material/Info';
export const BlockedUsersModal = () => {
const [isOpenBlockedModal, setIsOpenBlockedModal] = useRecoilState(isOpenBlockedModalAtom)
const [hasChanged, setHasChanged] = useState(false); const [hasChanged, setHasChanged] = useState(false);
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [addressesWithNames, setAddressesWithNames] = useState({})
const { getAllBlockedUsers, removeBlockFromList, addToBlockList } = useContext(MyContext); const { isShow, onCancel, onOk, show, message } = useModal();
const { getAllBlockedUsers, removeBlockFromList, addToBlockList } =
useContext(MyContext);
const [blockedUsers, setBlockedUsers] = useState({ const [blockedUsers, setBlockedUsers] = useState({
addresses: {}, addresses: {},
names: {}, names: {},
@ -28,60 +36,157 @@ export const BlockedUsersModal = ({ close }) => {
}; };
useEffect(() => { useEffect(() => {
if(!isOpenBlockedModal) return
fetchBlockedUsers(); fetchBlockedUsers();
}, []); }, [isOpenBlockedModal]);
const getNames = async () => {
// const validApi = await findUsableApi();
const addresses = Object.keys(blockedUsers?.addresses)
const addressNames = {}
const getMemNames = addresses.map(async (address) => {
const name = await requestQueueMemberNames.enqueue(() => {
return getNameInfo(address);
});
if (name) {
addressNames[address] = name
}
return true;
});
await Promise.all(getMemNames);
setAddressesWithNames(addressNames)
};
const blockUser = async (e, user?: string) => {
try {
const valUser = user || value
if (!valUser) return;
const isAddress = validateAddress(valUser);
let userName = null;
let userAddress = null;
if (isAddress) {
userAddress = valUser;
const name = await getNameInfo(valUser);
if (name) {
userName = name;
}
}
if (!isAddress) {
const response = await fetch(`${getBaseApiReact()}/names/${valUser}`);
const data = await response.json();
if (!data?.owner) throw new Error("Name does not exist");
if (data?.owner) {
userAddress = data.owner;
userName = valUser;
}
}
if(!userName){
await addToBlockList(userAddress, null);
fetchBlockedUsers();
setHasChanged(true);
executeEvent('updateChatMessagesWithBlocks', true)
setValue('')
return
}
const responseModal = await show({
userName,
userAddress,
});
if (responseModal === "both") {
await addToBlockList(userAddress, userName);
} else if (responseModal === "address") {
await addToBlockList(userAddress, null);
} else if (responseModal === "name") {
await addToBlockList(null, userName);
}
fetchBlockedUsers();
setHasChanged(true);
setValue('')
if(user){
setIsOpenBlockedModal(false)
}
if(responseModal === 'both' || responseModal === 'address'){
executeEvent('updateChatMessagesWithBlocks', true)
}
} catch (error) {
console.error(error);
}
};
const blockUserFromOutsideModalFunc = (e) => {
const user = e.detail?.user;
setIsOpenBlockedModal(true)
blockUser(null, user)
};
useEffect(() => {
subscribeToEvent("blockUserFromOutside", blockUserFromOutsideModalFunc);
return () => {
unsubscribeFromEvent("blockUserFromOutside", blockUserFromOutsideModalFunc);
};
}, []);
return ( return (
<Dialog <Dialog
open={true} open={isOpenBlockedModal}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle>Blocked Users</DialogTitle> <DialogTitle>Blocked Users</DialogTitle>
<DialogContent sx={{ <DialogContent
padding: '20px' sx={{
}}> padding: "20px",
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
}} }}
> >
<TextField <Box
placeholder="Name" sx={{
value={value} display: "flex",
onChange={(e) => { alignItems: "center",
setValue(e.target.value); gap: "10px",
}} }}
/> >
<Button variant="contained" onClick={async ()=> { <TextField
try { placeholder="Name or address"
if(!value) return value={value}
await addToBlockList(undefined, value) onChange={(e) => {
fetchBlockedUsers() setValue(e.target.value);
setHasChanged(true) }}
} catch (error) { />
console.error(error) <Button
} sx={{
}}>Block</Button> flexShrink: 0,
</Box> }}
variant="contained"
onClick={blockUser}
>
Block
</Button>
</Box>
{Object.entries(blockedUsers?.addresses).length > 0 && ( {Object.entries(blockedUsers?.addresses).length > 0 && (
<> <>
<Spacer height="20px" /> <Spacer height="20px" />
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Blocked Users for Chat ( addresses ) Blocked addresses- blocks processing of txs
</DialogContentText> </DialogContentText>
<Spacer height="10px" /> <Spacer height="10px" />
<Button variant="contained" size="small" onClick={getNames}>Fetch names</Button>
<Spacer height="10px" />
</> </>
)} )}
<Box sx={{ <Box
display: 'flex', sx={{
flexDirection: 'column', display: "flex",
gap: '10px' flexDirection: "column",
}}> gap: "10px",
}}
>
{Object.entries(blockedUsers?.addresses || {})?.map( {Object.entries(blockedUsers?.addresses || {})?.map(
([key, value]) => { ([key, value]) => {
return ( return (
@ -90,18 +195,22 @@ export const BlockedUsersModal = ({ close }) => {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
gap: "10px", gap: "10px",
width: '100%', width: "100%",
justifyContent: 'space-between' justifyContent: "space-between",
}} }}
> >
<Typography>{key}</Typography> <Typography>{addressesWithNames[key] || key}</Typography>
<Button <Button
sx={{
flexShrink: 0,
}}
size="small"
variant="contained" variant="contained"
onClick={async () => { onClick={async () => {
try { try {
await removeBlockFromList(key, undefined); await removeBlockFromList(key, undefined);
setHasChanged(true); setHasChanged(true);
setValue('') setValue("");
fetchBlockedUsers(); fetchBlockedUsers();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -119,17 +228,19 @@ export const BlockedUsersModal = ({ close }) => {
<> <>
<Spacer height="20px" /> <Spacer height="20px" />
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Blocked Users for QDN and Chat (names) Blocked names for QDN
</DialogContentText> </DialogContentText>
<Spacer height="10px" /> <Spacer height="10px" />
</> </>
)} )}
<Box sx={{ <Box
display: 'flex', sx={{
flexDirection: 'column', display: "flex",
gap: '10px' flexDirection: "column",
}}> gap: "10px",
}}
>
{Object.entries(blockedUsers?.names || {})?.map(([key, value]) => { {Object.entries(blockedUsers?.names || {})?.map(([key, value]) => {
return ( return (
<Box <Box
@ -137,12 +248,16 @@ export const BlockedUsersModal = ({ close }) => {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
gap: "10px", gap: "10px",
width: '100%', width: "100%",
justifyContent: 'space-between' justifyContent: "space-between",
}} }}
> >
<Typography>{key}</Typography> <Typography>{key}</Typography>
<Button <Button
size="small"
sx={{
flexShrink: 0,
}}
variant="contained" variant="contained"
onClick={async () => { onClick={async () => {
try { try {
@ -175,16 +290,67 @@ export const BlockedUsersModal = ({ close }) => {
}, },
}} }}
variant="contained" variant="contained"
onClick={()=> { onClick={() => {
if(hasChanged){ if (hasChanged) {
executeEvent('updateChatMessagesWithBlocks', true) executeEvent("updateChatMessagesWithBlocks", true);
} }
close() setIsOpenBlockedModal(false);
}} }}
> >
close close
</Button> </Button>
</DialogActions> </DialogActions>
<Dialog
open={isShow}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Decide what to block"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Blocking {message?.userName || message?.userAddress}
</DialogContentText>
<Box sx={{
display: 'flex',
alignItems: 'center',
gap: '10px',
marginTop: '20px'
}}>
<InfoIcon sx={{
color: 'fff'
}}/> <Typography>Choose "block txs" or "all" to block chat messages </Typography>
</Box>
</DialogContent>
<DialogActions>
<Button
variant="contained"
onClick={() => {
onOk("address");
}}
>
Block txs
</Button>
<Button
variant="contained"
onClick={() => {
onOk("name");
}}
>
Block QDN data
</Button>
<Button
variant="contained"
onClick={() => {
onOk("both");
}}
>
Block All
</Button>
</DialogActions>
</Dialog>
</Dialog> </Dialog>
); );
}; };

View File

@ -75,9 +75,9 @@ 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 { useRecoilState, useSetRecoilState } from "recoil"; import { useRecoilState, useSetRecoilState } from "recoil";
import { addressInfoControllerAtom, groupsPropertiesAtom, selectedGroupIdAtom } from "../../atoms/global"; import { addressInfoControllerAtom, groupsPropertiesAtom, isOpenBlockedModalAtom, selectedGroupIdAtom } from "../../atoms/global";
import { sortArrayByTimestampAndGroupName } from "../../utils/time"; import { sortArrayByTimestampAndGroupName } from "../../utils/time";
import BlockIcon from '@mui/icons-material/Block'; import PersonOffIcon from '@mui/icons-material/PersonOff';
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"; import { BlockedUsersModal } from "./BlockedUsersModal";
@ -421,7 +421,7 @@ 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 setIsOpenBlockedUserModal = useSetRecoilState(isOpenBlockedModalAtom)
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false); const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState(""); const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState("");
@ -2035,7 +2035,7 @@ export const Group = ({
padding: '10px' padding: '10px'
}} }}
> >
<BlockIcon <PersonOffIcon
sx={{ sx={{
color: "white", color: "white",
}} }}
@ -2469,11 +2469,8 @@ export const Group = ({
/> />
)} )}
</div> </div>
{isOpenBlockedUserModal && ( <BlockedUsersModal />
<BlockedUsersModal close={()=> {
setIsOpenBlockedUserModal(false)
}} />
)}
{selectedDirect && !newChat && ( {selectedDirect && !newChat && (
<> <>

View File

@ -19,7 +19,7 @@ export const useBlockedAddresses = () => {
const isUserBlocked = useCallback((address, name)=> { const isUserBlocked = useCallback((address, name)=> {
try { try {
if(!address) return false if(!address) return false
if(userBlockedRef.current[address] || userNamesBlockedRef.current[name]) return true if(userBlockedRef.current[address]) return true
return false return false
@ -90,43 +90,13 @@ export const useBlockedAddresses = () => {
}, []) }, [])
const removeBlockFromList = useCallback(async (address, name)=> { const removeBlockFromList = useCallback(async (address, name)=> {
await new Promise((res, rej) => { if(name){
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) => { await new Promise((res, rej) => {
window.sendMessage("listActions", { window.sendMessage("listActions", {
type: 'remove', type: 'remove',
items: !name ? [name] : [address], items: [name] ,
listName: !name ? 'blockedNames' : 'blockedAddresses' listName: 'blockedNames'
}) })
.then((response) => { .then((response) => {
@ -134,9 +104,12 @@ export const useBlockedAddresses = () => {
rej(response?.message); rej(response?.message);
return; return;
} else { } else {
const copyObject = {...userBlockedRef.current}
delete copyObject[address] const copyObject = {...userNamesBlockedRef.current}
userBlockedRef.current = copyObject delete copyObject[name]
userNamesBlockedRef.current = copyObject
res(response); res(response);
} }
}) })
@ -145,42 +118,95 @@ export const useBlockedAddresses = () => {
}); });
}) })
} }
if(address){
await new Promise((res, rej) => {
window.sendMessage("listActions", {
type: 'remove',
items: [address],
listName: '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)=> { const addToBlockList = useCallback(async (address, name)=> {
await new Promise((res, rej) => { if(name){
window.sendMessage("listActions", { 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); type: 'add',
} items: [name],
listName: 'blockedNames'
})
.then((response) => {
if (response.error) {
rej(response?.message);
return;
} else {
const copyObject = {...userNamesBlockedRef.current}
copyObject[name] = true
userNamesBlockedRef.current = copyObject
res(response);
}
})
.catch((error) => {
console.error("Failed qortalRequest", error);
});
}) })
.catch((error) => { }
console.error("Failed qortalRequest", error); if(address){
}); await new Promise((res, rej) => {
}) window.sendMessage("listActions", {
type: 'add',
items: [address],
listName: 'blockedAddresses'
})
.then((response) => {
if (response.error) {
rej(response?.message);
return;
} else {
const copyObject = {...userBlockedRef.current}
copyObject[address] = true
userBlockedRef.current = copyObject
res(response);
}
})
.catch((error) => {
console.error("Failed qortalRequest", error);
});
})
}
}, []) }, [])
return { return {

View File

@ -169,12 +169,15 @@ useEffect(()=> {
onClick={async () => { onClick={async () => {
try { try {
setIsLoading(true) setIsLoading(true)
if(isAlreadyBlocked === true){ executeEvent("blockUserFromOutside", {
await removeBlockFromList(address, name) user: address
} else if(isAlreadyBlocked === false) { })
await addToBlockList(address, name) // if(isAlreadyBlocked === true){
} // await removeBlockFromList(address, name)
executeEvent('updateChatMessagesWithBlocks', true) // } else if(isAlreadyBlocked === false) {
// await addToBlockList(address, name)
// }
// executeEvent('updateChatMessagesWithBlocks', true)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {