diff --git a/backend/src/app.js b/backend/src/app.js index 73e8dcd..e1b5df1 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -60,11 +60,11 @@ const startWhatsAppSessions = async () => { const whatsapps = await Whatsapp.findAll(); if (whatsapps.length > 0) { - whatsapps.forEach(dbSession => { - initWbot(dbSession) + whatsapps.forEach(whatsapp => { + initWbot(whatsapp) .then(() => { - wbotMessageListener(dbSession); - wbotMonitor(dbSession); + wbotMessageListener(whatsapp); + wbotMonitor(whatsapp); }) .catch(err => console.log(err)); }); @@ -72,14 +72,6 @@ const startWhatsAppSessions = async () => { }; startWhatsAppSessions(); -// wBot -// .init() -// .then(({ dbSession }) => { -// wbotMessageListener(); -// wbotMonitor(dbSession); -// }) -// .catch(err => console.log(err)); - app.use(Sentry.Handlers.errorHandler()); app.use(async (err, req, res, next) => { @@ -88,5 +80,6 @@ app.use(async (err, req, res, next) => { console.log(err); return res.status(500).json(errors); } + return res.status(500).json({ error: "Internal server error" }); }); diff --git a/backend/src/controllers/WhatsAppController.js b/backend/src/controllers/WhatsAppController.js new file mode 100644 index 0000000..75d1d68 --- /dev/null +++ b/backend/src/controllers/WhatsAppController.js @@ -0,0 +1,86 @@ +const Whatsapp = require("../models/Whatsapp"); +const { getIO } = require("../libs/socket"); +const { getWbot, initWbot, removeWbot } = require("../libs/wbot"); +const wbotMessageListener = require("../services/wbotMessageListener"); +const wbotMonitor = require("../services/wbotMonitor"); + +exports.index = async (req, res) => { + const whatsapp = await Whatsapp.findAll(); + + return res.status(200).json(whatsapp); +}; + +exports.store = async (req, res) => { + const io = getIO(); + const whatsapp = await Whatsapp.create(req.body); + + if (!whatsapp) { + return res.status(400).json({ error: "Cannot create whatsapp session." }); + } + + initWbot(whatsapp) + .then(() => { + wbotMessageListener(whatsapp); + wbotMonitor(whatsapp); + }) + .catch(err => console.log(err)); + + io.emit("whatsapp", { + action: "update", + whatsapp: whatsapp, + }); + + return res.status(200).json(whatsapp); +}; + +exports.show = async (req, res) => { + const { whatsappId } = req.params; + const whatsapp = await Whatsapp.findByPk(whatsappId); + + if (!whatsapp) { + return res.status(200).json({ message: "Session not found" }); + } + + return res.status(200).json(whatsapp); +}; + +exports.update = async (req, res) => { + const io = getIO(); + const { whatsappId } = req.params; + + const whatsapp = await Whatsapp.findByPk(whatsappId); + + if (!whatsapp) { + return res.status(404).json({ message: "Whatsapp not found" }); + } + + await whatsapp.update(req.body); + + io.emit("whatsapp", { + action: "update", + whatsapp: whatsapp, + }); + + return res.status(200).json({ message: "Whatsapp updated" }); +}; + +exports.delete = async (req, res) => { + const io = getIO(); + const { whatsappId } = req.params; + + const whatsapp = await Whatsapp.findByPk(whatsappId); + + if (!whatsapp) { + return res.status(404).json({ message: "Whatsapp not found" }); + } + + await whatsapp.destroy(); + removeWbot(whatsapp.id); + + io.emit("whatsapp", { + action: "delete", + whatsappId: whatsapp.id, + }); + + return res.status(200).json({ message: "Whatsapp deleted." }); +}; diff --git a/backend/src/controllers/WhatsAppSessionController.js b/backend/src/controllers/WhatsAppSessionController.js index 2eca860..0bee528 100644 --- a/backend/src/controllers/WhatsAppSessionController.js +++ b/backend/src/controllers/WhatsAppSessionController.js @@ -1,91 +1,32 @@ -const Whatsapp = require("../models/Whatsapp"); -const { getIO } = require("../libs/socket"); -const { getWbot, initWbot, removeWbot } = require("../libs/wbot"); -const wbotMessageListener = require("../services/wbotMessageListener"); -const wbotMonitor = require("../services/wbotMonitor"); +// const Whatsapp = require("../models/Whatsapp"); +// const { getIO } = require("../libs/socket"); +// const { getWbot, initWbot, removeWbot } = require("../libs/wbot"); +// const wbotMessageListener = require("../services/wbotMessageListener"); +// const wbotMonitor = require("../services/wbotMonitor"); -exports.index = async (req, res) => { - const dbSession = await Whatsapp.findAll(); +// exports.show = async (req, res) => { +// const { whatsappId } = req.params; +// const dbSession = await Whatsapp.findByPk(whatsappId); - return res.status(200).json(dbSession); -}; +// if (!dbSession) { +// return res.status(200).json({ message: "Session not found" }); +// } -exports.store = async (req, res) => { - const io = getIO(); - const dbSession = await Whatsapp.create(req.body); +// return res.status(200).json(dbSession); +// }; - if (!dbSession) { - return res.status(400).json({ error: "Cannot create whatsapp session." }); - } +// exports.delete = async (req, res) => { +// const { whatsappId } = req.params; - initWbot(dbSession) - .then(() => { - wbotMessageListener(dbSession); - wbotMonitor(dbSession); - }) - .catch(err => console.log(err)); +// const dbSession = await Whatsapp.findByPk(whatsappId); - io.emit("session", { - action: "update", - session: dbSession, - }); +// if (!dbSession) { +// return res.status(404).json({ message: "Session not found" }); +// } - return res.status(200).json(dbSession); -}; +// const wbot = getWbot(dbSession.id); -exports.show = async (req, res) => { - const { sessionId } = req.params; - const dbSession = await Whatsapp.findByPk(sessionId); +// wbot.logout(); - if (!dbSession) { - return res.status(200).json({ message: "Session not found" }); - } - - return res.status(200).json(dbSession); -}; - -exports.update = async (req, res) => { - const io = getIO(); - const { sessionId } = req.params; - - const dbSession = await Whatsapp.findByPk(sessionId); - - if (!dbSession) { - return res.status(404).json({ message: "Session not found" }); - } - - const wbot = getWbot(dbSession.id); - wbot.logout(); - - await dbSession.update(req.body); - - io.emit("session", { - action: "update", - session: dbSession, - }); - - return res.status(200).json({ message: "Session updated" }); -}; - -exports.delete = async (req, res) => { - const io = getIO(); - const { sessionId } = req.params; - - const dbSession = await Whatsapp.findByPk(sessionId); - - if (!dbSession) { - return res.status(404).json({ message: "Session not found" }); - } - - const wbot = getWbot(dbSession.id); - await dbSession.destroy(); - - removeWbot(dbSession.id); - - io.emit("session", { - action: "delete", - sessionId: dbSession.id, - }); - - return res.status(200).json({ message: "Session deleted." }); -}; +// return res.status(200).json({ message: "Session disconnected." }); +// }; diff --git a/backend/src/database/migrations/20200906122228-add-name-default-field-to-whatsapp.js b/backend/src/database/migrations/20200906122228-add-name-default-field-to-whatsapp.js new file mode 100644 index 0000000..57e03fc --- /dev/null +++ b/backend/src/database/migrations/20200906122228-add-name-default-field-to-whatsapp.js @@ -0,0 +1,15 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.addColumn("Whatsapps", "default", { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false, + }); + }, + + down: queryInterface => { + return queryInterface.removeColumn("Whatsapps", "default"); + }, +}; diff --git a/backend/src/libs/wbot.js b/backend/src/libs/wbot.js index 39c76ba..4118221 100644 --- a/backend/src/libs/wbot.js +++ b/backend/src/libs/wbot.js @@ -6,17 +6,17 @@ const { getIO } = require("../libs/socket"); let sessions = []; module.exports = { - initWbot: async dbSession => { + initWbot: async whatsapp => { try { const io = getIO(); - const sessionName = dbSession.name; + const sessionName = whatsapp.name; let sessionCfg; - if (dbSession && dbSession.session) { - sessionCfg = JSON.parse(dbSession.session); + if (whatsapp && whatsapp.session) { + sessionCfg = JSON.parse(whatsapp.session); } - const sessionIndex = sessions.findIndex(s => s.id === dbSession.id); + const sessionIndex = sessions.findIndex(s => s.id === whatsapp.id); if (sessionIndex !== -1) { sessions[sessionIndex].destroy(); sessions.splice(sessionIndex, 1); @@ -33,51 +33,51 @@ module.exports = { qrCode.generate(qr, { small: true }); - await dbSession.update({ id: 1, qrcode: qr, status: "qrcode" }); + await whatsapp.update({ qrcode: qr, status: "qrcode" }); - io.emit("session", { + io.emit("whatsappSession", { action: "update", - session: dbSession, + session: whatsapp, }); }); wbot.on("authenticated", async session => { console.log("Session:", sessionName, "AUTHENTICATED"); - await dbSession.update({ + await whatsapp.update({ session: JSON.stringify(session), status: "authenticated", }); - io.emit("session", { + io.emit("whatsappSession", { action: "update", - session: dbSession, + session: whatsapp, }); }); wbot.on("auth_failure", async msg => { console.error("Session:", sessionName, "AUTHENTICATION FAILURE", msg); - await dbSession.update({ session: "" }); + await whatsapp.update({ session: "" }); }); wbot.on("ready", async () => { console.log("Session:", sessionName, "READY"); - await dbSession.update({ + await whatsapp.update({ status: "CONNECTED", qrcode: "", }); - io.emit("session", { + io.emit("whatsappSession", { action: "update", - session: dbSession, + session: whatsapp, }); wbot.sendPresenceAvailable(); }); - wbot.id = dbSession.id; + wbot.id = whatsapp.id; sessions.push(wbot); } catch (err) { console.log(err); diff --git a/backend/src/models/Whatsapp.js b/backend/src/models/Whatsapp.js index 05b57a3..754de3b 100644 --- a/backend/src/models/Whatsapp.js +++ b/backend/src/models/Whatsapp.js @@ -10,6 +10,11 @@ class Whatsapp extends Sequelize.Model { status: { type: Sequelize.STRING }, battery: { type: Sequelize.STRING }, plugged: { type: Sequelize.BOOLEAN }, + default: { + type: Sequelize.BOOLEAN, + defaultValue: false, + allowNull: false, + }, }, { sequelize, diff --git a/backend/src/router/routes/whatsapp.js b/backend/src/router/routes/whatsapp.js index 5c6125f..66d0318 100644 --- a/backend/src/router/routes/whatsapp.js +++ b/backend/src/router/routes/whatsapp.js @@ -1,30 +1,18 @@ const express = require("express"); const isAuth = require("../../middleware/is-auth"); -const WhatsAppSessionController = require("../../controllers/WhatsAppSessionController"); +const WhatsAppController = require("../../controllers/WhatsAppController"); const routes = express.Router(); -routes.get("/whatsapp/session/", isAuth, WhatsAppSessionController.index); +routes.get("/whatsapp/", isAuth, WhatsAppController.index); -routes.post("/whatsapp/session", isAuth, WhatsAppSessionController.store); +routes.post("/whatsapp/", isAuth, WhatsAppController.store); -routes.get( - "/whatsapp/session/:sessionId", - isAuth, - WhatsAppSessionController.show -); +routes.get("/whatsapp/:whatsappId", isAuth, WhatsAppController.show); -routes.put( - "/whatsapp/session/:sessionId", - isAuth, - WhatsAppSessionController.update -); +routes.put("/whatsapp/:whatsappId", isAuth, WhatsAppController.update); -routes.delete( - "/whatsapp/session/:sessionId", - isAuth, - WhatsAppSessionController.delete -); +routes.delete("/whatsapp/:whatsappId", isAuth, WhatsAppController.delete); module.exports = routes; diff --git a/backend/src/router/routes/whatsappsessions.js b/backend/src/router/routes/whatsappsessions.js new file mode 100644 index 0000000..2eb87f9 --- /dev/null +++ b/backend/src/router/routes/whatsappsessions.js @@ -0,0 +1,20 @@ +const express = require("express"); +const isAuth = require("../../middleware/is-auth"); + +const WhatsAppSessionController = require("../../controllers/WhatsAppSessionController"); + +const routes = express.Router(); + +routes.get( + "/whatsappsession/:whatsappId", + isAuth, + WhatsAppSessionController.show +); + +routes.delete( + "/whatsappsession/:whatsappId", + isAuth, + WhatsAppSessionController.delete +); + +module.exports = routes; diff --git a/backend/src/services/wbotMessageListener.js b/backend/src/services/wbotMessageListener.js index 9056caa..38e16d0 100644 --- a/backend/src/services/wbotMessageListener.js +++ b/backend/src/services/wbotMessageListener.js @@ -132,8 +132,8 @@ const handleMessage = async (msg, ticket, contact) => { }); }; -const wbotMessageListener = dbSession => { - const wbot = getWbot(dbSession.id); +const wbotMessageListener = whatsapp => { + const wbot = getWbot(whatsapp.id); const io = getIO(); wbot.on("message_create", async msg => { diff --git a/backend/src/services/wbotMonitor.js b/backend/src/services/wbotMonitor.js index 3bd286d..696b44d 100644 --- a/backend/src/services/wbotMonitor.js +++ b/backend/src/services/wbotMonitor.js @@ -5,16 +5,16 @@ const wbotMessageListener = require("./wbotMessageListener"); const { getIO } = require("../libs/socket"); const { getWbot, initWbot } = require("../libs/wbot"); -const wbotMonitor = dbSession => { +const wbotMonitor = whatsapp => { const io = getIO(); - const sessionName = dbSession.name; - const wbot = getWbot(dbSession.id); + const sessionName = whatsapp.name; + const wbot = getWbot(whatsapp.id); try { wbot.on("change_state", async newState => { console.log("Monitor session:", sessionName, newState); try { - await dbSession.update({ status: newState }); + await whatsapp.update({ status: newState }); } catch (err) { Sentry.captureException(err); console.log(err); @@ -22,7 +22,7 @@ const wbotMonitor = dbSession => { io.emit("session", { action: "update", - session: dbSession, + session: whatsapp, }); }); @@ -33,7 +33,7 @@ const wbotMonitor = dbSession => { ); try { - await dbSession.update({ battery, plugged }); + await whatsapp.update({ battery, plugged }); } catch (err) { Sentry.captureException(err); console.log(err); @@ -41,14 +41,14 @@ const wbotMonitor = dbSession => { io.emit("session", { action: "update", - session: dbSession, + session: whatsapp, }); }); wbot.on("disconnected", async reason => { console.log("Disconnected session:", sessionName, reason); try { - await dbSession.update({ status: "disconnected" }); + await whatsapp.update({ status: "disconnected" }); } catch (err) { Sentry.captureException(err); console.log(err); @@ -56,15 +56,15 @@ const wbotMonitor = dbSession => { io.emit("session", { action: "update", - session: dbSession, + session: whatsapp, }); setTimeout( () => - initWbot(dbSession) + initWbot(whatsapp) .then(() => { - wbotMessageListener(dbSession); - wbotMonitor(dbSession); + wbotMessageListener(whatsapp); + wbotMonitor(whatsapp); }) .catch(err => { Sentry.captureException(err); diff --git a/frontend/src/components/QrcodeModal/index.js b/frontend/src/components/QrcodeModal/index.js index 09a4d39..9616c66 100644 --- a/frontend/src/components/QrcodeModal/index.js +++ b/frontend/src/components/QrcodeModal/index.js @@ -1,37 +1,67 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import QRCode from "qrcode.react"; +import openSocket from "socket.io-client"; +import { toast } from "react-toastify"; -import { - Dialog, - DialogContent, - Paper, - Typography, - DialogTitle, -} from "@material-ui/core"; +import { Dialog, DialogContent, Paper, Typography } from "@material-ui/core"; import { i18n } from "../../translate/i18n"; +import api from "../../services/api"; -const QrcodeModal = ({ open, onClose, session }) => { - if (session) { - return ( - - {session.name} - - - - {i18n.t("qrCode.message")} - - {session.qrcode ? ( - - ) : ( - Waiting for QR Code - )} - - - - ); - } else { - return null; - } +const QrcodeModal = ({ open, onClose, whatsAppId }) => { + const [qrCode, setQrCode] = useState(""); + + useEffect(() => { + const fetchSession = async () => { + try { + const { data } = await api.get(`/whatsapp/${whatsAppId}`); + setQrCode(data.qrcode); + } catch (err) { + console.log(err); + if (err.response && err.response.data && err.response.data.error) { + toast.error(err.response.data.error); + } + } + }; + fetchSession(); + }, [whatsAppId]); + + useEffect(() => { + if (!whatsAppId) return; + const socket = openSocket(process.env.REACT_APP_BACKEND_URL); + console.log("connectiing"); + + socket.on("whatsappSession", data => { + if (data.action === "update" && data.session.id === whatsAppId) { + setQrCode(data.session.qrcode); + } + + if (data.action === "update" && data.session.qrcode === "") { + onClose(); + } + }); + + return () => { + socket.disconnect(); + console.log("disconnectiing"); + }; + }, [whatsAppId, onClose]); + + return ( + + + + + {i18n.t("qrCode.message")} + + {qrCode ? ( + + ) : ( + Waiting for QR Code + )} + + + + ); }; -export default QrcodeModal; +export default React.memo(QrcodeModal); diff --git a/frontend/src/components/SessionModal/index.js b/frontend/src/components/WhatsAppModal/index.js similarity index 64% rename from frontend/src/components/SessionModal/index.js rename to frontend/src/components/WhatsAppModal/index.js index fc7c0a8..538f867 100644 --- a/frontend/src/components/SessionModal/index.js +++ b/frontend/src/components/WhatsAppModal/index.js @@ -1,5 +1,4 @@ import React, { useState, useEffect } from "react"; -import QRCode from "qrcode.react"; import * as Yup from "yup"; import { Formik, Form, Field } from "formik"; import { toast } from "react-toastify"; @@ -10,21 +9,29 @@ import { green } from "@material-ui/core/colors"; import { Dialog, DialogContent, - Paper, - Typography, DialogTitle, Button, DialogActions, CircularProgress, TextField, + Switch, + FormControlLabel, } from "@material-ui/core"; -import { i18n } from "../../translate/i18n"; +// import { i18n } from "../../translate/i18n"; import api from "../../services/api"; const useStyles = makeStyles(theme => ({ + form: { + display: "flex", + alignItems: "center", + justifySelf: "center", + "& > *": { + margin: theme.spacing(1), + }, + }, + textField: { - marginRight: theme.spacing(1), flex: 1, }, @@ -49,21 +56,21 @@ const SessionSchema = Yup.object().shape({ .required("Required"), }); -const SessionModal = ({ open, onClose, sessionId }) => { +const WhatsAppModal = ({ open, onClose, whatsAppId }) => { const classes = useStyles(); const initialState = { name: "", - status: "", + default: false, }; - const [session, setSession] = useState(initialState); + const [whatsApp, setWhatsApp] = useState(initialState); useEffect(() => { const fetchSession = async () => { - if (!sessionId) return; + if (!whatsAppId) return; try { - const { data } = await api.get(`whatsapp/session/${sessionId}`); - setSession(data); + const { data } = await api.get(`whatsapp/${whatsAppId}`); + setWhatsApp(data); } catch (err) { console.log(err); if (err.response && err.response.data && err.response.data.error) { @@ -72,16 +79,19 @@ const SessionModal = ({ open, onClose, sessionId }) => { } }; fetchSession(); - }, [sessionId]); + }, [whatsAppId]); - const handleSaveSession = async values => { + const handleSaveWhatsApp = async values => { try { - if (sessionId) { - await api.put(`/whatsapp/session/${sessionId}`, values); + if (whatsAppId) { + await api.put(`/whatsapp/${whatsAppId}`, { + name: values.name, + default: values.default, + }); } else { - await api.post("/whatsapp/session", values); + await api.post("/whatsapp", values); } - toast.success("Session created!"); + toast.success("Success!"); } catch (err) { console.log(err); if (err.response && err.response.data && err.response.data.error) { @@ -93,26 +103,27 @@ const SessionModal = ({ open, onClose, sessionId }) => { const handleClose = () => { onClose(); - setSession(initialState); + setWhatsApp(initialState); }; return ( - Edit Session + WhatsApp { setTimeout(() => { - handleSaveSession(values); + handleSaveWhatsApp(values); + // alert(JSON.stringify(values, null, 2)); actions.setSubmitting(false); }, 400); }} > - {({ touched, errors, isSubmitting }) => ( + {({ values, touched, errors, isSubmitting }) => (
- + { margin="dense" className={classes.textField} /> - + } + label="Default" /> @@ -165,4 +179,4 @@ const SessionModal = ({ open, onClose, sessionId }) => { ); }; -export default SessionModal; +export default React.memo(WhatsAppModal); diff --git a/frontend/src/components/_layout/MainListItems.js b/frontend/src/components/_layout/MainListItems.js index ebfa195..df2a93a 100644 --- a/frontend/src/components/_layout/MainListItems.js +++ b/frontend/src/components/_layout/MainListItems.js @@ -42,8 +42,8 @@ const MainListItems = () => {
} /> } /> { - if (action.type === "LOAD_SESSIONS") { - const sessions = action.payload; - - return [...sessions]; - } - - if (action.type === "UPDATE_SESSIONS") { - const session = action.payload; - const sessionIndex = state.findIndex(s => s.id === session.id); - - if (sessionIndex !== -1) { - state[sessionIndex] = session; - return [...state]; - } else { - return [session, ...state]; - } - } - - if (action.type === "DELETE_SESSION") { - const sessionId = action.payload; - - const sessionIndex = state.findIndex(s => s.id === sessionId); - if (sessionIndex !== -1) { - state.splice(sessionIndex, 1); - } - return [...state]; - } - - if (action.type === "RESET") { - return []; - } -}; - -const useStyles = makeStyles(theme => ({ - // root: { - // display: "flex", - // alignItems: "center", - // justifyContent: "center", - // padding: theme.spacing(4), - // }, - - mainPaper: { - flex: 1, - padding: theme.spacing(1), - overflowY: "scroll", - ...theme.scrollbarStyles, - }, - - // paper: { - // padding: theme.spacing(2), - // margin: theme.spacing(1), - // display: "flex", - // width: 400, - // height: 270, - // overflow: "auto", - // flexDirection: "column", - // alignItems: "center", - // justifyContent: "center", - // }, - - // fixedHeight: { - // height: 640, - // }, -})); - -const WhatsAuth = () => { - const classes = useStyles(); - - const [sessions, dispatch] = useReducer(reducer, []); - - const [sessionModalOpen, setSessionModalOpen] = useState(false); - // const [sessionModalOpen, setSessionModalOpen] = useState(false); - const [selectedSession, setSelectedSession] = useState(null); - const [confirmModalOpen, setConfirmModalOpen] = useState(false); - // const [deletingSession, setDeletingSession] = useState(null); - - useEffect(() => { - const fetchSession = async () => { - try { - const { data } = await api.get("/whatsapp/session/"); - dispatch({ type: "LOAD_SESSIONS", payload: data }); - } catch (err) { - console.log(err); - if (err.response && err.response.data && err.response.data.error) { - toast.error(err.response.data.error); - } - } - }; - fetchSession(); - }, []); - - useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL); - - socket.on("session", data => { - if (data.action === "update") { - dispatch({ type: "UPDATE_SESSIONS", payload: data.session }); - } - }); - - socket.on("session", data => { - if (data.action === "delete") { - dispatch({ type: "DELETE_SESSION", payload: data.sessionId }); - } - }); - - return () => { - socket.disconnect(); - }; - }, []); - - const handleDisconnectSession = async sessionId => { - try { - await api.put(`/whatsapp/session/${sessionId}`, { - session: "", - status: "pending", - }); - } catch (err) { - console.log(err); - if (err.response && err.response.data && err.response.data.error) { - toast.error(err.response.data.error); - } - } - }; - - const handleOpenSessionModal = session => { - setSelectedSession(null); - setSessionModalOpen(true); - }; - - const handleCloseSessionModal = () => { - setSessionModalOpen(false); - setSelectedSession(null); - }; - - const handleEditUser = session => { - setSelectedSession(session); - setSessionModalOpen(true); - }; - - const handleDeleteSession = async sessionId => { - try { - await api.delete(`/whatsapp/session/${sessionId}`); - } catch (err) { - console.log(err); - if (err.response && err.response.data && err.response.data.error) { - toast.error(err.response.data.error); - } - } - }; - - return ( - - handleDeleteSession(selectedSession.id)} - > - Are you sure? It cannot be reverted. - - - - Connections - - - - - - - - - Name - Status - Last update - Actions - - - - {false ? ( - - ) : ( - <> - {sessions && - sessions.length > 0 && - sessions.map((session, index) => ( - - {session.name} - - {session.status === "qrcode" ? ( - - ) : ( - session.status - )} - - - {format(parseISO(session.updatedAt), "dd/MM/yy HH:mm")} - - - handleDisconnectSession(session.id)} - > - - - - { - setConfirmModalOpen(true); - setSelectedSession(session); - }} - > - - - - - ))} - - )} - -
-
- - {/*
- {sessions && - sessions.length > 0 && - sessions.map(session => { - if (session.status === "disconnected") - return ( - - - - ); - else { - return ( - - - - ); - } - })} -
*/} -
- ); -}; - -export default WhatsAuth; diff --git a/frontend/src/pages/Users/index.js b/frontend/src/pages/Users/index.js index 0b5a615..1165b34 100644 --- a/frontend/src/pages/Users/index.js +++ b/frontend/src/pages/Users/index.js @@ -88,6 +88,7 @@ const Users = () => { const [pageNumber, setPageNumber] = useState(1); const [hasMore, setHasMore] = useState(false); const [selectedUser, setSelectedUser] = useState(null); + const [deletingUser, setDeletingUser] = useState(null); const [userModalOpen, setUserModalOpen] = useState(false); const [confirmModalOpen, setConfirmModalOpen] = useState(false); const [searchParam, setSearchParam] = useState(""); @@ -167,7 +168,7 @@ const Users = () => { toast.error(err.response.data.error); } } - setSelectedUser(null); + setDeletingUser(null); setSearchParam(""); setPageNumber(1); }; @@ -187,10 +188,10 @@ const Users = () => { return ( handleDeleteUser(selectedUser.id)} + onConfirm={e => handleDeleteUser(deletingUser.id)} > Are you sure? It canoot be reverted. @@ -261,7 +262,7 @@ const Users = () => { size="small" onClick={e => { setConfirmModalOpen(true); - setSelectedUser(user); + setDeletingUser(user); }} > diff --git a/frontend/src/pages/WhatsApps/index.js b/frontend/src/pages/WhatsApps/index.js new file mode 100644 index 0000000..36fdc67 --- /dev/null +++ b/frontend/src/pages/WhatsApps/index.js @@ -0,0 +1,290 @@ +import React, { useState, useEffect, useReducer, useCallback } from "react"; +import openSocket from "socket.io-client"; +import { toast } from "react-toastify"; +import { format, parseISO } from "date-fns"; + +import { makeStyles } from "@material-ui/core/styles"; +import { + Button, + TableBody, + TableRow, + TableCell, + IconButton, + Table, + TableHead, + Paper, +} from "@material-ui/core"; +import { Edit, DeleteOutline } from "@material-ui/icons"; + +import MainContainer from "../../components/MainContainer"; +import MainHeader from "../../components/MainHeader"; +import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper"; +import Title from "../../components/Title"; +import TableRowSkeleton from "../../components/TableRowSkeleton"; + +import api from "../../services/api"; +import WhatsAppModal from "../../components/WhatsAppModal"; +import ConfirmationModal from "../../components/ConfirmationModal"; +import QrcodeModal from "../../components/QrcodeModal"; + +const reducer = (state, action) => { + if (action.type === "LOAD_WHATSAPPS") { + const whatsApps = action.payload; + + return [...whatsApps]; + } + + if (action.type === "UPDATE_WHATSAPPS") { + const whatsApp = action.payload; + const whatsAppIndex = state.findIndex(s => s.id === whatsApp.id); + + if (whatsAppIndex !== -1) { + state[whatsAppIndex] = whatsApp; + return [...state]; + } else { + return [whatsApp, ...state]; + } + } + + if (action.type === "UPDATE_SESSION") { + const whatsApp = action.payload; + const whatsAppIndex = state.findIndex(s => s.id === whatsApp.id); + + if (whatsAppIndex !== -1) { + state[whatsAppIndex].status = whatsApp.status; + state[whatsAppIndex].qrcode = whatsApp.qrcode; + return [...state]; + } else { + return [...state]; + } + } + + if (action.type === "DELETE_WHATSAPPS") { + const whatsAppId = action.payload; + + const whatsAppIndex = state.findIndex(s => s.id === whatsAppId); + if (whatsAppIndex !== -1) { + state.splice(whatsAppIndex, 1); + } + return [...state]; + } + + if (action.type === "RESET") { + return []; + } +}; + +const useStyles = makeStyles(theme => ({ + mainPaper: { + flex: 1, + padding: theme.spacing(1), + overflowY: "scroll", + ...theme.scrollbarStyles, + }, +})); + +const WhatsApps = () => { + const classes = useStyles(); + + const [whatsApps, dispatch] = useReducer(reducer, []); + + const [whatsAppModalOpen, setWhatsAppModalOpen] = useState(false); + const [qrModalOpen, setQrModalOpen] = useState(false); + const [selectedWhatsApp, setSelectedWhatsApp] = useState(null); + const [confirmModalOpen, setConfirmModalOpen] = useState(false); + const [deletingWhatsApp, setDeletingWhatsApp] = useState(null); + + useEffect(() => { + const fetchSession = async () => { + try { + const { data } = await api.get("/whatsapp/"); + dispatch({ type: "LOAD_WHATSAPPS", payload: data }); + } catch (err) { + console.log(err); + if (err.response && err.response.data && err.response.data.error) { + toast.error(err.response.data.error); + } + } + }; + fetchSession(); + }, []); + + useEffect(() => { + const socket = openSocket(process.env.REACT_APP_BACKEND_URL); + + socket.on("whatsapp", data => { + if (data.action === "update") { + dispatch({ type: "UPDATE_WHATSAPPS", payload: data.whatsapp }); + } + }); + + socket.on("whatsapp", data => { + if (data.action === "delete") { + dispatch({ type: "DELETE_WHATSAPPS", payload: data.whatsappId }); + } + }); + + socket.on("whatsappSession", data => { + if (data.action === "update") { + dispatch({ type: "UPDATE_SESSION", payload: data.session }); + } + }); + + return () => { + socket.disconnect(); + }; + }, []); + + // const handleDisconnectSession = async whatsAppId => { + // try { + // await api.put(`/whatsapp/whatsApp/${whatsAppId}`, { + // whatsApp: "", + // status: "pending", + // }); + // } catch (err) { + // console.log(err); + // if (err.response && err.response.data && err.response.data.error) { + // toast.error(err.response.data.error); + // } + // } + // }; + + const handleOpenWhatsAppModal = () => { + setSelectedWhatsApp(null); + setWhatsAppModalOpen(true); + }; + + const handleCloseWhatsAppModal = useCallback(() => { + setWhatsAppModalOpen(false); + setSelectedWhatsApp(null); + }, [setSelectedWhatsApp, setWhatsAppModalOpen]); + + const handleOpenQrModal = whatsApp => { + setSelectedWhatsApp(whatsApp); + setQrModalOpen(true); + }; + + const handleCloseQrModal = useCallback(() => { + setQrModalOpen(false); + setSelectedWhatsApp(null); + }, [setQrModalOpen, setSelectedWhatsApp]); + + const handleEditWhatsApp = whatsApp => { + setSelectedWhatsApp(whatsApp); + setWhatsAppModalOpen(true); + }; + + const handleDeleteWhatsApp = async whatsAppId => { + try { + await api.delete(`/whatsapp/${whatsAppId}`); + toast.success("Deleted!"); + } catch (err) { + console.log(err); + if (err.response && err.response.data && err.response.data.error) { + toast.error(err.response.data.error); + } + } + setDeletingWhatsApp(null); + }; + + return ( + + handleDeleteWhatsApp(deletingWhatsApp.id)} + > + Are you sure? It cannot be reverted. + + + + + WhatsApps + + + + + + + + + Name + Status + Last update + Actions + + + + {false ? ( + + ) : ( + <> + {whatsApps && + whatsApps.length > 0 && + whatsApps.map((whatsApp, index) => ( + + {whatsApp.name} + + {whatsApp.status === "qrcode" ? ( + + ) : ( + whatsApp.status + )} + + + {format(parseISO(whatsApp.updatedAt), "dd/MM/yy HH:mm")} + + + handleEditWhatsApp(whatsApp)} + > + + + + { + setConfirmModalOpen(true); + setDeletingWhatsApp(whatsApp); + }} + > + + + + + ))} + + )} + +
+
+
+ ); +}; + +export default WhatsApps; diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js index b48a030..5a9d14f 100644 --- a/frontend/src/routes/index.js +++ b/frontend/src/routes/index.js @@ -7,7 +7,7 @@ import Dashboard from "../pages/Dashboard/"; import Tickets from "../pages/Tickets/"; import Signup from "../pages/Signup/"; import Login from "../pages/Login/"; -import Connection from "../pages/Connection/"; +import WhatsApps from "../pages/WhatsApps/"; import Settings from "../pages/Settings/"; import Users from "../pages/Users"; import Contacts from "../pages/Contacts/"; @@ -29,7 +29,7 @@ const Routes = () => { component={Tickets} isPrivate /> - +