UNPKG

react-garden

Version:

React + TypeScript + ThreeJS app using Material UI on NextJS, Apollo Client, GraphQL + WordPress REST APIs, for ThreeD web development.. a part of the threed.ai code family.

406 lines (374 loc) 12.5 kB
// ** React Imports import { useState, useEffect, useCallback } from 'react' // ** Next Import import Link from 'next/link' // ** MUI Imports import Box from '@mui/material/Box' import Card from '@mui/material/Card' import Menu from '@mui/material/Menu' import Grid from '@mui/material/Grid' import { DataGrid } from '@mui/x-data-grid' import MenuItem from '@mui/material/MenuItem' import { styled } from '@mui/material/styles' import IconButton from '@mui/material/IconButton' import Typography from '@mui/material/Typography' import CardHeader from '@mui/material/CardHeader' import InputLabel from '@mui/material/InputLabel' import FormControl from '@mui/material/FormControl' import CardContent from '@mui/material/CardContent' import Select from '@mui/material/Select' // ** Icons Imports import Laptop from 'mdi-material-ui/Laptop' import ChartDonut from 'mdi-material-ui/ChartDonut' import CogOutline from 'mdi-material-ui/CogOutline' import EyeOutline from 'mdi-material-ui/EyeOutline' import DotsVertical from 'mdi-material-ui/DotsVertical' import PencilOutline from 'mdi-material-ui/PencilOutline' import DeleteOutline from 'mdi-material-ui/DeleteOutline' import AccountOutline from 'mdi-material-ui/AccountOutline' // ** Store Imports import { useDispatch, useSelector } from 'react-redux' // ** Custom Components Imports import CustomChip from '~/@core/components/mui/chip' import CustomAvatar from '~/@core/components/mui/avatar' // ** Utils Import import { getInitials } from '~/@core/utils/get-initials' // ** Actions Imports import { fetchData, deleteUser } from '~/store/apps/user' // ** Custom Components Imports import TableHeader from '~/views/apps/user/list/TableHeader' import AddUserDrawer from '~/views/apps/user/list/AddUserDrawer' // ** Vars const userRoleObj = { admin: <Laptop fontSize='small' sx={{ mr: 3, color: 'error.main' }} />, author: <CogOutline fontSize='small' sx={{ mr: 3, color: 'warning.main' }} />, editor: <PencilOutline fontSize='small' sx={{ mr: 3, color: 'info.main' }} />, maintainer: <ChartDonut fontSize='small' sx={{ mr: 3, color: 'success.main' }} />, subscriber: <AccountOutline fontSize='small' sx={{ mr: 3, color: 'primary.main' }} /> } const userStatusObj = { active: 'success', pending: 'warning', inactive: 'secondary' } // ** Styled component for the link for the avatar with image const AvatarWithImageLink = styled(Link)(({ theme }) => ({ marginRight: theme.spacing(3) })) // ** Styled component for the link for the avatar without image const AvatarWithoutImageLink = styled(Link)(({ theme }) => ({ textDecoration: 'none', marginRight: theme.spacing(3) })) // ** renders client column const renderClient = row => { if (row.avatar.length) { return ( <AvatarWithImageLink href={`/apps/user/view/${row.id}`}> <CustomAvatar src={row.avatar} sx={{ mr: 3, width: 30, height: 30 }} /> </AvatarWithImageLink> ) } else { return ( <AvatarWithoutImageLink href={`/apps/user/view/${row.id}`}> <CustomAvatar skin='light' color={row.avatarColor || 'primary'} sx={{ mr: 3, width: 30, height: 30, fontSize: '.875rem' }} > {getInitials(row.fullName ? row.fullName : 'Marty McGee')} </CustomAvatar> </AvatarWithoutImageLink> ) } } // ** Styled component for the link inside menu const MenuItemLink = styled('a')(({ theme }) => ({ width: '100%', display: 'flex', alignItems: 'center', textDecoration: 'none', padding: theme.spacing(1.5, 4), color: theme.palette.text.primary })) const RowOptions = ({ id }) => { // ** Hooks const dispatch = useDispatch() // ** State const [anchorEl, setAnchorEl] = useState(null) const rowOptionsOpen = Boolean(anchorEl) const handleRowOptionsClick = event => { setAnchorEl(event.currentTarget) } const handleRowOptionsClose = () => { setAnchorEl(null) } const handleDelete = () => { dispatch(deleteUser(id)) handleRowOptionsClose() } return ( <> <IconButton size='small' onClick={handleRowOptionsClick}> <DotsVertical /> </IconButton> <Menu keepMounted anchorEl={anchorEl} open={rowOptionsOpen} onClose={handleRowOptionsClose} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} transformOrigin={{ vertical: 'top', horizontal: 'right' }} PaperProps={{ style: { minWidth: '8rem' } }} > <MenuItem sx={{ p: 0 }}> <Link href={`/apps/user/view/${id}`} passHref> <MenuItemLink> <EyeOutline fontSize='small' sx={{ mr: 2 }} /> View </MenuItemLink> </Link> </MenuItem> <MenuItem onClick={handleRowOptionsClose}> <PencilOutline fontSize='small' sx={{ mr: 2 }} /> Edit </MenuItem> <MenuItem onClick={handleDelete}> <DeleteOutline fontSize='small' sx={{ mr: 2 }} /> Delete </MenuItem> </Menu> </> ) } const columns = [ { flex: 0.2, minWidth: 230, field: 'fullName', headerName: 'User', renderCell: ({ row }) => { const { id, fullName, username } = row return ( <Box sx={{ display: 'flex', alignItems: 'center' }}> {renderClient(row)} <Box sx={{ display: 'flex', alignItems: 'flex-start', flexDirection: 'column' }}> <Link href={`/apps/user/view/${id}`} passHref> <Typography noWrap component='a' variant='body2' sx={{ fontWeight: 600, color: 'text.primary', textDecoration: 'none' }} > {fullName} </Typography> </Link> <Link href={`/apps/user/view/${id}`} passHref> <Typography noWrap component='a' variant='caption' sx={{ textDecoration: 'none' }}> @{username} </Typography> </Link> </Box> </Box> ) } }, { flex: 0.2, minWidth: 250, field: 'email', headerName: 'Email', renderCell: ({ row }) => { return ( <Typography noWrap variant='body2'> {row.email} </Typography> ) } }, { flex: 0.15, field: 'role', minWidth: 150, headerName: 'Role', renderCell: ({ row }) => { return ( <Box sx={{ display: 'flex', alignItems: 'center' }}> {userRoleObj[row.role]} <Typography noWrap sx={{ color: 'text.secondary', textTransform: 'capitalize' }}> {row.role} </Typography> </Box> ) } }, { flex: 0.15, minWidth: 120, headerName: 'Plan', field: 'currentPlan', renderCell: ({ row }) => { return ( <Typography noWrap sx={{ textTransform: 'capitalize' }}> {row.currentPlan} </Typography> ) } }, { flex: 0.1, minWidth: 110, field: 'status', headerName: 'Status', renderCell: ({ row }) => { return ( <CustomChip skin='light' size='small' label={row.status} color={userStatusObj[row.status]} sx={{ textTransform: 'capitalize' }} /> ) } }, { flex: 0.1, minWidth: 90, sortable: false, field: 'actions', headerName: 'Actions', renderCell: ({ row }) => <RowOptions id={row.id} /> } ] const UserList = () => { // ** State const [role, setRole] = useState('') const [plan, setPlan] = useState('') const [value, setValue] = useState('') const [status, setStatus] = useState('') const [pageSize, setPageSize] = useState(10) const [addUserOpen, setAddUserOpen] = useState(false) // ** Hooks const dispatch = useDispatch() const store = useSelector(state => state.user) useEffect(() => { dispatch( fetchData({ role, status, q: value, currentPlan: plan }) ) }, [dispatch, plan, role, status, value]) const handleFilter = useCallback(val => { setValue(val) }, []) const handleRoleChange = useCallback(e => { setRole(e.target.value) }, []) const handlePlanChange = useCallback(e => { setPlan(e.target.value) }, []) const handleStatusChange = useCallback(e => { setStatus(e.target.value) }, []) const toggleAddUserDrawer = () => setAddUserOpen(!addUserOpen) return ( <Grid container spacing={6}> <Grid item xs={12}> <Card> <CardHeader title='Search Filters' /> <CardContent> <Grid container spacing={6}> <Grid item sm={4} xs={12}> <FormControl fullWidth> <InputLabel id='role-select'>Select Role</InputLabel> <Select fullWidth value={role} id='select-role' label='Select Role' labelId='role-select' onChange={handleRoleChange} inputProps={{ placeholder: 'Select Role' }} > <MenuItem value=''>Select Role</MenuItem> <MenuItem value='admin'>Admin</MenuItem> <MenuItem value='author'>Author</MenuItem> <MenuItem value='editor'>Editor</MenuItem> <MenuItem value='maintainer'>Maintainer</MenuItem> <MenuItem value='subscriber'>Subscriber</MenuItem> </Select> </FormControl> </Grid> <Grid item sm={4} xs={12}> <FormControl fullWidth> <InputLabel id='plan-select'>Select Plan</InputLabel> <Select fullWidth value={plan} id='select-plan' label='Select Plan' labelId='plan-select' onChange={handlePlanChange} inputProps={{ placeholder: 'Select Plan' }} > <MenuItem value=''>Select Plan</MenuItem> <MenuItem value='basic'>Basic</MenuItem> <MenuItem value='company'>Company</MenuItem> <MenuItem value='enterprise'>Enterprise</MenuItem> <MenuItem value='team'>Team</MenuItem> </Select> </FormControl> </Grid> <Grid item sm={4} xs={12}> <FormControl fullWidth> <InputLabel id='status-select'>Select Status</InputLabel> <Select fullWidth value={status} id='select-status' label='Select Status' labelId='status-select' onChange={handleStatusChange} inputProps={{ placeholder: 'Select Role' }} > <MenuItem value=''>Select Role</MenuItem> <MenuItem value='pending'>Pending</MenuItem> <MenuItem value='active'>Active</MenuItem> <MenuItem value='inactive'>Inactive</MenuItem> </Select> </FormControl> </Grid> </Grid> </CardContent> </Card> </Grid> <Grid item xs={12}> <Card> <TableHeader value={value} handleFilter={handleFilter} toggle={toggleAddUserDrawer} /> <DataGrid autoHeight rows={store.data} columns={columns} checkboxSelection pageSize={pageSize} disableSelectionOnClick rowsPerPageOptions={[10, 25, 50]} onPageSizeChange={newPageSize => setPageSize(newPageSize)} /> </Card> </Grid> <AddUserDrawer open={addUserOpen} toggle={toggleAddUserDrawer} /> </Grid> ) } export default UserList