feat: show pending messages in appbar

This commit is contained in:
canove
2020-08-25 12:24:19 -03:00
parent ea4ff654ff
commit 6e8eba1187
11 changed files with 255 additions and 469 deletions

View File

@@ -13,12 +13,14 @@ exports.index = async (req, res) => {
status = "",
date = "",
searchParam = "",
showAll,
} = req.query;
const userId = req.userId;
const limit = 20;
const offset = limit * (pageNumber - 1);
let whereCondition = {};
let includeCondition = [
{
model: Contact,
@@ -27,16 +29,20 @@ exports.index = async (req, res) => {
},
];
let whereCondition = { userId: userId };
if (showAll === "true") {
whereCondition = {};
}
if (status) {
whereCondition = {
...whereCondition,
status: status,
};
}
// else if (status === "closed") {
// whereCondition = { ...whereCondition, status: "closed" };
// }
else if (searchParam) {
if (searchParam) {
includeCondition = [
...includeCondition,
{
@@ -56,7 +62,6 @@ exports.index = async (req, res) => {
];
whereCondition = {
...whereCondition,
[Sequelize.Op.or]: [
{
"$contact.name$": Sequelize.where(

View File

@@ -15,7 +15,7 @@ module.exports = async (req, res, next) => {
if (error) {
return res.status(401).json({ error: "Invalid token" });
}
req.userId = token.userId;
req.userId = result.userId;
// todo >> find user in DB and store in req.user to use latter, or throw an error if user not exists anymore
next();
});

View File

@@ -56,6 +56,7 @@ const NotificationsPopOver = () => {
const ticketId = +history.location.pathname.split("/")[2];
const anchorEl = useRef();
const [isOpen, setIsOpen] = useState(false);
const [notifications, setNotifications] = useState([]);
useEffect(() => {
if (!("Notification" in window)) {
@@ -87,7 +88,27 @@ const NotificationsPopOver = () => {
};
}, [history, ticketId, userId]);
const { tickets } = useTickets({ status: "open" });
const { tickets: openTickets } = useTickets({ status: "open" });
const { tickets: pendingTickets } = useTickets({ status: "pending" });
useEffect(() => {
if (openTickets.length > 0 || pendingTickets.length > 0) {
let aux = [];
openTickets.forEach(ticket => {
if (ticket.unreadMessages > 0) {
aux.push(ticket);
}
});
pendingTickets.forEach(ticket => {
if (ticket.unreadMessages > 0) {
aux.push(ticket);
}
});
setNotifications(aux);
}
}, [openTickets, pendingTickets]);
const showDesktopNotification = ({ message, contact, ticket }) => {
const options = {
@@ -135,7 +156,7 @@ const NotificationsPopOver = () => {
aria-label="Open Notifications"
color="inherit"
>
<Badge badgeContent={tickets.length} color="secondary">
<Badge badgeContent={notifications.length} color="secondary">
<ChatIcon />
</Badge>
</IconButton>
@@ -155,14 +176,12 @@ const NotificationsPopOver = () => {
onClose={handleClickAway}
>
<List dense className={classes.tabContainer}>
{tickets.length === 0 ? (
{notifications.length === 0 ? (
<ListItem>
<ListItemText>
You haven&apos;t received any messages yet.
</ListItemText>
<ListItemText>No tickets with unread messages.</ListItemText>
</ListItem>
) : (
tickets.map(ticket => (
notifications.map(ticket => (
<TicketListItem
key={ticket.id}
ticket={ticket}

View File

@@ -86,7 +86,7 @@ const TicketListItem = ({
ticket,
handleAcepptTicket,
handleSelectTicket,
ticketId,
selectedTicketId,
}) => {
const classes = useStyles();
@@ -99,7 +99,7 @@ const TicketListItem = ({
if (ticket.status === "pending" && handleAcepptTicket) return;
handleSelectTicket(e, ticket);
}}
selected={ticketId && +ticketId === ticket.id}
selected={selectedTicketId && +selectedTicketId === ticket.id}
className={classes.ticket}
>
<ListItemAvatar>

View File

@@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { toast } from "react-toastify";
@@ -11,11 +12,13 @@ import ConfirmationModal from "../ConfirmationModal";
const TicketOptionsMenu = ({ ticket, menuOpen, handleClose, anchorEl }) => {
const [confirmationOpen, setConfirmationOpen] = useState(false);
const history = useHistory();
const handleDeleteTicket = async () => {
try {
await api.delete(`/tickets/${ticket.id}`);
toast.success("Ticket deletado com sucesso.");
history.push("/chat");
} catch (err) {
toast.error("Erro ao deletar o ticket");
}

View File

@@ -1,9 +1,8 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import { useHistory, useParams } from "react-router-dom";
import { makeStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import List from "@material-ui/core/List";
import SearchIcon from "@material-ui/icons/Search";
import InputBase from "@material-ui/core/InputBase";
import Tabs from "@material-ui/core/Tabs";
@@ -14,19 +13,13 @@ import IconButton from "@material-ui/core/IconButton";
import AddIcon from "@material-ui/icons/Add";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Switch from "@material-ui/core/Switch";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import TicketsSkeleton from "../TicketsSkeleton";
import NewTicketModal from "../NewTicketModal";
// import TicketsList from "../TicketsList";
import TicketListItem from "../TicketListItem";
import TicketsList from "../TicketsList";
import TabPanel from "../TabPanel";
import { i18n } from "../../translate/i18n";
import api from "../../services/api";
import useTickets from "../../hooks/useTickets";
const useStyles = makeStyles(theme => ({
ticketsWrapper: {
@@ -40,7 +33,6 @@ const useStyles = makeStyles(theme => ({
},
tabsHeader: {
// display: "flex",
flex: "none",
backgroundColor: "#eee",
},
@@ -56,87 +48,21 @@ const useStyles = makeStyles(theme => ({
width: 120,
},
halfTicketsList: {
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)",
},
fullHeightTicketsList: {
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",
alignItems: "center",
fontWeight: 500,
fontSize: "16px",
height: "56px",
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",
},
ticketsListActions: {
flex: "none",
marginLeft: "auto",
},
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: {
searchBox: {
position: "relative",
display: "flex",
alignItems: "center",
background: "#fafafa",
padding: "10px 13px",
},
serachInputWrapper: {
flex: 1,
background: "#fff",
display: "flex",
borderRadius: 40,
@@ -150,7 +76,7 @@ const useStyles = makeStyles(theme => ({
alignSelf: "center",
},
contactsSearchInput: {
searchInput: {
flex: 1,
border: "none",
borderRadius: 30,
@@ -167,46 +93,11 @@ const Tickets = () => {
const [tab, setTab] = useState("open");
const [newTicketModalOpen, setNewTicketModalOpen] = useState(false);
const [showAllTickets, setShowAllTickets] = useState(false);
const [pageNumber, setPageNumber] = useState(1);
const {
tickets: ticketsOpen,
hasMore: hasMoreOpen,
loading: loadingOpen,
dispatch: dispatchOpen,
} = useTickets({
pageNumber,
searchParam,
status: "open",
});
const {
tickets: ticketsPending,
hasMore: hasMorePending,
loading: loadingPending,
dispatch: dispatchPending,
} = useTickets({
pageNumber,
searchParam,
status: "pending",
});
useEffect(() => {
dispatchOpen({ type: "RESET" });
dispatchPending({ type: "RESET" });
setPageNumber(1);
}, [searchParam, tab, dispatchOpen, dispatchPending]);
const loadMore = () => {
setPageNumber(prevState => prevState + 1);
};
const handleSelectTicket = (e, ticket) => {
history.push(`/chat/${ticket.id}`);
};
// console.log(tickets);
const handleSearchContact = e => {
if (e.target.value === "") {
setSearchParam(e.target.value.toLowerCase());
@@ -217,15 +108,6 @@ const Tickets = () => {
setTab("search");
};
const handleScroll = e => {
if (!hasMoreOpen || loadingOpen) return;
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
if (scrollHeight - (scrollTop + 100) < clientHeight) {
loadMore();
}
};
const handleChangeTab = (e, newValue) => {
setTab(newValue);
};
@@ -242,17 +124,6 @@ const Tickets = () => {
history.push(`/chat/${ticketId}`);
};
// const countTickets = (status, userId) => {
// const ticketsFound = tickets.filter(
// t =>
// (t.status === status && t.userId === userId) ||
// (t.status === status && showAllTickets)
// ).length;
// if (ticketsFound === 0) return "";
// return ticketsFound;
// };
return (
<Paper elevation={0} variant="outlined" className={classes.ticketsWrapper}>
<NewTicketModal
@@ -288,151 +159,70 @@ const Tickets = () => {
/>
</Tabs>
</Paper>
<Paper square elevation={0} className={classes.contactsSearchBox}>
<Paper square elevation={0} className={classes.searchBox}>
<div className={classes.serachInputWrapper}>
<SearchIcon className={classes.searchIcon} />
<InputBase
className={classes.contactsSearchInput}
className={classes.searchInput}
placeholder={i18n.t("tickets.search.placeholder")}
type="search"
onChange={handleSearchContact}
/>
</div>
<div className={classes.ticketsListActions}>
<FormControlLabel
label={i18n.t("tickets.buttons.showAll")}
labelPlacement="start"
control={
<Switch
size="small"
checked={showAllTickets}
onChange={() => setShowAllTickets(prevState => !prevState)}
name="showAllTickets"
color="primary"
/>
}
/>
<IconButton
aria-label="add ticket"
size="small"
onClick={e => setNewTicketModalOpen(true)}
style={{ marginLeft: 20 }}
>
<AddIcon />
</IconButton>
</div>
</Paper>
<TabPanel value={tab} name="open" className={classes.ticketsWrapper}>
<Paper
square
elevation={0}
className={classes.halfTicketsList}
onScroll={handleScroll}
>
<div className={classes.ticketsListHeader}>
{i18n.t("tickets.tabs.open.assignedHeader")}
<span className={classes.ticketsCount}>{ticketsOpen.length}</span>
<div className={classes.ticketsListActions}>
<FormControlLabel
label={i18n.t("tickets.buttons.showAll")}
labelPlacement="start"
control={
<Switch
size="small"
checked={showAllTickets}
onChange={() => setShowAllTickets(prevState => !prevState)}
name="showAllTickets"
color="primary"
/>
}
/>
<IconButton
aria-label="add ticket"
onClick={e => setNewTicketModalOpen(true)}
style={{ marginLeft: 20 }}
>
<AddIcon />
</IconButton>
</div>
</div>
<List style={{ paddingTop: 0 }}>
{ticketsOpen.length === 0 ? (
<ListItem>
<ListItemText>
You haven&apos;t received any messages yet.
</ListItemText>
</ListItem>
) : (
ticketsOpen.map(ticket => (
<TicketListItem
ticket={ticket}
key={ticket.id}
// loading={loading}
handleSelectTicket={handleSelectTicket}
handleAcepptTicket={handleAcepptTicket}
ticketId={ticketId}
/>
))
)}
{loadingOpen && <TicketsSkeleton />}
</List>
</Paper>
<Paper
square
elevation={0}
className={classes.halfTicketsList}
onScroll={handleScroll}
>
<div className={classes.ticketsListHeader}>
{i18n.t("tickets.tabs.open.pendingHeader")}
<span className={classes.ticketsCount}>
{ticketsPending.length}
</span>
</div>
<List style={{ paddingTop: 0 }}>
{ticketsPending.length === 0 ? (
<ListItem>
<ListItemText>
You haven&apos;t received any messages yet.
</ListItemText>
</ListItem>
) : (
ticketsPending.map(ticket => (
<TicketListItem
ticket={ticket}
key={ticket.id}
// loading={loading}
handleSelectTicket={handleSelectTicket}
handleAcepptTicket={handleAcepptTicket}
ticketId={ticketId}
/>
))
)}
{loadingPending && <TicketsSkeleton />}
</List>
</Paper>
{/* <TicketsList
status="open"
handleSelectTicket={handleSelectTicket}
selectedTicketId={ticketId}
showAll={showAllTickets}
/> */}
<TicketsList
status="pending"
handleSelectTicket={handleSelectTicket}
handleAcepptTicket={handleAcepptTicket}
selectedTicketId={ticketId}
showAll={true}
/>
</TabPanel>
<TabPanel value={tab} name="closed" className={classes.ticketsWrapper}>
<Paper
square
elevation={0}
className={classes.fullHeightTicketsList}
onScroll={handleScroll}
>
<List style={{ paddingTop: 0 }}>
{/* <TicketsList
tickets={tickets}
loading={loading}
handleSelectTicket={handleSelectTicket}
showAllTickets={showAllTickets}
ticketId={ticketId}
handleAcepptTicket={handleAcepptTicket}
status="closed"
userId={null}
/>
{loading && <TicketsSkeleton />} */}
</List>
</Paper>
<TicketsList
status="closed"
handleSelectTicket={handleSelectTicket}
selectedTicketId={ticketId}
showAll={true}
/>
</TabPanel>
<TabPanel value={tab} name="search" className={classes.ticketsWrapper}>
<Paper
square
elevation={0}
className={classes.fullHeightTicketsList}
onScroll={handleScroll}
>
<List style={{ paddingTop: 0 }}>
{/* <TicketsList
tickets={tickets}
loading={loading}
handleSelectTicket={handleSelectTicket}
showAllTickets={showAllTickets}
ticketId={ticketId}
handleAcepptTicket={handleAcepptTicket}
noTicketsTitle={i18n.t("tickets.tabs.search.noTicketsTitle")}
noTicketsMessage={i18n.t("tickets.tabs.search.noTicketsMessage")}
status="all"
/>
{loading && <TicketsSkeleton />} */}
</List>
</Paper>
<TicketsList
handleSelectTicket={handleSelectTicket}
selectedTicketId={ticketId}
searchParam={searchParam}
showAll={true}
/>
</TabPanel>
</Paper>
);

View File

@@ -1,38 +1,55 @@
import React from "react";
import { parseISO, format, isSameDay } from "date-fns";
import React, { useState, useEffect } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { green } from "@material-ui/core/colors";
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 Button from "@material-ui/core/Button";
import List from "@material-ui/core/List";
import Paper from "@material-ui/core/Paper";
import TicketListItem from "../TicketListItem";
import TicketsSkeleton from "../TicketsSkeleton";
import useTickets from "../../hooks/useTickets";
import { i18n } from "../../translate/i18n";
const useStyles = makeStyles(theme => ({
ticket: {
ticketsListWrapper: {
position: "relative",
"& .hidden-button": {
display: "none",
},
"&:hover .hidden-button": {
display: "flex",
position: "absolute",
left: "50%",
},
},
noTicketsDiv: {
display: "flex",
height: "100px",
margin: 40,
height: "100%",
flexDirection: "column",
overflow: "hidden",
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
},
ticketsList: {
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",
alignItems: "center",
justifyContent: "center",
fontWeight: 500,
fontSize: "16px",
height: "56px",
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",
},
noTicketsText: {
@@ -49,163 +66,100 @@ const useStyles = makeStyles(theme => ({
margin: "0px",
},
contactNameWrapper: {
noTicketsDiv: {
display: "flex",
justifyContent: "space-between",
},
lastMessageTime: {
justifySelf: "flex-end",
},
closedBadge: {
alignSelf: "center",
justifySelf: "flex-end",
marginRight: 32,
marginLeft: "auto",
},
contactLastMessage: {
paddingRight: 20,
},
newMessagesCount: {
alignSelf: "center",
marginRight: 8,
marginLeft: "auto",
},
badgeStyle: {
color: "white",
backgroundColor: green[500],
height: "100px",
margin: 40,
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
},
}));
const TicketsList = ({
tickets,
status,
userId,
searchParam,
handleSelectTicket,
showAllTickets,
ticketId,
noTicketsTitle,
loading,
noTicketsMessage,
handleAcepptTicket,
selectedTicketId,
showAll,
}) => {
const classes = useStyles();
const [pageNumber, setPageNumber] = useState(1);
let viewTickets = [];
tickets.forEach(ticket => {
if (
(ticket.status === status && ticket.userId === userId) ||
(ticket.status === status && showAllTickets) ||
(ticket.status === "closed" && status === "closed") ||
status === "all"
)
viewTickets.push(
<React.Fragment key={ticket.id}>
<ListItem
dense
button
onClick={e => {
if (ticket.status === "pending" && handleAcepptTicket) return;
handleSelectTicket(e, ticket);
}}
selected={ticketId && +ticketId === ticket.id}
className={classes.ticket}
>
<ListItemAvatar>
<Avatar
src={
ticket.contact.profilePicUrl && ticket.contact.profilePicUrl
}
></Avatar>
</ListItemAvatar>
<ListItemText
primary={
<span className={classes.contactNameWrapper}>
<Typography
noWrap
component="span"
variant="body2"
color="textPrimary"
>
{ticket.contact.name}
</Typography>
{ticket.status === "closed" && (
<Badge
className={classes.closedBadge}
badgeContent={"closed"}
color="primary"
/>
)}
{ticket.lastMessage && (
<Typography
className={classes.lastMessageTime}
component="span"
variant="body2"
color="textSecondary"
>
{isSameDay(parseISO(ticket.updatedAt), new Date()) ? (
<>{format(parseISO(ticket.updatedAt), "HH:mm")}</>
) : (
<>{format(parseISO(ticket.updatedAt), "dd/MM/yyyy")}</>
)}
</Typography>
)}
</span>
}
secondary={
<span className={classes.contactNameWrapper}>
<Typography
className={classes.contactLastMessage}
noWrap
component="span"
variant="body2"
color="textSecondary"
>
{ticket.lastMessage || <br />}
</Typography>
<Badge
className={classes.newMessagesCount}
badgeContent={ticket.unreadMessages}
classes={{
badge: classes.badgeStyle,
}}
/>
</span>
}
/>
{ticket.status === "pending" && handleAcepptTicket ? (
<Button
variant="contained"
size="small"
color="primary"
className="hidden-button"
onClick={e => handleAcepptTicket(ticket.id)}
>
{i18n.t("ticketsList.buttons.accept")}
</Button>
) : null}
</ListItem>
<Divider variant="inset" component="li" />
</React.Fragment>
);
const { tickets, hasMore, loading, dispatch } = useTickets({
pageNumber,
searchParam,
status,
showAll,
});
if (viewTickets.length > 0) {
return viewTickets;
} else if (!loading) {
return (
<div className={classes.noTicketsDiv}>
<span className={classes.noTicketsTitle}>{noTicketsTitle}</span>
<p className={classes.noTicketsText}>{noTicketsMessage}</p>
</div>
);
} else return null;
useEffect(() => {
dispatch({ type: "RESET" });
setPageNumber(1);
}, [status, searchParam, dispatch, showAll]);
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 (
<div className={classes.ticketsListWrapper}>
<Paper
square
name="closed"
elevation={0}
className={classes.ticketsList}
onScroll={handleScroll}
>
<List style={{ paddingTop: 0 }}>
{status === "open" && (
<div className={classes.ticketsListHeader}>
{i18n.t("tickets.tabs.open.assignedHeader")}
<span className={classes.ticketsCount}>{tickets.length}</span>
</div>
)}
{status === "pending" && (
<div className={classes.ticketsListHeader}>
{i18n.t("tickets.tabs.open.pendingHeader")}
<span className={classes.ticketsCount}>{tickets.length}</span>
</div>
)}
{tickets.length === 0 && !loading ? (
<div className={classes.noTicketsDiv}>
<span className={classes.noTicketsTitle}>Nothing here!</span>
<p className={classes.noTicketsText}>
No tickets found with this status or search term.
</p>
</div>
) : (
<>
{tickets.map(ticket => (
<TicketListItem
ticket={ticket}
key={ticket.id}
handleSelectTicket={handleSelectTicket}
handleAcepptTicket={handleAcepptTicket}
selectedTicketId={selectedTicketId}
/>
))}
</>
)}
{loading && <TicketsSkeleton />}
</List>
</Paper>
</div>
);
};
export default TicketsList;

View File

@@ -16,7 +16,7 @@ import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import AccountCircle from "@material-ui/icons/AccountCircle";
import MainListItems from "./MainListItems";
import NotificationsPopOver from "./NotificationsPopOver";
import NotificationsPopOver from "../NotificationsPopOver";
import { AuthContext } from "../../context/Auth/AuthContext";
const drawerWidth = 240;
@@ -181,7 +181,7 @@ const MainDrawer = ({ appTitle, children }) => {
>
{appTitle}
</Typography>
<NotificationsPopOver />
{/* <NotificationsPopOver /> */}
<div>
<IconButton

View File

@@ -1,6 +1,5 @@
import { useState, useEffect, useReducer } from "react";
import openSocket from "socket.io-client";
import { useHistory } from "react-router-dom";
import api from "../../services/api";
@@ -24,17 +23,22 @@ const reducer = (state, action) => {
}
if (action.type === "UPDATE_TICKETS") {
const ticket = action.payload;
const { ticket, status, loggedUser } = action.payload;
const ticketIndex = state.findIndex(t => t.id === ticket.id);
if (ticketIndex !== -1) {
if (ticket.status !== state[ticketIndex]) {
if (ticket.status !== state[ticketIndex].status) {
state.splice(ticketIndex, 1);
} else {
state[ticketIndex] = ticket;
state.unshift(state.splice(ticketIndex, 1)[0]);
}
} else {
} else if (
ticket.status === status &&
(ticket.userId === loggedUser ||
!ticket.userId ||
ticket.status === "closed")
) {
state.unshift(ticket);
}
return [...state];
@@ -65,13 +69,14 @@ const reducer = (state, action) => {
}
};
const useTickets = ({ searchParam, pageNumber, status, date }) => {
const history = useHistory();
const useTickets = ({ searchParam, pageNumber, status, date, showAll }) => {
const userId = +localStorage.getItem("userId");
const [loading, setLoading] = useState(true);
const [hasMore, setHasMore] = useState(false);
const [tickets, dispatch] = useReducer(reducer, []);
console.log("rendering");
useEffect(() => {
setLoading(true);
const delayDebounceFn = setTimeout(() => {
@@ -83,6 +88,7 @@ const useTickets = ({ searchParam, pageNumber, status, date }) => {
pageNumber,
status,
date,
showAll,
},
});
dispatch({
@@ -98,7 +104,7 @@ const useTickets = ({ searchParam, pageNumber, status, date }) => {
fetchTickets();
}, 500);
return () => clearTimeout(delayDebounceFn);
}, [searchParam, pageNumber, status, date]);
}, [searchParam, pageNumber, status, date, showAll]);
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
@@ -110,11 +116,13 @@ const useTickets = ({ searchParam, pageNumber, status, date }) => {
}
if (data.action === "updateStatus" || data.action === "create") {
console.log("to aqui", status, data.ticket);
dispatch({
type: "UPDATE_TICKETS",
payload: data.ticket,
status: status,
payload: {
ticket: data.ticket,
status: status,
loggedUser: userId,
},
});
}
@@ -125,14 +133,21 @@ const useTickets = ({ searchParam, pageNumber, status, date }) => {
socket.on("appMessage", data => {
if (data.action === "create") {
dispatch({ type: "UPDATE_TICKETS", payload: data.ticket });
dispatch({
type: "UPDATE_TICKETS",
payload: {
ticket: data.ticket,
status: status,
loggedUser: userId,
},
});
}
});
return () => {
socket.disconnect();
};
}, [status]);
}, [status, userId]);
return { loading, tickets, hasMore, dispatch };
};

View File

@@ -100,7 +100,7 @@ const Contacts = () => {
}
};
fetchContacts();
}, 1000);
}, 500);
return () => clearTimeout(delayDebounceFn);
}, [searchParam, page, rowsPerPage]);

View File

@@ -37,7 +37,7 @@ const messages = {
dashboard: {
charts: {
perDay: {
title: "Tickets today:",
title: "Tickets today: ",
},
},
},