ATENÇÃO: Alteração de versão do react: ^16.13.1 e do react-dom: ^16.13.1 para react: ^17.0.2 e react-dom: ^17.0.2, caso houver problemas de compatibilidade, voltar para versão anterior 16

pull/1/head
adriano 2022-01-24 08:44:42 -03:00
parent 4ef28e7326
commit bd29afd402
10 changed files with 1012 additions and 6 deletions

View File

@ -3,24 +3,31 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@date-io/date-fns": "^1.3.13",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.56",
"@material-ui/pickers": "^3.3.10",
"@mui/material": "^5.3.0",
"@mui/x-data-grid": "^5.3.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.0.4",
"@testing-library/user-event": "^12.1.7",
"axios": "^0.21.1",
"date-fns": "^2.16.1",
"date-fns": "^2.28.0",
"emoji-mart": "^3.0.1",
"formik": "^2.2.0",
"i18next": "^19.8.2",
"i18next-browser-languagedetector": "^6.0.1",
"markdown-to-jsx": "^7.1.0",
"material-table": "^1.69.3",
"mic-recorder-to-mp3": "^2.2.2",
"qrcode.react": "^1.0.0",
"react": "^16.13.1",
"react": "^17.0.2",
"react-color": "^2.19.3",
"react-dom": "^16.13.1",
"react-dom": "^17.0.2",
"react-modal-image": "^2.5.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
@ -50,6 +57,5 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {}
}
}

View File

@ -15,6 +15,9 @@
<link rel="shortcut icon" href="http://www.hittelco.com/images/favicon.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
<meta name="theme-color" content="#000000" />
<meta
name="viewport"

View File

@ -0,0 +1,75 @@
import React, { Fragment, useState } from "react";
import DateFnsUtils from '@date-io/date-fns'; // choose your lib
import {
KeyboardDatePicker,
DatePicker,
TimePicker,
DateTimePicker,
MuiPickersUtilsProvider,
} from '@material-ui/pickers';
function ResponsiveDatePickers(props) {
const [selectedDate, handleDateChange] = useState(new Date());
props.func(selectedDate);
return (
<Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
autoOk
variant="inline"
inputVariant="outlined"
label={props.title}
//format="MM/dd/yyyy"
format="dd/MM/yyyy"
value={selectedDate}
InputAdornmentProps={{ position: "start" }}
onChange={date => handleDateChange(date)}
/>
</MuiPickersUtilsProvider>
</Fragment>
);
}
export default ResponsiveDatePickers;
/*import * as React from 'react';
import TextField from '@mui/material/TextField';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import DesktopDatePicker from '@mui/lab/DesktopDatePicker';
import Stack from '@mui/material/Stack';
const ResponsiveDatePickers = (props) => {
const [value, setValue] = React.useState(new Date());
props.func(value);
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={1}>
<DesktopDatePicker
label={props.title}
value={value}
minDate={new Date('2017-01-01')}
onChange={(newValue) => {setValue(newValue)}}
renderInput={(params) => <TextField {...params} />}
/>
</Stack>
</LocalizationProvider>
);
}
export default ResponsiveDatePickers*/

View File

