From bd29afd40221b7a341cdbf5df490833872e8c081 Mon Sep 17 00:00:00 2001 From: adriano Date: Mon, 24 Jan 2022 08:44:42 -0300 Subject: [PATCH 1/4] =?UTF-8?q?ATEN=C3=87=C3=83O:=20Altera=C3=A7=C3=A3o=20?= =?UTF-8?q?de=20vers=C3=A3o=20do=20react:=20^16.13.1=20=20e=20do=20react-d?= =?UTF-8?q?om:=20^16.13.1=20para=20react:=20^17.0.2=20=20e=20react-dom:=20?= =?UTF-8?q?^17.0.2,=20caso=20houver=20problemas=20de=20compatibilidade,=20?= =?UTF-8?q?voltar=20para=20=20vers=C3=A3o=20anterior=2016?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/package.json | 16 +- frontend/public/index.html | 3 + .../src/components/Report/DatePicker/index.js | 75 +++++ frontend/src/components/Report/MTable/data.js | 113 +++++++ .../src/components/Report/MTable/index.js | 69 +++++ frontend/src/components/Report/Modal/index.js | 117 ++++++++ .../components/Report/SelectField/index.js | 181 ++++++++++++ frontend/src/components/Report/Table/index.js | 149 ++++++++++ frontend/src/pages/Report/index.js | 279 ++++++++++++++++++ frontend/src/routes/index.js | 16 +- 10 files changed, 1012 insertions(+), 6 deletions(-) create mode 100644 frontend/src/components/Report/DatePicker/index.js create mode 100644 frontend/src/components/Report/MTable/data.js create mode 100644 frontend/src/components/Report/MTable/index.js create mode 100644 frontend/src/components/Report/Modal/index.js create mode 100644 frontend/src/components/Report/SelectField/index.js create mode 100644 frontend/src/components/Report/Table/index.js 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) => ( + + {option.label} + + ))} + + + {currencies.map((option) => ( + + ))} + +
+
+ + {currencies.map((option) => ( + + {option.label} + + ))} + + + {currencies.map((option) => ( + + ))} + +
+
+ + {currencies.map((option) => ( + + {option.label} + + ))} + + + {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 - /> + /> + + + + From dd06ac45c970d05a4a66f56078a84f9f29bb012f Mon Sep 17 00:00:00 2001 From: adriano Date: Tue, 25 Jan 2022 11:24:05 -0300 Subject: [PATCH 2/4] =?UTF-8?q?Consulta=20por=20id,=20dataInicio,=20dataFi?= =?UTF-8?q?m=20funcional=20porem=20com=20problema=20na=20renderiza=C3=A7?= =?UTF-8?q?=C3=A3o=20da=20tabela.=20Este=20commit=20ser=C3=A1=20para=20alt?= =?UTF-8?q?era=C3=A7=C3=A3o=20na=20vers=C3=A3o=20da=20tabela=20materia-tab?= =?UTF-8?q?le=20para=20tentar=20corrigir=20o=20congelamento=20da=20p=C3=A1?= =?UTF-8?q?gina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/controllers/ReportController.ts | 24 +++- backend/src/routes/reportRoutes.ts | 4 +- .../TicketServices/ShowTicketReport.ts | 96 +++++++------ .../src/components/Report/DatePicker/index.js | 8 +- frontend/src/components/Report/MTable/data.js | 95 ++++++++++++- .../src/components/Report/MTable/index.js | 17 +-- .../components/Report/SelectField/index.js | 6 +- frontend/src/pages/Report/index.js | 132 ++++++++++++++---- 8 files changed, 299 insertions(+), 83 deletions(-) diff --git a/backend/src/controllers/ReportController.ts b/backend/src/controllers/ReportController.ts index 56f5c80..4025384 100644 --- a/backend/src/controllers/ReportController.ts +++ b/backend/src/controllers/ReportController.ts @@ -5,7 +5,13 @@ import AppError from "../errors/AppError"; import ShowTicketReport from "../services/TicketServices/ShowTicketReport"; -export const reportUser = async (req: Request, res: Response): Promise => { +type IndexQuery = { + userId: string; + startDate: string; + endDate: string; + }; + +/*export const reportUser = async (req: Request, res: Response): Promise => { const { userId } = req.params; @@ -15,6 +21,22 @@ export const reportUser = async (req: Request, res: Response): Promise return res.status(200).json(test); +};*/ + + +export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise => { + + const { userId, startDate, endDate } = req.query as IndexQuery + + console.log('******* Estrou no report') + console.log('******* userId: ', userId) + console.log('******* startDate: ', startDate) + console.log('******* endDate: ', endDate) + + const data_query = await ShowTicketReport(userId, startDate, endDate); + + return res.status(200).json(data_query); + }; /*export const reportAll = async (req: Request, res: Response): Promise => { diff --git a/backend/src/routes/reportRoutes.ts b/backend/src/routes/reportRoutes.ts index c05f6f4..e86ac41 100644 --- a/backend/src/routes/reportRoutes.ts +++ b/backend/src/routes/reportRoutes.ts @@ -7,7 +7,9 @@ import * as ReportController from "../controllers/ReportController"; const reportRoutes = express.Router(); -reportRoutes.get("/reports/:userId", /*isAuth,*/ ReportController.reportUser); +//reportRoutes.get("/reports/:userId", /*isAuth,*/ ReportController.reportUser); + +reportRoutes.get("/reports", /*isAuth,*/ ReportController.reportUserByDateStartDateEnd); //reportRoutes.get("/reports", /*isAuth,*/ ReportController.reportAll); diff --git a/backend/src/services/TicketServices/ShowTicketReport.ts b/backend/src/services/TicketServices/ShowTicketReport.ts index 8b83ade..527a5c6 100644 --- a/backend/src/services/TicketServices/ShowTicketReport.ts +++ b/backend/src/services/TicketServices/ShowTicketReport.ts @@ -7,7 +7,62 @@ import Queue from "../../models/Queue"; import Message from "../../models/Message"; import { userInfo } from "os"; -//Report by user +import { Op } from "sequelize"; + +import { Sequelize } from "sequelize"; +import moment from 'moment'; + +import { startOfDay, endOfDay, parseISO, getDate} from "date-fns"; + +//Report by user, startDate, endDate +const ShowTicketReport = async (id: string | number, startDate: string, endDate: string): Promise => { + + const ticket = await Ticket.findAll({ + where: { + userid: id, + //createdAt: { + // [Op.between]: [+new Date('2022-01-24').toISOString(), +new Date().toISOString()] + //}, + createdAt: { + [Op.gte]: startDate+' 00:00:00.000000', + [Op.lte]: endDate +' 23:59:59.999999' + } + + }, + + + attributes: ['id', 'status', 'createdAt', 'updatedAt'], + include: [ + { + model: Message, + required:true, + separate: true, + attributes: ['body', 'read', 'mediaType','fromMe', 'mediaUrl','createdAt'], + order: [ + ['createdAt', 'ASC'] + ] + }, + { + model: Contact, + attributes: ['name', 'number'] + }, + { + model: User, + attributes: ['name', 'email'] + }, + { + model: Queue, + attributes: ['name'] + }, + + ], + + }); + + + + +/*//Report by user const ShowTicketReport = async (id: string | number): Promise => { const ticket = await Ticket.findAll({ @@ -36,47 +91,10 @@ const ShowTicketReport = async (id: string | number): Promise => { attributes: ['name'] }, - ], - - + ], - }); - - - - - - /*const ticket = await Message.findAll({ - //raw: true, - where:{''}, - attributes: ['body', 'createdAt', 'ticketId'], - include: [ - { - model: Ticket, - attributes: ['contactid', 'userid', 'queueid', 'status'], - include:[ - { - model: Contact, - attributes: ['name', 'number'] - }, - { - model: User, - attributes: ['name', 'email'] - }, - { - model: Queue, - attributes: ['name'] - } - ], - }, - - ], - order: - ['ticketId', 'createdAt'] - }); */ - if (!ticket) { throw new AppError("ERR_NO_TICKET_FOUND", 404); } diff --git a/frontend/src/components/Report/DatePicker/index.js b/frontend/src/components/Report/DatePicker/index.js index b36b15a..5031bd9 100644 --- a/frontend/src/components/Report/DatePicker/index.js +++ b/frontend/src/components/Report/DatePicker/index.js @@ -12,11 +12,17 @@ import { MuiPickersUtilsProvider, } from '@material-ui/pickers'; + +function formatDateDatePicker(data){ + return String(new Date(data).getFullYear())+'-'+ + String(new Date(data).getMonth() + 1).padStart(2,'0')+'-'+ + String(new Date(data).getDate()).padStart(2,'0') +} function ResponsiveDatePickers(props) { const [selectedDate, handleDateChange] = useState(new Date()); - props.func(selectedDate); + props.func(formatDateDatePicker(selectedDate)); return ( diff --git a/frontend/src/components/Report/MTable/data.js b/frontend/src/components/Report/MTable/data.js index 6cebce3..41a355d 100644 --- a/frontend/src/components/Report/MTable/data.js +++ b/frontend/src/components/Report/MTable/data.js @@ -1,6 +1,12 @@ import { gridDateTimeFormatter } from "@mui/x-data-grid"; + + + + + export const data = [ + { "id": 210, "status": "closed", @@ -109,5 +115,92 @@ export const data = [ "createdAt": "2022-01-18T20:26:04.360Z" } ] - } + }, + + { + "id":229, + "status":"closed", + "createdAt":"2022-01-24T13:20:01.000Z", + "updatedAt":"2022-01-24T13:21:02.000Z", + "contact":{ + "name":"Meu Numero Oi", + "number":"5517988325936" + }, + "user":{ + "name":"Administrador", + "email":"admin@whaticket.com" + }, + "queue":{ + "name":"Cancelamento ou Sugestões" + }, + "messages":[ + { + "mediaUrl":null, + "body":"Bom dia", + "read":true, + "mediaType":"chat", + "fromMe":false, + "createdAt":"2022-01-24T13:20:01.562Z" + }, + { + "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-24T13:20:04.674Z" + }, + { + "mediaUrl":null, + "body":"2", + "read":true, + "mediaType":"chat", + "fromMe":false, + "createdAt":"2022-01-24T13:20:08.617Z" + }, + { + "mediaUrl":null, + "body":"‎Olá, sou do Cancelamento ou Sugestões, vou te atender em alguns instantes!", + "read":true, + "mediaType":"chat", + "fromMe":true, + "createdAt":"2022-01-24T13:20:09.216Z" + }, + { + "mediaUrl":null, + "body":"Ok obrigado", + "read":true, + "mediaType":"chat", + "fromMe":false, + "createdAt":"2022-01-24T13:20:13.902Z" + }, + { + "mediaUrl":null, + "body":"*Administrador:*\nOlá bom dia como posso ajudar", + "read":true, + "mediaType":"chat", + "fromMe":true, + "createdAt":"2022-01-24T13:20:34.561Z" + }, + { + "mediaUrl":null, + "body":"Estou com problemas técnicos", + "read":true, + "mediaType":"chat", + "fromMe":false, + "createdAt":"2022-01-24T13:20:54.191Z" + }, + { + "mediaUrl":null, + "body":"*Administrador:*\nok", + "read":true, + "mediaType":"chat", + "fromMe":true, + "createdAt":"2022-01-24T13:20:57.847Z" + } + ], + "tableData":{ + "id":0 + } + } ] \ No newline at end of file diff --git a/frontend/src/components/Report/MTable/index.js b/frontend/src/components/Report/MTable/index.js index 1fc4c52..87e7364 100644 --- a/frontend/src/components/Report/MTable/index.js +++ b/frontend/src/components/Report/MTable/index.js @@ -4,21 +4,13 @@ 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'; - +import React from 'react'; - -let child_columns = [ - { title: 'Atendente', field: 'user.name' } -]; - const MTable = (props) => { const [selectedRow, setSelectedRow] = useState(null); - console.log('rederizou....................') + console.log('rederizou....................: ',props.data) useEffect(() => { @@ -40,7 +32,7 @@ const MTable = (props) => { console.log(selectedRow.messages); setSelectedRow(selectedRow.tableData.id) - render() + render() //evt.stopPropagation() } @@ -66,4 +58,5 @@ const MTable = (props) => { }; - export default React.memo(MTable); \ No newline at end of file + + export default React.memo(MTable) \ No newline at end of file diff --git a/frontend/src/components/Report/SelectField/index.js b/frontend/src/components/Report/SelectField/index.js index 2c3992f..ce5bd3a 100644 --- a/frontend/src/components/Report/SelectField/index.js +++ b/frontend/src/components/Report/SelectField/index.js @@ -7,6 +7,8 @@ import TextField from '@mui/material/TextField'; const SelectTextFields = (props) => { const [currency, setCurrency] = React.useState('0'); + props.currencies.push({ value: '0', label: ''}) + props.func(currency); const handleChange = (event) => { @@ -15,7 +17,7 @@ const SelectTextFields = (props) => { return ( - { noValidate autoComplete="off" > - { + + if(action.type === 'LOAD_QUERY'){ + + console.log('----------------action.payload: ', action.payload) + const queries = action.payload + const newQueries = [] + + queries.forEach((query) => { + + const queryIndex = state.findIndex((q) => q.id === query.id) + + if(queryIndex !== -1){ + state[queryIndex] = query + } + else{ + newQueries.push(query) + } + + }) + + return [...state, ...newQueries] + } + + if (action.type === "RESET") { + return []; + } + +} + + + const reducer = (state, action) => { + if (action.type === "LOAD_USERS") { const users = action.payload; const newUsers = []; @@ -36,6 +70,7 @@ const reducer = (state, action) => { } }; + function Item(props) { @@ -71,8 +106,6 @@ Item.propTypes = { }; - - let columnsData = [ { title: 'Atendente', field: 'user.name' }, @@ -97,7 +130,7 @@ let columnsData = [ ]; - const currencies = [ + /*const currencies = [ { value: '1', label: 'Adriano', @@ -119,7 +152,7 @@ let columnsData = [ label: '', }, - ]; + ];*/ @@ -132,25 +165,33 @@ const Report = () => { 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 [columns, setColums] = useState([]) + + const [startDate, setDatePicker1] = useState(new Date()) + const [endDate, setDatePicker2] = useState(new Date()) const [userId, setUser] = useState(null) + const [query, dispatchQ] = useReducer(reducerQ, []) + useEffect(() => { dispatch({ type: "RESET" }); + dispatchQ({ 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); @@ -158,41 +199,76 @@ const Report = () => { console.log(err); } }; + fetchUsers(); + }, 500); return () => clearTimeout(delayDebounceFn); }, [searchParam, pageNumber]); - function handleTot (){ - setTot(tot+1) + useEffect(() => { - console.log('Datepicker valeu: ',DatePicker1.data) - /* if(tot == 3){ - setColums(columns1) - } */ + setLoading(true); -} + const delayDebounceFn = setTimeout(() => { + + const fetchQueries = async () => { + try { + const dataQuery = await api.get("/reports/", {params: {userId, startDate, endDate },}); + + console.log('fffffffffffffffffffff query: ', dataQuery.data) + dispatchQ({ type: "LOAD_QUERY", payload: dataQuery.data }); + + setLoading(false); + + } catch (err) { + console.log(err); + } + }; + + fetchQueries(); + + }, 500); + return () => clearTimeout(delayDebounceFn); + + }, [userId, startDate, endDate]); + // Get from child 1 -const datePicker1Value = (data) => { - console.log(data); +const datePicker1Value = (data) => { + console.log('DATE1: ',(data)); setDatePicker1(data) } // Get from child 2 const datePicker2Value = (data) => { - console.log(data); + console.log('DATE2: ',(data)); setDatePicker2(data) } // Get from child 3 const textFieldSelectUser = (data) => { - console.log(data); + console.log('textField: ',data); setUser(data) } + +function handleQuery (){ + + console.log('startDate: ', startDate) + console.log('endDate: ', endDate) + console.log('userid: ', userId) + + /* if(tot == 3){ + setColums(columns1) + } */ + +} + +console.log('XXXXXXXXX: ', query) + return ( @@ -200,12 +276,16 @@ const textFieldSelectUser = (data) => { - + { + return {'value': obj.id, 'label': obj.name} + })}/> + + - + @@ -214,10 +294,10 @@ const textFieldSelectUser = (data) => { display: 'grid', }}> - - - - + + +
+ {/* From 3b4bef8266b57a5165676173f70b2036a42af918 Mon Sep 17 00:00:00 2001 From: adriano Date: Tue, 25 Jan 2022 12:09:27 -0300 Subject: [PATCH 3/4] =?UTF-8?q?Estado=20funcional=20do=20relat=C3=B3rio=20?= =?UTF-8?q?de=20atendimento=20por=20usu=C3=A1rio=20passando:=20id,=20dataI?= =?UTF-8?q?nicio,=20dataFim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Report/MTable/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Report/MTable/index.js b/frontend/src/components/Report/MTable/index.js index 87e7364..b9c46a2 100644 --- a/frontend/src/components/Report/MTable/index.js +++ b/frontend/src/components/Report/MTable/index.js @@ -11,6 +11,12 @@ const MTable = (props) => { const [selectedRow, setSelectedRow] = useState(null); console.log('rederizou....................: ',props.data) + + const dataLoad = props.data.map((dt) => { return { ...dt }}); + const columnsLoad = props.columns.map((column) => { return { ...column }}); + + console.log('dataLoad....................: ',dataLoad) + console.log('columnsLoad....................: ',columnsLoad) useEffect(() => { @@ -22,8 +28,8 @@ const MTable = (props) => { { From 39453e791d16e2b099329fbb56e326645448a1e1 Mon Sep 17 00:00:00 2001 From: adriano Date: Tue, 25 Jan 2022 13:25:37 -0300 Subject: [PATCH 4/4] =?UTF-8?q?Adapta=C3=A7=C3=A3o=20para=20ura=20funciona?= =?UTF-8?q?r=20com=20op=C3=A7=C3=A3o=20e=20sem=20op=C3=A7=C3=A3o=20e=20ide?= =?UTF-8?q?nta=C3=A7=C3=A3o=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WbotServices/wbotMessageListener.ts | 27 ++++++++++++------- frontend/src/layout/index.js | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 2c74edd..a85e356 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -143,23 +143,30 @@ const verifyQueue = async ( const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!); - if (queues.length === 1) { + /*if (queues.length === 1) { await UpdateTicketService({ ticketData: { queueId: queues[0].id }, ticketId: ticket.id }); return; + }*/ + + + let selectedOption = null; + let choosenQueue = null + + if (queues.length === 1) { + selectedOption = 1; + choosenQueue = queues[+selectedOption - 1]; + } + else{ + selectedOption = msg.body; + choosenQueue = queues[+selectedOption - 1]; } - - console.log('queues.lengthqueues.lengthqueues.lengthqueues.lengthqueues.length: ',queues.length) - - const selectedOption = msg.body; - const choosenQueue = queues[+selectedOption - 1]; - - //apagar essa gambiarra e ativar as 2 linhas acima thuanny - //const selectedOption = 1; - //const choosenQueue = queues[+selectedOption - 1]; + // const selectedOption = msg.body; + // const choosenQueue = queues[+selectedOption - 1]; + if (choosenQueue) { await UpdateTicketService({ diff --git a/frontend/src/layout/index.js b/frontend/src/layout/index.js index e91ce89..6353668 100644 --- a/frontend/src/layout/index.js +++ b/frontend/src/layout/index.js @@ -220,7 +220,7 @@ const LoggedInLayout = ({ children }) => { className={classes.title} > - GRUPO HIT + BETAGROUP {user.id && }