import React, { useContext, useReducer, useEffect, useState, useCallback } from "react" import { addHours, addMinutes, addSeconds, intervalToDuration } from "date-fns" import Paper from "@material-ui/core/Paper" import Container from "@material-ui/core/Container" import Grid from "@material-ui/core/Grid" import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" import Tooltip from "@mui/material/Tooltip" import Zoom from "@mui/material/Zoom" import IconButton from "@mui/material/IconButton" import Info from "@material-ui/icons/Info" import SelectField from "../../components/Report/SelectField" import { AuthContext } from "../../context/Auth/AuthContext" import { i18n } from "../../translate/i18n"; import Chart from "./Chart" import PieChart from "./PieChart" import openSocket from "socket.io-client" import api from "../../services/api" import { Can } from "../../components/Can" import TableUser from "../../components/DashboardUser/TableUser" const useStyles = makeStyles((theme) => ({ container: { paddingTop: theme.spacing(4), paddingBottom: theme.spacing(4), }, fixedHeightPaper: { padding: theme.spacing(2), display: "flex", overflow: "auto", flexDirection: "column", height: 280, }, customFixedHeightPaper: { padding: theme.spacing(2), display: "flex", overflow: "auto", flexDirection: "column", height: 120, }, customFixedHeightPaperLg: { padding: theme.spacing(2), display: "flex", overflow: "auto", flexDirection: "column", height: "100%", }, containerPaperFix: { width: "100%", textTransform: "capitalize", padding: theme.spacing(2), paddingBottom: theme.spacing(4), height: "auto", overflowY: "hidden", }, cardPaperFix: { textTransform: "capitalize", paddingLeft: theme.spacing(4), paddingRight: theme.spacing(4), height: window.innerWidth <= 992 ? "500px" : "auto", overflowY: "hidden", }, cardStyleFix: { display: "flex", flexDirection: "row", justifyContent: "left", alignItems: "center", gap: "32px", }, logginBtn: { position: "absolute", bottom: "21px", right: "21px", fontSize: "12px", }, tableRowHead: { backgroundColor: "lightgrey", }, tableRowBody: { textAlign: "center", " &:nth-child(even)": { backgroundColor: "#f7f7f7", }, }, tableCounterOpen: { color: "white", backgroundColor: "green", width: "25px", textAlign: "center", borderRadius: "5px", }, tableCounterClosed: { color: "white", backgroundColor: "red", width: "25px", textAlign: "center", borderRadius: "5px", }, tableQueues: { color: "white", width: "25px", textAlign: "center", borderRadius: "5px", }, })) var _fifo const sumOnlineTimeNow = (oldOnlineTimeSum) => { let onlineTime = new Date() if (!oldOnlineTimeSum.onlineTime) { oldOnlineTimeSum.onlineTime = `${oldOnlineTimeSum.updatedAt.split(' ')[0]} 00:00:00` } onlineTime.setUTCHours(new Date(oldOnlineTimeSum.onlineTime).getHours()) onlineTime.setUTCMinutes(new Date(oldOnlineTimeSum.onlineTime).getMinutes()) onlineTime.setUTCSeconds(new Date(oldOnlineTimeSum.onlineTime).getSeconds()) let newtTime = intervalToDuration({ start: new Date(oldOnlineTimeSum.updatedAt), end: new Date() }) if (newtTime.hours && +newtTime.hours > 0) { onlineTime = addHours(onlineTime, newtTime.hours) } if (newtTime.minutes && +newtTime.minutes > 0) { onlineTime = addMinutes(onlineTime, newtTime.minutes) } if (newtTime.seconds && +newtTime.seconds > 0) { onlineTime = addSeconds(onlineTime, newtTime.seconds) } const isoDate = new Date(onlineTime) const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ') return newOnlinetime } const reducer = (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") { 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 === "UPDATE_STATUS_ONLINE") { let onlineUser = action.payload let index = -1 // console.log('UPDATE_STATUS_ONLINE: ', onlineUser) let onlySumOpenClosed = false if (onlineUser.sumOpen || onlineUser.sumClosed) { index = state.findIndex( (e) => (onlineUser.sumOpen && e.id === onlineUser.sumOpen.userId) || (onlineUser.sumClosed && e.id === onlineUser.sumClosed.userId) ) onlySumOpenClosed = true } else { index = state.findIndex((e) => `${e.id}` === `${onlineUser.userId}`) } if (index !== -1) { if (!onlySumOpenClosed) { 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 } } if (onlineUser.openClosedInQueue) { state[index].openClosedInQueue = onlineUser.openClosedInQueue } if (onlineUser.openClosedOutQueue) { state[index].openClosedOutQueue = onlineUser.openClosedOutQueue } } return [...state] } if (action.type === "RESET") { return [] } } const Dashboard = () => { const { user } = useContext(AuthContext) const classes = useStyles() const [usersOnlineInfo, dispatch] = useReducer(reducer, []) const [ticketStatusChange, setStatus] = useState() const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 }) const [ticketStatusChatEnd, setTicketStatusChatEnd] = useState([]) const userQueueIds = user.queues?.map((q) => q.id); const [selectedQueue, setSelectedQueue] = useState(userQueueIds || []); useEffect(() => { dispatch({ type: "RESET" }) }, []) const handleLogouOnlineUser = async (userId) => { try { await api.get(`/users/logout/${userId}`) //toast.success(("Desloged!")); //handleDeleteRows(scheduleId) } catch (err) { // toastError(err); } } useEffect(() => { //setLoading(true); const delayDebounceFn = setTimeout(() => { // setLoading(true); const fetchQueries = async () => { try { let date = new Date().toLocaleDateString("pt-BR").split("/") let dateToday = `${date[2]}-${date[1]}-${date[0]}` const { data } = await api.get("/reports/user/services", { params: { userId: null, startDate: dateToday, endDate: dateToday, userQueues: selectedQueue }, }) dispatch({ type: "RESET" }) dispatch({ type: "LOAD_QUERY", payload: data.usersProfile }) const { data: ticketStatusChatEndData } = await api.get("/reports/count/statusChatEnd", { params: { startDate: dateToday, endDate: dateToday, userQueues: selectedQueue }, }) setTicketStatusChatEnd(ticketStatusChatEndData.reportStatusChatEnd) } catch (err) { } } fetchQueries() }, 500) return () => clearTimeout(delayDebounceFn) }, [selectedQueue]) useEffect(() => { if (!usersOnlineInfo || usersOnlineInfo.length === 0) return if (_fifo) { clearInterval(_fifo) } _fifo = setInterval(() => { for (let i = 0; i < usersOnlineInfo.length; i++) { if (usersOnlineInfo[i].statusOnline && usersOnlineInfo[i].statusOnline.status === 'online') { let onlineTimeCurrent = sumOnlineTimeNow({ onlineTime: usersOnlineInfo[i].statusOnline.onlineTime, updatedAt: usersOnlineInfo[i].statusOnline.updatedAt }) dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: usersOnlineInfo[i].id, status: usersOnlineInfo[i].statusOnline.status, onlineTime: onlineTimeCurrent } }) } } // usersOnlineInfo.map((e) => { // if (e.statusOnline && e.statusOnline.status === 'online') { // let onlineTimeCurrent = sumOnlineTimeNow({onlineTime: e.statusOnline.onlineTime, updatedAt: e.statusOnline.updatedAt}) // dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: e.id, status: e.statusOnline.status, onlineTime: onlineTimeCurrent } }); // } // }) }, 3000) }, [usersOnlineInfo]) useEffect(() => { const socket = openSocket(process.env.REACT_APP_BACKEND_URL) socket.on("ticketStatus", (data) => { if (data.action === "update") { setStatus("") setStatus(data.ticketStatus.status) } }) socket.on("onlineStatus", (data) => { if (data.action === "logout" || data.action === "update") { dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) } else if (data.action === "delete") { dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) } }) socket.on("user", (data) => { if (data.action === "delete") { dispatch({ type: "DELETE_USER", payload: +data.userId }) } }) return () => { socket.disconnect() } }, []) const handleSelectedQueue = useCallback((queueSelected) => { if(queueSelected !== 'All'){ const queueIndex = user?.queues?.findIndex((q) => q.id === parseInt(queueSelected)); const queueIds = [] queueIds.push(user?.queues[queueIndex]?.id); setSelectedQueue(queueIds); }else{ const queueIds = user?.queues?.map((queue) => queue.id); setSelectedQueue(queueIds); } },[user, setSelectedQueue]) useEffect(() => { if (ticketStatusChange === "") return const delayDebounceFn = setTimeout(() => { const fetchQueries = async () => { try { let date = new Date().toLocaleDateString("pt-BR").split("/") let dateToday = `${date[2]}-${date[1]}-${date[0]}` const _open = await api.get("/tickets/count", { params: { status: "open", date: dateToday, queueIds: selectedQueue }, }) const _closed = await api.get("/tickets/count", { params: { status: "closed", date: dateToday, queueIds: selectedQueue }, }) const _pending = await api.get("/tickets/count", { params: { status: "pending", queueIds: selectedQueue }, }) const _openAll = await api.get("/tickets/count", { params: { status: "open", queueIds: selectedQueue }, }) setTicktsStatus({ open: _open.data.count, openAll: _openAll.data.count, closed: _closed.data.count, pending: _pending.data.count, }) // setOpen(_open.data.count); // setClosed(_closed.data.count); // setPending(_pending.data.count); } catch (err) { console.log(err) } } fetchQueries() }, 500) return () => clearTimeout(delayDebounceFn) }, [ticketStatusChange, selectedQueue]) return ( ( tickets { return { 'value': obj.id, 'label': obj.name } })} /> {i18n.t('dashboard.titles.waiting')} {ticketsStatus.pending} {i18n.t('dashboard.titles.inService')} Hoje/Todo Periodo {ticketsStatus.open}/{ticketsStatus.openAll} {i18n.t('dashboard.titles.ticketsClosed')} {ticketsStatus.closed} {i18n.t('dashboard.titles.users')} Total de Agentes {usersOnlineInfo.length} Online { usersOnlineInfo.filter( (status) => status.statusOnline && status.statusOnline.status === "online" ).length } Offline { usersOnlineInfo.filter( (status) => !status.statusOnline || status.statusOnline.status === "offline" ).length } {usersOnlineInfo && } )} /> ) } export default Dashboard