You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/dialog/EditProfilePictureModal.tsx

163 lines
5.0 KiB
TypeScript

import { useState } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { clearOurAvatar, uploadOurAvatar } from '../../interactions/conversationInteractions';
import { ToastUtils } from '../../session/utils';
import { editProfileModal, updateEditProfilePictureModal } from '../../state/ducks/modalDialog';
import type { EditProfilePictureModalProps } from '../../types/ReduxTypes';
import { pickFileForAvatar } from '../../types/attachments/VisualAttachment';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SpacerLG } from '../basic/Text';
import { SessionIconButton } from '../icon';
import { SessionSpinner } from '../loading';
import { ProfileAvatar } from './edit-profile/components';
const StyledAvatarContainer = styled.div`
cursor: pointer;
`;
const StyledUploadButton = styled.div`
background-color: var(--chat-buttons-background-color);
border-radius: 50%;
overflow: hidden;
`;
const UploadImageButton = () => {
return (
<div style={{ position: 'relative' }}>
<StyledUploadButton>
<SessionIconButton iconType="thumbnail" iconSize={80} iconPadding="16px" />
</StyledUploadButton>
<SessionIconButton
iconType="plusFat"
iconSize={23}
iconColor="var(--modal-background-content-color)"
iconPadding="5px"
borderRadius="50%"
backgroundColor="var(--primary-color)"
style={{ position: 'absolute', bottom: 0, right: 0 }}
/>
</div>
);
};
const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => {
if (scaledAvatarUrl?.length) {
try {
const blobContent = await (await fetch(scaledAvatarUrl)).blob();
if (!blobContent || !blobContent.size) {
throw new Error('Failed to fetch blob content from scaled avatar');
}
await uploadOurAvatar(await blobContent.arrayBuffer());
} catch (error) {
if (error.message && error.message.length) {
ToastUtils.pushToastError('edit-profile', error.message);
}
window.log.error(
'showEditProfileDialog Error ensuring that image is properly sized:',
error && error.stack ? error.stack : error
);
}
}
};
export const EditProfilePictureModal = (props: EditProfilePictureModalProps) => {
const dispatch = useDispatch();
const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState<string | null>(props.avatarPath);
const [loading, setLoading] = useState(false);
if (!props) {
return null;
}
const { avatarPath, profileName, ourId } = props;
const closeDialog = () => {
dispatch(updateEditProfilePictureModal(null));
dispatch(editProfileModal({}));
};
const handleAvatarClick = async () => {
const updatedAvatarObjectUrl = await pickFileForAvatar();
if (updatedAvatarObjectUrl) {
setNewAvatarObjectUrl(updatedAvatarObjectUrl);
}
};
const handleUpload = async () => {
setLoading(true);
if (newAvatarObjectUrl === avatarPath) {
window.log.debug('Avatar Object URL has not changed!');
return;
}
await uploadProfileAvatar(newAvatarObjectUrl);
setLoading(false);
dispatch(updateEditProfilePictureModal(null));
};
const handleRemove = async () => {
setLoading(true);
await clearOurAvatar();
setNewAvatarObjectUrl(null);
setLoading(false);
dispatch(updateEditProfilePictureModal(null));
};
return (
<SessionWrapperModal
title={window.i18n('profileDisplayPictureSet')}
onClose={closeDialog}
showHeader={true}
headerReverse={true}
showExitIcon={true}
>
<div
className="avatar-center"
role="button"
onClick={() => void handleAvatarClick()}
data-testid={'image-upload-click'}
>
<StyledAvatarContainer className="avatar-center-inner">
{newAvatarObjectUrl || avatarPath ? (
<ProfileAvatar
newAvatarObjectUrl={newAvatarObjectUrl}
avatarPath={avatarPath}
profileName={profileName}
ourId={ourId}
/>
) : (
<UploadImageButton />
)}
</StyledAvatarContainer>
</div>
{loading ? (
<SessionSpinner loading={loading} />
) : (
<>
<SpacerLG />
<div className="session-modal__button-group">
<SessionButton
text={window.i18n('save')}
buttonType={SessionButtonType.Simple}
onClick={handleUpload}
disabled={newAvatarObjectUrl === avatarPath}
dataTestId="save-button-profile-update"
/>
<SessionButton
text={window.i18n('remove')}
buttonColor={SessionButtonColor.Danger}
buttonType={SessionButtonType.Simple}
onClick={handleRemove}
disabled={!avatarPath}
/>
</div>
</>
)}
</SessionWrapperModal>
);
};