From bd29afd40221b7a341cdbf5df490833872e8c081 Mon Sep 17 00:00:00 2001 From: adriano Date: Mon, 24 Jan 2022 08:44:42 -0300 Subject: [PATCH] =?UTF-8?q?ATEN=C3=87=C3=83O:=20Altera=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20vers=C3=A3o=20do=20react:=20^16.13.1=20=20e=20do=20react-dom?= =?UTF-8?q?:=20^16.13.1=20para=20react:=20^17.0.2=20=20e=20react-dom:=20^1?= =?UTF-8?q?7.0.2,=20caso=20houver=20problemas=20de=20compatibilidade,=20vo?= =?UTF-8?q?ltar=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 - /> + /> + + + +