Edits to user functions, new avatar preview

This commit is contained in:
bourquecharles
2021-07-21 14:18:58 -04:00
parent d830e4d27d
commit b37ba0f71d
9 changed files with 146 additions and 72 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ucentral-libs",
"version": "0.8.17",
"version": "0.8.18",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ucentral-libs",
"version": "0.8.17",
"version": "0.8.18",
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.14.5",

View File

@@ -1,6 +1,6 @@
{
"name": "ucentral-libs",
"version": "0.8.17",
"version": "0.8.18",
"main": "dist/index.js",
"source": "src/index.js",
"engines": {

View File

@@ -0,0 +1,42 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { CImg } from '@coreui/react';
import { emailToName } from '../../utils/formatting';
const Avatar = ({ src, fallback }) => {
const [error, setError] = useState(false);
useEffect(() => {
if (src && src !== '' && src !== 'data:;base64,') {
setError(false);
}
}, [src]);
if (!src || src === '' || src === 'data:;base64,' || error) {
return (
<div className="c-avatar avatar">
<div className="avatar bg-secondary">
{fallback === 'N/A' ? fallback : emailToName(fallback)}
</div>
</div>
);
}
return (
<div className="c-avatar avatar">
<CImg className="avatar" src={src} onError={() => setError(true)} />
</div>
);
};
Avatar.propTypes = {
src: PropTypes.string,
fallback: PropTypes.string,
};
Avatar.defaultProps = {
src: '',
fallback: 'N/A',
};
export default React.memo(Avatar);

View File

@@ -19,6 +19,7 @@ import PropTypes from 'prop-types';
import CIcon from '@coreui/icons-react';
import NotesTable from '../NotesTable';
import LoadingButton from '../LoadingButton';
import Avatar from '../Avatar';
const EditMyProfile = ({
t,
@@ -29,6 +30,10 @@ const EditMyProfile = ({
policies,
addNote,
uploadAvatar,
avatar,
newAvatar,
deleteAvatar,
showPreview,
}) => {
const [showPassword, setShowPassword] = useState(false);
@@ -109,10 +114,53 @@ const EditMyProfile = ({
/>
</CCol>
<CLabel sm="2" col htmlFor="avatar">
{t('user.avatar_file')}
{t('user.avatar')}
</CLabel>
<CCol sm="4">
<CInputFile id="file-input" name="file-input" accept="image/*" onChange={uploadAvatar} />
<CRow>
<CCol sm="2" className="pt-2">
{t('common.current')}
<div className="pt-5">Preview</div>
</CCol>
<CCol sm="2">
<Avatar src={avatar} fallback={user.email.value} />
<div className="pt-3">
<Avatar src={newAvatar} fallback={user.email.value} />
</div>
</CCol>
<CCol sm="4" className="pt-2">
<div className="mt-1 mb-4">
<LoadingButton
label={t('user.delete_avatar')}
isLoadingLabel={t('user.deleting')}
isLoading={loading}
action={deleteAvatar}
block={false}
disabled={loading || !avatar || avatar === '' || avatar === 'data:;base64,'}
/>
</div>
<div className="pt-1">
<CInputFile
id="file-input"
name="file-input"
accept="image/*"
onChange={showPreview}
/>
</div>
<div className="pt-3">
<LoadingButton
label={t('user.save_avatar')}
isLoadingLabel={t('common.saving')}
isLoading={loading}
action={uploadAvatar}
block={false}
disabled={
loading || !newAvatar || newAvatar === '' || newAvatar === 'data:;base64,'
}
/>
</div>
</CCol>
</CRow>
</CCol>
</CFormGroup>
<CRow>
@@ -152,6 +200,15 @@ EditMyProfile.propTypes = {
policies: PropTypes.instanceOf(Object).isRequired,
addNote: PropTypes.func.isRequired,
uploadAvatar: PropTypes.func.isRequired,
avatar: PropTypes.string,
newAvatar: PropTypes.string,
showPreview: PropTypes.func.isRequired,
deleteAvatar: PropTypes.func.isRequired,
};
EditMyProfile.defaultProps = {
avatar: '',
newAvatar: '',
};
export default React.memo(EditMyProfile);

View File

@@ -1,24 +0,0 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { CImg } from '@coreui/react';
const ImgWithFallback = ({ src, fallback }) => {
const [error, setError] = useState(false);
if (src === '' || error) {
return <div className="avatar bg-secondary">{fallback()}</div>;
}
return <CImg className="avatar" src={src} onError={() => setError(true)} />;
};
ImgWithFallback.propTypes = {
src: PropTypes.string,
fallback: PropTypes.func.isRequired,
};
ImgWithFallback.defaultProps = {
src: '',
};
export default React.memo(ImgWithFallback);

View File

@@ -46,6 +46,7 @@ const NotesTable = ({ t, notes, addNote, loading, size }) => {
</CCol>
</CRow>
<CRow className="pt-3">
<CCol sm="2" />
<CCol>
<div className="overflow-auto" style={{ height: '200px' }}>
<CDataTable

View File

@@ -77,48 +77,48 @@ const UserListTable = ({
<CCardHeader>
<CRow>
<CCol />
<CCol xs={2}>
<CRow>
<CCol xs={5}>
<div className="text-right">
<CSelect
custom
defaultValue={usersPerPage}
onChange={(e) => setUsersPerPage(e.target.value)}
disabled={loading}
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</CSelect>
</div>
</CCol>
<CCol xs={5}>
<div className="text-right">
<CButton
color="primary"
variant="outline"
shape="square"
onClick={toggleCreate}
>
{t('user.create')}
</CButton>
</div>
</CCol>
<CCol xs={2}>
<div className="text-center">
<CPopover content={t('common.refresh')}>
<CButton onClick={refreshUsers} color="primary" variant="outline">
<CIcon name="cil-sync" content={cilSync} />
</CButton>
</CPopover>
</div>
</CCol>
</CRow>
<CCol xs={1}>
<div className="text-right">
<CSelect
custom
defaultValue={usersPerPage}
onChange={(e) => setUsersPerPage(e.target.value)}
disabled={loading}
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</CSelect>
</div>
</CCol>
<CCol xs={1}>
<div className="text-right">
<CButton
color="primary"
variant="outline"
shape="square"
onClick={toggleCreate}
block
>
{t('user.create')}
</CButton>
</div>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<CRow className="pb-3 pr-2">
<CCol />
<CCol xs={1} className="text-right">
<div>
<CPopover content={t('common.refresh')}>
<CButton onClick={refreshUsers} color="primary" variant="outline">
<CIcon name="cil-sync" content={cilSync} />
</CButton>
</CPopover>
</div>
</CCol>
</CRow>
<CDataTable
items={users}
fields={fields}

View File

@@ -13,6 +13,7 @@ export { default as ConfirmFooter } from './components/ConfirmFooter';
export { default as EditUserModal } from './components/EditUserModal';
export { default as EditUserForm } from './components/EditUserForm';
export { default as EditMyProfile } from './components/EditMyProfile';
export { default as Avatar } from './components/Avatar';
// Pages
export { default as LoginPage } from './components/LoginPage';

View File

@@ -15,8 +15,7 @@ import PropTypes from 'prop-types';
import CIcon from '@coreui/icons-react';
import { cilAccountLogout } from '@coreui/icons';
import LanguageSwitcher from '../../components/LanguageSwitcher';
import ImgWithFallback from '../../components/ImgWithFallback';
import { emailToName } from '../../utils/formatting';
import Avatar from '../../components/Avatar';
const Header = ({
showSidebar,
@@ -63,9 +62,7 @@ const Header = ({
<CHeaderNav className="px-1">
<CDropdown inNav className="c-header-nav-items mx-2" direction="down">
<CDropdownToggle className="c-header-nav-link" caret={false}>
<div className="c-avatar avatar">
<ImgWithFallback src={avatar} fallback={() => emailToName(user.email)} />
</div>
<Avatar src={avatar} fallback={user.email} />
</CDropdownToggle>
<CDropdownMenu className="pt-0" placement="bottom-end">
<CDropdownItem to={() => '/myprofile'}>