import React, { useState, useEffect, useReducer, useContext } from "react"; import openSocket from "socket.io-client"; import { makeStyles } from "@material-ui/core/styles"; import List from "@material-ui/core/List"; import Paper from "@material-ui/core/Paper"; import TicketListItem from "../TicketListItem"; import TicketsListSkeleton from "../TicketsListSkeleton"; import useTickets from "../../hooks/useTickets"; import { i18n } from "../../translate/i18n"; import { AuthContext } from "../../context/Auth/AuthContext"; const useStyles = makeStyles(theme => ({ ticketsListWrapper: { position: "relative", display: "flex", height: "100%", flexDirection: "column", overflow: "hidden", borderTopRightRadius: 0, borderBottomRightRadius: 0, }, ticketsList: { flex: 1, overflowY: "scroll", ...theme.scrollbarStyles, borderTop: "2px solid rgba(0, 0, 0, 0.12)", }, ticketsListHeader: { color: "rgb(67, 83, 105)", zIndex: 2, backgroundColor: "white", borderBottom: "1px solid rgba(0, 0, 0, 0.12)", display: "flex", alignItems: "center", justifyContent: "space-between", }, ticketsCount: { fontWeight: "normal", color: "rgb(104, 121, 146)", marginLeft: "8px", fontSize: "14px", }, noTicketsText: { textAlign: "center", color: "rgb(104, 121, 146)", fontSize: "14px", lineHeight: "1.4", }, noTicketsTitle: { textAlign: "center", fontSize: "16px", fontWeight: "600", margin: "0px", }, noTicketsDiv: { display: "flex", height: "100px", margin: 40, flexDirection: "column", alignItems: "center", justifyContent: "center", }, })); const reducer = (state, action) => { if (action.type === "LOAD_TICKETS") { const newTickets = action.payload; newTickets.forEach(ticket => { const ticketIndex = state.findIndex(t => t.id === ticket.id); if (ticketIndex !== -1) { state[ticketIndex] = ticket; if (ticket.unreadMessages > 0) { state.unshift(state.splice(ticketIndex, 1)[0]); } } else { state.push(ticket); } }); return [...state]; } if (action.type === "RESET_UNREAD") { const ticketId = action.payload; const ticketIndex = state.findIndex(t => t.id === ticketId); if (ticketIndex !== -1) { state[ticketIndex].unreadMessages = 0; } return [...state]; } if (action.type === "UPDATE_TICKET") { const ticket = action.payload; const ticketIndex = state.findIndex(t => t.id === ticket.id); if (ticketIndex !== -1) { state[ticketIndex] = ticket; } else { state.unshift(ticket); } return [...state]; } if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") { const ticket = action.payload; const ticketIndex = state.findIndex(t => t.id === ticket.id); if (ticketIndex !== -1) { state[ticketIndex] = ticket; state.unshift(state.splice(ticketIndex, 1)[0]); } else { state.unshift(ticket); } return [...state]; } if (action.type === "UPDATE_TICKET_CONTACT") { const contact = action.payload; const ticketIndex = state.findIndex(t => t.contactId === contact.id); if (ticketIndex !== -1) { state[ticketIndex].contact = contact; } return [...state]; } if (action.type === "DELETE_TICKET") { const ticketId = action.payload; const ticketIndex = state.findIndex(t => t.id === ticketId); if (ticketIndex !== -1) { state.splice(ticketIndex, 1); } return [...state]; } if (action.type === "RESET") { return []; } }; const TicketsList = (props) => { const { status, searchParam, showAll, selectedQueueIds, updateCount, style } = props; const classes = useStyles(); const [pageNumber, setPageNumber] = useState(1); const [ticketsList, dispatch] = useReducer(reducer, []); const { user } = useContext(AuthContext); useEffect(() => { dispatch({ type: "RESET" }); setPageNumber(1); }, [status, searchParam, dispatch, showAll, selectedQueueIds]); const { tickets, hasMore, loading } = useTickets({ pageNumber, searchParam, status, showAll, queueIds: JSON.stringify(selectedQueueIds), }); useEffect(() => { if (!status && !searchParam) return; dispatch({ type: "LOAD_TICKETS", payload: tickets, }); }, [tickets, status, searchParam]); useEffect(() => { const socket = openSocket(process.env.REACT_APP_BACKEND_URL); const shouldUpdateTicket = ticket => (!ticket.userId || ticket.userId === user?.id || showAll) && (!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1); const notBelongsToUserQueues = ticket => ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1; socket.on("connect", () => { if (status) { socket.emit("joinTickets", status); } else { socket.emit("joinNotification"); } }); socket.on("ticket", data => { if (data.action === "updateUnread") { dispatch({ type: "RESET_UNREAD", payload: data.ticketId, }); } if (data.action === "update" && shouldUpdateTicket(data.ticket)) { dispatch({ type: "UPDATE_TICKET", payload: data.ticket, }); } if (data.action === "update" && notBelongsToUserQueues(data.ticket)) { dispatch({ type: "DELETE_TICKET", payload: data.ticket.id }); } if (data.action === "delete") { dispatch({ type: "DELETE_TICKET", payload: data.ticketId }); } }); socket.on("appMessage", data => { if (data.action === "create" && shouldUpdateTicket(data.ticket)) { dispatch({ type: "UPDATE_TICKET_UNREAD_MESSAGES", payload: data.ticket, }); } }); socket.on("contact", data => { if (data.action === "update") { dispatch({ type: "UPDATE_TICKET_CONTACT", payload: data.contact, }); } }); return () => { socket.disconnect(); }; }, [status, showAll, user, selectedQueueIds]); useEffect(() => { if (typeof updateCount === "function") { updateCount(ticketsList.length); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ticketsList]); const loadMore = () => { setPageNumber(prevState => prevState + 1); }; const handleScroll = e => { if (!hasMore || loading) return; const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; if (scrollHeight - (scrollTop + 100) < clientHeight) { loadMore(); } }; return ( {ticketsList.length === 0 && !loading ? (
{i18n.t("ticketsList.noTicketsTitle")}

{i18n.t("ticketsList.noTicketsMessage")}

) : ( <> {ticketsList.map(ticket => ( ))} )} {loading && }
); }; export default TicketsList;