682 lines
19 KiB
TypeScript

import Box from '@mui/material/Box'
import Checkbox from '@mui/material/Checkbox'
import Paper from '@mui/material/Paper'
import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
import TableCell from '@mui/material/TableCell'
import TableContainer from '@mui/material/TableContainer'
import TableHead from '@mui/material/TableHead'
import TablePagination from '@mui/material/TablePagination'
import TableRow from '@mui/material/TableRow'
import TableSortLabel from '@mui/material/TableSortLabel'
import { visuallyHidden } from '@mui/utils'
import { forwardRef, useDeferredValue, useEffect, useState } from 'react'
import Image from 'next/image'
import MuiAlert, { AlertProps } from '@mui/material/Alert'
import Snackbar from '@mui/material/Snackbar'
import Modal from '@mui/material/Modal'
import {
FormControl,
InputLabel,
MenuItem,
Select,
TextField,
Typography
} from '@mui/material'
import FormData from 'form-data'
import { InputUploadView } from '../inputUploadImg/inputUploadView'
import { api } from '../../services/api'
import FaqButton1 from '../buttons/faqButton/FaqButton1'
import FaqButton2 from '../buttons/faqButton/FaqButton2'
import { StyledStatus, TableView } from './TableView'
import ReactLoading from 'react-loading'
import { sanitizeStringSearch } from '../../utils/stringHelper'
import { stableSort } from '../../utils/stableSort'
const style = {
position: 'absolute' as const,
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 900,
height: 500,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
overflowY: 'scroll'
}
const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
props,
ref
) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />
})
interface Data {
clientCode: number
name: string
unity: string
status: string
}
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
if (b[orderBy] < a[orderBy]) {
return -1
}
if (b[orderBy] > a[orderBy]) {
return 1
}
return 0
}
type Order = 'asc' | 'desc'
function getComparator<Key extends keyof any>(
order: Order,
orderBy: any
): (
a: { [key in Key]: number | string },
b: { [key in Key]: number | string }
) => number {
return order === 'desc'
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy)
}
interface HeadCell {
disablePadding: boolean
id: keyof Data | string
label: string
numeric: boolean
}
const headCells: readonly HeadCell[] = [
{
id: 'clientCode',
numeric: false,
disablePadding: true,
label: 'código do cliente'
},
{
id: 'name',
numeric: false,
disablePadding: false,
label: 'name'
},
{
id: 'unity',
numeric: false,
disablePadding: false,
label: 'unity'
},
{
id: 'status',
numeric: false,
disablePadding: false,
label: 'status'
}
]
interface EnhancedTableProps {
numSelected: number
onRequestSort: (
event: React.MouseEvent<unknown>,
property: keyof Data
) => void
onSelectAllClick: (event: React.ChangeEvent<HTMLInputElement>) => void
order: Order
orderBy: string
rowCount: number
}
interface ClientsTableInterface {
clients: any
onChange: any
}
function sortedClients(client, search: string) {
search = sanitizeStringSearch(search)
return client
.map(client => ({
...client,
name: sanitizeStringSearch(client.name),
client_id: sanitizeStringSearch(String(client.client_id))
}))
.filter((client) => client.name.includes(search) || client.client_id.includes(search))
}
function EnhancedTableHead(props: EnhancedTableProps) {
const {
onSelectAllClick,
order,
orderBy,
numSelected,
rowCount,
onRequestSort
} = props
const createSortHandler =
(property: any) => (event: React.MouseEvent<unknown>) => {
onRequestSort(event, property)
}
return (
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
color="primary"
indeterminate={numSelected > 0 && numSelected < rowCount}
checked={rowCount > 0 && numSelected === rowCount}
onChange={onSelectAllClick}
inputProps={{
'aria-label': 'select all desserts'
}}
/>
</TableCell>
{headCells.map((headCell) => (
<TableCell
key={headCell.id}
align="left"
padding={headCell.disablePadding ? 'none' : 'normal'}
sortDirection={orderBy === headCell.id ? order : false}
>
<TableSortLabel
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : 'asc'}
onClick={createSortHandler(headCell.id)}
>
{headCell.label}
{orderBy === headCell.id ? (
<Box component="span" sx={visuallyHidden}>
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
</Box>
) : null}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
)
}
export default function ClientTable({
clients,
onChange
}: ClientsTableInterface) {
const [order, setOrder] = useState<Order>('asc')
const [orderBy, setOrderBy] = useState<keyof Data | string>('asc')
const [selected, setSelected] = useState<readonly string[]>([])
const [page, setPage] = useState<number>(0)
const [dense, setDense] = useState<boolean>(false)
const [rowsPerPage, setRowsPerPage] = useState<number>(5)
const [openSnackError, setOpenSnackError] = useState<boolean>(false)
const [open, setOpen] = useState(false)
const [openModalInativar, setOpenModalInativar] = useState(false)
const [clientEdit, setClientEdit] = useState<any>()
const [logo, setLogo] = useState(false)
const [imageURLS, setImageURLs] = useState([])
const [images, setImages] = useState([] as any)
const [nivelAcess, setnivelAcess] = useState<any>(2)
const [openEditUserModal, setOpenEditUserModal] = useState<any>(false)
const [openSnackSuccess, setOpenSnackSuccess] = useState<boolean>(false)
const [loading, setLoading] = useState<boolean>(false)
const [selectedClient, setSelectedClient] = useState<any>(2)
const [search, setSearch] = useState('')
const [units, setUnits] = useState([])
// Avoid a layout jump when reaching the last page with empty rows.
const emptyRows =
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - clients.length) : 0
const formData = new FormData()
const listClients = useDeferredValue(
sortedClients(stableSort(clients, getComparator(order, orderBy)), search)
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
)
// const handleOpen = () => setOpen(true)
const handleClose = () => setOpen(false)
function getClientUnits(client_id: number) {
api
.post('/units', {
filters: [
{
type: '=',
field: 'dados_cadastrais.cod_smart_cliente',
value: client_id
}
],
fields: ['unidade'],
distinct: true
})
.then((res) => setUnits(res.data.data))
.catch(() => setOpenSnackError(true))
return units
}
const handleCloseSnack = (
event?: React.SyntheticEvent | Event,
reason?: string
) => {
if (reason === 'clickaway') {
return
}
setOpenSnackError(false)
}
const handleRequestSort = (
event: React.MouseEvent<unknown>,
property: keyof Data
) => {
const isAsc = orderBy === property && order === 'asc'
setOrder(isAsc ? 'desc' : 'asc')
setOrderBy(property)
}
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.checked) {
const newSelecteds = clients.map((n) => n.name)
setSelected(newSelecteds)
return
}
setSelected([])
}
const handleClick = (event: React.MouseEvent<unknown>, code: string) => {
const selectedIndex = selected.indexOf(code)
let newSelected: readonly string[] = []
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, code)
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1))
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1))
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(
selected.slice(0, selectedIndex),
selected.slice(selectedIndex + 1)
)
}
setSelected(newSelected)
}
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage)
}
const handleChangeRowsPerPage = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setRowsPerPage(parseInt(event.target.value, 10))
setPage(0)
}
const isSelected = (code: any) => selected.indexOf(code.toString()) !== -1
function onImageChange(e: any) {
setImages([...e.target.files])
setLogo(e.target.files[0])
}
async function handleUpdateClient(props, id) {
logo && formData.append('file', logo)
let new_profile_picture
try {
setLoading(true)
if (logo) {
const { data } = await api.post('/sendFile', formData)
new_profile_picture = data.url
}
await api.put(`/user/${id}`, {
...props,
profile_picture: new_profile_picture
})
setOpenSnackSuccess(true)
setOpenModalInativar(false)
// window.location.reload()
} catch (err) {
setOpenSnackError(true)
} finally {
setLoading(false)
}
}
useEffect(() => {
onChange(selected)
}, [selected])
useEffect(() => {
if (images.length < 1) return
const newImageUrls: any = []
images.forEach((image: any) =>
newImageUrls.push(URL.createObjectURL(image))
)
setImageURLs(newImageUrls)
}, [images])
return (
<TableView>
<Snackbar
open={openSnackError}
autoHideDuration={4000}
onClose={handleCloseSnack}
>
<Alert
onClose={handleCloseSnack}
severity="error"
sx={{ width: '100%' }}
>
Não foi possivel encontrar unidades do client!
</Alert>
</Snackbar>
<TextField
onChange={(e) => setSearch(e.target.value)}
placeholder="Pesquisar por nome:"
/>
<Paper sx={{ width: '100%', mb: 2 }}>
<TableContainer>
<Table
sx={{ minWidth: 750 }}
aria-labelledby="tableTitle"
size={dense ? 'small' : 'medium'}
>
<EnhancedTableHead
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={clients.length}
/>
<TableBody>
{listClients.map((row, index) => {
const isItemSelected = isSelected(row.id)
const labelId = `enhanced-table-checkbox-${index}`
return (
<TableRow
hover
onClick={(event) => handleClick(event, row.id.toString())}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.id}
selected={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox
color="primary"
checked={isItemSelected}
inputProps={{ 'aria-labelledby': labelId }}
/>
</TableCell>
<TableCell
component="th"
id={labelId}
scope="row"
padding="none"
>
Client - {row.client_id}
</TableCell>
<TableCell
align="left"
style={{ cursor: 'pointer' }}
onClick={() => {
setOpenEditUserModal(true)
setSelectedClient(row)
setClientEdit({
email: row.email,
name: row.name,
client_id: row.client_id,
profile_picture: row.profile_picture
})
}}
>
{row.name}
</TableCell>
<TableCell
align="left"
style={{ cursor: 'pointer' }}
onClick={() => {
setOpen(true)
getClientUnits(row.client_id)
setSelectedClient(row)
}}
>
clique aqui para ver as unidades
</TableCell>
<TableCell align="left">
<StyledStatus
status={row.deleted_at ? 'inativo' : 'ativo'}
>
{' '}
{row.deleted_at ? 'inativo' : 'ativo'}
</StyledStatus>
</TableCell>
</TableRow>
)
})}
{emptyRows > 0 && (
<TableRow
style={{
height: (dense ? 33 : 53) * emptyRows
}}
>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={clients.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
<Modal
open={openEditUserModal}
onClose={() => setOpenEditUserModal(false)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<h1>Editar Cliente - {selectedClient.name}</h1>
<Typography
sx={{ color: 'gray', fontSize: 12 }}
variant="h5"
gutterBottom
component="div"
>
Adicionar Cliente Smart Energia
</Typography>
<br />
<TextField
id="outlined-basic"
label="Nome"
sx={{ width: 350, ml: 5 }}
onChange={(value) => {
setClientEdit({
...clientEdit,
name: value.target.value
})
}}
value={clientEdit?.name}
variant="outlined"
/>
<TextField
id="outlined-basic"
label="E-mail/Usuário"
value={clientEdit?.email}
sx={{ width: 350, ml: 8 }}
onChange={(value) => {
setClientEdit({
...clientEdit,
email: value.target.value.toLowerCase()
})
}}
variant="outlined"
/>
<TextField
id="outlined-basic"
label="Senha"
sx={{ width: 350, ml: 5, mt: 2 }}
onChange={(value) => {
setClientEdit({
...clientEdit,
password: value.target.value
})
}}
variant="outlined"
/>
<TextField
id="outlined-basic"
label="Confirma Senha"
sx={{ width: 350, ml: 8, mt: 2 }}
onChange={(value) => {
setClientEdit({
...clientEdit,
password_confirmation: value.target.value
})
}}
variant="outlined"
/>
<TextField
id="outlined-basic"
label="Codigo do Cliente Smart Energia"
sx={{ width: 350, ml: 5, mt: 2 }}
value={clientEdit?.client_id}
onChange={(value) => {
setClientEdit({
...clientEdit,
client_id: value.target.value
})
}}
variant="outlined"
/>
<InputUploadView>
<div className="imgContainer">
<article>
{imageURLS.map((imageSrc, index) => {
return (
<Image
src={imageSrc}
key={index}
width={30}
height={30}
className="image"
/>
)
})}
</article>
</div>
<div className="update">
<form action="">
<div>
<label htmlFor="arquivo">
{' '}
<p className="TitleButton"> Enviar foto de Perfil </p>{' '}
</label>
<input
type="file"
name="arquivo"
id="arquivo"
onChange={onImageChange}
/>
</div>
</form>
</div>
</InputUploadView>
<div className="select">
<FormControl sx={{ width: 350, ml: 5, mt: 2 }}>
<InputLabel id="demo-select-small">Nivel de acesso</InputLabel>
<Select
labelId="demo-select-small"
id="demo-select-small"
value={nivelAcess}
label="Unidade"
onChange={(value) => setnivelAcess(value.target.value)}
fullWidth
>
<MenuItem value={1}>Administrador</MenuItem>
<MenuItem value={2}>Cliente</MenuItem>
</Select>
</FormControl>
</div>
{!loading && (
<FaqButton1
title="Cancelar"
onClick={() => setOpenEditUserModal(false)}
/>
)}
{!loading ? (
<FaqButton2
title="Salvar"
onClick={() => handleUpdateClient(clientEdit, selectedClient.id)}
/>
) : (
<ReactLoading type="spin" color="#254f7f" height="5%" width="5%" />
)}
</Box>
</Modal>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
{units.map((units, index) => {
return (
<>
<li
style={{
listStyle: 'none'
}}
key={index}
>
{units.unidade}
</li>
<hr />
</>
)
})}
</Box>
</Modal>
</TableView>
)
}