@ -0,0 +1,113 @@
import { gridDateTimeFormatter } from "@mui/x-data-grid";
export const data = [
{
"id": 210,
"status": "closed",
"createdAt": "2022-01-18T20:24:23.000Z",
"updatedAt": "2022-01-18T20:26:10.000Z",
"contact": {
"name": "WhatsApp",
"number": "5517988325936"
},
"user": {
"name": "Administrador",
"email": "admin@whaticket.com"
},
"queue": {
"name": "Cobrança"
},
"messages": [
{
"id": 1,
"mediaUrl": null,
"body": "Ola",
"read": true,
"mediaType": "chat",
"fromMe": false,
"createdAt": "2022-01-18T20:24:24.007Z"
},
{
"id": 2,
"mediaUrl": null,
"body": "HIT COMMUNICATIONS 🇧🇷\n\nBem vindo ao novo canal digital de atendimento ao cliente. Escolha uma opção do MENU abaixo 👇 e digite o número:\n*1* - Atendimento a Fornecedores\n*2* - Cancelamento ou Sugestões\n*3* - Cobrança\n*4* - Comercial\n*5* - Contas a Pagar\n*6* - Suporte Técnico\n",
"read": true,
"mediaType": "chat",
"fromMe": true,
"createdAt": "2022-01-18T20:24:27.097Z"
},
{
"id": 3,
"mediaUrl": null,
"body": "G",
"read": true,
"mediaType": "chat",
"fromMe": false,
"createdAt": "2022-01-18T20:24:37.923Z"
},
{
"id": 4,
"mediaUrl": null,
"body": "HIT COMMUNICATIONS 🇧🇷\n\nBem vindo ao novo canal digital de atendimento ao cliente. Escolha uma opção do MENU abaixo 👇 e digite o número:\n*1* - Atendimento a Fornecedores\n*2* - Cancelamento ou Sugestões\n*3* - Cobrança\n*4* - Comercial\n*5* - Contas a Pagar\n*6* - Suporte Técnico\n",
"read": true,
"mediaType": "chat",
"fromMe": true,
"createdAt": "2022-01-18T20:24:40.980Z"
},
{
"id": 5,
"mediaUrl": null,
"body": "3",
"read": true,
"mediaType": "chat",
"fromMe": false,
"createdAt": "2022-01-18T20:24:57.888Z"
},
{
"id": 6,
"mediaUrl": null,
"body": "Olá sou da Cobrança, vou te atender em alguns instantes!",
"read": true,
"mediaType": "chat",
"fromMe": true,
"createdAt": "2022-01-18T20:24:58.580Z"
},
{
"id": 7,
"mediaUrl": null,
"body": "Ok",
"read": true,
"mediaType": "chat",
"fromMe": false,
"createdAt": "2022-01-18T20:25:05.310Z"
},
{
"id": 8,
"mediaUrl": null,
"body": "*Administrador:*\nOlá no que posso ajudar",
"read": true,
"mediaType": "chat",
"fromMe": true,
"createdAt": "2022-01-18T20:25:32.291Z"
},
{
"id": 9,
"mediaUrl": null,
"body": "Aqui ta chovendo",
"read": true,
"mediaType": "chat",
"fromMe": false,
"createdAt": "2022-01-18T20:25:52.922Z"
},
{
"id": 10,
"mediaUrl": null,
"body": "*Administrador:*\nCerto boa tarde",
"read": true,
"mediaType": "chat",
"fromMe": true,
"createdAt": "2022-01-18T20:26:04.360Z"
}
]
}
]

View File

@ -0,0 +1,69 @@
import { useState, useEffect} from 'react';
import MaterialTable from 'material-table';
import Modal from '../Modal'
import { render } from '@testing-library/react';
import React from 'react';
import { fontSize } from '@mui/system';
import { FastField } from 'formik';
let child_columns = [
{ title: 'Atendente', field: 'user.name' }
];
const MTable = (props) => {
const [selectedRow, setSelectedRow] = useState(null);
console.log('rederizou....................')
useEffect(() => {
console.log(`You have clicked the button ${selectedRow} times`)
},[selectedRow]);
return ( <div style={{ maxWidth: "100%", fontSize:10}}>
<MaterialTable
title='Relatorio'
columns={props.columns}
data={props.data}
onRowClick={(evt, selectedRow) => {
console.log(selectedRow.tableData.id);
console.log(selectedRow);
console.log(selectedRow.messages);
setSelectedRow(selectedRow.tableData.id)
render(<Modal data={selectedRow.messages}/>)
//evt.stopPropagation()
}
}
options={{
search: true,
selection: false,
paging: false,
searchFieldStyle: {
width: 300,
},
rowStyle: rowData => ({
fontSize: 12,
backgroundColor:
selectedRow === rowData.tableData.id ? '#ec5114' : '#FFF'
})
}}
/>
</div>
);
};
export default React.memo(MTable);

View File

