feat: Enable users to transfer to other queues and users with the same WhatsApp connection.

pull/22/head
adriano 2024-01-29 08:48:20 -03:00
parent d12a47f062
commit bc134c827c
25 changed files with 922 additions and 280 deletions

View File

@ -289,7 +289,7 @@ app.post('/api/session', async function (req, res) {
)
})
if (whatsapp[0]['name'].split('->').length > 0) {
if (whatsapp[0]['name']?.split('->')?.length > 0) {
whatsName = `${whatsapp[0]['name'].split('->')[0]} -> S${numberSession}`
} else {
whatsName = `${whatsapp[0]['name']} -> S${numberSession}`

View File

@ -64,7 +64,11 @@ export const reportUserService = async (req: Request, res: Response): Promise<Re
const { userId, startDate, endDate } = req.query as IndexQuery
let usersProfile = await ListUserParamiterService({ profile: 'user' })
// let usersProfile = await ListUserParamiterService({ profile: 'user' })
let usersProfile = await ListUserParamiterService({
profile: "user",
raw: true
});
const sumUserOlineTime = await ShowUserServiceReport({ startDate, endDate, userId });
const closedByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'closed', userId });

View File

@ -5,6 +5,12 @@ import AuthUserService from "../services/UserServices/AuthUserService";
import { SendRefreshToken } from "../helpers/SendRefreshToken";
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
import createOrUpdateOnlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
import { removeUserFromOlineList } from "../helpers/removeUserFromOnlineList";
// const usersSocket = require("./../libs/socket");
const usersSocket = require("../libs/socket");
export const store = async (req: Request, res: Response): Promise<Response> => {
const { email, password } = req.body;
@ -15,6 +21,11 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
SendRefreshToken(res, refreshToken);
const userOnline = await createOrUpdateOnlineUserService({
userId: serializedUser.id,
status: "online"
});
return res.status(200).json({
token,
user: serializedUser
@ -47,5 +58,14 @@ export const remove = async (
): Promise<Response> => {
res.clearCookie("jrt");
const { userId } = req.params;
removeUserFromOlineList(userId);
const userOnline = await createOrUpdateOnlineUserService({
userId,
status: "offline"
});
return res.send();
};

View File

@ -64,6 +64,10 @@ import Contact from "../models/Contact";
import BotIsOnQueue from "../helpers/BotIsOnQueue";
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import Whatsapp from "../models/Whatsapp";
import AppError from "../errors/AppError";
export const index = async (req: Request, res: Response): Promise<Response> => {
const {
@ -249,24 +253,88 @@ export const update = async (
req.body.userId = null;
}
console.log("REQ.BODY: ", JSON.stringify(req.body, null, 6));
let ticketData: TicketData = req.body;
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
if (ticketData.transfer) {
const defaultWhatsapp: any = await GetDefaultWhatsApp({
userId: ticketData.userId
const whatsappsByqueue = await ListWhatsAppsForQueueService(
ticketData.queueId
);
if (userOldInfo) {
let listTicketOpenPending: any = [];
for (const w of whatsappsByqueue) {
let whats = await ListWhatsAppsNumber(w.id);
console.log("-------> WHATS: ", JSON.stringify(whats, null, 6));
const ticket = await Ticket.findOne({
where: {
[Op.and]: [
{ contactId: userOldInfo.contactId },
{
whatsappId: {
[Op.in]: whats.whatsapps.map((w: any) => w.id)
}
},
{ status: { [Op.or]: ["open", "pending"] } }
]
}
});
const _ticket: any = await Ticket.findByPk(ticketId);
if (defaultWhatsapp && ticketData.status != "open") {
await CheckContactOpenTickets(
_ticket.dataValues.contactId,
defaultWhatsapp.dataValues.id
);
if (ticket) {
listTicketOpenPending.push({
ticketId: ticket.id,
status: ticket.status,
userId: ticket.userId,
contactId: ticket.contactId,
whatsappId: ticket.whatsappId,
queueId: ticket.queueId
});
}
}
ticketData.whatsappId = defaultWhatsapp.dataValues.id;
// console.log("userOldInfo: ", JSON.stringify(userOldInfo, null, 6));
// console.log("##########")
// console.log(
// "listTicketOpenPending: ",
// JSON.stringify(listTicketOpenPending)
// );
if (
listTicketOpenPending.filter(
(ob: any) => userOldInfo.whatsappId != ob.whatsappId
)?.length > 0
) {
throw new AppError("ERR_OTHER_OPEN_TICKET");
}
}
//////////////////////////////////////////////
// const defaultWhatsapp: any = await GetDefaultWhatsApp({
// userId: ticketData.userId
// });
// console.log(
// "ticketData.userId: ",
// ticketData.userId,
// " | defaultWhatsapp: ",
// JSON.stringify(defaultWhatsapp, null, 6)
// );
// const _ticket: any = await Ticket.findByPk(ticketId);
// if (defaultWhatsapp && ticketData.status != "open") {
// await CheckContactOpenTickets(
// _ticket.dataValues.contactId,
// defaultWhatsapp.dataValues.id
// );
// }
// ticketData.whatsappId = defaultWhatsapp.dataValues.id;
}
}

View File

@ -10,16 +10,28 @@ import UpdateUserService from "../services/UserServices/UpdateUserService";
import ShowUserService from "../services/UserServices/ShowUserService";
import DeleteUserService from "../services/UserServices/DeleteUserService";
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService"
import ListUser from "../services/UserServices/ListUserParamiterService";
import User from "../models/User";
import { startWhoIsOnlineMonitor, stopWhoIsOnlineMonitor } from "../helpers/WhoIsOnlineMonitor"
import UserOnlineTIme from '../models/UserOnlineTime'
import {
startWhoIsOnlineMonitor,
stopWhoIsOnlineMonitor
} from "../helpers/WhoIsOnlineMonitor";
import UserOnlineTIme from "../models/UserOnlineTime";
import { format, subMonths } from "date-fns";
import { ptBR } from "date-fns/locale";
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
import { splitDateTime } from "../helpers/SplitDateTime";
import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService";
import { json } from "sequelize";
import { getSettingValue } from "../helpers/WhaticketSettings";
type IndexQuery = {
searchParam: string;
pageNumber: string;
profile?: string;
userId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
@ -31,13 +43,21 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
profile
});
if (req.user.profile !== 'master') {
if (req.user.profile !== "master") {
let auxUsers: Array<object> = [];
// for (var user of users) {
// if (user.profile !== 'master') {
// auxUsers.push(user)
// }
// }
for (var user of users) {
if (user.profile !== 'master') {
auxUsers.push(user)
if (user.profile !== "master") {
if (req.user.profile == "supervisor" && user.profile == "admin")
continue;
auxUsers.push(user);
}
}
@ -46,8 +66,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
return res.json({ users, count, hasMore });
// const { users, count, hasMore } = await ListUsersService({
// searchParam,
// pageNumber
@ -69,11 +87,59 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
// return res.json({ users, count, hasMore });
};
// export const usersByWhatsappQueue = async (req: Request, res: Response): Promise<Response> => {
// const { profile } = req.query as IndexQuery;
// const users = await ListUser({
// profile
// });
// return res.json({ users });
// };
export const all = async (req: Request, res: Response): Promise<Response> => {
const { userId, profile } = req.query as IndexQuery;
console.log(
"userId: ",
userId,
" | profile: ",
profile,
' | getSettingValue("queueTransferByWhatsappScope")?.value: ',
getSettingValue("queueTransferByWhatsappScope")?.value
);
if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") {
const obj = await ListUserByWhatsappQueuesService(
userId,
'"admin", "user", "supervisor"'
);
const usersByWhatsqueue = obj.users;
const queues = obj.queues;
let userIds = usersByWhatsqueue.map((w: any) => w.userId);
const users = await ListUser({
userIds
});
return res.json({ users, queues });
} else {
const users = await ListUser({
profile
});
return res.json({ users });
}
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { email, password, name, profile, queueIds } = req.body;
if (req.url === "/signup" && (await CheckSettingsHelper("userCreation")) === "disabled") {
if (
req.url === "/signup" &&
(await CheckSettingsHelper("userCreation")) === "disabled"
) {
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
} else if (req.url !== "/signup" && req.user.profile !== "master") {
throw new AppError("ERR_NO_PERMISSION", 403);
@ -93,9 +159,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
user
});
// await stopWhoIsOnlineMonitor()
await startWhoIsOnlineMonitor()
await startWhoIsOnlineMonitor();
return res.status(200).json(user);
};
@ -108,17 +173,18 @@ export const show = async (req: Request, res: Response): Promise<Response> => {
return res.status(200).json(user);
};
export const logoutUser = async (req: Request, res: Response): Promise<Response> => {
export const logoutUser = async (
req: Request,
res: Response
): Promise<Response> => {
const { userId } = req.params;
await stopWhoIsOnlineMonitor()
await stopWhoIsOnlineMonitor();
let onlineTime = {
userId: userId,
status: 'logout...'
}
status: "logout..."
};
const io = getIO();
io.emit("onlineStatus", {
@ -126,25 +192,73 @@ export const logoutUser = async (req: Request, res: Response): Promise<Response>
userOnlineTime: onlineTime
});
await startWhoIsOnlineMonitor()
await startWhoIsOnlineMonitor();
//
return res.status(200).json({});
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
if (req.user.profile !== "admin" && req.user.profile !== "master") {
if (
req.user.profile !== "admin" &&
req.user.profile !== "master" &&
req.user.profile !== "supervisor"
) {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const { userId } = req.params;
const userData = req.body;
const user = await UpdateUserService({ userData, userId });
const dateToday = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
);
const currentDate = new Date();
const tenMonthsAgo = subMonths(currentDate, 10);
const formattedDate = format(tenMonthsAgo, "yyyy-MM-dd");
console.log("dateToday.fullDate: ", dateToday.fullDate);
console.log("formattedDate 10 months ago: ", formattedDate);
const openByUserOnQueue: any[] = await CountTicketsByUserQueue({
startDate: formattedDate,
endDate: dateToday.fullDate,
status: "open",
clientChatStart: true,
userId: userId
});
// console.log('------> openByUserOnQueue: ', openByUserOnQueue)
// console.log()
// console.log('------> 1 userData.queueIds: ', userData.queueIds)
let userQueuesAttendance = [];
if ((openByUserOnQueue && openByUserOnQueue.length) > 0) {
userQueuesAttendance = openByUserOnQueue.filter(
(e: any) => !userData.queueIds.includes(e.queueId)
);
if (userQueuesAttendance && userQueuesAttendance.length > 0) {
const queueInAttendance = userQueuesAttendance.map(e => e.queueId);
const mergedSet = new Set([...userData.queueIds, ...queueInAttendance]);
// Convert the Set back to an array
userData.queueIds = Array.from(mergedSet);
// console.log('------> 2 userData.queueIds: ', userData.queueIds)
}
}
// console.log('userQueuesAttendance: ', userQueuesAttendance)
// return res.status(200).json({});
let user: any = await UpdateUserService({ userData, userId });
const io = getIO();
io.emit("user", {
@ -152,6 +266,8 @@ export const update = async (
user
});
user.userQueuesAttendance = userQueuesAttendance;
return res.status(200).json(user);
};
@ -165,26 +281,23 @@ export const remove = async (
throw new AppError("ERR_NO_PERMISSION", 403);
}
await DeleteUserService(userId);
const io = getIO();
io.emit("user", {
action: "delete",
userId
});
//test del
await stopWhoIsOnlineMonitor()
await stopWhoIsOnlineMonitor();
io.emit("onlineStatus", {
action: "delete",
userOnlineTime: userId
});
await startWhoIsOnlineMonitor()
await startWhoIsOnlineMonitor();
//
return res.status(200).json({ message: "User deleted" });

View File

@ -0,0 +1,22 @@
import { QueryInterface } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.bulkInsert(
"Settings",
[
{
key: "queueTransferByWhatsappScope",
value: "disabled",
createdAt: new Date(),
updatedAt: new Date()
}
],
{}
);
},
down: (queryInterface: QueryInterface) => {
return queryInterface.bulkDelete("Settings", {});
}
};

View File

@ -3,16 +3,22 @@ import AppError from "../errors/AppError";
import Ticket from "../models/Ticket";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import { getSettingValue } from "./WhaticketSettings";
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
const CheckContactOpenTickets = async (
contactId: number,
whatsappId: number | string
): Promise<void> => {
whatsappId: number | string,
handle?: boolean
): Promise<void | any> => {
let ticket;
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
let whats = await ListWhatsAppsNumber(whatsappId);
console.log("contactId: ", contactId, " | whatsappId: ", whatsappId);
console.log("WHATS: ", JSON.stringify(whats, null, 6));
ticket = await Ticket.findOne({
where: {
[Op.and]: [
@ -22,6 +28,8 @@ const CheckContactOpenTickets = async (
]
}
});
console.log("TICKET: ", JSON.stringify(ticket, null, 6));
} else {
ticket = await Ticket.findOne({
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
@ -29,8 +37,12 @@ const CheckContactOpenTickets = async (
}
if (ticket) {
if (handle) return true;
throw new AppError("ERR_OTHER_OPEN_TICKET");
}
};
export default CheckContactOpenTickets;

View File

@ -67,7 +67,7 @@ const monitor = async () => {
const usersSocket = require('./../libs/socket');
if (usersSocket.ob) {
if (usersSocket?.ob) {
if (count > 1) {
count = 0

View File

@ -0,0 +1,17 @@
const usersSocket = require("../libs/socket");
export const removeUserFromOlineList = (userId: any) => {
let index = usersSocket.ob.listOnline.findIndex((o: any) => o.id == userId);
if (index != -1) {
usersSocket.ob.listOnline.splice(index, 1);
}
index = -1;
index = usersSocket.ob.listOnlineAux.findIndex((o: any) => o.id == userId);
if (index != -1) {
usersSocket.ob.listOnlineAux.splice(index, 1);
}
};

View File

@ -139,7 +139,7 @@ export const initIO = (httpServer: Server): SocketIO => {
lstOnline.push({ id: userId, status: "online", try: 0 });
lstOnlineAux.push({ id: userId });
console.log(" 1 PUSHED NEW USER ID 1: ", userId);
console.log(" 1 - PUSHED NEW USER ID 1: ", userId);
obj.listOnline = lstOnline;
} else {
@ -154,7 +154,7 @@ export const initIO = (httpServer: Server): SocketIO => {
if (index == -1) {
lstOnline.push({ id: userId, status: "online", try: 0 });
console.log(" 2 PUSHED NEW USER ID: ", userId);
console.log(" 2 - PUSHED NEW USER ID: ", userId);
obj.listOnline = lstOnline;
} else {

View File

@ -11,6 +11,6 @@ authRoutes.post("/login", SessionController.store);
authRoutes.post("/refresh_token", SessionController.update);
authRoutes.delete("/logout", isAuth, SessionController.remove);
authRoutes.delete("/logout/:userId", isAuth, SessionController.remove);
export default authRoutes;

View File

@ -6,6 +6,8 @@ import * as UserController from "../controllers/UserController";
const userRoutes = Router();
userRoutes.get("/users/all", isAuth, UserController.all);
userRoutes.get("/users", isAuth, UserController.index);
userRoutes.post("/users", isAuth, UserController.store);

View File

@ -16,6 +16,8 @@ import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
import User from "../../models/User";
import whatsappQueueMatchingUserQueue from "../../helpers/whatsappQueueMatchingUserQueue";
import Whatsapp from "../../models/Whatsapp";
import ListWhatsAppsForQueueService from "../WhatsappService/ListWhatsAppsForQueueService";
import { json } from "sequelize";
let flatten = require("flat");
interface Request {
@ -42,6 +44,27 @@ const CreateTicketService = async ({
defaultWhatsapp = await GetDefaultWhatsApp({ userId, queueId });
}
// if (queueId) {
// const whatsappsByQueue = await ListWhatsAppsForQueueService(queueId);
// const exist = await CheckContactOpenTickets(
// contactId,
// defaultWhatsapp.id,
// true
// );
// console.log(
// "whatsappsByQueue: ",
// JSON.stringify(whatsappsByQueue, null, 6)
// );
// if (exist) {
// console.log("kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk");
// }
// return new Ticket();
// }
// console.log(JSON.stringify(defaultWhatsapp, null, 2));
// throw new AppError("test error");
@ -59,6 +82,13 @@ const CreateTicketService = async ({
queueId = matchingQueue ? matchingQueue.queueId : undefined;
}
console.log(
"xxxxxxxxxxxx contactId: ",
contactId,
" | defaultWhatsapp.id: ",
defaultWhatsapp.id
);
await CheckContactOpenTickets(contactId, defaultWhatsapp.id);
const { isGroup } = await ShowContactService(contactId);

View File

@ -0,0 +1,67 @@
import { Sequelize } from "sequelize";
import Whatsapp from "../../models/Whatsapp";
import WhatsappQueue from "../../models/WhatsappQueue";
import { List } from "whatsapp-web.js";
const dbConfig = require("../../config/database");
const { QueryTypes } = require("sequelize");
const sequelize = new Sequelize(dbConfig);
const ListWhatsappQueueByUserQueue = async (
userId: number | string,
profiles: string
): Promise<any> => {
const users = await sequelize.query(
`select wq.whatsappId, wq.queueId, uq.userId, uq.queueId, u.id, u.name, u.profile, w.number
from WhatsappQueues wq join UserQueues uq join Users u join Whatsapps w on
wq.queueId = uq.queueId where u.id = uq.userId and u.profile in (${profiles}) and u.id = ${userId}
and w.id = wq.whatsappId group by w.number ;`,
{ type: QueryTypes.SELECT }
);
return users;
};
const ListWhatsappQueesByUser = async (whatsappIds: string): Promise<any> => {
const users = await sequelize.query(
`SELECT
wq.whatsappId, wq.queueId, q.name, q.id, q.name, q.color
FROM
WhatsappQueues wq
JOIN
Queues q ON wq.whatsappId IN (${whatsappIds}) AND q.id = wq.queueId group by wq.queueId;
`,
{ type: QueryTypes.SELECT }
);
return users;
};
const ListUserByWhatsappQueuesService = async (
userId: number | string,
profiles: string
): Promise<any> => {
const whatsapps: any = await ListWhatsappQueueByUserQueue(userId, profiles);
let whatsappIds = whatsapps.map((w: any) => w.whatsappId);
if (whatsappIds.length == 0) return { users: [], queues: [] };
console.log("----------> whatsappIds: ", whatsappIds, " | userId: ", userId);
whatsappIds = whatsappIds.join(", ");
const users: any = await sequelize.query(
`select wq.whatsappId, wq.queueId, uq.userId, uq.queueId, u.id, u.name, u.profile
from WhatsappQueues wq join UserQueues uq join Users u on
wq.queueId = uq.queueId where u.id = uq.userId and u.profile in (${profiles}) and wq.whatsappId in (${whatsappIds}) group by u.id;`,
{ type: QueryTypes.SELECT }
);
const queues = await ListWhatsappQueesByUser(whatsappIds);
return { users, queues };
};
export default ListUserByWhatsappQueuesService;

View File

@ -1,4 +1,3 @@
import { Op, Sequelize } from "sequelize";
import Queue from "../../models/Queue";
import User from "../../models/User";
@ -7,65 +6,44 @@ import UserQueue from "../../models/UserQueue";
interface Request {
userId?: string | number;
profile?: string;
raw?: boolean;
userIds?: string | number
}
const ListUser = async ({ profile, userId }: Request): Promise<User[]> => {
let where_clause = {}
const ListUser = async ({ profile, userId, raw, userIds }: Request): Promise<User[]> => {
let where_clause = {};
if (userId && profile) {
where_clause = {
[Op.and]: [
{ userId: userId },
{ profile: profile }
]
}
}
else if (userId) {
[Op.and]: [{ userId: userId }, { profile: profile }]
};
} else if (userId) {
where_clause = {
[Op.and]: [
{ userId: userId },
]
}
}
else if (profile) {
[Op.and]: [{ userId: userId }]
};
} else if (profile) {
where_clause = {
profile: profile
};
} else if (userIds) {
where_clause = {
id: { [Op.in]: userIds }
};
}
}
const users = await User.findAll({
where: where_clause,
raw: true,
attributes: ['id', 'name', 'email'],
raw,
attributes: ["id", "name", "email"],
include: [
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
],
// include: [
// {
// model: UserQueue,
// separate: true,
// attributes: ['id',],
// order: [
// ['createdAt', 'ASC']
// ]
// },
// ],
order: [["id", "ASC"]],
})
order: [["id", "ASC"]]
});
return users;
};
export default ListUser;

View File

@ -0,0 +1,22 @@
import { Sequelize } from "sequelize";
import Whatsapp from "../../models/Whatsapp";
import WhatsappQueue from "../../models/WhatsappQueue";
const dbConfig = require("../../config/database");
const { QueryTypes } = require("sequelize");
const sequelize = new Sequelize(dbConfig);
const ListWhatsAppsForQueueService = async (queueId: number | string): Promise<any> => {
const distinctWhatsapps = await sequelize.query(
`SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId
FROM Whatsapps w
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
GROUP BY w.number;`,
{ type: QueryTypes.SELECT }
);
return distinctWhatsapps;
};
export default ListWhatsAppsForQueueService;

View File

@ -87,8 +87,15 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
if (newValue?.number) {
setSelectedContact(newValue);
} else if (newValue?.name) {
setNewContact({ name: newValue.name });
setContactModalOpen(true);
if (/^-?\d+(\.\d+)?$/.test(newValue?.name)) {
setNewContact({ number: newValue.name })
}
else {
setNewContact({ name: newValue.name })
}
setContactModalOpen(true)
}
};

View File

@ -1,30 +1,34 @@
import React, { useState, useContext, useMemo } from "react";
import { useHistory } from "react-router-dom";
import React, { useState, useContext, useMemo, useEffect } from "react"
import { useHistory } from "react-router-dom"
import openSocket from "socket.io-client"
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import Select from "@material-ui/core/Select";
import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import { makeStyles } from "@material-ui/core";
import Button from "@material-ui/core/Button"
import Dialog from "@material-ui/core/Dialog"
import Select from "@material-ui/core/Select"
import FormControl from "@material-ui/core/FormControl"
import InputLabel from "@material-ui/core/InputLabel"
import MenuItem from "@material-ui/core/MenuItem"
import { makeStyles } from "@material-ui/core"
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import DialogActions from "@material-ui/core/DialogActions"
import DialogContent from "@material-ui/core/DialogContent"
import DialogTitle from "@material-ui/core/DialogTitle"
import { i18n } from "../../translate/i18n";
import api from "../../services/api";
import ButtonWithSpinner from "../ButtonWithSpinner";
import toastError from "../../errors/toastError";
import { i18n } from "../../translate/i18n"
import api from "../../services/api"
import ButtonWithSpinner from "../ButtonWithSpinner"
import toastError from "../../errors/toastError"
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext";
import { AuthContext } from "../../context/Auth/AuthContext"
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
const useStyles = makeStyles((theme) => ({
maxWidth: {
width: "100%",
},
}));
}))
// Receive array of queues arrays
// Return a new array with unique queues from all arrays has passed by the parameter
@ -45,49 +49,177 @@ const queueArraysToOneArray = (array) => {
const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
const history = useHistory();
const { whatsApps } = useContext(WhatsAppsContext);
const [loading, setLoading] = useState(false);
const [selectedQueue, setSelectedQueue] = useState('');
const classes = useStyles();
const queues = useMemo(() => {
const history = useHistory()
const { whatsApps } = useContext(WhatsAppsContext)
const { user } = useContext(AuthContext)
const [loading, setLoading] = useState(false)
const [selectedQueue, setSelectedQueue] = useState('')
const [selectedUser, setSelectedUser] = useState('')
const classes = useStyles()
const [users, setUsers] = useState([])
const [queues, setQueues] = useState([])
const [_queues, setQueuesByWhats] = useState([])
// const isRun = useRef(false)
const [itemHover, setItemHover] = useState(-1)
const [settings, setSettings] = useState([])
const _queues2 = useMemo(() => {
if (!whatsApps) return []
const whatsAppsQueues = whatsApps.map(({ queues }) => queues)
//const whatsAppsQueues = whatsApps.filter(({ status }) => status === "CONNECTED" ).map(({ queues }) => queues)
const uniqueQueuesAvailable = queueArraysToOneArray(whatsAppsQueues)
return uniqueQueuesAvailable
}, [whatsApps])
const [itemHover, setItemHover] = useState(-1)
// useEffect(() => {
// if (isRun.current) return
// // setQueues(_queues2)
// isRun.current = true
// }, [whatsApps])
useEffect(() => {
if (selectedUser) {
let { queues } = users.find(u => +u.id === +selectedUser)
const userQueues = queues.map((q) => {
const { id, color, name } = q
return { id, color, name }
})
setQueues(userQueues)
setSelectedQueue('')
}
else {
if (settings?.find(e => e?.key === 'queueTransferByWhatsappScope')?.value === 'enabled') {
setQueues(_queues)
}
else {
setQueues(_queues2)
}
setSelectedUser('')
}
}, [selectedUser, settings, _queues2, _queues, users])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
console.log('settings updated ----------------------------xxxxxxxxxxxx')
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
const settingIndex = aux.findIndex((s) => s.key === data.setting.key)
aux[settingIndex].value = data.setting.value
return aux
})
}
})
return () => {
socket.disconnect()
}
}, [])
useEffect(() => {
const fetchSession = async () => {
try {
const { data } = await api.get('/settings')
setSettings(data.settings)
} catch (err) {
toastError(err)
}
}
fetchSession()
}, [])
const handleClose = () => {
onClose();
};
onClose()
}
const handleSaveTicket = async e => {
e.preventDefault();
if (!ticketid) return;
if (!selectedQueue) return;
setLoading(true);
e.preventDefault()
if (!ticketid) return
if (!selectedQueue) return
setLoading(true)
try {
let data = {};
let data = {}
if (selectedQueue && selectedQueue !== null) {
data.queueId = selectedQueue
}
if (selectedUser) {
data.userId = selectedUser
}
else {
// test del PARA APARECER NA FILA DE OUTRO ATENDENTE E O MESMO CLICAR EM ACEITAR AO INVES DE ENVIAR PARA ATENDENDO
data.status = 'pending'
data.transfer = true
await api.put(`/tickets/${ticketid}`, data);
setLoading(false);
history.push(`/tickets`);
} catch (err) {
setLoading(false);
toastError(err);
}
};
await api.put(`/tickets/${ticketid}`, data)
setLoading(false)
history.push(`/tickets`)
} catch (err) {
setLoading(false)
toastError(err)
}
}
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
const fetchUsers = async () => {
try {
if (settings?.find(e => e?.key === 'queueTransferByWhatsappScope')?.value === 'enabled') {
const { data } = await api.get(`/users/all`, {
params: { userId: user.id },
})
setUsers(data.users)
setQueuesByWhats(data.queues)
setQueues(data.queues)
}
else {
const { data } = await api.get(`/users/all`, {
params: { profile: 'user' },
})
setUsers(data.users)
setQueues(_queues2)
}
} catch (err) {
console.log(err)
}
}
fetchUsers()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [settings, _queues2, user.id])
return (
<Dialog open={modalOpen} onClose={handleClose} maxWidth="lg" scroll="paper">
@ -98,6 +230,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
<DialogContent dividers>
<FormControl variant="outlined" className={classes.maxWidth}>
<InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel>
<Select
value={selectedQueue}
onChange={(e) => setSelectedQueue(e.target.value)}
@ -118,6 +251,26 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
</MenuItem>
))}
</Select>
<br />
<Select
value={selectedUser}
onChange={e => setSelectedUser(e.target.value)}
label={'Transfeir para usuario'}
>
<MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem>
{users.map((user) => (
<MenuItem
key={user.id}
value={user.id}
>{user.name}
</MenuItem>
))}
</Select>
</FormControl>
</DialogContent>
<DialogActions>
@ -140,7 +293,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
</DialogActions>
</form>
</Dialog >
);
};
)
}
export default TransferTicketModal;
export default TransferTicketModal

