mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentral-ui-libs.git
synced 2025-10-29 18:02:21 +00:00
Edits to user functions, new avatar preview
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ucentral-libs",
|
||||
"version": "0.8.17",
|
||||
"version": "0.8.18",
|
||||
"main": "dist/index.js",
|
||||
"source": "src/index.js",
|
||||
"engines": {
|
||||
|
||||
42
src/components/Avatar/index.js
Normal file
42
src/components/Avatar/index.js
Normal 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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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'}>
|
||||
|
||||
Reference in New Issue
Block a user