mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-06-07 17:06:58 +00:00
added group avatar
This commit is contained in:
parent
ed7b36791a
commit
6c03c16be8
@ -100,6 +100,7 @@ import { useRecoilState, useResetRecoilState, useSetRecoilState } from 'recoil';
|
|||||||
import {
|
import {
|
||||||
canSaveSettingToQdnAtom,
|
canSaveSettingToQdnAtom,
|
||||||
enabledDevModeAtom,
|
enabledDevModeAtom,
|
||||||
|
groupsOwnerNamesAtom,
|
||||||
groupsPropertiesAtom,
|
groupsPropertiesAtom,
|
||||||
hasSettingsChangedAtom,
|
hasSettingsChangedAtom,
|
||||||
isDisabledEditorEnterAtom,
|
isDisabledEditorEnterAtom,
|
||||||
@ -477,6 +478,7 @@ function App() {
|
|||||||
const resetLastPaymentSeenTimestampAtom = useResetRecoilState(
|
const resetLastPaymentSeenTimestampAtom = useResetRecoilState(
|
||||||
lastPaymentSeenTimestampAtom
|
lastPaymentSeenTimestampAtom
|
||||||
);
|
);
|
||||||
|
const resetGroupsOwnerNamesAtom = useResetRecoilState(groupsOwnerNamesAtom);
|
||||||
|
|
||||||
const resetAllRecoil = () => {
|
const resetAllRecoil = () => {
|
||||||
resetAtomSortablePinnedAppsAtom();
|
resetAtomSortablePinnedAppsAtom();
|
||||||
@ -489,6 +491,7 @@ function App() {
|
|||||||
resetAtomMailsAtom();
|
resetAtomMailsAtom();
|
||||||
resetGroupPropertiesAtom();
|
resetGroupPropertiesAtom();
|
||||||
resetLastPaymentSeenTimestampAtom();
|
resetLastPaymentSeenTimestampAtom();
|
||||||
|
resetGroupsOwnerNamesAtom();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSetGlobalApikey = (key) => {
|
const handleSetGlobalApikey = (key) => {
|
||||||
|
@ -192,6 +192,10 @@ export const groupsPropertiesAtom = atom({
|
|||||||
key: 'groupsPropertiesAtom',
|
key: 'groupsPropertiesAtom',
|
||||||
default: {},
|
default: {},
|
||||||
});
|
});
|
||||||
|
export const groupsOwnerNamesAtom = atom({
|
||||||
|
key: 'groupsOwnerNamesAtom',
|
||||||
|
default: {},
|
||||||
|
});
|
||||||
|
|
||||||
export const isOpenBlockedModalAtom = atom({
|
export const isOpenBlockedModalAtom = atom({
|
||||||
key: 'isOpenBlockedModalAtom',
|
key: 'isOpenBlockedModalAtom',
|
||||||
|
@ -15,6 +15,8 @@ export const AdminSpace = ({
|
|||||||
defaultThread,
|
defaultThread,
|
||||||
setDefaultThread,
|
setDefaultThread,
|
||||||
setIsForceShowCreationKeyPopup,
|
setIsForceShowCreationKeyPopup,
|
||||||
|
balance,
|
||||||
|
isOwner,
|
||||||
}) => {
|
}) => {
|
||||||
const { rootHeight } = useContext(MyContext);
|
const { rootHeight } = useContext(MyContext);
|
||||||
const [isMoved, setIsMoved] = useState(false);
|
const [isMoved, setIsMoved] = useState(false);
|
||||||
@ -37,6 +39,7 @@ export const AdminSpace = ({
|
|||||||
position: hide ? 'fixed' : 'relative',
|
position: hide ? 'fixed' : 'relative',
|
||||||
visibility: hide && 'hidden',
|
visibility: hide && 'hidden',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isAdmin && (
|
{!isAdmin && (
|
||||||
@ -56,6 +59,9 @@ export const AdminSpace = ({
|
|||||||
setIsForceShowCreationKeyPopup={setIsForceShowCreationKeyPopup}
|
setIsForceShowCreationKeyPopup={setIsForceShowCreationKeyPopup}
|
||||||
adminsWithNames={adminsWithNames}
|
adminsWithNames={adminsWithNames}
|
||||||
selectedGroup={selectedGroup}
|
selectedGroup={selectedGroup}
|
||||||
|
balance={balance}
|
||||||
|
userInfo={userInfo}
|
||||||
|
isOwner={isOwner}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,6 +15,7 @@ import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
|
|||||||
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
|
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
|
||||||
import { formatTimestampForum } from '../../utils/time';
|
import { formatTimestampForum } from '../../utils/time';
|
||||||
import { Spacer } from '../../common/Spacer';
|
import { Spacer } from '../../common/Spacer';
|
||||||
|
import { GroupAvatar } from '../GroupAvatar';
|
||||||
|
|
||||||
export const getPublishesFromAdminsAdminSpace = async (
|
export const getPublishesFromAdminsAdminSpace = async (
|
||||||
admins: string[],
|
admins: string[],
|
||||||
@ -53,6 +54,9 @@ export const AdminSpaceInner = ({
|
|||||||
selectedGroup,
|
selectedGroup,
|
||||||
adminsWithNames,
|
adminsWithNames,
|
||||||
setIsForceShowCreationKeyPopup,
|
setIsForceShowCreationKeyPopup,
|
||||||
|
balance,
|
||||||
|
userInfo,
|
||||||
|
isOwner,
|
||||||
}) => {
|
}) => {
|
||||||
const [adminGroupSecretKey, setAdminGroupSecretKey] = useState(null);
|
const [adminGroupSecretKey, setAdminGroupSecretKey] = useState(null);
|
||||||
const [isFetchingAdminGroupSecretKey, setIsFetchingAdminGroupSecretKey] =
|
const [isFetchingAdminGroupSecretKey, setIsFetchingAdminGroupSecretKey] =
|
||||||
@ -282,6 +286,32 @@ export const AdminSpaceInner = ({
|
|||||||
content encrypted with it.
|
content encrypted with it.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Spacer height="25px" />
|
||||||
|
{isOwner && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
border: '1px solid gray',
|
||||||
|
borderRadius: '6px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '20px',
|
||||||
|
maxWidth: '90%',
|
||||||
|
padding: '10px',
|
||||||
|
width: '300px',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Group Avatar</Typography>
|
||||||
|
|
||||||
|
<GroupAvatar
|
||||||
|
setOpenSnack={setOpenSnackGlobal}
|
||||||
|
setInfoSnack={setInfoSnackCustom}
|
||||||
|
myName={userInfo?.name}
|
||||||
|
balance={balance}
|
||||||
|
groupId={selectedGroup}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -68,6 +68,7 @@ import { AdminSpace } from '../Chat/AdminSpace';
|
|||||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import {
|
import {
|
||||||
addressInfoControllerAtom,
|
addressInfoControllerAtom,
|
||||||
|
groupsOwnerNamesAtom,
|
||||||
groupsPropertiesAtom,
|
groupsPropertiesAtom,
|
||||||
isOpenBlockedModalAtom,
|
isOpenBlockedModalAtom,
|
||||||
selectedGroupIdAtom,
|
selectedGroupIdAtom,
|
||||||
@ -449,10 +450,14 @@ export const Group = ({
|
|||||||
const [isOpenSideViewGroups, setIsOpenSideViewGroups] = useState(false);
|
const [isOpenSideViewGroups, setIsOpenSideViewGroups] = useState(false);
|
||||||
const [isForceShowCreationKeyPopup, setIsForceShowCreationKeyPopup] =
|
const [isForceShowCreationKeyPopup, setIsForceShowCreationKeyPopup] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
const groupsOwnerNamesRef = useRef({});
|
||||||
const { t } = useTranslation(['core', 'group']);
|
const { t } = useTranslation(['core', 'group']);
|
||||||
|
|
||||||
const [groupsProperties, setGroupsProperties] =
|
const [groupsProperties, setGroupsProperties] =
|
||||||
useRecoilState(groupsPropertiesAtom);
|
useRecoilState(groupsPropertiesAtom);
|
||||||
|
const [groupsOwnerNames, setGroupsOwnerNames] =
|
||||||
|
useRecoilState(groupsOwnerNamesAtom);
|
||||||
|
|
||||||
const setUserInfoForLevels = useSetRecoilState(addressInfoControllerAtom);
|
const setUserInfoForLevels = useSetRecoilState(addressInfoControllerAtom);
|
||||||
|
|
||||||
const isPrivate = useMemo(() => {
|
const isPrivate = useMemo(() => {
|
||||||
@ -826,6 +831,24 @@ export const Group = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getOwnerNameForGroup = async (owner: string, groupId: string) => {
|
||||||
|
try {
|
||||||
|
if (!owner) return;
|
||||||
|
if (groupsOwnerNamesRef.current[groupId]) return;
|
||||||
|
const name = await requestQueueMemberNames.enqueue(() => {
|
||||||
|
return getNameInfo(owner);
|
||||||
|
});
|
||||||
|
if (name) {
|
||||||
|
groupsOwnerNamesRef.current[groupId] = name;
|
||||||
|
setGroupsOwnerNames((prev) => {
|
||||||
|
return { ...prev, [groupId]: name };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getGroupsProperties = useCallback(async (address) => {
|
const getGroupsProperties = useCallback(async (address) => {
|
||||||
try {
|
try {
|
||||||
const url = `${getBaseApiReact()}/groups/member/${address}`;
|
const url = `${getBaseApiReact()}/groups/member/${address}`;
|
||||||
@ -837,6 +860,9 @@ export const Group = ({
|
|||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
setGroupsProperties(transformToObject);
|
setGroupsProperties(transformToObject);
|
||||||
|
Object.keys(transformToObject).forEach((key) => {
|
||||||
|
getOwnerNameForGroup(transformToObject[key]?.owner || '', key);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
@ -1024,6 +1050,8 @@ export const Group = ({
|
|||||||
triedToFetchSecretKey,
|
triedToFetchSecretKey,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
console.log('groupOwner?.owner', groupOwner);
|
||||||
|
|
||||||
const notifyAdmin = async (admin) => {
|
const notifyAdmin = async (admin) => {
|
||||||
try {
|
try {
|
||||||
setIsLoadingNotifyAdmin(true);
|
setIsLoadingNotifyAdmin(true);
|
||||||
@ -1299,6 +1327,8 @@ export const Group = ({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
console.log('selectedGroup', selectedGroup);
|
||||||
|
|
||||||
const openGroupChatFromNotification = (e) => {
|
const openGroupChatFromNotification = (e) => {
|
||||||
if (isLoadingOpenSectionFromNotification.current) return;
|
if (isLoadingOpenSectionFromNotification.current) return;
|
||||||
|
|
||||||
@ -1942,45 +1972,20 @@ export const Group = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
{groupsProperties[group?.groupId]?.isOpen === false ? (
|
{groupsOwnerNames[group?.groupId] ? (
|
||||||
<Box
|
<Avatar
|
||||||
sx={{
|
alt={group?.groupName?.charAt(0)}
|
||||||
alignItems: 'center',
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||||
background: theme.palette.background.default,
|
groupsOwnerNames[group?.groupId]
|
||||||
borderRadius: '50%',
|
}/qortal_group_avatar_${group?.groupId}?async=true`}
|
||||||
display: 'flex',
|
|
||||||
height: '40px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '40px',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{/* <Avatar src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
{group?.groupName?.charAt(0).toUpperCase()}
|
||||||
app?.name
|
</Avatar>
|
||||||
}/qortal_avatar?async=true`} /> */}
|
|
||||||
<LockIcon
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.other.positive,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Avatar alt={group?.groupName?.charAt(0)}>
|
||||||
sx={{
|
{' '}
|
||||||
alignItems: 'center',
|
{group?.groupName?.charAt(0).toUpperCase() || 'G'}
|
||||||
background: theme.palette.background.default,
|
</Avatar>
|
||||||
borderRadius: '50%',
|
|
||||||
display: 'flex',
|
|
||||||
height: '40px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '40px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NoEncryptionGmailerrorredIcon
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.other.danger,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)}
|
)}
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@ -2020,24 +2025,44 @@ export const Group = ({
|
|||||||
sx={{
|
sx={{
|
||||||
color: theme.palette.other.unread,
|
color: theme.palette.other.unread,
|
||||||
marginRight: '5px',
|
marginRight: '5px',
|
||||||
|
marginBottom: 'auto',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{group?.data &&
|
<Box
|
||||||
groupChatTimestamps[group?.groupId] &&
|
sx={{
|
||||||
group?.sender !== myAddress &&
|
display: 'flex',
|
||||||
group?.timestamp &&
|
flexDirection: 'column',
|
||||||
((!timestampEnterData[group?.groupId] &&
|
gap: '5px',
|
||||||
Date.now() - group?.timestamp <
|
justifyContent: 'flex-start',
|
||||||
timeDifferenceForNotificationChats) ||
|
height: '100%',
|
||||||
timestampEnterData[group?.groupId] <
|
marginBottom: 'auto',
|
||||||
group?.timestamp) && (
|
}}
|
||||||
<MarkChatUnreadIcon
|
>
|
||||||
|
{group?.data &&
|
||||||
|
groupChatTimestamps[group?.groupId] &&
|
||||||
|
group?.sender !== myAddress &&
|
||||||
|
group?.timestamp &&
|
||||||
|
((!timestampEnterData[group?.groupId] &&
|
||||||
|
Date.now() - group?.timestamp <
|
||||||
|
timeDifferenceForNotificationChats) ||
|
||||||
|
timestampEnterData[group?.groupId] <
|
||||||
|
group?.timestamp) && (
|
||||||
|
<MarkChatUnreadIcon
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.other.unread,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{groupsProperties[group?.groupId]?.isOpen === false && (
|
||||||
|
<LockIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: theme.palette.other.unread,
|
color: theme.palette.other.positive,
|
||||||
|
marginBottom: 'auto',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@ -2431,10 +2456,12 @@ export const Group = ({
|
|||||||
}
|
}
|
||||||
adminsWithNames={adminsWithNames}
|
adminsWithNames={adminsWithNames}
|
||||||
selectedGroup={selectedGroup?.groupId}
|
selectedGroup={selectedGroup?.groupId}
|
||||||
|
isOwner={groupOwner?.owner === myAddress}
|
||||||
myAddress={myAddress}
|
myAddress={myAddress}
|
||||||
userInfo={userInfo}
|
userInfo={userInfo}
|
||||||
hide={groupSection !== 'adminSpace'}
|
hide={groupSection !== 'adminSpace'}
|
||||||
isAdmin={admins.includes(myAddress)}
|
isAdmin={admins.includes(myAddress)}
|
||||||
|
balance={balance}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -49,7 +49,7 @@ import ErrorBoundary from '../../common/ErrorBoundary';
|
|||||||
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 { getFee } from '../../background';
|
import { getFee } from '../../background';
|
||||||
export const requestQueuePromos = new RequestQueueWithPromise(20);
|
export const requestQueuePromos = new RequestQueueWithPromise(3);
|
||||||
|
|
||||||
export function utf8ToBase64(inputString: string): string {
|
export function utf8ToBase64(inputString: string): string {
|
||||||
// Encode the string as UTF-8
|
// Encode the string as UTF-8
|
||||||
|
293
src/components/GroupAvatar.tsx
Normal file
293
src/components/GroupAvatar.tsx
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||||
|
import Logo2 from '../assets/svgs/Logo2.svg';
|
||||||
|
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
ButtonBase,
|
||||||
|
Popover,
|
||||||
|
Typography,
|
||||||
|
useTheme,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { Spacer } from '../common/Spacer';
|
||||||
|
import ImageUploader from '../common/ImageUploader';
|
||||||
|
import { getFee } from '../background';
|
||||||
|
import { fileToBase64 } from '../utils/fileReading';
|
||||||
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
|
|
||||||
|
export const GroupAvatar = ({
|
||||||
|
myName,
|
||||||
|
balance,
|
||||||
|
setOpenSnack,
|
||||||
|
setInfoSnack,
|
||||||
|
groupId,
|
||||||
|
}) => {
|
||||||
|
const [hasAvatar, setHasAvatar] = useState(false);
|
||||||
|
const [avatarFile, setAvatarFile] = useState(null);
|
||||||
|
const [tempAvatar, setTempAvatar] = useState(null);
|
||||||
|
const { show } = useContext(MyContext);
|
||||||
|
|
||||||
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
// Handle child element click to open Popover
|
||||||
|
const handleChildClick = (event) => {
|
||||||
|
event.stopPropagation(); // Prevent parent onClick from firing
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle closing the Popover
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine if the popover is open
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const id = open ? 'avatar-img' : undefined;
|
||||||
|
|
||||||
|
const checkIfAvatarExists = useCallback(async (name, groupId) => {
|
||||||
|
try {
|
||||||
|
const identifier = `qortal_group_avatar_${groupId}`;
|
||||||
|
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=THUMBNAIL&identifier=${identifier}&limit=1&name=${name}&includemetadata=false&prefix=true`;
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const responseData = await response.json();
|
||||||
|
if (responseData?.length > 0) {
|
||||||
|
setHasAvatar(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!myName || !groupId) return;
|
||||||
|
checkIfAvatarExists(myName, groupId);
|
||||||
|
}, [myName, groupId, checkIfAvatarExists]);
|
||||||
|
|
||||||
|
const publishAvatar = async () => {
|
||||||
|
try {
|
||||||
|
if (!groupId) return;
|
||||||
|
const fee = await getFee('ARBITRARY');
|
||||||
|
if (+balance < +fee.fee)
|
||||||
|
throw new Error(`Publishing an Avatar requires ${fee.fee}`);
|
||||||
|
await show({
|
||||||
|
message: 'Would you like to publish an avatar?',
|
||||||
|
publishFee: fee.fee + ' QORT',
|
||||||
|
});
|
||||||
|
setIsLoading(true);
|
||||||
|
const avatarBase64 = await fileToBase64(avatarFile);
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
window
|
||||||
|
.sendMessage('publishOnQDN', {
|
||||||
|
data: avatarBase64,
|
||||||
|
identifier: `qortal_group_avatar_${groupId}`,
|
||||||
|
service: 'THUMBNAIL',
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response?.error) {
|
||||||
|
res(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rej(response.error);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
rej(error.message || 'An error occurred');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setAvatarFile(null);
|
||||||
|
setTempAvatar(`data:image/webp;base64,${avatarBase64}`);
|
||||||
|
handleClose();
|
||||||
|
} catch (error) {
|
||||||
|
if (error?.message) {
|
||||||
|
setOpenSnack(true);
|
||||||
|
setInfoSnack({
|
||||||
|
type: 'error',
|
||||||
|
message: error?.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tempAvatar) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
height: '138px',
|
||||||
|
width: '138px',
|
||||||
|
}}
|
||||||
|
src={tempAvatar}
|
||||||
|
alt={myName}
|
||||||
|
>
|
||||||
|
{myName?.charAt(0)}
|
||||||
|
</Avatar>
|
||||||
|
<ButtonBase onClick={handleChildClick}>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
opacity: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
change avatar
|
||||||
|
</Typography>
|
||||||
|
</ButtonBase>
|
||||||
|
<PopoverComp
|
||||||
|
myName={myName}
|
||||||
|
avatarFile={avatarFile}
|
||||||
|
setAvatarFile={setAvatarFile}
|
||||||
|
id={id}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
handleClose={handleClose}
|
||||||
|
publishAvatar={publishAvatar}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAvatar) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
height: '138px',
|
||||||
|
width: '138px',
|
||||||
|
}}
|
||||||
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${myName}/qortal_group_avatar_${groupId}?async=true`}
|
||||||
|
alt={myName}
|
||||||
|
>
|
||||||
|
{myName?.charAt(0)}
|
||||||
|
</Avatar>
|
||||||
|
<ButtonBase onClick={handleChildClick}>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
opacity: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
change avatar
|
||||||
|
</Typography>
|
||||||
|
</ButtonBase>
|
||||||
|
<PopoverComp
|
||||||
|
myName={myName}
|
||||||
|
avatarFile={avatarFile}
|
||||||
|
setAvatarFile={setAvatarFile}
|
||||||
|
id={id}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
handleClose={handleClose}
|
||||||
|
publishAvatar={publishAvatar}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<img src={Logo2} />
|
||||||
|
<ButtonBase onClick={handleChildClick}>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
opacity: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
set avatar
|
||||||
|
</Typography>
|
||||||
|
</ButtonBase>
|
||||||
|
<PopoverComp
|
||||||
|
myName={myName}
|
||||||
|
avatarFile={avatarFile}
|
||||||
|
setAvatarFile={setAvatarFile}
|
||||||
|
id={id}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
handleClose={handleClose}
|
||||||
|
publishAvatar={publishAvatar}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PopoverComp = ({
|
||||||
|
avatarFile,
|
||||||
|
setAvatarFile,
|
||||||
|
id,
|
||||||
|
open,
|
||||||
|
anchorEl,
|
||||||
|
handleClose,
|
||||||
|
publishAvatar,
|
||||||
|
isLoading,
|
||||||
|
myName,
|
||||||
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
id={id}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
onClose={handleClose} // Close popover on click outside
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'center',
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ p: 2, display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
(500 KB max. for GIFS){' '}
|
||||||
|
</Typography>
|
||||||
|
<ImageUploader onPick={(file) => setAvatarFile(file)}>
|
||||||
|
<Button variant="contained">Choose Image</Button>
|
||||||
|
</ImageUploader>
|
||||||
|
{avatarFile?.name}
|
||||||
|
<Spacer height="25px" />
|
||||||
|
{!myName && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '5px',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ErrorIcon
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
|
A registered name is required to set an avatar
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Spacer height="25px" />
|
||||||
|
<LoadingButton
|
||||||
|
loading={isLoading}
|
||||||
|
disabled={!avatarFile || !myName}
|
||||||
|
onClick={publishAvatar}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Publish avatar
|
||||||
|
</LoadingButton>
|
||||||
|
</Box>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user