Implementação de solução para consultas dos tickets e dos contatos usando Redis como banco de dados em memória. Ajustes no frontend para corrigir bugs de datas exibidas nas mensagens
parent
603e5fa2dd
commit
bde6058455
Binary file not shown.
|
@ -26,8 +26,10 @@
|
|||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"fast-folder-size": "^1.7.0",
|
||||
"flat": "^5.0.2",
|
||||
"fs-extra": "^10.1.0",
|
||||
"http-graceful-shutdown": "^2.3.2",
|
||||
"ioredis": "^5.2.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"multer": "^1.4.2",
|
||||
"mysql2": "^2.2.5",
|
||||
|
|
|
@ -13,6 +13,12 @@ import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
|||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
||||
import AppError from "../errors/AppError";
|
||||
|
||||
|
||||
import { searchContactCache } from '../helpers/ContactsCache'
|
||||
import { off } from "process";
|
||||
|
||||
|
||||
|
||||
type IndexQuery = {
|
||||
searchParam: string;
|
||||
pageNumber: string;
|
||||
|
@ -30,12 +36,34 @@ interface ContactData {
|
|||
}
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { searchParam, pageNumber } = req.query as IndexQuery;
|
||||
let { searchParam, pageNumber } = req.query as IndexQuery;
|
||||
|
||||
const { contacts, count, hasMore } = await ListContactsService({
|
||||
searchParam,
|
||||
pageNumber
|
||||
});
|
||||
// TEST DEL
|
||||
if (searchParam && searchParam.trim().length > 0) {
|
||||
|
||||
try {
|
||||
|
||||
console.log('QUERY CONTACTS FROM CACHE SEARCH PARAM: ', searchParam)
|
||||
|
||||
const offset = 20 * (+pageNumber - 1);
|
||||
|
||||
const data = await searchContactCache(searchParam, offset, 20)
|
||||
|
||||
if (data) {
|
||||
|
||||
console.log('QUERY CONTACTS FROM CACHE QUERY LENGTH: ', data.length)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const { contacts, count, hasMore } = await ListContactsService({ searchParam, pageNumber });
|
||||
|
||||
return res.json({ contacts, count, hasMore });
|
||||
};
|
||||
|
@ -58,7 +86,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
}
|
||||
|
||||
await CheckIsValidContact(newContact.number);
|
||||
const validNumber : any = await CheckContactNumber(newContact.number)
|
||||
const validNumber: any = await CheckContactNumber(newContact.number)
|
||||
|
||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices
|
|||
// const test = await ListSchedulingNotifyContactService('5517988310949','2022-03-18','2022-03-19');
|
||||
// const test = await ListSchedulingNotifyContactService('','2022-03-18','2022-03-19');
|
||||
// const test = await ListSchedulingNotifyContactService('5517988310949');
|
||||
// console.log('$$$$$$$$$$$$$$$$$$$$$$$$$$ test:\n', test)
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ export const createOrUpdateScheduleNotify = async (req: Request, res: Response):
|
|||
|
||||
const scheduleData = req.body;
|
||||
|
||||
console.log(' +++++++++++ scheduleData: ', scheduleData)
|
||||
|
||||
|
||||
const schedulingNotifyCreate = await CreateSchedulingNotifyService(
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ export const createOrUpdateScheduleNotify = async (req: Request, res: Response):
|
|||
|
||||
export const remove = async ( req: Request, res: Response ): Promise<Response> => {
|
||||
|
||||
console.log('EEEEEEEEEEEEEEEEEEEEEEEEEEE')
|
||||
|
||||
|
||||
const { scheduleId } = req.params;
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ import ptBR from 'date-fns/locale/pt-BR';
|
|||
import { splitDateTime } from "../helpers/SplitDateTime";
|
||||
import format from 'date-fns/format';
|
||||
|
||||
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
|
||||
|
||||
import { searchTicketCache, loadTicketsCache, } from '../helpers/TicketCache'
|
||||
|
||||
|
||||
|
||||
|
@ -90,18 +92,13 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { contactId, status, userId }: TicketData = req.body;
|
||||
|
||||
// naty
|
||||
// console.log(
|
||||
// `contactId: ${contactId} \n| status: ${status} \n| userId: ${userId}`
|
||||
// )
|
||||
|
||||
|
||||
// test del
|
||||
let ticket = await Ticket.findOne({ where: { contactId, status: 'queueChoice' } });
|
||||
|
||||
if (ticket) {
|
||||
await UpdateTicketService({ ticketData: { status: 'open', userId: userId, }, ticketId: ticket.id });
|
||||
console.log('TICKET QUEUE CHOICE !!!!!!!')
|
||||
|
||||
}
|
||||
else {
|
||||
ticket = await CreateTicketService({ contactId, status, userId });
|
||||
|
@ -145,7 +142,7 @@ export const show = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
export const count = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
type indexQ = { status: string; date?: string; };
|
||||
// type indexQ = { status: string; date?: string; };
|
||||
const { status, date } = req.query as IndexQuery
|
||||
|
||||
const ticketCount = await CountTicketService(status, date);
|
||||
|
@ -156,9 +153,6 @@ export const count = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const update = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
const { ticketId } = req.params;
|
||||
|
@ -184,7 +178,7 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
|
||||
///////////////////////////////
|
||||
|
||||
//console.log('------- scheduleData.farewellMessage: ', scheduleData.farewellMessage)
|
||||
//
|
||||
|
||||
if (scheduleData.farewellMessage) {
|
||||
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
|
||||
|
@ -196,14 +190,10 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
// lembrete // agendamento
|
||||
if (scheduleData.statusChatEndId === '2' || scheduleData.statusChatEndId === '3') {
|
||||
|
||||
console.log('*** schedulingDate: ', scheduleData.schedulingDate)
|
||||
console.log('*** schedulingTime: ', scheduleData.schedulingTime)
|
||||
|
||||
if (isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)) {
|
||||
console.log('*** É AGENDAMENTO!')
|
||||
|
@ -257,8 +247,6 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
|
||||
if (userOldInfo.userId) {
|
||||
|
||||
// console.log('FECHOU...')
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(userOldInfo.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
}
|
||||
|
|
|
@ -112,11 +112,7 @@ export const show = async (req: Request, res: Response): Promise<Response> => {
|
|||
export const logoutUser = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { userId } = req.params;
|
||||
|
||||
//const user = await ShowUserService(userId);
|
||||
|
||||
console.log('userId: ', userId)
|
||||
|
||||
//test del
|
||||
await stopWhoIsOnlineMonitor()
|
||||
|
||||
let onlineTime = {
|
||||
|
|
|
@ -125,8 +125,6 @@ export const remove = async (
|
|||
|
||||
removeWbot(+whatsappId);
|
||||
|
||||
console.log('Deleteou o whatsapp service com id = ', whatsappId)
|
||||
|
||||
const io = getIO();
|
||||
io.emit("whatsapp", {
|
||||
action: "delete",
|
||||
|
|
|
@ -58,13 +58,6 @@ const remove = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
const wbot = getWbot(whatsapp.id);
|
||||
|
||||
console.log(
|
||||
'Desconectou s whatsapp.id: ', whatsapp.id,
|
||||
' | PATH TO DELETE',path.join(process.cwd(),'.wwebjs_auth', `session-bd_${whatsapp.id}`)
|
||||
)
|
||||
|
||||
//removeDir(path.join(process.cwd(),'.wwebjs_auth', `session-bd_${whatsapp.id}`))
|
||||
|
||||
await wbot.logout();
|
||||
|
||||
return res.status(200).json({ message: "Session disconnected." });
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
|
||||
import Redis from 'ioredis'
|
||||
import { type } from 'os'
|
||||
const unflatten = require('flat').unflatten
|
||||
var flatten = require('flat')
|
||||
import ListContactsServiceCache from "../services/ContactServices/ListContactsServiceCache"
|
||||
import { redisConn } from './TicketCache'
|
||||
|
||||
|
||||
const deleteContactsByIdCache = async (id: string | number) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const contact_cache: any = await redis.hgetall(`contact:${id}`)
|
||||
|
||||
try {
|
||||
if (contact_cache && Object.keys(contact_cache).length > 0) {
|
||||
|
||||
await redis.del(`contact:${id}`)
|
||||
|
||||
console.log(`Contacts cache number ${contact_cache['number']} deleted!`)
|
||||
}
|
||||
else {
|
||||
console.log('CONTACT CACHE NOT FOUND!')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`There was an error on deleteContactsByIdCache: ${error}`)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
const updateContactCache = async (hash: any, json_object: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
let entries = Object.entries(json_object)
|
||||
|
||||
entries.forEach((e: any) => {
|
||||
pipeline.hset(hash, e[0], e[1])
|
||||
})
|
||||
|
||||
await pipeline.exec(() => { console.log("Key/value inserted/updated") });
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
const updateContactCacheById = async (id: string | number, update_fields: object | any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const contact_cache: any = await redis.hgetall(`contact:${id}`)
|
||||
|
||||
try {
|
||||
if (contact_cache && Object.keys(contact_cache).length > 0) {
|
||||
|
||||
// await redis.del(`contact:${id}`)
|
||||
|
||||
update_fields.escaped_name = escapeCharCache(update_fields.name)
|
||||
|
||||
await updateContactCache(`contact:${id}`, update_fields)
|
||||
|
||||
console.log(`CONTACT ${contact_cache['number']} CACHE WAS UPDATED!`)
|
||||
}
|
||||
else {
|
||||
console.log('CONTACT CACHE NOT FOUND!')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`There was an error on updateContactCacheById: ${error}`)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
const createOrUpdateContactCache = async (hash: any, contact: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
if (contact.name) {
|
||||
contact.escaped_name = escapeCharCache(contact.name)
|
||||
}
|
||||
|
||||
await redis.hmset(hash, contact);
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function searchContactCache(search: string, offset: number, limit: number) {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return null
|
||||
|
||||
search = escapeCharCache(search)
|
||||
|
||||
const response: any = await redis.call('FT.SEARCH', 'idx_contact', `(@escaped_name:*${search}*)|(@number:*${search}*)`, 'LIMIT', offset, limit, 'SORTBY', 'escaped_name', 'ASC')
|
||||
redis.quit()
|
||||
|
||||
|
||||
if (response.length === 1) {
|
||||
return []
|
||||
}
|
||||
|
||||
const results: any = []
|
||||
|
||||
for (let n = 2; n < response.length; n += 2) {
|
||||
const result: any = {}
|
||||
const fieldNamesAndValues = response[n]
|
||||
|
||||
for (let m = 0; m < fieldNamesAndValues.length; m += 2) {
|
||||
const k = fieldNamesAndValues[m]
|
||||
const v = fieldNamesAndValues[m + 1]
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
results.push(result)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
|
||||
const removeExtraSpace = (str: string) => {
|
||||
|
||||
str = str.replace(/^\s+/g, '')
|
||||
|
||||
return str.replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
const escapeCharCache = (str: string) => {
|
||||
|
||||
const pattern = /[\'|\"|\.|\,|\;|\<|\>|\{|\}|\[|\]|\"|\'|\=|\~|\*|\:|\#|\+|\^|\$|\@|\%|\!|\&|\)|\(|/|\-|\\)]/g; // no match, use replace function.
|
||||
|
||||
let newStr = str.replace(pattern, (t1) => `\\${t1}`);
|
||||
|
||||
newStr = removeExtraSpace(newStr)
|
||||
|
||||
return newStr.trim()
|
||||
|
||||
}
|
||||
|
||||
const loadContactsCache = async () => {
|
||||
|
||||
await createContactIndexCache('idx_contact')
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
let contacts = await ListContactsServiceCache()
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
for (let i = 0; i < contacts.length; i++) {
|
||||
|
||||
contacts[i].createdAt = new Date(contacts[i].createdAt).toISOString()
|
||||
contacts[i].updatedAt = new Date(contacts[i].updatedAt).toISOString()
|
||||
|
||||
contacts[i].escaped_name = escapeCharCache(contacts[i].name)
|
||||
|
||||
pipeline.hmset(`contact:${contacts[i].id}`, contacts[i]);
|
||||
}
|
||||
|
||||
await pipeline.exec(() => { console.log(`${contacts.length} CONTACTS INSERTED IN CACHE!`) });
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
const createContactIndexCache = async (hashIndex: string) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
try {
|
||||
|
||||
const lst_index_redis: any = await redis.call('FT._LIST')
|
||||
|
||||
if (lst_index_redis.includes(hashIndex)) {
|
||||
console.log('entrou...')
|
||||
await redis.call('FT.DROPINDEX', hashIndex)
|
||||
}
|
||||
|
||||
const response = await redis.call('FT.CREATE', hashIndex, 'ON', 'HASH', 'PREFIX', '1', 'contact:', 'SCHEMA', 'escaped_name', 'TEXT', 'SORTABLE', 'number', 'TEXT', 'SORTABLE')
|
||||
|
||||
console.log('Contact index created: ', response)
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on createContactIndexCache: ', error)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
export {
|
||||
loadContactsCache,
|
||||
searchContactCache,
|
||||
deleteContactsByIdCache,
|
||||
updateContactCacheById,
|
||||
createOrUpdateContactCache,
|
||||
escapeCharCache
|
||||
}
|
|
@ -12,8 +12,6 @@ export const WhatsIndex = (whatsapps: Object[]) => {
|
|||
WhatsQueueIndex.setIndex(0)
|
||||
}
|
||||
|
||||
// console.log('WhatsQueueIndex.getIndex(): ', WhatsQueueIndex.getIndex())
|
||||
|
||||
index = +WhatsQueueIndex.getIndex()
|
||||
|
||||
WhatsQueueIndex.setIndex(+WhatsQueueIndex.getIndex() + 1)
|
||||
|
|
|
@ -90,21 +90,20 @@ const monitor = async () => {
|
|||
|
||||
whatsapps.forEach(async whats => {
|
||||
|
||||
// console.log('whats id: ', whats.id)
|
||||
|
||||
|
||||
const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`)
|
||||
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
|
||||
try {
|
||||
// console.log('dir path exist!')
|
||||
|
||||
const fastFolderSizeAsync = promisify(fastFolderSize)
|
||||
|
||||
let size = await fastFolderSizeAsync(sourcePath)
|
||||
|
||||
size = convertBytes(size)
|
||||
|
||||
// console.log(size)
|
||||
|
||||
// SESSION MONITORING
|
||||
const io = getIO();
|
||||
|
|
|
@ -52,7 +52,6 @@ const SetTicketMessagesAsRead = async (ticket: Ticket): Promise<void> => {
|
|||
|
||||
if (whatsapp && whatsapp.status == 'CONNECTED') {
|
||||
|
||||
console.log('SetTicketMessagesAsRead.ts - ENTROU NO RESTORE...')
|
||||
|
||||
let timestamp = Math.floor(Date.now() / 1000)
|
||||
|
||||
|
@ -60,7 +59,6 @@ const SetTicketMessagesAsRead = async (ticket: Ticket): Promise<void> => {
|
|||
|
||||
await restartWhatsSession(whatsapp)
|
||||
|
||||
console.log('...PASSOU O RESTORE - SetTicketMessagesAsRead.ts ')
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import { addHours, addMinutes, addSeconds, intervalToDuration, add } from "date-
|
|||
onlineTime.setUTCMinutes(new Date(oldOnlineTimeSum.onlineTime).getMinutes())
|
||||
onlineTime.setUTCSeconds(new Date(oldOnlineTimeSum.onlineTime).getSeconds())
|
||||
|
||||
// console.log('_________________oldOnlineTimeSum.updatedAt: ', oldOnlineTimeSum.updatedAt)
|
||||
|
||||
let newtTime = intervalToDuration({ start: new Date(oldOnlineTimeSum.updatedAt), end: new Date() })
|
||||
|
||||
|
@ -26,7 +25,6 @@ import { addHours, addMinutes, addSeconds, intervalToDuration, add } from "date-
|
|||
|
||||
const isoDate = new Date(onlineTime);
|
||||
const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ');
|
||||
//console.log('sum new online time: ', newOnlinetime)
|
||||
|
||||
return newOnlinetime
|
||||
}
|
||||
|
|
|
@ -0,0 +1,389 @@
|
|||
|
||||
import Redis from 'ioredis'
|
||||
import { List } from 'whatsapp-web.js'
|
||||
const unflatten = require('flat').unflatten
|
||||
var flatten = require('flat')
|
||||
import ListTicketServiceCache from "../services/TicketServices/ListTicketServiceCache"
|
||||
|
||||
import { escapeCharCache } from './ContactsCache'
|
||||
|
||||
|
||||
const redisConn = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const redis = new Redis();
|
||||
|
||||
const conn = () => new Promise((resolve, reject) => {
|
||||
|
||||
redis.on('error', (err) => {
|
||||
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
console.error(`Redis connection error: ${err}.`)
|
||||
redis.quit()
|
||||
}
|
||||
else {
|
||||
console.error(`Redis encountered an error: ${err.message}.`)
|
||||
}
|
||||
|
||||
reject(err)
|
||||
|
||||
})
|
||||
|
||||
redis.on('connect', () => {
|
||||
|
||||
resolve(redis);
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
return await conn();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const flushCache = async () => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status === 'connect') {
|
||||
|
||||
console.log('TICKETS CACHE REMOVED')
|
||||
await redis.call('FLUSHALL')
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const cacheSize = async () => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status !== 'connect') {
|
||||
return -1
|
||||
}
|
||||
|
||||
const size = await redis.call('dbsize')
|
||||
redis.quit()
|
||||
return size
|
||||
|
||||
}
|
||||
|
||||
const loadTicketsCache = async () => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
await createTicketIndexCache('idx_ticket')
|
||||
|
||||
let tickets = await ListTicketServiceCache({})
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
|
||||
tickets[i].createdAt = new Date(tickets[i].createdAt).toISOString()
|
||||
tickets[i].updatedAt = new Date(tickets[i].updatedAt).toISOString()
|
||||
|
||||
tickets[i].escaped_name = escapeCharCache(tickets[i]['contact.name'])
|
||||
|
||||
// tickets[i]['contact_name'] = tickets[i]['contact.name']
|
||||
// delete tickets[i]['contact.name']
|
||||
|
||||
tickets[i]['contact_number'] = tickets[i]['contact.number']
|
||||
delete tickets[i]['contact.number']
|
||||
|
||||
pipeline.hmset(`ticket:${tickets[i].id}`, tickets[i]);
|
||||
}
|
||||
|
||||
await pipeline.exec(() => { console.log(`${tickets.length} TICKETS INSERTED IN CACHE!`) });
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
|
||||
const createTicketIndexCache = async (hashIndex: string) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
try {
|
||||
|
||||
const lst_index_redis: any = await redis.call('FT._LIST')
|
||||
|
||||
if (lst_index_redis.includes(hashIndex)) {
|
||||
console.log('entrou...')
|
||||
await redis.call('FT.DROPINDEX', hashIndex)
|
||||
}
|
||||
|
||||
const response = await redis.call('FT.CREATE', hashIndex, 'ON', 'HASH', 'PREFIX', '1', 'ticket:', 'SCHEMA', 'escaped_name', 'TEXT', 'SORTABLE', 'contact_number', 'TEXT', 'SORTABLE', 'status', 'TAG', 'SORTABLE')
|
||||
|
||||
console.log('Ticket index created: ', response)
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on createTicketIndexCache: ', error)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
}
|
||||
|
||||
const updateTicketCache = async (hash: any, json_object: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
let entries = Object.entries(json_object)
|
||||
|
||||
entries.forEach((e: any) => {
|
||||
pipeline.hset(hash, e[0], e[1])
|
||||
})
|
||||
|
||||
await pipeline.exec(() => { console.log("updateTicketCache Key/value inserted/updated") });
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
const updateTicketCacheByTicketId = async (ticketId: string | number, update_fields: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const ticket_cache = await redis.hgetall(`ticket:${ticketId}`)
|
||||
|
||||
try {
|
||||
if (ticket_cache && Object.keys(ticket_cache).length > 0) {
|
||||
|
||||
if (update_fields.escaped_name) {
|
||||
update_fields.escaped_name = escapeCharCache(update_fields['contact.name'])
|
||||
}
|
||||
|
||||
await updateTicketCache(`ticket:${ticketId}`, update_fields)
|
||||
|
||||
console.log(`updateTicketCacheByTicketId TICKET ${ticket_cache['contact_number']} CACHE WAS UPDATED!`)
|
||||
}
|
||||
else {
|
||||
console.log('TICKET CACHE NOT FOUND!')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`There was an error on updateTicketCacheByTicketId: ${error}`)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
const createOrUpdateTicketCache = async (hash: any, ticket: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
ticket.escaped_name = escapeCharCache(ticket['contact.name'])
|
||||
|
||||
ticket['contact_number'] = ticket['contact.number']
|
||||
delete ticket['contact.number']
|
||||
|
||||
await redis.hmset(hash, ticket);
|
||||
|
||||
console.log('CREATED/UPDATED TICKET CACHE')
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
const deleteTicketsByIdCache = async (ticketId: string | number) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const ticket_cache = await redis.hgetall(`ticket:${ticketId}`)
|
||||
|
||||
try {
|
||||
if (ticket_cache && Object.keys(ticket_cache).length > 0) {
|
||||
|
||||
await redis.del(`ticket:${ticketId}`)
|
||||
|
||||
console.log(`TICKET ${ticket_cache['id']} CACHE WAS DELETED!`)
|
||||
}
|
||||
else {
|
||||
console.log('TICKET CACHE NOT FOUND!')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`There was an error on deleteTicketsByIdCache: ${error}`)
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
const deleteTicketsFieldsCache = async (tickets: any, del_fields: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
if (tickets && tickets.length > 0) {
|
||||
try {
|
||||
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
|
||||
pipeline.hdel(`ticket:${tickets[i]['id']}`, del_fields)
|
||||
|
||||
}
|
||||
|
||||
await pipeline.exec(() => { console.log(`Tickets cache contact updated!`) })
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on deleteTicketsFieldsByContactsCache function: ', error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
|
||||
const updateTicketsByContactsCache = async (oldNumber: string, newName: string, newNumber: string) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
const tickets = await searchTicketCache(oldNumber)
|
||||
|
||||
if (tickets && tickets.length > 0) {
|
||||
try {
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
|
||||
tickets[i]['contact.name'] = newName
|
||||
tickets[i].escaped_name = escapeCharCache(newName)
|
||||
tickets[i]['contact_number'] = newNumber
|
||||
|
||||
pipeline.hmset(`ticket:${tickets[i]['id']}`, tickets[i])
|
||||
|
||||
}
|
||||
|
||||
await pipeline.exec(() => { console.log(`updateTicketsByContactsCache Tickets cache contact updated!`) })
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on updateTicketsByContactsCache function: ', error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
|
||||
const deleteTicketsByContactsCache = async (number: string) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
const pipeline = redis.pipeline()
|
||||
|
||||
const tickets = await searchTicketCache(number)
|
||||
|
||||
if (tickets && tickets.length > 0) {
|
||||
try {
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
|
||||
pipeline.del(`ticket:${tickets[i]['id']}`)
|
||||
|
||||
}
|
||||
|
||||
await pipeline.exec(() => { console.log(`Tickets cache number ${tickets[0]['contact_number']} deleted!`) })
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on deleteTicketsByContactsCache function: ', error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
const deleteTicketCache = async (hash: any) => {
|
||||
|
||||
const redis: any = await redisConn();
|
||||
if (redis.status !== 'connect') return
|
||||
|
||||
await redis.del(hash)
|
||||
redis.quit()
|
||||
|
||||
}
|
||||
|
||||
async function searchTicketCache(search: string, offset?: number, limit?: number) {
|
||||
|
||||
const redis:any = await redisConn();
|
||||
|
||||
if(redis.status!=='connect') return null
|
||||
|
||||
search = escapeCharCache(search)
|
||||
|
||||
let response: any = undefined
|
||||
|
||||
if (offset != undefined && limit != undefined) {
|
||||
response = await redis.call('FT.SEARCH', 'idx_ticket', `(@escaped_name:*${search}*)|(@contact_number:*${search}*)`, 'LIMIT', offset, limit, 'SORTBY', 'status', 'DESC')
|
||||
}
|
||||
else {
|
||||
response = await redis.call('FT.SEARCH', 'idx_ticket', `(@escaped_name:*${search}*)|(@contact_number:*${search}*)`)
|
||||
}
|
||||
redis.quit()
|
||||
|
||||
// console.log('response: ', response)
|
||||
|
||||
if (response.length === 1) {
|
||||
return []
|
||||
}
|
||||
|
||||
const results: any = []
|
||||
|
||||
for (let n = 2; n < response.length; n += 2) {
|
||||
const result: any = {}
|
||||
const fieldNamesAndValues = response[n]
|
||||
|
||||
for (let m = 0; m < fieldNamesAndValues.length; m += 2) {
|
||||
const k = fieldNamesAndValues[m]
|
||||
const v = fieldNamesAndValues[m + 1]
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
results.push(result)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
export {
|
||||
loadTicketsCache,
|
||||
updateTicketCache,
|
||||
createOrUpdateTicketCache,
|
||||
searchTicketCache,
|
||||
updateTicketCacheByTicketId,
|
||||
deleteTicketsByContactsCache,
|
||||
updateTicketsByContactsCache,
|
||||
deleteTicketsByIdCache,
|
||||
flushCache,
|
||||
deleteTicketsFieldsCache,
|
||||
cacheSize,
|
||||
redisConn
|
||||
}
|
|
@ -5,12 +5,12 @@ const UpdateDeletedUserOpenTicketsStatus = async (
|
|||
tickets: Ticket[]
|
||||
): Promise<void> => {
|
||||
tickets.forEach(async t => {
|
||||
|
||||
const ticketId = t.id.toString();
|
||||
|
||||
await UpdateTicketService({
|
||||
ticketData: { status: "pending" },
|
||||
ticketId
|
||||
});
|
||||
await UpdateTicketService({ ticketData: { status: "pending" }, ticketId });
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ const monitor = async () => {
|
|||
|
||||
|
||||
if (indexAux == -1) {
|
||||
console.log(' entrou indexAux: ', indexAux)
|
||||
|
||||
const userOnline = await createOrUpdateOnlineUserService({ userId: el.id, status: 'online' })
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
listOnlineAux.push({ 'id': userId })
|
||||
}
|
||||
else {
|
||||
console.log(' -------------- PULO FORA')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -37,9 +37,7 @@ class Message extends Model<Message> {
|
|||
@Column(DataType.STRING)
|
||||
get mediaUrl(): string | null {
|
||||
if (this.getDataValue("mediaUrl")) {
|
||||
return `${process.env.BACKEND_URL}:${
|
||||
process.env.PROXY_PORT
|
||||
}/public/${this.getDataValue("mediaUrl")}`;
|
||||
return `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${this.getDataValue("mediaUrl")}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import * as TicketController from "../controllers/TicketController";
|
|||
const ticketRoutes = express.Router();
|
||||
|
||||
|
||||
// ticketRoutes.get("/tickets/cache", isAuth, TicketController.ticketsCache);
|
||||
|
||||
ticketRoutes.get("/tickets/count", isAuth, TicketController.count);
|
||||
|
||||
ticketRoutes.get("/tickets", isAuth, TicketController.index);
|
||||
|
|
|
@ -7,6 +7,9 @@ import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhats
|
|||
import { startSchedulingMonitor } from "./helpers/SchedulingNotifySendMessage"
|
||||
import { startWhoIsOnlineMonitor } from "./helpers/WhoIsOnlineMonitor"
|
||||
|
||||
import { loadTicketsCache, flushCache, cacheSize } from './helpers/TicketCache'
|
||||
import { loadContactsCache } from './helpers/ContactsCache'
|
||||
|
||||
const server = app.listen(process.env.PORT, () => {
|
||||
logger.info(`Server started on port: ${process.env.PORT}`);
|
||||
});
|
||||
|
@ -15,5 +18,20 @@ initIO(server);
|
|||
StartAllWhatsAppsSessions();
|
||||
gracefulShutdown(server);
|
||||
|
||||
(async()=>{
|
||||
|
||||
const cacheLength = await cacheSize()
|
||||
|
||||
if(cacheLength == 0){
|
||||
console.log('Loading from cache...')
|
||||
await flushCache()
|
||||
await loadContactsCache()
|
||||
await loadTicketsCache()
|
||||
}
|
||||
|
||||
})()
|
||||
|
||||
|
||||
startSchedulingMonitor(5000)
|
||||
startWhoIsOnlineMonitor(50000)
|
||||
startWhoIsOnlineMonitor(3000)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import AppError from "../../errors/AppError";
|
||||
import Contact from "../../models/Contact";
|
||||
|
||||
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
|
||||
|
||||
interface ExtraInfo {
|
||||
name: string;
|
||||
value: string;
|
||||
|
@ -40,6 +42,12 @@ const CreateContactService = async ({
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
// TEST DEL
|
||||
await createOrUpdateContactCache(`contact:${contact.id}`, {id: contact.id, name, number, profilePicUrl:'', isGroup:'false', extraInfo, email })
|
||||
//
|
||||
|
||||
|
||||
return contact;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { getIO } from "../../libs/socket";
|
||||
import Contact from "../../models/Contact";
|
||||
|
||||
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
|
||||
|
||||
interface ExtraInfo {
|
||||
name: string;
|
||||
value: string;
|
||||
|
@ -28,11 +30,16 @@ const CreateOrUpdateContactService = async ({
|
|||
const io = getIO();
|
||||
let contact: Contact | null;
|
||||
|
||||
|
||||
contact = await Contact.findOne({ where: { number } });
|
||||
|
||||
if (contact) {
|
||||
contact.update({ profilePicUrl });
|
||||
|
||||
// TEST DEL
|
||||
await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl })
|
||||
//
|
||||
|
||||
io.emit("contact", {
|
||||
action: "update",
|
||||
contact
|
||||
|
@ -47,6 +54,11 @@ const CreateOrUpdateContactService = async ({
|
|||
extraInfo
|
||||
});
|
||||
|
||||
// TEST DEL
|
||||
await createOrUpdateContactCache(`contact:${contact.id}`, {id: contact.id, name, number, profilePicUrl, isGroup, extraInfo, email })
|
||||
//
|
||||
|
||||
|
||||
io.emit("contact", {
|
||||
action: "create",
|
||||
contact
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import Contact from "../../models/Contact";
|
||||
import AppError from "../../errors/AppError";
|
||||
|
||||
import { deleteTicketsByContactsCache } from '../../helpers/TicketCache'
|
||||
import {deleteContactsByIdCache} from '../../helpers/ContactsCache'
|
||||
|
||||
const DeleteContactService = async (id: string): Promise<void> => {
|
||||
const contact = await Contact.findOne({
|
||||
where: { id }
|
||||
|
@ -10,6 +13,11 @@ const DeleteContactService = async (id: string): Promise<void> => {
|
|||
throw new AppError("ERR_NO_CONTACT_FOUND", 404);
|
||||
}
|
||||
|
||||
// TEST DEL
|
||||
await deleteTicketsByContactsCache(contact.number)
|
||||
await deleteContactsByIdCache(contact.id)
|
||||
//
|
||||
|
||||
await contact.destroy();
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { Sequelize, Op } from "sequelize";
|
||||
import Contact from "../../models/Contact";
|
||||
|
||||
const ListContactsServiceCache = async (): Promise<any> => {
|
||||
|
||||
const contacts = await Contact.findAll({ where: {}, raw:true, order: [["name", "ASC"]] });
|
||||
|
||||
return contacts
|
||||
};
|
||||
|
||||
export default ListContactsServiceCache;
|
|
@ -2,6 +2,9 @@ import AppError from "../../errors/AppError";
|
|||
import Contact from "../../models/Contact";
|
||||
import ContactCustomField from "../../models/ContactCustomField";
|
||||
|
||||
import { updateTicketsByContactsCache } from '../../helpers/TicketCache'
|
||||
import { updateContactCacheById } from '../../helpers/ContactsCache'
|
||||
|
||||
interface ExtraInfo {
|
||||
id?: number;
|
||||
name: string;
|
||||
|
@ -19,6 +22,7 @@ interface Request {
|
|||
contactId: string;
|
||||
}
|
||||
|
||||
|
||||
const UpdateContactService = async ({
|
||||
contactData,
|
||||
contactId
|
||||
|
@ -53,17 +57,29 @@ const UpdateContactService = async ({
|
|||
);
|
||||
}
|
||||
|
||||
const oldNumber = contact.number
|
||||
|
||||
await contact.update({
|
||||
name,
|
||||
number,
|
||||
email
|
||||
});
|
||||
|
||||
//TEST DEL
|
||||
await updateTicketsByContactsCache(oldNumber, contact.name, contact.number)
|
||||
//
|
||||
|
||||
|
||||
await contact.reload({
|
||||
attributes: ["id", "name", "number", "email", "profilePicUrl"],
|
||||
include: ["extraInfo"]
|
||||
});
|
||||
|
||||
|
||||
|
||||
// console.log('contactcontactcontactcontact: ',flatten(JSON.parse(JSON.stringify(contact))))
|
||||
await updateContactCacheById(contact.id, JSON.parse(JSON.stringify(contact)))
|
||||
|
||||
return contact;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { updateTicketCacheByTicketId } from "../../helpers/TicketCache";
|
||||
import { getIO } from "../../libs/socket";
|
||||
import Message from "../../models/Message";
|
||||
import Ticket from "../../models/Ticket";
|
||||
|
@ -16,7 +17,7 @@ interface Request {
|
|||
messageData: MessageData;
|
||||
}
|
||||
|
||||
const CreateMessageService = async ({messageData}: Request): Promise<Message> => {
|
||||
const CreateMessageService = async ({ messageData }: Request): Promise<Message> => {
|
||||
await Message.upsert(messageData);
|
||||
|
||||
const message = await Message.findByPk(messageData.id, {
|
||||
|
@ -40,8 +41,19 @@ const CreateMessageService = async ({messageData}: Request): Promise<Message> =>
|
|||
}
|
||||
|
||||
|
||||
if (message.ticket.status != 'queueChoice') {
|
||||
|
||||
|
||||
// TEST DEL
|
||||
await updateTicketCacheByTicketId(message.ticket.id,
|
||||
{
|
||||
lastMessage: message.body,
|
||||
updatedAt: new Date(message.ticket.updatedAt).toISOString(),
|
||||
'contact.profilePicUrl': message.ticket.contact.profilePicUrl,
|
||||
unreadMessages: message.ticket.unreadMessages
|
||||
})
|
||||
//
|
||||
|
||||
if(message.ticket.status!='queueChoice'){
|
||||
|
||||
const io = getIO();
|
||||
io.to(message.ticketId.toString())
|
||||
|
|
|
@ -2,13 +2,30 @@ import ShowQueueService from "./ShowQueueService";
|
|||
|
||||
import UserQueue from "../../models/UserQueue";
|
||||
|
||||
import ListTicketsServiceCache from "../TicketServices/ListTicketServiceCache";
|
||||
|
||||
import { deleteTicketsFieldsCache } from '../../helpers/TicketCache'
|
||||
|
||||
const DeleteQueueService = async (queueId: number | string): Promise<void> => {
|
||||
|
||||
const queue = await ShowQueueService(queueId);
|
||||
|
||||
if (queue.id) {
|
||||
|
||||
const tickets = await ListTicketsServiceCache({ queueId })
|
||||
|
||||
await deleteTicketsFieldsCache(tickets, ['queue.id', 'queue.name', 'queue.color'])
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
await UserQueue.destroy({ where: {queueId: queueId } });
|
||||
|
||||
await UserQueue.destroy({ where: { queueId: queueId } });
|
||||
|
||||
} catch (error) {
|
||||
console.log('Error on delete UserQueue by queueId: ',queueId)
|
||||
|
||||
console.log('Error on delete UserQueue by queueId: ', queueId)
|
||||
|
||||
}
|
||||
|
||||
await queue.destroy();
|
||||
|
|
|
@ -25,8 +25,6 @@ const CreateSchedulingNotifyService = async ({
|
|||
|
||||
if(schedulingNotifyId){
|
||||
|
||||
console.log('000000000000000000000000000 ATUALIZOU!')
|
||||
|
||||
schedulingNotify = await SchedulingNotify.findOne({ where: { id: schedulingNotifyId } });
|
||||
|
||||
if(schedulingNotify){
|
||||
|
@ -49,8 +47,6 @@ const CreateSchedulingNotifyService = async ({
|
|||
|
||||
if(!schedulingNotify){
|
||||
|
||||
console.log('111111111111111111111111111 criou!')
|
||||
|
||||
schedulingNotify = await SchedulingNotify.create(
|
||||
{
|
||||
ticketId,
|
||||
|
|
|
@ -13,6 +13,11 @@ import ptBR from 'date-fns/locale/pt-BR';
|
|||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
||||
import TicketEmiterSumOpenClosedByUser from "../../helpers/OnlineReporEmiterInfoByUser";
|
||||
|
||||
import { createOrUpdateTicketCache } from '../../helpers/TicketCache'
|
||||
let flatten = require('flat')
|
||||
|
||||
|
||||
|
||||
interface Request {
|
||||
contactId: number;
|
||||
status: string;
|
||||
|
@ -43,15 +48,28 @@ const CreateTicketService = async ({
|
|||
throw new AppError("ERR_CREATING_TICKET");
|
||||
}
|
||||
|
||||
// console.log('CONTACT ticket.id: ', ticket.id)
|
||||
|
||||
|
||||
// TEST DEL
|
||||
try {
|
||||
|
||||
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']
|
||||
|
||||
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 from user: ', error)
|
||||
}
|
||||
//
|
||||
|
||||
//test del
|
||||
// 2022-05-11T05:20:33.000Z,
|
||||
// const dateToday = ticket.createdAt.toISOString().split('T')[0]
|
||||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
//openByUser : [ { id: 13, status: 'online' } ]
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
const io = getIO();
|
||||
|
@ -61,9 +79,6 @@ const CreateTicketService = async ({
|
|||
});
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import Ticket from "../../models/Ticket";
|
||||
import AppError from "../../errors/AppError";
|
||||
|
||||
import { deleteTicketsByIdCache } from '../../helpers/TicketCache'
|
||||
|
||||
const DeleteTicketService = async (id: string): Promise<Ticket> => {
|
||||
const ticket = await Ticket.findOne({
|
||||
where: { id }
|
||||
|
@ -12,6 +14,10 @@ const DeleteTicketService = async (id: string): Promise<Ticket> => {
|
|||
|
||||
await ticket.destroy();
|
||||
|
||||
// TEST DEL
|
||||
await deleteTicketsByIdCache(id)
|
||||
//
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
|||
import ShowTicketService from "./ShowTicketService";
|
||||
|
||||
|
||||
|
||||
|
||||
const FindOrCreateTicketService = async (
|
||||
contact: Contact,
|
||||
whatsappId: number,
|
||||
|
@ -29,7 +27,7 @@ const FindOrCreateTicketService = async (
|
|||
|
||||
//Habilitar esse caso queira usar o bot
|
||||
// const botInfo = await BotIsOnQueue('botqueue')
|
||||
const botInfo = {isOnQueue: false}
|
||||
const botInfo = { isOnQueue: false }
|
||||
|
||||
|
||||
|
||||
|
@ -89,7 +87,7 @@ const FindOrCreateTicketService = async (
|
|||
|
||||
let status = "pending"
|
||||
|
||||
if(queues.length > 1 && !botInfo.isOnQueue){
|
||||
if (queues.length > 1 && !botInfo.isOnQueue) {
|
||||
status = "queueChoice"
|
||||
}
|
||||
|
||||
|
@ -100,10 +98,18 @@ const FindOrCreateTicketService = async (
|
|||
unreadMessages,
|
||||
whatsappId
|
||||
});
|
||||
|
||||
// TEST DEL
|
||||
|
||||
// const { name } = await ShowContactService(contact.id);
|
||||
// console.log('FIND OR CREATE TICKET SERVICE NAME: ', contact.name, ' STATUS: ', status)
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
ticket = await ShowTicketService(ticket.id);
|
||||
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,25 @@ import Contact from "../../models/Contact";
|
|||
import Queue from "../../models/Queue";
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
const ListTicketsServiceCache = async (status?: string, date?: string): Promise<any> => {
|
||||
|
||||
interface Request {
|
||||
status?: string;
|
||||
date?: string;
|
||||
userId?: string | number;
|
||||
queueId?: string | number
|
||||
}
|
||||
|
||||
const ListTicketsServiceCache = async ({
|
||||
status,
|
||||
date,
|
||||
userId,
|
||||
queueId
|
||||
}:Request): Promise<any> => {
|
||||
|
||||
let where_clause = {}
|
||||
|
||||
console.log(' QUEUE ID: ', queueId)
|
||||
|
||||
if (date) {
|
||||
where_clause = {
|
||||
createdAt: {
|
||||
|
@ -23,6 +38,19 @@ const ListTicketsServiceCache = async (status?: string, date?: string): Promise<
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(queueId){
|
||||
|
||||
|
||||
where_clause = {
|
||||
queueId: queueId
|
||||
}
|
||||
}
|
||||
else if(userId){
|
||||
|
||||
where_clause = {
|
||||
userId: userId
|
||||
}
|
||||
}
|
||||
else {
|
||||
// where_clause = {
|
||||
// createdAt: {
|
||||
|
|
|
@ -8,11 +8,17 @@ import Message from "../../models/Message";
|
|||
import Queue from "../../models/Queue";
|
||||
import ShowUserService from "../UserServices/ShowUserService";
|
||||
|
||||
const unflatten = require('flat').unflatten
|
||||
|
||||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
import ListTicketServiceCache from "./ListTicketServiceCache"
|
||||
|
||||
import { searchTicketCache, loadTicketsCache } from '../../helpers/TicketCache'
|
||||
|
||||
|
||||
|
||||
|
||||
interface Request {
|
||||
searchParam?: string;
|
||||
|
@ -32,6 +38,7 @@ interface Response {
|
|||
hasMore: boolean;
|
||||
}
|
||||
|
||||
|
||||
const ListTicketsService = async ({
|
||||
searchParam = "",
|
||||
pageNumber = "1",
|
||||
|
@ -43,18 +50,49 @@ const ListTicketsService = async ({
|
|||
withUnreadMessages,
|
||||
unlimited = 'false'
|
||||
}: Request): Promise<Response> => {
|
||||
let whereCondition: Filterable["where"] = {
|
||||
[Op.or]: [{ userId }, { status: "pending" }],
|
||||
queueId: { [Op.or]: [queueIds, null] }
|
||||
};
|
||||
|
||||
let whereCondition: Filterable["where"] = { [Op.or]: [{ userId }, { status: "pending" }], queueId: { [Op.or]: [queueIds, null] } };
|
||||
|
||||
if (searchParam && searchParam.trim().length > 0) {
|
||||
|
||||
try {
|
||||
|
||||
const offset = 40 * (+pageNumber - 1);
|
||||
|
||||
console.log('QUERY TICKET SEARCH PARAM FROM CACHE: ', searchParam)
|
||||
|
||||
let tickets: any = await searchTicketCache(searchParam, offset, 40);
|
||||
|
||||
if (tickets) {
|
||||
console.log('QUERY TICKET SEARCH PARAM FROM CACHE LENGTH...: ', tickets.length)
|
||||
|
||||
tickets.map((t: any) => {
|
||||
|
||||
t['contact.number'] = t['contact_number']
|
||||
delete t['contact_number']
|
||||
|
||||
return { ...['contact_number'] }
|
||||
})
|
||||
|
||||
tickets = tickets.map((e: any) => unflatten(e))
|
||||
|
||||
return { tickets, count: tickets.length, hasMore: tickets.length > 0 ? true : false };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on search ListTicketservice.ts search cache: ', error)
|
||||
}
|
||||
|
||||
console.log('QUERY TICKETS FROM DATABASE...')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let includeCondition: Includeable[];
|
||||
|
||||
|
||||
// test del
|
||||
// const test = await ListTicketServiceCache()
|
||||
// console.log('TEST:\n', test)
|
||||
//
|
||||
|
||||
|
||||
includeCondition = [
|
||||
{
|
||||
|
@ -77,7 +115,6 @@ const ListTicketsService = async ({
|
|||
|
||||
whereCondition = { ...whereCondition, status };
|
||||
|
||||
// console.log('TEST unlimited: ', unlimited)
|
||||
|
||||
if (unlimited === 'true' && status !== 'pending') {
|
||||
|
||||
|
@ -95,10 +132,6 @@ const ListTicketsService = async ({
|
|||
if (searchParam) {
|
||||
const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
|
||||
|
||||
//othavio
|
||||
|
||||
console.log('sanitizedSearchParam:'+ sanitizedSearchParam, ' | date: ',date)
|
||||
|
||||
// includeCondition = [
|
||||
// ...includeCondition,
|
||||
// {
|
||||
|
@ -152,7 +185,8 @@ const ListTicketsService = async ({
|
|||
const offset = limit * (+pageNumber - 1);
|
||||
|
||||
|
||||
// console.log('whereCondition: ', JSON.stringify(whereCondition))
|
||||
|
||||
console.log('ENTROU NO LIST TICKET SERVICE')
|
||||
|
||||
const { count, rows: tickets } = await Ticket.findAndCountAll({
|
||||
where: whereCondition,
|
||||
|
|
|
@ -6,6 +6,11 @@ import SendWhatsAppMessage from "../WbotServices/SendWhatsAppMessage";
|
|||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||
import ShowTicketService from "./ShowTicketService";
|
||||
|
||||
import { createOrUpdateTicketCache } from '../../helpers/TicketCache'
|
||||
var flatten = require('flat')
|
||||
|
||||
|
||||
|
||||
interface TicketData {
|
||||
status?: string;
|
||||
userId?: number;
|
||||
|
@ -47,10 +52,27 @@ const UpdateTicketService = async ({
|
|||
statusChatEnd
|
||||
});
|
||||
|
||||
|
||||
|
||||
await ticket.reload();
|
||||
|
||||
// TEST DEL
|
||||
try {
|
||||
|
||||
// const { name, number } = await ShowContactService(ticket.contactId)
|
||||
|
||||
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']
|
||||
|
||||
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)
|
||||
}
|
||||
//
|
||||
|
||||
let io = getIO();
|
||||
|
||||
if (ticket.status !== oldStatus || ticket.user?.id !== oldUserId) {
|
||||
|
|
|
@ -37,12 +37,12 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
|
||||
|
||||
const io = getIO();
|
||||
let userOnlineTime:any = null;
|
||||
let userOnlineTime: any = null;
|
||||
|
||||
const user = await User.findOne({ where: { id: userId } });
|
||||
|
||||
if (!user) {
|
||||
console.log(' yyyyyyyyyyyyyyyyyyyyyyyyyy não tem mais esse usuario id: ', userId)
|
||||
|
||||
return userOnlineTime
|
||||
}
|
||||
|
||||
|
@ -68,14 +68,14 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
let oldStatus = userOnlineTime.status
|
||||
|
||||
|
||||
console.log('>>>>>>>>> oldStatus: ', oldStatus, ' | new status', status)
|
||||
|
||||
|
||||
if (oldStatus == 'online' && status === 'offline') {
|
||||
//updatedAt
|
||||
let newtTime = intervalToDuration({ start: userOnlineTime.updatedAt, end: new Date() })
|
||||
console.log('TESTANDO INTERVAL DURATION: ', newtTime)
|
||||
|
||||
console.log('hours: ', newtTime.hours, ' | minutes: ', newtTime.minutes, ' | seconds: ', newtTime.seconds)
|
||||
|
||||
|
||||
|
||||
let onlineTime = new Date()
|
||||
|
||||
|
@ -83,12 +83,6 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
onlineTime.setUTCMinutes(userOnlineTime.onlineTime.getMinutes())
|
||||
onlineTime.setUTCSeconds(userOnlineTime.onlineTime.getSeconds())
|
||||
|
||||
console.log('userOnlineTime.onlineTime: ', userOnlineTime.onlineTime)
|
||||
console.log('userOnlineTime.onlineTime.getHours(): ', userOnlineTime.onlineTime.getHours())
|
||||
console.log('userOnlineTime.onlineTime.getMinutes(): ', userOnlineTime.onlineTime.getMinutes())
|
||||
console.log('userOnlineTime.onlineTime.getSeconds(): ', userOnlineTime.onlineTime.getSeconds())
|
||||
|
||||
console.log('online time 3: ', onlineTime)
|
||||
|
||||
|
||||
if (newtTime.hours && +newtTime.hours > 0) {
|
||||
|
@ -101,11 +95,11 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
onlineTime = addSeconds(onlineTime, newtTime.seconds)
|
||||
}
|
||||
|
||||
console.log('online time 4: ', onlineTime)
|
||||
|
||||
|
||||
const isoDate = new Date(onlineTime);
|
||||
const mySQLDateString = isoDate.toJSON().slice(0, 19).replace('T', ' ');
|
||||
console.log('mySQLDateString: ', mySQLDateString)
|
||||
|
||||
|
||||
await userOnlineTime.update({ status, onlineTime: mySQLDateString })
|
||||
|
||||
|
@ -114,8 +108,8 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
const updatedAtString = formatDateTimeString(userOnlineTime.updatedAt)
|
||||
const createdAtString = formatDateTimeString(userOnlineTime.createdAt)
|
||||
|
||||
console.log('CreatedAt string: ', createdAtString)
|
||||
console.log('UpdatedAt string: ', updatedAtString)
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
|
|
@ -106,10 +106,6 @@ const ShowUserServiceReport = async ({
|
|||
}
|
||||
|
||||
|
||||
// console.log('>>>>>>>>>>>>>> objQuery: ', objQuery)
|
||||
|
||||
|
||||
|
||||
if (!objQuery) {
|
||||
throw new AppError("ERR_NO_OBJ_QUERY_FOUND", 404);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import { getWbot } from "../../libs/wbot";
|
|||
import Contact from "../../models/Contact";
|
||||
import { logger } from "../../utils/logger";
|
||||
|
||||
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
|
||||
|
||||
const ImportContactsService = async (): Promise<void> => {
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||
|
||||
|
@ -32,7 +34,16 @@ const ImportContactsService = async (): Promise<void> => {
|
|||
|
||||
if (numberExists) return null;
|
||||
|
||||
return Contact.create({ number, name });
|
||||
let contact = await Contact.create({ number, name });
|
||||
|
||||
// await contact.reload()
|
||||
|
||||
// TEST DEL
|
||||
await createOrUpdateContactCache(`contact:${contact.id}`, {id:contact.id, name, number, profilePicUrl: contact.profilePicUrl, isGroup: contact.isGroup, extraInfo: '', email:'' })
|
||||
//
|
||||
|
||||
// return Contact.create({ number, name });
|
||||
return contact
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ import AppError from "../../errors/AppError";
|
|||
import GetTicketWbot from "../../helpers/GetTicketWbot";
|
||||
import Ticket from "../../models/Ticket";
|
||||
|
||||
import { updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
||||
import { date } from "faker";
|
||||
|
||||
interface Request {
|
||||
media: Express.Multer.File;
|
||||
ticket: Ticket;
|
||||
|
@ -22,6 +25,10 @@ const SendWhatsAppMedia = async ({
|
|||
|
||||
await ticket.update({ lastMessage: media.filename });
|
||||
|
||||
// TEST DEL
|
||||
await updateTicketCacheByTicketId(ticket.id, { lastMessage: media.filename, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||
//
|
||||
|
||||
fs.unlinkSync(media.path);
|
||||
|
||||
return sentMessage;
|
||||
|
|
|
@ -11,6 +11,7 @@ import wbotByUserQueue from '../../helpers/GetWbotByUserQueue'
|
|||
|
||||
import { WhatsIndex } from "../../helpers/LoadBalanceWhatsSameQueue";
|
||||
|
||||
import { updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
||||
|
||||
interface Request {
|
||||
body: string;
|
||||
|
@ -61,6 +62,12 @@ const SendWhatsAppMessage = async ({
|
|||
try {
|
||||
const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, body, { quotedMessageId: quotedMsgSerializedId, linkPreview: false });
|
||||
await ticket.update({ lastMessage: body });
|
||||
|
||||
|
||||
// TEST DEL
|
||||
await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||
//
|
||||
|
||||
return sentMessage;
|
||||
} catch (err) {
|
||||
throw new AppError("ERR_SENDING_WAPP_MSG");
|
||||
|
|
|
@ -10,6 +10,8 @@ import path from 'path';
|
|||
import { format } from "date-fns";
|
||||
import ptBR from 'date-fns/locale/pt-BR';
|
||||
|
||||
|
||||
|
||||
import {
|
||||
Contact as WbotContact,
|
||||
Message as WbotMessage,
|
||||
|
@ -51,6 +53,8 @@ import Whatsapp from "../../models/Whatsapp";
|
|||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
||||
//
|
||||
|
||||
import { updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
||||
|
||||
|
||||
|
||||
interface Session extends Client {
|
||||
|
@ -159,6 +163,10 @@ const verifyMessage = async (
|
|||
|
||||
await ticket.update({ lastMessage: msg.body });
|
||||
|
||||
// TEST DEL
|
||||
// await updateTicketCacheByTicketId(ticket.id, { lastMessage: msg.body, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||
//
|
||||
|
||||
await CreateMessageService({ messageData });
|
||||
};
|
||||
|
||||
|
@ -255,7 +263,8 @@ const verifyQueue = async (
|
|||
const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
|
||||
|
||||
await verifyMessage(sentMessage, ticket, contact);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
//test del transfere o atendimento se entrar na ura infinita
|
||||
|
@ -288,8 +297,7 @@ const verifyQueue = async (
|
|||
|
||||
}
|
||||
|
||||
//console.log('TICKET MESSAGE ON QUEUE CHOICE: ', ticket_message)
|
||||
//
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
@ -378,7 +386,7 @@ const handleMessage = async (
|
|||
|
||||
msgContact = await msg.getContact();
|
||||
|
||||
// console.log('-----msgContact TESTE MSG2: ', msgContact, ' | msg: ', msg)
|
||||
//
|
||||
|
||||
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
|
||||
Parcial msg and msgContact info:
|
||||
|
@ -415,6 +423,7 @@ const handleMessage = async (
|
|||
const contact = await verifyContact(msgContact);
|
||||
|
||||
|
||||
|
||||
if (unreadMessages === 0 && whatsapp.farewellMessage && whatsapp.farewellMessage === msg.body) return;
|
||||
|
||||
const ticket = await FindOrCreateTicketService(
|
||||
|
@ -424,10 +433,13 @@ const handleMessage = async (
|
|||
groupContact
|
||||
);
|
||||
|
||||
//
|
||||
// await updateTicketCacheByTicketId(ticket.id, {'contact.profilePicUrl': ticket.contact.profilePicUrl})
|
||||
|
||||
// Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen
|
||||
if (wbot.id != ticket.whatsappId) {
|
||||
|
||||
console.log('>>> entrou wbot.id: ', wbot.id, ' | ', ticket.whatsappId)
|
||||
|
||||
|
||||
await ticket.update({ whatsappId: wbot.id });
|
||||
}
|
||||
|
@ -495,7 +507,7 @@ const handleMessage = async (
|
|||
opt_user_attendant = data_ura[indexAttendant].id
|
||||
}
|
||||
|
||||
// console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ indexAttendant: ',indexAttendant, ' | opt_user_attendant: ', opt_user_attendant)
|
||||
//
|
||||
|
||||
let ticket_message = await ShowTicketMessage(ticket.id, true, ura_length, `^[0-${ura_length}}]$`);
|
||||
|
||||
|
@ -529,9 +541,9 @@ const handleMessage = async (
|
|||
|
||||
|
||||
|
||||
// console.log('----------------- ticket_message: ', ticket_message)
|
||||
//
|
||||
|
||||
//console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ MSG.BODY: ', msg.body , ' | opt_user_attendant: ',opt_user_attendant, ' | lastOption: ', lastOption)
|
||||
//
|
||||
|
||||
// È numero
|
||||
if (!Number.isNaN(Number(msg.body.trim())) && (+msg.body >= 0 && +msg.body <= data_ura.length)) {
|
||||
|
@ -546,7 +558,7 @@ const handleMessage = async (
|
|||
|
||||
|
||||
|
||||
console.log('TICKET MESSAGE: ', ticket_message)
|
||||
|
||||
|
||||
// test del
|
||||
let next = true
|
||||
|
@ -780,7 +792,7 @@ const handleMessage = async (
|
|||
|
||||
if (whatsapp.status == 'CONNECTED') {
|
||||
|
||||
console.log('wbotMessageListener.ts - ENTROU NO RESTORE...')
|
||||
|
||||
|
||||
let timestamp = Math.floor(Date.now() / 1000)
|
||||
|
||||
|
@ -789,7 +801,7 @@ const handleMessage = async (
|
|||
|
||||
await restartWhatsSession(whatsapp)
|
||||
|
||||
console.log('...PASSOU O RESTORE - wbotMessageListener.ts ')
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import "react-toastify/dist/ReactToastify.css";
|
|||
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
|
||||
import { ptBR } from "@material-ui/core/locale";
|
||||
|
||||
import { TabTicketProvider } from "../src/context/TabTicketHeaderOption/TabTicketHeaderOption";
|
||||
|
||||
const App = () => {
|
||||
const [locale, setLocale] = useState();
|
||||
|
||||
|
@ -41,7 +43,13 @@ const App = () => {
|
|||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
|
||||
{/*TabTicketProvider Context to manipulate the entire state of selected option from user click on tickets options header */}
|
||||
<TabTicketProvider>
|
||||
<Routes />
|
||||
</TabTicketProvider>
|
||||
|
||||
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -165,7 +165,7 @@ const Modal = (props) => {
|
|||
|
||||
// Get from child 2
|
||||
const datePickerValue = (data) => {
|
||||
console.log('datePickerValue: ', (data));
|
||||
|
||||
setDatePicker(data)
|
||||
|
||||
|
||||
|
@ -173,7 +173,7 @@ const Modal = (props) => {
|
|||
|
||||
// Get from child 3
|
||||
const timerPickerValue = (data) => {
|
||||
console.log('timerPickerValue: ', (data));
|
||||
|
||||
setTimerPicker(data)
|
||||
|
||||
|
||||
|
@ -207,7 +207,7 @@ const Modal = (props) => {
|
|||
|
||||
if (statusChatEndId === '2' || statusChatEndId === '3') {
|
||||
|
||||
console.log('Entrou! textArea1: ', textArea1)
|
||||
|
||||
|
||||
if (startDate.trim().length === 0) {
|
||||
|
||||
|
@ -255,18 +255,18 @@ const Modal = (props) => {
|
|||
let sendMessageDayBefore = currenciesTimeBefore.filter(i => i.label.indexOf('24 HORAS ANTES DO HORÁRIO DO AGENDAMENTO') >= 0);
|
||||
|
||||
if (sendMessageDayBefore.length > 0 && timeBefore === formatedTimeHour(timerPicker)) {
|
||||
console.log('ENVIAR MENSAGEM UM DIA ANTES!')
|
||||
console.log('MENSAGEM SERÁ ENVIA NO DIA: ', dateCurrentFormated(new Date(subDays(new Date(startDate + ' ' + formatedTimeHour(new Date(`${startDate} ${timerPicker.getHours()}:${timerPicker.getMinutes()}:00`))), 1))))
|
||||
|
||||
|
||||
|
||||
dateSendMessage = dateCurrentFormated(new Date(subDays(new Date(startDate + ' ' + formatedTimeHour(new Date(`${startDate} ${timerPicker.getHours()}:${timerPicker.getMinutes()}:00`))), 1)))
|
||||
}
|
||||
|
||||
|
||||
console.log('AGENDAMENTO ENVIO MENSAGEM1: ', `${dateSendMessage} ${timeBefore}:00`)
|
||||
|
||||
|
||||
} else if (statusChatEndId === '2') {
|
||||
|
||||
console.log('AGENDAMENTO ENVIO MENSAGEM2: ', startDate + ' ' + formatedTimeHour(new Date(`${startDate} ${timerPicker.getHours()}:${timerPicker.getMinutes()}:00`)))
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -297,21 +297,21 @@ const Modal = (props) => {
|
|||
let hours = []
|
||||
let hour = 1
|
||||
|
||||
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>> startDate: ', startDate)
|
||||
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>> dateCurrentFormated: ', dateCurrentFormated())
|
||||
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>> startDate: ', typeof (startDate))
|
||||
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>> startDate: ', (startDate))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (typeof (startDate) === 'string' && startDate.trim().length > 0 && startDate === dateCurrentFormated()) {
|
||||
|
||||
console.log('HOJE++++')
|
||||
|
||||
|
||||
while (subHours(timer, hour).getHours() >= 6 &&
|
||||
|
||||
subHours(timer, hour).getHours() >= new Date().getHours() &&
|
||||
subHours(timer, hour).getHours() <= 20) {
|
||||
|
||||
console.log('******** TIMER: ', formatedTimeHour(subHours(timer, hour)))
|
||||
|
||||
|
||||
hours.push({ value: formatedTimeHour(subHours(timer, hour)), label: `${hour} HORA ANTES DO HORÁRIO DO AGENDAMENTO` })
|
||||
|
||||
|
@ -319,7 +319,7 @@ const Modal = (props) => {
|
|||
}
|
||||
|
||||
if (hours.length > 1) {
|
||||
console.log('entrou----------------------: ', hours.length)
|
||||
|
||||
hours.pop()
|
||||
setCurrency(hours[0].value)
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ const Modal = (props) => {
|
|||
|
||||
while (subHours(timer, hour).getHours() >= 6 && subHours(timer, hour).getHours() <= 20) {
|
||||
|
||||
console.log('******** another day TIMER: ', formatedTimeHour(subHours(timer, hour)))
|
||||
|
||||
|
||||
hours.push(
|
||||
{
|
||||
|
@ -344,7 +344,7 @@ const Modal = (props) => {
|
|||
}
|
||||
|
||||
if (hours.length > 0) {
|
||||
console.log('entrou----------------------: ', hours.length)
|
||||
|
||||
setCurrency(hours[0].value)
|
||||
}
|
||||
else {
|
||||
|
@ -358,18 +358,18 @@ const Modal = (props) => {
|
|||
|
||||
hours.push({ value: formatedTimeHour(timerPicker), label: `24 HORAS ANTES DO HORÁRIO DO AGENDAMENTO` })
|
||||
|
||||
console.log('#subDays: ', dateCurrentFormated(new Date(subDays(new Date(startDate + ' ' + formatedTimeHour(new Date(`${startDate} ${timerPicker.getHours()}:${timerPicker.getMinutes()}:00`))), 1))))
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log('hourshourshourshourshourshourshourshourshourshourshourshours ', hours)
|
||||
|
||||
|
||||
|
||||
return { time: hours, hour: hour }
|
||||
|
||||
}
|
||||
|
||||
console.log('===================================== addDays: ', addDays(new Date(), 1))
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -394,7 +394,7 @@ const Modal = (props) => {
|
|||
|
||||
// Get from child 1
|
||||
const textFieldSelect = (data) => {
|
||||
console.log('textFieldSelect: ', data);
|
||||
|
||||
setStatusChatEnd(data)
|
||||
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ const Modal = (props) => {
|
|||
|
||||
const handleCheckBoxChange = (event) => {
|
||||
|
||||
//console.log('event.target.checked: ', event.target.checked)
|
||||
|
||||
setChecked(event.target.checked);
|
||||
};
|
||||
|
||||
|
@ -416,11 +416,11 @@ const Modal = (props) => {
|
|||
|
||||
const handleChangeHourBefore = (event) => {
|
||||
|
||||
console.log('textFihandleChangeHourBefore: ', event.target.value);
|
||||
|
||||
|
||||
// var matchedTime = currenciesTimeBefore.filter(i => i.label.indexOf('24 HORAS ANTES DO HORÁRIO DO AGENDAMENTO') >= 0);
|
||||
|
||||
// console.log('textFihandleChangeHourBefore matchedTime: ',matchedTime);
|
||||
|
||||
|
||||
setCurrency(event.target.value);
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ import InputLabel from "@mui/material/InputLabel";
|
|||
import MenuItem from "@mui/material/MenuItem";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Zoom from "@mui/material/Zoom";
|
||||
// import Tooltip from "@mui/material/Tooltip";
|
||||
// import Zoom from "@mui/material/Zoom";
|
||||
|
||||
import CancelIcon from "@material-ui/icons/Cancel";
|
||||
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
|
||||
|
|
|
@ -37,6 +37,10 @@ import { AuthContext } from "../../context/Auth/AuthContext";
|
|||
import { useLocalStorage } from "../../hooks/useLocalStorage";
|
||||
import toastError from "../../errors/toastError";
|
||||
|
||||
// import TicketsManager from "../../components/TicketsManager/";
|
||||
|
||||
import { TabTicketContext } from "../../context/TabTicketHeaderOption/TabTicketHeaderOption";
|
||||
|
||||
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
|
@ -202,6 +206,9 @@ const useStyles = makeStyles((theme) => ({
|
|||
}));
|
||||
|
||||
const MessageInput = ({ ticketStatus }) => {
|
||||
|
||||
const { tabOption, setTabOption } = useContext(TabTicketContext);
|
||||
|
||||
const classes = useStyles();
|
||||
const { ticketId } = useParams();
|
||||
|
||||
|
@ -214,8 +221,7 @@ const MessageInput = ({ ticketStatus }) => {
|
|||
const [typeBar, setTypeBar] = useState(false);
|
||||
const inputRef = useRef();
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const { setReplyingMessage, replyingMessage } =
|
||||
useContext(ReplyMessageContext);
|
||||
const { setReplyingMessage, replyingMessage } = useContext(ReplyMessageContext);
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
const [signMessage, setSignMessage] = useLocalStorage("signOption", true);
|
||||
|
@ -268,6 +274,12 @@ const MessageInput = ({ ticketStatus }) => {
|
|||
setLoading(true);
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
|
||||
if (tabOption === 'search') {
|
||||
setTabOption('open')
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("fromMe", true);
|
||||
medias.forEach((media) => {
|
||||
|
@ -289,6 +301,12 @@ const MessageInput = ({ ticketStatus }) => {
|
|||
if (inputMessage.trim() === "") return;
|
||||
setLoading(true);
|
||||
|
||||
|
||||
|
||||
if (tabOption === 'search') {
|
||||
setTabOption('open')
|
||||
}
|
||||
|
||||
const message = {
|
||||
read: 1,
|
||||
fromMe: true,
|
||||
|
@ -346,6 +364,13 @@ const MessageInput = ({ ticketStatus }) => {
|
|||
|
||||
const handleUploadAudio = async () => {
|
||||
setLoading(true);
|
||||
|
||||
|
||||
|
||||
if (tabOption === 'search') {
|
||||
setTabOption('open')
|
||||
}
|
||||
|
||||
try {
|
||||
const [, blob] = await Mp3Recorder.stop().getMp3();
|
||||
if (blob.size < 10000) {
|
||||
|
|
|
@ -283,7 +283,7 @@ const reducer = (state, action) => {
|
|||
state[messageIndex] = newMessage;
|
||||
} else {
|
||||
state.push(newMessage);
|
||||
// console.log(' TESTANDO NOVA MENSAGEM: ', newMessage)
|
||||
|
||||
}
|
||||
|
||||
return [...state];
|
||||
|
@ -371,8 +371,6 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
|
||||
if (data.action === "update") {
|
||||
|
||||
console.log('2 THIS IS THE DATA: ', data)
|
||||
|
||||
dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
|
||||
}
|
||||
});
|
||||
|
@ -487,11 +485,13 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (index < messagesList.length - 1) {
|
||||
let messageDay = parseISO(messagesList[index].createdAt);
|
||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||
|
||||
if (!isSameDay(messageDay, previousMessageDay)) {
|
||||
|
||||
return (
|
||||
<span
|
||||
className={classes.dailyTimestamp}
|
||||
|
@ -504,13 +504,30 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (index === messagesList.length - 1) {
|
||||
|
||||
let messageDay = parseISO(messagesList[index].createdAt);
|
||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isSameDay(messageDay, previousMessageDay) &&
|
||||
<span
|
||||
className={classes.dailyTimestamp}
|
||||
key={`timestamp-${message.id}`}
|
||||
>
|
||||
<div className={classes.dailyTimestampText}>
|
||||
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
|
||||
</div>
|
||||
</span>
|
||||
}
|
||||
<div
|
||||
key={`ref-${message.createdAt}`}
|
||||
ref={lastMessageRef}
|
||||
style={{ float: "left", clear: "both" }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -63,14 +63,14 @@ const NotificationsPopOver = () => {
|
|||
|
||||
// const [lastRef] = useState(+history.location.pathname.split("/")[2])
|
||||
|
||||
// console.log('ticketIdRef: ',ticketIdRef, ' | lastRef: ',lastRef)
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
soundAlertRef.current = play;
|
||||
|
||||
if (!("Notification" in window)) {
|
||||
console.log("This browser doesn't support notifications");
|
||||
|
||||
} else {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ const NotificationsPopOver = () => {
|
|||
|
||||
useEffect(() => {
|
||||
|
||||
// console.log('888888888888888888888888888888888888888888888888888888888888888888')
|
||||
|
||||
|
||||
ticketIdRef.current = ticketIdUrl;
|
||||
}, [ticketIdUrl]);
|
||||
|
@ -97,7 +97,7 @@ const NotificationsPopOver = () => {
|
|||
|
||||
if(data.action === "logout"){
|
||||
|
||||
console.log('___________data.userId: ', data.userOnlineTime['status'])
|
||||
|
||||
|
||||
if(`${user.id}` === data.userOnlineTime['userId']){
|
||||
|
||||
|
@ -112,7 +112,7 @@ const NotificationsPopOver = () => {
|
|||
|
||||
socket.on("isOnline", (data) => {
|
||||
|
||||
// console.log('___________data.userId: ', data.userId)
|
||||
|
||||
|
||||
if(data.action === "online"){
|
||||
|
||||
|
@ -169,7 +169,7 @@ const NotificationsPopOver = () => {
|
|||
|
||||
socket.on("appMessage", data => {
|
||||
|
||||
// console.log('******************* DATA: ', data)
|
||||
|
||||
|
||||
if (
|
||||
data.action === "create" &&
|
||||
|
@ -177,24 +177,24 @@ const NotificationsPopOver = () => {
|
|||
(data.ticket.userId === user?.id || !data.ticket.userId)
|
||||
) {
|
||||
|
||||
// console.log('entrou.............')
|
||||
|
||||
|
||||
|
||||
setNotifications(prevState => {
|
||||
|
||||
// console.log('prevState: ', prevState)
|
||||
|
||||
|
||||
// prevState.forEach((e)=>{
|
||||
// console.log(`>>> e.id: ${e.id} | data.ticket.Id: ${data.ticket.id}`)
|
||||
//
|
||||
// })
|
||||
|
||||
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id);
|
||||
if (ticketIndex !== -1) {
|
||||
// console.log(` data.ticket 1 `)
|
||||
|
||||
prevState[ticketIndex] = data.ticket;
|
||||
return [...prevState];
|
||||
}
|
||||
// console.log(` data.ticket 2 `)
|
||||
|
||||
return [data.ticket, ...prevState];
|
||||
});
|
||||
|
||||
|
@ -206,7 +206,7 @@ const NotificationsPopOver = () => {
|
|||
|
||||
if (shouldNotNotificate) return;
|
||||
|
||||
//console.log('PASSOU!!!!!!!')
|
||||
|
||||
|
||||
handleNotifications(data);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ const MTable = (props) => {
|
|||
|
||||
// useEffect(() => {
|
||||
|
||||
// console.log(`You have clicked the button ${selectedRow} times`)
|
||||
//
|
||||
|
||||
// }, [selectedRow]);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ useEffect(()=>{
|
|||
|
||||
setCurrency( event.target.value)
|
||||
|
||||
console.log('event.target.value: ', event.target.value)
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React from "react";
|
||||
|
||||
const TabPanel = ({ children, value, name, ...rest }) => {
|
||||
|
||||
|
||||
if (value === name) {
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -15,6 +15,8 @@ import { AuthContext } from "../../context/Auth/AuthContext";
|
|||
import Modal from "../ChatEnd/ModalChatEnd";
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { TabTicketContext } from "../../context/TabTicketHeaderOption/TabTicketHeaderOption";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
actionButtons: {
|
||||
marginRight: 6,
|
||||
|
@ -35,6 +37,8 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
const ticketOptionsMenuOpen = Boolean(anchorEl);
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
const { tabOption, setTabOption } = useContext(TabTicketContext);
|
||||
|
||||
const handleOpenTicketOptionsMenu = e => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
};
|
||||
|
@ -50,7 +54,7 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
|
||||
data = {...data, 'ticketId': ticket.id}
|
||||
|
||||
console.log('ChatEnd: ',(data));
|
||||
|
||||
|
||||
handleUpdateTicketStatus(null, "closed", user?.id, data)
|
||||
|
||||
|
@ -78,6 +82,10 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
|
||||
if(status==='closed'){
|
||||
|
||||
if (tabOption === 'search') {
|
||||
setTabOption('open')
|
||||
}
|
||||
|
||||
await api.put(`/tickets/${ticket.id}`, {
|
||||
status: status,
|
||||
userId: userId || null,
|
||||
|
@ -87,6 +95,10 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
}
|
||||
else{
|
||||
|
||||
if (tabOption === 'search') {
|
||||
setTabOption('open')
|
||||
}
|
||||
|
||||
await api.put(`/tickets/${ticket.id}`, {
|
||||
status: status,
|
||||
userId: userId || null
|
||||
|
@ -96,6 +108,8 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
|
||||
setLoading(false);
|
||||
if (status === "open") {
|
||||
|
||||
|
||||
history.push(`/tickets/${ticket.id}`);
|
||||
} else {
|
||||
history.push("/tickets");
|
||||
|
@ -124,7 +138,7 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
)}
|
||||
{ticket.status === "open" && (
|
||||
<>
|
||||
<ButtonWithSpinner
|
||||
<ButtonWithSpinner style={{ marginRight: "70px" }}
|
||||
loading={loading}
|
||||
startIcon={<Replay />}
|
||||
size="small"
|
||||
|
|
|
@ -118,6 +118,7 @@ const TicketListItem = ({ ticket }) => {
|
|||
const handleAcepptTicket = async id => {
|
||||
setLoading(true);
|
||||
try {
|
||||
|
||||
await api.put(`/tickets/${id}`, {
|
||||
status: "open",
|
||||
userId: user?.id,
|
||||
|
@ -129,6 +130,9 @@ const TicketListItem = ({ ticket }) => {
|
|||
if (isMounted.current) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
history.push(`/tickets/${id}`);
|
||||
};
|
||||
|
||||
|
@ -216,7 +220,7 @@ const TicketListItem = ({ ticket }) => {
|
|||
|
||||
<Badge
|
||||
className={classes.newMessagesCount}
|
||||
badgeContent={ticket.unreadMessages}
|
||||
badgeContent={+ticket.unreadMessages}
|
||||
classes={{
|
||||
badge: classes.badgeStyle,
|
||||
}}
|
||||
|
|
|
@ -12,6 +12,7 @@ import useTickets from "../../hooks/useTickets";
|
|||
import { i18n } from "../../translate/i18n";
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
|
||||
import { SearchTicketContext } from "../../context/SearchTicket/SearchTicket";
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
ticketsListWrapper: {
|
||||
|
@ -79,12 +80,10 @@ const reducer = (state, action) => {
|
|||
|
||||
newTickets.forEach(ticket => {
|
||||
|
||||
// console.log('* ticket.unreadMessages: ',ticket.unreadMessages)
|
||||
|
||||
const ticketIndex = state.findIndex(t => t.id === ticket.id);
|
||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||
if (ticketIndex !== -1) {
|
||||
state[ticketIndex] = ticket;
|
||||
if (ticket.unreadMessages > 0) {
|
||||
if (+ticket.unreadMessages > 0) {
|
||||
state.unshift(state.splice(ticketIndex, 1)[0]);
|
||||
}
|
||||
} else {
|
||||
|
@ -98,7 +97,10 @@ const reducer = (state, action) => {
|
|||
if (action.type === "RESET_UNREAD") {
|
||||
const ticketId = action.payload;
|
||||
|
||||
const ticketIndex = state.findIndex(t => t.id === ticketId);
|
||||
const ticketIndex = state.findIndex(t => +t.id === +ticketId);
|
||||
|
||||
|
||||
|
||||
if (ticketIndex !== -1) {
|
||||
state[ticketIndex].unreadMessages = 0;
|
||||
}
|
||||
|
@ -109,9 +111,8 @@ const reducer = (state, action) => {
|
|||
if (action.type === "UPDATE_TICKET") {
|
||||
const ticket = action.payload;
|
||||
|
||||
// console.log('++++++++++++ UPDATE_TICKET: ',ticket)
|
||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||
|
||||
const ticketIndex = state.findIndex(t => t.id === ticket.id);
|
||||
if (ticketIndex !== -1) {
|
||||
state[ticketIndex] = ticket;
|
||||
} else {
|
||||
|
@ -127,13 +128,13 @@ const reducer = (state, action) => {
|
|||
|
||||
const ticket = action.payload.ticket;
|
||||
|
||||
const ticketIndex = state.findIndex(t => t.id === ticket.id);
|
||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||
|
||||
if (ticketIndex !== -1) {
|
||||
|
||||
// console.log('>>>>>> ticketIndex: ', ticketIndex)
|
||||
|
||||
// console.log('&&&&&&& UPDATE_TICKET_UNREAD_MESSAGES ticket: ',ticket, ' |\n MESSAGE: ', message)
|
||||
|
||||
|
||||
|
||||
if (!message.fromMe) {
|
||||
ticket.unreadMessages += 1
|
||||
|
@ -151,7 +152,7 @@ const reducer = (state, action) => {
|
|||
|
||||
if (action.type === "UPDATE_TICKET_CONTACT") {
|
||||
const contact = action.payload;
|
||||
const ticketIndex = state.findIndex(t => t.contactId === contact.id);
|
||||
const ticketIndex = state.findIndex(t => +t.contactId === +contact.id);
|
||||
if (ticketIndex !== -1) {
|
||||
state[ticketIndex].contact = contact;
|
||||
}
|
||||
|
@ -160,7 +161,7 @@ const reducer = (state, action) => {
|
|||
|
||||
if (action.type === "DELETE_TICKET") {
|
||||
const ticketId = action.payload;
|
||||
const ticketIndex = state.findIndex(t => t.id === ticketId);
|
||||
const ticketIndex = state.findIndex(t => +t.id === +ticketId);
|
||||
if (ticketIndex !== -1) {
|
||||
state.splice(ticketIndex, 1);
|
||||
}
|
||||
|
@ -174,16 +175,21 @@ const reducer = (state, action) => {
|
|||
};
|
||||
|
||||
const TicketsList = (props) => {
|
||||
const { status, searchParam, showAll, selectedQueueIds, updateCount, style } = props;
|
||||
const { status, searchParam, showAll, selectedQueueIds, updateCount, style, tab } = props;
|
||||
const classes = useStyles();
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [ticketsList, dispatch] = useReducer(reducer, []);
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
const { searchTicket } = useContext(SearchTicketContext)
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
setPageNumber(1);
|
||||
}, [status, searchParam, dispatch, showAll, selectedQueueIds]);
|
||||
|
||||
}, [status, searchParam, showAll, selectedQueueIds, searchTicket]);
|
||||
|
||||
|
||||
|
||||
const { tickets, hasMore, loading } = useTickets({
|
||||
pageNumber,
|
||||
|
@ -191,20 +197,31 @@ const TicketsList = (props) => {
|
|||
status,
|
||||
showAll,
|
||||
queueIds: JSON.stringify(selectedQueueIds),
|
||||
tab
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!status && !searchParam) return;
|
||||
|
||||
// console.log('lllllllllllllllllllllllllllllllll')
|
||||
// if (searchParam) {
|
||||
//
|
||||
// dispatch({ type: "RESET" });
|
||||
// }
|
||||
|
||||
dispatch({
|
||||
type: "LOAD_TICKETS",
|
||||
payload: tickets,
|
||||
});
|
||||
}, [tickets, status, searchParam]);
|
||||
if ((searchParam && searchParam.trim().length > 0) &&
|
||||
(tickets && tickets.length === 0) &&
|
||||
pageNumber === 1) {
|
||||
dispatch({ type: "RESET" })
|
||||
}
|
||||
|
||||
dispatch({ type: "LOAD_TICKETS", payload: tickets, });
|
||||
|
||||
}, [tickets, status, searchParam, pageNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// if (tab=='search')return
|
||||
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||
|
||||
const shouldUpdateTicket = ticket =>
|
||||
|
@ -223,9 +240,14 @@ const TicketsList = (props) => {
|
|||
|
||||
});
|
||||
|
||||
|
||||
|
||||
socket.on("ticket", data => {
|
||||
|
||||
if (data.action === "updateUnread") {
|
||||
|
||||
if (tab === 'search' && data.ticket && data.ticket.status === 'pending') return
|
||||
|
||||
dispatch({
|
||||
type: "RESET_UNREAD",
|
||||
payload: data.ticketId,
|
||||
|
@ -233,6 +255,9 @@ const TicketsList = (props) => {
|
|||
}
|
||||
|
||||
if (data.action === "update" && shouldUpdateTicket(data.ticket)) {
|
||||
|
||||
if (tab === 'search' && data.ticket && (data.ticket.status === 'pending' || data.ticket.status === 'closed')) return
|
||||
|
||||
dispatch({
|
||||
type: "UPDATE_TICKET",
|
||||
payload: data.ticket,
|
||||
|
@ -248,10 +273,12 @@ const TicketsList = (props) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
socket.on("appMessage", data => {
|
||||
if (data.action === "create" && shouldUpdateTicket(data.ticket)) {
|
||||
|
||||
// console.log('((((((((((((((((((( DATA.MESSAGE: ', data.message)
|
||||
|
||||
if (tab === 'search') return
|
||||
|
||||
dispatch({
|
||||
type: "UPDATE_TICKET_UNREAD_MESSAGES",
|
||||
|
@ -273,7 +300,7 @@ const TicketsList = (props) => {
|
|||
return () => {
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [status, showAll, user, selectedQueueIds]);
|
||||
}, [status, showAll, user, selectedQueueIds, tab]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
@ -296,6 +323,9 @@ const TicketsList = (props) => {
|
|||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
||||
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
||||
|
||||
|
||||
|
||||
loadMore();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,6 +23,10 @@ import { Can } from "../Can";
|
|||
import TicketsQueueSelect from "../TicketsQueueSelect";
|
||||
import { Button } from "@material-ui/core";
|
||||
|
||||
import { TabTicketContext } from "../../context/TabTicketHeaderOption/TabTicketHeaderOption";
|
||||
|
||||
import { SearchTicketContext } from "../../context/SearchTicket/SearchTicket";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
ticketsWrapper: {
|
||||
position: "relative",
|
||||
|
@ -92,6 +96,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
}));
|
||||
|
||||
const TicketsManager = () => {
|
||||
|
||||
const { tabOption, setTabOption } = useContext(TabTicketContext);
|
||||
|
||||
const {setSearchTicket} = useContext(SearchTicketContext)
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const [searchParam, setSearchParam] = useState("");
|
||||
|
@ -108,6 +117,8 @@ const TicketsManager = () => {
|
|||
const userQueueIds = user.queues.map((q) => q.id);
|
||||
const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []);
|
||||
|
||||
const [inputSearch, setInputSearch] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (user.profile.toUpperCase() === "ADMIN") {
|
||||
setShowAllTickets(true);
|
||||
|
@ -119,25 +130,55 @@ const TicketsManager = () => {
|
|||
if (tab === "search") {
|
||||
searchInputRef.current.focus();
|
||||
}
|
||||
}, [tab]);
|
||||
|
||||
setTabOption(tab)
|
||||
|
||||
}, [tab, setTabOption]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
||||
if (tabOption === 'open') {
|
||||
|
||||
setTabOption('')
|
||||
setSearchParam('');
|
||||
setInputSearch('');
|
||||
setTab("open");
|
||||
return;
|
||||
}
|
||||
|
||||
}, [tabOption, setTabOption])
|
||||
|
||||
let searchTimeout;
|
||||
|
||||
const removeExtraSpace = (str) => {
|
||||
|
||||
str = str.replace(/^\s+/g, '')
|
||||
|
||||
return str.replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
const handleSearch = (e) => {
|
||||
let searchedTerm = e.target.value.toLowerCase()
|
||||
|
||||
setInputSearch(removeExtraSpace(searchedTerm))
|
||||
|
||||
setSearchTicket(searchParam)
|
||||
|
||||
clearTimeout(searchTimeout);
|
||||
|
||||
if (searchedTerm === "") {
|
||||
setSearchParam(searchedTerm);
|
||||
setInputSearch(searchedTerm)
|
||||
setTab("open");
|
||||
return;
|
||||
}
|
||||
|
||||
searchTimeout = setTimeout(() => {
|
||||
|
||||
setSearchParam(searchedTerm);
|
||||
}, 1000);
|
||||
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleChangeTab = (e, newValue) => {
|
||||
|
@ -198,6 +239,7 @@ const TicketsManager = () => {
|
|||
inputRef={searchInputRef}
|
||||
placeholder={i18n.t("tickets.search.placeholder")}
|
||||
type="search"
|
||||
value={inputSearch}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</div>
|
||||
|
@ -297,11 +339,15 @@ const TicketsManager = () => {
|
|||
/>
|
||||
</TabPanel>
|
||||
<TabPanel value={tab} name="search" className={classes.ticketsWrapper}>
|
||||
|
||||
|
||||
<TicketsList
|
||||
searchParam={searchParam}
|
||||
tab={tab}
|
||||
showAll={true}
|
||||
selectedQueueIds={selectedQueueIds}
|
||||
/>
|
||||
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ const AuthContext = createContext();
|
|||
const AuthProvider = ({ children }) => {
|
||||
const { loading, user, isAuth, handleLogin, handleLogout } = useAuth();
|
||||
|
||||
//{console.log('authContext teste: ', user)}
|
||||
//{
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import React, { useState, createContext } from "react";
|
||||
|
||||
const SearchTicketContext = createContext();
|
||||
|
||||
|
||||
const SearchTicketProvider = ({ children }) => {
|
||||
|
||||
const [searchTicket, setSearchTicket] = useState(0);
|
||||
|
||||
return (
|
||||
<SearchTicketContext.Provider value={{ searchTicket, setSearchTicket }}>
|
||||
{children}
|
||||
</SearchTicketContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export { SearchTicketContext, SearchTicketProvider };
|
|
@ -0,0 +1,33 @@
|
|||
import React, { useState, createContext } from "react";
|
||||
|
||||
// export const TabTicketContext = createContext();
|
||||
|
||||
const TabTicketContext = createContext();
|
||||
|
||||
|
||||
// export const TabTicketProvider= ({ children }) => {
|
||||
|
||||
// const [tabOption, setTabOption] = useState(0);
|
||||
|
||||
// return (
|
||||
// <TabTicketContext.Provider value={{ tabOption, setTabOption }}>
|
||||
// {children}
|
||||
// </TabTicketContext.Provider>
|
||||
// );
|
||||
// };
|
||||
|
||||
|
||||
|
||||
|
||||
const TabTicketProvider = ({ children }) => {
|
||||
|
||||
const [tabOption, setTabOption] = useState(0);
|
||||
|
||||
return (
|
||||
<TabTicketContext.Provider value={{ tabOption, setTabOption }}>
|
||||
{children}
|
||||
</TabTicketContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export { TabTicketContext, TabTicketProvider };
|
|
@ -11,24 +11,27 @@ const useTickets = ({
|
|||
showAll,
|
||||
queueIds,
|
||||
withUnreadMessages,
|
||||
unlimited
|
||||
unlimited,
|
||||
tab
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
const [tickets, setTickets] = useState([]);
|
||||
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchTickets = async () => {
|
||||
try {
|
||||
|
||||
if(searchParam){
|
||||
console.log('searchParam: ', searchParam)
|
||||
if ((tab === 'search') && ( !searchParam || searchParam.trim().length === 0 || searchParam.trim().length >40 || searchParam.endsWith(' '))) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const { data } = await api.get("/tickets", {
|
||||
params: {
|
||||
searchParam,
|
||||
|
@ -42,13 +45,14 @@ const useTickets = ({
|
|||
},
|
||||
});
|
||||
|
||||
console.log('data.tickets: ', data.tickets)
|
||||
// console.log('data.hasMore: ', data.hasMore)
|
||||
|
||||
|
||||
|
||||
setTickets(data.tickets);
|
||||
setHasMore(data.hasMore);
|
||||
setLoading(false);
|
||||
|
||||
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
toastError(err);
|
||||
|
@ -65,7 +69,7 @@ const useTickets = ({
|
|||
showAll,
|
||||
queueIds,
|
||||
withUnreadMessages,
|
||||
|
||||
tab,
|
||||
unlimited
|
||||
]);
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ const useWhatsApps = () => {
|
|||
socket.on("whatsappSessionMonit", data => {
|
||||
if (data.action === "update") {
|
||||
|
||||
// console.log('data.whatsappSessionSize: ', data.whatsappSessionSize)
|
||||
|
||||
|
||||
dispatch({ type: "UPDATE_WHATSAPPS_SESSION_MONIT", payload: data.whatsappSessionSize });
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ function ListItemLink(props) {
|
|||
}
|
||||
|
||||
const MainListItems = (props) => {
|
||||
const { drawerClose, setDrawerOpen, drawerOpen } = props;
|
||||
const { setDrawerOpen } = props;
|
||||
const { whatsApps } = useContext(WhatsAppsContext);
|
||||
const { user } = useContext(AuthContext);
|
||||
const [connectionWarning, setConnectionWarning] = useState(false);
|
||||
|
|
|
@ -45,7 +45,7 @@ const reducer = (state, action) => {
|
|||
|
||||
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;
|
||||
|
@ -60,7 +60,7 @@ const reducer = (state, action) => {
|
|||
|
||||
if (action.type === "UPDATE_CONTACTS") {
|
||||
const contact = action.payload;
|
||||
const contactIndex = state.findIndex((c) => c.id === contact.id);
|
||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id);
|
||||
|
||||
if (contactIndex !== -1) {
|
||||
state[contactIndex] = contact;
|
||||
|
@ -73,7 +73,7 @@ const reducer = (state, action) => {
|
|||
if (action.type === "DELETE_CONTACT") {
|
||||
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);
|
||||
}
|
||||
|
@ -110,25 +110,46 @@ const Contacts = () => {
|
|||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
setPageNumber(1);
|
||||
}, [searchParam]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
||||
if (searchParam.trim().length > 0 && searchParam.endsWith(' ')) {
|
||||
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchContacts = async () => {
|
||||
|
||||
try {
|
||||
const { data } = await api.get("/contacts/", {
|
||||
params: { searchParam, pageNumber },
|
||||
});
|
||||
|
||||
if (searchParam.trim().length > 40) {
|
||||
return
|
||||
}
|
||||
|
||||
const { data } = await api.get("/contacts/", { params: { searchParam, pageNumber }, });
|
||||
|
||||
|
||||
dispatch({ type: "LOAD_CONTACTS", payload: data.contacts });
|
||||
setHasMore(data.hasMore);
|
||||
setLoading(false);
|
||||
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
}
|
||||
|
||||
};
|
||||
fetchContacts();
|
||||
}, 500);
|
||||
|
@ -153,8 +174,15 @@ const Contacts = () => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
const removeExtraSpace = (str) => {
|
||||
|
||||
str = str.replace(/^\s+/g, '')
|
||||
|
||||
return str.replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
const handleSearch = (event) => {
|
||||
setSearchParam(event.target.value.toLowerCase());
|
||||
setSearchParam(removeExtraSpace(event.target.value.toLowerCase()));
|
||||
};
|
||||
|
||||
const handleOpenContactModal = () => {
|
||||
|
@ -217,7 +245,7 @@ const Contacts = () => {
|
|||
if (!hasMore || loading) return;
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
||||
// console.log('scrollTop: ', scrollTop, ' | scrollHeight: ', scrollHeight, ' | clientHeight: ', clientHeight)
|
||||
|
||||
|
||||
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
||||
loadMore();
|
||||
|
@ -235,8 +263,7 @@ const Contacts = () => {
|
|||
<ConfirmationModal
|
||||
title={
|
||||
deletingContact
|
||||
? `${i18n.t("contacts.confirmationModal.deleteTitle")} ${
|
||||
deletingContact.name
|
||||
? `${i18n.t("contacts.confirmationModal.deleteTitle")} ${deletingContact.name
|
||||
}?`
|
||||
: `${i18n.t("contacts.confirmationModal.importTitlte")}`
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import IconButton from "@mui/material/IconButton";
|
|||
import Info from "@material-ui/icons/Info";
|
||||
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
import { i18n } from "../../translate/i18n";
|
||||
// import { i18n } from "../../translate/i18n";
|
||||
import Chart from "./Chart";
|
||||
import openSocket from "socket.io-client";
|
||||
import api from "../../services/api";
|
||||
|
@ -241,7 +241,7 @@ const Dashboard = () => {
|
|||
dispatch({ type: "RESET" });
|
||||
dispatch({ type: "LOAD_QUERY", payload: dataQuery.data });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -280,7 +280,7 @@ const Dashboard = () => {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (ticketStatusChange === "") return console.log("foi");
|
||||
if (ticketStatusChange === "") return
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchQueries = async () => {
|
||||
try {
|
||||
|
|
|
@ -22,7 +22,6 @@ import fileDownload from 'js-file-download'
|
|||
|
||||
|
||||
import openSocket from "socket.io-client";
|
||||
import { TramOutlined } from "@material-ui/icons";
|
||||
|
||||
const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }]
|
||||
|
||||
|
@ -216,7 +215,7 @@ let columnsData = [
|
|||
{ title: 'Status', field: 'status' },
|
||||
|
||||
{ title: 'Criado', field: 'createdAt' },
|
||||
//{title: 'Atualizado', field: 'updatedAt'},
|
||||
{title: 'Atualizado', field: 'updatedAt'},
|
||||
{ title: 'Status de encerramento', field: 'statusChatEnd' }];
|
||||
|
||||
|
||||
|
@ -318,13 +317,8 @@ const Report = () => {
|
|||
const dataQuery = await api.get("/reports/user/services", { params: { userId, startDate, endDate }, });
|
||||
dispatchQ({ type: "RESET" })
|
||||
dispatchQ({ type: "LOAD_QUERY", payload: dataQuery.data });
|
||||
|
||||
//setLoading(false);
|
||||
|
||||
console.log('REPORT 2 dataQuery : ', dataQuery.data)
|
||||
|
||||
//console.log()
|
||||
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
|
|
@ -100,7 +100,7 @@ const Settings = () => {
|
|||
|
||||
// const handleEdit = () => {
|
||||
|
||||
// console.log('Editar....')
|
||||
//
|
||||
|
||||
// }
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import Ticket from "../../components/Ticket/";
|
|||
import { i18n } from "../../translate/i18n";
|
||||
import Hidden from "@material-ui/core/Hidden";
|
||||
|
||||
import { SearchTicketProvider } from "../../context/SearchTicket/SearchTicket";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
chatContainer: {
|
||||
flex: 1,
|
||||
|
@ -79,7 +81,11 @@ const Chat = () => {
|
|||
ticketId ? classes.contactsWrapperSmall : classes.contactsWrapper
|
||||
}
|
||||
>
|
||||
<SearchTicketProvider>
|
||||
<TicketsManager />
|
||||
</SearchTicketProvider>
|
||||
|
||||
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8} className={classes.messagessWrapper}>
|
||||
{/* <Grid item xs={8} className={classes.messagessWrapper}> */}
|
||||
|
|
|
@ -21,7 +21,7 @@ import { AuthProvider } from "../context/Auth/AuthContext";
|
|||
import { WhatsAppsProvider } from "../context/WhatsApp/WhatsAppsContext";
|
||||
import Route from "./Route";
|
||||
|
||||
//console.log('---AuthProvider: ',AuthProvider)
|
||||
|
||||
|
||||
const Routes = () => {
|
||||
return (
|
||||
|
|
|
@ -241,7 +241,7 @@ const messages = {
|
|||
search: { title: "Busca" },
|
||||
},
|
||||
search: {
|
||||
placeholder: "Buscar tickets e mensagens",
|
||||
placeholder: "Busca telefone/nome",
|
||||
},
|
||||
buttons: {
|
||||
showAll: "Todos",
|
||||
|
|
Loading…
Reference in New Issue