import React, { useContext, useReducer, useEffect, useState } from "react"; 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 Card from "@mui/material/Card"; import CardHeader from "@mui/material/CardHeader"; import CardContent from "@mui/material/CardContent"; import CardActions from "@mui/material/CardActions"; import Avatar from "@mui/material/Avatar"; import Tooltip from "@mui/material/Tooltip"; import Zoom from "@mui/material/Zoom"; import IconButton from "@mui/material/IconButton"; import Box from "@mui/material/Box"; import InputLabel from "@mui/material/InputLabel"; import MenuItem from "@mui/material/MenuItem"; import FormControl from "@mui/material/FormControl"; import Select from "@mui/material/Select"; import TextField from "@mui/material/TextField"; import Info from "@material-ui/icons/Info"; import CancelIcon from "@material-ui/icons/Cancel"; import CheckCircleIcon from "@material-ui/icons/CheckCircle"; import ErrorIcon from "@material-ui/icons/Error"; import RemoveCircleIcon from "@material-ui/icons/RemoveCircle"; import useTickets from "../../hooks/useTickets"; import { AuthContext } from "../../context/Auth/AuthContext"; import { i18n } from "../../translate/i18n"; import Chart from "./Chart"; import openSocket from "socket.io-client"; import api from "../../services/api"; import { Can } from "../../components/Can"; import { Button } from "@material-ui/core"; import { id } from "date-fns/locale"; 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: 240, }, 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%", }, cardPaperFix: { textTransform: "capitalize", padding: theme.spacing(2), paddingBottom: theme.spacing(4), height: "500px", overflowY: "scroll", }, cardStyleFix: { display: "flex", flexDirection: "row", justifyContent: "left", alignItems: "center", gap: "32px", }, logginBtn: { position: "absolute", bottom: "21px", right: "21px", fontSize: "12px", }, })); 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; 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; } } } return [...state]; } if (action.type === "RESET") { return []; } }; const Dashboard = () => { const classes = useStyles(); const [usersOnlineInfo, dispatch] = useReducer(reducer, []); const [search, setSearch] = useState(""); const [filterStatus, setFilterStatus] = useState(null); const { user } = useContext(AuthContext); var userQueueIds = []; if (user.queues && user.queues.length > 0) { userQueueIds = user.queues.map((q) => q.id); } const GetTickets = (status, showAll, withUnreadMessages, unlimited) => { const { tickets } = useTickets({ status: status, showAll: showAll, withUnreadMessages: withUnreadMessages, queueIds: JSON.stringify(userQueueIds), unlimited: unlimited, }); return tickets.length; }; 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 dataQuery = await api.get("/reports/user/services", { params: { userId: null, startDate: dateToday, endDate: dateToday }, }); dispatch({ type: "RESET" }); dispatch({ type: "LOAD_QUERY", payload: dataQuery.data }); //console.log() } catch (err) { console.log(err); } }; fetchQueries(); }, 500); return () => clearTimeout(delayDebounceFn); }, []); useEffect(() => { const socket = openSocket(process.env.REACT_APP_BACKEND_URL); 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") { // console.log(' entrou no delete user: ', data) dispatch({ type: "DELETE_USER", payload: +data.userId }); } }); return () => { socket.disconnect(); }; }, []); const handleFilterChange = (event) => { setFilterStatus(event.target.value); }; const handlesearch = (event) => { setSearch(event.target.value.toLowerCase()); }; return ( <Can role={user.profile} perform="dashboard-view:show" yes={() => ( <div> <Container maxWidth="lg" className={classes.container}> <Grid container spacing={3}> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> {i18n.t("dashboard.messages.inAttendance.title")} </Typography> <Grid item> <Typography component="h1" variant="h4"> {GetTickets("open", "true", "false", "true")} </Typography> </Grid> </Paper> </Grid> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> {i18n.t("dashboard.messages.waiting.title")} </Typography> <Grid item> <Typography component="h1" variant="h4"> {GetTickets("pending", "true", "false", "true")} </Typography> </Grid> </Paper> </Grid> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> {i18n.t("dashboard.messages.closed.title")} </Typography> <Grid item> <Typography component="h1" variant="h4"> {GetTickets("closed", "true", "false", "true")} </Typography> </Grid> </Paper> </Grid> </Grid> </Container> <Container maxWidth="lg" className={classes.container}> <Grid container spacing={3}> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> Total de Agentes </Typography> <Grid item> <Typography component="h1" variant="h4"> {usersOnlineInfo.length} </Typography> </Grid> </Paper> </Grid> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> Online </Typography> <Grid item> <Typography component="h1" variant="h4"> { usersOnlineInfo.filter( (status) => status.statusOnline && status.statusOnline.status === "online" ).length } </Typography> </Grid> </Paper> </Grid> <Grid item xs={12} sm={6} md={6} lg={4}> <Paper className={classes.customFixedHeightPaper} style={{ overflow: "hidden" }}> <Typography component="h3" variant="h6" color="primary" paragraph> Offline </Typography> <Grid item> <Typography component="h1" variant="h4"> { usersOnlineInfo.filter( (status) => status.statusOnline || status.statusOnline.status === "offline" ).length } </Typography> </Grid> </Paper> </Grid> </Grid> </Container> <Container maxWidth="lg" className={classes.container}> <Paper className={classes.cardPaperFix}> <Grid container sx={12} justifyContent="space-between"> <Grid item sx={4}> <Typography component="h3" variant="h6" color="primary" style={{ marginBottom: "16px" }} > Usuários <Tooltip title={`Os dados informados abaixo é baseado na data: ${new Date().toLocaleDateString()}`} color="primary" TransitionComponent={Zoom} > <IconButton> <Info /> </IconButton> </Tooltip> </Typography> </Grid> <Grid item sx={8} width="100%"> <Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}> <TextField id="outlined-basic" label="Usuário" variant="standard" value={search} onChange={handlesearch} /> <FormControl fullWidth variant="standard"> <InputLabel id="status">Status</InputLabel> <Select labelId="status" id="status" value={filterStatus} label="Status" onChange={handleFilterChange} > <MenuItem value={null}>Todos</MenuItem> <MenuItem value={"online"}>Online</MenuItem> <MenuItem value={"offline"}>Offline</MenuItem> <MenuItem value={"not"}>Não entrou</MenuItem> </Select> </FormControl> </Box> </Grid> </Grid> <Grid container spacing={3}> {usersOnlineInfo && usersOnlineInfo .filter((e) => { if (filterStatus === null) return e; if (filterStatus === "not") return !e.statusOnline; return e.statusOnline && e.statusOnline.status === filterStatus; }) .filter((e) => { return e.name.toLowerCase().includes(search); }) .map((user, index) => ( <Grid item xs={12} sm={6} md={6} lg={3} key={index} style={{ position: "relative" }} > <Card variant="outlined"> <CardHeader avatar={ <Avatar style={{ backgroundColor: user.statusOnline ? user.statusOnline.status === "online" ? "green" : user.statusOnline.status === "offline" ? "red" : "black" : "grey", }} > {user.statusOnline ? ( user.statusOnline.status === "online" ? ( <CheckCircleIcon style={{ color: "white" }} /> ) : user.statusOnline.status === "offline" ? ( <CancelIcon style={{ color: "white" }} /> ) : ( <ErrorIcon style={{ color: "yellow" }} /> ) ) : ( <RemoveCircleIcon style={{ color: "black" }} /> )} </Avatar> } title={ <Typography variant="h5" component="div"> {user.name} </Typography> } /> <CardContent> <Typography variant="h6" component="h1" color="textPrimary"> Em atendimento: <Typography component="p" color="textPrimary" paragraph> {user.sumOpen && user.sumOpen.count ? user.sumOpen.count : 0} </Typography> </Typography> <Typography variant="h6" component="h1" color="textPrimary"> Finalizado: <Typography component="p" color="textPrimary" paragraph> {user.sumClosed && user.sumClosed.count ? user.sumClosed.count : 0} </Typography> </Typography> <Typography variant="h6" component="h1" color="textPrimary"> Tempo online: <Typography component="p" color="textPrimary" paragraph> {user.sumOnlineTime && user.sumOnlineTime.sum ? user.sumOnlineTime.sum : "Não entrou Hoje"} </Typography> </Typography> </CardContent> <CardActions> {user.statusOnline && user.statusOnline.status === "online" && user.statusOnline && ( <Button className={classes.logginBtn} variant="contained" color="primary" onClick={(e) => { handleLogouOnlineUser(user.id); }} > {"Deslogar"} </Button> )} </CardActions> </Card> </Grid> ))} </Grid> </Paper> </Container> <Container maxWidth="lg" className={classes.container}> <Grid container className={classes.cardStyleFix}> <Grid item xs={12}> <Paper className={classes.fixedHeightPaper}> <Chart /> </Paper> </Grid> </Grid> </Container> </div> )} /> /**/ ); }; export default Dashboard;