Finished Contact Drawer styles and func

This commit is contained in:
canove
2020-07-27 16:51:54 -03:00
parent 66a1dc5fd2
commit 9477e46c24
12 changed files with 212 additions and 128 deletions

View File

@@ -48,8 +48,9 @@ exports.index = async (req, res, next) => {
include: [
{
model: Contact,
as: "contact",
include: "extraInfo",
attributes: ["name", "number", "profilePicUrl"],
attributes: ["id", "name", "number", "profilePicUrl"],
},
],
});
@@ -81,7 +82,6 @@ exports.index = async (req, res, next) => {
return res.json({
messages: serializedMessages.reverse(),
ticket: ticket,
contact: ticket.Contact,
});
};
@@ -98,6 +98,7 @@ exports.store = async (req, res, next) => {
include: [
{
model: Contact,
as: "contact",
attributes: ["number"],
},
],
@@ -113,12 +114,12 @@ exports.store = async (req, res, next) => {
}
sentMessage = await wbot.sendMessage(
`${ticket.Contact.number}@c.us`,
`${ticket.contact.number}@c.us`,
newMedia
);
} else {
sentMessage = await wbot.sendMessage(
`${ticket.Contact.number}@c.us`,
`${ticket.contact.number}@c.us`,
message.body
);
}

View File

