import React, { useState, useEffect } from "react";
import { useHistory, useParams } from "react-router-dom";
import openSocket from "socket.io-client";
import { parseISO, format } from "date-fns";
import { makeStyles } from "@material-ui/core/styles";
import { green } from "@material-ui/core/colors";
import Paper from "@material-ui/core/Paper";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
import Typography from "@material-ui/core/Typography";
import Avatar from "@material-ui/core/Avatar";
import Divider from "@material-ui/core/Divider";
import Badge from "@material-ui/core/Badge";
import SearchIcon from "@material-ui/icons/Search";
import InputBase from "@material-ui/core/InputBase";
import Button from "@material-ui/core/Button";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
import IconButton from "@material-ui/core/IconButton";
import AddIcon from "@material-ui/icons/Add";
import TicketsSkeleton from "../TicketsSkeleton";
import NewTicketModal from "../NewTicketModal";
import api from "../../services/api";
const useStyles = makeStyles(theme => ({
contactsWrapper: {
position: "relative",
display: "flex",
height: "100%",
flexDirection: "column",
overflow: "hidden",
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
},
tabsHeader: {
// display: "flex",
flex: "none",
backgroundColor: "#eee",
},
settingsIcon: {
alignSelf: "center",
marginLeft: "auto",
padding: 8,
},
openTicketsList: {
height: "50%",
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
backgroundColor: "#e8e8e8",
},
borderTop: "1px solid rgba(0, 0, 0, 0.12)",
},
closedTicketsList: {
flex: 1,
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
backgroundColor: "#e8e8e8",
},
borderTop: "2px solid rgba(0, 0, 0, 0.12)",
},
ticketsListHeader: {
display: "flex",
// flexShrink: 0,
// -webkitBoxAlign: "center",
alignItems: "center",
fontWeight: 500,
fontSize: "16px",
height: "56px",
// backgroundColor: "#eee",
color: "rgb(67, 83, 105)",
padding: "0px 12px",
borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
},
ticketsCount: {
fontWeight: "normal",
color: "rgb(104, 121, 146)",
marginLeft: "8px",
fontSize: "14px",
},
newTicketBtn: {
marginLeft: "auto",
},
ticket: {
position: "relative",
"& .hidden-button": {
display: "none",
},
"&:hover .hidden-button": {
display: "flex",
position: "absolute",
left: "50%",
},
},
noTicketsDiv: {
display: "flex",
height: "100px",
margin: 40,
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
},
noTicketsText: {
textAlign: "center",
color: "rgb(104, 121, 146)",
fontSize: "14px",
lineHeight: "1.4",
},
noTicketsTitle: {
textAlign: "center",
fontSize: "16px",
fontWeight: "600",
margin: "0px",
},
contactsSearchBox: {
position: "relative",
background: "#fafafa",
padding: "10px 13px",
},
serachInputWrapper: {
background: "#fff",
display: "flex",
borderRadius: 40,
padding: 4,
},
searchIcon: {
color: "grey",
marginLeft: 6,
marginRight: 6,
alignSelf: "center",
},
contactsSearchInput: {
flex: 1,
border: "none",
borderRadius: 30,
},
contactNameWrapper: {
display: "flex",
// display: "inline",
},
lastMessageTime: {
marginLeft: "auto",
},
contactLastMessage: {
paddingRight: 20,
},
newMessagesCount: {
alignSelf: "center",
marginRight: 8,
marginLeft: "auto",
},
badgeStyle: {
color: "white",
backgroundColor: green[500],
},
circleLoading: {
color: green[500],
opacity: "70%",
position: "absolute",
top: "50%",
left: "50%",
marginTop: 12,
// marginLeft: -12,
},
}));
const TicketsList = () => {
const classes = useStyles();
const history = useHistory();
const token = localStorage.getItem("token");
const userId = +localStorage.getItem("userId");
const { ticketId } = useParams();
const [tickets, setTickets] = useState([]);
const [loading, setLoading] = useState();
const [searchParam, setSearchParam] = useState("");
const [tab, setTab] = useState("open");
const [newTicketModalOpen, setNewTicketModalOpen] = useState(true);
useEffect(() => {
if (!("Notification" in window)) {
console.log("This browser doesn't support notifications");
} else {
Notification.requestPermission();
}
}, []);
useEffect(() => {
setLoading(true);
const delayDebounceFn = setTimeout(() => {
const fetchContacts = async () => {
try {
const res = await api.get("/tickets", {
params: { searchParam, status: tab },
});
setTickets(res.data);
setLoading(false);
} catch (err) {
console.log(err);
}
};
fetchContacts();
}, 1000);
return () => clearTimeout(delayDebounceFn);
}, [searchParam, token, tab]);
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
socket.emit("joinNotification");
socket.on("ticket", data => {
if (data.action === "updateUnread") {
resetUnreadMessages(data.ticketId);
}
if (data.action === "updateStatus") {
updateTicketStatus(data);
}
});
socket.on("appMessage", data => {
console.log(data);
if (data.action === "create") {
updateUnreadMessagesCount(data);
if (
(ticketId &&
data.message.ticketId === +ticketId &&
document.visibilityState === "visible") ||
(data.ticket.userId !== userId && data.ticket.userId)
)
return;
showDesktopNotification(data);
}
});
return () => {
socket.disconnect();
};
}, [ticketId, userId]);
const updateUnreadMessagesCount = data => {
setTickets(prevState => {
const ticketIndex = prevState.findIndex(
ticket => ticket.id === data.message.ticketId
);
if (ticketIndex !== -1) {
let aux = [...prevState];
aux[ticketIndex].unreadMessages++;
aux[ticketIndex].lastMessage = data.message.body;
aux.unshift(aux.splice(ticketIndex, 1)[0]);
return aux;
} else {
return [data.ticket, ...prevState];
}
});
};
const updateTicketStatus = data => {
setTickets(prevState => {
const ticketIndex = prevState.findIndex(
ticket => ticket.id === data.ticket.id
);
if (ticketIndex === -1) {
return [data.ticket, ...prevState];
} else {
let aux = [...prevState];
aux[ticketIndex] = data.ticket;
return aux;
}
});
};
const showDesktopNotification = data => {
const options = {
body: `${data.message.body} - ${format(new Date(), "HH:mm")}`,
icon: data.contact.profilePicUrl,
};
new Notification(`Mensagem de ${data.contact.name}`, options);
document.getElementById("sound").play();
};
const resetUnreadMessages = ticketId => {
setTickets(prevState => {
const ticketIndex = prevState.findIndex(
ticket => ticket.id === +ticketId
);
if (ticketIndex !== -1) {
let aux = [...prevState];
aux[ticketIndex].unreadMessages = 0;
return aux;
} else {
return prevState;
}
});
};
const handleSelectTicket = (e, ticket) => {
history.push(`/chat/${ticket.id}`);
};
const handleSearchContact = e => {
// let searchTerm = e.target.value.toLowerCase();
setSearchParam(e.target.value.toLowerCase());
};
const handleChangeTab = (event, newValue) => {
setTab(newValue);
};
const handleAcepptTicket = async ticketId => {
try {
await api.put(`/tickets/${ticketId}`, {
status: "open",
userId: userId,
});
} catch (err) {
alert(err);
}
history.push(`/chat/${ticketId}`);
};
const handleOpenNewTicketModal = () => {};
const countTickets = (status, userId) => {
const ticketsFound = tickets.filter(
t => t.status === status && t.userId === userId
).length;
if (ticketsFound === 0) return "";
return ticketsFound;
};
const renderTickets = (status, userId) => {
const viewTickets = tickets.map(ticket => {
if (
(ticket.status === status && ticket.userId === userId) ||
(ticket.status === "closed" && status === "closed")
)
return (
}
{status === "pending" ? "Nenhum ticket pendente por enquanto. Hora do café!" : "Aceite um ticket da fila para começar."}