From 5a6c3b6b14f5a37a7cdc4dfca46cf52b1b71ae03 Mon Sep 17 00:00:00 2001 From: canove Date: Wed, 22 Jul 2020 17:18:39 -0300 Subject: [PATCH] Finished styles and pagination of contacts page --- backend/src/controllers/ContactController.js | 30 +- frontend/src/App.js | 18 +- frontend/src/pages/Contacts/ContactsList.js | 192 +++++++++++ .../src/pages/Contacts/PaginationActions.js | 71 ++++ frontend/src/pages/Contacts/index.js | 326 ------------------ frontend/src/routes.js | 4 +- 6 files changed, 301 insertions(+), 340 deletions(-) create mode 100644 frontend/src/pages/Contacts/ContactsList.js create mode 100644 frontend/src/pages/Contacts/PaginationActions.js delete mode 100644 frontend/src/pages/Contacts/index.js 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 = () => { - +