added badges in chat

This commit is contained in:
PhilReact 2024-12-30 12:26:48 +02:00
parent 8ecfbd88ca
commit 843ceac095
16 changed files with 116 additions and 5 deletions

View File

@ -119,6 +119,7 @@ import BoundedNumericTextField from "./common/BoundedNumericTextField";
import { Wallets } from "./Wallets";
import './utils/seedPhrase/RandomSentenceGenerator';
import { test } from "vitest";
import { useHandleUserInfo } from "./components/Group/useHandleUserInfo";
type extStates =
| "not-authenticated"
@ -376,6 +377,7 @@ function App() {
saveSeedPhraseToDisk(seedPhrase)
}
const {showTutorial, openTutorialModal, shownTutorialsInitiated, setOpenTutorialModal} = useHandleTutorials()
const {getIndividualUserInfo} = useHandleUserInfo()
const passwordRef = useRef<HTMLInputElement>(null);
useEffect(() => {
@ -1709,6 +1711,7 @@ function App() {
setOpenSnackGlobal: setOpenSnack,
infoSnackCustom: infoSnack,
setInfoSnackCustom: setInfoSnack,
getIndividualUserInfo
}}
>
<Box

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -129,3 +129,16 @@ export const isUsingImportExportSettingsAtom = atom({
key: 'isUsingImportExportSettingsAtom',
default: null,
});
export const addressInfoControllerAtom = atom({
key: 'addressInfoControllerAtom',
default: {},
});
export const addressInfoKeySelector = selectorFamily({
key: 'addressInfoKeySelector',
get: (key) => ({ get }) => {
const userInfo = get(addressInfoControllerAtom);
return userInfo[key] || null; // Return the value for the key or null if not found
},
});

View File

@ -1,11 +1,11 @@
import { Message } from "@chatscope/chat-ui-kit-react";
import React, { useEffect, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { useInView } from "react-intersection-observer";
import { MessageDisplay } from "./MessageDisplay";
import { Avatar, Box, Button, ButtonBase, List, ListItem, ListItemText, Popover, Typography } from "@mui/material";
import { Avatar, Box, Button, ButtonBase, List, ListItem, ListItemText, Popover, Tooltip, Typography } from "@mui/material";
import { formatTimestamp } from "../../utils/time";
import { getBaseApi } from "../../background";
import { getBaseApiReact } from "../../App";
import { MyContext, getBaseApiReact } from "../../App";
import { generateHTML } from "@tiptap/react";
import Highlight from "@tiptap/extension-highlight";
import StarterKit from "@tiptap/starter-kit";
@ -19,6 +19,37 @@ import KeyOffIcon from '@mui/icons-material/KeyOff';
import EditIcon from '@mui/icons-material/Edit';
import Mention from "@tiptap/extension-mention";
import TextStyle from '@tiptap/extension-text-style';
import { addressInfoKeySelector } from "../../atoms/global";
import { useRecoilValue } from "recoil";
import level0Img from "../../assets/badges/level-0.png"
import level1Img from "../../assets/badges/level-1.png"
import level2Img from "../../assets/badges/level-2.png"
import level3Img from "../../assets/badges/level-3.png"
import level4Img from "../../assets/badges/level-4.png"
import level5Img from "../../assets/badges/level-5.png"
import level6Img from "../../assets/badges/level-6.png"
import level7Img from "../../assets/badges/level-7.png"
import level8Img from "../../assets/badges/level-8.png"
import level9Img from "../../assets/badges/level-9.png"
import level10Img from "../../assets/badges/level-10.png"
const getBadgeImg = (level)=> {
switch(level?.toString()){
case '0': return level0Img
case '1': return level1Img
case '2': return level2Img
case '3': return level3Img
case '4': return level4Img
case '5': return level5Img
case '6': return level6Img
case '7': return level7Img
case '8': return level8Img
case '9': return level9Img
case '10': return level10Img
default: return level0Img
}
}
export const MessageItem = ({
message,
@ -39,6 +70,9 @@ export const MessageItem = ({
isPrivate,
setMobileViewModeKeepOpen
}) => {
const {getIndividualUserInfo} = useContext(MyContext)
const userInfo = useRecoilValue(addressInfoKeySelector(message?.sender));
const [anchorEl, setAnchorEl] = useState(null);
const [selectedReaction, setSelectedReaction] = useState(null);
const { ref, inView } = useInView({
@ -52,6 +86,11 @@ export const MessageItem = ({
}
}, [inView, message.id, isLast]);
useEffect(()=> {
if(message?.sender){
getIndividualUserInfo(message?.sender)
}
}, [message?.sender])
return (
<>
@ -80,11 +119,18 @@ export const MessageItem = ({
}}
/>
) : (
<Box sx={{
display: 'flex',
flexDirection: 'column',
gap: '20px',
alignItems: 'center'
}}>
<WrapperUserAction
disabled={myAddress === message?.sender}
address={message?.sender}
name={message?.senderName}
>
<Avatar
sx={{
backgroundColor: "#27282c",
@ -97,7 +143,19 @@ export const MessageItem = ({
>
{message?.senderName?.charAt(0)}
</Avatar>
</WrapperUserAction>
<Tooltip disableFocusListener title={`level ${userInfo?.level}`}>
<img style={{
visibility: userInfo?.level !== undefined ? 'visible' : 'hidden',
width: '30px',
height: 'auto'
}} src={getBadgeImg(userInfo?.level)} />
</Tooltip>
</Box>
)}
<Box

View File

@ -95,7 +95,7 @@ import { formatEmailDate } from "./QMailMessages";
import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import { useSetRecoilState } from "recoil";
import { selectedGroupIdAtom } from "../../atoms/global";
import { addressInfoControllerAtom, selectedGroupIdAtom } from "../../atoms/global";
import { sortArrayByTimestampAndGroupName } from "../../utils/time";
import { AdminSpace } from "../Chat/AdminSpace";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
@ -498,7 +498,7 @@ export const Group = ({
const setSelectedGroupId = useSetRecoilState(selectedGroupIdAtom)
const [groupsProperties, setGroupsProperties] = useState({})
const setUserInfoForLevels = useSetRecoilState(addressInfoControllerAtom);
const isPrivate = useMemo(()=> {
if(!selectedGroup?.groupId || !groupsProperties[selectedGroup?.groupId]) return null
if(groupsProperties[selectedGroup?.groupId]?.isOpen === true) return false
@ -2047,6 +2047,7 @@ export const Group = ({
setTriedToFetchSecretKey(false);
setNewChat(false);
setSelectedGroup(null);
setUserInfoForLevels({})
setSecretKey(null);
lastFetchedSecretKey.current = null;
setSecretKeyPublishDate(null);

View File

@ -0,0 +1,36 @@
import React, { useCallback, useEffect, useState } from "react";
import { getBaseApiReact } from "../../App";
import { useRecoilState, useSetRecoilState } from "recoil";
import { addressInfoControllerAtom } from "../../atoms/global";
export const useHandleUserInfo = () => {
const [userInfo, setUserInfo] = useRecoilState(addressInfoControllerAtom);
const getIndividualUserInfo = useCallback(async (address)=> {
try {
if(!address || userInfo[address]) return
const url = `${getBaseApiReact()}/addresses/${address}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("network error");
}
const data = await response.json();
setUserInfo((prev)=> {
return {
...prev,
[address]: data
}
})
} catch (error) {
//error
}
}, [userInfo])
return {
getIndividualUserInfo,
};
};