add option to update profile avatar

This commit is contained in:
Ajay Bura 2024-12-15 09:42:48 +05:30
parent 9c46a6f43a
commit de281adc36

View file

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { import {
Box, Box,
Text, Text,
@ -14,6 +14,9 @@ import {
OverlayBackdrop, OverlayBackdrop,
OverlayCenter, OverlayCenter,
Modal, Modal,
Dialog,
Header,
config,
} from 'folds'; } from 'folds';
import FocusTrap from 'focus-trap-react'; import FocusTrap from 'focus-trap-react';
import { Page, PageContent, PageHeader } from '../../components/page'; import { Page, PageContent, PageHeader } from '../../components/page';
@ -33,6 +36,9 @@ import { useObjectURL } from '../../hooks/useObjectURL';
import { stopPropagation } from '../../utils/keyboard'; import { stopPropagation } from '../../utils/keyboard';
import { ImageEditor } from '../../components/image-editor'; import { ImageEditor } from '../../components/image-editor';
import { ModalWide } from '../../styles/Modal.css'; import { ModalWide } from '../../styles/Modal.css';
import { createUploadAtom, UploadSuccess } from '../../state/upload';
import { CompactUploadCardRenderer } from '../../components/upload-card';
import { useCapabilities } from '../../hooks/useCapabilities';
function MatrixId() { function MatrixId() {
const mx = useMatrixClient(); const mx = useMatrixClient();
@ -67,6 +73,9 @@ type ProfileAvatarProps = {
function ProfileAvatar({ profile, userId }: ProfileAvatarProps) { function ProfileAvatar({ profile, userId }: ProfileAvatarProps) {
const mx = useMatrixClient(); const mx = useMatrixClient();
const useAuthentication = useMediaAuthentication(); const useAuthentication = useMediaAuthentication();
const capabilities = useCapabilities();
const [alertRemove, setAlertRemove] = useState(false);
const disableSetAvatar = capabilities['m.set_avatar_url']?.enabled === false;
const defaultDisplayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId; const defaultDisplayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId;
const avatarUrl = profile.avatarUrl const avatarUrl = profile.avatarUrl
@ -75,13 +84,31 @@ function ProfileAvatar({ profile, userId }: ProfileAvatarProps) {
const [imageFile, setImageFile] = useState<File>(); const [imageFile, setImageFile] = useState<File>();
const imageFileURL = useObjectURL(imageFile); const imageFileURL = useObjectURL(imageFile);
const uploadAtom = useMemo(() => {
if (imageFile) return createUploadAtom(imageFile);
return undefined;
}, [imageFile]);
const pickFile = useFilePicker(setImageFile, false); const pickFile = useFilePicker(setImageFile, false);
const handleImageCropperClose = useCallback(() => { const handleRemoveUpload = useCallback(() => {
setImageFile(undefined); setImageFile(undefined);
}, []); }, []);
const handleUploaded = useCallback(
(upload: UploadSuccess) => {
const { mxc } = upload;
mx.setAvatarUrl(mxc);
handleRemoveUpload();
},
[mx, handleRemoveUpload]
);
const handleRemoveAvatar = () => {
mx.setAvatarUrl('');
setAlertRemove(false);
};
return ( return (
<SettingTile <SettingTile
title={ title={
@ -99,46 +126,103 @@ function ProfileAvatar({ profile, userId }: ProfileAvatarProps) {
</Avatar> </Avatar>
} }
> >
<Box gap="200"> {uploadAtom ? (
<Button <Box gap="200" direction="Column">
onClick={() => pickFile('image/*')} <CompactUploadCardRenderer
size="300" uploadAtom={uploadAtom}
variant="Secondary" onRemove={handleRemoveUpload}
fill="Soft" onComplete={handleUploaded}
outlined />
radii="300" </Box>
> ) : (
<Text size="B300">Upload</Text> <Box gap="200">
</Button> <Button
{avatarUrl && ( onClick={() => pickFile('image/*')}
<Button size="300" variant="Critical" fill="None" radii="300"> size="300"
<Text size="B300">Remove</Text> variant="Secondary"
fill="Soft"
outlined
radii="300"
disabled={disableSetAvatar}
>
<Text size="B300">Upload</Text>
</Button> </Button>
)} {avatarUrl && (
<Button
size="300"
variant="Critical"
fill="None"
radii="300"
disabled={disableSetAvatar}
onClick={() => setAlertRemove(true)}
>
<Text size="B300">Remove</Text>
</Button>
)}
</Box>
)}
{imageFileURL && ( {imageFileURL && (
<Overlay open backdrop={<OverlayBackdrop />}> <Overlay open={false} backdrop={<OverlayBackdrop />}>
<OverlayCenter> <OverlayCenter>
<FocusTrap <FocusTrap
focusTrapOptions={{ focusTrapOptions={{
initialFocus: false, initialFocus: false,
onDeactivate: handleImageCropperClose, onDeactivate: handleRemoveUpload,
clickOutsideDeactivates: true, clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation, escapeDeactivates: stopPropagation,
}}
>
<Modal className={ModalWide} variant="Surface" size="500">
<ImageEditor
name={imageFile?.name ?? 'Unnamed'}
url={imageFileURL}
requestClose={handleRemoveUpload}
/>
</Modal>
</FocusTrap>
</OverlayCenter>
</Overlay>
)}
<Overlay open={alertRemove} backdrop={<OverlayBackdrop />}>
<OverlayCenter>
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setAlertRemove(false),
clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation,
}}
>
<Dialog variant="Surface">
<Header
style={{
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
borderBottomWidth: config.borderWidth.B300,
}} }}
variant="Surface"
size="500"
> >
<Modal className={ModalWide} variant="Surface" size="500"> <Box grow="Yes">
<ImageEditor <Text size="H4">Remove Avatar</Text>
name={imageFile?.name ?? 'Unnamed'} </Box>
url={imageFileURL} <IconButton size="300" onClick={() => setAlertRemove(false)} radii="300">
requestClose={handleImageCropperClose} <Icon src={Icons.Cross} />
/> </IconButton>
</Modal> </Header>
</FocusTrap> <Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
</OverlayCenter> <Box direction="Column" gap="200">
</Overlay> <Text priority="400">Are you sure you want to remove profile avatar?</Text>
)} </Box>
</Box> <Button variant="Critical" onClick={handleRemoveAvatar}>
<Text size="B400">Remove</Text>
</Button>
</Box>
</Dialog>
</FocusTrap>
</OverlayCenter>
</Overlay>
</SettingTile> </SettingTile>
); );
} }