From c3562b48bd9725a1b18a939fc35748c87d3f1d02 Mon Sep 17 00:00:00 2001 From: bourquecharles Date: Tue, 20 Jul 2021 16:53:27 -0400 Subject: [PATCH] Edit user, edit profile, create user form --- package-lock.json | 4 +- package.json | 2 +- src/components/CreateUserForm/index.js | 76 +++++------- src/components/EditMyProfile/index.js | 140 ++++++++++++++++++++++ src/components/EditUserForm/index.js | 149 +++++++++++++++++++++++ src/components/EditUserModal/index.js | 49 ++++++++ src/components/NotesTable/index.js | 87 ++++++++++++++ src/components/UserListTable/index.js | 152 ++++++++++++++---------- src/components/UserProfileCard/index.js | 139 ---------------------- src/hooks/useUser/index.js | 2 +- src/index.js | 4 +- src/layout/Header/index.js | 8 +- 12 files changed, 554 insertions(+), 258 deletions(-) create mode 100644 src/components/EditMyProfile/index.js create mode 100644 src/components/EditUserForm/index.js create mode 100644 src/components/EditUserModal/index.js create mode 100644 src/components/NotesTable/index.js delete mode 100644 src/components/UserProfileCard/index.js diff --git a/package-lock.json b/package-lock.json index b514e85..c48bc17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ucentral-libs", - "version": "0.8.15", + "version": "0.8.16", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ucentral-libs", - "version": "0.8.15", + "version": "0.8.16", "devDependencies": { "@babel/core": "^7.14.6", "@babel/plugin-proposal-class-properties": "^7.14.5", diff --git a/package.json b/package.json index 6e0b08d..31949d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ucentral-libs", - "version": "0.8.15", + "version": "0.8.16", "main": "dist/index.js", "source": "src/index.js", "engines": { diff --git a/src/components/CreateUserForm/index.js b/src/components/CreateUserForm/index.js index f64d214..845eb85 100644 --- a/src/components/CreateUserForm/index.js +++ b/src/components/CreateUserForm/index.js @@ -28,7 +28,7 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies return ( - + {t('user.email_address')} @@ -42,14 +42,41 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies /> {t('user.provide_email')} + + {t('user.user_role')} + + + + + + + + + + + + + {t('user.name')} + + {t('user.description')} + + + + {t('common.optional')} + - + {t('user.password')} @@ -89,19 +116,6 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies - - {t('user.user_role')} - - - - - - - - - - - {t('user.note')} @@ -110,35 +124,9 @@ const CreateUserForm = ({ t, fields, updateField, createUser, loading, policies {t('common.optional')} - - - {t('user.description')} - - - - {t('common.optional')} - - - - - - + - + { + const [showPassword, setShowPassword] = useState(false); + + const toggleShowPassword = () => { + setShowPassword(!showPassword); + }; + + return ( + + + + {t('user.name')} + + + + + + {t('user.description')} + + + + + + + + {t('user.user_role')} + + + + + + + + + + + + + {t('login.new_password')} + + + + + + + + + + + + {t('user.provide_password')} + + + + + + + + + + + + + + + + + + + ); +}; + +EditMyProfile.propTypes = { + t: PropTypes.func.isRequired, + user: PropTypes.instanceOf(Object).isRequired, + updateUserWithId: PropTypes.func.isRequired, + loading: PropTypes.bool.isRequired, + saveUser: PropTypes.func.isRequired, + policies: PropTypes.instanceOf(Object).isRequired, + addNote: PropTypes.func.isRequired, +}; + +export default React.memo(EditMyProfile); diff --git a/src/components/EditUserForm/index.js b/src/components/EditUserForm/index.js new file mode 100644 index 0000000..e1f4315 --- /dev/null +++ b/src/components/EditUserForm/index.js @@ -0,0 +1,149 @@ +import React, { useState } from 'react'; +import { + CButton, + CCol, + CForm, + CFormGroup, + CInput, + CInputGroup, + CInputGroupAppend, + CInvalidFeedback, + CLabel, + CLink, + CPopover, + CRow, + CSelect, + CSwitch, +} from '@coreui/react'; +import PropTypes from 'prop-types'; +import CIcon from '@coreui/icons-react'; +import NotesTable from '../NotesTable'; +import LoadingButton from '../LoadingButton'; + +const EditUserForm = ({ t, user, updateUserWithId, loading, saveUser, policies, addNote }) => { + const [showPassword, setShowPassword] = useState(false); + + const toggleShowPassword = () => { + setShowPassword(!showPassword); + }; + + return ( + + + + {t('user.name')} + + + + + + {t('user.description')} + + + + + + + + {t('user.user_role')} + + + + + + + + + + + + + {t('login.new_password')} + + + + + + + + + + + + {t('user.provide_password')} + + + + + + {t('user.force_password_change')} + + + + + + + + + + + + + + + + + + + + + ); +}; + +EditUserForm.propTypes = { + t: PropTypes.func.isRequired, + user: PropTypes.instanceOf(Object).isRequired, + updateUserWithId: PropTypes.func.isRequired, + loading: PropTypes.bool.isRequired, + saveUser: PropTypes.func.isRequired, + policies: PropTypes.instanceOf(Object).isRequired, + addNote: PropTypes.func.isRequired, +}; + +export default React.memo(EditUserForm); diff --git a/src/components/EditUserModal/index.js b/src/components/EditUserModal/index.js new file mode 100644 index 0000000..f03b756 --- /dev/null +++ b/src/components/EditUserModal/index.js @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { CModal, CModalBody, CModalHeader, CModalTitle } from '@coreui/react'; +import EditUserForm from '../EditUserForm'; + +const EditUserModal = ({ + t, + user, + updateUserWithId, + saveUser, + loading, + policies, + show, + toggle, + addNote, +}) => ( + + + + {t('user.edit')} {user.email.value} + + + + + + +); + +EditUserModal.propTypes = { + t: PropTypes.func.isRequired, + user: PropTypes.instanceOf(Object).isRequired, + updateUserWithId: PropTypes.func.isRequired, + loading: PropTypes.bool.isRequired, + saveUser: PropTypes.func.isRequired, + policies: PropTypes.instanceOf(Object).isRequired, + show: PropTypes.bool.isRequired, + toggle: PropTypes.func.isRequired, + addNote: PropTypes.func.isRequired, +}; + +export default React.memo(EditUserModal); diff --git a/src/components/NotesTable/index.js b/src/components/NotesTable/index.js new file mode 100644 index 0000000..fa2876f --- /dev/null +++ b/src/components/NotesTable/index.js @@ -0,0 +1,87 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { CDataTable, CRow, CCol, CLabel, CInput } from '@coreui/react'; +import { prettyDate } from '../../utils/formatting'; +import LoadingButton from '../LoadingButton'; + +const NotesTable = ({ t, notes, addNote, loading, size }) => { + const [currentNote, setCurrentNote] = useState(''); + + const columns = [ + { key: 'created', label: t('common.date'), _style: { width: '30%' } }, + { key: 'createdBy', label: t('common.created_by'), _style: { width: '20%' } }, + { key: 'note', label: t('configuration.note'), _style: { width: '50%' } }, + ]; + + const saveNote = () => { + addNote(currentNote); + }; + + useEffect(() => { + setCurrentNote(''); + }, [notes]); + + return ( +
+ + + {t('configuration.notes')} : + + + setCurrentNote(e.target.value)} + /> + + + + + + + +
+ ( + + {item.created && item.created !== 0 ? prettyDate(item.created) : t('common.na')} + + ), + }} + /> +
+
+
+
+ ); +}; + +NotesTable.propTypes = { + t: PropTypes.func.isRequired, + notes: PropTypes.instanceOf(Array).isRequired, + addNote: PropTypes.func.isRequired, + loading: PropTypes.bool.isRequired, + size: PropTypes.string, +}; + +NotesTable.defaultProps = { + size: 'm', +}; + +export default NotesTable; diff --git a/src/components/UserListTable/index.js b/src/components/UserListTable/index.js index f22f942..8f6af0c 100644 --- a/src/components/UserListTable/index.js +++ b/src/components/UserListTable/index.js @@ -2,18 +2,17 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; import ReactPaginate from 'react-paginate'; import { + CButton, CCard, - CCardHeader, - CSelect, - CCol, - CRow, CCardBody, + CCardHeader, + CCol, CDataTable, CPopover, - CButton, - CLink, + CRow, + CSelect, } from '@coreui/react'; -import { cilBan, cilCheckCircle, cilInfo, cilPlus, cilTrash } from '@coreui/icons'; +import { cilBan, cilCheckCircle, cilPencil, cilSync, cilTrash } from '@coreui/icons'; import CIcon from '@coreui/icons-react'; import { capitalizeFirstLetter, prettyDate } from '../../utils/formatting'; import DeleteModal from '../DeleteModal'; @@ -28,6 +27,9 @@ const UserListTable = ({ setPage, deleteUser, deleteLoading, + toggleCreate, + toggleEdit, + refreshUsers, }) => { const [idToDelete, setIdToDelete] = useState(''); const [showDeleteModal, setShowDeleteModal] = useState(false); @@ -50,13 +52,20 @@ const UserListTable = ({ { key: 'email', label: t('user.login_id'), _style: { width: '20%' } }, { key: 'name', label: t('user.name'), _style: { width: '20%' } }, { key: 'userRole', label: t('user.user_role'), _style: { width: '5%' } }, - { key: 'description', label: t('user.description'), _style: { width: '25%' } }, + { key: 'description', label: t('user.description'), _style: { width: '24%' } }, { key: 'validated', label: t('user.validated'), _style: { width: '5%' } }, { key: 'lastLogin', label: t('user.last_login'), _style: { width: '20%' } }, { - key: 'user_actions', + key: 'user_details', label: '', - _style: { width: '5%' }, + _style: { width: '3%' }, + sorter: false, + filter: false, + }, + { + key: 'user_delete', + label: '', + _style: { width: '3%' }, sorter: false, filter: false, }, @@ -68,17 +77,44 @@ const UserListTable = ({ - - setUsersPerPage(e.target.value)} - disabled={loading} - > - - - - + + + +
+ setUsersPerPage(e.target.value)} + disabled={loading} + > + + + + +
+
+ +
+ + {t('user.create')} + +
+
+ +
+ + + + + +
+
+
@@ -89,23 +125,6 @@ const UserListTable = ({ loading={loading} hover border - columnHeaderSlot={{ - user_actions: ( -
- - `/users/create`} - > - - - - - -
- ), - }} scopedSlots={{ validated: (item) => ( @@ -120,35 +139,33 @@ const UserListTable = ({ userRole: (item) => ( {item.userRole ? capitalizeFirstLetter(item.userRole) : ''} ), - user_actions: (item) => ( + user_details: (item) => ( - - - - `/users/${item.Id}`} - > - - - - - - - - - handleDeleteClick(item.Id)} - color="primary" - variant="outline" - size="sm" - > - - - - - + + toggleEdit(item.Id)} + > + + + + + ), + user_delete: (item) => ( + + + handleDeleteClick(item.Id)} + color="primary" + variant="outline" + size="sm" + > + + + ), }} @@ -196,6 +213,9 @@ UserListTable.propTypes = { setPage: PropTypes.func.isRequired, deleteUser: PropTypes.func.isRequired, deleteLoading: PropTypes.bool.isRequired, + toggleCreate: PropTypes.func.isRequired, + toggleEdit: PropTypes.func.isRequired, + refreshUsers: PropTypes.func.isRequired, }; export default React.memo(UserListTable); diff --git a/src/components/UserProfileCard/index.js b/src/components/UserProfileCard/index.js deleted file mode 100644 index 3382025..0000000 --- a/src/components/UserProfileCard/index.js +++ /dev/null @@ -1,139 +0,0 @@ -import React, { useState } from 'react'; -import { - CButton, - CCard, - CCardBody, - CCardHeader, - CCol, - CForm, - CFormGroup, - CInput, - CInputGroup, - CInputGroupAppend, - CInvalidFeedback, - CLabel, - CPopover, - CRow, - CSelect, - CSwitch, -} from '@coreui/react'; -import PropTypes from 'prop-types'; -import LoadingButton from 'components/LoadingButton'; -import CIcon from '@coreui/icons-react'; - -const CreateUserForm = ({ t, user, updateUserWithId, loading, saveUser }) => { - const [showPassword, setShowPassword] = useState(false); - - const toggleShowPassword = () => { - setShowPassword(!showPassword); - }; - - return ( - - {t('common.details')} - - - - - {t('user.email_address')} -

{user.email.value}

-
- - {t('user.name')} - - - - {t('user.force_password_change')} - - - - -
- - - {t('user.user_role')} - - - - - - - - - - - {t('login.new_password')} - - - - - - - - - - {t('user.provide_password')} - - - - - - {t('user.description')} - - - - - - - - - - -
-
-
- ); -}; - -CreateUserForm.propTypes = { - t: PropTypes.func.isRequired, - user: PropTypes.instanceOf(Object).isRequired, - updateUserWithId: PropTypes.func.isRequired, - loading: PropTypes.bool.isRequired, - saveUser: PropTypes.func.isRequired, -}; - -export default React.memo(CreateUserForm); diff --git a/src/hooks/useUser/index.js b/src/hooks/useUser/index.js index b16252a..561f4bd 100644 --- a/src/hooks/useUser/index.js +++ b/src/hooks/useUser/index.js @@ -18,7 +18,7 @@ export default (initialState) => { (key, newValues) => { setUser({ ...user, - [user]: { + [key]: { ...user[key], ...newValues, }, diff --git a/src/index.js b/src/index.js index 7616a22..8225553 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,9 @@ export { default as UserListTable } from './components/UserListTable'; export { default as CreateUserForm } from './components/CreateUserForm'; export { default as LoadingButton } from './components/LoadingButton'; export { default as ConfirmFooter } from './components/ConfirmFooter'; -export { default as UserProfileCard } from './components/UserProfileCard'; +export { default as EditUserModal } from './components/EditUserModal'; +export { default as EditUserForm } from './components/EditUserForm'; +export { default as EditMyProfile } from './components/EditMyProfile'; // Pages export { default as LoginPage } from './components/LoginPage'; diff --git a/src/layout/Header/index.js b/src/layout/Header/index.js index e2fff77..29b5873 100644 --- a/src/layout/Header/index.js +++ b/src/layout/Header/index.js @@ -62,7 +62,7 @@ const Header = ({ -
+
emailToName(user.email)} @@ -70,11 +70,11 @@ const Header = ({
- -
My Account
+ '/myprofile'}> +
{t('user.my_profile')}
logout(authToken, endpoints.ucentralsec)}> - Logout + {t('common.logout')}