View File

@ -121,7 +121,31 @@ const UserModal = ({ open, onClose, userId }) => {
const userData = { ...values, queueIds: selectedQueueIds };
try {
if (userId) {
await api.put(`/users/${userId}`, userData);
const user = await api.put(`/users/${userId}`, userData);
console.log('USER: ', user.data)
if (user && user.data.userQueuesAttendance.length > 0) {
const userQueueInAttendance = user.data.userQueuesAttendance.map((e) => ({ "queue": e.queueName, "open": e.totAttendance }))
console.log('userQueueInAttendance: ', userQueueInAttendance)
let msg = '\nAVISO \n\nO atendente possui atendimento(s) em aberto na(s) fila(s) abaixo: \n\n'
userQueueInAttendance.forEach((e) => {
msg += `Fila: ${e.queue}\nAberto: ${e.open}\n\n`
})
msg += 'Para remover o atendente da(s) fila(s) acima é necessário que o mesmo encerre os atendimentos aberto(s) nessas filas.\n'
alert(msg)
}
} else {
await api.post("/users", userData);
}
@ -229,6 +253,7 @@ const UserModal = ({ open, onClose, userId }) => {
id="profile-selection"
required
>
<MenuItem value="supervisor">Supervisor</MenuItem>
<MenuItem value="admin">Admin</MenuItem>
<MenuItem value="user">User</MenuItem>
</Field>

View File

@ -131,7 +131,8 @@ const useAuth = () => {
setLoading(true)
try {
await api.delete('/auth/logout')
await api.delete(`/auth/logout/${user.id}`);
setIsAuth(false)
setUser({})
localStorage.removeItem('token')

View File

@ -103,20 +103,31 @@ const MainListItems = (props) => {
primary={i18n.t('mainDrawer.listItems.quickAnswers')}
icon={<QuestionAnswerOutlinedIcon />}
/>
<Can
role={user.profile}
perform="menu-users:view"
yes={() => (
<>
<Divider />
<ListSubheader inset>{i18n.t("mainDrawer.listItems.administration")}</ListSubheader>
<ListItemLink
to="/users"
primary={i18n.t("mainDrawer.listItems.users")}
icon={<PeopleAltOutlinedIcon />}
/>
</>
)}
/>
<Can
role={user.profile}
perform="drawer-admin-items:view"
yes={() => (
<>
<Divider />
<ListSubheader inset>
{i18n.t('mainDrawer.listItems.administration')}
</ListSubheader>
<ListItemLink
to="/users"
primary={i18n.t('mainDrawer.listItems.users')}
icon={<PeopleAltOutlinedIcon />}
/>
<ListItemLink
to="/queues"
primary={i18n.t('mainDrawer.listItems.queues')}

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useReducer, useContext } from "react"
import React, { useState, useEffect, useReducer, useCallback, useContext } from "react"
import openSocket from "socket.io-client"
import { toast } from "react-toastify"
import { useHistory } from "react-router-dom"
@ -116,6 +116,7 @@ const Contacts = () => {
const [deletingContact, setDeletingContact] = useState(null)
const [confirmOpen, setConfirmOpen] = useState(false)
const [hasMore, setHasMore] = useState(false)
const [settings, setSettings] = useState([])
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
@ -161,11 +162,26 @@ const Contacts = () => {
}
useEffect(() => {
const fetchSession = async () => {
try {
const { data } = await api.get('/settings')
setSettings(data.settings)
} catch (err) {
toastError(err)
}
}
fetchSession()
}, [])
const getSettingValue = (key) => {
const { value } = settings.find((s) => s?.key === key)
return value
}
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
const fetchReportOnQueue = async () => {
@ -301,11 +317,46 @@ const Contacts = () => {
setContactModalOpen(false)
}
const handleSaveTicketOneQueue = useCallback(async (contactId, userId, queueId) => {
if (!contactId || !userId) {
console.log("Missing contactId or userId")
return
};
if (!queueId) {
toast.warning("Nenhuma Fila Selecionada")
return
}
// if (isMounted.current) setLoading(true)
try {
const { data: ticket } = await api.post("/tickets", {
contactId: contactId,
userId: userId,
queueId: queueId,
status: "open",
})
history.push(`/tickets/${ticket.id}`)
} catch (err) {
toastError(err)
}
// if (isMounted.current) setLoading(false)
}, [history])
const handleOpenCreateTicketModal = (contactId) => {
setSelectedContactId(contactId)
if (getSettingValue('whatsaAppCloudApi') === 'disabled' && user?.queues?.length === 1){
handleSaveTicketOneQueue(contactId, user.id, user.queues[0].id)
}
else{
setIsCreateTicketModalOpen(true)
}
// setSelectedContactId(contactId)
// setIsCreateTicketModalOpen(true)
}
const handleCloseCreateTicketModal = () => {
setIsCreateTicketModalOpen(false)
}

View File

@ -1,25 +1,25 @@
import React, { useContext, useReducer, useEffect, useState } from "react";
import React, { useContext, useReducer, useEffect, useState } from "react"
import { addHours, addMinutes, addSeconds, intervalToDuration } from "date-fns";
import { addHours, addMinutes, addSeconds, intervalToDuration } from "date-fns"
import Paper from "@material-ui/core/Paper";
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Tooltip from "@mui/material/Tooltip";
import Zoom from "@mui/material/Zoom";
import IconButton from "@mui/material/IconButton";
import Info from "@material-ui/icons/Info";
import Paper from "@material-ui/core/Paper"
import Container from "@material-ui/core/Container"
import Grid from "@material-ui/core/Grid"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import Tooltip from "@mui/material/Tooltip"
import Zoom from "@mui/material/Zoom"
import IconButton from "@mui/material/IconButton"
import Info from "@material-ui/icons/Info"
import { AuthContext } from "../../context/Auth/AuthContext";
import { AuthContext } from "../../context/Auth/AuthContext"
// import { i18n } from "../../translate/i18n";
import Chart from "./Chart";
import openSocket from "socket.io-client";
import api from "../../services/api";
import Chart from "./Chart"
import openSocket from "socket.io-client"
import api from "../../services/api"
import { Can } from "../../components/Can";
import TableUser from "../../components/DashboardUser/TableUser";
import { Can } from "../../components/Can"
import TableUser from "../../components/DashboardUser/TableUser"
const useStyles = makeStyles((theme) => ({
container: {
@ -104,7 +104,7 @@ const useStyles = makeStyles((theme) => ({
textAlign: "center",
borderRadius: "5px",
},
}));
}))
var _fifo
@ -136,70 +136,70 @@ const sumOnlineTimeNow = (oldOnlineTimeSum) => {
onlineTime = addSeconds(onlineTime, newtTime.seconds)
}
const isoDate = new Date(onlineTime);
const isoDate = new Date(onlineTime)
const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ');
const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ')
return newOnlinetime
}
const reducer = (state, action) => {
if (action.type === "DELETE_USER_STATUS") {
const userId = action.payload;
const userId = action.payload
const userIndex = state.findIndex((u) => `${u.id}` === `${userId}`);
const userIndex = state.findIndex((u) => `${u.id}` === `${userId}`)
if (userIndex !== -1) {
state.splice(userIndex, 1);
state.splice(userIndex, 1)
}
return [...state];
return [...state]
}
if (action.type === "LOAD_QUERY") {
const queries = action.payload;
const newQueries = [];
const queries = action.payload
const newQueries = []
queries.forEach((query) => {
const queryIndex = state.findIndex((q) => q.id === query.id);
const queryIndex = state.findIndex((q) => q.id === query.id)
if (queryIndex !== -1) {
state[queryIndex] = query;
state[queryIndex] = query
} else {
newQueries.push(query);
newQueries.push(query)
}
});
})
return [...state, ...newQueries];
return [...state, ...newQueries]
}
if (action.type === "UPDATE_STATUS_ONLINE") {
let onlineUser = action.payload;
let index = -1;
let onlineUser = action.payload
let index = -1
// console.log('UPDATE_STATUS_ONLINE: ', onlineUser)
let onlySumOpenClosed = false;
let onlySumOpenClosed = false
if (onlineUser.sumOpen || onlineUser.sumClosed) {
index = state.findIndex(
(e) =>
(onlineUser.sumOpen && e.id === onlineUser.sumOpen.userId) ||
(onlineUser.sumClosed && e.id === onlineUser.sumClosed.userId)
);
)
onlySumOpenClosed = true;
onlySumOpenClosed = true
} else {
index = state.findIndex((e) => `${e.id}` === `${onlineUser.userId}`);
index = state.findIndex((e) => `${e.id}` === `${onlineUser.userId}`)
}
if (index !== -1) {
if (!onlySumOpenClosed) {
if (!("statusOnline" in state[index])) {
state[index].statusOnline = onlineUser;
state[index].statusOnline = onlineUser
} else if ("statusOnline" in state[index]) {
state[index].statusOnline["status"] = onlineUser.status;
state[index].statusOnline["status"] = onlineUser.status
}
}
@ -209,7 +209,6 @@ const reducer = (state, action) => {
if ("sumOnlineTime" in state[index]) {
// console.log(' ffffffffffffffffffffffffffff ')
state[index].sumOnlineTime.sum = onlineUser.onlineTime.split(" ")[1]
} else if (!("sumOnlineTime" in state[index])) {
@ -217,63 +216,63 @@ const reducer = (state, action) => {
state[index].sumOnlineTime = {
userId: onlineUser.userId,
sum: onlineUser.onlineTime.split(" ")[1],
};
}
}
}
if (onlineUser.sumOpen) {
if ("sumOpen" in state[index]) {
state[index].sumOpen["count"] = onlineUser.sumOpen.count;
state[index].sumOpen["count"] = onlineUser.sumOpen.count
} else if (!("sumOpen" in state[index])) {
state[index].sumOpen = onlineUser.sumOpen;
state[index].sumOpen = onlineUser.sumOpen
}
}
if (onlineUser.sumClosed) {
if ("sumClosed" in state[index]) {
state[index].sumClosed["count"] = onlineUser.sumClosed.count;
state[index].sumClosed["count"] = onlineUser.sumClosed.count
} else if (!("sumClosed" in state[index])) {
state[index].sumClosed = onlineUser.sumClosed;
state[index].sumClosed = onlineUser.sumClosed
}
}
if (onlineUser.openClosedInQueue) {
state[index].openClosedInQueue = onlineUser.openClosedInQueue;
state[index].openClosedInQueue = onlineUser.openClosedInQueue
}
if (onlineUser.openClosedOutQueue) {
state[index].openClosedOutQueue = onlineUser.openClosedOutQueue;
state[index].openClosedOutQueue = onlineUser.openClosedOutQueue
}
}
return [...state];
return [...state]
}
if (action.type === "RESET") {
return [];
return []
}
}
};
const Dashboard = () => {
const classes = useStyles();
const [usersOnlineInfo, dispatch] = useReducer(reducer, []);
const [ticketStatusChange, setStatus] = useState();
const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 });
const classes = useStyles()
const [usersOnlineInfo, dispatch] = useReducer(reducer, [])
const [ticketStatusChange, setStatus] = useState()
const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 })
const { user } = useContext(AuthContext);
const { user } = useContext(AuthContext)
useEffect(() => {
dispatch({ type: "RESET" });
}, []);
dispatch({ type: "RESET" })
}, [])
const handleLogouOnlineUser = async (userId) => {
try {
await api.get(`/users/logout/${userId}`);
await api.get(`/users/logout/${userId}`)
//toast.success(("Desloged!"));
//handleDeleteRows(scheduleId)
} catch (err) {
// toastError(err);
}
};
}
useEffect(() => {
//setLoading(true);
@ -282,26 +281,26 @@ const Dashboard = () => {
// setLoading(true);
const fetchQueries = async () => {
try {
let date = new Date().toLocaleDateString("pt-BR").split("/");
let dateToday = `${date[2]}-${date[1]}-${date[0]}`;
let date = new Date().toLocaleDateString("pt-BR").split("/")
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
const { data } = await api.get("/reports/user/services", {
params: { userId: null, startDate: dateToday, endDate: dateToday },
});
})
// console.log('data.data: ', data.usersProfile)
dispatch({ type: "RESET" });
dispatch({ type: "LOAD_QUERY", payload: data.usersProfile });
dispatch({ type: "RESET" })
dispatch({ type: "LOAD_QUERY", payload: data.usersProfile })
} catch (err) {
}
};
}
fetchQueries();
}, 500);
return () => clearTimeout(delayDebounceFn);
}, []);
fetchQueries()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [])
useEffect(() => {
@ -310,7 +309,7 @@ const Dashboard = () => {
if (!usersOnlineInfo || usersOnlineInfo.length === 0) return
if (_fifo) {
clearInterval(_fifo);
clearInterval(_fifo)
}
_fifo = setInterval(() => {
@ -321,7 +320,7 @@ const Dashboard = () => {
let onlineTimeCurrent = sumOnlineTimeNow({ onlineTime: usersOnlineInfo[i].statusOnline.onlineTime, updatedAt: usersOnlineInfo[i].statusOnline.updatedAt })
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: usersOnlineInfo[i].id, status: usersOnlineInfo[i].statusOnline.status, onlineTime: onlineTimeCurrent } });
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: usersOnlineInfo[i].id, status: usersOnlineInfo[i].statusOnline.status, onlineTime: onlineTimeCurrent } })
}
}
@ -340,80 +339,81 @@ const Dashboard = () => {
// })
}, 3000);
}, 3000)
}, [usersOnlineInfo])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("ticketStatus", (data) => {
if (data.action === "update") {
setStatus("");
setStatus(data.ticketStatus.status);
setStatus("")
setStatus(data.ticketStatus.status)
}
});
})
socket.on("onlineStatus", (data) => {
if (data.action === "logout" || data.action === "update") {
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime });
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
} else if (data.action === "delete") {
dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime });
dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
}
});
})
socket.on("user", (data) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId });
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
});
})
return () => {
socket.disconnect();
};
}, []);
socket.disconnect()
}
}, [])
useEffect(() => {
if (ticketStatusChange === "") return
const delayDebounceFn = setTimeout(() => {
const fetchQueries = async () => {
try {
let date = new Date().toLocaleDateString("pt-BR").split("/");
let dateToday = `${date[2]}-${date[1]}-${date[0]}`;
let date = new Date().toLocaleDateString("pt-BR").split("/")
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
const _open = await api.get("/tickets/count", {
params: { status: "open", date: dateToday },
});
})
const _closed = await api.get("/tickets/count", {
params: { status: "closed", date: dateToday },
});
})
const _pending = await api.get("/tickets/count", {
params: { status: "pending" },
});
})
const _openAll = await api.get("/tickets/count", {
params: { status: "open" },
});
})
setTicktsStatus({
open: _open.data.count,
openAll: _openAll.data.count,
closed: _closed.data.count,
pending: _pending.data.count,
});
})
// setOpen(_open.data.count);
// setClosed(_closed.data.count);
// setPending(_pending.data.count);
} catch (err) {
console.log(err);
console.log(err)
}
}
};
fetchQueries();
}, 500);
return () => clearTimeout(delayDebounceFn);
}, [ticketStatusChange]);
fetchQueries()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [ticketStatusChange])
return (
<Can
@ -602,7 +602,7 @@ const Dashboard = () => {
</Container>
)}
/>
);
};
)
}
export default Dashboard;
export default Dashboard