@@ -22,6 +22,7 @@ exports.index = async (req, res) => {
include: [
{
model: Contact,
as: "contact",
attributes: ["name", "number", "profilePicUrl"],
},
],
@@ -60,6 +61,7 @@ exports.update = async (req, res) => {
include: [
{
model: Contact,
as: "contact",
attributes: ["name", "number", "profilePicUrl"],
},
],

View File

@@ -18,7 +18,7 @@ class Contact extends Sequelize.Model {
}
static associate(models) {
this.hasMany(models.Ticket, { foreignKey: "contactId" });
this.hasMany(models.Ticket, { foreignKey: "contactId", as: "contact" });
this.hasMany(models.ContactCustomField, {
foreignKey: "contactId",
as: "extraInfo",

View File

@@ -5,6 +5,7 @@ class Ticket extends Sequelize.Model {
super.init(
{
status: { type: Sequelize.STRING, defaultValue: "pending" },
userId: { type: Sequelize.INTEGER, defaultValue: null },
lastMessage: { type: Sequelize.STRING },
},
{
@@ -16,7 +17,7 @@ class Ticket extends Sequelize.Model {
}
static associate(models) {
this.belongsTo(models.Contact, { foreignKey: "contactId" });
this.belongsTo(models.Contact, { foreignKey: "contactId", as: "contact" });
this.belongsTo(models.User, { foreignKey: "userId" });
this.hasMany(models.Message, { foreignKey: "ticketId" });
}

View File

@@ -28,22 +28,16 @@ const verifyContact = async (msgContact, profilePicUrl) => {
};
const verifyTicket = async contact => {
let ticket = await Ticket.findOne({
const [ticket, created] = await Ticket.findOrCreate({
where: {
status: {
[Op.or]: ["open", "pending"],
},
contactId: contact.id,
},
defaults: { contactId: contact.id, status: "pending" },
});
if (!ticket) {
ticket = await Ticket.create({
contactId: contact.id,
status: "pending",
});
}
return ticket;
};
@@ -127,6 +121,7 @@ const wbotMessageListener = () => {
...ticket.dataValues,
unreadMessages: 1,
lastMessage: newMessage.body,
contact: contact,
};
io.to(ticket.id).to("notification").emit("appMessage", {

View File

@@ -1,10 +1,19 @@
import React from "react";
import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
import CloseIcon from "@material-ui/icons/Close";
import Drawer from "@material-ui/core/Drawer";
import Link from "@material-ui/core/Link";
import InputLabel from "@material-ui/core/InputLabel";
import Avatar from "@material-ui/core/Avatar";
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";
import LinkifyWithTargetBlank from "../LinkifyWithTargetBlank";
import ContactModal from "../ContactModal";
import ContactDrawerSkeleton from "../ContactDrawerSkeleton";
const drawerWidth = 320;
@@ -21,7 +30,7 @@ const useStyles = makeStyles(theme => ({
borderBottomRightRadius: 4,
backgroundColor: "#eee",
},
drawerHeader: {
header: {
display: "flex",
borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
backgroundColor: "#eee",
@@ -30,11 +39,75 @@ const useStyles = makeStyles(theme => ({
minHeight: "73px",
justifyContent: "flex-start",
},
content: {
display: "flex",
flexDirection: "column",
padding: "8px 0px 8px 8px",
// backgroundColor: "red",
height: "100%",
overflow: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
// borderRadius: "2px",
boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
backgroundColor: "#e8e8e8",
},
},
contactAvatar: {
margin: 15,
width: 160,
height: 160,
},
contactHeader: {
display: "flex",
padding: 8,
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
"& > *": {
margin: 4,
},
},
contactDetails: {
marginTop: 8,
padding: 8,
display: "flex",
flexDirection: "column",
// overflowX: "scroll",
// flex: 1,
// "&::-webkit-scrollbar": {
// width: "8px",
// height: "8px",
// },
// "&::-webkit-scrollbar-thumb": {
// // borderRadius: "2px",
// boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
// backgroundColor: "#e8e8e8",
// },
},
contactExtraInfo: {
marginTop: 4,
padding: 6,
},
}));
const ContactDrawer = ({ open, children, handleDrawerClose }) => {
const ContactDrawer = ({
open,
children,
handleDrawerClose,
contact,
loading,
}) => {
const classes = useStyles();
const [modalOpen, setModalOpen] = useState(false);
return (
<Drawer
className={classes.drawer}
@@ -51,7 +124,7 @@ const ContactDrawer = ({ open, children, handleDrawerClose }) => {
paper: classes.drawerPaper,
}}
>
<div className={classes.drawerHeader}>
<div className={classes.header}>
<IconButton onClick={handleDrawerClose}>
<CloseIcon />
</IconButton>
@@ -59,7 +132,57 @@ const ContactDrawer = ({ open, children, handleDrawerClose }) => {
Dados do contato
</Typography>
</div>
{children}
{loading ? (
<ContactDrawerSkeleton classes={classes} />
) : (
<div className={classes.content}>
<Paper square variant="outlined" className={classes.contactHeader}>
<Avatar
alt={contact.name}
src={contact.profilePicUrl}
className={classes.contactAvatar}
></Avatar>
<Typography>{contact.name}</Typography>
<Typography>
<Link href={`tel:${contact.number}`}>{contact.number}</Link>
</Typography>
<Button
variant="outlined"
color="primary"
onClick={e => setModalOpen(true)}
>
Editar contato
</Button>
</Paper>
<Paper square variant="outlined" className={classes.contactDetails}>
<ContactModal
modalOpen={modalOpen}
onClose={e => setModalOpen(false)}
aria-labelledby="form-dialog-title"
contactId={contact.id}
></ContactModal>
<Typography variant="subtitle1">Outras informações</Typography>
{contact &&
contact.extraInfo &&
contact.extraInfo.map(info => (
<Paper
key={info.id}
square
variant="outlined"
className={classes.contactExtraInfo}
>
<InputLabel>{info.name}</InputLabel>
<LinkifyWithTargetBlank>
<Typography noWrap style={{ paddingTop: 2 }}>
{info.value}
</Typography>
</LinkifyWithTargetBlank>
</Paper>
))}
</Paper>
</div>
)}
</Drawer>
);
};

View File

@@ -0,0 +1,40 @@
import React from "react";
import Skeleton from "@material-ui/lab/Skeleton";
import Typography from "@material-ui/core/Typography";
import Paper from "@material-ui/core/Paper";
const ContactDrawerSkeleton = ({ classes }) => {
return (
<div className={classes.content}>
<Paper square variant="outlined" className={classes.contactHeader}>
<Skeleton
animation="wave"
variant="circle"
width={160}
height={160}
className={classes.contactAvatar}
/>
<Skeleton animation="wave" height={25} width={90} />
<Skeleton animation="wave" height={25} width={80} />
<Skeleton animation="wave" height={25} width={80} />
</Paper>
<Paper square className={classes.contactDetails}>
<Typography variant="subtitle1">Outras informações</Typography>
<Paper square variant="outlined" className={classes.contactExtraInfo}>
<Skeleton animation="wave" height={20} width={60} />
<Skeleton animation="wave" height={20} width={160} />
</Paper>
<Paper square variant="outlined" className={classes.contactExtraInfo}>
<Skeleton animation="wave" height={20} width={60} />
<Skeleton animation="wave" height={20} width={160} />
</Paper>
<Paper square variant="outlined" className={classes.contactExtraInfo}>
<Skeleton animation="wave" height={20} width={60} />
<Skeleton animation="wave" height={20} width={160} />
</Paper>
</Paper>
</div>
);
};
export default ContactDrawerSkeleton;

View File

@@ -77,7 +77,7 @@ const ContactModal = ({ modalOpen, onClose, contactId }) => {
};
fetchContact();
}, [contactId]);
}, [contactId, modalOpen]);
const handleClose = () => {
onClose();

View File

@@ -16,29 +16,15 @@ import Card from "@material-ui/core/Card";
import CardHeader from "@material-ui/core/CardHeader";
import ReplayIcon from "@material-ui/icons/Replay";
import Avatar from "@material-ui/core/Avatar";
import Divider from "@material-ui/core/Divider";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import Link from "@material-ui/core/Link";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import { green } from "@material-ui/core/colors";
import Skeleton from "@material-ui/lab/Skeleton";
// import Drawer from "@material-ui/core/Drawer";
import api from "../../services/api";
import ContactDrawer from "../ContactDrawer";
import whatsBackground from "../../assets/wa-background.png";
import LinkifyWithTargetBlank from "../LinkifyWithTargetBlank";
import api from "../../services/api";
import MessageInput from "../MessageInput/";
const drawerWidth = 320;
@@ -111,6 +97,7 @@ const useStyles = makeStyles(theme => ({
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
// borderRadius: "2px",
@@ -126,7 +113,6 @@ const useStyles = makeStyles(theme => ({
top: 0,
left: "50%",
marginTop: 12,
// marginLeft: -12,
},
messageLeft: {
@@ -226,44 +212,6 @@ const useStyles = makeStyles(theme => ({
verticalAlign: "middle",
marginLeft: 4,
},
drawerContent: {
display: "flex",
flexDirection: "column",
padding: 8,
// backgroundColor: "red",
height: "100%",
overflow: "hidden",
},
drawerAvatar: {
margin: 15,
width: 160,
height: 160,
},
drawerHeader: {
// margin: 8,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
"& > *": {
margin: 4,
},
},
drawerDetails: {
marginTop: 8,
padding: 8,
display: "flex",
flexDirection: "column",
// overflow: "hidden",
// whiteSpace: "nowrap",
// textOverflow: "ellipsis",
// overflow: "scroll",
flex: 1,
},
}));
const MessagesList = () => {
@@ -297,7 +245,7 @@ const MessagesList = () => {
const res = await api.get("/messages/" + ticketId, {
params: { searchParam, pageNumber },
});
setContact(res.data.contact);
setContact(res.data.ticket.contact);
setTicket(res.data.ticket);
setMessagesList(prevMessages => {
return [...res.data.messages, ...prevMessages];
@@ -331,6 +279,12 @@ const MessagesList = () => {
}
});
socket.on("contact", data => {
if (data.action === "update") {
setContact(data.contact);
}
});
return () => {
socket.disconnect();
setSearchParam("");
@@ -531,8 +485,6 @@ const MessagesList = () => {
setOpen(false);
};
console.log(contact);
return (
<div className={classes.root} id="drawer-container">
<Paper
@@ -627,46 +579,13 @@ const MessagesList = () => {
) : null}
</div>
</Paper>
<ContactDrawer open={open} handleDrawerClose={handleDrawerClose}>
<div className={classes.drawerContent}>
<div className={classes.drawerHeader}>
<Avatar
alt={contact.name}
src={contact.profilePicUrl}
className={classes.drawerAvatar}
></Avatar>
<Typography>{contact.name}</Typography>
<Typography>
<Link href={`tel:${contact.number}`}>{contact.number}</Link>
</Typography>
<Button variant="outlined" color="primary">
Editar contato
</Button>
</div>
<Paper className={classes.drawerDetails}>
<Typography variant="subtitle1">Informações</Typography>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>Nome</TableCell>
<TableCell>Valor</TableCell>
</TableRow>
</TableHead>
<TableBody>
{contact &&
contact.extraInfo &&
contact.extraInfo.map(info => (
<TableRow key={info.id}>
<TableCell>{info.name}</TableCell>
<TableCell>{info.value}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Paper>
</div>
</ContactDrawer>
<ContactDrawer
open={open}
handleDrawerClose={handleDrawerClose}
contact={contact}
loading={loading}
/>
</div>
);
};

View File

@@ -1,7 +1,6 @@
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";
@@ -18,11 +17,11 @@ 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 TicketsSkeleton from "../TicketsSkeleton";
import api from "../../services/api";
@@ -55,6 +54,7 @@ const useStyles = makeStyles(theme => ({
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
@@ -68,6 +68,7 @@ const useStyles = makeStyles(theme => ({
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
@@ -194,6 +195,8 @@ const useStyles = makeStyles(theme => ({
const TicketsList = () => {
const classes = useStyles();
const history = useHistory();
const token = localStorage.getItem("token");
const userId = +localStorage.getItem("userId");
const { ticketId } = useParams();
@@ -202,10 +205,6 @@ const TicketsList = () => {
const [searchParam, setSearchParam] = useState("");
const [tab, setTab] = useState("open");
// const [modalOpen, setModalOpen] = useState(false);
const history = useHistory();
useEffect(() => {
if (!("Notification" in window)) {
console.log("This browser doesn't support notifications");
@@ -301,8 +300,6 @@ const TicketsList = () => {
});
};
console.log(tickets);
const showDesktopNotification = data => {
const options = {
body: `${data.message.body} - ${format(new Date(), "HH:mm")}`,
@@ -382,7 +379,7 @@ const TicketsList = () => {
<ListItemAvatar>
<Avatar
src={
ticket.Contact.profilePicUrl && ticket.Contact.profilePicUrl
ticket.contact.profilePicUrl && ticket.contact.profilePicUrl
}
></Avatar>
</ListItemAvatar>
@@ -395,7 +392,7 @@ const TicketsList = () => {
variant="body2"
color="textPrimary"
>
{ticket.Contact.name}
{ticket.contact.name}
</Typography>
{ticket.lastMessage && (
<Typography

View File

@@ -57,6 +57,7 @@ const useStyles = makeStyles(theme => ({
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
height: "8px",
},
"&::-webkit-scrollbar-thumb": {
// borderRadius: "2px",
@@ -191,7 +192,6 @@ const Contacts = () => {
<ContactModal
modalOpen={modalOpen}
onClose={handleClose}
setModalOpen={setModalOpen}
aria-labelledby="form-dialog-title"
contactId={selectedContactId}
></ContactModal>

View File

@@ -3,7 +3,13 @@ import React from "react";
const Dashboard = () => {
return (
<div>
<h1>Todo Dashboard</h1>
<a
rel="bookmark"
target="_parent"
href="https://economicros.ddns.com.br:4043/"
>
teste
</a>
</div>
);
};