diff --git a/frontend/package.json b/frontend/package.json
index acc009a..265ef83 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -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": {}
+ }
}
diff --git a/frontend/public/index.html b/frontend/public/index.html
index 573114e..e3e354c 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -15,6 +15,9 @@
+
+
+
+
+ handleDateChange(date)}
+ />
+
+
+ );
+}
+
+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 (
+
+
+ {setValue(newValue)}}
+ renderInput={(params) => }
+ />
+
+
+ );
+}
+
+export default ResponsiveDatePickers*/
\ No newline at end of file
diff --git a/frontend/src/components/Report/MTable/data.js b/frontend/src/components/Report/MTable/data.js
new file mode 100644
index 0000000..6cebce3
--- /dev/null
+++ b/frontend/src/components/Report/MTable/data.js
@@ -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"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/frontend/src/components/Report/MTable/index.js b/frontend/src/components/Report/MTable/index.js
new file mode 100644
index 0000000..1fc4c52
--- /dev/null
+++ b/frontend/src/components/Report/MTable/index.js
@@ -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 (
+
+ {
+
+ console.log(selectedRow.tableData.id);
+ console.log(selectedRow);
+ console.log(selectedRow.messages);
+ setSelectedRow(selectedRow.tableData.id)
+
+ render()
+
+ //evt.stopPropagation()
+ }
+ }
+
+ options={{
+ search: true,
+ selection: false,
+ paging: false,
+ searchFieldStyle: {
+ width: 300,
+ },
+
+ rowStyle: rowData => ({
+ fontSize: 12,
+ backgroundColor:
+ selectedRow === rowData.tableData.id ? '#ec5114' : '#FFF'
+ })
+ }}
+ />
+
+ );
+
+ };
+
+ export default React.memo(MTable);
\ No newline at end of file
diff --git a/frontend/src/components/Report/Modal/index.js b/frontend/src/components/Report/Modal/index.js
new file mode 100644
index 0000000..205ccc7
--- /dev/null
+++ b/frontend/src/components/Report/Modal/index.js
@@ -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 (
+
+
+
+
+ );
+}
+
+export default Modal
\ No newline at end of file
diff --git a/frontend/src/components/Report/SelectField/index.js b/frontend/src/components/Report/SelectField/index.js
new file mode 100644
index 0000000..2c3992f
--- /dev/null
+++ b/frontend/src/components/Report/SelectField/index.js
@@ -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 (
+
+
+
+ {props.currencies.map((option) => (
+
+ ))}
+
+
+
+
+
+ );
+}
+
+export default SelectTextFields
+
+
+
+
+
+
+
+
+
+
+/*
+
+return (
+
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+ {currencies.map((option) => (
+
+ ))}
+
+
+
+ );
+
+*/
diff --git a/frontend/src/components/Report/Table/index.js b/frontend/src/components/Report/Table/index.js
new file mode 100644
index 0000000..a847a7e
--- /dev/null
+++ b/frontend/src/components/Report/Table/index.js
@@ -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 (
+
+ {
+
+ 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
+ />
+
+ );
+}
+
+export default DataGridTable
\ No newline at end of file
diff --git a/frontend/src/pages/Report/index.js b/frontend/src/pages/Report/index.js
index e69de29..f8898de 100644
--- a/frontend/src/pages/Report/index.js
+++ b/frontend/src/pages/Report/index.js
@@ -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 (
+ (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 (
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ {/*
+ {i18n.t("users.title")}
+
+
+
+
+
+
+
+
+
+
+ {i18n.t("users.table.name")}
+
+ {i18n.t("users.table.email")}
+
+
+ {i18n.t("users.table.profile")}
+
+
+
+ {i18n.t("users.table.actions")}
+
+
+
+
+
+ <>
+ {users.map((user) => (
+
+ {user.name}
+ {user.email}
+ {user.profile}
+
+
+
+
+
+
+
+ ))}
+ {loading && }
+ >
+
+
+ */}
+
+
+
+ )
+};
+
+export default Report;
diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js
index 3251cd3..f05b0b6 100644
--- a/frontend/src/routes/index.js
+++ b/frontend/src/routes/index.js
@@ -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
- />
+ />
+
+
+
+