Merge branch 'new_features' into _dialogflow_omnihit_hit_new_features
commit
763d707ca5
|
@ -23,6 +23,11 @@ WWebJS
|
|||
*/WWebJS/*
|
||||
**WWebJS
|
||||
|
||||
.wwebjs_auth
|
||||
*/wwebjs_auth/*
|
||||
.wwebjs_cache
|
||||
*/wwebjs_cache/*
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
PORT=8019
|
||||
PORT_START=8020
|
||||
BASE_URL=http://localhost
|
||||
BASE_URL=http://localhost
|
||||
PASS="strongpassword, strongpassword32"
|
||||
DB_MONGO_URL=mongodb://localhost:27017
|
||||
DB_MONGO_NAME=session_out_omnihit_db
|
||||
DB_MONGO_NAME_CAMPAIGN=broker_omnihit
|
||||
|
|
@ -1,486 +1,518 @@
|
|||
const express = require('express');
|
||||
const bodyparser = require('body-parser');
|
||||
const dotenv = require('dotenv');
|
||||
dotenv.config({ path: '.env' });
|
||||
const express = require('express')
|
||||
const bodyparser = require('body-parser')
|
||||
const dotenv = require('dotenv')
|
||||
dotenv.config({ path: '.env' })
|
||||
const copyFolder = require('./helpers/copyFolder')
|
||||
const createDir = require('./helpers/createDir')
|
||||
const createFile = require('./helpers/createFile')
|
||||
const path = require('path');
|
||||
const path = require('path')
|
||||
const db_info = require('./db_conn')
|
||||
const fs = require('fs');
|
||||
let mysql_conn = require('./helpers/mysql_conn.js');
|
||||
const { exec, execSync, spawn } = require("child_process");
|
||||
const fs = require('fs')
|
||||
let mysql_conn = require('./helpers/mysql_conn.js')
|
||||
const { exec, execSync, spawn } = require('child_process')
|
||||
|
||||
const startPm2Process = require('./helpers/startPm2Process');
|
||||
const removeDir = require('./helpers/remove_dir');
|
||||
const startPm2Process = require('./helpers/startPm2Process')
|
||||
const removeDir = require('./helpers/remove_dir')
|
||||
const setSessionName = require('./helpers/setSessionNumber')
|
||||
const getNumberFromName = require('./helpers/getNumberSequence')
|
||||
const pm2 = require('pm2');
|
||||
const pm2 = require('pm2')
|
||||
const bcrypt = require('bcrypt')
|
||||
const OmnihitDBConn = require('./model/db_conn')
|
||||
|
||||
const app = express();
|
||||
const app = express()
|
||||
|
||||
app.use(bodyparser.json());
|
||||
app.use(bodyparser.json())
|
||||
|
||||
app.get('/', function (req, res) { return res.send('Express + TypeScript Server'); });
|
||||
app.get('/', function (req, res) {
|
||||
return res.send('Express + TypeScript Server')
|
||||
})
|
||||
|
||||
app.post('/api/session', async function (req, res) {
|
||||
let { app_name, whatsappId, client_url, number } = req.body
|
||||
|
||||
let { app_name, whatsappId, client_url, number } = req.body
|
||||
if (app_name) {
|
||||
app_name = app_name.trim()
|
||||
}
|
||||
|
||||
if(app_name){
|
||||
app_name = app_name.trim()
|
||||
console.log('__dirname: ', path.join(__dirname, '..', app_name))
|
||||
|
||||
console.log(
|
||||
'app_name: ',
|
||||
app_name,
|
||||
' | whatsappId: ',
|
||||
whatsappId,
|
||||
' | client_url: ',
|
||||
client_url
|
||||
)
|
||||
|
||||
const sessionsPath = path.join(__dirname, '..', 'sessions')
|
||||
|
||||
const directoriesInDIrectory = fs
|
||||
.readdirSync(sessionsPath, { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name)
|
||||
|
||||
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
|
||||
|
||||
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
|
||||
|
||||
let dirSessionsApp = path.join(sessionsPath, app_name)
|
||||
|
||||
if (dirExist.length == 0) {
|
||||
let create = createDir(dirSessionsApp)
|
||||
|
||||
if (!create) {
|
||||
res.status(500).json({ message: 'Cannot create the directory path!' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
console.log('__dirname: ', path.join(__dirname, '..', app_name))
|
||||
let appPort = []
|
||||
|
||||
console.log('app_name: ', app_name, ' | whatsappId: ', whatsappId, ' | client_url: ',client_url)
|
||||
let existSubDir = false
|
||||
|
||||
const sessionsPath = path.join(__dirname, '..', 'sessions')
|
||||
for (let i = 0; i < directoriesInDIrectory.length; i++) {
|
||||
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
|
||||
|
||||
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name);
|
||||
const subDir = fs
|
||||
.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), {
|
||||
withFileTypes: true,
|
||||
})
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name)
|
||||
|
||||
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
|
||||
for (let x = 0; x < subDir.length; x++) {
|
||||
console.log('subdir: ', subDir[x])
|
||||
|
||||
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
|
||||
let whatsId = subDir[x].split('_')[0]
|
||||
|
||||
let dirSessionsApp = path.join(sessionsPath, app_name)
|
||||
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
|
||||
let currPath = path.join(
|
||||
sessionsPath,
|
||||
directoriesInDIrectory[i],
|
||||
subDir[x]
|
||||
)
|
||||
|
||||
if (dirExist.length == 0) {
|
||||
console.log(
|
||||
'PATH: ',
|
||||
path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
|
||||
)
|
||||
|
||||
let create = createDir(dirSessionsApp)
|
||||
let oldNumber = subDir[x].split('_')[1]
|
||||
|
||||
if (!create) {
|
||||
|
||||
res.status(500).json({ message: 'Cannot create the directory path!' })
|
||||
return
|
||||
if (oldNumber != number) {
|
||||
deletePm2Process(subDir[x], currPath)
|
||||
|
||||
removeDir(currPath)
|
||||
} else {
|
||||
res.send('ok')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let appPort = []
|
||||
let auxPort = subDir[x].split('_')[3]
|
||||
|
||||
console.log('---------> auxPort: ' + auxPort)
|
||||
|
||||
if (auxPort) {
|
||||
auxPort = +auxPort.trim()
|
||||
|
||||
let existSubDir = false
|
||||
|
||||
for (let i = 0; i < directoriesInDIrectory.length; i++) {
|
||||
|
||||
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
|
||||
|
||||
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name);
|
||||
|
||||
for (let x = 0; x < subDir.length; x++) {
|
||||
|
||||
console.log('subdir: ', subDir[x])
|
||||
|
||||
let whatsId = subDir[x].split('_')[0]
|
||||
|
||||
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
|
||||
|
||||
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
|
||||
|
||||
console.log('PATH: ', path.join(sessionsPath, directoriesInDIrectory[i], subDir[x]))
|
||||
|
||||
let oldNumber = subDir[x].split('_')[1]
|
||||
// let sessionNum = subDir[x].split('_')[2]
|
||||
// let sessionPort = subDir[x].split('_')[3]
|
||||
// let newSessionAppName = `${whatsId}_${number}_${sessionNum}_${sessionPort}`
|
||||
|
||||
// let newPath = path.join(sessionsPath, directoriesInDIrectory[i], newSessionAppName)
|
||||
|
||||
// console.log(`number: ${number}\noldNumber: ${oldNumber}\nsessionNum: ${sessionNum}\nsessionPort: ${sessionPort}\nnewSessionAppName:${newSessionAppName}`)
|
||||
|
||||
if (oldNumber != number) {
|
||||
|
||||
deletePm2Process(subDir[x], currPath)
|
||||
|
||||
removeDir(currPath)
|
||||
}
|
||||
else {
|
||||
res.send('ok')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// try {
|
||||
|
||||
// //
|
||||
|
||||
// fs.renameSync(currPath, newPath)
|
||||
|
||||
// console.log("Successfully renamed the directory.")
|
||||
|
||||
// const data = fs.readFileSync(path.join(`${newPath}`, '.env'), 'utf-8');
|
||||
|
||||
// // console.log('Data: ', data)
|
||||
|
||||
// const newValue = data.replace(`MOBILEUID=${oldNumber}`, `MOBILEUID=${number}`)
|
||||
|
||||
// fs.writeFileSync(path.join(`${newPath}`, '.env'), newValue, 'utf-8');
|
||||
|
||||
// if (oldNumber != number) {
|
||||
// removeDir(path.join(newPath, '.wwebjs_auth'))
|
||||
// }
|
||||
|
||||
// startPm2Process(newSessionAppName, 'app.js', newPath, sessionPort)
|
||||
|
||||
|
||||
// } catch (err) {
|
||||
// console.log(err)
|
||||
// }
|
||||
|
||||
|
||||
// res.send('ok')
|
||||
// return
|
||||
}
|
||||
|
||||
appPort.push(+subDir[x].split('_')[3])
|
||||
|
||||
console.log('---------> appPort: '+appPort)
|
||||
|
||||
existSubDir = true
|
||||
|
||||
if (!isNaN(auxPort)) {
|
||||
appPort.push(auxPort)
|
||||
}
|
||||
}
|
||||
|
||||
existSubDir = true
|
||||
}
|
||||
}
|
||||
|
||||
appPort = existSubDir ? Math.max(...appPort) + 1 : process.env.PORT_START
|
||||
|
||||
console.log('new port: ', appPort)
|
||||
|
||||
let dirSessionAppName
|
||||
|
||||
let numberSession = 1
|
||||
|
||||
let lstPass = process.env.PASS
|
||||
|
||||
if (!lstPass) {
|
||||
console.log('PASS VARIABLE NOT FOUND INTO .ENV!')
|
||||
return res.send('OK')
|
||||
}
|
||||
|
||||
let db_credentials
|
||||
try {
|
||||
db_credentials = await OmnihitDBConn.findOne({ client_url })
|
||||
|
||||
if (!db_credentials) {
|
||||
db_credentials = new OmnihitDBConn({
|
||||
client_url: client_url,
|
||||
db_conf: {
|
||||
DB: '',
|
||||
DB_HOST: '',
|
||||
DB_USER: '',
|
||||
DB_PASS: '',
|
||||
DB_PORT: '',
|
||||
},
|
||||
})
|
||||
await db_credentials.save()
|
||||
return res.send('ok')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
if (db_credentials && db_credentials.db_conf.DB.trim().length > 0) {
|
||||
lstPass = lstPass.split(',')
|
||||
let password = null
|
||||
|
||||
// password = await lstPass.find(
|
||||
// async (pass) =>
|
||||
// await bcrypt.compare(pass.trim(), db_credentials.db_conf.DB_PASS)
|
||||
// )
|
||||
|
||||
for (let i = 0; i < lstPass.length; i++) {
|
||||
const hasPass = await bcrypt.compare(
|
||||
lstPass[i].trim(),
|
||||
db_credentials.db_conf.DB_PASS
|
||||
)
|
||||
|
||||
if (hasPass) {
|
||||
password = lstPass[i].trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
appPort = existSubDir ? Math.max(...appPort) + 1 : process.env.PORT_START
|
||||
|
||||
console.log('new port: ', appPort)
|
||||
|
||||
|
||||
|
||||
let dirSessionAppName
|
||||
|
||||
let numberSession = 1
|
||||
|
||||
// const dirSessionsNumberAppDirectories = fs.readdirSync(dirSessionsApp, { withFileTypes: true })
|
||||
// .filter((item) => item.isDirectory() && item.name.includes(`${number}`))
|
||||
// .map((item) => item.name);
|
||||
|
||||
// console.log('dirSessionsNumberAppDirectories', dirSessionsNumberAppDirectories, ' | dirSessionsApp: ', dirSessionsApp)
|
||||
|
||||
console.log('client_url: ', client_url)
|
||||
|
||||
let db = db_info.filter((e) => e.client_url == client_url)
|
||||
|
||||
if (db && db.length > 0) {
|
||||
|
||||
db = db[0].db_conf
|
||||
if (password) {
|
||||
db_credentials.db_conf.DB_PASS = password
|
||||
} else {
|
||||
return res.send('ok')
|
||||
}
|
||||
}
|
||||
|
||||
// if (dirSessionsNumberAppDirectories.length > 0) {
|
||||
|
||||
if (db && Object.keys(db).length > 0) {
|
||||
|
||||
const whatsapp_numbers = await new Promise((resolve, reject) => {
|
||||
mysql_conn(db).query('SELECT name FROM Whatsapps WHERE name LIKE ?', [`%${number}%`], (err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
}
|
||||
else {
|
||||
resolve(result)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
console.log('whatsapp_numbers: ', whatsapp_numbers)
|
||||
|
||||
let session_num = []
|
||||
|
||||
if (whatsapp_numbers && whatsapp_numbers.length > 0) {
|
||||
|
||||
console.log('whatsapp_numbers.length: ', whatsapp_numbers.length)
|
||||
|
||||
if (whatsapp_numbers.length == 5) {
|
||||
res.status(400).json({ message: 'Cannot create more than 4 sessions from the same number' })
|
||||
return
|
||||
}
|
||||
|
||||
let regex = /-> [a-zA-Z]\d$/
|
||||
|
||||
let numbered_sessions = whatsapp_numbers.filter((e) => regex.test(e.name))
|
||||
|
||||
console.log('numbered_sessions: ', numbered_sessions)
|
||||
|
||||
session_num = numbered_sessions.map((e) => parseInt((e.name.split('->')[e.name.split('->').length - 1]).trim().match(/\d+/)[0]))
|
||||
|
||||
console.log('session_num', session_num)
|
||||
|
||||
}
|
||||
|
||||
let index = 1;
|
||||
|
||||
while (index <= 4) {
|
||||
|
||||
if (!session_num.includes(index)) {
|
||||
console.log(index)
|
||||
numberSession = index
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
db_credentials.db_conf &&
|
||||
Object.keys(db_credentials.db_conf).length > 0
|
||||
) {
|
||||
const whatsapp_numbers = await new Promise((resolve, reject) => {
|
||||
mysql_conn(db_credentials.db_conf).query(
|
||||
'SELECT name FROM Whatsapps WHERE name LIKE ?',
|
||||
[`%${number}%`],
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
console.log('whatsapp_numbers: ', whatsapp_numbers)
|
||||
|
||||
// numberSession = Math.max(...session_number) + 1
|
||||
let session_num = []
|
||||
|
||||
console.log('Number session: ', numberSession)
|
||||
|
||||
// }
|
||||
|
||||
dirSessionAppName = `${whatsappId}_${number}_${numberSession}_${appPort}`
|
||||
|
||||
|
||||
|
||||
destDir = path.join(dirSessionsApp, dirSessionAppName)
|
||||
|
||||
originDir = path.join(__dirname, '..', 'whats')
|
||||
|
||||
copyFolder(originDir, destDir)
|
||||
|
||||
|
||||
if (db && Object.keys(db).length > 0) {
|
||||
|
||||
console.log('kkkkkkkkkkkkkkk')
|
||||
|
||||
let whatsName
|
||||
|
||||
const whatsapp = await new Promise((resolve, reject) => {
|
||||
|
||||
mysql_conn(db).query("SELECT name from Whatsapps where id = ?", [whatsappId], (err, result) => {
|
||||
|
||||
if (err) {
|
||||
reject(err)
|
||||
}
|
||||
else {
|
||||
resolve(result)
|
||||
}
|
||||
});
|
||||
if (whatsapp_numbers && whatsapp_numbers.length > 0) {
|
||||
console.log('whatsapp_numbers.length: ', whatsapp_numbers.length)
|
||||
|
||||
if (whatsapp_numbers.length == 5) {
|
||||
res.status(400).json({
|
||||
message: 'Cannot create more than 4 sessions from the same number',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (whatsapp[0]["name"].split('->').length > 0) {
|
||||
whatsName = `${whatsapp[0]["name"].split('->')[0]} -> S${numberSession}`
|
||||
}
|
||||
else {
|
||||
whatsName = `${whatsapp[0]["name"]} -> S${numberSession}`
|
||||
}
|
||||
let regex = /-> [a-zA-Z]\d$/
|
||||
|
||||
console.log('whatsName: ', whatsName)
|
||||
let numbered_sessions = whatsapp_numbers.filter((e) => regex.test(e.name))
|
||||
|
||||
console.log(`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`)
|
||||
console.log('numbered_sessions: ', numbered_sessions)
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
mysql_conn(db).query("UPDATE Whatsapps SET url = ?, name = ? where id = ?", [`${process.env.BASE_URL}:${appPort}`, `${whatsName}`, whatsappId],
|
||||
|
||||
function (err, result) {
|
||||
if (err) {
|
||||
reject(err)
|
||||
console.log("===> ERROR: " + err);
|
||||
}
|
||||
else {
|
||||
resolve(result)
|
||||
// console.log('RESULT: ', result)
|
||||
}
|
||||
// else
|
||||
// console.log('myslq result: ', result);
|
||||
});
|
||||
})
|
||||
|
||||
let whatsappName = `${number} - s${numberSession}`
|
||||
|
||||
console.log('-------------- numberSession', numberSession)
|
||||
|
||||
if (whatsapp.length > 0) {
|
||||
|
||||
if (whatsapp[0]['name'].split(' ').length > 0) {
|
||||
|
||||
whatsappName = `${whatsapp[0]['name'].split(' ')[0]} - S${numberSession}`
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.log('whatsapp: ', whatsapp)
|
||||
console.log("whatsapp[0]['name']: ", whatsapp[0]['name'])
|
||||
|
||||
const keys = Object.keys(db);
|
||||
|
||||
var stream = fs.createWriteStream(path.join(destDir, '.env'));
|
||||
stream.once('open', function (fd) {
|
||||
stream.write("# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n");
|
||||
stream.write(`MOBILEUID=${number}\n`);
|
||||
stream.write(`MOBILENAME=${whatsappName}\n`);
|
||||
stream.write("\n");
|
||||
|
||||
stream.write("# PORT NUMBER FOR THIS API\n");
|
||||
stream.write(`PORT=${appPort}\n`);
|
||||
stream.write("\n");
|
||||
|
||||
stream.write("# URL FROM THE OMNIHIT BACKEND API\n");
|
||||
stream.write(`CLIENT_URL=${client_url}\n`);
|
||||
stream.write("\n");
|
||||
|
||||
stream.write("# OMNIHIT DATABASE\n");
|
||||
keys.forEach((key, index) => {
|
||||
stream.write(`${key}=${db[key]}\n`);
|
||||
});
|
||||
stream.write("\n");
|
||||
|
||||
stream.write(`# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE\n`);
|
||||
stream.write(`WHATSAPP_ID=${whatsappId}`);
|
||||
|
||||
stream.end();
|
||||
});
|
||||
|
||||
|
||||
|
||||
console.log('----------------destDir: ', destDir)
|
||||
|
||||
|
||||
execSync(`npm install`, { cwd: destDir }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
});
|
||||
|
||||
startPm2Process(dirSessionAppName, 'app.js', destDir, appPort)
|
||||
session_num = numbered_sessions.map((e) =>
|
||||
parseInt(
|
||||
e.name
|
||||
.split('->')
|
||||
[e.name.split('->').length - 1].trim()
|
||||
.match(/\d+/)[0]
|
||||
)
|
||||
)
|
||||
|
||||
console.log('session_num', session_num)
|
||||
}
|
||||
|
||||
res.send("OK");
|
||||
let index = 1
|
||||
|
||||
});
|
||||
while (index <= 4) {
|
||||
if (!session_num.includes(index)) {
|
||||
console.log(index)
|
||||
numberSession = index
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
// numberSession = Math.max(...session_number) + 1
|
||||
|
||||
console.log('Number session: ', numberSession)
|
||||
|
||||
// }
|
||||
|
||||
dirSessionAppName = `${whatsappId}_${number}_${numberSession}_${appPort}`
|
||||
|
||||
destDir = path.join(dirSessionsApp, dirSessionAppName)
|
||||
|
||||
originDir = path.join(__dirname, '..', 'whats')
|
||||
|
||||
copyFolder(originDir, destDir)
|
||||
|
||||
if (
|
||||
db_credentials.db_conf &&
|
||||
Object.keys(db_credentials.db_conf).length > 0
|
||||
) {
|
||||
console.log('***SUCCESS SEED DIRECTORY CREATED***')
|
||||
|
||||
let whatsName
|
||||
|
||||
const whatsapp = await new Promise((resolve, reject) => {
|
||||
mysql_conn(db_credentials.db_conf).query(
|
||||
'SELECT name from Whatsapps where id = ?',
|
||||
[whatsappId],
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
if (whatsapp[0]['name'].split('->').length > 0) {
|
||||
whatsName = `${whatsapp[0]['name'].split('->')[0]} -> S${numberSession}`
|
||||
} else {
|
||||
whatsName = `${whatsapp[0]['name']} -> S${numberSession}`
|
||||
}
|
||||
|
||||
console.log('whatsName: ', whatsName)
|
||||
|
||||
console.log(
|
||||
`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`
|
||||
)
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
mysql_conn(db_credentials.db_conf).query(
|
||||
'UPDATE Whatsapps SET url = ?, name = ? where id = ?',
|
||||
[`${process.env.BASE_URL}:${appPort}`, `${whatsName}`, whatsappId],
|
||||
|
||||
function (err, result) {
|
||||
if (err) {
|
||||
reject(err)
|
||||
console.log('===> ERROR: ' + err)
|
||||
} else {
|
||||
resolve(result)
|
||||
// console.log('RESULT: ', result)
|
||||
}
|
||||
// else
|
||||
// console.log('myslq result: ', result);
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
let whatsappName = `${number} - s${numberSession}`
|
||||
|
||||
console.log('-------------- numberSession', numberSession)
|
||||
|
||||
if (whatsapp.length > 0) {
|
||||
if (whatsapp[0]['name'].split(' ').length > 0) {
|
||||
whatsappName = `${whatsapp[0]['name'].split(' ')[0]
|
||||
} - S${numberSession}`
|
||||
}
|
||||
}
|
||||
|
||||
console.log('whatsapp: ', whatsapp)
|
||||
console.log("whatsapp[0]['name']: ", whatsapp[0]['name'])
|
||||
|
||||
const keys = Object.keys(db_credentials.db_conf)
|
||||
|
||||
var stream = fs.createWriteStream(path.join(destDir, '.env'))
|
||||
stream.once('open', function (fd) {
|
||||
stream.write('# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n')
|
||||
stream.write(`MOBILEUID=${number}\n`)
|
||||
stream.write(`MOBILENAME=${whatsappName}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.write('# PORT NUMBER FOR THIS API\n')
|
||||
stream.write(`PORT=${appPort}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.write('# URL FROM THE OMNIHIT BACKEND API\n')
|
||||
stream.write(`CLIENT_URL=${client_url}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.write('# OMNIHIT DATABASE\n')
|
||||
keys.forEach((key, index) => {
|
||||
stream.write(`${key}=${db_credentials.db_conf[key]}\n`)
|
||||
})
|
||||
stream.write('\n')
|
||||
|
||||
stream.write(
|
||||
`# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE\n`
|
||||
)
|
||||
stream.write(`WHATSAPP_ID=${whatsappId}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.write('# MONGO CONNECTION\n')
|
||||
stream.write(`DB_MONGO_URL=${process.env.DB_MONGO_URL}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.write('# MONGO COLLECTION\n')
|
||||
stream.write(`DB_MONGO_NAME=${process.env.DB_MONGO_NAME_CAMPAIGN}\n`)
|
||||
stream.write('\n')
|
||||
|
||||
stream.end()
|
||||
})
|
||||
|
||||
console.log('----------------destDir: ', destDir)
|
||||
|
||||
execSync(`npm install`, { cwd: destDir }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`)
|
||||
return
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`)
|
||||
return
|
||||
}
|
||||
console.log(`stdout: ${stdout}`)
|
||||
})
|
||||
|
||||
const env = {
|
||||
PORT: appPort,
|
||||
DB_MONGO_URL: process.env.DB_MONGO_URL,
|
||||
DB_MONGO_NAME: process.env.DB_MONGO_NAME_CAMPAIGN
|
||||
}
|
||||
|
||||
startPm2Process(dirSessionAppName, 'app.js', destDir, env)
|
||||
}
|
||||
|
||||
res.send('OK')
|
||||
})
|
||||
|
||||
app.post('/api/session/edit', async function (req, res) {
|
||||
|
||||
const { app_name, whatsappId, client_url, number } = req.body
|
||||
|
||||
const { app_name, whatsappId, client_url, number } = req.body
|
||||
})
|
||||
|
||||
app.post('/api/session/del', async function (req, res) {
|
||||
let { whatsappId, app_name } = req.body
|
||||
|
||||
let { whatsappId, app_name } = req.body
|
||||
if (app_name) {
|
||||
app_name = app_name.trim()
|
||||
}
|
||||
|
||||
if(app_name){
|
||||
app_name = app_name.trim()
|
||||
const sessionsPath = path.join(__dirname, '..', 'sessions')
|
||||
|
||||
const directoriesInDIrectory = fs
|
||||
.readdirSync(sessionsPath, { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name)
|
||||
|
||||
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
|
||||
|
||||
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
|
||||
|
||||
console.log('dirExist: ', dirExist)
|
||||
|
||||
if (dirExist.length == 0) res.send('ok')
|
||||
|
||||
for (let i = 0; i < directoriesInDIrectory.length; i++) {
|
||||
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
|
||||
|
||||
const subDir = fs
|
||||
.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), {
|
||||
withFileTypes: true,
|
||||
})
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name)
|
||||
|
||||
for (let x = 0; x < subDir.length; x++) {
|
||||
console.log('subdir: ', subDir[x])
|
||||
|
||||
let whatsId = subDir[x].split('_')[0]
|
||||
|
||||
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
|
||||
let currPath = path.join(
|
||||
sessionsPath,
|
||||
directoriesInDIrectory[i],
|
||||
subDir[x]
|
||||
)
|
||||
|
||||
deletePm2Process(subDir[x], currPath)
|
||||
|
||||
console.log('currPath: ', currPath)
|
||||
|
||||
removeDir(currPath)
|
||||
|
||||
return res.send('ok')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sessionsPath = path.join(__dirname, '..', 'sessions')
|
||||
|
||||
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name);
|
||||
|
||||
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
|
||||
|
||||
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
|
||||
|
||||
console.log('dirExist: ', dirExist)
|
||||
|
||||
if (dirExist.length == 0)
|
||||
res.send('ok')
|
||||
|
||||
|
||||
for (let i = 0; i < directoriesInDIrectory.length; i++) {
|
||||
|
||||
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
|
||||
|
||||
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true })
|
||||
.filter((item) => item.isDirectory())
|
||||
.map((item) => item.name);
|
||||
|
||||
for (let x = 0; x < subDir.length; x++) {
|
||||
|
||||
console.log('subdir: ', subDir[x])
|
||||
|
||||
let whatsId = subDir[x].split('_')[0]
|
||||
|
||||
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
|
||||
|
||||
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
|
||||
|
||||
deletePm2Process(subDir[x], currPath);
|
||||
|
||||
console.log('currPath: ', currPath)
|
||||
|
||||
removeDir(currPath)
|
||||
|
||||
return res.send('ok')
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
res.send('ok')
|
||||
|
||||
res.send('ok')
|
||||
})
|
||||
|
||||
|
||||
|
||||
app.listen(process.env.PORT || 8003, function () {
|
||||
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003);
|
||||
});
|
||||
console.log(
|
||||
'\u26A1[server]: Server is running at Port ::: ' + process.env.PORT || 8003
|
||||
)
|
||||
})
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.error(' ');
|
||||
console.error('----- ' + (new Date).toUTCString() + ' ----------------------------------')
|
||||
console.error('Erro uncaughtException: ', err.message)
|
||||
console.error(err.stack)
|
||||
console.error(' ');
|
||||
return
|
||||
});
|
||||
console.error(' ')
|
||||
console.error(
|
||||
'----- ' + new Date().toUTCString() + ' ----------------------------------'
|
||||
)
|
||||
console.error('Erro uncaughtException: ', err.message)
|
||||
console.error(err.stack)
|
||||
console.error(' ')
|
||||
return
|
||||
})
|
||||
|
||||
function deletePm2Process(process_name, currPath) {
|
||||
pm2.connect(function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
pm2.connect(function (err) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
pm2.list(function (err, processes) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
pm2.list(function (err, processes) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
processes.forEach(function (process) {
|
||||
console.log('.........process.name: ', process.name)
|
||||
|
||||
if (process.name === process_name) {
|
||||
execSync(
|
||||
`pm2 delete ${process_name} && pm2 save --force`,
|
||||
{ cwd: currPath },
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`)
|
||||
return
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`)
|
||||
return
|
||||
}
|
||||
console.log(`stdout: ${stdout}`)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
processes.forEach(function (process) {
|
||||
|
||||
console.log(".........process.name: ", process.name);
|
||||
|
||||
if (process.name === process_name) {
|
||||
execSync(`pm2 delete ${process_name} && pm2 save --force`, { cwd: currPath }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
pm2.disconnect();
|
||||
});
|
||||
});
|
||||
pm2.disconnect()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
const mongoose = require('mongoose')
|
||||
require('dotenv').config({ path: `${process.cwd()}/.env` })
|
||||
|
||||
async function main(){
|
||||
await mongoose.connect(process.env.DB_MONGO_URL, { dbName: process.env.DB_MONGO_NAME })
|
||||
console.log('Conectou ao Mongoose!')
|
||||
}
|
||||
|
||||
main().catch((err)=>console.log(err))
|
||||
|
||||
module.exports = mongoose
|
|
@ -0,0 +1,20 @@
|
|||
const bcrypt = require('bcrypt')
|
||||
|
||||
// const pass = async () => {
|
||||
// // create a password
|
||||
// const salt = await bcrypt.genSalt(12)
|
||||
// const passwordHash = await bcrypt.hash('7901228899', salt)
|
||||
// console.log(passwordHash)
|
||||
// }
|
||||
// pass()
|
||||
|
||||
const passDec = async () => {
|
||||
const _pass = await bcrypt.compare(
|
||||
'strongpassword',
|
||||
'$2b$12$PZ8N1jU77nnNUCCGyKTMNOi2QI7X/SgPsISVQfr.cQ/jgdx5Z7AqC'
|
||||
)
|
||||
console.log('_pass: ', _pass)
|
||||
}
|
||||
passDec()
|
||||
|
||||
console.log('process.cwd(): ', process.cwd())
|
|
@ -1,44 +1,49 @@
|
|||
const pm2 = require('pm2');
|
||||
const { execSync } = require("child_process");
|
||||
const pm2 = require('pm2')
|
||||
const { execSync } = require("child_process")
|
||||
|
||||
function startPm2Process(process_name, file, path, port) {
|
||||
function startPm2Process(process_name, file, path, env) {
|
||||
|
||||
pm2.connect(function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
console.error(err)
|
||||
// process.exit(2);
|
||||
}
|
||||
|
||||
console.log('ENV PM2: ', env)
|
||||
|
||||
pm2.start({
|
||||
name: process_name,
|
||||
script: file,
|
||||
cwd: path,
|
||||
env: {
|
||||
PORT: port
|
||||
}
|
||||
env
|
||||
// env: {
|
||||
// NODE_ENV: 'production',
|
||||
|
||||
// PORT: port,
|
||||
// }
|
||||
// additional options here if needed
|
||||
}, function (err, apps) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
console.error(err)
|
||||
// process.exit(2);
|
||||
}
|
||||
else {
|
||||
execSync(`pm2 save --force`, { cwd: path }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`error: ${error.message}`);
|
||||
return;
|
||||
console.log(`error: ${error.message}`)
|
||||
return
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`stderr: ${stderr}`);
|
||||
return;
|
||||
console.log(`stderr: ${stderr}`)
|
||||
return
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
});
|
||||
console.log(`stdout: ${stdout}`)
|
||||
})
|
||||
}
|
||||
|
||||
pm2.disconnect();
|
||||
});
|
||||
});
|
||||
pm2.disconnect()
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
const mongoose = require('../db/connMongo')
|
||||
const { Schema } = mongoose
|
||||
|
||||
const OmnihitDBConn = mongoose.model(
|
||||
'Omnihit_db_conn',
|
||||
new Schema(
|
||||
{
|
||||
client_url: {
|
||||
type: String,
|
||||
},
|
||||
db_conf: {
|
||||
DB: {
|
||||
type: String,
|
||||
},
|
||||
DB_HOST: {
|
||||
type: String,
|
||||
},
|
||||
DB_USER: {
|
||||
type: String,
|
||||
},
|
||||
DB_PASS: {
|
||||
type: String,
|
||||
},
|
||||
DB_PORT: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
)
|
||||
)
|
||||
|
||||
module.exports = OmnihitDBConn
|
File diff suppressed because it is too large
Load Diff
|
@ -11,10 +11,12 @@
|
|||
"author": "Adriano <adriano08andrade@hotmail.com>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.1.0",
|
||||
"body-parser": "^1.20.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"fs-extra": "^11.1.0",
|
||||
"mongoose": "^7.4.0",
|
||||
"mysql": "^2.18.1",
|
||||
"nodemon": "^2.0.20",
|
||||
"socket.io": "^4.5.4"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE
|
||||
MOBILEUID=5517988310949
|
||||
MOBILENAME=Numero de teste
|
||||
MOBILENAME=test - S1
|
||||
|
||||
# PORT NUMBER FOR THIS API
|
||||
PORT=8020
|
||||
PORT=8029
|
||||
|
||||
# URL FROM THE OMNIHIT BACKEND API
|
||||
CLIENT_URL=http://localhost:8080
|
||||
|
@ -13,8 +13,13 @@ DB=whaticket
|
|||
DB_HOST=localhost
|
||||
DB_USER=whaticket
|
||||
DB_PASS=strongpassword
|
||||
DB_PORT=3306
|
||||
DB_PORT=3306
|
||||
|
||||
# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE
|
||||
WHATSAPP_ID=46
|
||||
|
||||
WHATSAPP_ID=223
|
||||
|
||||
# MONGO CONNECTION
|
||||
DB_MONGO_URL=mongodb://localhost:27017
|
||||
|
||||
# MONGO COLLECTION
|
||||
DB_MONGO_NAME=broker_omnihit
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
const { MongoClient } = require('mongodb')
|
||||
|
||||
const uri = process.env.DB_MONGO_URL
|
||||
|
||||
const mongo = new MongoClient(uri)
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
await mongo.connect()
|
||||
console.log('Connectado ao mongo db')
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
||||
|
||||
module.exports = mongo
|
|
@ -0,0 +1,41 @@
|
|||
const http = require('http')
|
||||
|
||||
const checkInternetConnection = async () => {
|
||||
const options = {
|
||||
hostname: 'www.google.com',
|
||||
port: 80,
|
||||
method: 'HEAD'
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(options, (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
resolve(true)
|
||||
} else {
|
||||
resolve(false)
|
||||
}
|
||||
req.abort()
|
||||
})
|
||||
|
||||
req.on('error', (err) => {
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
req.end()
|
||||
})
|
||||
};
|
||||
|
||||
// (async () => {
|
||||
// try {
|
||||
// const isConnected = await checkInternetConnection()
|
||||
// if (isConnected) {
|
||||
// console.log('Internet connection is available.')
|
||||
// } else {
|
||||
// console.log('Internet connection is not available.')
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Error checking internet connection:', error)
|
||||
// }
|
||||
// })()
|
||||
|
||||
module.exports = checkInternetConnection
|
File diff suppressed because it is too large
Load Diff
|
@ -15,17 +15,18 @@
|
|||
"dotenv": "^16.0.0",
|
||||
"express": "^4.17.1",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"logger": "^0.0.1",
|
||||
"mime": "^2.4.5",
|
||||
"mongodb": "^4.1.1",
|
||||
"mongoose": "^7.4.3",
|
||||
"multer": "^1.4.4",
|
||||
"mysql": "^2.18.1",
|
||||
"node-os-utils": "^1.3.5",
|
||||
"qr-encode": "^0.3.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"socket.io": "^4.5.4",
|
||||
"socket.io-client": "^4.5.4",
|
||||
"fs-extra": "^11.1.0"
|
||||
"socket.io-client": "^4.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.20"
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns": "^2.16.1",
|
||||
"date-fns-tz": "^1.3.4",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns-tz": "^1.3.8",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
|
|
|
@ -8,7 +8,7 @@ import ShowContactService from "../services/ContactServices/ShowContactService";
|
|||
import UpdateContactService from "../services/ContactServices/UpdateContactService";
|
||||
import DeleteContactService from "../services/ContactServices/DeleteContactService";
|
||||
|
||||
import CheckContactNumber from "../services/WbotServices/CheckNumber"
|
||||
import CheckContactNumber from "../services/WbotServices/CheckNumber";
|
||||
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
||||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
||||
import AppError from "../errors/AppError";
|
||||
|
@ -47,42 +47,46 @@ type IndexGetContactQuery = {
|
|||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
let { searchParam, pageNumber } = req.query as IndexQuery;
|
||||
|
||||
console.log('PAGE NUMBER CONTACT: ', pageNumber)
|
||||
console.log("PAGE NUMBER CONTACT: ", pageNumber);
|
||||
|
||||
if (pageNumber === undefined || pageNumber.trim().length == 0) {
|
||||
pageNumber = '1'
|
||||
pageNumber = "1";
|
||||
}
|
||||
|
||||
// TEST DEL
|
||||
// TEST DEL
|
||||
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
||||
|
||||
try {
|
||||
|
||||
const offset = 20 * (+pageNumber - 1);
|
||||
|
||||
searchParam = searchParam.replace(/\s+/g, ' ').trim().toLowerCase();
|
||||
searchParam = searchParam.replace(/\s+/g, " ").trim().toLowerCase();
|
||||
|
||||
const data = await searchContactCache(searchParam, offset, 20)
|
||||
const data = await searchContactCache(searchParam, offset, 20);
|
||||
|
||||
if (data) {
|
||||
console.log("QUERY CONTACTS FROM CACHE SEARCH PARAM: ", searchParam);
|
||||
|
||||
console.log('QUERY CONTACTS FROM CACHE SEARCH PARAM: ', searchParam)
|
||||
console.log("QUERY CONTACTS FROM CACHE QUERY LENGTH: ", data.length);
|
||||
|
||||
console.log('QUERY CONTACTS FROM CACHE QUERY LENGTH: ', data.length)
|
||||
|
||||
return res.json({ contacts: data, count: data.length, hasMore: data.length > 0 ? true : false });
|
||||
return res.json({
|
||||
contacts: data,
|
||||
count: data.length,
|
||||
hasMore: data.length > 0 ? true : false
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on search ContactController.ts search cache: ', error)
|
||||
console.log(
|
||||
"There was an error on search ContactController.ts search cache: ",
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log('QUERY CONTACTS FROM DATABASE SEARCH PARAM: ', searchParam)
|
||||
console.log("QUERY CONTACTS FROM DATABASE SEARCH PARAM: ", searchParam);
|
||||
|
||||
const { contacts, count, hasMore } = await ListContactsService({ searchParam, pageNumber });
|
||||
const { contacts, count, hasMore } = await ListContactsService({
|
||||
searchParam,
|
||||
pageNumber
|
||||
});
|
||||
|
||||
return res.json({ contacts, count, hasMore });
|
||||
};
|
||||
|
@ -118,16 +122,15 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
const validNumber = await CheckIsValidContact(newContact.number);
|
||||
|
||||
// const validNumber: any = await CheckContactNumber(newContact.number)
|
||||
// const validNumber: any = await CheckContactNumber(newContact.number)
|
||||
|
||||
if(!validNumber){
|
||||
if (!validNumber) {
|
||||
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
||||
}
|
||||
|
||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||
|
||||
console.log('xxxxxxxxxxx profilePicUrl: ',profilePicUrl)
|
||||
|
||||
console.log("xxxxxxxxxxx profilePicUrl: ", profilePicUrl);
|
||||
|
||||
// console.log(`newContact.name: ${newContact.name}\n
|
||||
// newContact.number: ${newContact.number}\n
|
||||
|
@ -146,7 +149,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
email,
|
||||
useDialogflow,
|
||||
profilePicUrl: profilePicUrl,
|
||||
extraInfo,
|
||||
extraInfo
|
||||
});
|
||||
|
||||
const io = getIO();
|
||||
|
@ -175,8 +178,8 @@ export const update = async (
|
|||
const schema = Yup.object().shape({
|
||||
name: Yup.string(),
|
||||
number: Yup.string()
|
||||
.matches(/^\d+$/,"Invalid number format. Only numbers is allowed.")
|
||||
.matches(/^55\d+$/, "The number must start with 55.")
|
||||
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
||||
.matches(/^55\d+$/, "The number must start with 55.")
|
||||
});
|
||||
|
||||
try {
|
||||
|
@ -257,7 +260,14 @@ export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Pro
|
|||
|
||||
// console.log('THE BODY: ', req.body)
|
||||
|
||||
const { adminId, identifier, queueStatus, file, contacts_inserted } = req.body
|
||||
const {
|
||||
adminId,
|
||||
identifier,
|
||||
queueStatus,
|
||||
file,
|
||||
contacts_inserted,
|
||||
campaign
|
||||
} = req.body;
|
||||
|
||||
const io = getIO();
|
||||
io.emit("contactsBulkInsertOnQueueStatus", {
|
||||
|
@ -266,17 +276,14 @@ export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Pro
|
|||
adminId: adminId,
|
||||
identifier: identifier,
|
||||
queueStatus: queueStatus,
|
||||
file: file
|
||||
file: file,
|
||||
campaign
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (process.env.CACHE && contacts_inserted) {
|
||||
|
||||
await insertContactsCache(contacts_inserted)
|
||||
|
||||
await insertContactsCache(contacts_inserted);
|
||||
}
|
||||
|
||||
return res.status(200).json({ message: 'ok' })
|
||||
return res.status(200).json({ message: "ok" });
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ import AppError from "../errors/AppError";
|
|||
|
||||
import UpdateSettingService from "../services/SettingServices/UpdateSettingService";
|
||||
import ListSettingsService from "../services/SettingServices/ListSettingsService";
|
||||
import loadSettings from "../helpers/LoadSettings";
|
||||
import updateSettingTicket from "../services/SettingServices/UpdateSettingTicket";
|
||||
import SettingTicket from "../models/SettingTicket";
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
// if (req.user.profile !== "master") {
|
||||
|
@ -13,7 +16,76 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
const settings = await ListSettingsService();
|
||||
|
||||
return res.status(200).json(settings);
|
||||
const config = await SettingTicket.findAll();
|
||||
|
||||
return res.status(200).json({ settings, config });
|
||||
};
|
||||
|
||||
export const updateTicketSettings = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
): Promise<Response> => {
|
||||
const {
|
||||
outBusinessHours,
|
||||
ticketExpiration,
|
||||
weekend,
|
||||
saturday,
|
||||
sunday,
|
||||
holiday
|
||||
} = req.body;
|
||||
|
||||
if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...outBusinessHours,
|
||||
key: "outBusinessHours"
|
||||
});
|
||||
}
|
||||
|
||||
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...ticketExpiration,
|
||||
key: "ticketExpiration"
|
||||
});
|
||||
}
|
||||
|
||||
if (weekend && Object.keys(weekend).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...weekend,
|
||||
key: "weekend"
|
||||
});
|
||||
}
|
||||
|
||||
if (saturday && Object.keys(saturday).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...saturday,
|
||||
key: "saturday"
|
||||
});
|
||||
}
|
||||
|
||||
if (sunday && Object.keys(sunday).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...sunday,
|
||||
key: "sunday"
|
||||
});
|
||||
}
|
||||
|
||||
if (holiday && Object.keys(holiday).length > 0) {
|
||||
await updateSettingTicket({
|
||||
...holiday,
|
||||
key: "holiday"
|
||||
});
|
||||
}
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({
|
||||
outBusinessHours,
|
||||
ticketExpiration,
|
||||
weekend,
|
||||
saturday,
|
||||
sunday,
|
||||
holiday
|
||||
});
|
||||
};
|
||||
|
||||
export const update = async (
|
||||
|
@ -31,6 +103,8 @@ export const update = async (
|
|||
value
|
||||
});
|
||||
|
||||
loadSettings();
|
||||
|
||||
const io = getIO();
|
||||
io.emit("settings", {
|
||||
action: "update",
|
||||
|
|
|
@ -8,24 +8,22 @@ import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
|||
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
|
||||
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
||||
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
|
||||
import ShowStatusChatEndService from '../services/StatusChatEndService/ShowStatusChatEndService'
|
||||
import ShowStatusChatEndService from "../services/StatusChatEndService/ShowStatusChatEndService";
|
||||
|
||||
import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService";
|
||||
import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService";
|
||||
|
||||
import { isScheduling } from "../helpers/CheckSchedulingReminderNotify"
|
||||
import { isScheduling } from "../helpers/CheckSchedulingReminderNotify";
|
||||
|
||||
import ptBR from 'date-fns/locale/pt-BR';
|
||||
import ptBR from "date-fns/locale/pt-BR";
|
||||
import { splitDateTime } from "../helpers/SplitDateTime";
|
||||
import format from 'date-fns/format';
|
||||
import format from "date-fns/format";
|
||||
|
||||
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
|
||||
|
||||
import { searchTicketCache, loadTicketsCache, } from '../helpers/TicketCache'
|
||||
import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
|
||||
import { Op } from "sequelize";
|
||||
|
||||
|
||||
|
||||
type IndexQuery = {
|
||||
searchParam: string;
|
||||
pageNumber: string;
|
||||
|
@ -35,7 +33,7 @@ type IndexQuery = {
|
|||
withUnreadMessages: string;
|
||||
queueIds: string;
|
||||
unlimited?: string;
|
||||
searchParamContent?: string
|
||||
searchParamContent?: string;
|
||||
};
|
||||
|
||||
interface TicketData {
|
||||
|
@ -43,13 +41,12 @@ interface TicketData {
|
|||
status: string;
|
||||
queueId: number;
|
||||
userId: number;
|
||||
whatsappId?: string | number
|
||||
msg?: string,
|
||||
transfer?: boolean | undefined,
|
||||
fromMe?: boolean
|
||||
whatsappId?: string | number;
|
||||
msg?: string;
|
||||
transfer?: boolean | undefined;
|
||||
fromMe?: boolean;
|
||||
}
|
||||
|
||||
|
||||
import ListStatusChatEndService from "../services/StatusChatEndService/ListStatusChatEndService";
|
||||
import Ticket from "../models/Ticket";
|
||||
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
|
||||
|
@ -60,16 +57,15 @@ import ShowUserService from "../services/UserServices/ShowUserService";
|
|||
import axios from "axios";
|
||||
import User from "../models/User";
|
||||
import CheckContactOpenTickets from "../helpers/CheckContactOpenTickets";
|
||||
import QueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
||||
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
||||
import { getWbot } from "../libs/wbot";
|
||||
import endPointQuery from "../helpers/old_EndPointQuery";
|
||||
import Contact from "../models/Contact";
|
||||
import BotIsOnQueue from "../helpers/BotIsOnQueue";
|
||||
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
|
||||
import { getSettingValue } from "../helpers/WhaticketSettings";
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
const {
|
||||
pageNumber,
|
||||
status,
|
||||
|
@ -82,7 +78,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
searchParamContent
|
||||
} = req.query as IndexQuery;
|
||||
|
||||
|
||||
const userId = req.user.id;
|
||||
|
||||
let queueIds: number[] = [];
|
||||
|
@ -110,22 +105,23 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { contactId, status, userId, msg, queueId }: TicketData = req.body;
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
// const botInfo = await BotIsOnQueue("botqueue");
|
||||
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ contactId, status: 'queueChoice' },
|
||||
{ contactId, status: 'open', userId: botInfo.userIdBot }
|
||||
{ contactId, status: "queueChoice" }
|
||||
// { contactId, status: "open", userId: botInfo.userIdBot }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (ticket) {
|
||||
await UpdateTicketService({ ticketData: { status: 'open', userId: userId, queueId }, ticketId: ticket.id });
|
||||
|
||||
}
|
||||
else {
|
||||
await UpdateTicketService({
|
||||
ticketData: { status: "open", userId: userId, queueId },
|
||||
ticketId: ticket.id
|
||||
});
|
||||
} else {
|
||||
ticket = await CreateTicketService({ contactId, status, userId, queueId });
|
||||
}
|
||||
|
||||
|
@ -134,8 +130,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
action: "update",
|
||||
ticket
|
||||
});
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
// const ticket = await CreateTicketService({ contactId, status, userId });
|
||||
|
||||
|
@ -148,58 +143,65 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
return res.status(200).json(ticket);
|
||||
};
|
||||
|
||||
|
||||
export const show = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { ticketId } = req.params;
|
||||
|
||||
const contact = await ShowTicketService(ticketId);
|
||||
|
||||
const { statusChatEnd, count, hasMore } = await ListStatusChatEndService({ searchParam: "", pageNumber: "1" });
|
||||
const { statusChatEnd, count, hasMore } = await ListStatusChatEndService({
|
||||
searchParam: "",
|
||||
pageNumber: "1"
|
||||
});
|
||||
|
||||
//////////////////
|
||||
const schedulesContact = await ListSchedulingNotifyContactService(contact.contact.number);
|
||||
const schedulesContact = await ListSchedulingNotifyContactService(
|
||||
contact.contact.number
|
||||
);
|
||||
/////////////////
|
||||
|
||||
|
||||
return res.status(200).json({ contact, statusChatEnd, schedulesContact });
|
||||
};
|
||||
|
||||
export const count = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
// type indexQ = { status: string; date?: string; };
|
||||
const { status, date } = req.query as IndexQuery
|
||||
const { status, date } = req.query as IndexQuery;
|
||||
|
||||
const ticketCount = await CountTicketService(status, date);
|
||||
|
||||
return res.status(200).json(ticketCount);
|
||||
};
|
||||
|
||||
|
||||
export const update = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
console.log('ENTROU NO UPDATE TICKET CONTROLLER')
|
||||
export const update = async (
|
||||
req: Request,
|
||||
res: Response
|
||||
): Promise<Response> => {
|
||||
console.log("ENTROU NO UPDATE TICKET CONTROLLER");
|
||||
|
||||
const { ticketId } = req.params;
|
||||
|
||||
const userOldInfo = await Ticket.findByPk(ticketId)
|
||||
const userOldInfo = await Ticket.findByPk(ticketId);
|
||||
|
||||
let ticket2 = {}
|
||||
|
||||
if (req.body['status'] === "closed") {
|
||||
let ticket2 = {};
|
||||
|
||||
if (req.body["status"] === "closed") {
|
||||
const { status, userId, schedulingNotifyData } = req.body;
|
||||
|
||||
// lembrete
|
||||
const scheduleData = JSON.parse(schedulingNotifyData)
|
||||
const scheduleData = JSON.parse(schedulingNotifyData);
|
||||
|
||||
const statusChatEndName = await ShowStatusChatEndService(scheduleData.statusChatEndId)
|
||||
const statusChatEndName = await ShowStatusChatEndService(
|
||||
scheduleData.statusChatEndId
|
||||
);
|
||||
|
||||
const { ticket } = await UpdateTicketService({
|
||||
ticketData: { 'status': status, 'userId': userId, 'statusChatEnd': statusChatEndName.name },
|
||||
ticketData: {
|
||||
status: status,
|
||||
userId: userId,
|
||||
statusChatEnd: statusChatEndName.name
|
||||
},
|
||||
ticketId
|
||||
});
|
||||
|
||||
|
||||
if (scheduleData.farewellMessage) {
|
||||
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
|
||||
|
||||
|
@ -210,115 +212,105 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// lembrete // agendamento
|
||||
if (scheduleData.statusChatEndId === '2' || scheduleData.statusChatEndId === '3') {
|
||||
|
||||
|
||||
if (isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)) {
|
||||
console.log('*** É AGENDAMENTO!')
|
||||
}
|
||||
else {
|
||||
console.log('*** É LEMBRETE!')
|
||||
if (
|
||||
scheduleData.statusChatEndId === "2" ||
|
||||
scheduleData.statusChatEndId === "3"
|
||||
) {
|
||||
if (
|
||||
isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)
|
||||
) {
|
||||
console.log("*** É AGENDAMENTO!");
|
||||
} else {
|
||||
console.log("*** É LEMBRETE!");
|
||||
}
|
||||
|
||||
const schedulingNotifyCreate = await CreateSchedulingNotifyService(
|
||||
{
|
||||
ticketId: scheduleData.ticketId,
|
||||
statusChatEndId: scheduleData.statusChatEndId,
|
||||
schedulingDate: scheduleData.schedulingDate,
|
||||
schedulingTime: scheduleData.schedulingTime,
|
||||
message: scheduleData.message
|
||||
}
|
||||
)
|
||||
const schedulingNotifyCreate = await CreateSchedulingNotifyService({
|
||||
ticketId: scheduleData.ticketId,
|
||||
statusChatEndId: scheduleData.statusChatEndId,
|
||||
schedulingDate: scheduleData.schedulingDate,
|
||||
schedulingTime: scheduleData.schedulingTime,
|
||||
message: scheduleData.message
|
||||
});
|
||||
}
|
||||
|
||||
ticket2 = ticket
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
ticket2 = ticket;
|
||||
} else {
|
||||
// Para aparecer pendente para todos usuarios que estao na fila
|
||||
if (req.body.transfer) {
|
||||
req.body.userId = null
|
||||
req.body.userId = null;
|
||||
}
|
||||
|
||||
let ticketData: TicketData = req.body;
|
||||
|
||||
// console.log('ticketData: ', ticketData)
|
||||
// console.log('ticketData.transfer', ticketData.transfer)
|
||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||
if (ticketData.transfer) {
|
||||
const defaultWhatsapp: any = await GetDefaultWhatsApp(
|
||||
ticketData.userId
|
||||
);
|
||||
|
||||
// return res.send()
|
||||
const _ticket: any = await Ticket.findByPk(ticketId);
|
||||
|
||||
if (defaultWhatsapp && ticketData.status != "open") {
|
||||
await CheckContactOpenTickets(
|
||||
_ticket.dataValues.contactId,
|
||||
defaultWhatsapp.dataValues.id
|
||||
);
|
||||
}
|
||||
|
||||
// if (ticketData.transfer) {
|
||||
|
||||
// const defaultWhatsapp: any = await GetDefaultWhatsApp(ticketData.userId);
|
||||
|
||||
// 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
|
||||
|
||||
// }
|
||||
|
||||
console.log('--------> ticketData.status: ', ticketData.status, ' | ticketData.fromMe: ', ticketData.fromMe)
|
||||
ticketData.whatsappId = defaultWhatsapp.dataValues.id;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
"--------> ticketData.status: ",
|
||||
ticketData.status,
|
||||
" | ticketData.fromMe: ",
|
||||
ticketData.fromMe
|
||||
);
|
||||
|
||||
const { ticket } = await UpdateTicketService({
|
||||
ticketData,
|
||||
ticketId,
|
||||
ticketId
|
||||
});
|
||||
|
||||
|
||||
if (ticketData.status == 'open' && !ticketData.fromMe) {
|
||||
|
||||
if (ticketData.status == "open" && !ticketData.fromMe) {
|
||||
await setMessageAsRead(ticket);
|
||||
|
||||
}
|
||||
|
||||
console.log('ticket.unreadMessages: ', ticket.unreadMessages)
|
||||
console.log("ticket.unreadMessages: ", ticket.unreadMessages);
|
||||
|
||||
if (ticketData.userId) {
|
||||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
TicketEmiterSumOpenClosedByUser(ticketData.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
const dateToday = splitDateTime(
|
||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
||||
);
|
||||
TicketEmiterSumOpenClosedByUser(
|
||||
ticketData.userId.toString(),
|
||||
dateToday.fullDate,
|
||||
dateToday.fullDate
|
||||
);
|
||||
}
|
||||
|
||||
ticket2 = ticket
|
||||
|
||||
ticket2 = ticket;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (userOldInfo) {
|
||||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
const dateToday = splitDateTime(
|
||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
||||
);
|
||||
|
||||
if (userOldInfo.userId) {
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(userOldInfo.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(
|
||||
userOldInfo.userId.toString(),
|
||||
dateToday.fullDate,
|
||||
dateToday.fullDate
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return res.status(200).json(ticket2);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// export const update = async (
|
||||
// req: Request,
|
||||
// res: Response
|
||||
|
@ -341,7 +333,6 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
// }
|
||||
// }
|
||||
|
||||
|
||||
// return res.status(200).json(ticket);
|
||||
// };
|
||||
|
||||
|
@ -354,13 +345,10 @@ export const remove = async (
|
|||
const ticket = await DeleteTicketService(ticketId);
|
||||
|
||||
const io = getIO();
|
||||
io.to(ticket.status)
|
||||
.to(ticketId)
|
||||
.to("notification")
|
||||
.emit("ticket", {
|
||||
action: "delete",
|
||||
ticketId: +ticketId
|
||||
});
|
||||
io.to(ticket.status).to(ticketId).to("notification").emit("ticket", {
|
||||
action: "delete",
|
||||
ticketId: +ticketId
|
||||
});
|
||||
|
||||
return res.status(200).json({ message: "ticket deleted" });
|
||||
};
|
||||
|
@ -371,4 +359,3 @@ export const remove = async (
|
|||
|
||||
// await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
||||
// }
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import UserOnlineTime from "../models/UserOnlineTime";
|
|||
|
||||
import Dialogflow from "../models/Dialogflow";
|
||||
import QueryItem from "../models/QueryItem";
|
||||
import SettingTicket from "../models/SettingTicket";
|
||||
// eslint-disable-next-line
|
||||
const dbConfig = require("../config/database");
|
||||
// import dbConfig from "../config/database";
|
||||
|
@ -40,7 +41,8 @@ const models = [
|
|||
StatusChatEnd,
|
||||
UserOnlineTime,
|
||||
Dialogflow,
|
||||
QueryItem
|
||||
QueryItem,
|
||||
SettingTicket
|
||||
];
|
||||
|
||||
sequelize.addModels(models);
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import { QueryInterface, DataTypes } from "sequelize"
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.createTable("SettingTickets", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
allowNull: false
|
||||
},
|
||||
message: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true
|
||||
},
|
||||
startTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true
|
||||
},
|
||||
endTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true
|
||||
},
|
||||
value: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
key: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.dropTable("SettingTickets");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { QueryInterface } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"Settings",
|
||||
[
|
||||
{
|
||||
key: "oneContactChatWithManyWhats",
|
||||
value: "enabled",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("Settings", {});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
import { QueryInterface } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"SettingTickets",
|
||||
[
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "outBusinessHours",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
},
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "ticketExpiration",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("SettingTickets", {});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
import { QueryInterface } from "sequelize"
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"SettingTickets",
|
||||
[
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "saturday",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
},
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "sunday",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("SettingTickets", {})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { QueryInterface } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"SettingTickets",
|
||||
[
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "holiday",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
},
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("SettingTickets", {});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
import { QueryInterface } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkInsert(
|
||||
"SettingTickets",
|
||||
[
|
||||
{
|
||||
message: "",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(),
|
||||
value: "disabled",
|
||||
key: "weekend",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}
|
||||
],
|
||||
{}
|
||||
);
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.bulkDelete("SettingTickets", {});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
import SettingTicket from "../models/SettingTicket";
|
||||
import ListTicketTimeLife from "../services/TicketServices/ListTicketTimeLife";
|
||||
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
|
||||
import BotIsOnQueue from "./BotIsOnQueue";
|
||||
|
||||
import {
|
||||
format as _format,
|
||||
isWithinInterval,
|
||||
parse,
|
||||
subMinutes
|
||||
} from "date-fns";
|
||||
|
||||
import ptBR from "date-fns/locale/pt-BR";
|
||||
import { splitDateTime } from "./SplitDateTime";
|
||||
|
||||
const fsPromises = require("fs/promises");
|
||||
const fs = require("fs");
|
||||
|
||||
let timer: any;
|
||||
|
||||
const AutoCloseTickets = async () => {
|
||||
try {
|
||||
// const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
// if (!botInfo.userIdBot) return
|
||||
|
||||
const ticketExpiration = await SettingTicket.findOne({
|
||||
where: { key: "ticketExpiration" }
|
||||
});
|
||||
|
||||
if (ticketExpiration && ticketExpiration.value == "enabled") {
|
||||
const startTime = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(ticketExpiration.startTime), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const seconds = timeStringToSeconds(startTime.fullTime);
|
||||
|
||||
// console.log("Ticket seconds: ", seconds);
|
||||
|
||||
let tickets: any = await ListTicketTimeLife({
|
||||
timeseconds: seconds,
|
||||
status: "open"
|
||||
});
|
||||
|
||||
// console.log("tickets: ", tickets);
|
||||
|
||||
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) {
|
||||
console.log("There was an error on try close the bot tickets: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
function timeStringToSeconds(timeString: any) {
|
||||
const [hours, minutes, seconds] = timeString.split(":").map(Number);
|
||||
return hours * 3600 + minutes * 60 + seconds;
|
||||
}
|
||||
|
||||
const schedule = async () => {
|
||||
try {
|
||||
clearInterval(timer);
|
||||
|
||||
await AutoCloseTickets();
|
||||
} catch (error) {
|
||||
console.log("error on schedule: ", error);
|
||||
} finally {
|
||||
timer = setInterval(schedule, 60000);
|
||||
}
|
||||
};
|
||||
|
||||
timer = setInterval(schedule, 60000);
|
||||
|
||||
export default schedule;
|
|
@ -1,11 +1,32 @@
|
|||
import { Op } from "sequelize";
|
||||
import AppError from "../errors/AppError";
|
||||
import Ticket from "../models/Ticket";
|
||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||
import { getSettingValue } from "./WhaticketSettings";
|
||||
|
||||
const CheckContactOpenTickets = async (contactId: number): Promise<void> => {
|
||||
const ticket = await Ticket.findOne({
|
||||
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
|
||||
});
|
||||
const CheckContactOpenTickets = async (
|
||||
contactId: number,
|
||||
whatsappId: number | string
|
||||
): Promise<void> => {
|
||||
let ticket;
|
||||
|
||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
[Op.and]: [
|
||||
{ contactId: contactId },
|
||||
{ whatsappId: { [Op.in]: whats.whatsapps.map((w: any) => w.id) } },
|
||||
{ status: { [Op.or]: ["open", "pending"] } }
|
||||
]
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ticket = await Ticket.findOne({
|
||||
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
|
||||
});
|
||||
}
|
||||
|
||||
if (ticket) {
|
||||
throw new AppError("ERR_OTHER_OPEN_TICKET");
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import Setting from "../models/Setting";
|
||||
import fs from "fs";
|
||||
import dir from "path";
|
||||
import os from "os";
|
||||
|
||||
async function loadSettings() {
|
||||
const setting = await Setting.findAll({});
|
||||
|
||||
if (setting) {
|
||||
let sett = setting.map((s: any) => {
|
||||
return { key: s.key, value: s.value };
|
||||
});
|
||||
|
||||
try {
|
||||
const keyFilename = dir.join(os.tmpdir(), `whaticket_settings.json`);
|
||||
|
||||
const jsonSettings = JSON.stringify(sett, null, 2);
|
||||
|
||||
fs.writeFileSync(keyFilename, jsonSettings);
|
||||
console.log(`Settings saved to ${keyFilename}`);
|
||||
} catch (err) {
|
||||
console.error("Error saving Settings to file:", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default loadSettings;
|
|
@ -55,4 +55,4 @@ const mostRepeatedPhrase = async (ticketId: number | string, fromMe: boolean = f
|
|||
return { body: '', occurrences: 0 }
|
||||
}
|
||||
|
||||
export default mostRepeatedPhrase;
|
||||
export default mostRepeatedPhrase;
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
import SettingTicket from "../models/SettingTicket";
|
||||
import { splitDateTime } from "./SplitDateTime";
|
||||
import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";
|
||||
|
||||
import {
|
||||
format as _format,
|
||||
isWithinInterval,
|
||||
parse,
|
||||
subMinutes,
|
||||
isSaturday,
|
||||
isSunday,
|
||||
parseISO
|
||||
} from "date-fns";
|
||||
import ptBR from "date-fns/locale/pt-BR";
|
||||
|
||||
const isHoliday = async () => {
|
||||
let obj = { set: false, msg: "" };
|
||||
|
||||
const holiday = await SettingTicket.findOne({
|
||||
where: { key: "holiday" }
|
||||
});
|
||||
|
||||
if (
|
||||
holiday &&
|
||||
holiday.value == "enabled" &&
|
||||
holiday.message?.trim()?.length > 0
|
||||
) {
|
||||
const startTime = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(holiday.startTime), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const currentDate = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
if (currentDate.fullDate == startTime.fullDate) {
|
||||
obj.set = true;
|
||||
obj.msg = holiday.message.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
const isWeekend = async () => {
|
||||
let obj = { set: false, msg: "" };
|
||||
|
||||
const weekend = await SettingTicket.findOne({
|
||||
where: { key: "weekend" }
|
||||
});
|
||||
|
||||
if (
|
||||
weekend &&
|
||||
weekend.value == "enabled" &&
|
||||
weekend.message?.trim()?.length > 0
|
||||
) {
|
||||
|
||||
// Specify your desired timezone
|
||||
const brazilTimeZone = "America/Sao_Paulo";
|
||||
|
||||
const currentDateUtc = new Date();
|
||||
|
||||
// Convert UTC date to Brazil time zone
|
||||
const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);
|
||||
|
||||
// Format the date using the desired format
|
||||
const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");
|
||||
|
||||
const parsedDate = parseISO(formattedDate);
|
||||
|
||||
// Convert parsed date to Brazil time zone
|
||||
const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
|
||||
|
||||
// Check if it's Saturday or Sunday
|
||||
if (isSaturday(localDate)) {
|
||||
const saturday = await SettingTicket.findOne({
|
||||
where: { key: "saturday" }
|
||||
});
|
||||
|
||||
if (saturday && saturday.value == "enabled") {
|
||||
// botSendMessage(ticket, weekend.message);
|
||||
obj.set = true;
|
||||
obj.msg = weekend.message;
|
||||
}
|
||||
} else if (isSunday(localDate)) {
|
||||
const sunday = await SettingTicket.findOne({
|
||||
where: { key: "sunday" }
|
||||
});
|
||||
|
||||
if (sunday && sunday.value == "enabled") {
|
||||
// botSendMessage(ticket, weekend.message);
|
||||
obj.set = true;
|
||||
obj.msg = weekend.message;
|
||||
}
|
||||
}
|
||||
else{
|
||||
// obj.set = true;
|
||||
// obj.msg = weekend.message;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
async function isOutBusinessTime() {
|
||||
let obj = { set: false, msg: "" };
|
||||
|
||||
const outBusinessHours = await SettingTicket.findOne({
|
||||
where: { key: "outBusinessHours" }
|
||||
});
|
||||
|
||||
let isWithinRange = false;
|
||||
|
||||
if (
|
||||
outBusinessHours &&
|
||||
outBusinessHours.value == "enabled" &&
|
||||
outBusinessHours?.message?.trim()?.length > 0
|
||||
) {
|
||||
const ticketDateTimeUpdate = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const startTime = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(outBusinessHours.startTime), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const endTime = splitDateTime(
|
||||
new Date(
|
||||
_format(new Date(outBusinessHours.endTime), "yyyy-MM-dd HH:mm:ss", {
|
||||
locale: ptBR
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const format = "HH:mm:ss";
|
||||
const parsedStartTime = parse(
|
||||
ticketDateTimeUpdate.fullTime,
|
||||
format,
|
||||
new Date()
|
||||
);
|
||||
const parsedEndTime = parse(startTime.fullTime, format, new Date());
|
||||
const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
|
||||
const timeInterval = { start: parsedStartTime, end: parsedEndTime };
|
||||
|
||||
// If the time range spans across different days, handle the date part
|
||||
if (parsedEndTime < parsedStartTime) {
|
||||
const nextDay = new Date(parsedStartTime);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
timeInterval.end = nextDay;
|
||||
}
|
||||
|
||||
isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);
|
||||
|
||||
if (!isWithinRange) {
|
||||
obj.set = true;
|
||||
obj.msg = outBusinessHours.message;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
export {
|
||||
isWeekend,
|
||||
isHoliday,
|
||||
isOutBusinessTime
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import fs from "fs";
|
||||
import dir from "path";
|
||||
import os from "os";
|
||||
|
||||
export function getSettingValue(key: any) {
|
||||
let value: any = {};
|
||||
|
||||
try {
|
||||
const keyFilename = dir.join(os.tmpdir(), `whaticket_settings.json`);
|
||||
const jsonData = fs.readFileSync(keyFilename, "utf8");
|
||||
const settings = JSON.parse(jsonData);
|
||||
value = settings.find((s: any) => s.key === key);
|
||||
} catch (err) {
|
||||
console.error("Error reading or parsing data from file:", err);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
|
@ -23,4 +23,4 @@ async function whatsappQueueMatchingUserQueue(userId: number, whatsapp: Whatsapp
|
|||
return matchingQueue
|
||||
}
|
||||
|
||||
export default whatsappQueueMatchingUserQueue
|
||||
export default whatsappQueueMatchingUserQueue
|
||||
|
|
|
@ -3,47 +3,53 @@ import { Server } from "http";
|
|||
import AppError from "../errors/AppError";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
|
||||
import { addHours, addMinutes, addSeconds, intervalToDuration, add } from "date-fns";
|
||||
import {
|
||||
addHours,
|
||||
addMinutes,
|
||||
addSeconds,
|
||||
intervalToDuration,
|
||||
add
|
||||
} from "date-fns";
|
||||
|
||||
let io: SocketIO;
|
||||
|
||||
//test del
|
||||
import createOrUpdateOnlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
|
||||
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";
|
||||
import ListUserOnlineOffline from "../services/UserServices/ListUsersOnlineOfflineService";
|
||||
import { handleMessage, handleMsgAck } from "../services/WbotServices/wbotMessageListener";
|
||||
import {
|
||||
handleMessage,
|
||||
handleMsgAck
|
||||
} from "../services/WbotServices/wbotMessageListener";
|
||||
import { join } from "path";
|
||||
import Whatsapp from "../models/Whatsapp";
|
||||
|
||||
let count: number = 0
|
||||
let listOnline: any[] = []
|
||||
let listOnlineAux: any[] = []
|
||||
let countOnline: number = 0
|
||||
let obj: any = { listOnline: [], uuid: null, listOnlineAux: [] }
|
||||
let count: number = 0;
|
||||
let listOnline: any[] = [];
|
||||
let listOnlineAux: any[] = [];
|
||||
let countOnline: number = 0;
|
||||
let obj: any = { listOnline: [], uuid: null, listOnlineAux: [] };
|
||||
|
||||
let lstOnline: any[] = [];
|
||||
let lstOnlineAux: any[] = [];
|
||||
let lstTry: any[] = [];
|
||||
|
||||
|
||||
|
||||
let lstOnline: any[] = []
|
||||
let lstOnlineAux: any[] = []
|
||||
let lstTry: any[] = []
|
||||
|
||||
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
let dateTime = splitDateTime(
|
||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
||||
);
|
||||
|
||||
export const initIO = (httpServer: Server): SocketIO => {
|
||||
io = new SocketIO(httpServer, {
|
||||
cors: {
|
||||
origin: process.env.FRONTEND_URL
|
||||
},
|
||||
},
|
||||
maxHttpBufferSize: 1e8
|
||||
});
|
||||
|
||||
|
||||
io.on("connection", socket => {
|
||||
logger.info("Client Connected");
|
||||
|
||||
|
@ -53,9 +59,8 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
});
|
||||
|
||||
socket.on("message_from_client", () => {
|
||||
|
||||
socket.emit('message_from_server', 'Sent an event from the server!');
|
||||
})
|
||||
socket.emit("message_from_server", "Sent an event from the server!");
|
||||
});
|
||||
|
||||
socket.on("message_create", async (data: any) => {
|
||||
|
||||
|
@ -65,154 +70,141 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
|
||||
});
|
||||
|
||||
|
||||
socket.on("media_uploaded", async (data: any) => {
|
||||
|
||||
socket.on("media_uploaded", async (data: any) => {
|
||||
handleMessage(data.msg, data);
|
||||
|
||||
});
|
||||
|
||||
socket.on("message_ack", async (data: any) => {
|
||||
|
||||
handleMsgAck(data.id, data.ack)
|
||||
|
||||
handleMsgAck(data.id, data.ack);
|
||||
});
|
||||
|
||||
socket.on("campaign_message_sent", async (data: any) => {
|
||||
// console.log("campaign_message_sent: ", data);
|
||||
|
||||
const io = getIO();
|
||||
|
||||
let campaign = {};
|
||||
|
||||
if (data?.read) {
|
||||
campaign = {
|
||||
id: data.id,
|
||||
read: data.read
|
||||
};
|
||||
} else if (data?.sent) {
|
||||
campaign = {
|
||||
id: data.id,
|
||||
sent: data.sent
|
||||
};
|
||||
} else if (data?.status) {
|
||||
campaign = {
|
||||
id: data.id,
|
||||
status: data.status
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
io.emit("campaign", {
|
||||
action: "update",
|
||||
campaign
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("online", (userId: any) => {
|
||||
|
||||
// console.log('userId: ', userId)
|
||||
|
||||
obj.uuid = uuidv4()
|
||||
obj.uuid = uuidv4();
|
||||
|
||||
if (userId.logoutUserId) {
|
||||
|
||||
let index = lstOnline.findIndex((x: any) => x.id == userId.logoutUserId)
|
||||
let index = lstOnline.findIndex(
|
||||
(x: any) => x.id == userId.logoutUserId
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
|
||||
lstOnline.splice(index, 1)
|
||||
|
||||
lstOnline.splice(index, 1);
|
||||
}
|
||||
|
||||
|
||||
index = lstOnlineAux.findIndex((x: any) => x.id == userId.logoutUserId)
|
||||
index = lstOnlineAux.findIndex((x: any) => x.id == userId.logoutUserId);
|
||||
|
||||
if (index != -1) {
|
||||
|
||||
lstOnlineAux.splice(index, 1)
|
||||
|
||||
lstOnlineAux.splice(index, 1);
|
||||
}
|
||||
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if (lstOnline.length == 0) {
|
||||
|
||||
const index = listOnlineAux.findIndex((e: any) => e.id == userId)
|
||||
const index = listOnlineAux.findIndex((e: any) => e.id == userId);
|
||||
|
||||
if (index == -1) {
|
||||
listOnlineAux.push({ 'id': userId })
|
||||
}
|
||||
else {
|
||||
return
|
||||
listOnlineAux.push({ id: userId });
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
lstOnline.push({ 'id': userId, 'status': 'online', 'try': 0 })
|
||||
lstOnline.push({ id: userId, status: "online", try: 0 });
|
||||
|
||||
lstOnlineAux.push({ 'id': userId })
|
||||
console.log(' 1 PUSHED NEW USER ID 1: ', userId)
|
||||
lstOnlineAux.push({ id: userId });
|
||||
console.log(" 1 PUSHED NEW USER ID 1: ", userId);
|
||||
|
||||
obj.listOnline = lstOnline
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
const indexAux = lstOnlineAux.findIndex((e: any) => e.id == userId)
|
||||
obj.listOnline = lstOnline;
|
||||
} else {
|
||||
const indexAux = lstOnlineAux.findIndex((e: any) => e.id == userId);
|
||||
|
||||
if (indexAux == -1) {
|
||||
lstOnlineAux.push({ 'id': userId })
|
||||
lstOnlineAux.push({ id: userId });
|
||||
}
|
||||
|
||||
const index = lstOnline.findIndex((e: any) => e.id == userId)
|
||||
const index = lstOnline.findIndex((e: any) => e.id == userId);
|
||||
|
||||
if (index == -1) {
|
||||
lstOnline.push({ id: userId, status: "online", try: 0 });
|
||||
|
||||
console.log(" 2 PUSHED NEW USER ID: ", userId);
|
||||
|
||||
lstOnline.push({ 'id': userId, 'status': 'online', 'try': 0 })
|
||||
|
||||
|
||||
console.log(' 2 PUSHED NEW USER ID: ', userId)
|
||||
|
||||
obj.listOnline = lstOnline
|
||||
}
|
||||
else {
|
||||
|
||||
if (countOnline > (lstOnline.length - 1)) {
|
||||
|
||||
obj.listOnline = lstOnline;
|
||||
} else {
|
||||
if (countOnline > lstOnline.length - 1) {
|
||||
lstOnline.forEach((x: any) => {
|
||||
if (lstOnlineAux.map((e: any) => e.id).includes(x.id)) {
|
||||
x.try = 0
|
||||
x.status = 'online'
|
||||
x.try = 0;
|
||||
x.status = "online";
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
var difference = lstOnline.filter((x: any) => !lstOnlineAux.map((e: any) => e.id).includes(x.id));
|
||||
});
|
||||
|
||||
var difference = lstOnline.filter(
|
||||
(x: any) => !lstOnlineAux.map((e: any) => e.id).includes(x.id)
|
||||
);
|
||||
|
||||
if (difference.length > 0) {
|
||||
|
||||
difference.forEach((e) => {
|
||||
|
||||
e.try += 1
|
||||
difference.forEach(e => {
|
||||
e.try += 1;
|
||||
|
||||
if (e.try > 1) {
|
||||
e.status = 'waiting...'
|
||||
e.status = "waiting...";
|
||||
}
|
||||
|
||||
if (e.try > 3) {
|
||||
|
||||
const index = lstOnline.findIndex((x: any) => x.id == e.id)
|
||||
const index = lstOnline.findIndex((x: any) => x.id == e.id);
|
||||
|
||||
if (index != -1) {
|
||||
|
||||
lstOnline.splice(index, 1)
|
||||
|
||||
lstOnline.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
obj.listOnline = lstOnline
|
||||
obj.listOnlineAux = lstOnlineAux
|
||||
obj.listOnline = lstOnline;
|
||||
obj.listOnlineAux = lstOnlineAux;
|
||||
|
||||
lstOnlineAux = [];
|
||||
listOnlineAux = [];
|
||||
|
||||
lstOnlineAux = []
|
||||
listOnlineAux = []
|
||||
|
||||
countOnline = -1
|
||||
countOnline = -1;
|
||||
}
|
||||
|
||||
|
||||
countOnline++
|
||||
countOnline++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.ob = obj
|
||||
|
||||
|
||||
exports.ob = obj;
|
||||
});
|
||||
|
||||
socket.on("joinChatBox", (ticketId: string) => {
|
||||
|
@ -235,49 +227,51 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
});
|
||||
|
||||
socket.on("disconnecting", async () => {
|
||||
console.log('socket.rooms: ', socket.rooms); // the Set contains at least the socket ID
|
||||
console.log("socket.rooms: ", socket.rooms); // the Set contains at least the socket ID
|
||||
|
||||
let rooms = socket.rooms
|
||||
let rooms = socket.rooms;
|
||||
|
||||
console.log('rooms: ', rooms, ' | rooms.size: ', rooms.size)
|
||||
console.log("rooms: ", rooms, " | rooms.size: ", rooms.size);
|
||||
|
||||
if(rooms && rooms.size==1) return
|
||||
if(rooms && rooms.size==2 && !([...rooms][1].startsWith('session_'))) return
|
||||
if (rooms && rooms.size == 1) return;
|
||||
if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_"))
|
||||
return;
|
||||
|
||||
let whatsappIds: any = await Whatsapp.findAll({ attributes: ['id'], raw: true })
|
||||
let whatsappIds: any = await Whatsapp.findAll({
|
||||
attributes: ["id"],
|
||||
raw: true
|
||||
});
|
||||
|
||||
if (whatsappIds && whatsappIds.length > 0) {
|
||||
whatsappIds = whatsappIds.map((e: any) => `${e.id}`);
|
||||
|
||||
whatsappIds = whatsappIds.map((e: any) => `${e.id}`)
|
||||
console.log(
|
||||
"whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ",
|
||||
whatsappIds
|
||||
);
|
||||
|
||||
console.log('whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ',whatsappIds)
|
||||
if (
|
||||
rooms &&
|
||||
rooms.size == 2 &&
|
||||
[...rooms][1].startsWith("session_") &&
|
||||
whatsappIds.includes([...rooms][1].replace("session_", ""))
|
||||
) {
|
||||
console.log([...rooms][1]);
|
||||
|
||||
if (rooms && rooms.size == 2 &&
|
||||
[...rooms][1].startsWith('session_') &&
|
||||
whatsappIds.includes([...rooms][1].replace('session_', ''))) {
|
||||
let whatsappId = [...rooms][1].replace("session_", "");
|
||||
|
||||
console.log([...rooms][1])
|
||||
|
||||
let whatsappId = [...rooms][1].replace('session_', '')
|
||||
|
||||
const whatsapp = await Whatsapp.findByPk(whatsappId, {})
|
||||
const whatsapp = await Whatsapp.findByPk(whatsappId, {});
|
||||
|
||||
if (whatsapp) {
|
||||
|
||||
await whatsapp.update({ status: 'OPENING' });
|
||||
await whatsapp.update({ status: "OPENING" });
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
return io;
|
||||
|
@ -290,12 +284,9 @@ export const getIO = (): SocketIO => {
|
|||
return io;
|
||||
};
|
||||
|
||||
|
||||
|
||||
function writeFileAsync(arg0: any, data: any, arg2: string) {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
|
||||
// exports.listOnlineUsers = listUserId
|
||||
// exports.listUserId
|
||||
|
||||
// exports.listUserId
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import {
|
||||
Table,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript";
|
||||
|
||||
@Table
|
||||
class SettingTicket extends Model<SettingTicket> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
id: number;
|
||||
|
||||
@Column
|
||||
message: string;
|
||||
|
||||
@Column
|
||||
startTime: Date;
|
||||
|
||||
@Column
|
||||
endTime: Date;
|
||||
|
||||
@Column
|
||||
value: string;
|
||||
|
||||
@Column
|
||||
key: string;
|
||||
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export default SettingTicket;
|
|
@ -3,13 +3,21 @@ import isAuth from "../middleware/isAuth";
|
|||
|
||||
import * as SettingController from "../controllers/SettingController";
|
||||
|
||||
const settingRoutes = Router();
|
||||
const settingRoutes = Router();
|
||||
|
||||
settingRoutes.get("/settings", SettingController.index);
|
||||
|
||||
// routes.get("/settings/:settingKey", isAuth, SettingsController.show);
|
||||
|
||||
settingRoutes.put(
|
||||
"/settings/ticket",
|
||||
isAuth,
|
||||
SettingController.updateTicketSettings
|
||||
);
|
||||
|
||||
|
||||
// change setting key to key in future
|
||||
settingRoutes.put("/settings/:settingKey", isAuth, SettingController.update);
|
||||
|
||||
|
||||
export default settingRoutes;
|
||||
|
|
|
@ -12,16 +12,22 @@ import { loadContactsCache } from "./helpers/ContactsCache";
|
|||
import "./helpers/CloseBotTickets";
|
||||
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
||||
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
||||
import "./helpers/AutoCloseTickets";
|
||||
|
||||
import "./helpers/SchedulingNotifySendMessage"
|
||||
import "./helpers/SchedulingNotifySendMessage";
|
||||
import axios from "axios";
|
||||
import os from 'os';
|
||||
import os from "os";
|
||||
import Setting from "./models/Setting";
|
||||
|
||||
import fs from "fs";
|
||||
import dir from "path";
|
||||
import { getSettingValue } from "./helpers/WhaticketSettings";
|
||||
import loadSettings from "./helpers/LoadSettings";
|
||||
|
||||
const server = app.listen(process.env.PORT, () => {
|
||||
logger.info(`Server started on port: ${process.env.PORT}`);
|
||||
});
|
||||
|
||||
|
||||
// if (global.gc) {
|
||||
// console.log(">> Starting Garbage Collector...");
|
||||
// global.gc();
|
||||
|
@ -34,99 +40,84 @@ initIO(server);
|
|||
// StartAllWhatsAppsSessions();
|
||||
gracefulShutdown(server);
|
||||
|
||||
(async () => {
|
||||
console.log("os.tmpdir(): ", os.tmpdir());
|
||||
|
||||
loadSettings();
|
||||
|
||||
(async()=>{
|
||||
|
||||
console.log('os.tmpdir(): ', os.tmpdir())
|
||||
|
||||
let whatsapps: any = await Whatsapp.findAll({ attributes: ['id', 'url'] })
|
||||
let whatsapps: any = await Whatsapp.findAll({ attributes: ["id", "url"] });
|
||||
|
||||
// console.log('whatsapps: ', whatsapps)
|
||||
|
||||
if (whatsapps && whatsapps.length > 0) {
|
||||
|
||||
for (let i = 0; i < whatsapps.length; i++) {
|
||||
|
||||
try {
|
||||
console.log(
|
||||
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`
|
||||
);
|
||||
|
||||
console.log(`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`)
|
||||
const response = await axios.get(
|
||||
`${whatsapps[i].dataValues.url}/api/connection/status`,
|
||||
{}
|
||||
);
|
||||
|
||||
const response = await axios.get(`${whatsapps[i].dataValues.url}/api/connection/status`, {});
|
||||
|
||||
console.log(`-------> Response: ${response.data.data}`)
|
||||
console.log(`-------> Response: ${response.data.data}`);
|
||||
|
||||
if (!response) {
|
||||
throw new Error('Response null');
|
||||
throw new Error("Response null");
|
||||
}
|
||||
|
||||
if (response.data.data && response.data.data == 'CONNECTED') {
|
||||
await whatsapps[i].update({ status: 'CONNECTED' });
|
||||
if (response.data.data && response.data.data == "CONNECTED") {
|
||||
await whatsapps[i].update({ status: "CONNECTED" });
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
await whatsapps[i].update({ status: "OPENING" });
|
||||
|
||||
await whatsapps[i].update({ status: 'OPENING' });
|
||||
|
||||
console.log(`There was an error on try acess the api sessions ${whatsapps[i].dataValues.url}`)
|
||||
console.log(
|
||||
`There was an error on try acess the api sessions ${whatsapps[i].dataValues.url}`
|
||||
);
|
||||
}
|
||||
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (process.env.CACHE) {
|
||||
const cacheLength = await cacheSize();
|
||||
|
||||
const cacheLength = await cacheSize()
|
||||
|
||||
console.log('cacheSize: ', cacheLength)
|
||||
console.log("cacheSize: ", cacheLength);
|
||||
|
||||
if (cacheLength == 0) {
|
||||
console.log('Loading from cache...')
|
||||
await flushCache()
|
||||
await loadContactsCache()
|
||||
await loadTicketsCache()
|
||||
console.log("Loading from cache...");
|
||||
await flushCache();
|
||||
await loadContactsCache();
|
||||
await loadTicketsCache();
|
||||
}
|
||||
|
||||
await loadSchedulesCache()
|
||||
await loadSchedulesCache();
|
||||
// await loadWhatsappCache()
|
||||
}
|
||||
|
||||
delRestoreControllFile()
|
||||
})()
|
||||
delRestoreControllFile();
|
||||
})();
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
const io = getIO();
|
||||
|
||||
console.log('Triggered socket!')
|
||||
console.log("Triggered socket!");
|
||||
|
||||
let users = await User.findAll({ raw: true, attributes: ["id"], })
|
||||
let users = await User.findAll({ raw: true, attributes: ["id"] });
|
||||
|
||||
if (users && users.length > 0) {
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
|
||||
io.emit("reload_page", {
|
||||
action: "update",
|
||||
userId: users[i].id
|
||||
});
|
||||
|
||||
console.log('USER ID: ', users[i].id)
|
||||
console.log("USER ID: ", users[i].id);
|
||||
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, 5000)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}, 5000);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import AppError from "../../errors/AppError";
|
||||
import SettingTicket from "../../models/SettingTicket";
|
||||
|
||||
interface Request {
|
||||
key: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
value: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
const updateSettingTicket = async ({
|
||||
key,
|
||||
startTime,
|
||||
endTime,
|
||||
value,
|
||||
message
|
||||
}: Request): Promise<SettingTicket | undefined> => {
|
||||
try {
|
||||
const businessHours = await SettingTicket.findOne({ where: { key } });
|
||||
|
||||
if (!businessHours) {
|
||||
throw new AppError("ERR_NO_SETTING_FOUND", 404);
|
||||
}
|
||||
|
||||
await businessHours.update({ startTime, endTime, message, value });
|
||||
|
||||
return businessHours;
|
||||
} catch (error: any) {
|
||||
console.error("===> Error on UpdateSettingService.ts file: \n", error);
|
||||
throw new AppError(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export default updateSettingTicket;
|
|
@ -35,8 +35,9 @@ const CreateTicketService = async ({
|
|||
try {
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||
|
||||
const user = await User.findByPk(userId, { raw: true });
|
||||
|
||||
if (!queueId) {
|
||||
const user = await User.findByPk(userId, { raw: true });
|
||||
const matchingQueue = await whatsappQueueMatchingUserQueue(
|
||||
userId,
|
||||
defaultWhatsapp,
|
||||
|
@ -45,7 +46,7 @@ const CreateTicketService = async ({
|
|||
queueId = matchingQueue ? matchingQueue.queueId : undefined;
|
||||
}
|
||||
|
||||
await CheckContactOpenTickets(contactId);
|
||||
await CheckContactOpenTickets(contactId, defaultWhatsapp.id);
|
||||
|
||||
const { isGroup } = await ShowContactService(contactId);
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ import Ticket from "../../models/Ticket";
|
|||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||
import ShowTicketService from "./ShowTicketService";
|
||||
import AppError from "../../errors/AppError";
|
||||
|
||||
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
||||
import { getSettingValue } from "../../helpers/WhaticketSettings";
|
||||
|
||||
const FindOrCreateTicketService = async (
|
||||
contact: Contact,
|
||||
|
@ -14,21 +15,34 @@ const FindOrCreateTicketService = async (
|
|||
unreadMessages: number,
|
||||
groupContact?: Contact
|
||||
): Promise<Ticket> => {
|
||||
|
||||
try {
|
||||
let ticket;
|
||||
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending", "queueChoice"]
|
||||
},
|
||||
contactId: groupContact ? groupContact.id : contact.id
|
||||
}
|
||||
});
|
||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending", "queueChoice"]
|
||||
},
|
||||
contactId: groupContact ? groupContact.id : contact.id,
|
||||
whatsappId: { [Op.in]: whats.whatsapps.map((w: any) => w.id) }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending", "queueChoice"]
|
||||
},
|
||||
contactId: groupContact ? groupContact.id : contact.id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
||||
|
||||
|
||||
//Habilitar esse caso queira usar o bot
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
// const botInfo = { isOnQueue: false }
|
||||
|
@ -46,10 +60,7 @@ const FindOrCreateTicketService = async (
|
|||
order: [["updatedAt", "DESC"]]
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (ticket) {
|
||||
|
||||
await ticket.update({
|
||||
status: "pending",
|
||||
userId: null,
|
||||
|
@ -59,7 +70,6 @@ const FindOrCreateTicketService = async (
|
|||
}
|
||||
|
||||
if (!ticket && !groupContact) {
|
||||
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
updatedAt: {
|
||||
|
@ -77,7 +87,6 @@ const FindOrCreateTicketService = async (
|
|||
});
|
||||
|
||||
if (ticket) {
|
||||
|
||||
await ticket.update({
|
||||
status: "pending",
|
||||
userId: null,
|
||||
|
@ -87,11 +96,10 @@ const FindOrCreateTicketService = async (
|
|||
}
|
||||
|
||||
if (!ticket) {
|
||||
|
||||
let status = "pending"
|
||||
let status = "pending";
|
||||
|
||||
if (queues.length > 1 && !botInfo.isOnQueue) {
|
||||
status = "queueChoice"
|
||||
status = "queueChoice";
|
||||
}
|
||||
|
||||
ticket = await Ticket.create({
|
||||
|
@ -113,9 +121,8 @@ const FindOrCreateTicketService = async (
|
|||
ticket = await ShowTicketService(ticket.id);
|
||||
|
||||
return ticket;
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('===> Error on FindOrCreateTicketService.ts file: \n', error)
|
||||
console.error("===> Error on FindOrCreateTicketService.ts file: \n", error);
|
||||
throw new AppError(error.message);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,25 +6,24 @@ import SendWhatsAppMessage from "../WbotServices/SendWhatsAppMessage";
|
|||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||
import ShowTicketService from "./ShowTicketService";
|
||||
|
||||
import { createOrUpdateTicketCache } from '../../helpers/TicketCache'
|
||||
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||
import AppError from "../../errors/AppError";
|
||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||
var flatten = require('flat')
|
||||
|
||||
|
||||
var flatten = require("flat");
|
||||
|
||||
interface TicketData {
|
||||
status?: string;
|
||||
userId?: number;
|
||||
queueId?: number;
|
||||
statusChatEnd?: string;
|
||||
statusChatEnd?: string;
|
||||
unreadMessages?: number;
|
||||
whatsappId?: string | number;
|
||||
}
|
||||
|
||||
interface Request {
|
||||
ticketData: TicketData;
|
||||
ticketId: string | number;
|
||||
msg?: string
|
||||
ticketId: string | number;
|
||||
msg?: string;
|
||||
}
|
||||
|
||||
interface Response {
|
||||
|
@ -35,13 +34,18 @@ interface Response {
|
|||
|
||||
const UpdateTicketService = async ({
|
||||
ticketData,
|
||||
ticketId,
|
||||
msg=''
|
||||
ticketId,
|
||||
msg = ""
|
||||
}: Request): Promise<Response> => {
|
||||
|
||||
try {
|
||||
|
||||
const { status, userId, queueId, statusChatEnd, unreadMessages } = ticketData;
|
||||
const {
|
||||
status,
|
||||
userId,
|
||||
queueId,
|
||||
statusChatEnd,
|
||||
unreadMessages,
|
||||
whatsappId
|
||||
} = ticketData;
|
||||
|
||||
const ticket = await ShowTicketService(ticketId);
|
||||
// await SetTicketMessagesAsRead(ticket);
|
||||
|
@ -50,7 +54,7 @@ const UpdateTicketService = async ({
|
|||
const oldUserId = ticket.user?.id;
|
||||
|
||||
if (oldStatus === "closed") {
|
||||
await CheckContactOpenTickets(ticket.contact.id);
|
||||
await CheckContactOpenTickets(ticket.contact.id, ticket.whatsappId);
|
||||
}
|
||||
|
||||
await ticket.update({
|
||||
|
@ -58,36 +62,36 @@ const UpdateTicketService = async ({
|
|||
queueId,
|
||||
userId,
|
||||
unreadMessages,
|
||||
statusChatEnd
|
||||
statusChatEnd,
|
||||
whatsappId
|
||||
});
|
||||
|
||||
await ticket.reload();
|
||||
|
||||
if (msg.length > 0) {
|
||||
if (msg?.trim().length > 0) {
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
sendWhatsAppMessageSocket(ticket, msg)
|
||||
|
||||
}, 2000)
|
||||
sendWhatsAppMessageSocket(ticket, msg);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// TEST DEL
|
||||
// TEST DEL
|
||||
try {
|
||||
// const { name, number } = await ShowContactService(ticket.contactId)
|
||||
|
||||
// const { name, number } = await ShowContactService(ticket.contactId)
|
||||
|
||||
let jsonString = JSON.stringify(ticket); //convert to string to remove the sequelize specific meta data
|
||||
let jsonString = JSON.stringify(ticket); //convert to string to remove the sequelize specific meta data
|
||||
let ticket_obj = JSON.parse(jsonString); //to make plain json
|
||||
delete ticket_obj['contact']['extraInfo']
|
||||
delete ticket_obj['user']
|
||||
delete ticket_obj["contact"]["extraInfo"];
|
||||
delete ticket_obj["user"];
|
||||
|
||||
ticket_obj = flatten(ticket_obj)
|
||||
|
||||
await createOrUpdateTicketCache(`ticket:${ticket.id}`, ticket_obj)
|
||||
ticket_obj = flatten(ticket_obj);
|
||||
|
||||
await createOrUpdateTicketCache(`ticket:${ticket.id}`, ticket_obj);
|
||||
} catch (error) {
|
||||
console.log('There was an error on UpdateTicketService.ts on createTicketCache: ', error)
|
||||
console.log(
|
||||
"There was an error on UpdateTicketService.ts on createTicketCache: ",
|
||||
error
|
||||
);
|
||||
}
|
||||
//
|
||||
|
||||
|
@ -100,7 +104,6 @@ const UpdateTicketService = async ({
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
io.to(ticket.status)
|
||||
.to("notification")
|
||||
.to(ticketId.toString())
|
||||
|
@ -109,20 +112,16 @@ const UpdateTicketService = async ({
|
|||
ticket
|
||||
});
|
||||
|
||||
|
||||
io.emit("ticketStatus", {
|
||||
action: "update",
|
||||
ticketStatus: { ticketId: ticket.id, status: ticket.status }
|
||||
});
|
||||
|
||||
|
||||
return { ticket, oldStatus, oldUserId };
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('===> Error on UpdateTicketService.ts file: \n', error)
|
||||
console.error("===> Error on UpdateTicketService.ts file: \n", error);
|
||||
throw new AppError(error.message);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default UpdateTicketService;
|
||||
export default UpdateTicketService;
|
||||
|
|
|
@ -1,40 +1,62 @@
|
|||
|
||||
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");
|
||||
|
||||
interface Request {
|
||||
profile: string;
|
||||
userId?: string | number;
|
||||
profile?: string;
|
||||
userId?: string | number;
|
||||
}
|
||||
|
||||
const QueuesByUser = async ({ profile, userId }: Request): Promise<any[]> => {
|
||||
let queueByUsersInfo: any = [];
|
||||
|
||||
let queueByUsersInfo = []
|
||||
|
||||
if (userId) {
|
||||
// CONSULTANDO FILAS PELO ID DO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
if (userId && profile) {
|
||||
// CONSULTANDO FILAS PELO ID DO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(
|
||||
`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.id = '${userId}' and Users.profile = '${profile}' order by userId, queueId;`, { type: QueryTypes.SELECT });
|
||||
|
||||
} else {
|
||||
|
||||
// CONSULTANDO FILAS PELO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.id = '${userId}' and Users.profile = '${profile}' order by userId, queueId;`,
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
} else if (profile) {
|
||||
// CONSULTANDO FILAS PELO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(
|
||||
`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.profile = '${profile}' order by userId, queueId;`, { type: QueryTypes.SELECT });
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.profile = '${profile}' order by userId, queueId;`,
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
} else if (userId) {
|
||||
queueByUsersInfo = await sequelize.query(
|
||||
`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.id = '${userId}' order by userId, queueId;`,
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
// if (userId) {
|
||||
// // CONSULTANDO FILAS PELO ID DO USUARIO
|
||||
// queueByUsersInfo = await sequelize.query(
|
||||
// `select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
// Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
// UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.id = '${userId}' and Users.profile = '${profile}' order by userId, queueId;`,
|
||||
// { type: QueryTypes.SELECT }
|
||||
// );
|
||||
// } else {
|
||||
// // CONSULTANDO FILAS PELO USUARIO
|
||||
// queueByUsersInfo = await sequelize.query(
|
||||
// `select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
// Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
// UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.profile = '${profile}' order by userId, queueId;`,
|
||||
// { type: QueryTypes.SELECT }
|
||||
// );
|
||||
// }
|
||||
|
||||
return queueByUsersInfo;
|
||||
return queueByUsersInfo;
|
||||
};
|
||||
|
||||
export default QueuesByUser;
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,21 @@ import { copyFolder } from "../../helpers/CopyFolder";
|
|||
import { removeDir } from "../../helpers/DeleteDirectory";
|
||||
import path from "path";
|
||||
|
||||
import { format } from "date-fns";
|
||||
import {
|
||||
isHoliday,
|
||||
isOutBusinessTime,
|
||||
isWeekend
|
||||
} from "../../helpers/TicketConfig";
|
||||
|
||||
import {
|
||||
format as _format,
|
||||
isWithinInterval,
|
||||
parse,
|
||||
subMinutes,
|
||||
isSaturday,
|
||||
isSunday,
|
||||
parseISO
|
||||
} from "date-fns";
|
||||
import ptBR from "date-fns/locale/pt-BR";
|
||||
|
||||
import {
|
||||
|
@ -37,6 +51,8 @@ import ShowQueueService from "../QueueService/ShowQueueService";
|
|||
import ShowTicketMessage from "../TicketServices/ShowTicketMessage";
|
||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
||||
import Queue from "../../models/Queue";
|
||||
import SettingTicket from "../../models/SettingTicket";
|
||||
|
||||
|
||||
import fs from "fs";
|
||||
|
||||
|
@ -914,6 +930,19 @@ const handleMessage = async (msg: any, wbot: any): Promise<void> => {
|
|||
// let groupContact: Contact | undefined;
|
||||
|
||||
if (msg.fromMe) {
|
||||
const ticketExpiration = await SettingTicket.findOne({
|
||||
where: { key: "ticketExpiration" }
|
||||
});
|
||||
|
||||
if (
|
||||
ticketExpiration &&
|
||||
ticketExpiration.value == "enabled" &&
|
||||
ticketExpiration?.message.trim() == msg.body.trim()
|
||||
) {
|
||||
console.log("*********** TICKET EXPIRATION");
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log('FROM ME: ', msg.fromMe, ' | /\u200e/.test(msg.body[0]: ', (/\u200e/.test(msg.body[0])))
|
||||
|
||||
// messages sent automatically by wbot have a special character in front of it
|
||||
|
@ -1206,6 +1235,54 @@ const handleMessage = async (msg: any, wbot: any): Promise<void> => {
|
|||
if (msg && !msg.fromMe && ticket.status == "pending") {
|
||||
await setMessageAsRead(ticket);
|
||||
}
|
||||
|
||||
let ticketHasQueue = false;
|
||||
|
||||
if (ticket?.queueId) {
|
||||
ticketHasQueue = true;
|
||||
}
|
||||
|
||||
if (ticketHasQueue) {
|
||||
// MESSAGE TO HOLIDAY
|
||||
const holiday: any = await isHoliday();
|
||||
|
||||
if (holiday && holiday.set) {
|
||||
if (msg.fromMe && holiday.msg == msg.body) {
|
||||
console.log("HOLIDAY MESSAGE IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
botSendMessage(ticket, holiday.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// MESSAGES TO SATURDAY OR SUNDAY
|
||||
const weekend: any = await isWeekend();
|
||||
|
||||
if (weekend && weekend.set) {
|
||||
if (msg.fromMe && weekend.msg == msg.body) {
|
||||
console.log("WEEKEND MESSAGE IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
botSendMessage(ticket, weekend.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// MESSAGE TO BUSINESS TIME
|
||||
const businessTime = await isOutBusinessTime();
|
||||
|
||||
if (businessTime && businessTime.set) {
|
||||
if (msg.fromMe && businessTime.msg == msg.body) {
|
||||
console.log("BUSINESS TIME MESSAGE IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
botSendMessage(ticket, businessTime.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log("xxxxxxxxxxxxx err: ", err);
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
|
||||
import Whatsapp from "../../models/Whatsapp";
|
||||
|
||||
const ListWhatsAppsNumber = async (whatsappId: string | number, status: string): Promise<Whatsapp[] | any> => {
|
||||
const ListWhatsAppsNumber = async (
|
||||
whatsappId: string | number,
|
||||
status?: string
|
||||
): Promise<Whatsapp[] | any> => {
|
||||
const whatsapp = await Whatsapp.findByPk(whatsappId, { raw: true });
|
||||
|
||||
// const whatsapp = await Whatsapp.findOne({
|
||||
// raw: true,
|
||||
// where: { id: whatsappId }
|
||||
// })
|
||||
|
||||
const whatsapp = await Whatsapp.findByPk(whatsappId, { raw: true })
|
||||
|
||||
if (whatsapp) {
|
||||
|
||||
const whatsapps = await Whatsapp.findAll({
|
||||
raw: true,
|
||||
where: { number: whatsapp.number, status: status },
|
||||
attributes: ['id', 'number', 'status', 'isDefault', 'url']
|
||||
});
|
||||
|
||||
return { whatsapps, whatsapp };
|
||||
let whatsapps: any = [];
|
||||
|
||||
if (whatsapp) {
|
||||
if (status) {
|
||||
whatsapps = await Whatsapp.findAll({
|
||||
raw: true,
|
||||
where: { number: whatsapp.number, status: status },
|
||||
attributes: ["id", "number", "status", "isDefault", "url"]
|
||||
});
|
||||
} else {
|
||||
whatsapps = await Whatsapp.findAll({
|
||||
raw: true,
|
||||
where: { number: whatsapp.number },
|
||||
attributes: ["id", "number", "status", "isDefault", "url"]
|
||||
});
|
||||
}
|
||||
|
||||
return { whatsapps: [], whatsapp: null }
|
||||
|
||||
return { whatsapps, whatsapp };
|
||||
}
|
||||
|
||||
return { whatsapps: [], whatsapp: null };
|
||||
};
|
||||
|
||||
export default ListWhatsAppsNumber;
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"@date-io/date-fns": "^1.3.13",
|
||||
"@emotion/react": "^11.7.1",
|
||||
"@emotion/styled": "^11.6.0",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@material-ui/core": "^4.12.1",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.56",
|
||||
"@material-ui/pickers": "^3.3.10",
|
||||
"@mui/material": "^5.3.0",
|
||||
"@mui/material": "^5.14.4",
|
||||
"@mui/x-data-grid": "^5.3.0",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.0.4",
|
||||
|
@ -20,6 +20,7 @@
|
|||
"dotenv": "^16.0.1",
|
||||
"emoji-mart": "^3.0.1",
|
||||
"formik": "^2.2.0",
|
||||
"formik-material-ui-pickers": "^1.0.0-alpha.1",
|
||||
"i18next": "^19.8.2",
|
||||
"i18next-browser-languagedetector": "^6.0.1",
|
||||
"js-file-download": "^0.4.12",
|
||||
|
@ -30,6 +31,7 @@
|
|||
"react": "^17.0.2",
|
||||
"react-color": "^2.19.3",
|
||||
"react-csv": "^2.2.2",
|
||||
"react-datepicker": "^4.16.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-modal-image": "^2.5.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
import React, { useState, useEffect, useContext, } from 'react'
|
||||
import * as Yup from 'yup'
|
||||
import { Formik, Form, Field, } from 'formik'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { green } from '@material-ui/core/colors'
|
||||
|
||||
import { AuthContext } from '../../context/Auth/AuthContext'
|
||||
|
||||
|
||||
import apiBroker from '../../services/apiBroker'
|
||||
|
||||
import Select from "@material-ui/core/Select"
|
||||
import MenuItem from "@material-ui/core/MenuItem"
|
||||
|
||||
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Button,
|
||||
DialogActions,
|
||||
CircularProgress,
|
||||
TextField,
|
||||
} from '@material-ui/core'
|
||||
|
||||
import { i18n } from '../../translate/i18n'
|
||||
import toastError from '../../errors/toastError'
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
|
||||
multFieldLine: {
|
||||
display: 'flex',
|
||||
'& > *:not(:last-child)': {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
|
||||
btnWrapper: {
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
buttonProgress: {
|
||||
color: green[500],
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
}))
|
||||
|
||||
const SessionSchema = Yup.object().shape({
|
||||
name: Yup.string()
|
||||
.min(2, 'Too Short!')
|
||||
.max(100, 'Too Long!')
|
||||
.required('Required'),
|
||||
|
||||
secondStart: Yup.number()
|
||||
.required('Min time is required')
|
||||
.min(3, 'Min time must be 3')
|
||||
.max(3600, 'Min must be less than 3600'),
|
||||
|
||||
secondEnd: Yup.number()
|
||||
.required('Max time is required')
|
||||
.min(3, 'Min time must be 3')
|
||||
.max(3600, 'Max must be less than 3600')
|
||||
.test('higher-than-lower', 'Tempo final deve ser maior que tempo inicio!', function (
|
||||
secondEnd
|
||||
) {
|
||||
const secondStart = this.resolve(Yup.ref('secondStart'))
|
||||
return secondStart === undefined || secondEnd === undefined || secondEnd > secondStart
|
||||
}),
|
||||
|
||||
})
|
||||
|
||||
const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
|
||||
const classes = useStyles()
|
||||
const initialState = {
|
||||
name: '',
|
||||
message: '',
|
||||
status: 'pending',
|
||||
whatsapp_sender: '',
|
||||
csv_original_file_name: '',
|
||||
secondStart: '3',
|
||||
secondEnd: '15',
|
||||
textToSeconds: true,
|
||||
}
|
||||
|
||||
const { user } = useContext(AuthContext)
|
||||
|
||||
const { whatsApps } = useContext(WhatsAppsContext)
|
||||
|
||||
const [campaign, setCampaign] = useState(initialState)
|
||||
// const [selectedQueueIds, setSelectedQueueIds] = useState([])
|
||||
const [file, setFile] = useState()
|
||||
|
||||
const [selectedNumber, setSelectedNumber] = useState('')
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSession = async () => {
|
||||
if (!campaignId) return
|
||||
|
||||
try {
|
||||
|
||||
const { data } = await apiBroker.get('/campaign', {
|
||||
params: {
|
||||
adminId: user.id,
|
||||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||
identifier: 'campaign',
|
||||
id: campaignId
|
||||
}
|
||||
})
|
||||
|
||||
setCampaign(data.campaign)
|
||||
setSelectedNumber(data.campaign.whatsapp_sender)
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
fetchSession()
|
||||
}, [campaignId, user.id])
|
||||
|
||||
const handleSaveCampaign = async (values) => {
|
||||
let response = null
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('adminId', user.id)
|
||||
formData.append('baseURL', process.env.REACT_APP_BACKEND_URL_PRIVATE)
|
||||
formData.append('frontURL', process.env.REACT_APP_FRONTEND_URL)
|
||||
formData.append('identifier', 'campaign')
|
||||
formData.append('file', file)
|
||||
formData.append('name', values.name)
|
||||
formData.append('whatsapp_sender', selectedNumber)
|
||||
formData.append('secondStart', values.secondStart)
|
||||
formData.append('secondEnd', values.secondEnd)
|
||||
formData.append('textToSeconds', values.textToSeconds)
|
||||
formData.append('message', values.message)
|
||||
formData.append('csv_original_file_name', file?.name)
|
||||
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
|
||||
try {
|
||||
if (campaignId) {
|
||||
|
||||
response = await apiBroker.patch(`/campaign/${campaignId}`,
|
||||
formData,
|
||||
config
|
||||
)
|
||||
toast.success('Campanha atualizada com sucesso!')
|
||||
|
||||
} else {
|
||||
|
||||
response = await apiBroker.post('/campaign',
|
||||
formData,
|
||||
config
|
||||
)
|
||||
toast.success('Campanha criada com sucesso!')
|
||||
}
|
||||
|
||||
dispatch({ type: "UPDATE_CAMPAIGNS", payload: response.data.campaign })
|
||||
|
||||
handleClose()
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
onClose()
|
||||
setCampaign(initialState)
|
||||
setSelectedNumber('')
|
||||
setFile(null)
|
||||
}
|
||||
|
||||
async function handleChange(event) {
|
||||
try {
|
||||
if (event.target.files[0].size > 1024 * 1024 * 4) {
|
||||
alert('Arquivo não pode ser maior que 4 MB!')
|
||||
return
|
||||
}
|
||||
|
||||
setFile(event.target.files[0])
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
scroll="paper"
|
||||
>
|
||||
<DialogTitle>
|
||||
{campaignId ? 'Editar campanha' : 'Adicionar campanha'}
|
||||
</DialogTitle>
|
||||
<Formik
|
||||
initialValues={campaign}
|
||||
enableReinitialize={true}
|
||||
validationSchema={SessionSchema}
|
||||
onSubmit={(values, actions) => {
|
||||
setTimeout(() => {
|
||||
handleSaveCampaign(values)
|
||||
actions.setSubmitting(false)
|
||||
}, 400)
|
||||
}}
|
||||
>
|
||||
{({ values, touched, errors, isSubmitting }) => (
|
||||
|
||||
<Form>
|
||||
<DialogContent dividers>
|
||||
<div>
|
||||
<div className={classes.multFieldLine}>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={i18n.t('whatsappModal.form.name')}
|
||||
autoFocus
|
||||
name="name"
|
||||
error={touched.name && Boolean(errors.name)}
|
||||
helperText={touched.name && errors.name}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
className={classes.textField}
|
||||
/>
|
||||
|
||||
<Select
|
||||
value={selectedNumber}
|
||||
onChange={(e) => setSelectedNumber(e.target.value)}
|
||||
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
|
||||
required
|
||||
>
|
||||
<MenuItem style={{ background: "white", }} value={''}> </MenuItem>
|
||||
{whatsApps.map((whatsapp) => (
|
||||
<MenuItem
|
||||
key={whatsapp.id}
|
||||
value={whatsapp.number}
|
||||
>{whatsapp.number}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className={classes.multFieldLine}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Field
|
||||
as={TextField}
|
||||
label="Mensagem"
|
||||
type="message"
|
||||
multiline
|
||||
rows={5}
|
||||
fullWidth
|
||||
name="message"
|
||||
error={touched.message && Boolean(errors.message)}
|
||||
helperText={touched.message && errors.message}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
accept=".csv"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleChange}
|
||||
id="contained-button-file"
|
||||
/>
|
||||
|
||||
<label htmlFor="contained-button-file">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
component="span"
|
||||
>
|
||||
CSV UPLOAD
|
||||
</Button>
|
||||
</label>
|
||||
|
||||
<h3>{file?.name || campaign?.csv_original_file_name}</h3>
|
||||
</div>
|
||||
|
||||
<div className={classes.multFieldLine} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Field
|
||||
as={TextField}
|
||||
label='Inicio em segundos'
|
||||
autoFocus
|
||||
name="secondStart"
|
||||
error={touched.secondStart && Boolean(errors.secondStart)}
|
||||
helperText={touched.secondStart && errors.secondStart}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
className={classes.textField}
|
||||
/>
|
||||
|
||||
<Field
|
||||
as={TextField}
|
||||
label='Fim em segundos'
|
||||
autoFocus
|
||||
name="secondEnd"
|
||||
error={touched.secondEnd && Boolean(errors.secondEnd)}
|
||||
helperText={touched.secondEnd && errors.secondEnd}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
className={classes.textField}
|
||||
/>
|
||||
|
||||
<label>
|
||||
<Field type="checkbox" name="textToSeconds"/>
|
||||
Tamanho do texto para segundos
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
color="secondary"
|
||||
disabled={isSubmitting}
|
||||
variant="outlined"
|
||||
>
|
||||
{i18n.t('whatsappModal.buttons.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
color="primary"
|
||||
disabled={isSubmitting}
|
||||
variant="contained"
|
||||
className={classes.btnWrapper}
|
||||
>
|
||||
{campaignId
|
||||
? i18n.t('whatsappModal.buttons.okEdit')
|
||||
: i18n.t('whatsappModal.buttons.okAdd')}
|
||||
{isSubmitting && (
|
||||
<CircularProgress
|
||||
size={24}
|
||||
className={classes.buttonProgress}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(CampaignModal)
|
|
@ -0,0 +1,449 @@
|
|||
import React, { useState, useEffect, } from 'react'
|
||||
// import * as Yup from 'yup'
|
||||
import { Formik, Form, Field, } from 'formik'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { green } from '@material-ui/core/colors'
|
||||
|
||||
import { TimePicker, DatePicker } from 'formik-material-ui-pickers'
|
||||
|
||||
import DateFnsUtils from '@date-io/date-fns'
|
||||
|
||||
import ptBrLocale from "date-fns/locale/pt-BR"
|
||||
|
||||
|
||||
|
||||
import {
|
||||
MuiPickersUtilsProvider,
|
||||
} from '@material-ui/pickers'
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Button,
|
||||
DialogActions,
|
||||
CircularProgress,
|
||||
TextField,
|
||||
Switch,
|
||||
FormControlLabel,
|
||||
} from '@material-ui/core'
|
||||
|
||||
import api from '../../services/api'
|
||||
import { i18n } from '../../translate/i18n'
|
||||
import toastError from '../../errors/toastError'
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
|
||||
multFieldLine: {
|
||||
display: 'flex',
|
||||
'& > *:not(:last-child)': {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
|
||||
btnWrapper: {
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
buttonProgress: {
|
||||
color: green[500],
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
}))
|
||||
|
||||
// const SessionSchema = Yup.object().shape({
|
||||
// name: Yup.string()
|
||||
// .min(2, 'Too Short!')
|
||||
// .max(100, 'Too Long!')
|
||||
// .required('Required'),
|
||||
// })
|
||||
|
||||
const ConfigModal = ({ open, onClose, change }) => {
|
||||
const classes = useStyles()
|
||||
const initialState = {
|
||||
startTimeBus: new Date(),
|
||||
endTimeBus: new Date(),
|
||||
messageBus: '',
|
||||
businessTimeEnable: false,
|
||||
ticketTimeExpiration: new Date(),
|
||||
ticketExpirationMsg: '',
|
||||
ticketExpirationEnable: false,
|
||||
holidayDate: new Date(),
|
||||
holidayDateEnable: false,
|
||||
holidayDateMessage: '',
|
||||
checkboxSundayValue: false,
|
||||
checkboxSaturdayValue: false,
|
||||
weekendMessage: '',
|
||||
enableWeekendMessage: false
|
||||
}
|
||||
|
||||
const [config, setConfig] = useState(initialState)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSession = async () => {
|
||||
|
||||
try {
|
||||
const { data } = await api.get('/settings')
|
||||
|
||||
const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
|
||||
const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
|
||||
const saturday = data.config.find((c) => c.key === "saturday")
|
||||
const sunday = data.config.find((c) => c.key === "sunday")
|
||||
const weekend = data.config.find((c) => c.key === "weekend")
|
||||
const holiday = data.config.find((c) => c.key === "holiday")
|
||||
|
||||
setConfig({
|
||||
startTimeBus: outBusinessHours.startTime,
|
||||
endTimeBus: outBusinessHours.endTime,
|
||||
messageBus: outBusinessHours.message,
|
||||
businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false,
|
||||
|
||||
ticketTimeExpiration: ticketExpiration.startTime,
|
||||
ticketExpirationMsg: ticketExpiration.message,
|
||||
ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false,
|
||||
|
||||
checkboxSaturdayValue: saturday.value === 'enabled' ? true : false,
|
||||
checkboxSundayValue: sunday.value === 'enabled' ? true : false,
|
||||
weekendMessage: weekend.message,
|
||||
enableWeekendMessage: weekend.value === 'enabled' ? true : false,
|
||||
|
||||
holidayDate: holiday.startTime,
|
||||
holidayDateMessage: holiday.message,
|
||||
holidayDateEnable: holiday.value === 'enabled' ? true : false,
|
||||
})
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
fetchSession()
|
||||
}, [change])
|
||||
|
||||
const handleSaveConfig = async (values) => {
|
||||
|
||||
values = {
|
||||
outBusinessHours: {
|
||||
startTime: values.startTimeBus,
|
||||
endTime: values.endTimeBus,
|
||||
message: values.messageBus,
|
||||
value: values.businessTimeEnable ? 'enabled' : 'disabled'
|
||||
},
|
||||
ticketExpiration: {
|
||||
startTime: values.ticketTimeExpiration,
|
||||
message: values.ticketExpirationMsg,
|
||||
value: values.ticketExpirationEnable ? 'enabled' : 'disabled'
|
||||
},
|
||||
weekend: {
|
||||
message: values.weekendMessage,
|
||||
value: values.enableWeekendMessage ? 'enabled' : 'disabled'
|
||||
},
|
||||
saturday:{
|
||||
value: values.checkboxSaturdayValue ? 'enabled' : 'disabled'
|
||||
},
|
||||
sunday: {
|
||||
value: values.checkboxSundayValue ? 'enabled' : 'disabled'
|
||||
},
|
||||
holiday: {
|
||||
startTime: values.holidayDate,
|
||||
message: values.holidayDateMessage,
|
||||
value: values.holidayDateEnable ? 'enabled' : 'disabled'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
|
||||
await api.put(`/settings/ticket`, values)
|
||||
|
||||
toast.success('Atualização realizada com sucesso!')
|
||||
handleClose()
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
onClose()
|
||||
// setConfig(initialState)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
scroll="paper"
|
||||
>
|
||||
<DialogTitle>
|
||||
Configurações
|
||||
</DialogTitle>
|
||||
|
||||
|
||||
<Formik
|
||||
initialValues={config}
|
||||
enableReinitialize={true}
|
||||
// validationSchema={SessionSchema}
|
||||
onSubmit={(values, actions) => {
|
||||
|
||||
setTimeout(() => {
|
||||
handleSaveConfig(values)
|
||||
actions.setSubmitting(false)
|
||||
}, 100)
|
||||
}}
|
||||
>
|
||||
{({ values, touched, errors, isSubmitting }) => (
|
||||
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
|
||||
<Form>
|
||||
|
||||
<DialogContent dividers>
|
||||
|
||||
<div className={classes.multFieldLine}>
|
||||
<Field
|
||||
component={TimePicker}
|
||||
name="startTimeBus"
|
||||
label="Inicio atendimento"
|
||||
ampm={false}
|
||||
openTo="hours"
|
||||
views={['hours', 'minutes',]}
|
||||
format="HH:mm"
|
||||
/>
|
||||
{' '}
|
||||
<Field
|
||||
component={TimePicker}
|
||||
name="endTimeBus"
|
||||
label="Fim atendimento"
|
||||
ampm={false}
|
||||
openTo="hours"
|
||||
views={['hours', 'minutes',]}
|
||||
format="HH:mm"
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Field
|
||||
as={Switch}
|
||||
color="primary"
|
||||
name="businessTimeEnable"
|
||||
checked={values.businessTimeEnable}
|
||||
/>
|
||||
}
|
||||
label={'Ativar/Desativar'} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={'Mensagem fora do horário de atendimento'}
|
||||
type="messageBus"
|
||||
multiline
|
||||
rows={5}
|
||||
fullWidth
|
||||
name="messageBus"
|
||||
error={
|
||||
touched.messageBus && Boolean(errors.messageBus)
|
||||
}
|
||||
helperText={
|
||||
touched.messageBus && errors.messageBus
|
||||
}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
{/* Saturday and Sunday date */}
|
||||
<div className={classes.multFieldLine} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<label style={{ marginRight: '10px' }}>
|
||||
<Field type="checkbox" name="checkboxSundayValue" />
|
||||
Sábado
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<Field type="checkbox" name="checkboxSaturdayValue" />
|
||||
Domingo
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Field
|
||||
as={Switch}
|
||||
color="primary"
|
||||
name="enableWeekendMessage"
|
||||
checked={values.enableWeekendMessage}
|
||||
/>
|
||||
}
|
||||
label={'Ativar/Desativar'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={'Mensagem para final de semana'}
|
||||
type="weekendMessage"
|
||||
multiline
|
||||
rows={5}
|
||||
fullWidth
|
||||
name="weekendMessage"
|
||||
error={
|
||||
touched.weekendMessage && Boolean(errors.weekendMessage)
|
||||
}
|
||||
helperText={
|
||||
touched.weekendMessage && errors.weekendMessage
|
||||
}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
{/* Holiday date */}
|
||||
<div className={classes.multFieldLine} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
|
||||
<Field
|
||||
component={DatePicker}
|
||||
name="holidayDate"
|
||||
label="Data do feriado"
|
||||
format="dd/MM/yyyy"
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Field
|
||||
as={Switch}
|
||||
color="primary"
|
||||
name="holidayDateEnable"
|
||||
checked={values.holidayDateEnable}
|
||||
/>
|
||||
}
|
||||
label={'Ativar/Desativar'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={'Mensagem para feriado'}
|
||||
type="holidayDateMessage"
|
||||
multiline
|
||||
rows={5}
|
||||
fullWidth
|
||||
name="holidayDateMessage"
|
||||
error={
|
||||
touched.holidayDateMessage && Boolean(errors.holidayDateMessage)
|
||||
}
|
||||
helperText={
|
||||
touched.holidayDateMessage && errors.holidayDateMessage
|
||||
}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br />
|
||||
<div className={classes.multFieldLine} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Field
|
||||
component={TimePicker}
|
||||
name="ticketTimeExpiration"
|
||||
label="Ticket expira em hh:mm"
|
||||
ampm={false}
|
||||
openTo="hours"
|
||||
views={['hours', 'minutes',]}
|
||||
format="HH:mm"
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Field
|
||||
as={Switch}
|
||||
color="primary"
|
||||
name="ticketExpirationEnable"
|
||||
checked={values.ticketExpirationEnable}
|
||||
/>
|
||||
}
|
||||
label={'Ativar/Desativar'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={'Mensagem por falta de atividade no atendimento'}
|
||||
type="ticketExpirationMsg"
|
||||
multiline
|
||||
rows={5}
|
||||
fullWidth
|
||||
name="ticketExpirationMsg"
|
||||
error={
|
||||
touched.ticketExpirationMsg && Boolean(errors.ticketExpirationMsg)
|
||||
}
|
||||
helperText={
|
||||
touched.ticketExpirationMsg && errors.ticketExpirationMsg
|
||||
}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
color="secondary"
|
||||
disabled={isSubmitting}
|
||||
variant="outlined"
|
||||
>
|
||||
{i18n.t('whatsappModal.buttons.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
color="primary"
|
||||
disabled={isSubmitting}
|
||||
variant="contained"
|
||||
className={classes.btnWrapper}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<CircularProgress
|
||||
size={24}
|
||||
className={classes.buttonProgress}
|
||||
/>
|
||||
) : 'Salvar'}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Form>
|
||||
</MuiPickersUtilsProvider>
|
||||
)}
|
||||
</Formik>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default React.memo(ConfigModal)
|
|
@ -1,8 +1,8 @@
|
|||
import { toast } from "react-toastify";
|
||||
import { i18n } from "../translate/i18n";
|
||||
|
||||
const toastError = err => {
|
||||
const errorMsg = err.response?.data?.message || err.response.data.error;
|
||||
const toastError = err => {
|
||||
const errorMsg = err.response?.data?.message || err?.response?.data?.error || `${err?.message}`;
|
||||
if (errorMsg) {
|
||||
if (i18n.exists(`backendErrors.${errorMsg}`)) {
|
||||
toast.error(i18n.t(`backendErrors.${errorMsg}`), {
|
||||
|
|
|
@ -76,7 +76,7 @@ const useAuth = () => {
|
|||
const fetchSession = async () => {
|
||||
try {
|
||||
const { data } = await api.get('/settings')
|
||||
setSetting(data)
|
||||
setSetting(data.settings)
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
|
|
|
@ -1,41 +1,46 @@
|
|||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { Link as RouterLink } from 'react-router-dom'
|
||||
|
||||
import DeviceHubOutlined from "@material-ui/icons/DeviceHubOutlined"
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import ListSubheader from "@material-ui/core/ListSubheader";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import { Badge } from "@material-ui/core";
|
||||
import DashboardOutlinedIcon from "@material-ui/icons/DashboardOutlined";
|
||||
import DeviceHubOutlined from "@material-ui/icons/DeviceHubOutlined"
|
||||
import ListItemText from "@material-ui/core/ListItemText"
|
||||
import ListSubheader from "@material-ui/core/ListSubheader"
|
||||
import Divider from "@material-ui/core/Divider"
|
||||
import { Badge } from "@material-ui/core"
|
||||
import DashboardOutlinedIcon from "@material-ui/icons/DashboardOutlined"
|
||||
import ListItem from '@material-ui/core/ListItem'
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||
|
||||
import ReportOutlinedIcon from "@material-ui/icons/ReportOutlined";
|
||||
import SendOutlined from "@material-ui/icons/SendOutlined";
|
||||
import ReportOutlinedIcon from '@material-ui/icons/ReportOutlined'
|
||||
import CampaignIcon from '@material-ui/icons/Send'
|
||||
|
||||
|
||||
import SendOutlined from '@material-ui/icons/SendOutlined'
|
||||
|
||||
//import ReportOutlined from "@bit/mui-org.material-ui-icons.report-outlined";
|
||||
|
||||
import WhatsAppIcon from '@material-ui/icons/WhatsApp'
|
||||
import SyncAltIcon from '@material-ui/icons/SyncAlt'
|
||||
import SettingsOutlinedIcon from '@material-ui/icons/SettingsOutlined'
|
||||
import PeopleAltOutlinedIcon from '@material-ui/icons/PeopleAltOutlined'
|
||||
import ContactPhoneOutlinedIcon from '@material-ui/icons/ContactPhoneOutlined'
|
||||
import AccountTreeOutlinedIcon from '@material-ui/icons/AccountTreeOutlined'
|
||||
import QuestionAnswerOutlinedIcon from '@material-ui/icons/QuestionAnswerOutlined'
|
||||
|
||||
import WhatsAppIcon from "@material-ui/icons/WhatsApp";
|
||||
import SyncAltIcon from "@material-ui/icons/SyncAlt";
|
||||
import SettingsOutlinedIcon from "@material-ui/icons/SettingsOutlined";
|
||||
import PeopleAltOutlinedIcon from "@material-ui/icons/PeopleAltOutlined";
|
||||
import ContactPhoneOutlinedIcon from "@material-ui/icons/ContactPhoneOutlined";
|
||||
import AccountTreeOutlinedIcon from "@material-ui/icons/AccountTreeOutlined";
|
||||
import QuestionAnswerOutlinedIcon from "@material-ui/icons/QuestionAnswerOutlined";
|
||||
|
||||
import { i18n } from "../translate/i18n";
|
||||
import { WhatsAppsContext } from "../context/WhatsApp/WhatsAppsContext";
|
||||
import { AuthContext } from "../context/Auth/AuthContext";
|
||||
import { Can } from "../components/Can";
|
||||
import { i18n } from '../translate/i18n'
|
||||
import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext'
|
||||
import { AuthContext } from '../context/Auth/AuthContext'
|
||||
import { Can } from '../components/Can'
|
||||
|
||||
function ListItemLink(props) {
|
||||
const { icon, primary, to, className } = props;
|
||||
const { icon, primary, to, className } = props
|
||||
|
||||
const renderLink = React.useMemo(
|
||||
() => React.forwardRef((itemProps, ref) => <RouterLink to={to} ref={ref} {...itemProps} />),
|
||||
() =>
|
||||
React.forwardRef((itemProps, ref) => (
|
||||
<RouterLink to={to} ref={ref} {...itemProps} />
|
||||
)),
|
||||
[to]
|
||||
);
|
||||
)
|
||||
|
||||
return (
|
||||
<li>
|
||||
|
@ -44,60 +49,59 @@ function ListItemLink(props) {
|
|||
<ListItemText primary={primary} />
|
||||
</ListItem>
|
||||
</li>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
const MainListItems = (props) => {
|
||||
const { setDrawerOpen } = props;
|
||||
const { whatsApps } = useContext(WhatsAppsContext);
|
||||
const { user } = useContext(AuthContext);
|
||||
const [connectionWarning, setConnectionWarning] = useState(false);
|
||||
const { setDrawerOpen } = props
|
||||
const { whatsApps } = useContext(WhatsAppsContext)
|
||||
const { user } = useContext(AuthContext)
|
||||
const [connectionWarning, setConnectionWarning] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
if (whatsApps.length > 0) {
|
||||
const offlineWhats = whatsApps.filter((whats) => {
|
||||
return (
|
||||
whats.status === "qrcode" ||
|
||||
whats.status === "PAIRING" ||
|
||||
whats.status === "DISCONNECTED" ||
|
||||
whats.status === "TIMEOUT" ||
|
||||
whats.status === "OPENING"
|
||||
);
|
||||
});
|
||||
whats.status === 'qrcode' ||
|
||||
whats.status === 'PAIRING' ||
|
||||
whats.status === 'DISCONNECTED' ||
|
||||
whats.status === 'TIMEOUT' ||
|
||||
whats.status === 'OPENING'
|
||||
)
|
||||
})
|
||||
if (offlineWhats.length > 0) {
|
||||
setConnectionWarning(true);
|
||||
setConnectionWarning(true)
|
||||
} else {
|
||||
setConnectionWarning(false);
|
||||
setConnectionWarning(false)
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [whatsApps]);
|
||||
}, 2000)
|
||||
return () => clearTimeout(delayDebounceFn)
|
||||
}, [whatsApps])
|
||||
|
||||
return (
|
||||
//Solicitado pelo Adriano: Click no LinkItem e fechar o menu!
|
||||
<div onClick={() => setDrawerOpen(false)}>
|
||||
<ListItemLink
|
||||
to="/tickets"
|
||||
primary={i18n.t("mainDrawer.listItems.tickets")}
|
||||
primary={i18n.t('mainDrawer.listItems.tickets')}
|
||||
icon={<WhatsAppIcon />}
|
||||
/>
|
||||
|
||||
<ListItemLink
|
||||
to="/contacts"
|
||||
primary={i18n.t("mainDrawer.listItems.contacts")}
|
||||
primary={i18n.t('mainDrawer.listItems.contacts')}
|
||||
icon={<ContactPhoneOutlinedIcon />}
|
||||
/>
|
||||
|
||||
<ListItemLink to="/schedulesReminder"
|
||||
primary={i18n.t("mainDrawer.listItems.reminders")}
|
||||
<ListItemLink
|
||||
to="/schedulesReminder"
|
||||
primary={i18n.t('mainDrawer.listItems.schedules')}
|
||||
icon={<SendOutlined />}
|
||||
/>
|
||||
|
||||
<ListItemLink
|
||||
to="/quickAnswers"
|
||||
primary={i18n.t("mainDrawer.listItems.quickAnswers")}
|
||||
primary={i18n.t('mainDrawer.listItems.quickAnswers')}
|
||||
icon={<QuestionAnswerOutlinedIcon />}
|
||||
/>
|
||||
<Can
|
||||
|
@ -106,31 +110,47 @@ const MainListItems = (props) => {
|
|||
yes={() => (
|
||||
<>
|
||||
<Divider />
|
||||
<ListSubheader inset>{i18n.t("mainDrawer.listItems.administration")}</ListSubheader>
|
||||
<ListSubheader inset>
|
||||
{i18n.t('mainDrawer.listItems.administration')}
|
||||
</ListSubheader>
|
||||
<ListItemLink
|
||||
to="/users"
|
||||
primary={i18n.t("mainDrawer.listItems.users")}
|
||||
primary={i18n.t('mainDrawer.listItems.users')}
|
||||
icon={<PeopleAltOutlinedIcon />}
|
||||
/>
|
||||
<ListItemLink
|
||||
to="/queues"
|
||||
primary={i18n.t("mainDrawer.listItems.queues")}
|
||||
primary={i18n.t('mainDrawer.listItems.queues')}
|
||||
icon={<AccountTreeOutlinedIcon />}
|
||||
/>
|
||||
|
||||
<ListItemLink
|
||||
to="/connections"
|
||||
primary={i18n.t("mainDrawer.listItems.connections")}
|
||||
primary={i18n.t('mainDrawer.listItems.connections')}
|
||||
icon={
|
||||
<Badge badgeContent={connectionWarning ? "!" : 0} color="error">
|
||||
<Badge badgeContent={connectionWarning ? '!' : 0} color="error">
|
||||
<SyncAltIcon />
|
||||
</Badge>
|
||||
}
|
||||
/>
|
||||
|
||||
<ListItemLink to="/" primary="Dashboard" icon={<DashboardOutlinedIcon />} />
|
||||
<ListItemLink
|
||||
to="/"
|
||||
primary="Dashboard"
|
||||
icon={<DashboardOutlinedIcon />}
|
||||
/>
|
||||
|
||||
<ListItemLink to="/report" primary="Relatório" icon={<ReportOutlinedIcon />} />
|
||||
<ListItemLink
|
||||
to="/report"
|
||||
primary="Relatório"
|
||||
icon={<ReportOutlinedIcon />}
|
||||
/>
|
||||
|
||||
<ListItemLink
|
||||
to="/campaign"
|
||||
primary="Campanha"
|
||||
icon={<CampaignIcon />}
|
||||
/>
|
||||
|
||||
<Can
|
||||
role={user.profile}
|
||||
|
@ -148,13 +168,14 @@ const MainListItems = (props) => {
|
|||
icon={<DeviceHubOutlined />}
|
||||
/>
|
||||
</>
|
||||
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default MainListItems;
|
||||
export default MainListItems
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import openSocket from 'socket.io-client'
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { green } from '@material-ui/core/colors'
|
||||
import {
|
||||
Button,
|
||||
TableBody,
|
||||
TableRow,
|
||||
TableCell,
|
||||
IconButton,
|
||||
Table,
|
||||
TableHead,
|
||||
Paper,
|
||||
} from '@material-ui/core'
|
||||
import {
|
||||
Edit,
|
||||
DeleteOutline,
|
||||
// Restore
|
||||
} from '@material-ui/icons'
|
||||
|
||||
import MainContainer from '../../components/MainContainer'
|
||||
import MainHeader from '../../components/MainHeader'
|
||||
import MainHeaderButtonsWrapper from '../../components/MainHeaderButtonsWrapper'
|
||||
import Title from '../../components/Title'
|
||||
import TableRowSkeleton from '../../components/TableRowSkeleton'
|
||||
|
||||
import CampaignModal from '../../components/CampaignModal'
|
||||
import ConfirmationModal from '../../components/ConfirmationModal'
|
||||
import QrcodeModal from '../../components/QrcodeModal'
|
||||
import { i18n } from '../../translate/i18n'
|
||||
// import { WhatsAppsContext } from '../../context/WhatsApp/WhatsAppsContext'
|
||||
import toastError from '../../errors/toastError'
|
||||
|
||||
//--------
|
||||
import { AuthContext } from '../../context/Auth/AuthContext'
|
||||
import { Can } from '../../components/Can'
|
||||
|
||||
import apiBroker from '../../services/apiBroker'
|
||||
|
||||
|
||||
|
||||
|
||||
const reducer = (state, action) => {
|
||||
|
||||
|
||||
if (action.type === "LOAD_CAMPAIGNS") {
|
||||
|
||||
const campaigns = action.payload
|
||||
return [...state, ...campaigns]
|
||||
}
|
||||
if (action.type === "UPDATE_CAMPAIGNS") {
|
||||
|
||||
const campaign = action.payload
|
||||
const campaignIndex = state.findIndex((c) => c.id === campaign.id)
|
||||
|
||||
if (campaignIndex !== -1) {
|
||||
|
||||
state[campaignIndex] = { ...state[campaignIndex], ...campaign }
|
||||
|
||||
return [...state]
|
||||
|
||||
// state[campaignIndex] = campaign
|
||||
|
||||
// return [...state]
|
||||
} else {
|
||||
return [campaign, ...state]
|
||||
}
|
||||
}
|
||||
if (action.type === "DELETE_CAMPAIGN") {
|
||||
const campaignId = action.payload
|
||||
|
||||
const campaignIndex = state.findIndex((c) => c.id === campaignId)
|
||||
if (campaignIndex !== -1) {
|
||||
state.splice(campaignIndex, 1)
|
||||
}
|
||||
return [...state]
|
||||
}
|
||||
|
||||
if (action.type === "RESET") {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
mainPaper: {
|
||||
flex: 1,
|
||||
padding: theme.spacing(1),
|
||||
overflowY: 'scroll',
|
||||
...theme.scrollbarStyles,
|
||||
},
|
||||
customTableCell: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: '#f5f5f9',
|
||||
color: 'rgba(0, 0, 0, 0.87)',
|
||||
fontSize: theme.typography.pxToRem(14),
|
||||
border: '1px solid #dadde9',
|
||||
maxWidth: 450,
|
||||
},
|
||||
tooltipPopper: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
buttonProgress: {
|
||||
color: green[500],
|
||||
},
|
||||
}))
|
||||
|
||||
const Campaign = () => {
|
||||
//--------
|
||||
const { user } = useContext(AuthContext)
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
// const { whatsApps } = useContext(WhatsAppsContext)
|
||||
|
||||
// const { campaigns, loading } = useContext(WhatsAppsContext)
|
||||
const [campaignModalOpen, setCampaignModalOpen] = useState(false)
|
||||
const [qrModalOpen, setQrModalOpen] = useState(false)
|
||||
const [selectedCampaign, setSelectedCampaign] = useState(null)
|
||||
const [confirmModalOpen, setConfirmModalOpen] = useState(false)
|
||||
|
||||
const [campaigns, dispatch] = useReducer(reducer, [])
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const confirmationModalInitialState = {
|
||||
action: '',
|
||||
title: '',
|
||||
message: '',
|
||||
campaignId: '',
|
||||
csv_original_file_name: '',
|
||||
open: false,
|
||||
}
|
||||
const [confirmModalInfo, setConfirmModalInfo] = useState(
|
||||
confirmationModalInitialState
|
||||
)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" })
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchContacts = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const { data } = await apiBroker.get('/campaign', {
|
||||
params: {
|
||||
adminId: user.id,
|
||||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||
identifier: 'campaign'
|
||||
}
|
||||
})
|
||||
|
||||
dispatch({ type: "LOAD_CAMPAIGNS", payload: data.campaign })
|
||||
setLoading(false)
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
|
||||
}
|
||||
fetchContacts()
|
||||
}, 500)
|
||||
return () => clearTimeout(delayDebounceFn)
|
||||
}, [user.id])
|
||||
|
||||
|
||||
const handleOpenCampaignModal = () => {
|
||||
setSelectedCampaign(null)
|
||||
setCampaignModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCloseCampaignModal = useCallback(() => {
|
||||
setCampaignModalOpen(false)
|
||||
setSelectedCampaign(null)
|
||||
}, [setSelectedCampaign, setCampaignModalOpen])
|
||||
|
||||
const handleStart = async (campaign) => {
|
||||
|
||||
try {
|
||||
const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`)
|
||||
|
||||
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
|
||||
|
||||
toast.success('Campanha iniciada com sucesso')
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleStop = async (campaign) => {
|
||||
|
||||
try {
|
||||
const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`)
|
||||
|
||||
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
|
||||
|
||||
toast.success('Campanha parada com sucesso')
|
||||
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseQrModal = useCallback(() => {
|
||||
setSelectedCampaign(null)
|
||||
setQrModalOpen(false)
|
||||
}, [setQrModalOpen, setSelectedCampaign])
|
||||
|
||||
const handleEditCampaign = (campaign) => {
|
||||
setSelectedCampaign(campaign)
|
||||
setCampaignModalOpen(true)
|
||||
}
|
||||
|
||||
const handleOpenConfirmationModal = (action, campaignId) => {
|
||||
if (action === 'disconnect') {
|
||||
setConfirmModalInfo({
|
||||
action: action,
|
||||
title: i18n.t('connections.confirmationModal.disconnectTitle'),
|
||||
message: i18n.t('connections.confirmationModal.disconnectMessage'),
|
||||
campaignId: campaignId,
|
||||
})
|
||||
}
|
||||
|
||||
if (action === 'delete') {
|
||||
setConfirmModalInfo({
|
||||
action: action,
|
||||
title: i18n.t('connections.confirmationModal.deleteTitle'),
|
||||
message: i18n.t('connections.confirmationModal.deleteMessage'),
|
||||
campaignId: campaignId,
|
||||
})
|
||||
}
|
||||
setConfirmModalOpen(true)
|
||||
}
|
||||
|
||||
const handleSubmitConfirmationModal = async () => {
|
||||
|
||||
if (confirmModalInfo.action === 'delete') {
|
||||
try {
|
||||
await apiBroker.delete(`/campaign/${confirmModalInfo.campaignId}`, {
|
||||
params: {
|
||||
adminId: user.id,
|
||||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||
identifier: 'campaign',
|
||||
},
|
||||
})
|
||||
|
||||
dispatch({ type: "DELETE_CAMPAIGN", payload: confirmModalInfo.campaignId })
|
||||
|
||||
toast.success('Campanha deletada com sucesso')
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
}
|
||||
|
||||
setConfirmModalInfo(confirmationModalInitialState)
|
||||
}
|
||||
|
||||
const renderActionButtons = (campaign) => {
|
||||
return (
|
||||
<>
|
||||
{campaign.status === 'stopped' && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => handleStart(campaign)}
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
)}
|
||||
{campaign.status === 'running' && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => handleStop(campaign)}
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
|
||||
|
||||
|
||||
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
|
||||
if (data.action === 'update') {
|
||||
|
||||
if (String(data.insertOnQueue.adminId) === String(user.id)) {
|
||||
|
||||
if (data?.insertOnQueue?.campaign?.status === "stopped") {
|
||||
|
||||
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.insertOnQueue.campaign })
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('campaign', (data) => {
|
||||
|
||||
if (data.action === 'update') {
|
||||
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
return () => {
|
||||
socket.disconnect()
|
||||
}
|
||||
}, [user.id])
|
||||
|
||||
return (
|
||||
<Can
|
||||
role={user.profile}
|
||||
perform="connections-view:show"
|
||||
yes={() => (
|
||||
<MainContainer>
|
||||
<ConfirmationModal
|
||||
title={confirmModalInfo.title}
|
||||
open={confirmModalOpen}
|
||||
onClose={setConfirmModalOpen}
|
||||
onConfirm={handleSubmitConfirmationModal}
|
||||
>
|
||||
{confirmModalInfo.message}
|
||||
</ConfirmationModal>
|
||||
|
||||
<QrcodeModal
|
||||
open={qrModalOpen}
|
||||
onClose={handleCloseQrModal}
|
||||
campaignId={!campaignModalOpen && selectedCampaign?.id}
|
||||
/>
|
||||
|
||||
<CampaignModal
|
||||
open={campaignModalOpen}
|
||||
onClose={handleCloseCampaignModal}
|
||||
campaignId={selectedCampaign?.id}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
|
||||
<MainHeader>
|
||||
<Title>Campanhas</Title>
|
||||
|
||||
<MainHeaderButtonsWrapper>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleOpenCampaignModal}
|
||||
>
|
||||
criar campanha
|
||||
</Button>
|
||||
</MainHeaderButtonsWrapper>
|
||||
</MainHeader>
|
||||
|
||||
<Paper className={classes.mainPaper} variant="outlined">
|
||||
<>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">
|
||||
Name
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Status
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Sent
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Read
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Start/stop
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Sender
|
||||
</TableCell>
|
||||
|
||||
|
||||
<TableCell align="center">
|
||||
Message
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{i18n.t('connections.table.actions')}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{loading ? (
|
||||
<TableRowSkeleton />
|
||||
) : (
|
||||
<>
|
||||
{campaigns?.length > 0 &&
|
||||
campaigns.map((campaign) => (
|
||||
<TableRow key={campaign.id}>
|
||||
<TableCell align="center">
|
||||
{campaign.name}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{campaign.status}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{campaign.status === 'stopped' || campaign.status === 'running' || campaign.status === 'success' ? `${campaign.sent}/${campaign.all}` : '0/0'}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{campaign.status === 'stopped' || campaign.status === 'running' || campaign.status === 'success' ? `${campaign.read}` : '0'}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{renderActionButtons(campaign)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{campaign.whatsapp_sender}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{campaign.message}
|
||||
</TableCell>
|
||||
|
||||
{campaign.status !== 'running' ? <TableCell align="center">
|
||||
|
||||
{campaign.status !== 'success' && (
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() =>
|
||||
handleEditCampaign(campaign)
|
||||
}
|
||||
>
|
||||
<Edit />
|
||||
</IconButton>)}
|
||||
|
||||
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
handleOpenConfirmationModal(
|
||||
'delete',
|
||||
campaign.id
|
||||
)
|
||||
}}
|
||||
>
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
</TableCell> : <TableCell align="center"></TableCell>}
|
||||
|
||||
|
||||
|
||||
</TableRow>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</>
|
||||
</Paper>
|
||||
</MainContainer>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Campaign
|
|
@ -6,6 +6,9 @@ import openSocket from 'socket.io-client'
|
|||
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { green } from '@material-ui/core/colors'
|
||||
|
||||
import Settings from "@material-ui/icons/Settings";
|
||||
|
||||
import {
|
||||
Button,
|
||||
TableBody,
|
||||
|
@ -47,6 +50,7 @@ import toastError from '../../errors/toastError'
|
|||
//--------
|
||||
import { AuthContext } from '../../context/Auth/AuthContext'
|
||||
import { Can } from '../../components/Can'
|
||||
import ConfigModal from '../../components/ConfigModal'
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
mainPaper: {
|
||||
|
@ -107,6 +111,7 @@ const Connections = () => {
|
|||
|
||||
const { whatsApps, loading } = useContext(WhatsAppsContext)
|
||||
const [whatsAppModalOpen, setWhatsAppModalOpen] = useState(false)
|
||||
const [configModalOpen, setConfigModalOpen] = useState(false)
|
||||
const [qrModalOpen, setQrModalOpen] = useState(false)
|
||||
const [selectedWhatsApp, setSelectedWhatsApp] = useState(null)
|
||||
const [confirmModalOpen, setConfirmModalOpen] = useState(false)
|
||||
|
@ -134,7 +139,7 @@ const Connections = () => {
|
|||
const fetchSession = async () => {
|
||||
try {
|
||||
const { data } = await api.get('/settings')
|
||||
setSettings(data)
|
||||
setSettings(data.settings)
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
|
@ -205,6 +210,13 @@ const Connections = () => {
|
|||
setWhatsAppModalOpen(true)
|
||||
}
|
||||
|
||||
const handleOpenConfigModal = () => {
|
||||
setConfigModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCloseConfigModal = () => {
|
||||
setConfigModalOpen(false)
|
||||
}
|
||||
const handleCloseWhatsAppModal = useCallback(() => {
|
||||
setWhatsAppModalOpen(false)
|
||||
setSelectedWhatsApp(null)
|
||||
|
@ -307,17 +319,17 @@ const Connections = () => {
|
|||
{(whatsApp.status === 'CONNECTED' ||
|
||||
whatsApp.status === 'PAIRING' ||
|
||||
whatsApp.status === 'TIMEOUT') && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
handleOpenConfirmationModal('disconnect', whatsApp.id)
|
||||
}}
|
||||
>
|
||||
{i18n.t('connections.buttons.disconnect')}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
handleOpenConfirmationModal('disconnect', whatsApp.id)
|
||||
}}
|
||||
>
|
||||
{i18n.t('connections.buttons.disconnect')}
|
||||
</Button>
|
||||
)}
|
||||
{whatsApp.status === 'OPENING' && (
|
||||
<Button size="small" variant="outlined" disabled color="default">
|
||||
{i18n.t('connections.buttons.connecting')}
|
||||
|
@ -454,10 +466,24 @@ const Connections = () => {
|
|||
whatsAppId={!qrModalOpen && selectedWhatsApp?.id}
|
||||
/>
|
||||
|
||||
<ConfigModal
|
||||
open={configModalOpen}
|
||||
onClose={handleCloseConfigModal}
|
||||
change={configModalOpen}
|
||||
/>
|
||||
|
||||
<MainHeader>
|
||||
<Title>{i18n.t('connections.title')}</Title>
|
||||
|
||||
<MainHeaderButtonsWrapper>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleOpenConfigModal}
|
||||
>
|
||||
<Settings/>
|
||||
</Button>
|
||||
<Can
|
||||
role={user.profile}
|
||||
perform="btn-add-whatsapp"
|
||||
|
@ -664,8 +690,8 @@ const Connections = () => {
|
|||
settings.length > 0 &&
|
||||
getSettingValue('editURA') &&
|
||||
getSettingValue('editURA') ===
|
||||
'enabled') |
|
||||
(user.profile === 'master') ? (
|
||||
'enabled') |
|
||||
(user.profile === 'master') ? (
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() =>
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
import React, { useState, useEffect, useReducer, useContext } from "react";
|
||||
import openSocket from "socket.io-client";
|
||||
import { toast } from "react-toastify";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import React, { useState, useEffect, useReducer, useContext } from "react"
|
||||
import openSocket from "socket.io-client"
|
||||
import { toast } from "react-toastify"
|
||||
import { useHistory } from "react-router-dom"
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import WhatsAppIcon from "@material-ui/icons/WhatsApp";
|
||||
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 Table from "@material-ui/core/Table"
|
||||
import TableBody from "@material-ui/core/TableBody"
|
||||
import TableCell from "@material-ui/core/TableCell"
|
||||
import TableHead from "@material-ui/core/TableHead"
|
||||
import TableRow from "@material-ui/core/TableRow"
|
||||
import Paper from "@material-ui/core/Paper"
|
||||
import Button from "@material-ui/core/Button"
|
||||
import Avatar from "@material-ui/core/Avatar"
|
||||
import WhatsAppIcon from "@material-ui/icons/WhatsApp"
|
||||
import SearchIcon from "@material-ui/icons/Search"
|
||||
import TextField from "@material-ui/core/TextField"
|
||||
import InputAdornment from "@material-ui/core/InputAdornment"
|
||||
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
|
||||
import EditIcon from "@material-ui/icons/Edit";
|
||||
import IconButton from "@material-ui/core/IconButton"
|
||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
|
||||
import EditIcon from "@material-ui/icons/Edit"
|
||||
|
||||
import api from "../../services/api";
|
||||
import TableRowSkeleton from "../../components/TableRowSkeleton";
|
||||
import ContactModal from "../../components/ContactModal";
|
||||
import ConfirmationModal from "../../components/ConfirmationModal/";
|
||||
import api from "../../services/api"
|
||||
import TableRowSkeleton from "../../components/TableRowSkeleton"
|
||||
import ContactModal from "../../components/ContactModal"
|
||||
import ConfirmationModal from "../../components/ConfirmationModal/"
|
||||
|
||||
import { i18n } from "../../translate/i18n";
|
||||
import MainHeader from "../../components/MainHeader";
|
||||
import Title from "../../components/Title";
|
||||
import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper";
|
||||
import MainContainer from "../../components/MainContainer";
|
||||
import toastError from "../../errors/toastError";
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
import { Can } from "../../components/Can";
|
||||
import { i18n } from "../../translate/i18n"
|
||||
import MainHeader from "../../components/MainHeader"
|
||||
import Title from "../../components/Title"
|
||||
import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper"
|
||||
import MainContainer from "../../components/MainContainer"
|
||||
import toastError from "../../errors/toastError"
|
||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||
import { Can } from "../../components/Can"
|
||||
|
||||
import apiBroker from "../../services/apiBroker";
|
||||
import apiBroker from "../../services/apiBroker"
|
||||
import fileDownload from 'js-file-download'
|
||||
import ContactCreateTicketModal from "../../components/ContactCreateTicketModal";
|
||||
import ContactCreateTicketModal from "../../components/ContactCreateTicketModal"
|
||||
|
||||
|
||||
|
||||
|
@ -46,50 +46,50 @@ const reducer = (state, action) => {
|
|||
|
||||
if (action.type === "LOAD_CONTACTS") {
|
||||
|
||||
const contacts = action.payload;
|
||||
const newContacts = [];
|
||||
const contacts = action.payload
|
||||
const newContacts = []
|
||||
|
||||
contacts.forEach((contact) => {
|
||||
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id);
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id)
|
||||
|
||||
if (contactIndex !== -1) {
|
||||
state[contactIndex] = contact;
|
||||
state[contactIndex] = contact
|
||||
} else {
|
||||
newContacts.push(contact);
|
||||
newContacts.push(contact)
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
return [...state, ...newContacts];
|
||||
return [...state, ...newContacts]
|
||||
}
|
||||
|
||||
if (action.type === "UPDATE_CONTACTS") {
|
||||
const contact = action.payload;
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id);
|
||||
const contact = action.payload
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id)
|
||||
|
||||
if (contactIndex !== -1) {
|
||||
state[contactIndex] = contact;
|
||||
return [...state];
|
||||
state[contactIndex] = contact
|
||||
return [...state]
|
||||
} else {
|
||||
return [contact, ...state];
|
||||
return [contact, ...state]
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === "DELETE_CONTACT") {
|
||||
const contactId = action.payload;
|
||||
const contactId = action.payload
|
||||
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contactId);
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contactId)
|
||||
if (contactIndex !== -1) {
|
||||
state.splice(contactIndex, 1);
|
||||
state.splice(contactIndex, 1)
|
||||
}
|
||||
return [...state];
|
||||
return [...state]
|
||||
}
|
||||
|
||||
if (action.type === "RESET") {
|
||||
return [];
|
||||
return []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
mainPaper: {
|
||||
|
@ -98,24 +98,24 @@ const useStyles = makeStyles((theme) => ({
|
|||
overflowY: "scroll",
|
||||
...theme.scrollbarStyles,
|
||||
},
|
||||
}));
|
||||
}))
|
||||
|
||||
const Contacts = () => {
|
||||
const classes = useStyles();
|
||||
const history = useHistory();
|
||||
const classes = useStyles()
|
||||
const history = useHistory()
|
||||
|
||||
const { user } = useContext(AuthContext);
|
||||
const { user } = useContext(AuthContext)
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [searchParam, setSearchParam] = useState("");
|
||||
const [contacts, dispatch] = useReducer(reducer, []);
|
||||
const [selectedContactId, setSelectedContactId] = useState(null);
|
||||
const [contactModalOpen, setContactModalOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [pageNumber, setPageNumber] = useState(1)
|
||||
const [searchParam, setSearchParam] = useState("")
|
||||
const [contacts, dispatch] = useReducer(reducer, [])
|
||||
const [selectedContactId, setSelectedContactId] = useState(null)
|
||||
const [contactModalOpen, setContactModalOpen] = useState(false)
|
||||
const [isCreateTicketModalOpen, setIsCreateTicketModalOpen] = useState(false)
|
||||
const [deletingContact, setDeletingContact] = useState(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
const [deletingContact, setDeletingContact] = useState(null)
|
||||
const [confirmOpen, setConfirmOpen] = useState(false)
|
||||
const [hasMore, setHasMore] = useState(false)
|
||||
|
||||
|
||||
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
||||
|
@ -132,20 +132,20 @@ const Contacts = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("adminId", user.id);
|
||||
formData.append("baseURL", process.env.REACT_APP_BACKEND_URL_PRIVATE,);
|
||||
formData.append("frontURL", process.env.REACT_APP_FRONTEND_URL);
|
||||
formData.append("identifier", 'contacts_insert_csv');
|
||||
formData.append("file", event.target.files[0]);
|
||||
const formData = new FormData()
|
||||
formData.append("adminId", user.id)
|
||||
formData.append("baseURL", process.env.REACT_APP_BACKEND_URL_PRIVATE,)
|
||||
formData.append("frontURL", process.env.REACT_APP_FRONTEND_URL)
|
||||
formData.append("identifier", 'contacts_insert_csv')
|
||||
formData.append("file", event.target.files[0])
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const bulk_contact_insert = await apiBroker.post("/contacts/bulk/insert", formData, config);
|
||||
const bulk_contact_insert = await apiBroker.post("/contacts/bulk/insert", formData, config)
|
||||
|
||||
console.log(bulk_contact_insert.data)
|
||||
|
||||
|
@ -156,7 +156,7 @@ const Contacts = () => {
|
|||
|
||||
// history.go(0);
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -177,12 +177,9 @@ const Contacts = () => {
|
|||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||
identifier: 'contacts_insert_csv'
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
if (insertOnQueue && insertOnQueue.data) {
|
||||
|
||||
console.log('insertOnQueue: ', insertOnQueue.data)
|
||||
console.log('data.app.file: ', insertOnQueue.data.app.file)
|
||||
if (insertOnQueue && insertOnQueue.data) {
|
||||
|
||||
setZipFile(insertOnQueue.data.app.file)
|
||||
setOnQueueProcessStatus(insertOnQueue.data.app.status)
|
||||
|
@ -193,23 +190,23 @@ const Contacts = () => {
|
|||
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(err)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fetchReportOnQueue();
|
||||
fetchReportOnQueue()
|
||||
|
||||
}, 500);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, 500)
|
||||
return () => clearTimeout(delayDebounceFn)
|
||||
|
||||
}, [user])
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
setPageNumber(1);
|
||||
}, [searchParam]);
|
||||
dispatch({ type: "RESET" })
|
||||
setPageNumber(1)
|
||||
}, [searchParam])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
@ -220,7 +217,7 @@ const Contacts = () => {
|
|||
|
||||
|
||||
|
||||
setLoading(true);
|
||||
setLoading(true)
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchContacts = async () => {
|
||||
|
||||
|
@ -230,25 +227,25 @@ const Contacts = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const { data } = await api.get("/contacts/", { params: { searchParam, pageNumber }, });
|
||||
const { data } = await api.get("/contacts/", { params: { searchParam, pageNumber }, })
|
||||
|
||||
|
||||
dispatch({ type: "LOAD_CONTACTS", payload: data.contacts });
|
||||
setHasMore(data.hasMore);
|
||||
setLoading(false);
|
||||
dispatch({ type: "LOAD_CONTACTS", payload: data.contacts })
|
||||
setHasMore(data.hasMore)
|
||||
setLoading(false)
|
||||
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
|
||||
};
|
||||
fetchContacts();
|
||||
}, 500);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [searchParam, pageNumber]);
|
||||
}
|
||||
fetchContacts()
|
||||
}, 500)
|
||||
return () => clearTimeout(delayDebounceFn)
|
||||
}, [searchParam, pageNumber])
|
||||
|
||||
useEffect(() => {
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
|
||||
|
||||
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
|
||||
if (data.action === 'update') {
|
||||
|
@ -261,7 +258,7 @@ const Contacts = () => {
|
|||
setOnQueueProcessStatus(data.insertOnQueue.queueStatus)
|
||||
|
||||
if (data.insertOnQueue.queueStatus === "success") {
|
||||
history.go(0);
|
||||
history.go(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,18 +267,18 @@ const Contacts = () => {
|
|||
|
||||
socket.on("contact", (data) => {
|
||||
if (data.action === "update" || data.action === "create") {
|
||||
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact });
|
||||
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact })
|
||||
}
|
||||
|
||||
if (data.action === "delete") {
|
||||
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId });
|
||||
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId })
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return () => {
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [user, history]);
|
||||
socket.disconnect()
|
||||
}
|
||||
}, [user, history])
|
||||
|
||||
const removeExtraSpace = (str) => {
|
||||
|
||||
|
@ -291,18 +288,18 @@ const Contacts = () => {
|
|||
}
|
||||
|
||||
const handleSearch = (event) => {
|
||||
setSearchParam(removeExtraSpace(event.target.value.toLowerCase()));
|
||||
};
|
||||
setSearchParam(removeExtraSpace(event.target.value.toLowerCase()))
|
||||
}
|
||||
|
||||
const handleOpenContactModal = () => {
|
||||
setSelectedContactId(null);
|
||||
setContactModalOpen(true);
|
||||
};
|
||||
setSelectedContactId(null)
|
||||
setContactModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCloseContactModal = () => {
|
||||
setSelectedContactId(null);
|
||||
setContactModalOpen(false);
|
||||
};
|
||||
setSelectedContactId(null)
|
||||
setContactModalOpen(false)
|
||||
}
|
||||
|
||||
const handleOpenCreateTicketModal = (contactId) => {
|
||||
setSelectedContactId(contactId)
|
||||
|
@ -330,46 +327,46 @@ const Contacts = () => {
|
|||
// };
|
||||
|
||||
const hadleEditContact = (contactId) => {
|
||||
setSelectedContactId(contactId);
|
||||
setContactModalOpen(true);
|
||||
};
|
||||
setSelectedContactId(contactId)
|
||||
setContactModalOpen(true)
|
||||
}
|
||||
|
||||
const handleDeleteContact = async (contactId) => {
|
||||
try {
|
||||
await api.delete(`/contacts/${contactId}`);
|
||||
toast.success(i18n.t("contacts.toasts.deleted"));
|
||||
await api.delete(`/contacts/${contactId}`)
|
||||
toast.success(i18n.t("contacts.toasts.deleted"))
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
setDeletingContact(null);
|
||||
setSearchParam("");
|
||||
setPageNumber(1);
|
||||
};
|
||||
setDeletingContact(null)
|
||||
setSearchParam("")
|
||||
setPageNumber(1)
|
||||
}
|
||||
|
||||
const handleimportContact = async () => {
|
||||
try {
|
||||
await api.post("/contacts/import");
|
||||
history.go(0);
|
||||
await api.post("/contacts/import")
|
||||
history.go(0)
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const handleDownload = async () => {
|
||||
|
@ -378,16 +375,16 @@ const Contacts = () => {
|
|||
|
||||
try {
|
||||
|
||||
let res = await apiBroker.get(`/contacts/download/${zipfile}`, { responseType: 'blob' });
|
||||
let res = await apiBroker.get(`/contacts/download/${zipfile}`, { responseType: 'blob' })
|
||||
|
||||
if (res) {
|
||||
fileDownload(res.data, `${zipfile}`);
|
||||
fileDownload(res.data, `${zipfile}`)
|
||||
setOnQueueProcessStatus('empty')
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
|
||||
|
@ -406,7 +403,7 @@ const Contacts = () => {
|
|||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||
identifier: 'contacts_insert_csv'
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
if (res) {
|
||||
setOnQueueProcessStatus('empty')
|
||||
|
@ -414,7 +411,7 @@ const Contacts = () => {
|
|||
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
|
||||
|
@ -452,13 +449,13 @@ const Contacts = () => {
|
|||
>
|
||||
{"CSV ALL"}
|
||||
</Button> */}
|
||||
</>);
|
||||
</>)
|
||||
|
||||
case 'pending' || 'processing':
|
||||
return (
|
||||
<>
|
||||
<span>PROCESSING...</span>
|
||||
</>);
|
||||
</>)
|
||||
|
||||
case 'success':
|
||||
return (
|
||||
|
@ -472,7 +469,7 @@ const Contacts = () => {
|
|||
>
|
||||
{'DOWNLOAD'}
|
||||
</Button>
|
||||
</>);
|
||||
</>)
|
||||
case 'error':
|
||||
return (
|
||||
<>
|
||||
|
@ -485,16 +482,16 @@ const Contacts = () => {
|
|||
>
|
||||
{'ERROR'}
|
||||
</Button>
|
||||
</>);
|
||||
</>)
|
||||
case 'downloading':
|
||||
return (
|
||||
<>
|
||||
<span>DOWNLOADING...</span>
|
||||
</>);
|
||||
</>)
|
||||
|
||||
|
||||
default:
|
||||
return (<><span>WAITING...</span></>);
|
||||
return (<><span>WAITING...</span></>)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,8 +639,8 @@ const Contacts = () => {
|
|||
<IconButton
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
setConfirmOpen(true);
|
||||
setDeletingContact(contact);
|
||||
setConfirmOpen(true)
|
||||
setDeletingContact(contact)
|
||||
}}
|
||||
>
|
||||
<DeleteOutlineIcon />
|
||||
|
@ -659,7 +656,7 @@ const Contacts = () => {
|
|||
</Table>
|
||||
</Paper>
|
||||
</MainContainer>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Contacts;
|
||||
export default Contacts
|
|
@ -121,7 +121,7 @@ const Queues = () => {
|
|||
const fetchSession = async () => {
|
||||
try {
|
||||
const { data } = await api.get('/settings')
|
||||
setSettings(data)
|
||||
setSettings(data.settings)
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ const Settings = () => {
|
|||
const fetchSession = async () => {
|
||||
try {
|
||||
const { data } = await api.get('/settings')
|
||||
setSettings(data)
|
||||
setSettings(data.settings)
|
||||
} catch (err) {
|
||||
toastError(err)
|
||||
}
|
||||
|
@ -198,6 +198,34 @@ const Settings = () => {
|
|||
</Paper>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Container className={classes.container} maxWidth="sm">
|
||||
<Paper className={classes.paper}>
|
||||
<Typography variant="body1">
|
||||
Contato conversar com whatsapps distintos no omnihit
|
||||
</Typography>
|
||||
|
||||
<Select
|
||||
margin="dense"
|
||||
variant="outlined"
|
||||
native
|
||||
id="oneContactChatWithManyWhats-setting"
|
||||
name="oneContactChatWithManyWhats"
|
||||
value={
|
||||
settings &&
|
||||
settings.length > 0 &&
|
||||
getSettingValue('oneContactChatWithManyWhats')
|
||||
}
|
||||
className={classes.settingOption}
|
||||
onChange={handleChangeSetting}
|
||||
>
|
||||
<option value="enabled">Ativado</option>
|
||||
<option value="disabled">Desativado</option>
|
||||
</Select>
|
||||
</Paper>
|
||||
</Container>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import React from "react";
|
||||
import { BrowserRouter, Switch } from "react-router-dom";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import React from 'react'
|
||||
import { BrowserRouter, Switch } from 'react-router-dom'
|
||||
import { ToastContainer } from 'react-toastify'
|
||||
|
||||
import LoggedInLayout from "../layout";
|
||||
import Dashboard from "../pages/Dashboard/";
|
||||
|
||||
import Report from "../pages/Report/";
|
||||
import SchedulesReminder from "../pages/SchedulesReminder/";
|
||||
|
||||
import Tickets from "../pages/Tickets/";
|
||||
import Signup from "../pages/Signup/";
|
||||
import Login from "../pages/Login/";
|
||||
import Connections from "../pages/Connections/";
|
||||
import Settings from "../pages/Settings/";
|
||||
import Users from "../pages/Users";
|
||||
import Contacts from "../pages/Contacts/";
|
||||
import QuickAnswers from "../pages/QuickAnswers/";
|
||||
import Queues from "../pages/Queues/";
|
||||
import { AuthProvider } from "../context/Auth/AuthContext";
|
||||
import { WhatsAppsProvider } from "../context/WhatsApp/WhatsAppsContext";
|
||||
import Route from "./Route";
|
||||
import LoggedInLayout from '../layout'
|
||||
import Dashboard from '../pages/Dashboard/'
|
||||
|
||||
import Dialogflows from "../pages/Dialogflow/";
|
||||
import Report from '../pages/Report/'
|
||||
import SchedulesReminder from '../pages/SchedulesReminder/'
|
||||
|
||||
import Tickets from '../pages/Tickets/'
|
||||
import Signup from '../pages/Signup/'
|
||||
import Login from '../pages/Login/'
|
||||
import Connections from '../pages/Connections/'
|
||||
import Campaign from '../pages/Campaign'
|
||||
import Settings from '../pages/Settings/'
|
||||
import Users from '../pages/Users'
|
||||
import Contacts from '../pages/Contacts/'
|
||||
import QuickAnswers from '../pages/QuickAnswers/'
|
||||
import Queues from '../pages/Queues/'
|
||||
import { AuthProvider } from '../context/Auth/AuthContext'
|
||||
import { WhatsAppsProvider } from '../context/WhatsApp/WhatsAppsContext'
|
||||
import Route from './Route'
|
||||
|
||||
const Routes = () => {
|
||||
return (
|
||||
|
@ -33,28 +33,49 @@ const Routes = () => {
|
|||
<WhatsAppsProvider>
|
||||
<LoggedInLayout>
|
||||
<Route exact path="/" component={Dashboard} isPrivate />
|
||||
<Route exact path="/tickets/:ticketId?" component={Tickets} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/tickets/:ticketId?"
|
||||
component={Tickets}
|
||||
isPrivate
|
||||
/>
|
||||
|
||||
<Route exact path="/connections" component={Connections} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/connections"
|
||||
component={Connections}
|
||||
isPrivate
|
||||
/>
|
||||
|
||||
<Route exact path="/report" component={Report} isPrivate />
|
||||
|
||||
<Route exact path="/contacts" component={Contacts} isPrivate />
|
||||
|
||||
<Route exact path="/schedulesReminder" component={SchedulesReminder} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/schedulesReminder"
|
||||
component={SchedulesReminder}
|
||||
isPrivate
|
||||
/>
|
||||
|
||||
<Route exact path="/users" component={Users} isPrivate />
|
||||
<Route exact path="/quickAnswers" component={QuickAnswers} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/quickAnswers"
|
||||
component={QuickAnswers}
|
||||
isPrivate
|
||||
/>
|
||||
<Route exact path="/Settings" component={Settings} isPrivate />
|
||||
<Route exact path="/Queues" component={Queues} isPrivate />
|
||||
<Route exact path="/Dialogflows" component={Dialogflows} isPrivate />
|
||||
<Route exact path="/campaign" component={Campaign} isPrivate />
|
||||
</LoggedInLayout>
|
||||
</WhatsAppsProvider>
|
||||
</Switch>
|
||||
<ToastContainer autoClose={3000} />
|
||||
</AuthProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Routes;
|
||||
export default Routes
|
||||
|
|
Loading…
Reference in New Issue