1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

F #3951: Fix switcher component (#175)

* Fix switcher component
* Fix header styles
* Add popover component in header
This commit is contained in:
Sergio Betanzos 2020-09-01 17:13:27 +02:00 committed by GitHub
parent 2d31acad99
commit e0111785ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 420 additions and 268 deletions

View File

@ -1,4 +1,5 @@
import React from 'react';
import { string } from 'prop-types';
import {
Box,
@ -26,12 +27,13 @@ const useStyles = makeStyles(theme => {
},
text: {
...theme.typography.body1,
paddingLeft: theme.spacing(1)
paddingLeft: theme.spacing(1),
overflowWrap: 'anywhere'
}
};
});
const ErrorHelper = ({ label = 'Error', ...rest }) => {
const ErrorHelper = ({ label, ...rest }) => {
const classes = useStyles();
return (
@ -44,4 +46,12 @@ const ErrorHelper = ({ label = 'Error', ...rest }) => {
);
};
ErrorHelper.propTypes = {
label: string
};
ErrorHelper.defaultProps = {
label: 'Error'
};
export default ErrorHelper;

View File

@ -14,17 +14,16 @@
/* -------------------------------------------------------------------------- */
import React from 'react';
import { func } from 'prop-types';
import { MenuItem, TextField } from '@material-ui/core';
import { FilterVintage } from '@material-ui/icons';
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import { Translate } from 'client/components/HOC';
import { Tr } from 'client/components/HOC';
import { FILTER_POOL } from 'client/constants';
const GroupSelect = ({ handleChange }) => {
const GroupSelect = props => {
const { filterPool, authUser } = useAuth();
const { groups } = useOpennebula();
@ -53,25 +52,21 @@ const GroupSelect = ({ handleChange }) => {
<TextField
select
fullWidth
onChange={handleChange}
defaultValue={defaultValue}
variant="outlined"
inputProps={{ 'data-cy': 'select-group' }}
label={<Translate word="Select a group" />}
label={Tr('Select a group')}
FormHelperTextProps={{ 'data-cy': 'select-group-error' }}
{...props}
>
<MenuItem value={FILTER_POOL.ALL_RESOURCES}>{`Show all`}</MenuItem>
<MenuItem value={FILTER_POOL.ALL_RESOURCES}>{Tr('Show all')}</MenuItem>
{orderGroups}
</TextField>
);
};
GroupSelect.propTypes = {
handleChange: func
};
GroupSelect.propTypes = {};
GroupSelect.defaultProps = {
handleChange: () => undefined
};
GroupSelect.defaultProps = {};
export default GroupSelect;

View File

@ -1,35 +0,0 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import { Box } from '@material-ui/core';
import { FILTER_POOL } from 'client/constants';
import useAuth from 'client/hooks/useAuth';
import GroupSelect from '../FormControl/GroupSelect';
const FilterPoolSelect = () => {
const { setPrimaryGroup } = useAuth();
const handleChangeFilter = evt => {
console.log(evt);
// setPrimaryGroup({ group: });
};
return <GroupSelect handleChange={handleChangeFilter} />;
};
export default FilterPoolSelect;

View File

@ -0,0 +1,80 @@
import React from 'react';
import { Button } from '@material-ui/core';
import FilterIcon from '@material-ui/icons/FilterDrama';
import SelectedIcon from '@material-ui/icons/FilterVintage';
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import Search from 'client/components/Search';
import { FILTER_POOL } from 'client/constants';
import HeaderPopover from 'client/components/Header/Popover';
import headerStyles from 'client/components/Header/styles';
const { ALL_RESOURCES, PRIMARY_GROUP_RESOURCES } = FILTER_POOL;
const Group = () => {
const classes = headerStyles();
const { authUser, filterPool, setPrimaryGroup } = useAuth();
const { groups } = useOpennebula();
const handleChangeGroup = group => {
group && setPrimaryGroup({ group });
};
const filterSearch = ({ NAME }, search) =>
NAME?.toLowerCase().includes(search);
const renderResult = ({ ID, NAME }, handleClose) => {
const isSelected =
(filterPool === ALL_RESOURCES && ALL_RESOURCES === ID) ||
(filterPool === PRIMARY_GROUP_RESOURCES && authUser?.GID === ID);
return (
<Button
key={`term-${ID}`}
fullWidth
className={classes.groupButton}
onClick={() => {
handleChangeGroup(ID);
handleClose();
}}
>
{NAME}
{isSelected && <SelectedIcon className={classes.groupSelectedIcon} />}
</Button>
);
};
const sortMainGroupFirst = groups
?.concat({ ID: ALL_RESOURCES, NAME: 'Show All' })
?.sort((a, b) => {
if (a.ID === authUser?.GUID) {
return -1;
} else if (b.ID === authUser?.GUID) {
return 1;
}
return 0;
});
return (
<HeaderPopover
id="group-list"
icon={<FilterIcon />}
IconProps={{ 'data-cy': 'header-group-button' }}
headerTitle="Switch group"
>
{({ handleClose }) => (
<Search
list={sortMainGroupFirst}
maxResults={5}
filterSearch={filterSearch}
renderResult={group => renderResult(group, handleClose)}
/>
)}
</HeaderPopover>
);
};
export default Group;

View File

@ -0,0 +1,124 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import {
Box,
IconButton,
useMediaQuery,
Popover,
Typography,
Button
} from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import { Tr } from 'client/components/HOC';
import headerStyles from 'client/components/Header/styles';
import clsx from 'clsx';
const typeButton = {
button: Button,
iconButton: IconButton
};
const HeaderPopover = ({
id,
icon,
buttonLabel,
IconProps,
headerTitle,
disablePadding,
children
}) => {
const classes = headerStyles();
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'));
const [anchorEl, setAnchorEl] = useState(null);
const handleOpen = event => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
const open = Boolean(anchorEl);
const anchorId = open ? id : undefined;
const ButtonComponent = React.useMemo(
() => (buttonLabel ? typeButton.button : typeButton.iconButton),
[buttonLabel]
);
return (
<>
<ButtonComponent
color="inherit"
aria-controls={anchorId}
aria-describedby={anchorId}
aria-haspopup="true"
onClick={handleOpen}
{...IconProps}
>
{icon}
{buttonLabel && (
<span className={classes.buttonLabel}>{buttonLabel}</span>
)}
</ButtonComponent>
<Popover
BackdropProps={{ invisible: !isMobile }}
PaperProps={{
className: clsx(classes.paper, {
[classes.padding]: !disablePadding
})
}}
id={anchorId}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right'
}}
>
{(headerTitle || isMobile) && (
<Box className={classes.header}>
{headerTitle && (
<Typography className={classes.title} variant="body1">
{Tr(headerTitle)}
</Typography>
)}
{isMobile && (
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
)}
</Box>
)}
{children({ handleClose })}
</Popover>
</>
);
};
HeaderPopover.propTypes = {
id: PropTypes.string,
icon: PropTypes.node,
buttonLabel: PropTypes.string,
IconProps: PropTypes.objectOf(PropTypes.object),
headerTitle: PropTypes.string,
disablePadding: PropTypes.bool,
children: PropTypes.func
};
HeaderPopover.defaultProps = {
id: 'id-popover',
icon: null,
buttonLabel: undefined,
IconProps: {},
headerTitle: null,
disablePadding: false,
children: () => undefined
};
export default HeaderPopover;

View File

@ -1,114 +1,40 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { useState, useRef, Fragment } from 'react';
import React from 'react';
import { useHistory } from 'react-router-dom';
import {
Button,
Popper,
Grow,
Paper,
MenuItem,
MenuList,
ClickAwayListener,
Divider,
useMediaQuery
} from '@material-ui/core';
import { MenuItem, MenuList, Divider } from '@material-ui/core';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import { Translate } from 'client/components/HOC';
import { PATH } from 'client/router/endpoints';
import { SignOut } from 'client/constants';
import useAuth from 'client/hooks/useAuth';
import FilterPoolSelect from 'client/components/Header/FilterPoolSelect';
import { Tr } from 'client/components/HOC';
import { SignOut } from 'client/constants';
import { PATH } from 'client/router/endpoints';
import HeaderPopover from 'client/components/Header/Popover';
const User = React.memo(() => {
const history = useHistory();
const { logout, authUser, isOneAdmin } = useAuth();
const isUpSm = useMediaQuery(theme => theme.breakpoints.up('sm'));
const [open, setOpen] = useState(false);
const anchorRef = useRef(null);
const { current } = anchorRef;
const handleToggle = () => setOpen(prevOpen => !prevOpen);
const { logout, authUser } = useAuth();
const handleLogout = () => logout();
const handleGoToSettings = () => history.push(PATH.SETTINGS);
const handleClose = e => {
if (current && current.contains(e.target)) {
return;
}
setOpen(false);
};
return (
<Fragment>
<Button
ref={anchorRef}
color="inherit"
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
data-cy="header-user-button"
>
<AccountCircleIcon />
{isUpSm && <span style={{ paddingLeft: 5 }}>{authUser?.NAME}</span>}
</Button>
<Popper
open={open}
anchorEl={current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === 'bottom' ? 'center top' : 'center bottom'
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow">
<MenuItem onClick={handleGoToSettings}>Settings</MenuItem>
<Divider />
<MenuItem
onClick={handleLogout}
data-cy="header-logout-button"
>
<Translate word={SignOut} />
</MenuItem>
{!isOneAdmin && (
<>
<Divider />
<MenuItem>
<FilterPoolSelect />
</MenuItem>
</>
)}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</Fragment>
<HeaderPopover
id="user-menu"
buttonLabel={authUser?.NAME}
icon={<AccountCircleIcon />}
IconProps={{ 'data-cy': 'header-user-button' }}
disablePadding
>
{() => (
<MenuList>
<MenuItem onClick={handleGoToSettings}>{Tr('Settings')}</MenuItem>
<Divider />
<MenuItem onClick={handleLogout} data-cy="header-logout-button">
{Tr(SignOut)}
</MenuItem>
</MenuList>
)}
</HeaderPopover>
);
});

View File

@ -13,72 +13,27 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { useState, useRef } from 'react';
import {
Button,
Popper,
Grow,
Paper,
MenuItem,
MenuList,
ClickAwayListener
} from '@material-ui/core';
import React from 'react';
import { MenuItem, MenuList } from '@material-ui/core';
import LanguageIcon from '@material-ui/icons/Language';
const Zone = React.memo(() => {
const [open, setOpen] = useState(false);
const anchorRef = useRef(null);
const { current } = anchorRef;
import { Tr } from 'client/components/HOC';
import HeaderPopover from 'client/components/Header/Popover';
const handleToggle = () => {
setOpen(prevOpen => !prevOpen);
};
const handleClose = e => {
if (current && current.contains(e.target)) {
return;
}
setOpen(false);
};
return (
<>
<Button
ref={anchorRef}
color="inherit"
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
<LanguageIcon />
</Button>
<Popper
open={open}
anchorEl={current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === 'bottom' ? 'center top' : 'center bottom'
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow">
<MenuItem onClick={handleClose}>Zone</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</>
);
});
const Zone = React.memo(() => (
<HeaderPopover
id="zone-menu"
icon={<LanguageIcon />}
IconProps={{ 'data-cy': 'header-zone-button' }}
disablePadding
>
{({ handleClose }) => (
<MenuList>
<MenuItem onClick={handleClose}>{Tr('Zone')}</MenuItem>
</MenuList>
)}
</HeaderPopover>
));
export default Zone;

View File

@ -25,12 +25,15 @@ import {
} from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import useAuth from 'client/hooks/useAuth';
import useGeneral from 'client/hooks/useGeneral';
import User from 'client/components/Header/User';
import Group from 'client/components/Header/Group';
import Zone from 'client/components/Header/Zone';
import headerStyles from 'client/components/Header/styles';
const Header = ({ title }) => {
const { isOneAdmin } = useAuth();
const { isFixMenu, fixMenu } = useGeneral();
const classes = headerStyles();
const isUpLg = useMediaQuery(theme => theme.breakpoints.up('lg'));
@ -54,11 +57,12 @@ const Header = ({ title }) => {
{title}
</Typography>
<User />
{!isOneAdmin && <Group />}
<Zone />
</Toolbar>
</AppBar>
),
[isFixMenu, fixMenu, isUpLg]
[isFixMenu, fixMenu, isUpLg, isOneAdmin]
);
};

View File

@ -4,5 +4,40 @@ export default makeStyles(theme => ({
title: {
flexGrow: 1,
textTransform: 'capitalize'
},
/* POPOVER */
backdrop: {
[theme.breakpoints.only('xs')]: {
backgroundColor: theme.palette.action.disabledOpacity
}
},
paper: {
[theme.breakpoints.only('xs')]: {
width: '100%',
height: '100%'
}
},
padding: {
padding: theme.spacing(2)
},
header: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
borderBottom: '1px solid',
borderBottomColor: theme.palette.action.disabledBackground
},
buttonLabel: {
paddingLeft: theme.spacing(1),
[theme.breakpoints.only('xs')]: {
display: 'none'
}
},
/* GROUP SWITCHER */
headerSwitcherLabel: { flexGrow: 1 },
groupButton: { justifyContent: 'start' },
groupSelectedIcon: {
fontSize: '1rem',
margin: theme.spacing(0, 2)
}
}));

View File

@ -0,0 +1,54 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { TextField, Box } from '@material-ui/core';
const Search = ({
list,
maxResults,
filterSearch,
renderResult,
ResultBoxProps
}) => {
const [search, setSearch] = useState('');
const [result, setResult] = useState(list);
useEffect(() => {
setResult(list?.filter(item => filterSearch(item, search)));
}, [search, list]);
const handleChange = event => setSearch(event.target.value);
return (
<>
<TextField
type="search"
value={search}
onChange={handleChange}
fullWidth
placeholder="Search..."
/>
<Box {...ResultBoxProps}>
{result?.slice(0, maxResults).map(renderResult)}
</Box>
</>
);
};
Search.propTypes = {
list: PropTypes.arrayOf(PropTypes.object).isRequired,
maxResults: PropTypes.number,
filterSearch: PropTypes.func,
renderResult: PropTypes.func,
ResultBoxProps: PropTypes.objectOf(PropTypes.object)
};
Search.defaultProps = {
list: [],
maxResults: undefined,
filterSearch: (item, search) => item.toLowerCase().includes(search),
renderResult: item => item,
ResultBoxProps: {}
};
export default Search;

View File

@ -0,0 +1,19 @@
import { makeStyles } from '@material-ui/core';
export default makeStyles(theme => ({
backdrop: {
[theme.breakpoints.only('xs')]: {
backgroundColor: theme.palette.action.disabledOpacity
}
},
paper: {
padding: '1rem',
[theme.breakpoints.only('xs')]: {
width: '100%',
height: '100%'
}
},
header: { display: 'flex', alignItems: 'center' },
title: { flexGrow: 1 },
button: { justifyContent: 'start' }
}));

View File

@ -26,6 +26,7 @@ module.exports = {
Token2FA: '2FA Token',
SignOut: 'Sign Out',
jwtName: 'SunstoneToken',
filterPool: 'FilterPool',
Submit: 'Submit',
Response: 'Response',
by: {

View File

@ -0,0 +1,5 @@
import Create from 'client/containers/Application/Create';
import Deploy from 'client/containers/Application/Deploy';
import Manage from 'client/containers/Application/Manage';
export { Create, Deploy, Manage };

View File

@ -1,5 +1,6 @@
import React from 'react';
import { func, string } from 'prop-types';
import { Box, Button, TextField } from '@material-ui/core';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';

View File

@ -1,45 +1,46 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import { func } from 'prop-types';
import { Box, Button } from '@material-ui/core';
import { useForm, Controller } from 'react-hook-form';
import GroupSelect from 'client/components/FormControl/GroupSelect';
import ButtonSubmit from 'client/components/FormControl/SubmitButton';
import { Tr } from 'client/components/HOC';
import loginStyles from 'client/containers/Login/styles';
import { Next } from 'client/constants';
function FormGroup({ classes, onBack, onSubmit }) {
function FormGroup({ onBack, onSubmit }) {
const classes = loginStyles();
const { control, handleSubmit } = useForm();
return (
<Box
component="form"
className={classes?.form}
className={classes.form}
onSubmit={handleSubmit(onSubmit)}
>
<Controller as={<GroupSelect />} control={control} name="group" />
<Controller as={GroupSelect} name="group" control={control} />
<Button onClick={onBack}>Logout</Button>
<ButtonSubmit
data-cy="login-group-button"
isSubmitting={false}
label="Enter"
label={Tr(Next)}
/>
</Box>
);
}
FormGroup.propTypes = {
onBack: func.isRequired,
onSubmit: func.isRequired
};
FormGroup.defaultProps = {
onBack: () => undefined,
onSubmit: () => undefined
};
FormGroup.propTypes = {};
FormGroup.defaultProps = {};

View File

@ -1,18 +1,3 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React from 'react';
import { func, string } from 'prop-types';
import { Box, Checkbox, TextField, FormControlLabel } from '@material-ui/core';

View File

@ -24,7 +24,6 @@ import {
} from '@material-ui/core';
import useAuth from 'client/hooks/useAuth';
import useOpennebula from 'client/hooks/useOpennebula';
import FormUser from 'client/containers/Login/FormUser';
import Form2fa from 'client/containers/Login/Form2fa';
@ -51,7 +50,6 @@ function Login() {
getAuthInfo,
setPrimaryGroup
} = useAuth();
const { groups } = useOpennebula();
const handleSubmitUser = dataForm => {
login({ ...user, ...dataForm }).then(data => {
@ -122,11 +120,7 @@ function Login() {
unmountOnExit
>
<Box style={{ opacity: isLoading ? 0.7 : 1 }}>
<FormGroup
groups={groups}
onBack={handleBack}
onSubmit={handleSubmitGroup}
/>
<FormGroup onBack={handleBack} onSubmit={handleSubmitGroup} />
</Box>
</Slide>
</Box>

View File

@ -27,7 +27,6 @@ export default function useAuth() {
filterPool,
user: authUser
} = useSelector(state => state?.Authenticated, shallowEqual);
const baseURL = useSelector(state => state?.System?.baseURL, shallowEqual);
const dispatch = useDispatch();
useEffect(() => {
@ -43,7 +42,7 @@ export default function useAuth() {
dispatch(startAuth());
return serviceAuth
.login(user, baseURL)
.login(user)
.then(data => {
const { id, token } = data;
dispatch(successAuth());
@ -67,7 +66,7 @@ export default function useAuth() {
dispatch(failureAuth({ error: err }));
});
},
[dispatch, baseURL, jwtName]
[dispatch, jwtName]
);
const logout = useCallback(() => {
@ -79,22 +78,22 @@ export default function useAuth() {
dispatch(startAuth());
return serviceAuth
.getUser(baseURL)
.getUser()
.then(user => dispatch(successAuth({ user })))
.then(serviceGroups.getGroups)
.then(groups => dispatch(setGroups(groups)))
.catch(err => dispatch(failureAuth({ error: err })));
}, [dispatch, baseURL, jwtName, authUser]);
}, [dispatch, jwtName, authUser]);
const setPrimaryGroup = useCallback(
values => {
if (values?.group === FILTER_POOL.ALL_RESOURCES) {
({ group }) => {
if (group === FILTER_POOL.ALL_RESOURCES) {
dispatch(selectFilterGroup({ filterPool: FILTER_POOL.ALL_RESOURCES }));
} else {
dispatch(startAuth());
serviceUsers
.changeGroup({ id: authUser.ID, ...values })
.changeGroup({ id: authUser.ID, group })
.then(() =>
dispatch(
selectFilterGroup({
@ -102,10 +101,11 @@ export default function useAuth() {
})
)
)
.then(getAuthInfo)
.catch(err => dispatch(failureAuth({ error: err })));
}
},
[dispatch, authUser, jwtName]
[dispatch, authUser]
);
return {

View File

@ -2,9 +2,8 @@ import { httpCodes } from 'server/utils/constants';
import { jwtName, endpointsRoutes } from 'client/constants';
import { requestData, removeStoreData } from 'client/utils';
export const login = (user, baseURL = '') =>
export const login = user =>
requestData(endpointsRoutes.login, {
baseURL,
data: user,
method: 'POST',
authenticate: false,
@ -21,9 +20,8 @@ export const login = (user, baseURL = '') =>
return res?.data;
});
export const getUser = (baseURL = '') =>
export const getUser = () =>
requestData(endpointsRoutes.userInfo, {
baseURL,
error: err => {
removeStoreData(jwtName);
return err?.message;

View File

@ -37,7 +37,7 @@ export const requestParams = (data, command) => {
const resources = getResources(mappedParams);
const body = getDataBody(mappedParams);
const url = `api/${name.replace('.', '/')}`;
const url = `/api/${name.replace('.', '/')}`;
return {
url: `${url}/${resources}?${queries}`,