diff --git a/frontend/package.json b/frontend/package.json index 078c767..9c27aa8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "mic-recorder-to-mp3": "^2.2.2", "qrcode.react": "^1.0.0", "react": "^16.13.1", + "react-color": "^2.19.3", "react-dom": "^16.13.1", "react-modal-image": "^2.5.0", "react-router-dom": "^5.2.0", diff --git a/frontend/src/components/ColorPicker/index.js b/frontend/src/components/ColorPicker/index.js new file mode 100644 index 0000000..fdd5dbd --- /dev/null +++ b/frontend/src/components/ColorPicker/index.js @@ -0,0 +1,25 @@ +import React, { useState } from "react"; + +import { GithubPicker } from "react-color"; + +const ColorPicker = ({ onChange, currentColor }) => { + const [color, setColor] = useState(currentColor); + + const handleChange = color => { + setColor(color.hex); + }; + + return ( +
+ onChange(color.hex)} + /> +
+ ); +}; + +export default ColorPicker; diff --git a/frontend/src/components/ConfirmationModal/index.js b/frontend/src/components/ConfirmationModal/index.js index ce5681d..ce340f2 100644 --- a/frontend/src/components/ConfirmationModal/index.js +++ b/frontend/src/components/ConfirmationModal/index.js @@ -8,11 +8,11 @@ import Typography from "@material-ui/core/Typography"; import { i18n } from "../../translate/i18n"; -const ConfirmationModal = ({ title, children, open, setOpen, onConfirm }) => { +const ConfirmationModal = ({ title, children, open, onClose, onConfirm }) => { return ( setOpen(false)} + onClose={() => onClose(false)} aria-labelledby="confirm-dialog" > {title} @@ -22,7 +22,7 @@ const ConfirmationModal = ({ title, children, open, setOpen, onConfirm }) => { + + + + )} + + + + ); +}; + +export default QueueModal; diff --git a/frontend/src/components/TicketOptionsMenu/index.js b/frontend/src/components/TicketOptionsMenu/index.js index 8087a89..48d1035 100644 --- a/frontend/src/components/TicketOptionsMenu/index.js +++ b/frontend/src/components/TicketOptionsMenu/index.js @@ -76,7 +76,7 @@ const TicketOptionsMenu = ({ ticket, menuOpen, handleClose, anchorEl }) => { ticket.contact.name }?`} open={confirmationOpen} - setOpen={setConfirmationOpen} + onClose={setConfirmationOpen} onConfirm={handleDeleteTicket} > {i18n.t("ticketOptionsMenu.confirmationModal.message")} diff --git a/frontend/src/layout/MainListItems.js b/frontend/src/layout/MainListItems.js index cec6a3c..dcc22a6 100644 --- a/frontend/src/layout/MainListItems.js +++ b/frontend/src/layout/MainListItems.js @@ -7,12 +7,13 @@ import ListItemText from "@material-ui/core/ListItemText"; import ListSubheader from "@material-ui/core/ListSubheader"; import Divider from "@material-ui/core/Divider"; import { Badge } from "@material-ui/core"; -import DashboardIcon from "@material-ui/icons/Dashboard"; +import DashboardOutlinedIcon from "@material-ui/icons/DashboardOutlined"; import WhatsAppIcon from "@material-ui/icons/WhatsApp"; import SyncAltIcon from "@material-ui/icons/SyncAlt"; -import SettingsIcon from "@material-ui/icons/Settings"; -import GroupIcon from "@material-ui/icons/Group"; -import ContactPhoneIcon from "@material-ui/icons/ContactPhone"; +import SettingsOutlinedIcon from "@material-ui/icons/SettingsOutlined"; +import PeopleAltOutlinedIcon from "@material-ui/icons/PeopleAltOutlined"; +import ContactPhoneOutlinedIcon from "@material-ui/icons/ContactPhoneOutlined"; +import AccountTreeOutlinedIcon from "@material-ui/icons/AccountTreeOutlined"; import { i18n } from "../translate/i18n"; import { WhatsAppsContext } from "../context/WhatsApp/WhatsAppsContext"; @@ -69,7 +70,11 @@ const MainListItems = () => { return (
- } /> + } + /> { } + icon={} /> {userProfile === "admin" && ( <> @@ -99,12 +104,17 @@ const MainListItems = () => { } + icon={} + /> + } /> } + icon={} /> )} diff --git a/frontend/src/pages/Connections/index.js b/frontend/src/pages/Connections/index.js index f1f5fb0..8974ce2 100644 --- a/frontend/src/pages/Connections/index.js +++ b/frontend/src/pages/Connections/index.js @@ -294,7 +294,7 @@ const Connections = () => { {confirmModalInfo.message} diff --git a/frontend/src/pages/Contacts/index.js b/frontend/src/pages/Contacts/index.js index 302b846..7f12e2e 100644 --- a/frontend/src/pages/Contacts/index.js +++ b/frontend/src/pages/Contacts/index.js @@ -229,7 +229,7 @@ const Contacts = () => { : `${i18n.t("contacts.confirmationModal.importTitlte")}` } open={confirmOpen} - setOpen={setConfirmOpen} + onClose={setConfirmOpen} onConfirm={e => deletingContact ? handleDeleteContact(deletingContact.id) diff --git a/frontend/src/pages/Queues/index.js b/frontend/src/pages/Queues/index.js index b7e1581..b9d87ba 100644 --- a/frontend/src/pages/Queues/index.js +++ b/frontend/src/pages/Queues/index.js @@ -1,7 +1,206 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; + +import { + Button, + IconButton, + makeStyles, + Paper, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Typography, +} from "@material-ui/core"; + +import MainContainer from "../../components/MainContainer"; +import MainHeader from "../../components/MainHeader"; +import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper"; +import TableRowSkeleton from "../../components/TableRowSkeleton"; +import Title from "../../components/Title"; +import { i18n } from "../../translate/i18n"; +import toastError from "../../errors/toastError"; +import api from "../../services/api"; +import { DeleteOutline, Edit } from "@material-ui/icons"; +import QueueModal from "../../components/QueueModal"; +import { toast } from "react-toastify"; +import ConfirmationModal from "../../components/ConfirmationModal"; + +const useStyles = makeStyles(theme => ({ + mainPaper: { + flex: 1, + padding: theme.spacing(1), + overflowY: "scroll", + ...theme.scrollbarStyles, + }, + customTableCell: { + display: "flex", + + alignItems: "center", + justifyContent: "center", + }, +})); const Queues = () => { - return
; + const classes = useStyles(); + + const [queues, setQueue] = useState([]); + const [loading, setLoading] = useState(false); + + const [queueModalOpen, setQueueModalOpen] = useState(false); + const [selectedQueue, setSelectedQueue] = useState(null); + const [confirmModalOpen, setConfirmModalOpen] = useState(false); + + useEffect(() => { + (async () => { + setLoading(true); + try { + const { data } = await api.get("/queue"); + + setQueue(data); + setLoading(false); + } catch (err) { + toastError(err); + setLoading(false); + } + })(); + }, []); + + const handleOpenQueueModal = () => { + setQueueModalOpen(true); + setSelectedQueue(null); + }; + + const handleCloseQueueModal = () => { + setQueueModalOpen(false); + setSelectedQueue(null); + }; + + const handleEditQueue = queue => { + setSelectedQueue(queue); + setQueueModalOpen(true); + }; + + const handleCloseConfirmationModal = () => { + setConfirmModalOpen(false); + setSelectedQueue(null); + }; + + const handleDeleteQueue = async queueId => { + try { + await api.delete(`/queue/${queueId}`); + toast.success(i18n.t("Queue deleted successfully!")); + } catch (err) { + toastError(err); + } + setSelectedQueue(null); + }; + + return ( + + handleDeleteQueue(selectedQueue.id)} + > + {i18n.t("queues.confirmationModal.deleteMessage")} + + + + {i18n.t("queues.title")} + + + + + + + + + + {i18n.t("queues.table.name")} + + + {i18n.t("queues.table.color")} + + + {i18n.t("queues.table.greeting")} + + + {i18n.t("queues.table.actions")} + + + + + <> + {queues.map(queue => ( + + {queue.name} + +
+ +
+
+ +
+ + {queue.greetingMessage} + +
+
+ + handleEditQueue(queue)} + > + + + + { + setSelectedQueue(queue); + setConfirmModalOpen(true); + }} + > + + + +
+ ))} + {loading && } + +
+
+
+
+ ); }; export default Queues; diff --git a/frontend/src/pages/Users/index.js b/frontend/src/pages/Users/index.js index d8817a3..a457b5d 100644 --- a/frontend/src/pages/Users/index.js +++ b/frontend/src/pages/Users/index.js @@ -193,7 +193,7 @@ const Users = () => { }?` } open={confirmModalOpen} - setOpen={setConfirmModalOpen} + onClose={setConfirmModalOpen} onConfirm={() => handleDeleteUser(deletingUser.id)} > {i18n.t("users.confirmationModal.deleteMessage")} diff --git a/frontend/src/translate/languages/en.js b/frontend/src/translate/languages/en.js index 0ab8b46..fe73f7d 100644 --- a/frontend/src/translate/languages/en.js +++ b/frontend/src/translate/languages/en.js @@ -153,6 +153,22 @@ const messages = { }, success: "Contact saved successfully.", }, + queueModal: { + title: { + add: "Add queue", + edit: "Edit queue", + }, + form: { + name: "Name", + color: "Color", + greetingMessage: "Greeting Message", + }, + buttons: { + okAdd: "Add", + okEdit: "Save", + cancel: "Cancel", + }, + }, userModal: { title: { add: "Add user", @@ -226,6 +242,7 @@ const messages = { connections: "Connections", tickets: "Tickets", contacts: "Contacts", + queues: "Queues", administration: "Administration", users: "Users", settings: "Settings", @@ -240,6 +257,23 @@ const messages = { notifications: { noTickets: "No notifications.", }, + queues: { + title: "Queues", + table: { + name: "Name", + color: "Color", + greeting: "Greeting message", + actions: "Actions", + }, + buttons: { + add: "Add queue", + }, + confirmationModal: { + deleteTitle: "Delete", + deleteMessage: + "Are you sure? It cannot be reverted! Tickets in this queue will still exist, but will not have any queues assigned.", + }, + }, users: { title: "Users", table: { diff --git a/frontend/src/translate/languages/es.js b/frontend/src/translate/languages/es.js index dfdd70a..48a6519 100644 --- a/frontend/src/translate/languages/es.js +++ b/frontend/src/translate/languages/es.js @@ -156,6 +156,22 @@ const messages = { }, success: "Contacto guardado satisfactoriamente.", }, + queueModal: { + title: { + add: "Agregar cola", + edit: "Editar cola", + }, + form: { + name: "Nombre", + color: "Color", + greetingMessage: "Mensaje de saludo", + }, + buttons: { + okAdd: "Añadir", + okEdit: "Ahorrar", + cancel: "Cancelar", + }, + }, userModal: { title: { add: "Agregar usuario", @@ -230,6 +246,7 @@ const messages = { connections: "Conexiones", tickets: "Tickets", contacts: "Contactos", + queues: "Linhas", administration: "Administración", users: "Usuarios", settings: "Configuración", @@ -244,6 +261,23 @@ const messages = { notifications: { noTickets: "Sin notificaciones.", }, + queues: { + title: "Linhas", + table: { + name: "Nombre", + color: "Color", + greeting: "Mensaje de saludo", + actions: "Comportamiento", + }, + buttons: { + add: "Agregar cola", + }, + confirmationModal: { + deleteTitle: "Eliminar", + deleteMessage: + "¿Estás seguro? ¡Esta acción no se puede revertir! Los tickets en esa cola seguirán existiendo, pero ya no tendrán ninguna cola asignada.", + }, + }, users: { title: "Usuarios", table: { diff --git a/frontend/src/translate/languages/pt.js b/frontend/src/translate/languages/pt.js index f98eddc..4b04b8c 100644 --- a/frontend/src/translate/languages/pt.js +++ b/frontend/src/translate/languages/pt.js @@ -154,6 +154,22 @@ const messages = { }, success: "Contato salvo com sucesso.", }, + queueModal: { + title: { + add: "Adicionar fila", + edit: "Editar fila", + }, + form: { + name: "Nome", + color: "Cor", + greetingMessage: "Mensagem de saudação", + }, + buttons: { + okAdd: "Adicionar", + okEdit: "Salvar", + cancel: "Cancelar", + }, + }, userModal: { title: { add: "Adicionar usuário", @@ -228,6 +244,7 @@ const messages = { connections: "Conexões", tickets: "Tickets", contacts: "Contatos", + queues: "Filas", administration: "Administração", users: "Usuários", settings: "Configurações", @@ -242,6 +259,23 @@ const messages = { notifications: { noTickets: "Nenhuma notificação.", }, + queues: { + title: "Filas", + table: { + name: "Nome", + color: "Cor", + greeting: "Mensagem de saudação", + actions: "Ações", + }, + buttons: { + add: "Adicionar fila", + }, + confirmationModal: { + deleteTitle: "Excluir", + deleteMessage: + "Você tem certeza? Essa ação não pode ser revertida! Os tickets dessa fila continuarão existindo, mas não terão mais nenhuma fila atribuída.", + }, + }, users: { title: "Usuários", table: {