View File

@ -257,6 +257,35 @@ const Settings = () => {
</div>
<div className={classes.root}>
<Container className={classes.container} maxWidth="sm">
<Paper className={classes.paper}>
<Typography variant="body1">
Escopo de transferência de usuario por filas atribuidas a conexão e usuarios atribuido a filas
</Typography>
<Select
margin="dense"
variant="outlined"
native
id="queueTransferByWhatsappScope-setting"
name="queueTransferByWhatsappScope"
value={
settings &&
settings.length > 0 &&
getSettingValue('queueTransferByWhatsappScope')
}
className={classes.settingOption}
onChange={handleChangeSetting}
>
<option value="enabled">Ativado</option>
<option value="disabled">Desativado</option>
</Select>
</Paper>
</Container>
</div>
</div>
)}
/>

View File

@ -3,11 +3,20 @@ const rules = {
static: [],
},
supervisor: {
static: [
"menu-users:view",
"user-view:show",
"user-modal:editQueues"
]
},
admin: {
static: [
'show-icon-edit-whatsapp',
'show-icon-edit-queue',
'menu-users:view',
'drawer-admin-items:view',
'tickets-manager:showall',
'user-modal:editProfile',
@ -25,6 +34,7 @@ const rules = {
master: {
static: [
'menu-users:view',
'url-remote-session:show',
'show-icon-edit-whatsapp',
'show-icon-add-queue',