Compare commits
	
		
			No commits in common. "11e2dc1a50f120684a52559d43d1b3158becadbe" and "0751374fb7f7931c6982bf801fe9d37a00adcc9d" have entirely different histories. 
		
	
	
		
			11e2dc1a50
			...
			0751374fb7
		
	
		|  | @ -30,8 +30,6 @@ app.get('/', function (req, res) { | |||
| app.post('/api/session', async function (req, res) { | ||||
|   let { app_name, whatsappId, client_url, number } = req.body | ||||
| 
 | ||||
|   let oldNumber = '' | ||||
| 
 | ||||
|   if (app_name) { | ||||
|     app_name = app_name.trim() | ||||
|   } | ||||
|  | @ -69,7 +67,6 @@ app.post('/api/session', async function (req, res) { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   let appPort = [] | ||||
| 
 | ||||
|   let existSubDir = false | ||||
|  | @ -101,7 +98,7 @@ app.post('/api/session', async function (req, res) { | |||
|           path.join(sessionsPath, directoriesInDIrectory[i], subDir[x]) | ||||
|         ) | ||||
| 
 | ||||
|         oldNumber = subDir[x].split('_')[1] | ||||
|         let oldNumber = subDir[x].split('_')[1] | ||||
| 
 | ||||
|         if (oldNumber != number) { | ||||
|           deletePm2Process(subDir[x], currPath) | ||||
|  | @ -200,7 +197,7 @@ app.post('/api/session', async function (req, res) { | |||
|   ) { | ||||
|     const whatsapp_numbers = await new Promise((resolve, reject) => { | ||||
|       mysql_conn(db_credentials.db_conf).query( | ||||
|         'SELECT name, number FROM Whatsapps WHERE name LIKE ?', | ||||
|         'SELECT name FROM Whatsapps WHERE name LIKE ?', | ||||
|         [`%${number}%`], | ||||
|         (err, result) => { | ||||
|           if (err) { | ||||
|  | @ -212,6 +209,8 @@ app.post('/api/session', async function (req, res) { | |||
|       ) | ||||
|     }) | ||||
| 
 | ||||
|     console.log('whatsapp_numbers: ', whatsapp_numbers) | ||||
| 
 | ||||
|     let session_num = [] | ||||
| 
 | ||||
|     if (whatsapp_numbers && whatsapp_numbers.length > 0) { | ||||
|  | @ -342,7 +341,6 @@ app.post('/api/session', async function (req, res) { | |||
|       stream.write('# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n') | ||||
|       stream.write(`MOBILEUID=${number}\n`) | ||||
|       stream.write(`MOBILENAME=${whatsappName}\n`) | ||||
|       stream.write(`OLD_MOBILEUID=${oldNumber}\n`) | ||||
|       stream.write('\n') | ||||
| 
 | ||||
|       stream.write('# PORT NUMBER FOR THIS API\n') | ||||
|  |  | |||
|  | @ -288,6 +288,8 @@ client.on("ready", async () => { | |||
| 
 | ||||
|         let url = process.env.CLIENT_URL + '/whatsapp/connection/number' | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         try { | ||||
| 
 | ||||
|             await client.logout() | ||||
|  | @ -302,48 +304,6 @@ client.on("ready", async () => { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     if (process.env.OLD_MOBILEUID) { | ||||
|         const ticketSettingsId = await new Promise((resolve, reject) => { | ||||
| 
 | ||||
|             dbcc.query("select id from SettingTickets where number = ?", [process.env.OLD_MOBILEUID,], (err, result) => { | ||||
| 
 | ||||
|                 if (err) { | ||||
|                     reject(err) | ||||
|                 } | ||||
|                 else { | ||||
|                     // resolve(result)
 | ||||
|                     const idArray = result.map(row => row.id) | ||||
|                     resolve(idArray) | ||||
|                 } | ||||
|             }) | ||||
| 
 | ||||
|         }) | ||||
| 
 | ||||
| 
 | ||||
|         if (ticketSettingsId?.length > 0) { | ||||
|             await new Promise((resolve, reject) => { | ||||
|                 const idsToUpdate = ticketSettingsId // Assuming ticketSettingsId is an array of IDs
 | ||||
| 
 | ||||
|                 // Create placeholders for the IN clause based on the number of elements in idsToUpdate
 | ||||
|                 const placeholders = Array(idsToUpdate.length).fill('?').join(',') | ||||
| 
 | ||||
|                 dbcc.query( | ||||
|                     `UPDATE SettingTickets SET number = ? WHERE id IN (${placeholders})`, | ||||
|                     [client.info["wid"]["user"], ...idsToUpdate], // Spread the array to pass individual values
 | ||||
|                     function (err, result) { | ||||
|                         if (err) { | ||||
|                             console.log("ERROR: " + err) | ||||
|                             reject(err) | ||||
|                         } else { | ||||
|                             resolve(result) | ||||
|                         } | ||||
|                     } | ||||
|                 ) | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     await new Promise((resolve, reject) => { | ||||
| 
 | ||||
|  | @ -364,6 +324,7 @@ client.on("ready", async () => { | |||
|     }) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode' | ||||
| 
 | ||||
|     try { | ||||
|  | @ -1232,9 +1193,9 @@ function comercialBuss(until_hour) { | |||
| 
 | ||||
| scheduler_monitor = setInterval(monitor, 10000) | ||||
| 
 | ||||
| // scheduler_campaign_monitor = setInterval(sendCampaignMessage, 3000)
 | ||||
| scheduler_campaign_monitor = setInterval(sendCampaignMessage, 3000) | ||||
| 
 | ||||
| // scheduler_internet_conn = setInterval(internetMonitor, 60000)
 | ||||
| scheduler_internet_conn = setInterval(internetMonitor, 60000) | ||||
| 
 | ||||
| app.listen(process.env.PORT || 8003, function () { | ||||
|     console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003) | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| NODE_ENV= | ||||
| BACKEND_URL=http://localhost | ||||
| FRONTEND_URL=http://localhost:3000 | ||||
| PROXY_PORT=8080 | ||||
| PORT=8080 | ||||
| 
 | ||||
| DB_DIALECT= | ||||
| DB_HOST= | ||||
| DB_USER= | ||||
| DB_PASS= | ||||
| DB_NAME= | ||||
| 
 | ||||
| JWT_SECRET= | ||||
| JWT_REFRESH_SECRET= | ||||
|  | @ -34,7 +34,6 @@ type IndexQuery = { | |||
|   startDate: string; | ||||
|   endDate: string; | ||||
|   pageNumber: string; | ||||
|   userQueues: []; | ||||
| }; | ||||
| 
 | ||||
| type ReportOnQueue = { | ||||
|  | @ -53,11 +52,12 @@ export const reportUserByDateStartDateEnd = async (req: Request, res: Response): | |||
|     throw new AppError("ERR_NO_PERMISSION", 403); | ||||
|   } | ||||
| 
 | ||||
|   const { userId, startDate, endDate, pageNumber, userQueues } = req.query as IndexQuery | ||||
|   const { userId, startDate, endDate, pageNumber } = req.query as IndexQuery | ||||
| 
 | ||||
|   console.log("userId, startDate, endDate, pageNumber: ", userId, startDate, endDate, pageNumber); | ||||
| 
 | ||||
|   const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber }); | ||||
| 
 | ||||
|   // console.log('kkkkkkkkkkkkkkkkkk tickets: ', JSON.stringify(tickets, null, 6))
 | ||||
|   | ||||
|   return res.status(200).json({ tickets, count, hasMore }); | ||||
|  |  | |||
|  | @ -18,20 +18,9 @@ export const index = async (req: Request, res: Response): Promise<Response> => { | |||
| 
 | ||||
|   const settings = await ListSettingsService(); | ||||
| 
 | ||||
|   // const config = await SettingTicket.findAll();
 | ||||
|   const config = await SettingTicket.findAll(); | ||||
| 
 | ||||
|   return res.status(200).json({ settings, }); | ||||
| }; | ||||
| 
 | ||||
| export const ticketSettings = async ( | ||||
|   req: Request, | ||||
|   res: Response | ||||
| ): Promise<Response> => { | ||||
|   const { number } = req.params;  | ||||
| 
 | ||||
|   const config = await SettingTicket.findAll({ where: { number } }); | ||||
| 
 | ||||
|   return res.status(200).json({ config }); | ||||
|   return res.status(200).json({ settings, config }); | ||||
| }; | ||||
| 
 | ||||
| export const updateTicketSettings = async ( | ||||
|  | @ -39,7 +28,6 @@ export const updateTicketSettings = async ( | |||
|   res: Response | ||||
| ): Promise<Response> => { | ||||
|   const { | ||||
|     number, | ||||
|     outBusinessHours, | ||||
|     ticketExpiration, | ||||
|     weekend, | ||||
|  | @ -48,53 +36,45 @@ export const updateTicketSettings = async ( | |||
|     holiday | ||||
|   } = req.body; | ||||
| 
 | ||||
|   if (!number) throw new AppError("No number selected", 400); | ||||
| 
 | ||||
|   if (outBusinessHours && Object.keys(outBusinessHours).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...outBusinessHours, | ||||
|       key: "outBusinessHours", | ||||
|       number | ||||
|       key: "outBusinessHours" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   if (ticketExpiration && Object.keys(ticketExpiration).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...ticketExpiration, | ||||
|       key: "ticketExpiration", | ||||
|       number | ||||
|       key: "ticketExpiration" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   if (weekend && Object.keys(weekend).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...weekend, | ||||
|       key: "weekend", | ||||
|       number | ||||
|       key: "weekend" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   if (saturday && Object.keys(saturday).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...saturday, | ||||
|       key: "saturday", | ||||
|       number | ||||
|       key: "saturday" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   if (sunday && Object.keys(sunday).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...sunday, | ||||
|       key: "sunday", | ||||
|       number | ||||
|       key: "sunday" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   if (holiday && Object.keys(holiday).length > 0) { | ||||
|     await updateSettingTicket({ | ||||
|       ...holiday, | ||||
|       key: "holiday", | ||||
|       number | ||||
|       key: "holiday" | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -253,6 +253,8 @@ 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") { | ||||
|  |  | |||
|  | @ -134,33 +134,21 @@ export const all = async (req: Request, res: Response): Promise<Response> => { | |||
| }; | ||||
| 
 | ||||
| export const store = async (req: Request, res: Response): Promise<Response> => { | ||||
|   const { email, password, name, profile, positionCompany, queueIds } = req.body; | ||||
| 
 | ||||
|   console.log("===========> req.url: ", req.url);  | ||||
|   const { email, password, name, profile, queueIds } = req.body; | ||||
| 
 | ||||
|   if ( | ||||
|     req.url === "/user" && | ||||
|     getSettingValue("userCreation")?.value == "disabled" && | ||||
|     req.user.profile == "admin" | ||||
|   ) { | ||||
|     throw new AppError("ERR_NO_PERMISSION", 403); | ||||
|   } else if ( | ||||
|     req.url === "/signup" && | ||||
|     getSettingValue("userCreation")?.value == "disabled" | ||||
|     (await CheckSettingsHelper("userCreation")) === "disabled" | ||||
|   ) { | ||||
|     throw new AppError("ERR_USER_CREATION_DISABLED", 403); | ||||
|   } else if (  | ||||
|     req.user.profile !== "master"   | ||||
|   ) { | ||||
|   } else if (req.url !== "/signup" && req.user.profile !== "master") { | ||||
|     throw new AppError("ERR_NO_PERMISSION", 403); | ||||
|   } | ||||
| 
 | ||||
|     | ||||
|   const user = await CreateUserService({ | ||||
|     email, | ||||
|     password, | ||||
|     name, | ||||
|     positionCompany, | ||||
|     profile, | ||||
|     queueIds | ||||
|   }); | ||||
|  |  | |||
|  | @ -39,9 +39,6 @@ import receiveWhatsAppMediaOfficialAPI from "../helpers/ReceiveWhatsAppMediaOffi | |||
| import whatsappOfficialAPI from "../helpers/WhatsappOfficialAPI"; | ||||
| import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo"; | ||||
| import { getSettingValue } from "../helpers/WhaticketSettings"; | ||||
| import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber"; | ||||
| import SettingTicket from "../models/SettingTicket"; | ||||
| import { Op } from "sequelize"; | ||||
| 
 | ||||
| interface WhatsappData { | ||||
|   name: string; | ||||
|  | @ -486,38 +483,6 @@ export const remove = async ( | |||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   let whats = await ListWhatsAppsNumber(whatsappId); | ||||
| 
 | ||||
|   //  Remove tickets business hours config
 | ||||
|   if (whats?.whatsapps?.length == 1) { | ||||
|     const configIds = await SettingTicket.findAll({ | ||||
|       where: { number: whats?.whatsapps[0]?.number }, | ||||
|       raw: true, | ||||
|       attributes: ["id"] | ||||
|     }); | ||||
| 
 | ||||
|     const whatsappTicketConfig = await SettingTicket.findOne({ | ||||
|       where: { number: whats.whatsapps[0].number } | ||||
|     }); | ||||
| 
 | ||||
|     if (whatsappTicketConfig) { | ||||
|       try { | ||||
|         await SettingTicket.destroy({ | ||||
|           where: { | ||||
|             id: { | ||||
|               [Op.in]: configIds.map(config => config.id) | ||||
|             } | ||||
|           } | ||||
|         }); | ||||
|       } catch (error) { | ||||
|         console.log( | ||||
|           "Error on delete SettingTicket by number: ", | ||||
|           whats?.whatsapps[0]?.number | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   await DeleteWhatsAppService(whatsappId); | ||||
| 
 | ||||
|   removeDir( | ||||
|  |  | |||
|  | @ -1,14 +0,0 @@ | |||
| import { QueryInterface, DataTypes } from "sequelize"; | ||||
| 
 | ||||
| module.exports = { | ||||
|   up: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.addColumn("SettingTickets", "number", { | ||||
|       type: DataTypes.STRING, | ||||
|       allowNull: true | ||||
|     }); | ||||
|   }, | ||||
| 
 | ||||
|   down: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.removeColumn("SettingTickets", "number"); | ||||
|   } | ||||
| }; | ||||
|  | @ -1,14 +0,0 @@ | |||
| import { QueryInterface, DataTypes } from "sequelize"; | ||||
| 
 | ||||
| module.exports = { | ||||
|   up: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.addColumn("Users", "positionCompany", { | ||||
|       type: DataTypes.STRING, | ||||
|       allowNull: true | ||||
|     }); | ||||
|   }, | ||||
| 
 | ||||
|   down: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.removeColumn("Users", "positionCompany"); | ||||
|   } | ||||
| }; | ||||
|  | @ -1,26 +0,0 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| module.exports = { | ||||
|   up: (queryInterface, Sequelize) => { | ||||
|     /* | ||||
|       Add altering commands here. | ||||
|       Return a promise to correctly handle asynchronicity. | ||||
| 
 | ||||
|       Example: | ||||
|       return queryInterface.bulkInsert('People', [{ | ||||
|         name: 'John Doe', | ||||
|         isBetaMember: false | ||||
|       }], {}); | ||||
|     */ | ||||
|   }, | ||||
| 
 | ||||
|   down: (queryInterface, Sequelize) => { | ||||
|     /* | ||||
|       Add reverting commands here. | ||||
|       Return a promise to correctly handle asynchronicity. | ||||
| 
 | ||||
|       Example: | ||||
|       return queryInterface.bulkDelete('People', null, {}); | ||||
|     */ | ||||
|   } | ||||
| }; | ||||
|  | @ -1,22 +0,0 @@ | |||
| import { QueryInterface } from "sequelize"; | ||||
| 
 | ||||
| module.exports = { | ||||
|   up: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.bulkInsert( | ||||
|       "Settings", | ||||
|       [ | ||||
|         { | ||||
|           key: "hasCampaign", | ||||
|           value: "disabled", | ||||
|           createdAt: new Date(), | ||||
|           updatedAt: new Date() | ||||
|         } | ||||
|       ], | ||||
|       {} | ||||
|     ); | ||||
|   }, | ||||
| 
 | ||||
|   down: (queryInterface: QueryInterface) => { | ||||
|     return queryInterface.bulkDelete("Settings", {}); | ||||
|   } | ||||
| }; | ||||
|  | @ -12,7 +12,6 @@ import { | |||
| 
 | ||||
| import ptBR from "date-fns/locale/pt-BR"; | ||||
| import { splitDateTime } from "./SplitDateTime"; | ||||
| import Whatsapp from "../models/Whatsapp"; | ||||
| 
 | ||||
| const fsPromises = require("fs/promises"); | ||||
| const fs = require("fs"); | ||||
|  | @ -25,43 +24,37 @@ const AutoCloseTickets = async () => { | |||
| 
 | ||||
|     // if (!botInfo.userIdBot) return
 | ||||
| 
 | ||||
|     const whatsapps = await Whatsapp.findAll({ group: ["number"] }); | ||||
|     const ticketExpiration = await SettingTicket.findOne({ | ||||
|       where: { key: "ticketExpiration" } | ||||
|     }); | ||||
| 
 | ||||
|     for (const whatsapp of whatsapps) { | ||||
|       // console.log("-------> whatsapp: ", JSON.stringify(whatsapps, null, 6));
 | ||||
|     if (ticketExpiration && ticketExpiration.value == "enabled") { | ||||
|       const startTime = splitDateTime( | ||||
|         new Date( | ||||
|           _format(new Date(ticketExpiration.startTime), "yyyy-MM-dd HH:mm:ss", { | ||||
|             locale: ptBR | ||||
|           }) | ||||
|         ) | ||||
|       ); | ||||
| 
 | ||||
|       const ticketExpiration = await SettingTicket.findOne({ | ||||
|         where: { key: "ticketExpiration", number: whatsapp.number } | ||||
|       const seconds = timeStringToSeconds(startTime.fullTime); | ||||
| 
 | ||||
|       // console.log("Ticket seconds: ", seconds);
 | ||||
| 
 | ||||
|       let tickets: any = await ListTicketTimeLife({ | ||||
|         timeseconds: seconds, | ||||
|         status: "open" | ||||
|       }); | ||||
| 
 | ||||
|       if (ticketExpiration && ticketExpiration.value == "enabled") { | ||||
|         const startTime = splitDateTime( | ||||
|           new Date( | ||||
|             _format( | ||||
|               new Date(ticketExpiration.startTime), | ||||
|               "yyyy-MM-dd HH:mm:ss", | ||||
|               { | ||||
|                 locale: ptBR | ||||
|               } | ||||
|             ) | ||||
|           ) | ||||
|         ); | ||||
|       // console.log("tickets: ", tickets);
 | ||||
| 
 | ||||
|         const seconds = timeStringToSeconds(startTime.fullTime);   | ||||
|       for (let i = 0; i < tickets.length; i++) {  | ||||
|          | ||||
|         let tickets: any = await ListTicketTimeLife({ | ||||
|           timeseconds: seconds, | ||||
|           status: "open", | ||||
|           number: whatsapp.number | ||||
|         await UpdateTicketService({ | ||||
|           ticketData: { status: "closed", statusChatEnd: "FINALIZADO" }, | ||||
|           ticketId: tickets[i].ticket_id, | ||||
|           msg: ticketExpiration.message | ||||
|         }); | ||||
| 
 | ||||
|         for (let i = 0; i < tickets.length; i++) { | ||||
|           await UpdateTicketService({ | ||||
|             ticketData: { status: "closed", statusChatEnd: "FINALIZADO" }, | ||||
|             ticketId: tickets[i].ticket_id, | ||||
|             msg: ticketExpiration.message | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } catch (error) { | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ import { convertBytes } from "./ConvertBytes"; | |||
| import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache"; | ||||
| import SchedulingNotify from "../models/SchedulingNotify"; | ||||
| import Ticket from "../models/Ticket"; | ||||
| import User from "../models/User"; | ||||
| import { Sequelize, Op } from "sequelize"; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -66,21 +65,12 @@ const monitor = async () => { | |||
|                 if (_ticket) continue  | ||||
|                   | ||||
|                 if (ticket.dataValues.status == 'closed') { | ||||
|                     await ticket.update({ status: 'open' }) | ||||
|                 }  | ||||
|                 const userId: number = ticket.getDataValue('userId'); | ||||
|                 let userN = ''; | ||||
|                 if(userId){ | ||||
|                    const useer = await User.findByPk(userId); | ||||
|                    if(useer){ | ||||
|                       const userName: string = useer.getDataValue('name'); | ||||
|                       userN = `*${userName}:* \n`; | ||||
|                    } | ||||
|                     await ticket.update({ status: 'pending' }) | ||||
|                 }  | ||||
| 
 | ||||
|                 await new Promise(f => setTimeout(f, 3000)); | ||||
|                 await SendWhatsAppMessage({ | ||||
|                     body: userN+schedulingNotifies[i].message, ticket | ||||
|                     body: schedulingNotifies[i].message, ticket | ||||
|                 }); | ||||
| 
 | ||||
| 
 | ||||
|  | @ -90,33 +80,33 @@ const monitor = async () => { | |||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         // exec("df -h /", (error: any, stdout: any, stderr: any) => {
 | ||||
|         exec("df -h /", (error: any, stdout: any, stderr: any) => { | ||||
| 
 | ||||
|         //     if (error) {
 | ||||
|         //         console.log(`exec error: ${error.message}`);
 | ||||
|         //         return;
 | ||||
|         //     }
 | ||||
|         //     if (stderr) {
 | ||||
|         //         console.log(`exec stderr: ${stderr}`);
 | ||||
|         //         return;
 | ||||
|         //     }
 | ||||
|             if (error) { | ||||
|                 console.log(`exec error: ${error.message}`); | ||||
|                 return; | ||||
|             } | ||||
|             if (stderr) { | ||||
|                 console.log(`exec stderr: ${stderr}`); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|         //     stdout = stdout.split(/\r?\n/)
 | ||||
|         //     stdout = stdout[1].trim().split(/\s+/)
 | ||||
|             stdout = stdout.split(/\r?\n/) | ||||
|             stdout = stdout[1].trim().split(/\s+/) | ||||
| 
 | ||||
|         //     // DISK SPACE MONITORING
 | ||||
|         //     const io = getIO();
 | ||||
|         //     io.emit("diskSpaceMonit", {
 | ||||
|         //         action: "update",
 | ||||
|         //         diskSpace: {
 | ||||
|         //             size: stdout[1],
 | ||||
|         //             used: stdout[2],
 | ||||
|         //             available: stdout[3],
 | ||||
|         //             use: stdout[4]
 | ||||
|         //         }
 | ||||
|         //     });
 | ||||
|             // DISK SPACE MONITORING
 | ||||
|             const io = getIO(); | ||||
|             io.emit("diskSpaceMonit", { | ||||
|                 action: "update", | ||||
|                 diskSpace: { | ||||
|                     size: stdout[1], | ||||
|                     used: stdout[2], | ||||
|                     available: stdout[3], | ||||
|                     use: stdout[4] | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|         // });
 | ||||
|         }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ import User from "../models/User"; | |||
| interface SerializedUser { | ||||
|   id: number; | ||||
|   name: string; | ||||
|   positionCompany: string; | ||||
|   email: string; | ||||
|   profile: string; | ||||
|   queues: Queue[]; | ||||
|  | @ -14,7 +13,6 @@ export const SerializeUser = (user: User): SerializedUser => { | |||
|   return { | ||||
|     id: user.id, | ||||
|     name: user.name, | ||||
|     positionCompany: user.positionCompany, | ||||
|     email: user.email, | ||||
|     profile: user.profile, | ||||
|     queues: user.queues | ||||
|  |  | |||
|  | @ -13,11 +13,11 @@ import { | |||
| } from "date-fns"; | ||||
| import ptBR from "date-fns/locale/pt-BR"; | ||||
| 
 | ||||
| const isHoliday = async (number: string | number) => { | ||||
| const isHoliday = async () => { | ||||
|   let obj = { set: false, msg: "" }; | ||||
| 
 | ||||
|   const holiday = await SettingTicket.findOne({ | ||||
|     where: { key: "holiday", number } | ||||
|     where: { key: "holiday" } | ||||
|   }); | ||||
| 
 | ||||
|   if ( | ||||
|  | @ -50,11 +50,11 @@ const isHoliday = async (number: string | number) => { | |||
|   return obj; | ||||
| }; | ||||
| 
 | ||||
| const isWeekend = async (number: string | number) => { | ||||
| const isWeekend = async () => { | ||||
|   let obj = { set: false, msg: "" }; | ||||
| 
 | ||||
|   const weekend = await SettingTicket.findOne({ | ||||
|     where: { key: "weekend", number } | ||||
|     where: { key: "weekend" } | ||||
|   }); | ||||
| 
 | ||||
|   if ( | ||||
|  | @ -62,6 +62,7 @@ const isWeekend = async (number: string | number) => { | |||
|     weekend.value == "enabled" && | ||||
|     weekend.message?.trim()?.length > 0 | ||||
|   ) {  | ||||
| 
 | ||||
|     // Specify your desired timezone
 | ||||
|     const brazilTimeZone = "America/Sao_Paulo"; | ||||
| 
 | ||||
|  | @ -99,7 +100,8 @@ const isWeekend = async (number: string | number) => { | |||
|         obj.set = true; | ||||
|         obj.msg = weekend.message; | ||||
|       } | ||||
|     } else { | ||||
|     } | ||||
|     else{ | ||||
|       //  obj.set = true;
 | ||||
|       //  obj.msg = weekend.message;
 | ||||
|     }  | ||||
|  | @ -107,11 +109,11 @@ const isWeekend = async (number: string | number) => { | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| async function isOutBusinessTime(number: string | number) { | ||||
| async function isOutBusinessTime() { | ||||
|   let obj = { set: false, msg: "" }; | ||||
| 
 | ||||
|   const outBusinessHours = await SettingTicket.findOne({ | ||||
|     where: { key: "outBusinessHours", number } | ||||
|     where: { key: "outBusinessHours" } | ||||
|   }); | ||||
| 
 | ||||
|   let isWithinRange = false; | ||||
|  |  | |||
|  | @ -30,9 +30,6 @@ class SettingTicket extends Model<SettingTicket> { | |||
|   @Column | ||||
|   key: string; | ||||
| 
 | ||||
|   @Column | ||||
|   number: string; | ||||
| 
 | ||||
|   @CreatedAt | ||||
|   createdAt: Date; | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,9 +42,6 @@ class User extends Model<User> { | |||
|   @Column | ||||
|   tokenVersion: number; | ||||
| 
 | ||||
|   @Column | ||||
|   positionCompany: string; | ||||
|    | ||||
|   @Default("admin") | ||||
|   @Column | ||||
|   profile: string; | ||||
|  | @ -54,6 +51,7 @@ class User extends Model<User> { | |||
| 
 | ||||
|   @UpdatedAt | ||||
|   updatedAt: Date; | ||||
| 
 | ||||
|   @HasMany(() => Ticket) | ||||
|   tickets: Ticket[]; | ||||
|   | ||||
|  |  | |||
|  | @ -7,8 +7,6 @@ const settingRoutes = Router(); | |||
| 
 | ||||
| settingRoutes.get("/settings", SettingController.index); | ||||
| 
 | ||||
| settingRoutes.get("/settings/ticket/:number", SettingController.ticketSettings);      | ||||
| 
 | ||||
| // routes.get("/settings/:settingKey", isAuth, SettingsController.show);
 | ||||
| 
 | ||||
| settingRoutes.put( | ||||
|  |  | |||
|  | @ -7,7 +7,6 @@ interface Request { | |||
|   endTime: string; | ||||
|   value: string; | ||||
|   message: string; | ||||
|   number: string; | ||||
| } | ||||
| 
 | ||||
| const updateSettingTicket = async ({ | ||||
|  | @ -15,30 +14,16 @@ const updateSettingTicket = async ({ | |||
|   startTime, | ||||
|   endTime, | ||||
|   value, | ||||
|   message, | ||||
|   number | ||||
|   message | ||||
| }: Request): Promise<SettingTicket | undefined> => { | ||||
|   try { | ||||
|     let businessHours = await SettingTicket.findOne({ where: { key, number } }); | ||||
|     const businessHours = await SettingTicket.findOne({ where: { key } }); | ||||
| 
 | ||||
|     if (!businessHours) { | ||||
|       // throw new AppError("ERR_NO_SETTING_FOUND", 404);
 | ||||
| 
 | ||||
|       businessHours = await SettingTicket.create({ | ||||
|         key, | ||||
|         startTime, | ||||
|         endTime, | ||||
|         value, | ||||
|         message, | ||||
|         number | ||||
|       }); | ||||
|       return businessHours; | ||||
|       throw new AppError("ERR_NO_SETTING_FOUND", 404); | ||||
|     } | ||||
| 
 | ||||
|     await businessHours.update( | ||||
|       { startTime, endTime, message, value, number }, | ||||
|       { where: { key, number } } | ||||
|     ); | ||||
|     await businessHours.update({ startTime, endTime, message, value }); | ||||
| 
 | ||||
|     return businessHours; | ||||
|   } catch (error: any) { | ||||
|  |  | |||
|  | @ -1,60 +1,47 @@ | |||
| import { Sequelize } from "sequelize"; | ||||
| 
 | ||||
| import { Sequelize, } from "sequelize"; | ||||
| 
 | ||||
| const dbConfig = require("../../config/database"); | ||||
| const sequelize = new Sequelize(dbConfig);  | ||||
| const { QueryTypes } = require("sequelize"); | ||||
| const { QueryTypes } = require('sequelize'); | ||||
| 
 | ||||
| import { splitDateTime } from "../../helpers/SplitDateTime"; | ||||
| import format from "date-fns/format"; | ||||
| import ptBR from "date-fns/locale/pt-BR"; | ||||
| import format from 'date-fns/format'; | ||||
| import ptBR from 'date-fns/locale/pt-BR'; | ||||
| 
 | ||||
| 
 | ||||
| interface Request {  | ||||
|   timeseconds: string | number; | ||||
|   status: string; | ||||
|   number?: string; | ||||
|   userId?: string | number; | ||||
|     timeseconds: string | number; | ||||
|     status: string; | ||||
|     userId?: string | number;   | ||||
| } | ||||
| 
 | ||||
| const ListTicketTimeLife = async ({ | ||||
|   timeseconds, | ||||
|   status, | ||||
|   number, | ||||
|   userId | ||||
| }: Request): Promise<any[]> => { | ||||
|   let tickets = []; | ||||
| const ListTicketTimeLife = async ({timeseconds, status, userId }: Request): Promise<any[]> => { | ||||
| 
 | ||||
|   let currentDate = format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }); | ||||
|     let tickets = [] | ||||
| 
 | ||||
|   // console.log('------------------> currentDate: ', currentDate)
 | ||||
|     let currentDate = format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }) | ||||
| 
 | ||||
|   if (userId) { | ||||
|     // CONSULTANDO FILAS PELO ID DO USUARIO
 | ||||
|     tickets = await sequelize.query( | ||||
|       `select user.id as user_id, user.name as user_name, t.id as ticket_id from Tickets as t inner join Users as user on
 | ||||
|         t.userId = user.id and user.name = 'botqueue' and t.status='${status}' and (TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}')) >= ${timeseconds};`,
 | ||||
|       { type: QueryTypes.SELECT } | ||||
|     ); | ||||
|   } else if (number) { | ||||
|     // CONSULTANDO TICKETS PELO WHATSAPP
 | ||||
|     tickets = await sequelize.query( | ||||
|       `SELECT t.id AS ticket_id
 | ||||
|        FROM Tickets t | ||||
|        JOIN Whatsapps w ON t.whatsappId = w.id  | ||||
|        AND w.number = ${number} | ||||
|        WHERE t.status = 'open'  | ||||
|        AND TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}') >= ${timeseconds};`,
 | ||||
|       { type: QueryTypes.SELECT } | ||||
|     );  | ||||
|   } else { | ||||
|     // CONSULTANDO FILAS PELO USUARIO
 | ||||
|     tickets = await sequelize.query( | ||||
|       `select id as ticket_id from Tickets where status='${status}' and 
 | ||||
|         (TIMESTAMPDIFF(SECOND, updatedAt, '${currentDate}')) >= ${timeseconds};`,
 | ||||
|       { type: QueryTypes.SELECT } | ||||
|     ); | ||||
|   } | ||||
|     // console.log('------------------> currentDate: ', currentDate)  
 | ||||
|     | ||||
|   return tickets; | ||||
|     if (userId) { | ||||
|         // CONSULTANDO FILAS PELO ID DO USUARIO
 | ||||
|         tickets = await sequelize.query(`select user.id as user_id, user.name as user_name, t.id as ticket_id from Tickets as t inner join Users as user on
 | ||||
|         t.userId = user.id and user.name = 'botqueue' and t.status='${status}' and (TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}')) >= ${timeseconds};`, { type: QueryTypes.SELECT });
 | ||||
| 
 | ||||
|     } else { | ||||
| 
 | ||||
|         // CONSULTANDO FILAS PELO USUARIO
 | ||||
|         tickets = await sequelize.query(`select id as ticket_id from Tickets where status='${status}' and 
 | ||||
|         (TIMESTAMPDIFF(SECOND, updatedAt, '${currentDate}')) >= ${timeseconds};`, { type: QueryTypes.SELECT });
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     return tickets; | ||||
| }; | ||||
| 
 | ||||
| export default ListTicketTimeLife; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ import Queue from "../../models/Queue"; | |||
| interface SerializedUser { | ||||
|   id: number; | ||||
|   name: string; | ||||
|   positionCompany: string; | ||||
|   email: string; | ||||
|   profile: string; | ||||
|   queues: Queue[]; | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ interface Request { | |||
|   email: string; | ||||
|   password: string; | ||||
|   name: string; | ||||
|   positionCompany?: string; | ||||
|   queueIds?: number[]; | ||||
|   profile?: string; | ||||
| } | ||||
|  | @ -16,7 +15,6 @@ interface Request { | |||
| interface Response { | ||||
|   email: string; | ||||
|   name: string; | ||||
|   positionCompany: string; | ||||
|   id: number; | ||||
|   profile: string; | ||||
| } | ||||
|  | @ -25,7 +23,6 @@ const CreateUserService = async ({ | |||
|   email, | ||||
|   password, | ||||
|   name, | ||||
|   positionCompany, | ||||
|   queueIds = [], | ||||
|   profile = "master" | ||||
| }: Request): Promise<Response> => { | ||||
|  | @ -73,7 +70,6 @@ const CreateUserService = async ({ | |||
|         email, | ||||
|         password, | ||||
|         name, | ||||
|         positionCompany, | ||||
|         profile | ||||
|       }, | ||||
|       { include: ["queues"] } | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ const ListUser = async ({ profile, userId, raw, userIds, profiles }: Request): P | |||
|   const users = await User.findAll({ | ||||
|     where: where_clause, | ||||
|     raw, | ||||
|     attributes: ["id", "name", "email", "positionCompany"], | ||||
|     attributes: ["id", "name", "email"], | ||||
| 
 | ||||
|     include: [ | ||||
|       { model: Queue, as: "queues", attributes: ["id", "name", "color"] } | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ const ListUsersService = async ({ | |||
| 
 | ||||
|   const { count, rows: users } = await User.findAndCountAll({ | ||||
|     where: whereCondition, | ||||
|     attributes: ["name", "id", "email","positionCompany", "profile", "createdAt"], | ||||
|     attributes: ["name", "id", "email", "profile", "createdAt"], | ||||
|     limit, | ||||
|     offset, | ||||
|     order: [["createdAt", "DESC"]], | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import Queue from "../../models/Queue"; | |||
| 
 | ||||
| const ShowUserService = async (id: string | number): Promise<User> => { | ||||
|   const user = await User.findByPk(id, { | ||||
|     attributes: ["name", "id", "email", "profile", "positionCompany", "tokenVersion"], | ||||
|     attributes: ["name", "id", "email", "profile", "tokenVersion"], | ||||
|     include: [ | ||||
|       { model: Queue, as: "queues", attributes: ["id", "name", "color"] } | ||||
|     ], | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ interface UserData { | |||
|   email?: string; | ||||
|   password?: string; | ||||
|   name?: string; | ||||
|   positionCompany?: string; | ||||
|   profile?: string; | ||||
|   queueIds?: number[]; | ||||
| } | ||||
|  | @ -61,7 +60,7 @@ const UpdateUserService = async ({ | |||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|     const { email, password, profile, name, positionCompany, queueIds = [] } = userData; | ||||
|     const { email, password, profile, name, queueIds = [] } = userData; | ||||
| 
 | ||||
|     try { | ||||
|       await schema.validate({ email, password, profile, name }); | ||||
|  | @ -74,7 +73,6 @@ const UpdateUserService = async ({ | |||
|       email, | ||||
|       password, | ||||
|       profile, | ||||
|       positionCompany, | ||||
|       name | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -87,7 +87,6 @@ import { Op } from "sequelize"; | |||
| 
 | ||||
| import SettingTicket from "../../models/SettingTicket"; | ||||
| import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase"; | ||||
| import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber"; | ||||
| 
 | ||||
| var lst: any[] = getWhatsappIds(); | ||||
| 
 | ||||
|  | @ -167,6 +166,7 @@ const verifyMediaMessage = async ( | |||
|     phoneNumberId: msg?.phoneNumberId | ||||
|   }; | ||||
|   | ||||
| 
 | ||||
|   if (!ticket?.phoneNumberId) { | ||||
|     if (!media.filename) { | ||||
|       const ext = media.mimetype.split("/")[1].split(";")[0]; | ||||
|  | @ -263,6 +263,10 @@ const verifyMediaMessage = async ( | |||
| //   return newMessage;
 | ||||
| // };
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| const verifyMessage = async ( | ||||
|   msg: any, | ||||
|   ticket: Ticket, | ||||
|  | @ -343,9 +347,7 @@ const verifyQueue = async ( | |||
|     } | ||||
|     //
 | ||||
| 
 | ||||
|     let whatsapp: any = await whatsappInfo(ticket?.whatsappId); | ||||
| 
 | ||||
|     const outService = await outOfService(whatsapp?.number); | ||||
|     const outService = await outOfService(); | ||||
| 
 | ||||
|     if (outService.length > 0) { | ||||
|       const { type, msg: msgOutService } = outService[0]; | ||||
|  | @ -553,21 +555,17 @@ const handleMessage = async ( | |||
|     // let groupContact: Contact | undefined;
 | ||||
| 
 | ||||
|     if (msg.fromMe) { | ||||
|       const whatsapp = await whatsappInfo(wbot.id); | ||||
|       const ticketExpiration = await SettingTicket.findOne({ | ||||
|         where: { key: "ticketExpiration" } | ||||
|       }); | ||||
| 
 | ||||
|       if (whatsapp?.number) { | ||||
|         const ticketExpiration = await SettingTicket.findOne({ | ||||
|           where: { key: "ticketExpiration", number: whatsapp.number } | ||||
|         }); | ||||
| 
 | ||||
|         if ( | ||||
|           ticketExpiration && | ||||
|           ticketExpiration.value == "enabled" && | ||||
|           ticketExpiration?.message.trim() == msg.body.trim() | ||||
|         ) { | ||||
|           console.log("*********** TICKET EXPIRATION"); | ||||
|           return; | ||||
|         } | ||||
|       if ( | ||||
|         ticketExpiration && | ||||
|         ticketExpiration.value == "enabled" && | ||||
|         ticketExpiration?.message.trim() == msg.body.trim() | ||||
|       ) { | ||||
|         console.log("*********** TICKET EXPIRATION"); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       // messages sent automatically by wbot have a special character in front of it
 | ||||
|  | @ -696,23 +694,22 @@ const handleMessage = async ( | |||
|       ticketHasQueue = true; | ||||
|     } | ||||
| 
 | ||||
|     if (ticketHasQueue && ticket.status != "open") { | ||||
|       let whatsapp: any = await whatsappInfo(ticket?.whatsappId); | ||||
|      if (ticketHasQueue && ticket.status != "open") { | ||||
|        const outService = await outOfService(); | ||||
| 
 | ||||
|       const outService = await outOfService(whatsapp.number); | ||||
|        if (outService.length > 0) { | ||||
|          const { type, msg: msgOutService } = outService[0]; | ||||
| 
 | ||||
|       if (outService.length > 0) { | ||||
|         const { type, msg: msgOutService } = outService[0]; | ||||
|          if (msg.fromMe && msgOutService == msg.body) { | ||||
|            console.log(`${type} message ignored`); | ||||
|            return; | ||||
|          } | ||||
| 
 | ||||
|         if (msg.fromMe && msgOutService == msg.body) { | ||||
|           console.log(`${type} message ignored`); | ||||
|           return; | ||||
|         } | ||||
|          botSendMessage(ticket, msgOutService); | ||||
|          return; | ||||
|        } | ||||
|      } | ||||
|       | ||||
|         botSendMessage(ticket, msgOutService); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|   } catch (err) { | ||||
|     Sentry.captureException(err); | ||||
|     console.log("Error handling whatsapp message: Err: ", err); | ||||
|  | @ -781,9 +778,9 @@ const wbotMessageListener = (wbot: Session): void => { | |||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const outOfService = async (number: string) => { | ||||
| const outOfService = async () => { | ||||
|   // MESSAGE TO HOLIDAY
 | ||||
|   const holiday: any = await isHoliday(number); | ||||
|   const holiday: any = await isHoliday(); | ||||
| 
 | ||||
|   let objs: any = []; | ||||
| 
 | ||||
|  | @ -792,14 +789,14 @@ const outOfService = async (number: string) => { | |||
|   } | ||||
| 
 | ||||
|   // MESSAGES TO SATURDAY OR SUNDAY
 | ||||
|   const weekend: any = await isWeekend(number); | ||||
|   const weekend: any = await isWeekend(); | ||||
| 
 | ||||
|   if (weekend && weekend.set) { | ||||
|     objs.push({ type: "weekend", msg: weekend.msg }); | ||||
|   } | ||||
| 
 | ||||
|   // MESSAGE TO BUSINESS TIME
 | ||||
|   const businessTime = await isOutBusinessTime(number); | ||||
|   const businessTime = await isOutBusinessTime(); | ||||
| 
 | ||||
|   if (businessTime && businessTime.set) { | ||||
|     objs.push({ type: "businessTime", msg: businessTime.msg }); | ||||
|  | @ -819,6 +816,3 @@ export { | |||
|   isValidMsg, | ||||
|   mediaTypeWhatsappOfficial | ||||
| }; | ||||
| async function whatsappInfo(whatsappId: string | number) { | ||||
|   return await Whatsapp.findByPk(whatsappId); | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| REACT_APP_BACKEND_URL = http://localhost:8080/ | ||||
|  | @ -1,4 +1,4 @@ | |||
| import React, { useState, useEffect, useContext } from 'react' | ||||
| import React, { useState, useEffect, } from 'react' | ||||
| // import * as Yup from 'yup'
 | ||||
| import { Formik, Form, Field, } from 'formik' | ||||
| import { toast } from 'react-toastify' | ||||
|  | @ -12,7 +12,7 @@ import DateFnsUtils from '@date-io/date-fns' | |||
| 
 | ||||
| import ptBrLocale from "date-fns/locale/pt-BR" | ||||
| 
 | ||||
| import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext" | ||||
| 
 | ||||
| 
 | ||||
| import { | ||||
|     MuiPickersUtilsProvider, | ||||
|  | @ -28,16 +28,12 @@ import { | |||
|     TextField, | ||||
|     Switch, | ||||
|     FormControlLabel, | ||||
|     Divider, | ||||
| } from '@material-ui/core' | ||||
| 
 | ||||
| import api from '../../services/api' | ||||
| import { i18n } from '../../translate/i18n' | ||||
| import toastError from '../../errors/toastError' | ||||
| 
 | ||||
| import Select from "@material-ui/core/Select" | ||||
| import MenuItem from "@material-ui/core/MenuItem" | ||||
| 
 | ||||
| const useStyles = makeStyles((theme) => ({ | ||||
|     root: { | ||||
|         display: 'flex', | ||||
|  | @ -91,35 +87,13 @@ const ConfigModal = ({ open, onClose, change }) => { | |||
|         enableWeekendMessage: false | ||||
|     } | ||||
| 
 | ||||
|     const { whatsApps } = useContext(WhatsAppsContext) | ||||
|     const [selectedNumber, setSelectedNumber] = useState('') | ||||
| 
 | ||||
|     const [config, setConfig] = useState(initialState) | ||||
| 
 | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         console.log('selectedNumber: ', selectedNumber) | ||||
| 
 | ||||
|         if (selectedNumber?.trim().length === 0) { | ||||
|             setConfig(initialState) | ||||
|         } | ||||
| 
 | ||||
|     }, [selectedNumber]) | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         const fetchSession = async () => { | ||||
| 
 | ||||
|             try { | ||||
|                 // const { data } = await api.get('/settings')  
 | ||||
| 
 | ||||
|                 if (!selectedNumber) return | ||||
| 
 | ||||
|                 const { data } = await api.get(`/settings/ticket/${selectedNumber}`) | ||||
|   | ||||
|                 if (data?.config && data.config.length === 0) { | ||||
|                     setConfig(initialState) | ||||
|                     return | ||||
|                 } | ||||
|                 const { data } = await api.get('/settings')  | ||||
| 
 | ||||
|                 const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours") | ||||
|                 const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration") | ||||
|  | @ -153,12 +127,11 @@ const ConfigModal = ({ open, onClose, change }) => { | |||
|             } | ||||
|         } | ||||
|         fetchSession() | ||||
|     }, [change, selectedNumber]) | ||||
|     }, [change]) | ||||
| 
 | ||||
|     const handleSaveConfig = async (values) => { | ||||
| 
 | ||||
|         values = { | ||||
|             number: selectedNumber, | ||||
|             outBusinessHours: { | ||||
|                 startTime: values.startTimeBus, | ||||
|                 endTime: values.endTimeBus, | ||||
|  | @ -174,7 +147,7 @@ const ConfigModal = ({ open, onClose, change }) => { | |||
|                 message: values.weekendMessage, | ||||
|                 value: values.enableWeekendMessage ? 'enabled' : 'disabled' | ||||
|             }, | ||||
|             saturday: { | ||||
|             saturday:{ | ||||
|                 value: values.checkboxSaturdayValue ? 'enabled' : 'disabled' | ||||
|             }, | ||||
|             sunday: { | ||||
|  | @ -238,39 +211,6 @@ const ConfigModal = ({ open, onClose, change }) => { | |||
| 
 | ||||
|                                 <DialogContent dividers> | ||||
| 
 | ||||
|                                     <div> | ||||
|                                         <Select | ||||
|                                             value={selectedNumber} | ||||
|                                             onChange={(e) => setSelectedNumber(e.target.value)} | ||||
|                                             label={i18n.t("transferTicketModal.fieldQueuePlaceholder")} | ||||
|                                             required | ||||
|                                         > | ||||
|                                             <MenuItem style={{ background: "white", }} value={''}> </MenuItem> | ||||
| 
 | ||||
|                                             {whatsApps.reduce((acc, curr) => { | ||||
|                                                 const existingObject = acc.find(item => item.number === curr.number) | ||||
| 
 | ||||
|                                                 if (!existingObject) { | ||||
|                                                     acc.push(curr) | ||||
|                                                 } | ||||
| 
 | ||||
|                                                 return acc | ||||
|                                             }, []).map((whatsapp) => ( | ||||
|                                                 <MenuItem | ||||
|                                                     key={whatsapp.id} | ||||
|                                                     value={whatsapp.number} | ||||
|                                                 > | ||||
|                                                     {whatsapp.number} | ||||
|                                                 </MenuItem> | ||||
|                                             ))} | ||||
|                                         </Select> | ||||
|                                     </div> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                                     <Divider /> | ||||
|                                     <br /> | ||||
| 
 | ||||
|                                     <div className={classes.multFieldLine}> | ||||
|                                         <Field | ||||
|                                             component={TimePicker} | ||||
|  |  | |||
|  | @ -227,30 +227,9 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { | |||
| 				<DialogTitle id="form-dialog-title"> | ||||
| 					{i18n.t("transferTicketModal.title")} | ||||
| 				</DialogTitle> | ||||
| 				<DialogContent dividers > | ||||
| 					<FormControl variant="outlined" className={classes.maxWidth} style={{marginBottom: '8px'}}> | ||||
| 						{/* <InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel> */} | ||||
| 
 | ||||
| 						<InputLabel>{'Usuário'}</InputLabel> | ||||
| 
 | ||||
| 						<Select | ||||
| 							value={selectedUser} | ||||
| 							onChange={e => setSelectedUser(e.target.value)} | ||||
| 							label={'Transfeir para fila'} | ||||
| 						> | ||||
| 							<MenuItem style={{ background: "white", }} value={''}> </MenuItem> | ||||
| 							{users.map((user) => ( | ||||
| 								<MenuItem | ||||
| 									key={user.id} | ||||
| 									value={user.id} | ||||
| 								>{user.name} | ||||
| 								</MenuItem> | ||||
| 							))} | ||||
| 						</Select> | ||||
| 					</FormControl>  | ||||
| 
 | ||||
| 				<DialogContent dividers> | ||||
| 					<FormControl variant="outlined" className={classes.maxWidth}> | ||||
| 						<InputLabel>{i18n.t("transferTicketModal.fieldQueuePlaceholder")}</InputLabel> | ||||
| 						<InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel> | ||||
| 
 | ||||
| 						<Select | ||||
| 							value={selectedQueue} | ||||
|  | @ -274,6 +253,24 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { | |||
| 						</Select> | ||||
| 
 | ||||
| 
 | ||||
| 						<br /> | ||||
| 
 | ||||
| 						<Select | ||||
| 							value={selectedUser} | ||||
| 							onChange={e => setSelectedUser(e.target.value)} | ||||
| 							label={'Transfeir para usuario'} | ||||
| 						> | ||||
| 							<MenuItem style={{ background: "white", }} value={''}> </MenuItem> | ||||
| 							{users.map((user) => ( | ||||
| 								<MenuItem | ||||
| 									key={user.id} | ||||
| 									value={user.id} | ||||
| 								>{user.name} | ||||
| 								</MenuItem> | ||||
| 							))} | ||||
| 						</Select> | ||||
| 
 | ||||
| 
 | ||||
| 					</FormControl> | ||||
| 				</DialogContent> | ||||
| 				<DialogActions> | ||||
|  |  | |||
|  | @ -84,8 +84,6 @@ const UserModal = ({ open, onClose, userId }) => { | |||
| 		name: "", | ||||
| 		email: "", | ||||
| 		password: "", | ||||
| 		positionCompany: "", | ||||
| 		position: "", | ||||
| 		profile: "user", | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -222,9 +220,10 @@ const UserModal = ({ open, onClose, userId }) => { | |||
| 										fullWidth | ||||
| 									/> | ||||
| 								</div> | ||||
| 								<div className={classes.multFieldLine}> | ||||
| 									<Field | ||||
| 										as={TextField} | ||||
| 										label='Login' | ||||
| 										label={i18n.t("userModal.form.email")} | ||||
| 										name="email" | ||||
| 										error={touched.email && Boolean(errors.email)} | ||||
| 										helperText={touched.email && errors.email} | ||||
|  | @ -232,17 +231,6 @@ const UserModal = ({ open, onClose, userId }) => { | |||
| 										margin="dense" | ||||
| 										fullWidth | ||||
| 									/> | ||||
| 								<div className={classes.multFieldLine}> | ||||
| 									<Field | ||||
| 									as={TextField} | ||||
| 									label="Cargo" | ||||
| 									name="positionCompany" | ||||
| 									error={touched.name && Boolean(errors.name)} | ||||
| 									helperText={touched.name && errors.name} | ||||
| 									variant="outlined" | ||||
| 									margin="dense" | ||||
| 									fullWidth | ||||
| 								/> | ||||
| 									<FormControl | ||||
| 										variant="outlined" | ||||
| 										className={classes.formControl} | ||||
|  | @ -274,7 +262,6 @@ const UserModal = ({ open, onClose, userId }) => { | |||
| 										/> | ||||
| 									</FormControl> | ||||
| 								</div> | ||||
| 										 | ||||
| 								<Can | ||||
| 									role={loggedInUser.profile} | ||||
| 									perform="user-modal:editQueues" | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import { Badge } from '@material-ui/core' | |||
| import DashboardOutlinedIcon from '@material-ui/icons/DashboardOutlined' | ||||
| 
 | ||||
| import ReportOutlinedIcon from '@material-ui/icons/ReportOutlined'   | ||||
| import CampaignIcon from '@material-ui/icons/Send' | ||||
| import CampaignIcon from '@material-ui/icons/Send'; | ||||
| 
 | ||||
| 
 | ||||
| import SendOutlined from '@material-ui/icons/SendOutlined' | ||||
|  | @ -29,10 +29,6 @@ import { i18n } from '../translate/i18n' | |||
| import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext' | ||||
| import { AuthContext } from '../context/Auth/AuthContext' | ||||
| import { Can } from '../components/Can' | ||||
| import openSocket from 'socket.io-client' | ||||
| import api from '../services/api' | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| function ListItemLink(props) { | ||||
|   const { icon, primary, to, className } = props | ||||
|  | @ -60,8 +56,6 @@ const MainListItems = (props) => { | |||
|   const { whatsApps } = useContext(WhatsAppsContext) | ||||
|   const { user } = useContext(AuthContext) | ||||
|   const [connectionWarning, setConnectionWarning] = useState(false) | ||||
|   const [settings, setSettings] = useState([]) | ||||
| 
 | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const delayDebounceFn = setTimeout(() => { | ||||
|  | @ -85,55 +79,6 @@ const MainListItems = (props) => { | |||
|     return () => clearTimeout(delayDebounceFn) | ||||
|   }, [whatsApps]) | ||||
| 
 | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const delayDebounceFn = setTimeout(() => { | ||||
|       const fetchSession = async () => { | ||||
|         try { | ||||
|           try { | ||||
|             const { data } = await api.get('/settings') | ||||
| 
 | ||||
|             setSettings(data.settings) | ||||
|           } catch (err) { | ||||
|             // toastError(err)
 | ||||
|           } | ||||
|         } catch (err) { | ||||
|           // toastError(err)
 | ||||
|         } | ||||
|       } | ||||
|       fetchSession() | ||||
|     }, 500) | ||||
|     return () => clearTimeout(delayDebounceFn) | ||||
| 
 | ||||
|   }, []) | ||||
| 
 | ||||
|   const getSettingValue = (key) => { | ||||
| 
 | ||||
|     return settings?.find((s) => s?.key === key)?.value | ||||
| 
 | ||||
|     // const { value } = settings.find((s) => s?.key === key)
 | ||||
|     // return value
 | ||||
|   } | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const socket = openSocket(process.env.REACT_APP_BACKEND_URL) | ||||
| 
 | ||||
|     socket.on('settings', (data) => { | ||||
|       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() | ||||
|     } | ||||
|   }, []) | ||||
| 
 | ||||
|   return ( | ||||
|     //Solicitado pelo Adriano: Click no LinkItem e fechar o menu!
 | ||||
|     <div onClick={() => setDrawerOpen(false)}> | ||||
|  | @ -167,7 +112,11 @@ const MainListItems = (props) => { | |||
|           <> | ||||
|             <Divider /> | ||||
|             <ListSubheader inset>{i18n.t("mainDrawer.listItems.administration")}</ListSubheader> | ||||
| 
 | ||||
|             <ListItemLink | ||||
|               to="/users" | ||||
|               primary={i18n.t("mainDrawer.listItems.users")} | ||||
|               icon={<PeopleAltOutlinedIcon />} | ||||
|             /> | ||||
|             <ListItemLink | ||||
|               to="/" | ||||
|               primary="Dashboard" | ||||
|  | @ -191,11 +140,7 @@ const MainListItems = (props) => { | |||
|         perform="drawer-admin-items:view" | ||||
|         yes={() => ( | ||||
|           <> | ||||
|             <ListItemLink | ||||
|               to="/users" | ||||
|               primary={i18n.t("mainDrawer.listItems.users")} | ||||
|               icon={<PeopleAltOutlinedIcon />} | ||||
|             /> | ||||
|         | ||||
|             <ListItemLink | ||||
|               to="/queues" | ||||
|               primary={i18n.t('mainDrawer.listItems.queues')} | ||||
|  | @ -224,16 +169,11 @@ const MainListItems = (props) => { | |||
|               icon={<ReportOutlinedIcon />} | ||||
|             /> */} | ||||
| 
 | ||||
|             { | ||||
|               (getSettingValue('hasCampaign') === 'enabled' || user.profile === 'master') && ( | ||||
|                 <ListItemLink | ||||
|                   to="/campaign" | ||||
|                   primary="Campanha" | ||||
|                   icon={<CampaignIcon />} | ||||
|                 /> | ||||
|               ) | ||||
|             } | ||||
| 
 | ||||
|             <ListItemLink | ||||
|               to="/campaign" | ||||
|               primary="Campanha" | ||||
|               icon={<CampaignIcon />} | ||||
|             /> | ||||
| 
 | ||||
|             <Can | ||||
|               role={user.profile} | ||||
|  |  | |||
|  | @ -103,7 +103,7 @@ const Queues = () => { | |||
|   const [settings, setSettings] = useState([]) | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     ; (async () => { | ||||
|     ;(async () => { | ||||
|       setLoading(true) | ||||
|       try { | ||||
|         const { data } = await api.get('/queue') | ||||
|  | @ -203,7 +203,8 @@ const Queues = () => { | |||
|           <ConfirmationModal | ||||
|             title={ | ||||
|               selectedQueue && | ||||
|               `${i18n.t('queues.confirmationModal.deleteTitle')} ${selectedQueue.name | ||||
|               `${i18n.t('queues.confirmationModal.deleteTitle')} ${ | ||||
|                 selectedQueue.name | ||||
|               }?` | ||||
|             } | ||||
|             open={confirmModalOpen} | ||||
|  | @ -300,36 +301,28 @@ const Queues = () => { | |||
|                                 settings.length > 0 && | ||||
|                                 getSettingValue('editQueue') && | ||||
|                                 getSettingValue('editQueue') === 'enabled') | | ||||
|                                 (user.profile === 'master') ? ( | ||||
| 
 | ||||
|                                 <> | ||||
|                                   <IconButton | ||||
|                                     size="small" | ||||
|                                     onClick={() => handleEditQueue(queue)} | ||||
|                                   > | ||||
|                                     <Edit /> | ||||
|                                   </IconButton> | ||||
|                                   <IconButton | ||||
|                                     size="small" | ||||
|                                     onClick={() => { | ||||
|                                       setSelectedQueue(queue) | ||||
|                                       setConfirmModalOpen(true) | ||||
|                                     }} | ||||
|                                   > | ||||
|                                     <DeleteOutline /> | ||||
|                                   </IconButton> | ||||
|                                 </> | ||||
| 
 | ||||
| 
 | ||||
|                               (user.profile === 'master') ? ( | ||||
|                                 <IconButton | ||||
|                                   size="small" | ||||
|                                   onClick={() => handleEditQueue(queue)} | ||||
|                                 > | ||||
|                                   <Edit /> | ||||
|                                 </IconButton> | ||||
|                               ) : ( | ||||
|                                 <div></div> | ||||
|                               )} | ||||
|                             </div> | ||||
| 
 | ||||
|                             // <IconButton
 | ||||
|                             //   size="small"
 | ||||
|                             //   onClick={() => handleEditQueue(queue)}
 | ||||
|                             // >
 | ||||
|                             //   <Edit />
 | ||||
|                             // </IconButton>
 | ||||
|                           )} | ||||
|                         /> | ||||
| 
 | ||||
|                         {/* <Can | ||||
|                         <Can | ||||
|                           role={user.profile} | ||||
|                           perform="show-icon-delete-queue" | ||||
|                           yes={() => ( | ||||
|  | @ -343,7 +336,7 @@ const Queues = () => { | |||
|                               <DeleteOutline /> | ||||
|                             </IconButton> | ||||
|                           )} | ||||
|                         /> */} | ||||
|                         /> | ||||
|                       </TableCell> | ||||
|                     </TableRow> | ||||
|                   ))} | ||||
|  |  | |||
|  | @ -221,19 +221,6 @@ let columnsData = [ | |||
|   { title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }] | ||||
| 
 | ||||
| let columnsDataSuper = [ | ||||
|   { title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column1_2")}`, field: 'user.name' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'contact.name' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column1_5")}`, field: 'queue.name' }, | ||||
| 
 | ||||
|   { title: 'Status', field: 'status' }, | ||||
| 
 | ||||
|   { title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' }, | ||||
|   { title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' } | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
|   | ||||
| // function convertAndFormatDate(dateString) {
 | ||||
|  | @ -258,6 +245,7 @@ let columnsDataSuper = [ | |||
| const Report = () => { | ||||
| 
 | ||||
|   const { user: userA } = useContext(AuthContext) | ||||
| 
 | ||||
|   //-------- 
 | ||||
|   const [searchParam] = useState("") | ||||
| 
 | ||||
|  | @ -328,21 +316,14 @@ const Report = () => { | |||
|       setLoading(true) | ||||
|       const fetchQueries = async () => { | ||||
|         try { | ||||
| 
 | ||||
|           if (reportOption === '1') {  | ||||
| 
 | ||||
|             // const { data } = await api.get("/reports/", { params: { userId: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
 | ||||
| 
 | ||||
|             const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, userQueues: userA.queues}) | ||||
|             const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, }) | ||||
| 
 | ||||
| 
 | ||||
|             let ticketsQueue = data.tickets; | ||||
|             let userQueues = userA.queues; | ||||
|             let filterQueuesTickets = []; | ||||
|             if(userQueues.length > 1){ | ||||
|                 filterQueuesTickets = ticketsQueue.filter(ticket => userQueues.some(queue => queue?.name === ticket?.queue?.name)); | ||||
|             }else if(userQueues.length > 0) { | ||||
|                filterQueuesTickets = ticketsQueue.filter(ticket => ticket?.queue?.name === userQueues[0]?.name); | ||||
|             } | ||||
|             data.tickets = filterQueuesTickets; | ||||
|             dispatchQ({ type: "LOAD_QUERY", payload: data.tickets }) | ||||
| 
 | ||||
|             setHasMore(data.hasMore) | ||||
|  | @ -703,7 +684,7 @@ const Report = () => { | |||
|                 <> | ||||
| 
 | ||||
|                   <MTable data={query} | ||||
|                     columns={userA.profile !== 'supervisor' ?columnsData:columnsDataSuper} | ||||
|                     columns={columnsData} | ||||
|                     hasChild={true} | ||||
|                     removeClickRow={false} | ||||
| 
 | ||||
|  |  | |||
|  | @ -285,33 +285,6 @@ const Settings = () => { | |||
|             </Container> | ||||
|           </div> | ||||
| 
 | ||||
|           <div className={classes.root}> | ||||
|             <Container className={classes.container} maxWidth="sm"> | ||||
|               <Paper className={classes.paper}> | ||||
|                 <Typography variant="body1"> | ||||
|                   Modulo campanha | ||||
|                 </Typography> | ||||
| 
 | ||||
|                 <Select | ||||
|                   margin="dense" | ||||
|                   variant="outlined" | ||||
|                   native | ||||
|                   id="hasCampaign-setting" | ||||
|                   name="hasCampaign" | ||||
|                   value={ | ||||
|                     settings && | ||||
|                     settings.length > 0 && | ||||
|                     getSettingValue('hasCampaign') | ||||
|                   } | ||||
|                   className={classes.settingOption} | ||||
|                   onChange={handleChangeSetting} | ||||
|                 > | ||||
|                   <option value="enabled">Ativado</option> | ||||
|                   <option value="disabled">Desativado</option> | ||||
|                 </Select> | ||||
|               </Paper> | ||||
|             </Container> | ||||
|           </div> | ||||
| 
 | ||||
|         </div> | ||||
|       )} | ||||
|  |  | |||
|  | @ -1,82 +1,82 @@ | |||
| import React, { useState, useEffect, useReducer, useContext } from "react" | ||||
| import { toast } from "react-toastify" | ||||
| import openSocket from "socket.io-client" | ||||
| import React, { useState, useEffect, useReducer, useContext} from "react"; | ||||
| import { toast } from "react-toastify"; | ||||
| import openSocket from "socket.io-client"; | ||||
| 
 | ||||
| import { makeStyles } from "@material-ui/core/styles" | ||||
| import Paper from "@material-ui/core/Paper" | ||||
| import Button from "@material-ui/core/Button" | ||||
| 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 IconButton from "@material-ui/core/IconButton" | ||||
| import SearchIcon from "@material-ui/icons/Search" | ||||
| import TextField from "@material-ui/core/TextField" | ||||
| import InputAdornment from "@material-ui/core/InputAdornment" | ||||
| import { makeStyles } from "@material-ui/core/styles"; | ||||
| import Paper from "@material-ui/core/Paper"; | ||||
| import Button from "@material-ui/core/Button"; | ||||
| 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 IconButton from "@material-ui/core/IconButton"; | ||||
| import SearchIcon from "@material-ui/icons/Search"; | ||||
| import TextField from "@material-ui/core/TextField"; | ||||
| import InputAdornment from "@material-ui/core/InputAdornment"; | ||||
| 
 | ||||
| import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline" | ||||
| import EditIcon from "@material-ui/icons/Edit" | ||||
| import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"; | ||||
| import EditIcon from "@material-ui/icons/Edit"; | ||||
| 
 | ||||
| import MainContainer from "../../components/MainContainer" | ||||
| import MainHeader from "../../components/MainHeader" | ||||
| import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper" | ||||
| import Title from "../../components/Title" | ||||
| import MainContainer from "../../components/MainContainer"; | ||||
| import MainHeader from "../../components/MainHeader"; | ||||
| import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper"; | ||||
| import Title from "../../components/Title"; | ||||
| 
 | ||||
| import api from "../../services/api" | ||||
| import { i18n } from "../../translate/i18n" | ||||
| import TableRowSkeleton from "../../components/TableRowSkeleton" | ||||
| import UserModal from "../../components/UserModal" | ||||
| import ConfirmationModal from "../../components/ConfirmationModal" | ||||
| import toastError from "../../errors/toastError" | ||||
| import api from "../../services/api"; | ||||
| import { i18n } from "../../translate/i18n"; | ||||
| import TableRowSkeleton from "../../components/TableRowSkeleton"; | ||||
| import UserModal from "../../components/UserModal"; | ||||
| import ConfirmationModal from "../../components/ConfirmationModal"; | ||||
| import toastError from "../../errors/toastError"; | ||||
| 
 | ||||
| //--------
 | ||||
| import { AuthContext } from "../../context/Auth/AuthContext" | ||||
| import { Can } from "../../components/Can" | ||||
| import { AuthContext } from "../../context/Auth/AuthContext"; | ||||
| import { Can } from "../../components/Can"; | ||||
| 
 | ||||
| const reducer = (state, action) => { | ||||
|   if (action.type === "LOAD_USERS") { | ||||
|     const users = action.payload | ||||
|     const newUsers = [] | ||||
|     const users = action.payload; | ||||
|     const newUsers = []; | ||||
| 
 | ||||
|     users.forEach((user) => { | ||||
|       const userIndex = state.findIndex((u) => u.id === user.id) | ||||
|       const userIndex = state.findIndex((u) => u.id === user.id); | ||||
|       if (userIndex !== -1) { | ||||
|         state[userIndex] = user | ||||
|         state[userIndex] = user; | ||||
|       } else { | ||||
|         newUsers.push(user) | ||||
|         newUsers.push(user); | ||||
|       } | ||||
|     }) | ||||
|     }); | ||||
| 
 | ||||
|     return [...state, ...newUsers] | ||||
|     return [...state, ...newUsers]; | ||||
|   } | ||||
| 
 | ||||
|   if (action.type === "UPDATE_USERS") { | ||||
|     const user = action.payload | ||||
|     const userIndex = state.findIndex((u) => u.id === user.id) | ||||
|     const user = action.payload; | ||||
|     const userIndex = state.findIndex((u) => u.id === user.id); | ||||
| 
 | ||||
|     if (userIndex !== -1) { | ||||
|       state[userIndex] = user | ||||
|       return [...state] | ||||
|       state[userIndex] = user; | ||||
|       return [...state]; | ||||
|     } else { | ||||
|       return [user, ...state] | ||||
|       return [user, ...state]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (action.type === "DELETE_USER") { | ||||
|     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 === "RESET") { | ||||
|     return [] | ||||
|     return []; | ||||
|   } | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| const useStyles = makeStyles((theme) => ({ | ||||
|   mainPaper: { | ||||
|  | @ -85,229 +85,167 @@ const useStyles = makeStyles((theme) => ({ | |||
|     overflowY: "scroll", | ||||
|     ...theme.scrollbarStyles, | ||||
|   }, | ||||
| })) | ||||
| })); | ||||
| 
 | ||||
| const Users = () => { | ||||
|   const classes = useStyles() | ||||
|   const classes = useStyles(); | ||||
|    | ||||
|   //--------
 | ||||
|   const { user: userA } = useContext(AuthContext) | ||||
| 
 | ||||
|   const [loading, setLoading] = useState(false) | ||||
|   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("") | ||||
|   const [users, dispatch] = useReducer(reducer, []) | ||||
|   const [settings, setSettings] = useState([]) | ||||
| 	const { user: userA } = useContext(AuthContext);  | ||||
| 
 | ||||
|   const [loading, setLoading] = useState(false); | ||||
|   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(""); | ||||
|   const [users, dispatch] = useReducer(reducer, []); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     dispatch({ type: "RESET" }) | ||||
|     setPageNumber(1) | ||||
|   }, [searchParam]) | ||||
|     dispatch({ type: "RESET" }); | ||||
|     setPageNumber(1); | ||||
|   }, [searchParam]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setLoading(true) | ||||
|     setLoading(true); | ||||
|     const delayDebounceFn = setTimeout(() => { | ||||
|       const fetchUsers = async () => { | ||||
|         try { | ||||
|           const { data } = await api.get("/users/", { | ||||
|             params: { searchParam, pageNumber }, | ||||
|           }) | ||||
|           dispatch({ type: "LOAD_USERS", payload: data.users }) | ||||
|           setHasMore(data.hasMore) | ||||
|           setLoading(false) | ||||
|           }); | ||||
|           dispatch({ type: "LOAD_USERS", payload: data.users }); | ||||
|           setHasMore(data.hasMore); | ||||
|           setLoading(false); | ||||
|         } catch (err) { | ||||
|           toastError(err) | ||||
|           toastError(err); | ||||
|         } | ||||
|       } | ||||
|       fetchUsers() | ||||
|     }, 500) | ||||
|     return () => clearTimeout(delayDebounceFn) | ||||
|   }, [searchParam, pageNumber]) | ||||
| 
 | ||||
| 
 | ||||
|       }; | ||||
|       fetchUsers(); | ||||
|     }, 500); | ||||
|     return () => clearTimeout(delayDebounceFn); | ||||
|   }, [searchParam, pageNumber]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const delayDebounceFn = setTimeout(() => { | ||||
|       const fetchSession = async () => { | ||||
|         try { | ||||
|           try { | ||||
|             const { data } = await api.get('/settings') | ||||
| 
 | ||||
|             setSettings(data.settings) | ||||
|           } catch (err) { | ||||
|             toastError(err) | ||||
|           } | ||||
|         } catch (err) { | ||||
|           toastError(err) | ||||
|         } | ||||
|       } | ||||
|       fetchSession() | ||||
|     }, 500) | ||||
|     return () => clearTimeout(delayDebounceFn)  | ||||
| 
 | ||||
|   }, []) | ||||
| 
 | ||||
|   const getSettingValue = (key) => { | ||||
|      | ||||
|    return  settings?.find((s) => s?.key === key)?.value | ||||
| 
 | ||||
|     // const { value } = settings.find((s) => s?.key === key)
 | ||||
|     // return value
 | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const socket = openSocket(process.env.REACT_APP_BACKEND_URL) | ||||
|     const socket = openSocket(process.env.REACT_APP_BACKEND_URL); | ||||
| 
 | ||||
|     socket.on("user", (data) => { | ||||
|       if (data.action === "update" || data.action === "create") { | ||||
|         dispatch({ type: "UPDATE_USERS", payload: data.user }) | ||||
|         dispatch({ type: "UPDATE_USERS", payload: data.user }); | ||||
|       } | ||||
| 
 | ||||
|       if (data.action === "delete") { | ||||
|         dispatch({ type: "DELETE_USER", payload: +data.userId }) | ||||
|         dispatch({ type: "DELETE_USER", payload: +data.userId }); | ||||
|       } | ||||
|     }) | ||||
| 
 | ||||
| 
 | ||||
|     socket.on('settings', (data) => { | ||||
|       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() | ||||
|     } | ||||
|   }, []) | ||||
|       socket.disconnect(); | ||||
|     }; | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleOpenUserModal = () => { | ||||
|     setSelectedUser(null) | ||||
|     setUserModalOpen(true) | ||||
|   } | ||||
|     setSelectedUser(null); | ||||
|     setUserModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleCloseUserModal = () => { | ||||
|     setSelectedUser(null) | ||||
|     setUserModalOpen(false) | ||||
|   } | ||||
|     setSelectedUser(null); | ||||
|     setUserModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSearch = (event) => { | ||||
|     setSearchParam(event.target.value.toLowerCase()) | ||||
|   } | ||||
|     setSearchParam(event.target.value.toLowerCase()); | ||||
|   }; | ||||
| 
 | ||||
|   const handleEditUser = (user) => { | ||||
|     setSelectedUser(user) | ||||
|     setUserModalOpen(true) | ||||
|   } | ||||
|     setSelectedUser(user); | ||||
|     setUserModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDeleteUser = async (userId) => { | ||||
|     try { | ||||
|       await api.delete(`/users/${userId}`) | ||||
|       toast.success(i18n.t("users.toasts.deleted")) | ||||
|       await api.delete(`/users/${userId}`); | ||||
|       toast.success(i18n.t("users.toasts.deleted")); | ||||
|     } catch (err) { | ||||
|       toastError(err) | ||||
|       toastError(err); | ||||
|     } | ||||
|     setDeletingUser(null) | ||||
|     setSearchParam("") | ||||
|     setPageNumber(1) | ||||
|   } | ||||
|     setDeletingUser(null); | ||||
|     setSearchParam(""); | ||||
|     setPageNumber(1); | ||||
|   }; | ||||
| 
 | ||||
|   const loadMore = () => { | ||||
|     setPageNumber((prevState) => prevState + 1) | ||||
|   } | ||||
|     setPageNumber((prevState) => prevState + 1); | ||||
|   }; | ||||
| 
 | ||||
|   const handleScroll = (e) => { | ||||
|     if (!hasMore || loading) return | ||||
|     const { scrollTop, scrollHeight, clientHeight } = e.currentTarget | ||||
|     if (!hasMore || loading) return; | ||||
|     const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; | ||||
|     if (scrollHeight - (scrollTop + 100) < clientHeight) { | ||||
|       loadMore() | ||||
|       loadMore(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   console.log('userA.profile: ', userA.profile) | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
| 
 | ||||
|     <Can | ||||
|       role={userA.profile} | ||||
|       perform="user-view:show" | ||||
|       yes={() => ( | ||||
| 		  role={userA.profile} | ||||
| 		  perform="user-view:show" | ||||
| 		  yes={() => ( | ||||
|         <MainContainer> | ||||
|           <ConfirmationModal | ||||
|             title={ | ||||
|               deletingUser && | ||||
|               `${i18n.t("users.confirmationModal.deleteTitle")} ${deletingUser.name | ||||
|               }?` | ||||
|             } | ||||
|             open={confirmModalOpen} | ||||
|             onClose={setConfirmModalOpen} | ||||
|             onConfirm={() => handleDeleteUser(deletingUser.id)} | ||||
|           > | ||||
|             {i18n.t("users.confirmationModal.deleteMessage")} | ||||
|           </ConfirmationModal> | ||||
|           <UserModal | ||||
|             open={userModalOpen} | ||||
|             onClose={handleCloseUserModal} | ||||
|             aria-labelledby="form-dialog-title" | ||||
|             userId={selectedUser && selectedUser.id} | ||||
|           /> | ||||
|           <MainHeader> | ||||
|             <Title>{i18n.t("users.title")}</Title> | ||||
|             <MainHeaderButtonsWrapper> | ||||
|               <TextField | ||||
|                 placeholder={i18n.t("contacts.searchPlaceholder")} | ||||
|                 type="search" | ||||
|                 value={searchParam} | ||||
|                 onChange={handleSearch} | ||||
|                 InputProps={{ | ||||
|                   startAdornment: ( | ||||
|                     <InputAdornment position="start"> | ||||
|                       <SearchIcon style={{ color: "gray" }} /> | ||||
|                     </InputAdornment> | ||||
|                   ), | ||||
|                 }} | ||||
|               /> | ||||
|         <ConfirmationModal | ||||
|           title={ | ||||
|             deletingUser && | ||||
|             `${i18n.t("users.confirmationModal.deleteTitle")} ${ | ||||
|               deletingUser.name | ||||
|             }?` | ||||
|           } | ||||
|           open={confirmModalOpen} | ||||
|           onClose={setConfirmModalOpen} | ||||
|           onConfirm={() => handleDeleteUser(deletingUser.id)} | ||||
|         > | ||||
|           {i18n.t("users.confirmationModal.deleteMessage")} | ||||
|         </ConfirmationModal> | ||||
|         <UserModal | ||||
|           open={userModalOpen} | ||||
|           onClose={handleCloseUserModal} | ||||
|           aria-labelledby="form-dialog-title" | ||||
|           userId={selectedUser && selectedUser.id} | ||||
|         /> | ||||
|         <MainHeader> | ||||
|           <Title>{i18n.t("users.title")}</Title> | ||||
|           <MainHeaderButtonsWrapper> | ||||
|             <TextField | ||||
|               placeholder={i18n.t("contacts.searchPlaceholder")} | ||||
|               type="search" | ||||
|               value={searchParam} | ||||
|               onChange={handleSearch} | ||||
|               InputProps={{ | ||||
|                 startAdornment: ( | ||||
|                   <InputAdornment position="start"> | ||||
|                     <SearchIcon style={{ color: "gray" }} /> | ||||
|                   </InputAdornment> | ||||
|                 ), | ||||
|               }} | ||||
|             /> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|               { | ||||
|                 (getSettingValue('userCreation') === 'enabled' || userA.profile === 'master') && ( | ||||
|                   <Button | ||||
|                     variant="contained" | ||||
|                     color="primary" | ||||
|                     onClick={handleOpenUserModal} | ||||
|                   > | ||||
|                     {i18n.t("users.buttons.add")} | ||||
|                   </Button> | ||||
|                 ) | ||||
|               } | ||||
| 
 | ||||
| 
 | ||||
|               {/* <Can | ||||
|                 role={userA.profile} | ||||
|                 perform="btn-add-user" | ||||
|                 yes={() => ( | ||||
|                   <Button | ||||
|                     variant="contained" | ||||
|                     color="primary" | ||||
|                     onClick={handleOpenUserModal} | ||||
|                   > | ||||
|                     {i18n.t("users.buttons.add")} | ||||
|                   </Button> | ||||
|                 )} | ||||
|               /> */} | ||||
|             <Can | ||||
|                     role={userA.profile} | ||||
|                     perform="btn-add-user" | ||||
|                     yes={() => ( | ||||
|                       <Button | ||||
|                         variant="contained" | ||||
|                         color="primary" | ||||
|                         onClick={handleOpenUserModal} | ||||
|                       > | ||||
|                         {i18n.t("users.buttons.add")} | ||||
|                       </Button>  | ||||
|                     )} | ||||
|             /> | ||||
| 
 | ||||
|              | ||||
|               | ||||
|  | @ -329,9 +267,7 @@ const Users = () => { | |||
|                 <TableCell align="center"> | ||||
|                   {i18n.t("users.table.profile")} | ||||
|                 </TableCell> | ||||
|                 <TableCell align="center"> | ||||
|                   Cargo | ||||
|                 </TableCell> | ||||
|                  | ||||
|                 <TableCell align="center"> | ||||
|                   {i18n.t("users.table.actions")} | ||||
|                 </TableCell> | ||||
|  | @ -345,7 +281,6 @@ const Users = () => { | |||
|                     <TableCell align="center">{user.name}</TableCell> | ||||
|                     <TableCell align="center">{user.email}</TableCell> | ||||
|                     <TableCell align="center">{user.profile}</TableCell> | ||||
|                     <TableCell align="center">{user.positionCompany}</TableCell> | ||||
|                      | ||||
|                     <TableCell align="center"> | ||||
|                        | ||||
|  | @ -357,37 +292,37 @@ const Users = () => { | |||
|                       </IconButton> | ||||
| 
 | ||||
| 
 | ||||
|                         <Can | ||||
|                           role={userA.profile} | ||||
|                           perform="icon-remove-user" | ||||
|                           yes={() => ( | ||||
|                             <IconButton | ||||
|                               size="small" | ||||
|                               onClick={(e) => { | ||||
|                                 setConfirmModalOpen(true) | ||||
|                                 setDeletingUser(user) | ||||
|                               }} | ||||
|                             > | ||||
|                               <DeleteOutlineIcon /> | ||||
|                             </IconButton> | ||||
|                           )} | ||||
|                         /> | ||||
|                       <Can | ||||
|                             role={userA.profile} | ||||
|                             perform="icon-remove-user" | ||||
|                             yes={() => ( | ||||
|                               <IconButton | ||||
|                                 size="small" | ||||
|                                 onClick={(e) => { | ||||
|                                   setConfirmModalOpen(true); | ||||
|                                   setDeletingUser(user); | ||||
|                                 }} | ||||
|                               > | ||||
|                                 <DeleteOutlineIcon /> | ||||
|                               </IconButton>  | ||||
|                             )} | ||||
|                       />  | ||||
|    | ||||
|                       </TableCell> | ||||
|                     </TableCell> | ||||
|    | ||||
|                     </TableRow> | ||||
|                   ))} | ||||
|                   {loading && <TableRowSkeleton columns={4} />} | ||||
|                 </> | ||||
|               </TableBody> | ||||
|             </Table> | ||||
|           </Paper> | ||||
|         </MainContainer> | ||||
|       )} | ||||
|     /> | ||||
|                   </TableRow> | ||||
|                 ))} | ||||
|                 {loading && <TableRowSkeleton columns={4} />} | ||||
|               </> | ||||
|             </TableBody> | ||||
|           </Table> | ||||
|         </Paper> | ||||
|       </MainContainer> | ||||
| 		  )} | ||||
| 		/> | ||||
| 
 | ||||
|      | ||||
|   ) | ||||
| } | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Users | ||||
| export default Users; | ||||
|  |  | |||
|  | @ -16,7 +16,6 @@ const rules = { | |||
| 
 | ||||
|   admin: { | ||||
|     static: [ | ||||
|       'show-icon-add-queue', | ||||
|       'show-icon-edit-whatsapp', | ||||
|       'show-icon-edit-queue', | ||||
|       'menu-users:view', | ||||
|  | @ -32,7 +31,6 @@ const rules = { | |||
|       'queues-view:show', | ||||
|       'user-view:show', | ||||
|       'ticket-report:show', | ||||
|       'btn-add-user' | ||||
|     ], | ||||
|   }, | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue