import React, { useState, useEffect, useReducer, useContext, useCallback } from "react" import MainContainer from "../../components/MainContainer" import api from "../../services/api" import SelectField from "../../components/Report/SelectField" import DatePicker1 from '../../components/Report/DatePicker' import DatePicker2 from '../../components/Report/DatePicker' import MTable from "../../components/Report/MTable" import PropTypes from 'prop-types' import Box from '@mui/material/Box' import { AuthContext } from "../../context/Auth/AuthContext" import { Can } from "../../components/Can" import FormControlLabel from "@mui/material/FormControlLabel" import Checkbox from '@mui/material/Checkbox' import { Button } from "@material-ui/core" import ReportModal from "../../components/ReportModal" import ReportModalType from "../../components/ReportModalType" import MaterialTable from 'material-table' import LogoutIcon from '@material-ui/icons/CancelOutlined' import apiBroker from "../../services/apiBroker" import fileDownload from 'js-file-download' import openSocket from "socket.io-client" import { i18n } from "../../translate/i18n" import Switch from '@mui/material/Switch' const label = { inputProps: { 'aria-label': 'Size switch demo' } } const report = [ { 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }, { 'value': '3', 'label': 'Relatorio de atendimento por numeros' }, { 'value': '4', 'label': 'Relatorio de atendimento por filas' }, ] const reportOptType = [ { 'value': '1', 'label': 'Padrão' }, { 'value': '2', 'label': 'Sintético' }, { 'value': '3', 'label': 'Analítico' } ] const reducerQ = (state, action) => { if (action.type === "DELETE_USER_STATUS") { const userId = action.payload const userIndex = state.findIndex((u) => `${u.id}` === `${userId}`) if (userIndex !== -1) { state.splice(userIndex, 1) } return [...state] } if (action.type === 'LOAD_QUERY') { let queries = action.payload const newQueries = [] if (queries?.hasOwnProperty('usersProfile')) { queries = queries.usersProfile } 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 === "UPDATE_STATUS_ONLINE") { let onlineUser = action.payload let index = -1 if (onlineUser.sumOpen || onlineUser.sumClosed) { index = state.findIndex((e) => ((onlineUser.sumOpen && e.id === onlineUser.sumOpen.userId) || (onlineUser.sumClosed && e.id === onlineUser.sumClosed.userId))) } else { index = state.findIndex((e) => `${e.id}` === `${onlineUser.userId}`) } if (index !== -1) { if (!("statusOnline" in state[index])) { state[index].statusOnline = onlineUser } else if ("statusOnline" in state[index]) { state[index].statusOnline['status'] = onlineUser.status } if ("onlineTime" in onlineUser) { if ("sumOnlineTime" in state[index]) { state[index].sumOnlineTime['sum'] = (onlineUser.onlineTime).split(" ")[1] } else if (!("sumOnlineTime" in state[index])) { state[index].sumOnlineTime = { userId: onlineUser.userId, sum: (onlineUser.onlineTime).split(" ")[1] } } } if (onlineUser.sumOpen) { if ("sumOpen" in state[index]) { state[index].sumOpen['count'] = onlineUser.sumOpen.count } else if (!("sumOpen" in state[index])) { state[index].sumOpen = onlineUser.sumOpen } } if (onlineUser.sumClosed) { if ("sumClosed" in state[index]) { state[index].sumClosed['count'] = onlineUser.sumClosed.count } else if (!("sumClosed" in state[index])) { state[index].sumClosed = onlineUser.sumClosed } } } return [...state] } if (action.type === "RESET") { return [] } } 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 === "DELETE_USER") { const userId = action.payload const userIndex = state.findIndex((u) => u.id === userId) if (userIndex !== -1) { state.splice(userIndex, 1) } return [...state] } 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: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' }, { title: `${i18n.t("reports.listColumns.column1_2")}`, field: 'user.name' }, { title: `${i18n.t("reports.listColumns.column0_4")}`, field: 'contact.number' }, { title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'contact.name' }, { title: `${i18n.t("reports.listColumns.column1_5")}`, field: 'queue.name' }, { title: 'Status', field: 'status' }, { title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' }, { title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' }, { title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }, { title: `Espera`, field: 'waiting_time' }, { title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true }, ] let columnsDataSuper = [ { title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' }, { title: `${i18n.t("reports.listColumns.column1_2")}`, field: 'user.name' }, { title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'contact.name' }, { title: `${i18n.t("reports.listColumns.column1_5")}`, field: 'queue.name' }, { title: 'Status', field: 'status' }, { title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' }, { title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' }, { title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }, { title: `Espera`, field: 'waiting_time' }, { title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true }, ] // function convertAndFormatDate(dateString) { // // Check if the input date string is in the desired format // const isDesiredFormat = /^\w{3} \w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2} GMT[-+]\d{4} \([\w\s]+\)$/i.test(dateString) // if (isDesiredFormat) { // // Convert the input date string to a JavaScript Date object // const dateObj = new Date(dateString) // // Format the date to the desired string format (e.g., 'yyyy-MM-dd') in the Brazil time zone // const formattedDate = `${dateObj.getUTCFullYear()}-${(dateObj.getUTCMonth() + 1).toString().padStart(2, '0')}-${dateObj.getUTCDate().toString().padStart(2, '0')}` // return formattedDate // } // // If the date is not in the desired format, return the original input string // return dateString // } const Report = () => { const { user: userA } = useContext(AuthContext) //-------- const [searchParam] = useState("") const [loading, setLoading] = useState(false) const [hasMore, setHasMore] = useState(false) const [pageNumberTickets, setTicketsPageNumber] = useState(1) const [totalCountTickets, setTotalCountTickets] = useState(0) const [pageNumber, setPageNumber] = useState(1) const [users, dispatch] = useReducer(reducer, []) const [startDate, setDatePicker1] = useState(new Date()) const [endDate, setDatePicker2] = useState(new Date()) const [userId, setUser] = useState(null) const [query, dispatchQ] = useReducer(reducerQ, []) const [reportOption, setReport] = useState('1') const [reporList,] = useState(report) const [profile, setProfile] = useState('') const [dataRows, setData] = useState([]) const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined) const [csvFile, setCsvFile] = useState() const [selectedValue, setSelectedValue] = useState('created') const [checked, setChecked] = useState(true) const [queues, setQueues] = useState([]) const [queueId, setQueue] = useState(null) const [reportTypeList,] = useState(reportOptType) const [reportType, setReportType] = useState('1') const [firstLoad, setFirstLoad] = useState(true) useEffect(() => { dispatch({ type: "RESET" }) dispatchQ({ type: "RESET" }) setTicketsPageNumber(1) setPageNumber(1) }, [searchParam, profile]) useEffect(() => { if (firstLoad) { setFirstLoad(false) } else { } }, [firstLoad]) useEffect(() => { //setLoading(true); const delayDebounceFn = setTimeout(() => { const fetchUsers = async () => { try { const { data } = await api.get("/users/", { params: { searchParam, pageNumber, profile }, }) dispatch({ type: "LOAD_USERS", payload: data.users }) //setLoading(false); } catch (err) { console.log(err) } } fetchUsers() }, 500) return () => clearTimeout(delayDebounceFn) }, [searchParam, pageNumber, reportOption, profile]) useEffect(() => { //setLoading(true); if (firstLoad) return const delayDebounceFn = setTimeout(() => { setLoading(true) const fetchQueries = async () => { try { if (reportOption === '1') { const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues }) let ticketsQueue = data.tickets let userQueues = userA.queues let filterQueuesTickets = [] if (userQueues.length > 1) { filterQueuesTickets = ticketsQueue.filter(ticket => userQueues.some(queue => queue?.name === ticket?.queue?.name)) } else if (userQueues.length > 0) { filterQueuesTickets = ticketsQueue.filter(ticket => ticket?.queue?.name === userQueues[0]?.name) } data.tickets = filterQueuesTickets const tickets = data.tickets.map(ticket => ({ ...ticket, messagesToFilter: ticket.messages.map(message => message.body).join(' '), })) dispatchQ({ type: "LOAD_QUERY", payload: tickets }) console.log(tickets) setHasMore(data.hasMore) setTotalCountTickets(data.count) setLoading(false) setQueues(data.queues) } else if (reportOption === '2') { const dataQuery = await api.get("/reports/user/services", { params: { userId, startDate, endDate }, }) dispatchQ({ type: "RESET" }) dispatchQ({ type: "LOAD_QUERY", payload: dataQuery.data }) //setLoading(false); } else if (reportOption === '3') { const dataQuery = await api.get("/reports/services/numbers", { params: { startDate, endDate }, }) dispatchQ({ type: "RESET" }) dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService }) } else if (reportOption === '4') { const dataQuery = await api.get("/reports/services/queues", { params: { startDate, endDate }, }) console.log(' dataQuery?.data?.reportService: ', dataQuery?.data?.reportService) dispatchQ({ type: "RESET" }) dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService }) } } catch (err) { console.log(err) } } fetchQueries() }, 500) return () => clearTimeout(delayDebounceFn) }, [userId, queueId, checked, startDate, endDate, reportOption, pageNumberTickets, totalCountTickets, selectedValue]) const handleCheckBoxChange = (value) => { setSelectedValue(value) } // Get from child 1 const datePicker1Value = (data) => { setDatePicker1(data) } // Get from child 2 const datePicker2Value = (data) => { setDatePicker2(data) } // Get from child 3 const textFieldSelectUser = (data) => { setQueue(null) setUser(data) } const textFieldSelectQueue = (data) => { setUser(0) setQueue(data) } // Get from report option const reportValue = (data) => { if (data === '2') { setChecked(true) } setReport(data) } // Get from report type option const reportTypeValue = (data) => { console.log('DATA: ', data) let type = '1' if (data === '1') type = 'default' if (data === '2') type = 'synthetic' if (data === '3') type = 'analytic' handleCSVMessages(type) setReportType(data) } useEffect(() => { if (reportOption === '1') { setProfile('') } else if (reportOption === '2') { setProfile('user') } }, [reportOption]) useEffect(() => { const delayDebounceFn = setTimeout(() => { const fetchReportOnQueue = async () => { try { const queryOnQueue = await apiBroker.get("/reports/status/query/onqueue", { params: { adminId: userA.id, baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE, identifier: 'csv' } }) if (queryOnQueue.data) { setCsvFile(queryOnQueue.data.app.file) setOnQueueProcessStatus(queryOnQueue.data.app.status) } else { setOnQueueProcessStatus('empty') } } catch (err) { console.log(err) } } fetchReportOnQueue() }, 500) return () => clearTimeout(delayDebounceFn) }, [userA]) const handleCSVDownload = async () => { setOnQueueProcessStatus('downloading') try { let res = await apiBroker.get(`/reports/download/${csvFile}`, { responseType: 'blob' }) if (res) { fileDownload(res.data, `${csvFile}`) setOnQueueProcessStatus('empty') } } catch (err) { console.log(err) } } const handleCSVMessages = (type = 'default') => { const fetchQueries = async () => { try { const querySavedOnQueue = await apiBroker.post("/reports/messages", { app: { adminId: userA.id, baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE, frontURL: process.env.REACT_APP_FRONTEND_URL, identifier: 'csv' }, query_params: { queueId: queueId, userId: userId, startDate: startDate, endDate: endDate }, query_type: type }) const onQueueStatus = querySavedOnQueue.data.queueStatus setOnQueueProcessStatus(onQueueStatus) } catch (err) { console.log(err) } } fetchQueries() } useEffect(() => { const socket = openSocket(process.env.REACT_APP_BACKEND_URL) socket.on("queryOnQueueStatus", (data) => { if (data.action === 'update') { if (String(data.queryOnQueue.adminId) === String(userA.id)) { setCsvFile(data.queryOnQueue.file) setOnQueueProcessStatus(data.queryOnQueue.queueStatus) } } }) if (reportOption === '2') { socket.on("onlineStatus", (data) => { let date = new Date().toLocaleDateString('pt-BR').split('/') let dateToday = `${date[2]}-${date[1]}-${date[0]}` if (data.action === "logout" || (data.action === "update" && ((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) { dispatchQ({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) } else if (data.action === "delete") { dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) } }) socket.on("user", (data) => { if (data.action === "delete") { dispatch({ type: "DELETE_USER", payload: +data.userId }) } }) } else if (reportOption === "1") { dispatchQ({ type: "RESET" }) setTicketsPageNumber(1) } return () => { socket.disconnect() } }, [reportOption, startDate, endDate, userId, queueId, checked, userA, selectedValue]) useEffect(() => { setData(query.map((column) => { return { ...column } })) }, [query]) const handleLogouOnlineUser = async (userId) => { try { await api.get(`/users/logout/${userId}`) //toast.success(("Desloged!")); //handleDeleteRows(scheduleId) } catch (err) { // toastError(err); } } const loadMore = () => { setTicketsPageNumber((prevState) => prevState + 1) } const handleScroll = (e) => { if (!hasMore || loading) return const { scrollTop, scrollHeight, clientHeight } = e.currentTarget if (scrollHeight - (scrollTop + 1) < clientHeight) { loadMore() } } const renderSwitch = (param) => { switch (param) { case 'empty': return ( <> {query && query.length > 0 && } {/* */} ) case 'pending' || 'processing': return ( <> PROCESSING... ) case 'success': return ( <> ) case 'downloading': return ( <> DOWNLOADING... ) default: return (<>WAITING...) } } const handleChange = (event) => { setChecked(event.target.checked) } return ( ( {(reportOption === '1' || reportOption === '2') && <> {checked ? { return { 'value': obj.id, 'label': obj.name } })} /> : { return { 'value': obj.id, 'label': obj.name } })} /> } } {reportOption === '1' &&
}
{reportOption === '1' ? handleCheckBoxChange('created')} />} label="Criado" /> handleCheckBoxChange('updated')} />} label="Atualizado" /> : }
{reportOption === '1' &&
{renderSwitch(onQueueStatus)}
}
{reportOption === '1' && <> } {reportOption === '2' && imagem de perfil do whatsapp }, { title: 'Nome', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Status', field: 'statusOnline.status', cellStyle: (e, rowData) => { if (rowData['statusOnline'] && rowData['statusOnline'].status) { if (rowData['statusOnline'].status === 'offline') { return { color: "red" } } else if (rowData['statusOnline'].status === 'online') { return { color: "green" } } else if (rowData['statusOnline'].status === 'logout...') { return { color: "orange" } } else if (rowData['statusOnline'].status === 'waiting...') { return { color: "orange" } } } }, }, { title: 'Tempo online', field: 'sumOnlineTime.sum' }, { title: `${i18n.t("reports.dateStart")}`, field: 'startDate' }, { title: `${i18n.t("reports.dateEnd")}`, field: 'endDate' }, { title: 'Em atendimento', field: 'sumOpen.count' }, { title: 'Finalizado', field: 'sumClosed.count' }, ] } data={dataRows} actions={[ (rowData) => { if (rowData.statusOnline && rowData.statusOnline['status'] && rowData.statusOnline['status'] === 'online') { return { icon: LogoutIcon, tooltip: 'deslogar', disable: false, onClick: (event, rowData) => { handleLogouOnlineUser(rowData.id) } } } } ]} options={ { search: true, selection: false, paging: false, padding: 'dense', sorting: true, searchFieldStyle: { width: 300, }, pageSize: 20, headerStyle: { position: "sticky", top: "0" }, maxBodyHeight: "400px", rowStyle: { fontSize: 14, } }} /> } {reportOption === '3' && } {reportOption === '4' && { return { whiteSpace: 'nowrap', backgroundColor: rowData?.queueColor || 'inherit', color: 'white' } } }, { title: 'Conversas iniciadas', field: 'startedByAgent', }, { title: 'Conversas recebidas', field: 'startedByClient' }, { title: `Conversas finalizadas`, field: 'closedChat' }, { title: `Tempo médio de espera`, field: 'avgChatWaitingTime' }, { title: 'Aguardando', field: 'pendingChat' } ] } data={dataRows} options={ { search: true, selection: false, paging: false, padding: 'dense', sorting: true, searchFieldStyle: { width: 300, }, pageSize: 20, headerStyle: { position: "sticky", top: "0" }, maxBodyHeight: "400px", rowStyle: { fontSize: 14, } // rowStyle: rowData => ({ // backgroundColor: rowData.queueColor || 'inherit', // fontSize: 14 // }) }} /> }
)} /> ) } export default Report