diff --git a/client/src/actions/entry/modal.js b/client/src/actions/entry/modal.js index 1cfff668..533bddc8 100755 --- a/client/src/actions/entry/modal.js +++ b/client/src/actions/entry/modal.js @@ -8,6 +8,13 @@ export const openUsersModal = () => ({ }, }); +export const openUserSettingsModal = () => ({ + type: EntryActionTypes.MODAL_OPEN, + payload: { + type: ModalTypes.USER_SETTINGS, + }, +}); + export const openAddProjectModal = () => ({ type: EntryActionTypes.MODAL_OPEN, payload: { diff --git a/client/src/components/App.jsx b/client/src/components/App.jsx index 46246488..9a815282 100755 --- a/client/src/components/App.jsx +++ b/client/src/components/App.jsx @@ -4,19 +4,22 @@ import PropTypes from 'prop-types'; import HeaderContainer from '../containers/HeaderContainer'; import ProjectsContainer from '../containers/ProjectsContainer'; import UsersModalContainer from '../containers/UsersModalContainer'; +import UserSettingsModalContainer from '../containers/UserSettingsModalContainer'; import AddProjectModalContainer from '../containers/AddProjectModalContainer'; -const App = ({ isUsersModalOpened, isAddProjectModalOpened }) => ( +const App = ({ isUsersModalOpened, isUserSettingsModalOpened, isAddProjectModalOpened }) => ( <> {isUsersModalOpened && } + {isUserSettingsModalOpened && } {isAddProjectModalOpened && } ); App.propTypes = { isUsersModalOpened: PropTypes.bool.isRequired, + isUserSettingsModalOpened: PropTypes.bool.isRequired, isAddProjectModalOpened: PropTypes.bool.isRequired, }; diff --git a/client/src/components/Header/Header.jsx b/client/src/components/Header/Header.jsx index 7f18bcb6..9c5ea2bd 100755 --- a/client/src/components/Header/Header.jsx +++ b/client/src/components/Header/Header.jsx @@ -16,14 +16,7 @@ const Header = React.memo( isEditable, onUsers, onNotificationDelete, - onUserUpdate, - onUserAvatarUpload, - onUserUsernameUpdate, - onUserUsernameUpdateMessageDismiss, - onUserEmailUpdate, - onUserEmailUpdateMessageDismiss, - onUserPasswordUpdate, - onUserPasswordUpdateMessageDismiss, + onUserSettings, onLogout, }) => (
@@ -45,25 +38,7 @@ const Header = React.memo( )} - + {user.name} @@ -80,14 +55,7 @@ Header.propTypes = { isEditable: PropTypes.bool.isRequired, onUsers: PropTypes.func.isRequired, onNotificationDelete: PropTypes.func.isRequired, - onUserUpdate: PropTypes.func.isRequired, - onUserAvatarUpload: PropTypes.func.isRequired, - onUserUsernameUpdate: PropTypes.func.isRequired, - onUserUsernameUpdateMessageDismiss: PropTypes.func.isRequired, - onUserEmailUpdate: PropTypes.func.isRequired, - onUserEmailUpdateMessageDismiss: PropTypes.func.isRequired, - onUserPasswordUpdate: PropTypes.func.isRequired, - onUserPasswordUpdateMessageDismiss: PropTypes.func.isRequired, + onUserSettings: PropTypes.func.isRequired, onLogout: PropTypes.func.isRequired, }; diff --git a/client/src/components/User/User.jsx b/client/src/components/User/User.jsx index 1ad33360..1bf1c5e3 100755 --- a/client/src/components/User/User.jsx +++ b/client/src/components/User/User.jsx @@ -10,6 +10,7 @@ const SIZES = { SMALL: 'small', MEDIUM: 'medium', LARGE: 'large', + MASSIVE: 'massive', }; // TODO: move to styles @@ -43,6 +44,13 @@ const STYLES = { padding: '12px 0 10px', width: '36px', }, + massive: { + fontSize: '36px', + fontWeight: '500', + height: '100px', + padding: '32px 0 10px', + width: '100px', + }, }; const COLORS = [ diff --git a/client/src/components/UserPopup/EditAvatarStep.jsx b/client/src/components/UserPopup/EditAvatarStep.jsx deleted file mode 100755 index 0282b988..00000000 --- a/client/src/components/UserPopup/EditAvatarStep.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { useCallback, useEffect, useRef } from 'react'; -import PropTypes from 'prop-types'; -import { useTranslation } from 'react-i18next'; -import { Button } from 'semantic-ui-react'; -import { Popup } from '../../lib/custom-ui'; - -import User from '../User'; - -import styles from './EditAvatarStep.module.css'; - -const EditAvatarStep = React.memo( - ({ defaultValue, name, isUploading, onUpload, onClear, onBack }) => { - const [t] = useTranslation(); - - const field = useRef(null); - - const handleFieldChange = useCallback( - ({ target }) => { - if (target.files[0]) { - onUpload(target.files[0]); - - target.value = null; // eslint-disable-line no-param-reassign - } - }, - [onUpload], - ); - - useEffect(() => { - field.current.focus(); - }, []); - - return ( - <> - - {t('common.editAvatar', { - context: 'title', - })} - - - -
-
- {defaultValue && + +
+
+ + + +
+
+ + + +
+ + ); + }, +); + +AccountPane.propTypes = { + email: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + username: PropTypes.string, + avatar: PropTypes.string, + isAvatarUploading: PropTypes.bool.isRequired, + /* eslint-disable react/forbid-prop-types */ + usernameUpdateForm: PropTypes.object.isRequired, + emailUpdateForm: PropTypes.object.isRequired, + passwordUpdateForm: PropTypes.object.isRequired, + /* eslint-enable react/forbid-prop-types */ + onUpdate: PropTypes.func.isRequired, + onAvatarUpload: PropTypes.func.isRequired, + onUsernameUpdate: PropTypes.func.isRequired, + onUsernameUpdateMessageDismiss: PropTypes.func.isRequired, + onEmailUpdate: PropTypes.func.isRequired, + onEmailUpdateMessageDismiss: PropTypes.func.isRequired, + onPasswordUpdate: PropTypes.func.isRequired, + onPasswordUpdateMessageDismiss: PropTypes.func.isRequired, +}; + +AccountPane.defaultProps = { + username: undefined, + avatar: undefined, +}; + +export default AccountPane; diff --git a/client/src/components/UserSettingsModal/AccountPane/AccountPane.module.css b/client/src/components/UserSettingsModal/AccountPane/AccountPane.module.css new file mode 100644 index 00000000..f2e68a67 --- /dev/null +++ b/client/src/components/UserSettingsModal/AccountPane/AccountPane.module.css @@ -0,0 +1,30 @@ +.action { + border: none; + display: inline-block; + height: 36px; + overflow: hidden; + position: relative; + transition: background 0.3s ease; + width: 100%; +} + +.action:hover { + background: #e9e9e9 !important; +} + +.actionButton { + background: transparent !important; + color: #6b808c !important; + font-weight: normal !important; + height: 36px; + line-height: 24px !important; + padding: 6px 12px !important; + text-align: left !important; + text-decoration: underline !important; + width: 100%; +} + +.wrapper { + border: none !important; + box-shadow: none !important; +} diff --git a/client/src/components/UserSettingsModal/AccountPane/EditAvatarPopup.jsx b/client/src/components/UserSettingsModal/AccountPane/EditAvatarPopup.jsx new file mode 100644 index 00000000..55182feb --- /dev/null +++ b/client/src/components/UserSettingsModal/AccountPane/EditAvatarPopup.jsx @@ -0,0 +1,71 @@ +import React, { useCallback, useEffect, useRef } from 'react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'semantic-ui-react'; +import { withPopup } from '../../../lib/popup'; +import { Popup } from '../../../lib/custom-ui'; + +import styles from './EditAvatarPopup.module.css'; + +const EditAvatarStep = React.memo(({ defaultValue, onUpload, onDelete, onClose }) => { + const [t] = useTranslation(); + + const field = useRef(null); + + const handleFieldChange = useCallback( + ({ target }) => { + if (target.files[0]) { + onUpload(target.files[0]); + onClose(); + } + }, + [onUpload, onClose], + ); + + const handleDeleteClick = useCallback(() => { + onDelete(); + onClose(); + }, [onDelete, onClose]); + + useEffect(() => { + field.current.focus(); + }, []); + + return ( + <> + + {t('common.editAvatar', { + context: 'title', + })} + + +
+
+ {defaultValue && ( +