Image upload, better error handling, removed warnings,
fixed date field not rendering correct date during edit
This commit is contained in:
m0n02hz
2022-03-04 02:03:10 +05:30
parent e2d3ccfb7e
commit 5d2e29fc41
8 changed files with 2042 additions and 5120 deletions

7085
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@
"dependencies": { "dependencies": {
"@asseinfo/react-kanban": "2.2.0", "@asseinfo/react-kanban": "2.2.0",
"@emotion/cache": "11.4.0", "@emotion/cache": "11.4.0",
"@emotion/react": "11.4.1", "@emotion/react": "^11.4.1",
"@emotion/styled": "11.3.0", "@emotion/styled": "11.3.0",
"@fullcalendar/daygrid": "5.9.0", "@fullcalendar/daygrid": "5.9.0",
"@fullcalendar/interaction": "5.9.0", "@fullcalendar/interaction": "5.9.0",

View File

@@ -1,4 +1,4 @@
import * as React from 'react'; import React, {useEffect, useState} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
@@ -6,11 +6,15 @@ import AdapterDateFns from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider'; import LocalizationProvider from '@mui/lab/LocalizationProvider';
import DateTimePicker from '@mui/lab/DateTimePicker'; import DateTimePicker from '@mui/lab/DateTimePicker';
export default function DateTimeInput({ disabled }) { export default function DateTimeInput({ disabled, value }) {
const [value, setValue] = React.useState(new Date()); const [date, setDate] = useState(value || new Date());
useEffect(() => {
setDate(value);
}, [value])
const handleChange = (newValue) => { const handleChange = (newValue) => {
setValue(newValue); setDate(newValue);
}; };
return ( return (
@@ -19,7 +23,7 @@ export default function DateTimeInput({ disabled }) {
<DateTimePicker <DateTimePicker
disabled={disabled} disabled={disabled}
label="" label=""
value={value} value={date}
renderInput={(params) => <TextField {...params} />} renderInput={(params) => <TextField {...params} />}
onChange={handleChange} onChange={handleChange}
/> />
@@ -29,5 +33,6 @@ export default function DateTimeInput({ disabled }) {
} }
DateTimeInput.propTypes = { DateTimeInput.propTypes = {
disabled: PropTypes.bool disabled: PropTypes.bool,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object])
}; };

View File

@@ -77,6 +77,7 @@ function CreateEditUser(props) {
const location = useLocation(); const location = useLocation();
const [editedUser, setEditedUser] = useState(location?.state?.user); const [editedUser, setEditedUser] = useState(location?.state?.user);
const [selectedRoles, setSelectedRoles] = useState([]); const [selectedRoles, setSelectedRoles] = useState([]);
const [uploadedImg, setUploadedImg] = useState();
useEffect(() => { useEffect(() => {
if (context === 'edit') { if (context === 'edit') {
@@ -86,6 +87,7 @@ function CreateEditUser(props) {
} else { } else {
setEditedUser(editedUser); setEditedUser(editedUser);
setSelectedRoles(editedUser.roles); setSelectedRoles(editedUser.roles);
editedUser.image_url && setUploadedImg(editedUser.image_url);
} }
} }
}, []); }, []);
@@ -110,6 +112,7 @@ function CreateEditUser(props) {
actions: '', actions: '',
visibilities: '', visibilities: '',
isActive: true, isActive: true,
image: '',
createdBy: currentUser ? currentUser.fullName : '', createdBy: currentUser ? currentUser.fullName : '',
createdAt: new Date(), createdAt: new Date(),
updatedBy: currentUser ? currentUser.fullName : '', updatedBy: currentUser ? currentUser.fullName : '',
@@ -125,6 +128,7 @@ function CreateEditUser(props) {
actions: editedUser?.permissions?.actions ? editedUser.permissions.actions.join(',') : '', actions: editedUser?.permissions?.actions ? editedUser.permissions.actions.join(',') : '',
visibilities: editedUser?.permissions?.allowedUIModules ? editedUser.permissions.allowedUIModules.join(',') : '', visibilities: editedUser?.permissions?.allowedUIModules ? editedUser.permissions.allowedUIModules.join(',') : '',
isActive: editedUser && editedUser.isActive !== undefined ? editedUser.isActive : true, isActive: editedUser && editedUser.isActive !== undefined ? editedUser.isActive : true,
image: editedUser ? editedUser.image_url : EditIcon,
createdBy: editedUser ? editedUser.createdBy?.fullName : '', createdBy: editedUser ? editedUser.createdBy?.fullName : '',
createdAt: editedUser ? editedUser.createdAt : '', createdAt: editedUser ? editedUser.createdAt : '',
updatedBy: editedUser ? editedUser.updatedBy?.fullName : '', updatedBy: editedUser ? editedUser.updatedBy?.fullName : '',
@@ -150,14 +154,20 @@ function CreateEditUser(props) {
delete valuesClone.warehouses; delete valuesClone.warehouses;
delete valuesClone.actions; delete valuesClone.actions;
delete valuesClone.visibilities; delete valuesClone.visibilities;
return valuesClone; valuesClone.permissions = JSON.stringify(valuesClone.permissions);
valuesClone.roles = selectedRoles && selectedRoles.length > 0 ? selectedRoles.map(role => role._id) : [];
const formData = new FormData();
Object.keys(valuesClone).forEach(key => formData.append(key, valuesClone[key]));
uploadedImg && formData.append('image', uploadedImg);
return formData;
}; };
values.roles = selectedRoles && selectedRoles.length > 0 ? selectedRoles.map(role => role._id) : [];
dispatch( dispatch(
UsersActions.createUserAction({ UsersActions.createUserAction({
loader: 'loading-request', loader: 'loading-request',
slug: context === 'edit' ? API.UPDATE_USER.replace(':id', editedUser._id): API.CREATE_USER, slug: context === 'edit' ? API.UPDATE_USER.replace(':id', editedUser._id): API.CREATE_USER,
method: 'post', method: 'post',
contentType: false,
processData: false,
data: adaptPayload(values), data: adaptPayload(values),
onValidationFailed, onValidationFailed,
onSuccessfulSubmission, onSuccessfulSubmission,
@@ -181,6 +191,13 @@ function CreateEditUser(props) {
setSelectedRoles(uniqueRoles); setSelectedRoles(uniqueRoles);
}; };
const handleFileChange = e => {
const [file] = e.target.files;
if (file) {
setUploadedImg(file);
}
};
return ( return (
<DashboardLayout className={classes.createEditUserGlobal}> <DashboardLayout className={classes.createEditUserGlobal}>
<DashboardNavbar /> <DashboardNavbar />
@@ -188,9 +205,13 @@ function CreateEditUser(props) {
<MDBox mx={4} sx={{ border: '1px solid #C4C4C4', borderRadius: '4px', padding: '30px' }}> <MDBox mx={4} sx={{ border: '1px solid #C4C4C4', borderRadius: '4px', padding: '30px' }}>
<MDBox sx={{ width: '50%', margin: 'auto' }}> <MDBox sx={{ width: '50%', margin: 'auto' }}>
<MDBox sx={{ width: '120px', margin: 'auto', position: 'relative' }}> <MDBox sx={{ width: '120px', margin: 'auto', position: 'relative' }}>
<img src={UserIcon} alt='img' /> <img src={uploadedImg ? typeof uploadedImg === 'string' ? uploadedImg : URL.createObjectURL(uploadedImg) : UserIcon} alt='img' width='120' height='120' style={{borderRadius: '50%'}} />
<MDBox sx={{ position: 'absolute', bottom: '0', right: '0', cursor: 'pointer' }}> <MDBox sx={{ position: 'absolute', bottom: '0', right: '0' }}>
<img src={EditIcon} alt='img' /> <label htmlFor="image" style={{ cursor: 'pointer' }}>
<img src={EditIcon} />
</label>
<input id='image' name='image' type="file" className='d-none' accept="image/png, image/gif, image/jpeg"
onChange={handleFileChange} />
</MDBox> </MDBox>
</MDBox> </MDBox>
<MDBox sx={{ marginBottom: '24px' }}> <MDBox sx={{ marginBottom: '24px' }}>
@@ -296,7 +317,7 @@ function CreateEditUser(props) {
<Box component='div' className={classes.labelSize}> <Box component='div' className={classes.labelSize}>
Date &amp; Time Date &amp; Time
</Box> </Box>
<DateTimeInput disabled name='createdAt' value={formik.values.createdAt} /> <DateTimeInput disabled name='createdAt' value={new Date(formik.values.createdAt)} />
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Box component='div' className={classes.labelSize}> <Box component='div' className={classes.labelSize}>
@@ -308,7 +329,7 @@ function CreateEditUser(props) {
<Box component='div' className={classes.labelSize}> <Box component='div' className={classes.labelSize}>
Date &amp; Time Date &amp; Time
</Box> </Box>
<DateTimeInput disabled name='updatedAt' value={formik.values.updatedAt} /> <DateTimeInput disabled name='updatedAt' value={new Date(formik.values.updatedAt)} />
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -165,9 +165,9 @@ function UserAccessScreen() {
} }
})); }));
const rowRenders = userRecords && userRecords.map(record => { const rowRenders = userRecords && userRecords.map((record, keyouter) => {
const canEdit = columnConfig => columnConfig.isEditAnchor && currentUser.email !== record.email; const canEdit = columnConfig => columnConfig.isEditAnchor && currentUser.email !== record.email;
return <StyledTableRow key={record.id}> return <StyledTableRow key={record.id + '-' + keyouter}>
{userHeadCells.map((columnConfig, key) => <TableCell key={key} onClick={() => canEdit(columnConfig) && navigate('/setup/users-access/edit-user', {state: {user: record}})}> {userHeadCells.map((columnConfig, key) => <TableCell key={key} onClick={() => canEdit(columnConfig) && navigate('/setup/users-access/edit-user', {state: {user: record}})}>
{canEdit(columnConfig) ? <span className={classes.iconwrap}> {canEdit(columnConfig) ? <span className={classes.iconwrap}>
<EditIcon className={classes.iconSize}/> <EditIcon className={classes.iconSize}/>
@@ -218,8 +218,8 @@ function UserAccessScreen() {
> >
<TableBody> <TableBody>
{rolesRecords && {rolesRecords &&
rolesRecords.map((item) => ( rolesRecords.map((item, key) => (
<StyledTableRow key={item.id}> <StyledTableRow key={item.id + '-' + key}>
<TableCell> <TableCell>
<div className={classes.iconwrap}> <div className={classes.iconwrap}>
<EditIcon className={classes.iconSize} /> <EditIcon className={classes.iconSize} />

View File

@@ -34,7 +34,11 @@ export function* onCreateUserData({ payload }) {
ApiServices[payload?.method], ApiServices[payload?.method],
AuthorizedAPI, AuthorizedAPI,
payload?.slug, payload?.slug,
payload?.data payload?.data,
{
processData: false,
contentType: false
}
); );
if (response?.status === 200) { if (response?.status === 200) {
const data = response.data?.data; const data = response.data?.data;
@@ -48,8 +52,9 @@ export function* onCreateUserData({ payload }) {
}) })
); );
} else { } else {
toast('Something went wrong!'); const error = response?.originalError?.response?.data?.error;
payload.onValidationFailed(response.data?.error); toast(error && error.indexOf('E11000') > -1 ? 'Email already exists!' : 'Something went wrong!');
payload.onValidationFailed();
yield put( yield put(
UsersActions.createUserFailure({ UsersActions.createUserFailure({
loader: payload?.loader, loader: payload?.loader,

View File

@@ -1,6 +1,6 @@
// REST API SERVICES // REST API SERVICES
export default { export default {
post: (API, slug, payload) => API.post(slug, payload), post: (API, slug, payload, headers) => headers ? API.post(slug, payload, {headers}) : API.post(slug, payload),
get: (API, slug) => API.get(slug), get: (API, slug) => API.get(slug),
delete: (API, slug) => { delete: (API, slug) => {
return API.delete(slug); return API.delete(slug);

View File

@@ -68,6 +68,8 @@ const schema = {
createUser: Yup.object({ createUser: Yup.object({
fullName: Yup.string('Enter Full Name').required('User Name is required'), fullName: Yup.string('Enter Full Name').required('User Name is required'),
email: Yup.string('Enter Email').required('Email is required'),
password: Yup.string('Enter Password').required('Password is required'),
phoneNumber: Yup.string('Enter Phone Numbe').required('Phone Number is required'), phoneNumber: Yup.string('Enter Phone Numbe').required('Phone Number is required'),
roles: Yup.string('Please select at least one role').required('At least one role is required') roles: Yup.string('Please select at least one role').required('At least one role is required')
}) })