feat(frontend): users crud | close #252
This commit is contained in:
parent
6dd9614eb5
commit
0327fa9969
|
|
@ -2,6 +2,8 @@ import ChartBarIcon from '@heroicons/react/24/solid/ChartBarIcon';
|
|||
import CogIcon from '@heroicons/react/24/solid/CogIcon';
|
||||
import ChatBubbleLeftRightIcon from '@heroicons/react/24/solid/ChatBubbleLeftRightIcon'
|
||||
import MapIcon from '@heroicons/react/24/solid/MapIcon'
|
||||
import UserGroupIcon from '@heroicons/react/24/solid/UserGroupIcon'
|
||||
import KeyIcon from '@heroicons/react/24/solid/KeyIcon'
|
||||
import CpuChip from '@heroicons/react/24/solid/CpuChipIcon';
|
||||
import { SvgIcon } from '@mui/material';
|
||||
|
||||
|
|
@ -42,6 +44,24 @@ export const items = [
|
|||
// </SvgIcon>
|
||||
// )
|
||||
// },
|
||||
// {
|
||||
// title: 'Credentials',
|
||||
// path: '/credentials',
|
||||
// icon: (
|
||||
// <SvgIcon fontSize="small">
|
||||
// <KeyIcon/>
|
||||
// </SvgIcon>
|
||||
// )
|
||||
// },
|
||||
{
|
||||
title: 'Users',
|
||||
path: '/users',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<UserGroupIcon/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
path: '/settings',
|
||||
|
|
|
|||
|
|
@ -1,290 +0,0 @@
|
|||
import { useCallback, useMemo, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { subDays, subHours } from 'date-fns';
|
||||
import ArrowDownOnSquareIcon from '@heroicons/react/24/solid/ArrowDownOnSquareIcon';
|
||||
import ArrowUpOnSquareIcon from '@heroicons/react/24/solid/ArrowUpOnSquareIcon';
|
||||
import PlusIcon from '@heroicons/react/24/solid/PlusIcon';
|
||||
import { Box, Button, Container, Stack, SvgIcon, Typography } from '@mui/material';
|
||||
import { useSelection } from 'src/hooks/use-selection';
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import { CustomersTable } from 'src/sections/customer/customers-table';
|
||||
import { CustomersSearch } from 'src/sections/customer/customers-search';
|
||||
import { applyPagination } from 'src/utils/apply-pagination';
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: '5e887ac47eed253091be10cb',
|
||||
address: {
|
||||
city: 'Cleveland',
|
||||
country: 'USA',
|
||||
state: 'Ohio',
|
||||
street: '2849 Fulton Street'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-carson-darrin.png',
|
||||
createdAt: subDays(subHours(now, 7), 1).getTime(),
|
||||
email: 'carson.darrin@devias.io',
|
||||
name: 'Carson Darrin',
|
||||
phone: '304-428-3097'
|
||||
},
|
||||
{
|
||||
id: '5e887b209c28ac3dd97f6db5',
|
||||
address: {
|
||||
city: 'Atlanta',
|
||||
country: 'USA',
|
||||
state: 'Georgia',
|
||||
street: '1865 Pleasant Hill Road'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-fran-perez.png',
|
||||
createdAt: subDays(subHours(now, 1), 2).getTime(),
|
||||
email: 'fran.perez@devias.io',
|
||||
name: 'Fran Perez',
|
||||
phone: '712-351-5711'
|
||||
},
|
||||
{
|
||||
id: '5e887b7602bdbc4dbb234b27',
|
||||
address: {
|
||||
city: 'North Canton',
|
||||
country: 'USA',
|
||||
state: 'Ohio',
|
||||
street: '4894 Lakeland Park Drive'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-jie-yan-song.png',
|
||||
createdAt: subDays(subHours(now, 4), 2).getTime(),
|
||||
email: 'jie.yan.song@devias.io',
|
||||
name: 'Jie Yan Song',
|
||||
phone: '770-635-2682'
|
||||
},
|
||||
{
|
||||
id: '5e86809283e28b96d2d38537',
|
||||
address: {
|
||||
city: 'Madrid',
|
||||
country: 'Spain',
|
||||
name: 'Anika Visser',
|
||||
street: '4158 Hedge Street'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-anika-visser.png',
|
||||
createdAt: subDays(subHours(now, 11), 2).getTime(),
|
||||
email: 'anika.visser@devias.io',
|
||||
name: 'Anika Visser',
|
||||
phone: '908-691-3242'
|
||||
},
|
||||
{
|
||||
id: '5e86805e2bafd54f66cc95c3',
|
||||
address: {
|
||||
city: 'San Diego',
|
||||
country: 'USA',
|
||||
state: 'California',
|
||||
street: '75247'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-miron-vitold.png',
|
||||
createdAt: subDays(subHours(now, 7), 3).getTime(),
|
||||
email: 'miron.vitold@devias.io',
|
||||
name: 'Miron Vitold',
|
||||
phone: '972-333-4106'
|
||||
},
|
||||
{
|
||||
id: '5e887a1fbefd7938eea9c981',
|
||||
address: {
|
||||
city: 'Berkeley',
|
||||
country: 'USA',
|
||||
state: 'California',
|
||||
street: '317 Angus Road'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-penjani-inyene.png',
|
||||
createdAt: subDays(subHours(now, 5), 4).getTime(),
|
||||
email: 'penjani.inyene@devias.io',
|
||||
name: 'Penjani Inyene',
|
||||
phone: '858-602-3409'
|
||||
},
|
||||
{
|
||||
id: '5e887d0b3d090c1b8f162003',
|
||||
address: {
|
||||
city: 'Carson City',
|
||||
country: 'USA',
|
||||
state: 'Nevada',
|
||||
street: '2188 Armbrester Drive'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-omar-darboe.png',
|
||||
createdAt: subDays(subHours(now, 15), 4).getTime(),
|
||||
email: 'omar.darobe@devias.io',
|
||||
name: 'Omar Darobe',
|
||||
phone: '415-907-2647'
|
||||
},
|
||||
{
|
||||
id: '5e88792be2d4cfb4bf0971d9',
|
||||
address: {
|
||||
city: 'Los Angeles',
|
||||
country: 'USA',
|
||||
state: 'California',
|
||||
street: '1798 Hickory Ridge Drive'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-siegbert-gottfried.png',
|
||||
createdAt: subDays(subHours(now, 2), 5).getTime(),
|
||||
email: 'siegbert.gottfried@devias.io',
|
||||
name: 'Siegbert Gottfried',
|
||||
phone: '702-661-1654'
|
||||
},
|
||||
{
|
||||
id: '5e8877da9a65442b11551975',
|
||||
address: {
|
||||
city: 'Murray',
|
||||
country: 'USA',
|
||||
state: 'Utah',
|
||||
street: '3934 Wildrose Lane'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-iulia-albu.png',
|
||||
createdAt: subDays(subHours(now, 8), 6).getTime(),
|
||||
email: 'iulia.albu@devias.io',
|
||||
name: 'Iulia Albu',
|
||||
phone: '313-812-8947'
|
||||
},
|
||||
{
|
||||
id: '5e8680e60cba5019c5ca6fda',
|
||||
address: {
|
||||
city: 'Salt Lake City',
|
||||
country: 'USA',
|
||||
state: 'Utah',
|
||||
street: '368 Lamberts Branch Road'
|
||||
},
|
||||
avatar: '/assets/avatars/avatar-nasimiyu-danai.png',
|
||||
createdAt: subDays(subHours(now, 1), 9).getTime(),
|
||||
email: 'nasimiyu.danai@devias.io',
|
||||
name: 'Nasimiyu Danai',
|
||||
phone: '801-301-7894'
|
||||
}
|
||||
];
|
||||
|
||||
const useCustomers = (page, rowsPerPage) => {
|
||||
return useMemo(
|
||||
() => {
|
||||
return applyPagination(data, page, rowsPerPage);
|
||||
},
|
||||
[page, rowsPerPage]
|
||||
);
|
||||
};
|
||||
|
||||
const useCustomerIds = (customers) => {
|
||||
return useMemo(
|
||||
() => {
|
||||
return customers.map((customer) => customer.id);
|
||||
},
|
||||
[customers]
|
||||
);
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(5);
|
||||
const customers = useCustomers(page, rowsPerPage);
|
||||
const customersIds = useCustomerIds(customers);
|
||||
const customersSelection = useSelection(customersIds);
|
||||
|
||||
const handlePageChange = useCallback(
|
||||
(event, value) => {
|
||||
setPage(value);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleRowsPerPageChange = useCallback(
|
||||
(event) => {
|
||||
setRowsPerPage(event.target.value);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Customers | Devias Kit
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
py: 8
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="xl">
|
||||
<Stack spacing={3}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
spacing={4}
|
||||
>
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="h4">
|
||||
Customers
|
||||
</Typography>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
spacing={1}
|
||||
>
|
||||
<Button
|
||||
color="inherit"
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<ArrowUpOnSquareIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Button
|
||||
color="inherit"
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<ArrowDownOnSquareIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<div>
|
||||
<Button
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<PlusIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
variant="contained"
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
</Stack>
|
||||
<CustomersSearch />
|
||||
<CustomersTable
|
||||
count={data.length}
|
||||
items={customers}
|
||||
onDeselectAll={customersSelection.handleDeselectAll}
|
||||
onDeselectOne={customersSelection.handleDeselectOne}
|
||||
onPageChange={handlePageChange}
|
||||
onRowsPerPageChange={handleRowsPerPageChange}
|
||||
onSelectAll={customersSelection.handleSelectAll}
|
||||
onSelectOne={customersSelection.handleSelectOne}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
selected={customersSelection.selected}
|
||||
/>
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
449
frontend/src/pages/users.js
Normal file
449
frontend/src/pages/users.js
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
import { useCallback, useMemo, useState, useEffect } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { subDays, subHours } from 'date-fns';
|
||||
import ArrowDownOnSquareIcon from '@heroicons/react/24/solid/ArrowDownOnSquareIcon';
|
||||
import ArrowUpOnSquareIcon from '@heroicons/react/24/solid/ArrowUpOnSquareIcon';
|
||||
import PlusIcon from '@heroicons/react/24/solid/PlusIcon';
|
||||
import { Box, Button, CircularProgress, Container, Dialog, DialogContent, DialogTitle, Stack, SvgIcon, Typography,
|
||||
DialogActions,
|
||||
TextField,
|
||||
Backdrop,
|
||||
} from '@mui/material';
|
||||
import { useSelection } from 'src/hooks/use-selection';
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import { CustomersTable } from 'src/sections/customer/customers-table';
|
||||
import { CustomersSearch } from 'src/sections/customer/customers-search';
|
||||
import { applyPagination } from 'src/utils/apply-pagination';
|
||||
import { useAuth } from 'src/hooks/use-auth';
|
||||
import { useRouter } from 'next/router';
|
||||
import { is } from 'date-fns/locale';
|
||||
import { set } from 'nprogress';
|
||||
|
||||
const Page = () => {
|
||||
|
||||
const auth = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
const validateEmail = (email) => {
|
||||
return email.match(
|
||||
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
);
|
||||
};
|
||||
|
||||
//const [page, setPage] = useState(0);
|
||||
//const [rowsPerPage, setRowsPerPage] = useState(5);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [creatingNewUser, setCreatingNewUser] = useState(false);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [selected, setSelected] = useState([]);
|
||||
const [addDeviceDialogOpen, setAddDeviceDialogOpen] = useState(false);
|
||||
const [newUserData, setNewUserData] = useState({});
|
||||
const [isPasswordEmpty, setIsPasswordEmpty] = useState(false);
|
||||
const [isEmailEmpty, setIsEmailEmpty] = useState(false);
|
||||
const [isEmailExistent, setIsEmailExistent] = useState(false);
|
||||
|
||||
const deleteUser = (id) => {
|
||||
console.log("request to delete user: ", id)
|
||||
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", auth.user.token);
|
||||
|
||||
var requestOptions = {
|
||||
method: 'DELETE',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow'
|
||||
}
|
||||
|
||||
return fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT + '/auth/delete/' + id, requestOptions)
|
||||
.then(response => {
|
||||
if (response.status === 401) {
|
||||
router.push("/auth/login")
|
||||
} else if (response.status === 403) {
|
||||
return router.push("/403")
|
||||
}
|
||||
setUsers(users.filter(user => user.email !== id))
|
||||
})
|
||||
.catch(error => {
|
||||
return console.error('Error:', error)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const fetchUsers = async () => {
|
||||
console.log("fetching users data...")
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", auth.user.token);
|
||||
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow'
|
||||
}
|
||||
|
||||
return fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT + '/users', requestOptions)
|
||||
.then(response => {
|
||||
if (response.status === 401) {
|
||||
router.push("/auth/login")
|
||||
} else if (response.status === 403) {
|
||||
return router.push("/403")
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then(json => {
|
||||
console.log("users: ", json)
|
||||
setUsers(json)
|
||||
// setPages(json.pages + 1)
|
||||
// setPage(json.page +1)
|
||||
// setDevices(json.devices)
|
||||
setLoading(false)
|
||||
})
|
||||
.catch(error => {
|
||||
return console.error('Error:', error)
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// if (auth.user.token) {
|
||||
// console.log("auth.user.token =", auth.user.token)
|
||||
// }else{
|
||||
// auth.user.token = localStorage.getItem("token")
|
||||
// }
|
||||
//console.log("auth.user.token =", auth.user.token)
|
||||
fetchUsers()
|
||||
}, []);
|
||||
|
||||
// const handlePageChange = useCallback(
|
||||
// (event, value) => {
|
||||
// setPage(value);
|
||||
// },
|
||||
// []
|
||||
// );
|
||||
|
||||
// const handleRowsPerPageChange = useCallback(
|
||||
// (event) => {
|
||||
// setRowsPerPage(event.target.value);
|
||||
// },
|
||||
// []
|
||||
// );
|
||||
|
||||
const createUser = async (data) => {
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", auth.user.token);
|
||||
|
||||
var raw = JSON.stringify(data);
|
||||
|
||||
var requestOptions = {
|
||||
method: 'POST',
|
||||
headers: myHeaders,
|
||||
body: raw,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
let result = await fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT+"/auth/register", requestOptions)
|
||||
|
||||
if (result.status == 200) {
|
||||
console.log("user created: deu boa raça !!")
|
||||
}else if (result.status == 403) {
|
||||
console.log("num tenx permissão, seu boca de sandália")
|
||||
setCreatingNewUser(false)
|
||||
return router.push("/403")
|
||||
}else if (result.status == 401){
|
||||
console.log("taix nem autenticado, sai fora oh")
|
||||
setCreatingNewUser(false)
|
||||
return router.push("/auth/login")
|
||||
}else if (result.status == 409){
|
||||
console.log("usuário já existe, seu boca de bagre")
|
||||
setIsEmailExistent(true)
|
||||
setCreatingNewUser(false)
|
||||
return
|
||||
}else if (result.status == 400){
|
||||
console.log("faltou mandar dados jow")
|
||||
setAddDeviceDialogOpen(false)
|
||||
setNewUserData({})
|
||||
setIsPasswordEmpty(false)
|
||||
setIsEmailEmpty(false)
|
||||
setIsEmailExistent(false)
|
||||
setCreatingNewUser(false)
|
||||
return
|
||||
}else {
|
||||
console.log("agora quebrasse ux córno mô quiridu")
|
||||
const content = await result.json()
|
||||
setCreatingNewUser(false)
|
||||
throw new Error(content);
|
||||
}
|
||||
setAddDeviceDialogOpen(false)
|
||||
data["_id"] = data.email
|
||||
data["createdAt"] = new Date().toLocaleDateString('es-pa')
|
||||
data["level"] = 0
|
||||
|
||||
setUsers([...users, data])
|
||||
setNewUserData({})
|
||||
setIsPasswordEmpty(false)
|
||||
setIsEmailEmpty(false)
|
||||
setIsEmailExistent(false)
|
||||
setCreatingNewUser(false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | Users
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
py: 8
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="xl">
|
||||
<Stack spacing={3}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
spacing={4}
|
||||
>
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="h4">
|
||||
Users
|
||||
</Typography>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
spacing={1}
|
||||
>
|
||||
{/* <Button
|
||||
color="inherit"
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<ArrowUpOnSquareIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
>
|
||||
Import
|
||||
</Button> */}
|
||||
{/* <Button
|
||||
color="inherit"
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<ArrowDownOnSquareIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
>
|
||||
Export
|
||||
</Button> */}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<div>
|
||||
<Button
|
||||
startIcon={(
|
||||
<SvgIcon fontSize="small">
|
||||
<PlusIcon />
|
||||
</SvgIcon>
|
||||
)}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setAddDeviceDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
</Stack>
|
||||
{/* <CustomersSearch /> */}
|
||||
{users && !loading ?
|
||||
<CustomersTable
|
||||
count={users.length}
|
||||
items={users}
|
||||
//onDeselectAll={customersSelection.handleDeselectAll}
|
||||
onDeselectOne={(id) => {
|
||||
setSelected(selected.filter((item) => item !== id))
|
||||
}}
|
||||
//onPageChange={handlePageChange}
|
||||
//onRowsPerPageChange={handleRowsPerPageChange}
|
||||
//onSelectAll={customersSelection.handleSelectAll}
|
||||
onSelectOne={(id) => {
|
||||
setSelected([...selected, id])
|
||||
console.log("added user " + id + " to selected array")
|
||||
}}
|
||||
//page={page}
|
||||
//rowsPerPage={rowsPerPage}
|
||||
deleteUser={deleteUser}
|
||||
selected={selected}
|
||||
/> :
|
||||
<CircularProgress></CircularProgress>
|
||||
}
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
<Dialog
|
||||
open={addDeviceDialogOpen}
|
||||
onClose={() => {
|
||||
setAddDeviceDialogOpen(false)
|
||||
setIsEmailEmpty(false)
|
||||
setIsEmailExistent(false)
|
||||
setIsPasswordEmpty(false)
|
||||
setNewUserData({})
|
||||
}}
|
||||
>
|
||||
<DialogTitle>Create User</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
spacing={2}
|
||||
>
|
||||
<TextField
|
||||
inputProps={{
|
||||
form: {
|
||||
autocomplete: 'new-password',
|
||||
},
|
||||
}}
|
||||
// focused={isEmailEmpty}
|
||||
// color={isEmailEmpty ? "error" : "primary"}
|
||||
helperText={isEmailEmpty ? "Email error" : (isEmailExistent ? "Email already exists" : "")}
|
||||
autoFocus
|
||||
required
|
||||
margin="dense"
|
||||
id="email"
|
||||
name="email"
|
||||
label="Email Address"
|
||||
type="email"
|
||||
fullWidth
|
||||
onChange={
|
||||
(event) => {
|
||||
setNewUserData({...newUserData, email: event.target.value})
|
||||
}
|
||||
}
|
||||
variant="standard">
|
||||
</TextField>
|
||||
<TextField
|
||||
// focused={isPasswordEmpty}
|
||||
//color={isPasswordEmpty ? "error" : "primary"}
|
||||
helperText={isPasswordEmpty ? "Password cannot be empty" : ""}
|
||||
autoFocus
|
||||
required
|
||||
margin="dense"
|
||||
id="password"
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
autoComplete='new-password'
|
||||
fullWidth
|
||||
onChange={
|
||||
(event) => {
|
||||
setNewUserData({...newUserData, password: event.target.value})
|
||||
}
|
||||
}
|
||||
variant="standard">
|
||||
</TextField>
|
||||
</Stack>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
spacing={2}
|
||||
>
|
||||
<TextField
|
||||
inputProps={{
|
||||
form: {
|
||||
autocomplete: 'off',
|
||||
},
|
||||
}}
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="name"
|
||||
name="name"
|
||||
label="Full Name"
|
||||
type="name"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
onChange={
|
||||
(event) => {
|
||||
setNewUserData({...newUserData, name: event.target.value})
|
||||
}
|
||||
}
|
||||
>
|
||||
</TextField>
|
||||
<TextField
|
||||
inputProps={{
|
||||
form: {
|
||||
autocomplete: 'off',
|
||||
},
|
||||
}}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="phone"
|
||||
name="phone"
|
||||
label="Phone Number"
|
||||
type="phone"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
onChange={
|
||||
(event) => {
|
||||
setNewUserData({...newUserData, phone: event.target.value})
|
||||
}
|
||||
}
|
||||
>
|
||||
</TextField>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={
|
||||
() => {
|
||||
setAddDeviceDialogOpen(false)
|
||||
setIsEmailEmpty(false)
|
||||
setIsEmailExistent(false)
|
||||
setIsPasswordEmpty(false)
|
||||
setNewUserData({})
|
||||
}
|
||||
}>Cancel</Button>
|
||||
<Button onClick={()=>{
|
||||
console.log("new user data: ", newUserData)
|
||||
if (newUserData.password === undefined || newUserData.password === "") {
|
||||
setIsPasswordEmpty(true)
|
||||
return
|
||||
} else{
|
||||
setIsPasswordEmpty(false)
|
||||
}
|
||||
if (newUserData.email === undefined || newUserData.email === "") {
|
||||
setIsEmailEmpty(true)
|
||||
return
|
||||
} else if(!validateEmail(newUserData.email)){
|
||||
setIsEmailEmpty(true)
|
||||
return
|
||||
}else{
|
||||
setIsEmailEmpty(false)
|
||||
}
|
||||
setIsEmailExistent(false)
|
||||
setCreatingNewUser(true)
|
||||
createUser(newUserData)
|
||||
}}>Confirm</Button>
|
||||
</DialogActions>
|
||||
{
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
open={creatingNewUser}
|
||||
>
|
||||
<CircularProgress color="inherit" />
|
||||
</Backdrop>
|
||||
}
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
|
|
@ -1,21 +1,31 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { format } from 'date-fns';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Card,
|
||||
Checkbox,
|
||||
Icon,
|
||||
Stack,
|
||||
Tab,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TablePagination,
|
||||
//TablePagination,
|
||||
TableRow,
|
||||
Typography
|
||||
Typography,
|
||||
SvgIcon,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
Button
|
||||
} from '@mui/material';
|
||||
import { Scrollbar } from 'src/components/scrollbar';
|
||||
import { getInitials } from 'src/utils/get-initials';
|
||||
import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const CustomersTable = (props) => {
|
||||
const {
|
||||
|
|
@ -27,13 +37,17 @@ export const CustomersTable = (props) => {
|
|||
onRowsPerPageChange,
|
||||
onSelectAll,
|
||||
onSelectOne,
|
||||
deleteUser,
|
||||
page = 0,
|
||||
rowsPerPage = 0,
|
||||
selected = []
|
||||
} = props;
|
||||
|
||||
const selectedSome = (selected.length > 0) && (selected.length < items.length);
|
||||
const selectedAll = (items.length > 0) && (selected.length === items.length);
|
||||
// const selectedSome = (selected.length > 0) && (selected.length < items.length);
|
||||
// const selectedAll = (items.length > 0) && (selected.length === items.length);
|
||||
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const [userToDelete, setUserToDelete] = useState("")
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
|
@ -42,8 +56,8 @@ export const CustomersTable = (props) => {
|
|||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
{/* <TableCell padding="checkbox"> */}
|
||||
{/* <Checkbox
|
||||
checked={selectedAll}
|
||||
indeterminate={selectedSome}
|
||||
onChange={(event) => {
|
||||
|
|
@ -53,55 +67,60 @@ export const CustomersTable = (props) => {
|
|||
onDeselectAll?.();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
/> */}
|
||||
{/* </TableCell> */}
|
||||
<TableCell sx={{marginLeft:"30px"}}>
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
Email
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{/* <TableCell>
|
||||
Location
|
||||
</TableCell>
|
||||
</TableCell> */}
|
||||
<TableCell>
|
||||
Phone
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
Signed Up
|
||||
Created At
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
Level
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
Actions
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{items.map((customer) => {
|
||||
const isSelected = selected.includes(customer.id);
|
||||
const createdAt = format(customer.createdAt, 'dd/MM/yyyy');
|
||||
|
||||
const isSelected = selected.includes(customer._id);
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
key={customer.id}
|
||||
key={customer._id}
|
||||
selected={isSelected}
|
||||
>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
{/* <TableCell padding="checkbox"> */}
|
||||
{/* <Checkbox
|
||||
checked={isSelected}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
onSelectOne?.(customer.id);
|
||||
console.log(customer._id+" is selected");
|
||||
onSelectOne(customer._id);
|
||||
} else {
|
||||
onDeselectOne?.(customer.id);
|
||||
onDeselectOne(customer._id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
/> */}
|
||||
{/* </TableCell> */}
|
||||
<TableCell align="center" sx={{margin: 'auto', textAlign: 'center'}}>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
spacing={2}
|
||||
>
|
||||
<Avatar src={customer.avatar}>
|
||||
<Avatar src={customer.avatar ? customer.avatar : "/assets/avatars/default-avatar.png"}>
|
||||
{getInitials(customer.name)}
|
||||
</Avatar>
|
||||
<Typography variant="subtitle2">
|
||||
|
|
@ -112,14 +131,33 @@ export const CustomersTable = (props) => {
|
|||
<TableCell>
|
||||
{customer.email}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{customer.address.city}, {customer.address.state}, {customer.address.country}
|
||||
</TableCell>
|
||||
{/* <TableCell>
|
||||
{customer.address}
|
||||
</TableCell> */}
|
||||
<TableCell>
|
||||
{customer.phone}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{createdAt}
|
||||
{customer.createdAt}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{customer.level == 1 ? "Admin" : "User"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{ customer.level == 0 ? <Button
|
||||
onClick={() => {
|
||||
console.log("delete user: ", customer._id)
|
||||
setUserToDelete(customer.email);
|
||||
setShowDeleteDialog(true);
|
||||
}}
|
||||
><SvgIcon
|
||||
color="action"
|
||||
fontSize="small"
|
||||
sx={{ cursor: 'pointer'}}
|
||||
>
|
||||
<TrashIcon
|
||||
></TrashIcon>
|
||||
</SvgIcon></Button>: <span></span>}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
|
|
@ -128,15 +166,43 @@ export const CustomersTable = (props) => {
|
|||
</Table>
|
||||
</Box>
|
||||
</Scrollbar>
|
||||
<TablePagination
|
||||
{/* <TablePagination
|
||||
component="div"
|
||||
count={count}
|
||||
onPageChange={onPageChange}
|
||||
onRowsPerPageChange={onRowsPerPageChange}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
/>
|
||||
//onPageChange={onPageChange}
|
||||
//onRowsPerPageChange={onRowsPerPageChange}
|
||||
//page={page}
|
||||
//rowsPerPage={rowsPerPage}
|
||||
//rowsPerPageOptions={[5, 10, 25]}
|
||||
/> */}
|
||||
<Dialog
|
||||
open={showDeleteDialog}
|
||||
onClose={() => setShowDeleteDialog(false)}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{"Delete User"}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete this user?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => {
|
||||
setShowDeleteDialog(false)
|
||||
setUserToDelete("")
|
||||
}} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={() => {
|
||||
deleteUser(userToDelete);
|
||||
setShowDeleteDialog(false);
|
||||
setUserToDelete("")
|
||||
}} color="primary" autoFocus>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
@ -147,10 +213,11 @@ CustomersTable.propTypes = {
|
|||
onDeselectAll: PropTypes.func,
|
||||
onDeselectOne: PropTypes.func,
|
||||
onPageChange: PropTypes.func,
|
||||
onRowsPerPageChange: PropTypes.func,
|
||||
//onRowsPerPageChange: PropTypes.func,
|
||||
onSelectAll: PropTypes.func,
|
||||
onSelectOne: PropTypes.func,
|
||||
page: PropTypes.number,
|
||||
rowsPerPage: PropTypes.number,
|
||||
deleteUser: PropTypes.func,
|
||||
//page: PropTypes.number,
|
||||
//rowsPerPage: PropTypes.number,
|
||||
selected: PropTypes.array
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user