mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-20 04:39:20 +00:00
Finished AuthContext
This commit is contained in:
@@ -52,7 +52,7 @@ sequelize
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("joinNotification", () => {
|
socket.on("joinNotification", () => {
|
||||||
console.log("chat entro no canal de notificações");
|
console.log("chat entrou no canal de notificações");
|
||||||
socket.join("notification");
|
socket.join("notification");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ exports.getContacts = async (req, res) => {
|
|||||||
const contacts = await Contact.findAll({
|
const contacts = await Contact.findAll({
|
||||||
include: {
|
include: {
|
||||||
model: Message,
|
model: Message,
|
||||||
attributes: ["messageBody"],
|
attributes: ["messageBody", "createdAt"],
|
||||||
},
|
},
|
||||||
attributes: {
|
attributes: {
|
||||||
include: [
|
include: [
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"WABrowserId":"\"E9dnt9Mm/JiFDCMJQHkXBw==\"","WASecretBundle":"{\"key\":\"fHTKtoDcxidboASIs5WV5JKyRrF+SfMktqHXmq/KBJU=\",\"encKey\":\"FrM3OnnEbuEr1JrtKypw5CPSc6rSD5bjbOGstv8ijk4=\",\"macKey\":\"fHTKtoDcxidboASIs5WV5JKyRrF+SfMktqHXmq/KBJU=\"}","WAToken1":"\"6UDP2DUC5ZZ99Iqy9CHRg53e2ZyeiVXEbcSnnxzuGWo=\"","WAToken2":"\"1@RByirgRpxu+HWxlX4oTADTz2yDLH4v2KNmYVektVG8dS9vCyaAukGYQG5/7Nvl82IuLiCrKtTffJLw==\""}
|
{"WABrowserId":"\"E9dnt9Mm/JiFDCMJQHkXBw==\"","WASecretBundle":"{\"key\":\"fHTKtoDcxidboASIs5WV5JKyRrF+SfMktqHXmq/KBJU=\",\"encKey\":\"FrM3OnnEbuEr1JrtKypw5CPSc6rSD5bjbOGstv8ijk4=\",\"macKey\":\"fHTKtoDcxidboASIs5WV5JKyRrF+SfMktqHXmq/KBJU=\"}","WAToken1":"\"tjwS2T/ux5P+nyxYcBEj+gRIUS/XqREEEPqap787yzg=\"","WAToken2":"\"1@781NE8OipW/PigfWCI6tiz8fEpUOVVhyNEePCZMuEyC7aXG0cy1I75liSVz8z6DxVjXiw4iGI7c4Hg==\""}
|
||||||
@@ -3,7 +3,7 @@ const jwt = require("jsonwebtoken");
|
|||||||
module.exports = (req, res, next) => {
|
module.exports = (req, res, next) => {
|
||||||
let decodedToken;
|
let decodedToken;
|
||||||
try {
|
try {
|
||||||
const token = req.get("Authorization").split(" ")[1];
|
const [, token] = req.get("Authorization").split(" ");
|
||||||
decodedToken = jwt.verify(token, "mysecret");
|
decodedToken = jwt.verify(token, "mysecret");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.statusCode = 401;
|
err.statusCode = 401;
|
||||||
|
|||||||
@@ -1,60 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
import Routes from "./routes";
|
||||||
import { toast, ToastContainer } from "react-toastify";
|
|
||||||
|
|
||||||
import Dashboard from "./pages/Home/Dashboard";
|
|
||||||
import Chat from "./pages/Chat/Chat";
|
|
||||||
import Profile from "./pages/Profile/Profile";
|
|
||||||
import Signup from "./pages/Signup/Signup";
|
|
||||||
import Login from "./pages/Login/Login";
|
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const showToast = (type, message) => {
|
return <Routes />;
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
toast.warning(message);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
toast.success(message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BrowserRouter>
|
|
||||||
<ToastContainer
|
|
||||||
autoClose={2000}
|
|
||||||
hideProgressBar={true}
|
|
||||||
position={toast.POSITION.TOP_CENTER}
|
|
||||||
/>
|
|
||||||
<Switch>
|
|
||||||
<Route exact path="/" render={props => <Dashboard />} />
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/login"
|
|
||||||
render={props => <Login showToast={showToast} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/profile"
|
|
||||||
render={props => <Profile showToast={showToast} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/signup"
|
|
||||||
render={props => <Signup showToast={showToast} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/chat"
|
|
||||||
render={props => <Chat showToast={showToast} />}
|
|
||||||
/>
|
|
||||||
</Switch>
|
|
||||||
</BrowserRouter>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
19
frontend/src/Context/Auth/AuthContext.js
Normal file
19
frontend/src/Context/Auth/AuthContext.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import React, { createContext } from "react";
|
||||||
|
|
||||||
|
import useAuth from "./useAuth";
|
||||||
|
|
||||||
|
const AuthContext = createContext();
|
||||||
|
|
||||||
|
const AuthProvider = ({ children }) => {
|
||||||
|
const { isAuth, loading, handleLogin, handleLogout } = useAuth();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider
|
||||||
|
value={{ loading, isAuth, handleLogin, handleLogout }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { AuthContext, AuthProvider };
|
||||||
50
frontend/src/Context/Auth/useAuth.js
Normal file
50
frontend/src/Context/Auth/useAuth.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
|
import api from "../../util/api";
|
||||||
|
|
||||||
|
const useAuth = () => {
|
||||||
|
const history = useHistory();
|
||||||
|
const [isAuth, setIsAuth] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
api.defaults.headers.Authorization = `Bearer ${JSON.parse(token)}`;
|
||||||
|
setIsAuth(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleLogin = async (e, user) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
const res = await api.post("/auth/login", user);
|
||||||
|
localStorage.setItem("token", JSON.stringify(res.data.token));
|
||||||
|
localStorage.setItem("username", res.data.username);
|
||||||
|
localStorage.setItem("userId", res.data.userId);
|
||||||
|
api.defaults.headers.Authorization = `Bearer ${res.data.token}`;
|
||||||
|
setIsAuth(true);
|
||||||
|
history.push("/chat");
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogout = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsAuth(false);
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("username");
|
||||||
|
localStorage.removeItem("userId");
|
||||||
|
api.defaults.headers.Authorization = undefined;
|
||||||
|
history.push("/login");
|
||||||
|
};
|
||||||
|
|
||||||
|
return { isAuth, loading, handleLogin, handleLogout };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useAuth;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useContext, useEffect } from "react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
@@ -16,6 +16,12 @@ import MenuIcon from "@material-ui/icons/Menu";
|
|||||||
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
|
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
|
||||||
import NotificationsIcon from "@material-ui/icons/Notifications";
|
import NotificationsIcon from "@material-ui/icons/Notifications";
|
||||||
import MainListItems from "./MainListItems";
|
import MainListItems from "./MainListItems";
|
||||||
|
import AccountCircle from "@material-ui/icons/AccountCircle";
|
||||||
|
|
||||||
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
|
import Menu from "@material-ui/core/Menu";
|
||||||
|
|
||||||
|
import { AuthContext } from "../../Context/Auth/AuthContext";
|
||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 240;
|
||||||
|
|
||||||
@@ -98,14 +104,34 @@ const useStyles = makeStyles(theme => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const MainDrawer = ({ appTitle, children }) => {
|
const MainDrawer = ({ appTitle, children }) => {
|
||||||
|
const { handleLogout } = useContext(AuthContext);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||||
|
const menuOpen = Boolean(anchorEl);
|
||||||
|
const drawerState = localStorage.getItem("drawerOpen");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (drawerState === "0") {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
}, [drawerState]);
|
||||||
|
|
||||||
const handleDrawerOpen = () => {
|
const handleDrawerOpen = () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
localStorage.setItem("drawerOpen", 1);
|
||||||
};
|
};
|
||||||
const handleDrawerClose = () => {
|
const handleDrawerClose = () => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
localStorage.setItem("drawerOpen", 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenu = event => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -159,6 +185,36 @@ const MainDrawer = ({ appTitle, children }) => {
|
|||||||
<NotificationsIcon />
|
<NotificationsIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<IconButton
|
||||||
|
aria-label="account of current user"
|
||||||
|
aria-controls="menu-appbar"
|
||||||
|
aria-haspopup="true"
|
||||||
|
onClick={handleMenu}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
|
<AccountCircle />
|
||||||
|
</IconButton>
|
||||||
|
<Menu
|
||||||
|
id="menu-appbar"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "right",
|
||||||
|
}}
|
||||||
|
keepMounted
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "right",
|
||||||
|
}}
|
||||||
|
open={menuOpen}
|
||||||
|
onClose={handleClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleClose}>Profile</MenuItem>
|
||||||
|
<MenuItem onClick={handleLogout}>Logout</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
<main className={classes.content}>
|
<main className={classes.content}>
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import ListItemText from "@material-ui/core/ListItemText";
|
|||||||
import Collapse from "@material-ui/core/Collapse";
|
import Collapse from "@material-ui/core/Collapse";
|
||||||
|
|
||||||
import DashboardIcon from "@material-ui/icons/Dashboard";
|
import DashboardIcon from "@material-ui/icons/Dashboard";
|
||||||
import PeopleIcon from "@material-ui/icons/People";
|
import WhatsAppIcon from "@material-ui/icons/WhatsApp";
|
||||||
|
// import PeopleIcon from "@material-ui/icons/People";
|
||||||
|
import BorderOuterIcon from "@material-ui/icons/BorderOuter";
|
||||||
import ChatIcon from "@material-ui/icons/Chat";
|
import ChatIcon from "@material-ui/icons/Chat";
|
||||||
import BarChartIcon from "@material-ui/icons/BarChart";
|
import BarChartIcon from "@material-ui/icons/BarChart";
|
||||||
import LayersIcon from "@material-ui/icons/Layers";
|
import LayersIcon from "@material-ui/icons/Layers";
|
||||||
@@ -25,7 +27,7 @@ const useStyles = makeStyles(theme => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
function ListItemLink(props) {
|
function ListItemLink(props) {
|
||||||
const { icon, primary, to } = props;
|
const { icon, primary, to, className } = props;
|
||||||
|
|
||||||
const renderLink = React.useMemo(
|
const renderLink = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -37,7 +39,7 @@ function ListItemLink(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<ListItem button component={renderLink}>
|
<ListItem button component={renderLink} className={className}>
|
||||||
{icon ? <ListItemIcon>{icon}</ListItemIcon> : null}
|
{icon ? <ListItemIcon>{icon}</ListItemIcon> : null}
|
||||||
<ListItemText primary={primary} />
|
<ListItemText primary={primary} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@@ -56,33 +58,38 @@ const MainListItems = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ListItemLink to="/" primary="Dashboard" icon={<DashboardIcon />} />
|
<ListItemLink to="/" primary="Dashboard" icon={<DashboardIcon />} />
|
||||||
<ListItemLink to="/chat" primary="Chat" icon={<ChatIcon />} />
|
|
||||||
|
|
||||||
<ListItem button onClick={handleClick}>
|
<ListItem button onClick={handleClick}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<PeopleIcon />
|
<WhatsAppIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Clientes" />
|
<ListItemText primary="WhatsApp" />
|
||||||
{open ? <ExpandLess /> : <ExpandMore />}
|
{open ? <ExpandLess /> : <ExpandMore />}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||||
<List component="div" disablePadding>
|
<List component="div" disablePadding>
|
||||||
<ListItem button className={classes.nested}>
|
<ListItemLink
|
||||||
<ListItemIcon>
|
className={classes.nested}
|
||||||
<LayersIcon />
|
to="/whats-auth"
|
||||||
</ListItemIcon>
|
primary="Autenticação"
|
||||||
<ListItemText primary="Starred" />
|
icon={<BorderOuterIcon />}
|
||||||
</ListItem>
|
/>
|
||||||
|
<ListItemLink
|
||||||
|
className={classes.nested}
|
||||||
|
to="/chat"
|
||||||
|
primary="Chat"
|
||||||
|
icon={<ChatIcon />}
|
||||||
|
/>
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
<ListItem button>
|
<ListItem button disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<BarChartIcon />
|
<BarChartIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Relatórios" />
|
<ListItemText primary="Relatórios" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem button>
|
<ListItem button disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<LayersIcon />
|
<LayersIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -6,10 +6,18 @@ import CssBaseline from "@material-ui/core/CssBaseline";
|
|||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<CssBaseline>
|
||||||
<CssBaseline>
|
<App />
|
||||||
<App />
|
</CssBaseline>,
|
||||||
</CssBaseline>
|
|
||||||
</React.StrictMode>,
|
|
||||||
document.getElementById("root")
|
document.getElementById("root")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ReactDOM.render(
|
||||||
|
// <React.StrictMode>
|
||||||
|
// <CssBaseline>
|
||||||
|
// <App />
|
||||||
|
// </CssBaseline>,
|
||||||
|
// </React.StrictMode>
|
||||||
|
|
||||||
|
// document.getElementById("root")
|
||||||
|
// );
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import api from "../../../../util/api";
|
import api from "../../../../util/api";
|
||||||
import openSocket from "socket.io-client";
|
import openSocket from "socket.io-client";
|
||||||
|
import moment from "moment-timezone";
|
||||||
|
|
||||||
import profileDefaultPic from "../../../../Images/profile_default.png";
|
import profileDefaultPic from "../../../../Images/profile_default.png";
|
||||||
|
|
||||||
@@ -13,12 +14,12 @@ import ListItem from "@material-ui/core/ListItem";
|
|||||||
import ListItemText from "@material-ui/core/ListItemText";
|
import ListItemText from "@material-ui/core/ListItemText";
|
||||||
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
|
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
|
||||||
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
|
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
import Divider from "@material-ui/core/Divider";
|
import Divider from "@material-ui/core/Divider";
|
||||||
import Badge from "@material-ui/core/Badge";
|
import Badge from "@material-ui/core/Badge";
|
||||||
import SearchIcon from "@material-ui/icons/Search";
|
import SearchIcon from "@material-ui/icons/Search";
|
||||||
import InputBase from "@material-ui/core/InputBase";
|
import InputBase from "@material-ui/core/InputBase";
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
|
|
||||||
import ContactsHeader from "../ContactsHeader/ContactsHeader";
|
import ContactsHeader from "../ContactsHeader/ContactsHeader";
|
||||||
|
|
||||||
@@ -87,6 +88,19 @@ const useStyles = makeStyles(theme => ({
|
|||||||
border: "none",
|
border: "none",
|
||||||
borderRadius: 30,
|
borderRadius: 30,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
contactNameWrapper: {
|
||||||
|
display: "flex",
|
||||||
|
// display: "inline",
|
||||||
|
},
|
||||||
|
|
||||||
|
contactName: {
|
||||||
|
// flex: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
lastMessageTime: {
|
||||||
|
marginLeft: "auto",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ContactsList = ({ selectedContact, setSelectedContact }) => {
|
const ContactsList = ({ selectedContact, setSelectedContact }) => {
|
||||||
@@ -102,18 +116,16 @@ const ContactsList = ({ selectedContact, setSelectedContact }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchContacts = async () => {
|
const fetchContacts = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await api.get("/contacts", {
|
const res = await api.get(
|
||||||
headers: { Authorization: "Bearer " + token },
|
"/contacts"
|
||||||
});
|
// { headers: { Authorization: "Bearer " + token }, }
|
||||||
|
);
|
||||||
setContacts(res.data);
|
setContacts(res.data);
|
||||||
setDisplayedContacts(res.data);
|
setDisplayedContacts(res.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.response.data.message === "invalidToken") {
|
if (err) {
|
||||||
localStorage.removeItem("token");
|
console.log(err);
|
||||||
localStorage.removeItem("username");
|
alert(err);
|
||||||
localStorage.removeItem("userId");
|
|
||||||
history.push("/login");
|
|
||||||
alert("Sessão expirada, por favor, faça login novamente.");
|
|
||||||
}
|
}
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
@@ -206,9 +218,35 @@ const ContactsList = ({ selectedContact, setSelectedContact }) => {
|
|||||||
></Avatar>
|
></Avatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primaryTypographyProps={{ noWrap: true }}
|
// primaryTypographyProps={{ noWrap: true }}
|
||||||
secondaryTypographyProps={{ noWrap: true }}
|
// secondaryTypographyProps={{ noWrap: true }}
|
||||||
primary={contact.name}
|
|
||||||
|
primary={
|
||||||
|
<div className={classes.contactNameWrapper}>
|
||||||
|
<Typography
|
||||||
|
className={classes.contactName}
|
||||||
|
noWrap
|
||||||
|
component="span"
|
||||||
|
variant="body2"
|
||||||
|
color="textPrimary"
|
||||||
|
>
|
||||||
|
{contact.name}
|
||||||
|
</Typography>
|
||||||
|
{contact.messages && contact.messages[0] && (
|
||||||
|
<Typography
|
||||||
|
className={classes.lastMessageTime}
|
||||||
|
oWrap
|
||||||
|
component="span"
|
||||||
|
variant="body2"
|
||||||
|
color="textSecondary"
|
||||||
|
>
|
||||||
|
{moment(contact.messages[0].createdAt)
|
||||||
|
.tz("America/Sao_Paulo")
|
||||||
|
.format("HH:mm")}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
secondary={
|
secondary={
|
||||||
(contact.messages &&
|
(contact.messages &&
|
||||||
contact.messages[0] &&
|
contact.messages[0] &&
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ const MessagesInput = ({ selectedContact, searchParam }) => {
|
|||||||
const contactId = selectedContact.id;
|
const contactId = selectedContact.id;
|
||||||
const userId = localStorage.getItem("userId");
|
const userId = localStorage.getItem("userId");
|
||||||
const username = localStorage.getItem("username");
|
const username = localStorage.getItem("username");
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
const mediaInitialState = { preview: "", raw: "", name: "" };
|
const mediaInitialState = { preview: "", raw: "", name: "" };
|
||||||
const [media, setMedia] = useState(mediaInitialState);
|
const [media, setMedia] = useState(mediaInitialState);
|
||||||
@@ -131,9 +130,7 @@ const MessagesInput = ({ selectedContact, searchParam }) => {
|
|||||||
formData.append("messageBody", media.name);
|
formData.append("messageBody", media.name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.post(`/messages/${contactId}`, formData, {
|
await api.post(`/messages/${contactId}`, formData);
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
alert(err);
|
alert(err);
|
||||||
@@ -151,9 +148,7 @@ const MessagesInput = ({ selectedContact, searchParam }) => {
|
|||||||
messageBody: `${username}: ${inputMessage.trim()}`,
|
messageBody: `${username}: ${inputMessage.trim()}`,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await api.post(`/messages/${contactId}`, message, {
|
await api.post(`/messages/${contactId}`, message);
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err);
|
alert(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,6 @@ const MessagesList = ({ selectedContact }) => {
|
|||||||
const fetchMessages = async () => {
|
const fetchMessages = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await api.get("/messages/" + contactId, {
|
const res = await api.get("/messages/" + contactId, {
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
params: { searchParam, pageNumber },
|
params: { searchParam, pageNumber },
|
||||||
});
|
});
|
||||||
setMessagesList(prevMessages => {
|
setMessagesList(prevMessages => {
|
||||||
|
|||||||
@@ -1,464 +0,0 @@
|
|||||||
/* Chat board */
|
|
||||||
|
|
||||||
.viewChatBoard {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
position: relative;
|
|
||||||
height: 92vh;
|
|
||||||
background-image: url("../../Images/wa-background.png");
|
|
||||||
|
|
||||||
backface-visibility: hidden;
|
|
||||||
border-left: 1px solid #ededed;
|
|
||||||
/* max-height: 104.3%; */
|
|
||||||
/* min-height: 104.3%; */
|
|
||||||
/* margin-right: 20px; */
|
|
||||||
/* border-radius: 10px; */
|
|
||||||
/* box-shadow: 0 5px 5px #808888; */
|
|
||||||
}
|
|
||||||
.viewAvatarItem {
|
|
||||||
margin-left: 20px;
|
|
||||||
/* background-image: url('../../images/nopic.jpg'); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerChatBoard {
|
|
||||||
border-bottom: 1px solid #e8e8e8;
|
|
||||||
padding: 5px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
background-color: #ededed;
|
|
||||||
}
|
|
||||||
.aboutme {
|
|
||||||
padding-top: 20px;
|
|
||||||
margin-left: 80px;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.textHeaderChatBoard {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #203152;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewListContentChat {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: scroll;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewListContentChat::-webkit-scrollbar-track {
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewListContentChat::-webkit-scrollbar {
|
|
||||||
width: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewListContentChat::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewBottom {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100px;
|
|
||||||
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewMediaBottom {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100px;
|
|
||||||
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewInputGallery {
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
z-index: -1;
|
|
||||||
left: 10px;
|
|
||||||
width: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icOpenGallery {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icOpenGallery:hover {
|
|
||||||
opacity: 70%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icOpenEmojis {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icOpenEmojis:hover {
|
|
||||||
opacity: 70%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icSend {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icSend:hover {
|
|
||||||
opacity: 70%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewMediaInput {
|
|
||||||
flex: 1;
|
|
||||||
width: 100%;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewInput {
|
|
||||||
flex: 1;
|
|
||||||
border-radius: 30px;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
border: 0px;
|
|
||||||
height: 50px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewInput:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input::placeholder {
|
|
||||||
color: rgb(199, 199, 199);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* serach messages */
|
|
||||||
|
|
||||||
.searchMessageBar {
|
|
||||||
padding: 10px;
|
|
||||||
width: 300px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input-field {
|
|
||||||
width: 300px;
|
|
||||||
|
|
||||||
border-radius: 10px;
|
|
||||||
|
|
||||||
/* margin-right: 85%; */
|
|
||||||
align-self: center;
|
|
||||||
border: none !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
outline: none !important;
|
|
||||||
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input-container {
|
|
||||||
/* IE10 */
|
|
||||||
display: flex;
|
|
||||||
width: 50%;
|
|
||||||
margin-left: 50%;
|
|
||||||
align-content: flex-end;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* View item message */
|
|
||||||
|
|
||||||
.viewItemRight {
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-top: 5px;
|
|
||||||
min-width: 100px;
|
|
||||||
max-width: 600px;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
align-self: flex-end;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #dcf8c6;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 8px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
box-shadow: 0 5px 5px #808888;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 40px;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
color: #203152;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewItemRight2 {
|
|
||||||
width: 315px;
|
|
||||||
padding: 8px;
|
|
||||||
height: auto;
|
|
||||||
background-color: #dcf8c6;
|
|
||||||
align-self: flex-end;
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 8px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
color: #203152;
|
|
||||||
box-shadow: 0 5px 5px #808888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewItemRight3 {
|
|
||||||
width: 300px;
|
|
||||||
height: auto;
|
|
||||||
align-self: flex-end;
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 8px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewWrapItemLeft {
|
|
||||||
/* width: 300px; */
|
|
||||||
text-align: left;
|
|
||||||
align-self: flex-start;
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewWrapItemRight {
|
|
||||||
width: 300px;
|
|
||||||
align-self: flex-end;
|
|
||||||
text-align: left;
|
|
||||||
/* margin-left: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: -15px; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewWrapItemLeft3 {
|
|
||||||
flex-direction: row;
|
|
||||||
display: flex;
|
|
||||||
width: 340px;
|
|
||||||
margin-bottom: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewItemLeft {
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 5px;
|
|
||||||
min-width: 100px;
|
|
||||||
max-width: 600px;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
background-color: #ffffff;
|
|
||||||
align-self: flex-start;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 8px;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 40px;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
color: #303030;
|
|
||||||
box-shadow: 0 5px 5px #808888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewItemLeft2 {
|
|
||||||
width: 315px;
|
|
||||||
padding: 8px;
|
|
||||||
height: auto;
|
|
||||||
background-color: #ffffff;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 8px;
|
|
||||||
color: #203152;
|
|
||||||
box-shadow: 0 5px 5px #808888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewItemLeft3 {
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 300px;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timesetup {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peerAvatarLeft {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 15px;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
object-fit: cover;
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewPaddingLeft {
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Item text */
|
|
||||||
|
|
||||||
.textContentItem {
|
|
||||||
font-size: 16px;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
padding: 0px 50px 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timestamp {
|
|
||||||
font-size: 11px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 5px;
|
|
||||||
right: 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewListContentChat div:last-child {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Item image */
|
|
||||||
|
|
||||||
.imgItemRight {
|
|
||||||
object-fit: cover;
|
|
||||||
width: 300px;
|
|
||||||
height: 300px;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 8px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.imgItemLeft {
|
|
||||||
object-fit: cover;
|
|
||||||
width: 290px;
|
|
||||||
height: 300px;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
align-self: center;
|
|
||||||
font: italic small-caps bold 15px/30px Georgia, serif;
|
|
||||||
width: 110px;
|
|
||||||
background-color: #e1f3fb;
|
|
||||||
margin: 10px;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textTime {
|
|
||||||
color: #808888;
|
|
||||||
font-size: 12px;
|
|
||||||
font-style: italic;
|
|
||||||
align-self: center;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stickers */
|
|
||||||
|
|
||||||
.viewStickers {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 90px;
|
|
||||||
border-top: 1px solid #e8e8e8;
|
|
||||||
overflow-x: scroll;
|
|
||||||
}
|
|
||||||
.viewStickers::-webkit-scrollbar-track {
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewStickers::-webkit-scrollbar {
|
|
||||||
width: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewStickers::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.imgSticker {
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Say hi */
|
|
||||||
|
|
||||||
.viewWrapSayHi {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textSayHi {
|
|
||||||
color: #808888;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
@@ -1,566 +0,0 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
|
||||||
import InfiniteScrollReverse from "react-infinite-scroll-reverse";
|
|
||||||
import { Spinner } from "react-bootstrap";
|
|
||||||
import {
|
|
||||||
FiPaperclip,
|
|
||||||
FiSend,
|
|
||||||
FiTrash2,
|
|
||||||
FiSmile,
|
|
||||||
FiFastForward,
|
|
||||||
FiFile,
|
|
||||||
} from "react-icons/fi";
|
|
||||||
import { BsCheck, BsCheckAll, BsClock } from "react-icons/bs";
|
|
||||||
|
|
||||||
import { Picker } from "emoji-mart";
|
|
||||||
import ModalImage from "react-modal-image";
|
|
||||||
import moment from "moment-timezone";
|
|
||||||
|
|
||||||
import api from "../../util/api";
|
|
||||||
import openSocket from "socket.io-client";
|
|
||||||
import profileDefaultPic from "../../Images/profile_default.png";
|
|
||||||
import ReactAudioPlayer from "react-audio-player";
|
|
||||||
|
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
|
||||||
import "emoji-mart/css/emoji-mart.css";
|
|
||||||
import "./ChatBox.css";
|
|
||||||
|
|
||||||
const ChatBox = ({ currentPeerContact }) => {
|
|
||||||
const SERVER_URL = "http://localhost:8080/";
|
|
||||||
const contactId = currentPeerContact.id;
|
|
||||||
|
|
||||||
const userId = localStorage.getItem("userId");
|
|
||||||
const username = localStorage.getItem("username");
|
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
const mediaInitialState = { preview: "", raw: "", name: "" };
|
|
||||||
const [inputMessage, setInputMessage] = useState("");
|
|
||||||
const [media, setMedia] = useState(mediaInitialState);
|
|
||||||
const [showEmoji, setShowEmoji] = useState(false);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [listMessages, setListMessages] = useState([]);
|
|
||||||
const [hasMore, setHasMore] = useState(false);
|
|
||||||
const [searchParam, setSearchParam] = useState("");
|
|
||||||
const [pageNumber, setPageNumber] = useState(0);
|
|
||||||
const lastMessageRef = useRef();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setListMessages([]);
|
|
||||||
}, [searchParam]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(true);
|
|
||||||
const delayDebounceFn = setTimeout(() => {
|
|
||||||
console.log(searchParam);
|
|
||||||
const fetchMessages = async () => {
|
|
||||||
try {
|
|
||||||
const res = await api.get("/messages/" + contactId, {
|
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
params: { searchParam, pageNumber },
|
|
||||||
});
|
|
||||||
setListMessages(prevMessages => {
|
|
||||||
return [...res.data.messages, ...prevMessages];
|
|
||||||
});
|
|
||||||
setHasMore(res.data.messages.length > 0);
|
|
||||||
setLoading(false);
|
|
||||||
console.log(res.data);
|
|
||||||
if (pageNumber === 1 && res.data.messages.length > 0) {
|
|
||||||
scrollToBottom();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
alert(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fetchMessages();
|
|
||||||
}, 1000);
|
|
||||||
return () => clearTimeout(delayDebounceFn);
|
|
||||||
}, [searchParam, pageNumber, contactId, token]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const socket = openSocket(SERVER_URL);
|
|
||||||
|
|
||||||
socket.emit("joinChatBox", contactId, () => {});
|
|
||||||
|
|
||||||
socket.on("appMessage", data => {
|
|
||||||
if (data.action === "create") {
|
|
||||||
addMessage(data.message);
|
|
||||||
scrollToBottom();
|
|
||||||
} else if (data.action === "update") {
|
|
||||||
updateMessageAck(data.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
socket.disconnect();
|
|
||||||
setInputMessage("");
|
|
||||||
setSearchParam("");
|
|
||||||
setShowEmoji(false);
|
|
||||||
setPageNumber(1);
|
|
||||||
setMedia({});
|
|
||||||
setListMessages([]);
|
|
||||||
};
|
|
||||||
}, [contactId]);
|
|
||||||
|
|
||||||
const loadMore = () => {
|
|
||||||
setPageNumber(prevPageNumber => prevPageNumber + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateMessageAck = message => {
|
|
||||||
let id = message.id;
|
|
||||||
setListMessages(prevState => {
|
|
||||||
let aux = [...prevState];
|
|
||||||
let messageIndex = aux.findIndex(message => message.id === id);
|
|
||||||
aux[messageIndex].ack = message.ack;
|
|
||||||
|
|
||||||
return aux;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
|
||||||
if (lastMessageRef) {
|
|
||||||
lastMessageRef.current.scrollIntoView({});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const addMessage = message => {
|
|
||||||
setListMessages(prevState => {
|
|
||||||
if (prevState.length >= 20) {
|
|
||||||
let aux = [...prevState];
|
|
||||||
aux.shift();
|
|
||||||
aux.push(message);
|
|
||||||
return aux;
|
|
||||||
} else {
|
|
||||||
return [...prevState, message];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeInput = e => {
|
|
||||||
setInputMessage(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddEmoji = e => {
|
|
||||||
let emoji = e.native;
|
|
||||||
setInputMessage(prevState => prevState + emoji);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeMedia = e => {
|
|
||||||
if (e.target.files.length) {
|
|
||||||
setMedia({
|
|
||||||
preview: URL.createObjectURL(e.target.files[0]),
|
|
||||||
raw: e.target.files[0],
|
|
||||||
name: e.target.files[0].name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputPaste = e => {
|
|
||||||
if (e.clipboardData.files[0]) {
|
|
||||||
setMedia({
|
|
||||||
preview: URL.createObjectURL(e.clipboardData.files[0]),
|
|
||||||
raw: e.clipboardData.files[0],
|
|
||||||
name: e.clipboardData.files[0].name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUploadMedia = async e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("media", media.raw);
|
|
||||||
formData.append("userId", userId);
|
|
||||||
formData.append("messageBody", media.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await api.post(`/messages/${contactId}`, formData, {
|
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
alert(err);
|
|
||||||
}
|
|
||||||
setMedia(mediaInitialState);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSendMessage = async () => {
|
|
||||||
if (inputMessage.trim() === "") return;
|
|
||||||
const message = {
|
|
||||||
read: 1,
|
|
||||||
userId: userId,
|
|
||||||
mediaUrl: "",
|
|
||||||
messageBody: `${username}: ${inputMessage.trim()}`,
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
await api.post(`/messages/${contactId}`, message, {
|
|
||||||
headers: { Authorization: "Bearer " + token },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
alert(err);
|
|
||||||
}
|
|
||||||
setInputMessage("");
|
|
||||||
setShowEmoji(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = e => {
|
|
||||||
setSearchParam(e.target.value);
|
|
||||||
setPageNumber(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkMessageDay = (message, index) => {
|
|
||||||
if (index < listMessages.length - 1) {
|
|
||||||
let messageDay = moment(listMessages[index].createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("DD");
|
|
||||||
|
|
||||||
let nextMessageDay = moment(listMessages[index + 1].createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("DD");
|
|
||||||
|
|
||||||
if (messageDay < nextMessageDay) {
|
|
||||||
return (
|
|
||||||
<span className="textTime" key={message.createdAt}>
|
|
||||||
<div className="time">
|
|
||||||
{moment(listMessages[index + 1].createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("DD/MM/YY")}
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index + 1 === listMessages.length) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={`ref-${message.createdAt}`}
|
|
||||||
ref={lastMessageRef}
|
|
||||||
style={{ float: "left", clear: "both" }}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderMsgAck = message => {
|
|
||||||
//todo remove timestamp logic from main return and adopt moment to timestamps
|
|
||||||
if (message.ack === 0) {
|
|
||||||
return <BsClock size="18" />;
|
|
||||||
} else if (message.ack === 1) {
|
|
||||||
return <BsCheck size="18" />;
|
|
||||||
} else if (message.ack === 2) {
|
|
||||||
return <BsCheckAll size="18" />;
|
|
||||||
} else if (message.ack === 3) {
|
|
||||||
return <BsCheckAll size="18" color="green" />;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderMessages = () => {
|
|
||||||
if (listMessages.length > 0) {
|
|
||||||
let viewListMessages = [];
|
|
||||||
listMessages.forEach((message, index) => {
|
|
||||||
// mensagens recebidas
|
|
||||||
if (message.userId === 0) {
|
|
||||||
if (message.mediaUrl && message.mediaType === "image") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemLeft2" key={message.id}>
|
|
||||||
<ModalImage
|
|
||||||
className="imgItemLeft"
|
|
||||||
smallSrcSet={message.mediaUrl}
|
|
||||||
medium={message.mediaUrl}
|
|
||||||
large={message.mediaUrl}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<div className="textContentItem">
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl && message.mediaType === "audio") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemLeft2" key={message.id}>
|
|
||||||
<ReactAudioPlayer
|
|
||||||
src={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
controls
|
|
||||||
/>
|
|
||||||
<div className="textContentItem">
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl && message.mediaType === "video") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemLeft2" key={message.id}>
|
|
||||||
<video
|
|
||||||
className="imgItemLeft"
|
|
||||||
src={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
controls
|
|
||||||
/>
|
|
||||||
<div className="textContentItem">
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl) {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemLeft" key={message.id}>
|
|
||||||
<div className="textContentItem">
|
|
||||||
<a
|
|
||||||
href={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
className="textContentItem"
|
|
||||||
>
|
|
||||||
{message.messageBody}
|
|
||||||
<FiFile size="20" />
|
|
||||||
</a>
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemLeft" key={message.id}>
|
|
||||||
<div className="textContentItem">
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} // mensagens enviadas
|
|
||||||
else {
|
|
||||||
if (message.mediaUrl && message.mediaType === "image") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemRight2" key={message.id}>
|
|
||||||
<ModalImage
|
|
||||||
className="imgItemRight"
|
|
||||||
smallSrcSet={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
medium={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
large={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<div className="textContentItem">
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}{" "}
|
|
||||||
{renderMsgAck(message)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl && message.mediaType === "audio") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemRight2 " key={message.id}>
|
|
||||||
<ReactAudioPlayer
|
|
||||||
src={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
controls
|
|
||||||
/>
|
|
||||||
<div className="textContetItem">
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}{" "}
|
|
||||||
{renderMsgAck(message)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl && message.mediaType === "video") {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemRight2" key={message.id}>
|
|
||||||
<video src={`${SERVER_URL}${message.mediaUrl}`} controls />
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}{" "}
|
|
||||||
{renderMsgAck(message)}
|
|
||||||
</span>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else if (message.mediaUrl) {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemRight" key={message.id}>
|
|
||||||
<div className="textContentItem">
|
|
||||||
<a
|
|
||||||
href={`${SERVER_URL}${message.mediaUrl}`}
|
|
||||||
className="textContentItem"
|
|
||||||
>
|
|
||||||
{message.messageBody}
|
|
||||||
<FiFile size="20" />
|
|
||||||
</a>
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}{" "}
|
|
||||||
{renderMsgAck(message)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
viewListMessages.push(
|
|
||||||
<div className="viewItemRight" key={message.id}>
|
|
||||||
<div className="textContentItem">
|
|
||||||
{message.messageBody}
|
|
||||||
<span className="timestamp">
|
|
||||||
{moment(message.createdAt)
|
|
||||||
.tz("America/Sao_Paulo")
|
|
||||||
.format("HH:mm")}{" "}
|
|
||||||
{renderMsgAck(message)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
checkMessageDay(message, index)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return viewListMessages;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div className="viewWrapSayHi">
|
|
||||||
<span className="textSayHi">Diga olá para o seu novo contato</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(listMessages);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="viewChatBoard">
|
|
||||||
<div className="headerChatBoard">
|
|
||||||
<img
|
|
||||||
className="viewAvatarItem"
|
|
||||||
src={currentPeerContact.imageURL || profileDefaultPic}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<span className="textHeaderChatBoard">
|
|
||||||
<p style={{ fontSize: "20px" }}>{currentPeerContact.name}</p>
|
|
||||||
</span>
|
|
||||||
<div className="aboutme">
|
|
||||||
<span>
|
|
||||||
<p>Status do contato</p>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="search-input-container">
|
|
||||||
<input
|
|
||||||
className="search-input-field"
|
|
||||||
type="text"
|
|
||||||
placeholder="Buscar Mensagens"
|
|
||||||
onChange={handleSearch}
|
|
||||||
value={searchParam}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<InfiniteScrollReverse
|
|
||||||
className="viewListContentChat"
|
|
||||||
hasMore={hasMore}
|
|
||||||
isLoading={loading}
|
|
||||||
loadMore={loadMore}
|
|
||||||
loadArea={10}
|
|
||||||
>
|
|
||||||
{listMessages.length > 0 ? renderMessages() : []}
|
|
||||||
</InfiniteScrollReverse>
|
|
||||||
|
|
||||||
{media.preview ? (
|
|
||||||
<div className="viewMediaBottom">
|
|
||||||
<FiTrash2
|
|
||||||
color="gray"
|
|
||||||
className="icOpenGallery"
|
|
||||||
onClick={e => setMedia(mediaInitialState)}
|
|
||||||
/>
|
|
||||||
<span className="viewMediaInput">
|
|
||||||
{media.name}
|
|
||||||
{/* <img src={media.preview} alt=""></img> */}
|
|
||||||
</span>
|
|
||||||
<FiFastForward
|
|
||||||
color="gray"
|
|
||||||
className="icSend"
|
|
||||||
onClick={handleUploadMedia}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="viewBottom">
|
|
||||||
<div>
|
|
||||||
{showEmoji ? (
|
|
||||||
<div className="viewStickers">
|
|
||||||
<Picker onSelect={handleAddEmoji} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<FiSmile
|
|
||||||
color="gray"
|
|
||||||
className="icOpenEmojis"
|
|
||||||
onClick={e => setShowEmoji(prevState => !prevState)}
|
|
||||||
/>
|
|
||||||
<label htmlFor="upload-button">
|
|
||||||
<FiPaperclip color="gray" className="icOpenGallery" />
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
id="upload-button"
|
|
||||||
style={{ display: "none" }}
|
|
||||||
onChange={handleChangeMedia}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
// ref={input => inputMessage && inputMessage.focus()}
|
|
||||||
name="inputMessage"
|
|
||||||
autoComplete="off"
|
|
||||||
className="viewInput"
|
|
||||||
placeholder="Digite uma mensagem"
|
|
||||||
onPaste={handleInputPaste}
|
|
||||||
value={inputMessage}
|
|
||||||
onChange={handleChangeInput}
|
|
||||||
onKeyPress={e => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handleSendMessage();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FiSend color="gray" className="icSend" onClick={handleSendMessage} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{loading ? (
|
|
||||||
<div className="viewLoading">
|
|
||||||
<Spinner animation="border" variant="success" />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ChatBox;
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
import { useHistory } from "react-router-dom";
|
|
||||||
import api from "../../util/api";
|
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
@@ -17,6 +15,8 @@ import Typography from "@material-ui/core/Typography";
|
|||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Container from "@material-ui/core/Container";
|
import Container from "@material-ui/core/Container";
|
||||||
|
|
||||||
|
import { AuthContext } from "../../Context/Auth/AuthContext";
|
||||||
|
|
||||||
const Copyright = () => {
|
const Copyright = () => {
|
||||||
return (
|
return (
|
||||||
<Typography variant="body2" color="textSecondary" align="center">
|
<Typography variant="body2" color="textSecondary" align="center">
|
||||||
@@ -51,27 +51,11 @@ const useStyles = makeStyles(theme => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const Login = ({ showToast }) => {
|
const Login = ({ showToast }) => {
|
||||||
const [user, setUser] = useState({ email: "", password: "" });
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const handleLogin = async e => {
|
const [user, setUser] = useState({ email: "", password: "" });
|
||||||
e.preventDefault();
|
|
||||||
try {
|
const { handleLogin } = useContext(AuthContext);
|
||||||
const res = await api.post("/auth/login", user);
|
|
||||||
localStorage.setItem("token", res.data.token);
|
|
||||||
localStorage.setItem("username", res.data.username);
|
|
||||||
localStorage.setItem("userId", res.data.userId);
|
|
||||||
// const remainingMilliseconds = 60 * 60 * 1000;
|
|
||||||
// const expiryDate = new Date(new Date().getTime() + remainingMilliseconds);
|
|
||||||
// localStorage.setItem("expiryDate", expiryDate.toISOString());
|
|
||||||
showToast(1, "Login efetuado com sucesso");
|
|
||||||
history.push("/chat");
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeInput = e => {
|
const handleChangeInput = e => {
|
||||||
setUser({ ...user, [e.target.name]: e.target.value });
|
setUser({ ...user, [e.target.name]: e.target.value });
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ const useStyles = makeStyles(theme => ({
|
|||||||
const SignUp = () => {
|
const SignUp = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const [user, setUser] = useState({ name: "", email: "", password: "" });
|
const [user, setUser] = useState({ name: "", email: "", password: "" });
|
||||||
|
|
||||||
const handleChangeInput = e => {
|
const handleChangeInput = e => {
|
||||||
|
|||||||
79
frontend/src/pages/WhatsAuth/WhatsAuth.js
Normal file
79
frontend/src/pages/WhatsAuth/WhatsAuth.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import React from "react";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import MainDrawer from "../../components/Layout/MainDrawer";
|
||||||
|
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
|
import Container from "@material-ui/core/Container";
|
||||||
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
root: {
|
||||||
|
display: "flex",
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
appBarSpacer: theme.mixins.toolbar,
|
||||||
|
content: {
|
||||||
|
flexGrow: 1,
|
||||||
|
|
||||||
|
overflow: "auto",
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
// paddingTop: theme.spacing(4),
|
||||||
|
// paddingBottom: theme.spacing(4),
|
||||||
|
height: `calc(100% - 64px)`,
|
||||||
|
},
|
||||||
|
paper: {
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
display: "flex",
|
||||||
|
overflow: "auto",
|
||||||
|
flexDirection: "column",
|
||||||
|
},
|
||||||
|
fixedHeight: {
|
||||||
|
height: 640,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const WhatsAuth = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
const fixedHeightPaper = clsx(classes.paper, classes.fixedHeight);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<MainDrawer appTitle="QR Code">
|
||||||
|
<div className={classes.root}>
|
||||||
|
<main className={classes.content}>
|
||||||
|
<div className={classes.appBarSpacer} />
|
||||||
|
<Container maxWidth="lg" className={classes.container}>
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<h4>Status da conexão</h4>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Paper className={fixedHeightPaper}>
|
||||||
|
<h1>QR Code</h1>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
{/* <Grid item xs={12} md={4} lg={3}>
|
||||||
|
<Paper className={fixedHeightPaper}>
|
||||||
|
<h1>paper2</h1>
|
||||||
|
</Paper>
|
||||||
|
</Grid> */}
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</MainDrawer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WhatsAuth;
|
||||||
70
frontend/src/routes.js
Normal file
70
frontend/src/routes.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import React, { useContext } from "react";
|
||||||
|
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
|
||||||
|
|
||||||
|
import { AuthContext, AuthProvider } from "./Context/Auth/AuthContext";
|
||||||
|
|
||||||
|
import Dashboard from "./pages/Home/Dashboard";
|
||||||
|
import Chat from "./pages/Chat/Chat";
|
||||||
|
import Profile from "./pages/Profile/Profile";
|
||||||
|
import Signup from "./pages/Signup/Signup";
|
||||||
|
import Login from "./pages/Login/Login";
|
||||||
|
import WhatsAuth from "./pages/WhatsAuth/WhatsAuth";
|
||||||
|
|
||||||
|
const PrivateRoute = ({ component: Component, ...rest }) => {
|
||||||
|
const { isAuth, loading } = useContext(AuthContext);
|
||||||
|
|
||||||
|
if (loading) return <h1>Loading...</h1>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
{...rest}
|
||||||
|
render={props =>
|
||||||
|
isAuth ? (
|
||||||
|
<Component {...props} />
|
||||||
|
) : (
|
||||||
|
<Redirect
|
||||||
|
to={{ pathname: "/login", state: { from: props.location } }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PublicRoute = ({ component: Component, ...rest }) => {
|
||||||
|
const { isAuth, loading } = useContext(AuthContext);
|
||||||
|
|
||||||
|
if (loading) return <h1>Loading...</h1>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
{...rest}
|
||||||
|
render={props =>
|
||||||
|
!isAuth ? (
|
||||||
|
<Component {...props} />
|
||||||
|
) : (
|
||||||
|
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Routes = () => {
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<AuthProvider>
|
||||||
|
<Switch>
|
||||||
|
<PrivateRoute exact path="/" component={Dashboard} />
|
||||||
|
<PrivateRoute exact path="/chat" component={Chat} />
|
||||||
|
<PrivateRoute exact path="/profile" component={Profile} />
|
||||||
|
<PrivateRoute exact path="/whats-auth" component={WhatsAuth} />
|
||||||
|
<PublicRoute exact path="/login" component={Login} />
|
||||||
|
<PublicRoute exact path="/signup" component={Signup} />
|
||||||
|
</Switch>
|
||||||
|
</AuthProvider>
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Routes;
|
||||||
Reference in New Issue
Block a user