From b5975993bebe0fe2f4f658df52ac4a916adb032b Mon Sep 17 00:00:00 2001 From: RenatoDiGiacomo Date: Mon, 25 Jul 2022 09:59:34 -0300 Subject: [PATCH] Left painel in construction , WIP --- frontend/src/components/MessagesList/index.js | 5 - frontend/src/components/Ticket/index.js | 68 +-- .../components/TicketActionButtons/index.js | 272 +++++----- .../TicketListItem/TicketListItem.jsx | 37 ++ .../src/components/TicketListItem/index.js | 10 +- .../components/TicketsList/TicketsList.jsx | 225 ++++++++ frontend/src/components/TicketsList/index.js | 504 +++++++++--------- .../TicketsManager/TicketsManager.jsx | 343 ++---------- .../TicketsManager/TicketsManager.style.jsx | 7 + frontend/src/pages/Tickets/Tickets.style.jsx | 3 +- 10 files changed, 707 insertions(+), 767 deletions(-) create mode 100644 frontend/src/components/TicketListItem/TicketListItem.jsx create mode 100644 frontend/src/components/TicketsList/TicketsList.jsx create mode 100644 frontend/src/components/TicketsManager/TicketsManager.style.jsx diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index 0344c7b..3eedb23 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -541,11 +541,6 @@ const MessagesList = ({ ticketId, isGroup }) => { })} >
- {!message.quotedMsg?.fromMe && ( - - {message.quotedMsg?.contact?.name} - - )} {message.quotedMsg?.body}
diff --git a/frontend/src/components/Ticket/index.js b/frontend/src/components/Ticket/index.js index 004803c..f569d73 100644 --- a/frontend/src/components/Ticket/index.js +++ b/frontend/src/components/Ticket/index.js @@ -19,64 +19,11 @@ import toastError from "../../errors/toastError"; const drawerWidth = 320; -const useStyles = makeStyles((theme) => ({ - root: { - display: "flex", - height: "100%", - position: "relative", - overflow: "hidden", - }, - - ticketInfo: { - maxWidth: "50%", - flexBasis: "50%", - [theme.breakpoints.down("sm")]: { - maxWidth: "80%", - flexBasis: "80%", - }, - }, - ticketActionButtons: { - maxWidth: "50%", - flexBasis: "50%", - display: "flex", - [theme.breakpoints.down("sm")]: { - maxWidth: "100%", - flexBasis: "100%", - marginBottom: "5px", - }, - }, - - mainWrapper: { - flex: 1, - height: "100%", - display: "flex", - flexDirection: "column", - overflow: "hidden", - borderTopLeftRadius: 0, - borderBottomLeftRadius: 0, - borderLeft: "0", - marginRight: -drawerWidth, - transition: theme.transitions.create("margin", { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen, - }), - }, - - mainWrapperShift: { - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - transition: theme.transitions.create("margin", { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen, - }), - marginRight: 0, - }, -})); const Ticket = () => { const { ticketId } = useParams(); const history = useHistory(); - const classes = useStyles(); + const [drawerOpen, setDrawerOpen] = useState(false); const [loading, setLoading] = useState(true); @@ -93,9 +40,6 @@ const Ticket = () => { const { data } = await api.get("/tickets/" + ticketId); - // setContact(data.contact); - // setTicket(data); - setContact(data.contact.contact); setTicket(data.contact); @@ -153,23 +97,21 @@ const Ticket = () => { }; return ( -
+
-
+
-
+
diff --git a/frontend/src/components/TicketActionButtons/index.js b/frontend/src/components/TicketActionButtons/index.js index 3919503..58feff5 100644 --- a/frontend/src/components/TicketActionButtons/index.js +++ b/frontend/src/components/TicketActionButtons/index.js @@ -12,167 +12,147 @@ import ButtonWithSpinner from "../ButtonWithSpinner"; import toastError from "../../errors/toastError"; import { AuthContext } from "../../context/Auth/AuthContext"; -import Modal from "../ChatEnd/ModalChatEnd"; -import { render } from '@testing-library/react'; +import Modal from "../ChatEnd/ModalChatEnd"; +import { render } from "@testing-library/react"; -const useStyles = makeStyles(theme => ({ - actionButtons: { - marginRight: 6, - flex: "none", - alignSelf: "center", - marginLeft: "auto", - "& > *": { - margin: theme.spacing(1), - }, - }, +const useStyles = makeStyles((theme) => ({ + actionButtons: { + marginRight: 6, + flex: "none", + alignSelf: "center", + marginLeft: "auto", + "& > *": { + margin: theme.spacing(1), + }, + }, })); const TicketActionButtons = ({ ticket, statusChatEnd }) => { - const classes = useStyles(); - const history = useHistory(); - const [anchorEl, setAnchorEl] = useState(null); - const [loading, setLoading] = useState(false); - const ticketOptionsMenuOpen = Boolean(anchorEl); - const { user } = useContext(AuthContext); - - const handleOpenTicketOptionsMenu = e => { - setAnchorEl(e.currentTarget); - }; + const classes = useStyles(); + const history = useHistory(); + const [anchorEl, setAnchorEl] = useState(null); + const [loading, setLoading] = useState(false); + const ticketOptionsMenuOpen = Boolean(anchorEl); + const { user } = useContext(AuthContext); - const handleCloseTicketOptionsMenu = e => { - setAnchorEl(null); - }; + const handleOpenTicketOptionsMenu = (e) => { + setAnchorEl(e.currentTarget); + }; - - const chatEndVal = (data) => { - - if(data){ + const handleCloseTicketOptionsMenu = (e) => { + setAnchorEl(null); + }; - data = {...data, 'ticketId': ticket.id} - - console.log('ChatEnd: ',(data)); + const chatEndVal = (data) => { + if (data) { + data = { ...data, ticketId: ticket.id }; - handleUpdateTicketStatus(null, "closed", user?.id, data) + console.log("ChatEnd: ", data); - } - - } + handleUpdateTicketStatus(null, "closed", user?.id, data); + } + }; + const handleModal = (/*status, userId*/) => { + render( + + ); + }; - const handleModal = (/*status, userId*/) => { + const handleUpdateTicketStatus = async (e, status, userId, schedulingData = {}) => { + setLoading(true); + try { + if (status === "closed") { + await api.put(`/tickets/${ticket.id}`, { + status: status, + userId: userId || null, + schedulingNotifyData: JSON.stringify(schedulingData), + }); + } else { + await api.put(`/tickets/${ticket.id}`, { + status: status, + userId: userId || null, + }); + } - render() - - }; - + setLoading(false); + if (status === "open") { + history.push(`/tickets/${ticket.id}`); + } else { + history.push("/tickets"); + } + } catch (err) { + setLoading(false); + toastError(err); + } + }; - const handleUpdateTicketStatus = async (e, status, userId, schedulingData={}) => { - - setLoading(true); - try { - - if(status==='closed'){ + return ( +
+ {ticket.status === "closed" && ( + } + size="small" + onClick={(e) => handleUpdateTicketStatus(e, "open", user?.id)} + > + {i18n.t("messagesList.header.buttons.reopen")} + + )} + {ticket.status === "open" && ( + <> + } + size="small" + onClick={(e) => handleUpdateTicketStatus(e, "pending", null)} + > + {i18n.t("messagesList.header.buttons.return")} + - await api.put(`/tickets/${ticket.id}`, { - status: status, - userId: userId || null, - schedulingNotifyData: JSON.stringify(schedulingData) - }); + { + handleModal(); + // handleUpdateTicketStatus(e, "closed", user?.id) + }} + > + {i18n.t("messagesList.header.buttons.resolve")} + - } - else{ - - await api.put(`/tickets/${ticket.id}`, { - status: status, - userId: userId || null - }); - - } - - setLoading(false); - if (status === "open") { - history.push(`/tickets/${ticket.id}`); - } else { - history.push("/tickets"); - } - } catch (err) { - setLoading(false); - toastError(err); - } - - - - - }; - - return ( -
- {ticket.status === "closed" && ( - } - size="small" - onClick={e => handleUpdateTicketStatus(e, "open", user?.id)} - > - {i18n.t("messagesList.header.buttons.reopen")} - - )} - {ticket.status === "open" && ( - <> - } - size="small" - onClick={e => handleUpdateTicketStatus(e, "pending", null)} - > - {i18n.t("messagesList.header.buttons.return")} - - - { - - - handleModal() - // handleUpdateTicketStatus(e, "closed", user?.id) - - }} - > - {i18n.t("messagesList.header.buttons.resolve")} - - - - - - - - )} - {ticket.status === "pending" && ( - handleUpdateTicketStatus(e, "open", user?.id)} - > - {i18n.t("messagesList.header.buttons.accept")} - - )} -
- ); + + + + + + )} + {ticket.status === "pending" && ( + handleUpdateTicketStatus(e, "open", user?.id)} + > + {i18n.t("messagesList.header.buttons.accept")} + + )} +
+ ); }; export default TicketActionButtons; + diff --git a/frontend/src/components/TicketListItem/TicketListItem.jsx b/frontend/src/components/TicketListItem/TicketListItem.jsx new file mode 100644 index 0000000..9673a1f --- /dev/null +++ b/frontend/src/components/TicketListItem/TicketListItem.jsx @@ -0,0 +1,37 @@ +import React from "react"; + +import { useHistory, useParams } from "react-router-dom"; +import { parseISO, format, isSameDay } from "date-fns"; + +import { i18n } from "../../translate/i18n"; + +import api from "../../services/api"; +import ButtonWithSpinner from "../ButtonWithSpinner"; +import MarkdownWrapper from "../MarkdownWrapper"; +import { Tooltip } from "@material-ui/core"; +import { AuthContext } from "../../context/Auth/AuthContext"; +import toastError from "../../errors/toastError"; + +const TicketListItem = ({ ticket, status }) => { + const history = useHistory(); + const { ticketId } = useParams(); + const isMounted = React.useRef(true); + const { user } = React.useContext(AuthContext); + + const handleSelectTicket = (id) => { + history.push(`/tickets/${id}`); + }; + console.log(ticket.id); + + if (ticket.status !== status) return null; + return ( + +

{ticket.id}

+ {ticket.id} +

{ticket.lastMessage}

+
+ ); +}; + +export default TicketListItem; + diff --git a/frontend/src/components/TicketListItem/index.js b/frontend/src/components/TicketListItem/index.js index f7460bf..5cc3008 100644 --- a/frontend/src/components/TicketListItem/index.js +++ b/frontend/src/components/TicketListItem/index.js @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef, useContext } from "react"; -import { useHistory, useParams } from "react-router-dom"; +import ReactDOM, { useHistory, useParams } from "react-router-dom"; import { parseISO, format, isSameDay } from "date-fns"; import clsx from "clsx"; @@ -102,10 +102,10 @@ const useStyles = makeStyles(theme => ({ })); const TicketListItem = ({ ticket }) => { - const classes = useStyles(); - const history = useHistory(); + const classes = ReactDOM.useStyles(); + const history = ReactDOM.useHistory(); const [loading, setLoading] = useState(false); - const { ticketId } = useParams(); + const { ticketId } = ReactDOM.useParams(); const isMounted = useRef(true); const { user } = useContext(AuthContext); @@ -145,7 +145,7 @@ const TicketListItem = ({ ticket }) => { if (ticket.status === "pending") return; handleSelectTicket(ticket.id); }} - selected={ticketId && +ticketId === ticket.id} + selected={ticketId && +ticketId === ticket.id} ///img src{id}.jpg className={clsx(classes.ticket, { [classes.pendingTicket]: ticket.status === "pending", })} diff --git a/frontend/src/components/TicketsList/TicketsList.jsx b/frontend/src/components/TicketsList/TicketsList.jsx new file mode 100644 index 0000000..31aede6 --- /dev/null +++ b/frontend/src/components/TicketsList/TicketsList.jsx @@ -0,0 +1,225 @@ +import React, { useReducer } from "react"; +import openSocket from "socket.io-client"; + +import useTickets from "../../hooks/useTickets"; +import TicketListItem from "../TicketListItem/TicketListItem"; +import TicketsListSkeleton from "../TicketsListSkeleton"; + +import { i18n } from "../../translate/i18n"; +import { AuthContext } from "../../context/Auth/AuthContext"; + +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 message = action.payload.message; + + const ticket = action.payload.ticket; + + const ticketIndex = state.findIndex((t) => t.id === ticket.id); + + if (ticketIndex !== -1) { + if (!message.fromMe) { + ticket.unreadMessages += 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 = ({ status, searchParam, showAll, selectedQueueIds, updateCount }) => { + const [pageNumber, setPageNumber] = React.useState(1); + const { user } = React.useContext(AuthContext); + const [ticketsList, dispatch] = useReducer(reducer, []); + + const { tickets, hasMore, loading } = useTickets({ + pageNumber, + searchParam, + status, + showAll, + queueIds: JSON.stringify(selectedQueueIds), + }); + + React.useEffect(() => { + dispatch({ type: "RESET" }); + setPageNumber(1); + }, [status, searchParam, dispatch, showAll, selectedQueueIds]); + + React.useEffect(() => { + if (!status && !searchParam) return; + dispatch({ + type: "LOAD_TICKETS", + payload: tickets, + }); + }, [tickets, status, searchParam]); + + React.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, + payload: data, + }); + } + }); + + socket.on("contact", (data) => { + if (data.action === "update") { + dispatch({ + type: "UPDATE_TICKET_CONTACT", + payload: data.contact, + }); + } + }); + + return () => { + socket.disconnect(); + }; + }, [status, showAll, user, selectedQueueIds]); + + 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; + diff --git a/frontend/src/components/TicketsList/index.js b/frontend/src/components/TicketsList/index.js index 604d603..1fb3263 100644 --- a/frontend/src/components/TicketsList/index.js +++ b/frontend/src/components/TicketsList/index.js @@ -12,294 +12,320 @@ 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, - }, +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)", - }, + 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", - }, + 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", - }, + 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", - }, + noTicketsText: { + textAlign: "center", + color: "rgb(104, 121, 146)", + fontSize: "14px", + lineHeight: "1.4", + }, - noTicketsTitle: { - textAlign: "center", - fontSize: "16px", - fontWeight: "600", - margin: "0px", - }, + noTicketsTitle: { + textAlign: "center", + fontSize: "16px", + fontWeight: "600", + margin: "0px", + }, - noTicketsDiv: { - display: "flex", - height: "100px", - margin: 40, - flexDirection: "column", - alignItems: "center", - justifyContent: "center", - }, + 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; + if (action.type === "LOAD_TICKETS") { + const newTickets = action.payload; + + + newTickets.forEach(ticket => { - 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); - } - }); + // console.log('* ticket.unreadMessages: ',ticket.unreadMessages) - return [...state]; - } + 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); + } + }); - if (action.type === "RESET_UNREAD") { - const ticketId = action.payload; + return [...state]; + } - const ticketIndex = state.findIndex((t) => t.id === ticketId); - if (ticketIndex !== -1) { - state[ticketIndex].unreadMessages = 0; - } + if (action.type === "RESET_UNREAD") { + const ticketId = action.payload; - return [...state]; - } + const ticketIndex = state.findIndex(t => t.id === ticketId); + if (ticketIndex !== -1) { + state[ticketIndex].unreadMessages = 0; + } - if (action.type === "UPDATE_TICKET") { - const ticket = action.payload; + return [...state]; + } - const ticketIndex = state.findIndex((t) => t.id === ticket.id); - if (ticketIndex !== -1) { - state[ticketIndex] = ticket; - } else { - state.unshift(ticket); - } + if (action.type === "UPDATE_TICKET") { + const ticket = action.payload; - return [...state]; - } + // console.log('++++++++++++ UPDATE_TICKET: ',ticket) - if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") { - const message = action.payload.message; + const ticketIndex = state.findIndex(t => t.id === ticket.id); + if (ticketIndex !== -1) { + state[ticketIndex] = ticket; + } else { + state.unshift(ticket); + } - const ticket = action.payload.ticket; + return [...state]; + } - const ticketIndex = state.findIndex((t) => t.id === ticket.id); + if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") { - if (ticketIndex !== -1) { - if (!message.fromMe) { - ticket.unreadMessages += 1; - } + const message = action.payload.message - state[ticketIndex] = ticket; - state.unshift(state.splice(ticketIndex, 1)[0]); - } else { - state.unshift(ticket); - } + const ticket = action.payload.ticket; - return [...state]; - } + const ticketIndex = state.findIndex(t => t.id === ticket.id); - 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 (ticketIndex !== -1) { + + // console.log('>>>>>> ticketIndex: ', ticketIndex) - if (action.type === "DELETE_TICKET") { - const ticketId = action.payload; - const ticketIndex = state.findIndex((t) => t.id === ticketId); - if (ticketIndex !== -1) { - state.splice(ticketIndex, 1); - } + // console.log('&&&&&&& UPDATE_TICKET_UNREAD_MESSAGES ticket: ',ticket, ' |\n MESSAGE: ', message) + + if(!message.fromMe){ + ticket.unreadMessages +=1 + } - return [...state]; - } + state[ticketIndex] = ticket; + state.unshift(state.splice(ticketIndex, 1)[0]); + + } else { + state.unshift(ticket); + } - if (action.type === "RESET") { - return []; - } + 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 = ({ status, searchParam, showAll, selectedQueueIds, updateCount, style }) => { - const classes = useStyles(); - const [pageNumber, setPageNumber] = useState(1); - const [ticketsList, dispatch] = useReducer(reducer, []); - const { user } = useContext(AuthContext); +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]); + useEffect(() => { + dispatch({ type: "RESET" }); + setPageNumber(1); + }, [status, searchParam, dispatch, showAll, selectedQueueIds]); - const { tickets, hasMore, loading } = useTickets({ - pageNumber, - searchParam, - status, - showAll, - queueIds: JSON.stringify(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(() => { + if (!status && !searchParam) return; + dispatch({ + type: "LOAD_TICKETS", + payload: tickets, + }); + }, [tickets, status, searchParam]); - useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL); + 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 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; + 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("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, - }); - } + socket.on("ticket", data => { + if (data.action === "updateUnread") { + dispatch({ + type: "RESET_UNREAD", + payload: data.ticketId, + }); + } - if (data.action === "update" && notBelongsToUserQueues(data.ticket)) { - dispatch({ type: "DELETE_TICKET", payload: data.ticket.id }); - } + if (data.action === "update" && shouldUpdateTicket(data.ticket)) { + dispatch({ + type: "UPDATE_TICKET", + payload: data.ticket, + }); + } - if (data.action === "delete") { - dispatch({ type: "DELETE_TICKET", payload: data.ticketId }); - } - }); + if (data.action === "update" && notBelongsToUserQueues(data.ticket)) { + dispatch({ type: "DELETE_TICKET", payload: data.ticket.id }); + } - socket.on("appMessage", (data) => { - if (data.action === "create" && shouldUpdateTicket(data.ticket)) { - dispatch({ - type: "UPDATE_TICKET_UNREAD_MESSAGES", - // payload: data.ticket, - payload: data, - }); - } - }); + if (data.action === "delete") { + dispatch({ type: "DELETE_TICKET", payload: data.ticketId }); + } + }); - socket.on("contact", (data) => { - if (data.action === "update") { - dispatch({ - type: "UPDATE_TICKET_CONTACT", - payload: data.contact, - }); - } - }); + socket.on("appMessage", data => { + if (data.action === "create" && shouldUpdateTicket(data.ticket)) { - return () => { - socket.disconnect(); - }; - }, [status, showAll, user, selectedQueueIds]); + // console.log('((((((((((((((((((( DATA.MESSAGE: ', data.message) - useEffect(() => { - if (typeof updateCount === "function") { - updateCount(ticketsList.length); - } - }, [ticketsList]); + dispatch({ + type: "UPDATE_TICKET_UNREAD_MESSAGES", + // payload: data.ticket, + payload: data, + }); + } + }); - const loadMore = () => { - setPageNumber((prevState) => prevState + 1); - }; + socket.on("contact", data => { + if (data.action === "update") { + dispatch({ + type: "UPDATE_TICKET_CONTACT", + payload: data.contact, + }); + } + }); - const handleScroll = (e) => { - if (!hasMore || loading) return; + return () => { + socket.disconnect(); + }; + }, [status, showAll, user, selectedQueueIds]); - const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; + useEffect(() => { - if (scrollHeight - (scrollTop + 100) < clientHeight) { - loadMore(); - } - }; - return ( - - - - {ticketsList.length === 0 && !loading ? ( -
- {i18n.t("ticketsList.noTicketsTitle")} -

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

-
- ) : ( - <> - {ticketsList.map((ticket) => ( - - ))} - - )} - {loading && } -
-
-
- ); + + 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; - diff --git a/frontend/src/components/TicketsManager/TicketsManager.jsx b/frontend/src/components/TicketsManager/TicketsManager.jsx index b1af5b8..29b74fb 100644 --- a/frontend/src/components/TicketsManager/TicketsManager.jsx +++ b/frontend/src/components/TicketsManager/TicketsManager.jsx @@ -1,337 +1,64 @@ -import React, { useContext, useEffect, useRef, useState } from "react"; -import openSocket from "socket.io-client" - -import { makeStyles } from "@material-ui/core/styles"; -import Paper from "@material-ui/core/Paper"; -import SearchIcon from "@material-ui/icons/Search"; -import InputBase from "@material-ui/core/InputBase"; -import Tabs from "@material-ui/core/Tabs"; -import Tab from "@material-ui/core/Tab"; -import Badge from "@material-ui/core/Badge"; -import MoveToInboxIcon from "@material-ui/icons/MoveToInbox"; -import CheckBoxIcon from "@material-ui/icons/CheckBox"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import Switch from "@material-ui/core/Switch"; -import { Button } from "@material-ui/core"; +import React from "react"; import NewTicketModal from "../NewTicketModal"; -import TicketsList from "../TicketsList"; -import TabPanel from "../TabPanel"; +import TicketsList from "../TicketsList/TicketsList"; import { i18n } from "../../translate/i18n"; import { AuthContext } from "../../context/Auth/AuthContext"; import { Can } from "../Can"; import TicketsQueueSelect from "../TicketsQueueSelect"; - -const useStyles = makeStyles((theme) => ({ - ticketsWrapper: { - position: "relative", - display: "flex", - height: "100%", - flexDirection: "column", - overflow: "hidden", - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - }, - - tabsHeader: { - flex: "none", - backgroundColor: "#eee", - }, - - settingsIcon: { - alignSelf: "center", - marginLeft: "auto", - padding: 8, - }, - - tab: { - minWidth: 120, - width: 120, - }, - - ticketOptionsBox: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", - background: "#fafafa", - padding: theme.spacing(1), - }, - - serachInputWrapper: { - flex: 1, - background: "#fff", - display: "flex", - borderRadius: 40, - padding: 4, - marginRight: theme.spacing(1), - }, - - searchIcon: { - color: "grey", - marginLeft: 6, - marginRight: 6, - alignSelf: "center", - }, - - searchInput: { - flex: 1, - border: "none", - borderRadius: 30, - }, - - badge: { - right: "-10px", - }, - show: { - display: "block", - }, - hide: { - display: "none !important", - }, -})); +import TicketsManagerStyled from "./TicketsManager.style"; const TicketsManager = () => { - const classes = useStyles(); + const [valueTab, setValueTab] = React.useState("open"); - // Old New State - const [newPage, setNewPage] = React.useState(true); - // Old New State + const [newTicketModalOpen, setNewTicketModalOpen] = React.useState(false); + const [showAllTickets, setShowAllTickets] = React.useState(false); + const { user } = React.useContext(AuthContext); - const [searchParam, setSearchParam] = useState(""); - const [tab, setTab] = useState("open"); - const [tabOpen, setTabOpen] = useState("open"); - const [newTicketModalOpen, setNewTicketModalOpen] = useState(false); - const [showAllTickets, setShowAllTickets] = useState(false); - const searchInputRef = useRef(); - const { user } = useContext(AuthContext); - - const [openCount, setOpenCount] = useState(0); - const [pendingCount, setPendingCount] = useState(0); const userQueueIds = user.queues.map((q) => q.id); - const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []); - const socket = openSocket.open(process.env.REACT_APP_BACKEND_URL) + const [selectedQueueIds, setSelectedQueueIds] = React.useState(userQueueIds || []); -console.log(user.queues) -console.log(selectedQueueIds) -socket.on("connect", () => { - if ("open") { - socket.emit("joinTickets", "open"); - } else { - socket.emit("joinNotification"); - } -}); - - -socket.on("connect", ()=>{ - -}) - - - useEffect(() => { + React.useEffect(() => { if (user.profile.toUpperCase() === "ADMIN") { setShowAllTickets(true); } }, [user.profile]); - useEffect(() => { - if (tab === "search") { - searchInputRef.current.focus(); - } - }, [tab]); - let searchTimeout; - const handleSearch = (e) => { - const searchedTerm = e.target.value.toLowerCase(); - - clearTimeout(searchTimeout); - - if (searchedTerm === "") { - setSearchParam(searchedTerm); - setTab("open"); - return; - } - - searchTimeout = setTimeout(() => { - setSearchParam(searchedTerm); - }, 500); - }; - - const handleChangeTab = (e, newValue) => { - setTab(newValue); - }; - - const handleChangeTabOpen = (e, newValue) => { - setTabOpen(newValue); - }; - - const applyPanelStyle = (status) => { - if (tabOpen !== status) { - return { width: 0, height: 0 }; - } - }; - - if (newPage) { - return ( - <> - setNewTicketModalOpen(false)} - /> -
- setSelectedQueueIds(values)} - /> - setOpenCount(val)} - style={applyPanelStyle("open")} - /> - setPendingCount(val)} - style={applyPanelStyle("pending")} - /> -
- - ); + const styleTmp = { + padding:"12px 0 ", + cursor: "pointer", } + + + console.log(valueTab); + return ( - + +
    +
  • setValueTab(e.target.id)}> + Abertos +
  • +
  • setValueTab(e.target.id)}> + Pendentes +
  • +
  • setValueTab(e.target.id)}> + Fechados +
  • +
