diff --git a/backend/src/controllers/ContactController.js b/backend/src/controllers/ContactController.js
index de46f8b..1e5d363 100644
--- a/backend/src/controllers/ContactController.js
+++ b/backend/src/controllers/ContactController.js
@@ -1,3 +1,5 @@
+const Sequelize = require("sequelize");
+
const Contact = require("../models/Contact");
// const Message = require("../models/Message");
// const Sequelize = require("sequelize");
@@ -5,23 +7,29 @@ const Contact = require("../models/Contact");
// const { getWbot } = require("../libs/wbot");
exports.index = async (req, res) => {
- // const { searchParam = "" } = req.query;
+ const { searchParam = "", pageNumber = 1, rowsPerPage = 10 } = req.query;
- // const lowerSerachParam = searchParam.toLowerCase();
+ const whereCondition = {
+ name: Sequelize.where(
+ Sequelize.fn("LOWER", Sequelize.col("name")),
+ "LIKE",
+ "%" + searchParam.toLowerCase() + "%"
+ ),
+ };
- // const whereCondition = {
- // name: Sequelize.where(
- // Sequelize.fn("LOWER", Sequelize.col("name")),
- // "LIKE",
- // "%" + lowerSerachParam + "%"
- // ),
- // };
+ let limit = +rowsPerPage;
+ let offset = limit * (pageNumber - 1);
//todo >> add contact number to search where condition
- const contacts = await Contact.findAll();
+ const { count, rows: contacts } = await Contact.findAndCountAll({
+ where: whereCondition,
+ limit,
+ offset,
+ order: [["createdAt", "DESC"]],
+ });
- return res.json(contacts);
+ return res.json({ contacts, count });
};
exports.store = async (req, res) => {
diff --git a/frontend/src/App.js b/frontend/src/App.js
index f3b4b50..032c7b3 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -2,8 +2,24 @@ import React from "react";
import Routes from "./routes";
import "dotenv/config";
+import { createMuiTheme, ThemeProvider } from "@material-ui/core/styles";
+import { ptBR } from "@material-ui/core/locale";
+
+const theme = createMuiTheme(
+ {
+ palette: {
+ primary: { main: "#1976d2" },
+ },
+ },
+ ptBR
+);
+
const App = () => {
- return ;
+ return (
+
+
+
+ );
};
export default App;
diff --git a/frontend/src/pages/Contacts/ContactsList.js b/frontend/src/pages/Contacts/ContactsList.js
new file mode 100644
index 0000000..76c8bd7
--- /dev/null
+++ b/frontend/src/pages/Contacts/ContactsList.js
@@ -0,0 +1,192 @@
+import React, { useState, useEffect } from "react";
+
+import { makeStyles } from "@material-ui/core/styles";
+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 Button from "@material-ui/core/Button";
+import Avatar from "@material-ui/core/Avatar";
+import TableFooter from "@material-ui/core/TableFooter";
+import TablePagination from "@material-ui/core/TablePagination";
+import SearchIcon from "@material-ui/icons/Search";
+import TextField from "@material-ui/core/TextField";
+import Container from "@material-ui/core/Container";
+import InputAdornment from "@material-ui/core/InputAdornment";
+
+import IconButton from "@material-ui/core/IconButton";
+import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
+import EditIcon from "@material-ui/icons/Edit";
+
+import PaginationActions from "./PaginationActions";
+import api from "../../util/api";
+
+const useStyles = makeStyles(theme => ({
+ mainContainer: {
+ flex: 1,
+ // backgroundColor: "#eee",
+ padding: theme.spacing(2),
+ height: `calc(100% - 48px)`,
+ overflowY: "hidden",
+ },
+
+ contactsHeader: {
+ display: "flex",
+ alignItems: "center",
+ padding: "0px 6px 6px 6px",
+ },
+
+ actionButtons: {
+ marginLeft: "auto",
+ "& > *": {
+ margin: theme.spacing(1),
+ },
+ },
+
+ mainPaper: {
+ height: "87%",
+ padding: theme.spacing(2),
+
+ overflowY: "scroll",
+ "&::-webkit-scrollbar": {
+ width: "8px",
+ },
+ "&::-webkit-scrollbar-thumb": {
+ // borderRadius: "2px",
+ boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
+ backgroundColor: "#e8e8e8",
+ },
+ },
+}));
+
+const Contacts = () => {
+ const classes = useStyles();
+
+ const token = localStorage.getItem("token");
+ const userId = localStorage.getItem("userId");
+
+ const [loading, setLoading] = useState(true);
+ const [page, setPage] = useState(0);
+ const [rowsPerPage, setRowsPerPage] = useState(10);
+ const [count, setCount] = useState(0);
+ const [searchParam, setSearchParam] = useState("");
+ const [contacts, setContacts] = useState([]);
+
+ useEffect(() => {
+ setLoading(true);
+ const delayDebounceFn = setTimeout(() => {
+ const fetchContacts = async () => {
+ try {
+ const res = await api.get("/contacts/", {
+ params: { searchParam, pageNumber: page + 1, rowsPerPage },
+ });
+ setContacts(res.data.contacts);
+ setCount(res.data.count);
+ setLoading(false);
+ } catch (err) {
+ console.log(err);
+ alert(err);
+ }
+ };
+ fetchContacts();
+ }, 1000);
+ return () => clearTimeout(delayDebounceFn);
+ }, [searchParam, page, token, rowsPerPage]);
+
+ const handleChangePage = (event, newPage) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = event => {
+ setRowsPerPage(+event.target.value);
+ setPage(0);
+ };
+
+ const handleSearch = event => {
+ setSearchParam(event.target.value.toLowerCase());
+ };
+
+ return (
+
+
+
Todos os contatos
+
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ Nome
+ Telefone
+ Email
+ Ações
+
+
+
+ {contacts.map(contact => (
+
+
+ {}
+
+ {contact.name}
+ {contact.number}
+ {contact.updatedAt}
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Contacts;
diff --git a/frontend/src/pages/Contacts/PaginationActions.js b/frontend/src/pages/Contacts/PaginationActions.js
new file mode 100644
index 0000000..854eae7
--- /dev/null
+++ b/frontend/src/pages/Contacts/PaginationActions.js
@@ -0,0 +1,71 @@
+import React from "react";
+
+import { makeStyles } from "@material-ui/core/styles";
+
+import FirstPageIcon from "@material-ui/icons/FirstPage";
+import KeyboardArrowLeft from "@material-ui/icons/KeyboardArrowLeft";
+import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight";
+import LastPageIcon from "@material-ui/icons/LastPage";
+import IconButton from "@material-ui/core/IconButton";
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ flexShrink: 0,
+ marginLeft: theme.spacing(2.5),
+ },
+}));
+
+const PaginationActions = ({ count, page, rowsPerPage, onChangePage }) => {
+ const classes = useStyles();
+
+ const handleFirstPageButtonClick = event => {
+ onChangePage(event, 0);
+ };
+
+ const handleBackButtonClick = event => {
+ onChangePage(event, page - 1);
+ };
+
+ const handleNextButtonClick = event => {
+ onChangePage(event, page + 1);
+ };
+
+ const handleLastPageButtonClick = event => {
+ onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
+ };
+
+ return (
+
+
+ {}
+
+
+ {}
+
+ = Math.ceil(count / rowsPerPage) - 1}
+ aria-label="next page"
+ >
+ {}
+
+ = Math.ceil(count / rowsPerPage) - 1}
+ aria-label="last page"
+ >
+ {}
+
+
+ );
+};
+
+export default PaginationActions;
diff --git a/frontend/src/pages/Contacts/index.js b/frontend/src/pages/Contacts/index.js
deleted file mode 100644
index 0b7454d..0000000
--- a/frontend/src/pages/Contacts/index.js
+++ /dev/null
@@ -1,326 +0,0 @@
-import React, { useState, useEffect } from "react";
-
-import Link from "@material-ui/core/Link";
-import { makeStyles } from "@material-ui/core/styles";
-import TableContainer from "@material-ui/core/TableContainer";
-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 Grid from "@material-ui/core/Grid";
-import Paper from "@material-ui/core/Paper";
-import Button from "@material-ui/core/Button";
-import Avatar from "@material-ui/core/Avatar";
-import TableFooter from "@material-ui/core/TableFooter";
-import TablePagination from "@material-ui/core/TablePagination";
-import FirstPageIcon from "@material-ui/icons/FirstPage";
-import KeyboardArrowLeft from "@material-ui/icons/KeyboardArrowLeft";
-import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight";
-import LastPageIcon from "@material-ui/icons/LastPage";
-
-import IconButton from "@material-ui/core/IconButton";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import EditIcon from "@material-ui/icons/Edit";
-
-const useStyles1 = makeStyles(theme => ({
- root: {
- flexShrink: 0,
- marginLeft: theme.spacing(2.5),
- },
-}));
-
-const TablePaginationActions = ({ count, page, rowsPerPage, onChangePage }) => {
- const classes = useStyles1();
-
- const handleFirstPageButtonClick = event => {
- onChangePage(event, 0);
- };
-
- const handleBackButtonClick = event => {
- onChangePage(event, page - 1);
- };
-
- const handleNextButtonClick = event => {
- onChangePage(event, page + 1);
- };
-
- const handleLastPageButtonClick = event => {
- onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
- };
-
- return (
-
-
- {}
-
-
- {}
-
- = Math.ceil(count / rowsPerPage) - 1}
- aria-label="next page"
- >
- {}
-
- = Math.ceil(count / rowsPerPage) - 1}
- aria-label="last page"
- >
- {}
-
-
- );
-};
-
-const useStyles = makeStyles(theme => ({
- mainContainer: {
- flex: 1,
- // backgroundColor: "#eee",
- padding: theme.spacing(4),
- height: `calc(100% - 48px)`,
- overflowY: "hidden",
- },
-
- contactsHeader: {
- display: "flex",
- alignItems: "center",
- padding: "0px 6px 6px 6px",
- },
-
- actionButtons: {
- marginLeft: "auto",
- "& > *": {
- margin: theme.spacing(0.5),
- },
- },
-
- mainPaper: {
- height: "100%",
- overflowY: "scroll",
- },
-}));
-
-const Contacts = () => {
- const classes = useStyles();
- const [page, setPage] = useState(0);
- const [rowsPerPage, setRowsPerPage] = useState(5);
- const [contacts, setContacts] = useState([
- // {
- // id: 1,
- // name: "Cassio",
- // number: "5513991428988",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/69475768_2460671290686732_6259438857054322688_n.jpg?oh=ec972d658eae256f9d0675852d8cf9a3&oe=5F1CDD33",
- // createdAt: "2020-07-17T16:16:59.000Z",
- // updatedAt: "2020-07-22T12:23:58.000Z",
- // },
- // {
- // id: 2,
- // name: "Luana",
- // number: "5513991264923",
- // profilePicUrl: null,
- // createdAt: "2020-07-17T17:48:01.000Z",
- // updatedAt: "2020-07-17T17:48:01.000Z",
- // },
- // {
- // id: 3,
- // name: "551333074319",
- // number: "551333074319",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/56106113_757880717947097_7376625555153616896_n.jpg?oh=287b4d0de2810cca361af7eaa1381076&oe=5F1ABC3A",
- // createdAt: "2020-07-17T18:13:15.000Z",
- // updatedAt: "2020-07-20T19:44:33.000Z",
- // },
- // {
- // id: 1,
- // name: "Cassio",
- // number: "5513991428988",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/69475768_2460671290686732_6259438857054322688_n.jpg?oh=ec972d658eae256f9d0675852d8cf9a3&oe=5F1CDD33",
- // createdAt: "2020-07-17T16:16:59.000Z",
- // updatedAt: "2020-07-22T12:23:58.000Z",
- // },
- // {
- // id: 2,
- // name: "Luana",
- // number: "5513991264923",
- // profilePicUrl: null,
- // createdAt: "2020-07-17T17:48:01.000Z",
- // updatedAt: "2020-07-17T17:48:01.000Z",
- // },
- // {
- // id: 3,
- // name: "551333074319",
- // number: "551333074319",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/56106113_757880717947097_7376625555153616896_n.jpg?oh=287b4d0de2810cca361af7eaa1381076&oe=5F1ABC3A",
- // createdAt: "2020-07-17T18:13:15.000Z",
- // updatedAt: "2020-07-20T19:44:33.000Z",
- // },
- // {
- // id: 1,
- // name: "Cassio",
- // number: "5513991428988",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/69475768_2460671290686732_6259438857054322688_n.jpg?oh=ec972d658eae256f9d0675852d8cf9a3&oe=5F1CDD33",
- // createdAt: "2020-07-17T16:16:59.000Z",
- // updatedAt: "2020-07-22T12:23:58.000Z",
- // },
- // {
- // id: 2,
- // name: "Luana",
- // number: "5513991264923",
- // profilePicUrl: null,
- // createdAt: "2020-07-17T17:48:01.000Z",
- // updatedAt: "2020-07-17T17:48:01.000Z",
- // },
- // {
- // id: 3,
- // name: "551333074319",
- // number: "551333074319",
- // profilePicUrl:
- // "https://pps.whatsapp.net/v/t61.24694-24/56106113_757880717947097_7376625555153616896_n.jpg?oh=287b4d0de2810cca361af7eaa1381076&oe=5F1ABC3A",
- // createdAt: "2020-07-17T18:13:15.000Z",
- // updatedAt: "2020-07-20T19:44:33.000Z",
- // },
- {
- id: 1,
- name: "Cassio",
- number: "5513991428988",
- profilePicUrl:
- "https://pps.whatsapp.net/v/t61.24694-24/69475768_2460671290686732_6259438857054322688_n.jpg?oh=ec972d658eae256f9d0675852d8cf9a3&oe=5F1CDD33",
- createdAt: "2020-07-17T16:16:59.000Z",
- updatedAt: "2020-07-22T12:23:58.000Z",
- },
- {
- id: 2,
- name: "Luana",
- number: "5513991264923",
- profilePicUrl: null,
- createdAt: "2020-07-17T17:48:01.000Z",
- updatedAt: "2020-07-17T17:48:01.000Z",
- },
- {
- id: 3,
- name: "551333074319",
- number: "551333074319",
- profilePicUrl:
- "https://pps.whatsapp.net/v/t61.24694-24/56106113_757880717947097_7376625555153616896_n.jpg?oh=287b4d0de2810cca361af7eaa1381076&oe=5F1ABC3A",
- createdAt: "2020-07-17T18:13:15.000Z",
- updatedAt: "2020-07-20T19:44:33.000Z",
- },
- {
- id: 1,
- name: "Cassio",
- number: "5513991428988",
- profilePicUrl:
- "https://pps.whatsapp.net/v/t61.24694-24/69475768_2460671290686732_6259438857054322688_n.jpg?oh=ec972d658eae256f9d0675852d8cf9a3&oe=5F1CDD33",
- createdAt: "2020-07-17T16:16:59.000Z",
- updatedAt: "2020-07-22T12:23:58.000Z",
- },
- {
- id: 2,
- name: "Luana",
- number: "5513991264923",
- profilePicUrl: null,
- createdAt: "2020-07-17T17:48:01.000Z",
- updatedAt: "2020-07-17T17:48:01.000Z",
- },
- {
- id: 3,
- name: "551333074319",
- number: "551333074319",
- profilePicUrl:
- "https://pps.whatsapp.net/v/t61.24694-24/56106113_757880717947097_7376625555153616896_n.jpg?oh=287b4d0de2810cca361af7eaa1381076&oe=5F1ABC3A",
- createdAt: "2020-07-17T18:13:15.000Z",
- updatedAt: "2020-07-20T19:44:33.000Z",
- },
- ]);
-
- const handleChangePage = (event, newPage) => {
- setPage(newPage);
- };
-
- const handleChangeRowsPerPage = event => {
- setRowsPerPage(parseInt(event.target.value, 10));
- setPage(0);
- };
-
- return (
-
-
-
-
Todos os contatos
-
-
-
-
-
-
-
-
-
- Nome
- Telefone
- Email
- Ações
-
-
-
- {contacts.map(contact => (
-
- {}
- {contact.name}
- {contact.number}
- {contact.updatedAt}
-
-
-
-
-
-
-
-
-
- ))}
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Contacts;
diff --git a/frontend/src/routes.js b/frontend/src/routes.js
index 2a7690a..5c16fd5 100644
--- a/frontend/src/routes.js
+++ b/frontend/src/routes.js
@@ -12,7 +12,7 @@ import Profile from "./pages/Profile/Profile";
import Signup from "./pages/Signup/Signup";
import Login from "./pages/Login/Login";
import WhatsAuth from "./pages/WhatsAuth/WhatsAuth";
-import Contacts from "./pages/Contacts";
+import ContactsList from "./pages/Contacts/ContactsList";
import { AuthContext, AuthProvider } from "./Context/Auth/AuthContext";
const useStyles = makeStyles(theme => ({
@@ -86,7 +86,7 @@ const Routes = () => {
-
+