diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index de96d47c0..6c23f393b 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -571,6 +571,12 @@ "coverRemoved": "Cover art removed", "coverUploadError": "Error uploading cover art", "coverRemoveError": "Error removing cover art", + "uploadAvatar": "Upload avatar", + "removeAvatar": "Remove avatar", + "avatarUploaded": "Avatar updated", + "avatarUploadError": "Error updating avatar", + "avatarRemoved": "Avatar removed", + "avatarRemoveError": "Error removing avatar", "metadataRefreshStarted": "Refreshing metadata in the background", "note": "NOTE", "transcodingDisabled": "Changing the transcoding configuration through the web interface is disabled for security reasons. If you would like to change (edit or add) transcoding options, restart the server with the %{config} configuration option.", diff --git a/ui/src/user/UserEdit.jsx b/ui/src/user/UserEdit.jsx index c5d9c75a4..b6523bc2b 100644 --- a/ui/src/user/UserEdit.jsx +++ b/ui/src/user/UserEdit.jsx @@ -20,8 +20,10 @@ import { usePermissions, useRecordContext, } from 'react-admin' -import { Typography } from '@material-ui/core' -import { Title } from '../common' +import { Avatar, Typography } from '@material-ui/core' +import { Title, ImageUploadOverlay } from '../common' +import subsonic from '../subsonic' +import config from '../config' import DeleteUserButton from './DeleteUserButton' import { LibrarySelectionField } from './LibrarySelectionField.jsx' import { validateUserForm } from './userValidation' @@ -33,6 +35,17 @@ const useStyles = makeStyles({ }, }) +const useAvatarStyles = makeStyles({ + avatarParent: { + display: 'inline-flex', + position: 'relative', + width: '8rem', + height: '8rem', + marginBottom: '1em', + }, + avatar: { width: '100%', height: '100%' }, +}) + const UserTitle = ({ record }) => { const translate = useTranslate() const resourceName = translate('resources.user.name', { smart_count: 1 }) @@ -65,6 +78,46 @@ const NewPasswordInput = ({ formData, ...rest }) => { ) : null } +const AvatarField = () => { + const record = useRecordContext() + const { permissions } = usePermissions() + const isAdmin = permissions === 'admin' + const isMyself = localStorage.getItem('userId') === record?.id + // Mirrors server canEditAvatar: the flag gates everyone, admins included. + const canEdit = config.enableUserAvatarUpload && (isAdmin || isMyself) + const classes = useAvatarStyles() + + if (!record?.id) return null + + return ( +
{children}
, + Avatar: ({ src, alt }) =>