-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add account data deletion functionality (#738)
Includes refactoring of Avatar Upload functionality to unionize it. * Add account data deletion functionality with deletion modal * Add profile deletion notification * Make remove data component into button and change Settings view * Reroute to dashboard after delete profile is complete * Separate component DialogContentUploader from EditProfile * Break out DialogAvatarUpload from EditProfile * Make AvatarUploader the universal uploader * Unionize setAvatarUploadUrl for camera upload and file upload * Change Dialog component and use it in EditProfile * Use latest core version with delete profile data functionality * Add core methods for upload correctly and use in Upload * Pass avatarUploadUrl to upload components * Delete old avatar on save new profile * Delete old unsaved upload upon new unsaved upload in onboarding and edit * Delete avatar image when deleting user entry in delete profile * Make upload onboarding continue possible with new component * Show avatar in next steps after uploading it in onboarding * Make avatar upload persist when going backwards in onboarding * Fix loading state for file upload * Add option to edit profile in profile deletion modal from settings Other: * Fix count of unread news in unread activities on dashboard * Delete old todo note in TabNavigationAction (fixed) * Skip blue border on avatar hover by default --------- Co-authored-by: Louise Linné <[email protected]>
- Loading branch information
Showing
20 changed files
with
4,388 additions
and
1,049 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,137 +1,83 @@ | ||
import { Avatar, Box, CircularProgress, Typography } from '@mui/material'; | ||
import { Box, CircularProgress } from '@mui/material'; | ||
import makeStyles from '@mui/styles/makeStyles'; | ||
import mime from 'mime/lite'; | ||
import PropTypes from 'prop-types'; | ||
import React, { Fragment, useEffect, useRef, useState } from 'react'; | ||
import { useDispatch } from 'react-redux'; | ||
import React, { Fragment, useEffect, useState } from 'react'; | ||
import { useSelector } from 'react-redux'; | ||
|
||
import GroupWalletCircleSVG from '%/images/organization-indicator.svg'; | ||
import core from '~/services/core'; | ||
import translate from '~/services/locale'; | ||
import notify, { NotificationsTypes } from '~/store/notifications/actions'; | ||
|
||
const IMAGE_FILE_TYPES = ['jpg', 'jpeg', 'png']; | ||
import Avatar from '~/components/Avatar'; | ||
import DialogAvatarUpload from '~/components/DialogAvatarUpload'; | ||
import { IconPlus } from '~/styles/icons'; | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
avatarUpload: { | ||
margin: '0 auto', | ||
width: theme.custom.components.avatarUploader, | ||
height: theme.custom.components.avatarUploader, | ||
color: theme.palette.text.primary, | ||
fontSize: '30px', | ||
fontWeight: theme.typography.fontWeightMedium, | ||
backgroundColor: theme.custom.colors.white, | ||
border: `1px solid ${theme.palette.text.primary}`, | ||
cursor: 'pointer', | ||
position: 'relative', | ||
zIndex: theme.zIndex.layer1, | ||
}, | ||
indicatorContainer: { | ||
position: 'absolute', | ||
zIndex: theme.zIndex.layer1, | ||
top: '-2px', | ||
left: 0, | ||
border: `1px solid ${theme.palette.secondary.main}`, | ||
}, | ||
avatarUploaderContainer: { | ||
width: theme.custom.components.avatarUploader, | ||
height: theme.custom.components.avatarUploader, | ||
margin: '0 auto', | ||
display: 'inline-flex', | ||
position: 'relative', | ||
flexShrink: 0, | ||
verticalAlign: 'middle', | ||
}, | ||
plusIcon: { | ||
fontSize: '16px', | ||
zIndex: theme.zIndex.layer2, | ||
}, | ||
})); | ||
|
||
const AvatarUploader = ({ | ||
handleUpload, | ||
onLoadingChange, | ||
onUpload, | ||
value, | ||
shouldHaveIndicator, | ||
showIndicatorRing, | ||
presetUrl, | ||
}) => { | ||
const classes = useStyles(); | ||
|
||
const dispatch = useDispatch(); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const fileInputElem = useRef(); | ||
|
||
const handleUploadClick = (event) => { | ||
event.preventDefault(); | ||
fileInputElem.current.click(); | ||
}; | ||
const [isOpenDialogUploadInfo, setIsOpenDialogUploadInfo] = useState(false); | ||
const [avatarUploadUrl, setAvatarUploadUrl] = useState(presetUrl); | ||
const isLoading = useSelector((state) => state.isLoading); | ||
|
||
useEffect(() => { | ||
onLoadingChange(isLoading); | ||
}, [isLoading, onLoadingChange]); | ||
|
||
const handleChange = async (event) => { | ||
setIsLoading(true); | ||
|
||
const { files } = event.target; | ||
if (files.length === 0) { | ||
return; | ||
} | ||
|
||
try { | ||
const result = await core.utils.requestAPI({ | ||
path: ['uploads', 'avatar'], | ||
method: 'POST', | ||
data: [...files].reduce((acc, file) => { | ||
acc.append('files', file, file.name); | ||
return acc; | ||
}, new FormData()), | ||
}); | ||
|
||
onUpload(result.data.url); | ||
} catch (error) { | ||
dispatch( | ||
notify({ | ||
text: ( | ||
<Typography classes={{ root: 'body4_white' }} variant="body4"> | ||
{translate('AvatarUploader.errorAvatarUpload')} | ||
</Typography> | ||
), | ||
type: NotificationsTypes.ERROR, | ||
}), | ||
); | ||
} | ||
|
||
setIsLoading(false); | ||
}; | ||
|
||
const fileTypesStr = IMAGE_FILE_TYPES.map((ext) => { | ||
return mime.getType(ext); | ||
}).join(','); | ||
|
||
return ( | ||
<Fragment> | ||
<Box className={classes.avatarUploaderContainer}> | ||
{shouldHaveIndicator && ( | ||
<Box className={classes.indicatorContainer}> | ||
<GroupWalletCircleSVG width={94} /> | ||
</Box> | ||
)} | ||
<DialogAvatarUpload | ||
avatarUploadUrl={avatarUploadUrl} | ||
handleClose={() => setIsOpenDialogUploadInfo(false)} | ||
handleUpload={handleUpload} | ||
isOpen={isOpenDialogUploadInfo} | ||
setAvatarUploadUrl={setAvatarUploadUrl} | ||
/> | ||
<Box | ||
className={classes.avatarUploaderContainer} | ||
onClick={() => setIsOpenDialogUploadInfo(true)} | ||
> | ||
<Avatar | ||
className={classes.avatarUpload} | ||
src={isLoading ? null : value} | ||
onClick={handleUploadClick} | ||
showIndicatorRing={showIndicatorRing} | ||
size="medium" | ||
url={avatarUploadUrl} | ||
withClickEffect={isOpenDialogUploadInfo} | ||
withHoverEffect | ||
> | ||
{isLoading ? <CircularProgress /> : '+'} | ||
{isLoading ? ( | ||
<CircularProgress /> | ||
) : ( | ||
<IconPlus className={classes.plusIcon} /> | ||
)} | ||
</Avatar> | ||
<input | ||
accept={fileTypesStr} | ||
ref={fileInputElem} | ||
style={{ display: 'none' }} | ||
type="file" | ||
onChange={handleChange} | ||
/> | ||
</Box> | ||
</Fragment> | ||
); | ||
}; | ||
|
||
AvatarUploader.propTypes = { | ||
handleUpload: PropTypes.func, | ||
onLoadingChange: PropTypes.func.isRequired, | ||
onUpload: PropTypes.func.isRequired, | ||
shouldHaveIndicator: PropTypes.bool, | ||
value: PropTypes.string, | ||
presetUrl: PropTypes.string, | ||
showIndicatorRing: PropTypes.bool, | ||
}; | ||
|
||
export default AvatarUploader; |
Oops, something went wrong.