+ setPendingCount(val)} + /> setNewTicketModalOpen(false)} + onClose={(e) => setNewTicketModalOpen(true)} /> - - - } - label={i18n.t("tickets.tabs.open.title")} - classes={{ root: classes.tab }} - /> - } - label={i18n.t("tickets.tabs.closed.title")} - classes={{ root: classes.tab }} - /> - } - label={i18n.t("tickets.tabs.search.title")} - classes={{ root: classes.tab }} - /> - - - - {tab === "search" ? ( -
- - -
- ) : ( - <> - - ( - setShowAllTickets((prevState) => !prevState)} - name="showAllTickets" - color="primary" - /> - } - /> - )} - /> - - )} - setSelectedQueueIds(values)} - /> -
- - - - {i18n.t("ticketsList.assignedHeader")} - - } - value={"open"} - /> - - {i18n.t("ticketsList.pendingHeader")} - - } - value={"pending"} - /> - - - setOpenCount(val)} - style={applyPanelStyle("open")} - /> - setPendingCount(val)} - style={applyPanelStyle("pending")} - /> - - - - - - - - -
+ ); }; diff --git a/frontend/src/components/TicketsManager/TicketsManager.style.jsx b/frontend/src/components/TicketsManager/TicketsManager.style.jsx new file mode 100644 index 0000000..1ed325f --- /dev/null +++ b/frontend/src/components/TicketsManager/TicketsManager.style.jsx @@ -0,0 +1,7 @@ +import styled from "styled-components" + +const TicketsManagerStyled = styled.div` + display:flex; + flex-direction: column; +` +export default TicketsManagerStyled \ No newline at end of file diff --git a/frontend/src/pages/Tickets/Tickets.style.jsx b/frontend/src/pages/Tickets/Tickets.style.jsx index c8c3ea7..b690fc6 100644 --- a/frontend/src/pages/Tickets/Tickets.style.jsx +++ b/frontend/src/pages/Tickets/Tickets.style.jsx @@ -3,7 +3,8 @@ import styled from "styled-components"; const TicketsStyled = styled.div` display: flex; flex-direction: row; - height: 86vh; + min-height: auto; + `; export default TicketsStyled \ No newline at end of file