@ -0,0 +1,117 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DataGridTable from '../Table';
import MTable from "../MTable";
//let columns = [{ title: 'Chat', field: 'messages.body' },];
// { title: 'Atendente', field: 'user.name' },
const columns = [
{ field: 'id',
title: 'ID',
width: 50,
sortable: false},
{
field: 'fromMe',
title: 'user/client',
type: 'bool',
width: 100,
flex: 1,
editable: false,
sortable: false
},
{
field: 'body',
title: 'message',
type: 'string',
//width: 150,
flex: 1,
editable: false,
sortable: false
},
/* {
field: 'mediaType',
headerName: 'media type',
//width: 110,
flex: 1,
editable: false,
},
{
field: 'mediaUrl',
headerName: 'media url',
type: 'string',
//width: 110,
flex: 1,
editable: false,
},
{
field: 'read',
headerName: 'tead',
type: 'bool',
//width: 110,
flex: 1,
editable: false,
},*/
{
field: 'createdAt',
title: 'created at',
type: 'dateTime',
//width: 110,
flex: 1,
editable: false,
sortable: false
}
];
const Modal = (props) => {
const [open, setOpen] = React.useState(true);
const [scroll, setScroll] = React.useState('paper');
const handleClose = () => {
setOpen(false);
};
const descriptionElementRef = React.useRef(null);
React.useEffect(() => {
if (open) {
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}
}, [open]);
return (
<div>
<Dialog
open={open}
onClose={handleClose}
fullWidth={true}
maxWidth={true}
scroll={scroll}
aria-labelledby="scroll-dialog-title"
aria-describedby="scroll-dialog-description"
>
<MTable data={props.data} columns={columns} />
<DialogActions>
<Button onClick={handleClose}>Ok</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default Modal

View File

@ -0,0 +1,181 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
const SelectTextFields = (props) => {
const [currency, setCurrency] = React.useState('0');
props.func(currency);
const handleChange = (event) => {
setCurrency(event.target.value);
};
return (
<Box
component="form"
sx={{
display: 'flex',
flexDirection: 'column',
'& .MuiTextField-root': { m: 1, width: '30ch' },}}
noValidate
autoComplete="off"
>
<TextField
id="outlined-select-currency-native"
margin="dense"
size="small"
select
label="Usuário"
value={currency}
onChange={handleChange}
SelectProps={{
native: true,
}}
//helperText="Please select your currency"
>
{props.currencies.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
</Box>
);
}
export default SelectTextFields
/*
return (
<Box
component="form"
sx={{
'& .MuiTextField-root': { m: 1, width: '25ch' },
}}
noValidate
autoComplete="off"
>
<div>
<TextField
id="outlined-select-currency"
select
label="Select"
value={currency}
onChange={handleChange}
helperText="Please select your currency"
>
{currencies.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
<TextField
id="outlined-select-currency-native"
select
label="Native select"
value={currency}
onChange={handleChange}
SelectProps={{
native: true,
}}
helperText="Please select your currency"
>
{currencies.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
</div>
<div>
<TextField
id="filled-select-currency"
select
label="Select"
value={currency}
onChange={handleChange}
helperText="Please select your currency"
variant="filled"
>
{currencies.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
<TextField
id="filled-select-currency-native"
select
label="Native select"
value={currency}
onChange={handleChange}
SelectProps={{
native: true,
}}
helperText="Please select your currency"
variant="filled"
>
{currencies.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
</div>
<div>
<TextField
id="standard-select-currency"
select
label="Select"
value={currency}
onChange={handleChange}
helperText="Please select your currency"
variant="standard"
>
{currencies.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
<TextField
id="standard-select-currency-native"
select
label="Native select"
value={currency}
onChange={handleChange}
SelectProps={{
native: true,
}}
helperText="Please select your currency"
variant="standard"
>
{currencies.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
</div>
</Box>
);
*/

View File

@ -0,0 +1,149 @@
import * as React from 'react';
import { DataGrid } from '@mui/x-data-grid';
/*const columns = [
{ field: 'id', headerName: 'ID', width: 90},
{
field: 'firstName',
headerName: 'First name',
width: 150,
editable: false,
},
{
field: 'lastName',
headerName: 'Last name',
width: 150,
editable: true,
},
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 110,
editable: true,
},
{
field: 'fullName',
headerName: 'Full name',
description: 'This column has a value getter and is not sortable.',
sortable: false,
width: 160,
valueGetter: (params) =>
`${params.row.firstName || ''} ${params.row.lastName || ''}`,
},
];
const rows = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
{ id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];*/
const columns = [
{ field: 'id',
headerName: 'ID',
width: 50,
sortable: false},
{
field: 'fromMe',
headerName: 'user/client',
type: 'bool',
width: 100,
flex: 1,
editable: false,
sortable: false
},
{
field: 'body',
headerName: 'message',
type: 'string',
//width: 150,
flex: 1,
editable: false,
sortable: false
},
/* {
field: 'mediaType',
headerName: 'media type',
//width: 110,
flex: 1,
editable: false,
},
{
field: 'mediaUrl',
headerName: 'media url',
type: 'string',
//width: 110,
flex: 1,
editable: false,
},
{
field: 'read',
headerName: 'tead',
type: 'bool',
//width: 110,
flex: 1,
editable: false,
},*/
{
field: 'createdAt',
headerName: 'created at',
type: 'dateTime',
//width: 110,
flex: 1,
editable: false,
sortable: false
}
];
const DataGridTable = (props) => {
return (
<div style={{ height: 400, width: '600' }}>
<DataGrid
onCellDoubleClick = {(params, event) => {
alert(params.value)
if (!event.ctrlKey) {
event.defaultMuiPrevented = true;
}
}}
onCellKeyDown = {(params, event) => {
if(event.key.toString().toLowerCase() == 'enter'){
alert(params.value)
}
}}
rows={props.data}
columns={columns}
pageSize={25}
rowsPerPageOptions={[25]}
rowHeight={38}
//checkboxSelection
disableSelectionOnClick
/>
</div>
);
}
export default DataGridTable

View File

@ -0,0 +1,279 @@
import React, { useState, useEffect, useReducer} from "react";
import MainContainer from "../../components/MainContainer";
import api from "../../services/api";
import SelectField from "../../components/Report/SelectField";
import { data } from '../../components/Report/MTable/data';
import DatePicker1 from '../../components/Report/DatePicker'
import DatePicker2 from '../../components/Report/DatePicker'
import { Button } from "@material-ui/core";
import MTable from "../../components/Report/MTable";
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
const reducer = (state, action) => {
if (action.type === "LOAD_USERS") {
const users = action.payload;
const newUsers = [];
users.forEach((user) => {
const userIndex = state.findIndex((u) => u.id === user.id);
if (userIndex !== -1) {
state[userIndex] = user;
} else {
newUsers.push(user);
}
});
return [...state, ...newUsers];
}
if (action.type === "RESET") {
return [];
}
};
function Item(props) {
const { sx, ...other } = props;
return (
<Box
sx={{
bgcolor: (theme) => (theme.palette.mode === 'dark' ? '#101010' : '#fff'),
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
border: '1px solid',
borderColor: (theme) =>
theme.palette.mode === 'dark' ? 'grey.800' : 'grey.300',
p: 1,
m: 1,
borderRadius: 2,
fontSize: '0.875rem',
fontWeight: '700',
...sx,
}}
{...other}
/>
);
}
Item.propTypes = {
sx: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool]),
),
PropTypes.func,
PropTypes.object,
]),
};
let columnsData = [
{ title: 'Atendente', field: 'user.name' },
{ title: 'Contato', field: 'contact.number' },
{ title: 'Assunto', field: 'queue.name' },
{ title: 'Status', field: 'status' },
{ title: 'Criado', field: 'createdAt' },
{ title: 'Atualizado', field: 'updatedAt',
/*cellStyle: {
backgroundColor: '#039be5',
color: '#FFF'
},
headerStyle: {
backgroundColor: '#039be5',
fontSize: 12
}*/
},
];
const currencies = [
{
value: '1',
label: 'Adriano',
},
{
value: '2',
label: 'Aguinaldo',
},
{
value: '3',
label: 'Maria',
},
{
value: '4',
label: 'Suely',
},
{
value: '0',
label: '',
},
];
const Report = () => {
//--------
const [searchParam, setSearchParam] = useState("");
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(false);
const [pageNumber, setPageNumber] = useState(1);
const [users, dispatch] = useReducer(reducer, []);
const [tot, setTot] = useState(0)
const [columns, setColums] = useState(columnsData)
const [datePicker1, setDatePicker1] = useState(new Date())
const [datePicker2, setDatePicker2] = useState(new Date())
const [userId, setUser] = useState(null)
useEffect(() => {
dispatch({ type: "RESET" });
setPageNumber(1);
}, [searchParam]);
useEffect(() => {
setLoading(true);
const delayDebounceFn = setTimeout(() => {
const fetchUsers = async () => {
try {
const { data } = await api.get("/users/", {
params: { searchParam, pageNumber },
});
dispatch({ type: "LOAD_USERS", payload: data.users });
setHasMore(data.hasMore);
setLoading(false);
} catch (err) {
console.log(err);
}
};
fetchUsers();
}, 500);
return () => clearTimeout(delayDebounceFn);
}, [searchParam, pageNumber]);
function handleTot (){
setTot(tot+1)
console.log('Datepicker valeu: ',DatePicker1.data)
/* if(tot == 3){
setColums(columns1)
} */
}
// Get from child 1
const datePicker1Value = (data) => {
console.log(data);
setDatePicker1(data)
}
// Get from child 2
const datePicker2Value = (data) => {
console.log(data);
setDatePicker2(data)
}
// Get from child 3
const textFieldSelectUser = (data) => {
console.log(data);
setUser(data)
}
return (
<MainContainer>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
<Item><SelectField func={textFieldSelectUser} currencies={currencies}/></Item>
<Item><DatePicker1 func={datePicker1Value} title={'Data inicio'}/></Item>
<Item><DatePicker2 func={datePicker2Value} title={'Data fim'}/></Item>
<Item sx={{ gridColumn: '4 / 5' }}>
<Button size="small" variant="contained" onClick={()=>{handleTot()}}>GO</Button>
</Item>
</Box>
<Box sx={{
display: 'grid',
}}>
<Item sx={{ gridColumn: '1', gridRow: 'span 1' }}>
<MTable data={data} columns={columns}/>
</Item>
</Box>
{/* <MainHeader>
<Title>{i18n.t("users.title")}</Title>
<MainHeaderButtonsWrapper>
</MainHeaderButtonsWrapper>
</MainHeader>
<Paper
className={classes.mainPaper}
variant="outlined"
onScroll={handleScroll}
>
<Table size="small">
<TableHead>
<TableRow>
<TableCell align="center">{i18n.t("users.table.name")}</TableCell>
<TableCell align="center">
{i18n.t("users.table.email")}
</TableCell>
<TableCell align="center">
{i18n.t("users.table.profile")}
</TableCell>
<TableCell align="center">
{i18n.t("users.table.actions")}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell align="center">{user.name}</TableCell>
<TableCell align="center">{user.email}</TableCell>
<TableCell align="center">{user.profile}</TableCell>
<TableCell align="center">
</TableCell>
</TableRow>
))}
{loading && <TableRowSkeleton columns={4} />}
</>
</TableBody>
</Table>
</Paper>*/}
</MainContainer>
)
};
export default Report;

View File

@ -4,6 +4,9 @@ import { ToastContainer } from "react-toastify";
import LoggedInLayout from "../layout";
import Dashboard from "../pages/Dashboard/";
import Report from "../pages/Report/";
import Tickets from "../pages/Tickets/";
import Signup from "../pages/Signup/";
import Login from "../pages/Login/";
@ -16,6 +19,8 @@ import Queues from "../pages/Queues/";
import { AuthProvider } from "../context/Auth/AuthContext";
import { WhatsAppsProvider } from "../context/WhatsApp/WhatsAppsContext";
import Route from "./Route";
//import { Report } from "@material-ui/icons";
//console.log('---AuthProvider: ',AuthProvider)
@ -44,7 +49,16 @@ const Routes = () => {
path="/connections"
component={Connections}
isPrivate
/>
/>
<Route
exact
path="/report"
component={Report}
isPrivate
/>
<Route exact path="/contacts" component={Contacts} isPrivate />
<Route exact path="/users" component={Users} isPrivate />