Compare commits

..

29 Commits

Author SHA1 Message Date
gustavo-gsp 940a6c1f97 Merge remote-tracking branch 'origin' into gertec 2024-09-06 19:41:25 -03:00
gustavo-gsp 5964b48b36 fix: correct and add functionalities in the IVR for two different numbers
Details:
- Fixed issues in the IVR system.
- Added new functionalities to support two different phone numbers.
2024-09-06 19:36:43 -03:00
gustavo-gsp f4f5dad8d2 fix: resolve issue of creating multiple contacts for the same WhatsApp number of a client
Details:
- Fixed the bug that allowed the creation of more than one contact for the same WhatsApp number of a client.
2024-09-06 16:59:23 -03:00
gustavo-gsp 05c9f3af6d perf: improve backend with compression and optimize frontend with lazy load
Details:
- Added compression to the backend to reduce page load times.
- Implemented lazy loading in frontend routes to optimize page loading performance.
2024-09-05 12:20:52 -03:00
adriano 0a031bd9a8 fix issues for websocket merge 2024-08-29 18:09:00 -03:00
adriano 1f8d5eb29b Merge branch 'websocket' of https://github.com/AdrianoRobson/projeto-hit into merge-socket 2024-08-22 16:53:27 -03:00
adriano 125e758a18 firt commit 2024-08-22 16:51:31 -03:00
adriano dc44dccd82 feat: Upadate pyload properties to send client phone to the whatsapp official billing api 2024-08-13 10:43:32 -03:00
adriano 69246d3d93 Merge branch 'master' of github.com:AdrianoRobson/projeto-hit 2024-08-09 16:46:30 -03:00
adriano 3e88b27021 feat: add 24-hour window and service category for official WhatsApp conversations in Redis; implement method to send billing info to API for Grafana usage report 2024-08-09 16:45:25 -03:00
adriano e8227661e0 fix(i18n): resolve translation issues 2024-07-26 16:08:18 -05:00
adriano 814c892e08 fix(i18n): correct translation bugs 2024-07-26 15:23:02 -05:00
adriano c39cae9f81 fix(i18n): add missing translations in the interface 2024-07-25 11:05:39 -05:00
adriano f1022063a4 Merge branch 'master' of github.com:AdrianoRobson/projeto-hit 2024-07-10 14:52:58 -03:00
gustavo-gsp 2bb5db92d7 fix: resolve issue with blocking audio and video without the option being active
Details:
- Fixed the problem where audio and video were being blocked even when the option was not active.
2024-06-27 14:10:26 -03:00
gustavo-gsp e30573519d fix: resolve issues with WhatsApp creation and editing, message input, and ControlByNumber errors
Details:
- Fixed issue where the 'number' field was not being saved during WhatsApp creation and editing.
- Resolved problem where text in the message input was being cleared upon receiving a new message.
- Addressed errors in ControlByNumber when ticketId was not found.
2024-06-25 10:45:46 -03:00
adriano 83d197f240 feat: remoteTickesControll listeners 2024-05-23 17:39:42 -03:00
adriano 435a577bed fix: listener para ticket deletado 2024-05-22 12:51:11 -03:00
adriano fce5554681 fix: update message ack 2024-05-22 09:51:10 -03:00
adriano 3ced558b18 fix: getSettingValue quebrando a app 2024-05-21 10:15:59 -03:00
adriano 7bb73cfa19 fix: bugs de atualizacao dos tickets tempo real 2024-05-20 17:24:06 -03:00
adriano 62f137d884 feat: load balance 2024-05-20 10:00:45 -03:00
willian-pessoa eb1d0f2303 feat: verificar ticket id antes de atualizar lista de msgs 2024-05-09 16:01:21 -03:00
willian-pessoa dac57f9d48 refactor: restantes das conexoes para a conexao ws global 2024-05-09 15:59:02 -03:00
willian-pessoa 5981f9dd5e refactor: mais 7 conexoes movidas para conexao ws global 2024-05-09 15:31:30 -03:00
willian-pessoa 4d3cab5333 refactor: mais tres ws connecoes movidas para conecao global 2024-05-09 09:01:21 -03:00
willian-pessoa a5d3f19e1a refactor: criado conexao web socket global e movido alguns listeners para ela 2024-05-08 18:02:31 -03:00
adriano 6f5a84e37b Merge branch 'master' of github.com:AdrianoRobson/projeto-hit 2024-03-07 18:17:14 -03:00
adriano 144bb6db94 update before git pull 2024-03-07 18:17:02 -03:00
56 changed files with 1121 additions and 579 deletions

View File

@ -17,10 +17,12 @@
"license": "MIT",
"dependencies": {
"@sentry/node": "^5.29.2",
"@socket.io/redis-adapter": "^7.2.0",
"@types/fluent-ffmpeg": "^2.1.21",
"@types/pino": "^6.3.4",
"axios": "^1.2.3",
"bcryptjs": "^2.4.3",
"compression": "^1.7.4",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"cpf-cnpj-validator": "^1.0.3",
@ -42,12 +44,13 @@
"pino": "^6.9.0",
"pino-pretty": "^9.1.1",
"qrcode-terminal": "^0.12.0",
"redis": "^4.6.13",
"reflect-metadata": "^0.1.13",
"sequelize": "^5.22.3",
"sequelize-cli": "^5.5.1",
"sequelize-typescript": "^1.1.0",
"sharp": "^0.32.5",
"socket.io": "^3.0.5",
"socket.io": "^4.7.5",
"socket.io-client": "^4.5.4",
"uuid": "^8.3.2",
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js",
@ -56,6 +59,7 @@
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/bluebird": "^3.5.32",
"@types/compression": "^1.7.5",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.7",
"@types/express": "^4.17.13",
@ -63,6 +67,7 @@
"@types/faker": "^5.1.3",
"@types/jest": "^26.0.15",
"@types/jsonwebtoken": "^8.5.0",
"@types/lodash": "4.14",
"@types/multer": "^1.4.4",
"@types/node": "^14.11.8",
"@types/supertest": "^2.0.10",

View File

@ -11,6 +11,7 @@ import uploadConfig from "./config/upload";
import AppError from "./errors/AppError";
import routes from "./routes";
import { logger } from "./utils/logger";
import compression from 'compression';
Sentry.init({ dsn: process.env.SENTRY_DSN });
@ -23,6 +24,7 @@ app.use(
})
);
app.use(compression());
app.use(cookieParser());
app.use(express.json());
app.use(Sentry.Handlers.requestHandler());

View File

@ -41,7 +41,10 @@ import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import SettingTicket from "../models/SettingTicket";
import { Op } from "sequelize";
import { del, get, set } from "../helpers/RedisClient";
import { del, get, getKeysByPattern, set, setCBPWhatsappOfficial } from "../helpers/RedisClient";
import axios from "axios";
interface WhatsappData {
name: string;
@ -214,6 +217,48 @@ export const weebhook = async (
return res.sendStatus(500);
}
if(
req?.body?.entry?.length > 0 &&
req?.body?.entry[0]?.changes?.length > 0 &&
req?.body?.entry[0]?.changes?.length > 0 &&
req?.body?.entry[0]?.changes[0]?.value?.statuses?.length>0 &&
req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id &&
req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.conversation?.origin?.type){
const company_phone = req?.body?.entry[0]?.changes[0]?.value?.metadata?.display_phone_number
const client_phone = req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id
const conversation_type = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].conversation.origin.type
const billable = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.billable
const pricing_model = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.pricing_model
const conversation_type_category = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.category
const msg_id = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].id
const _contact_to_exist = await get({
key: "whatsapp:*",
value: `${company_phone}`
});
if(_contact_to_exist){
const lst_services_cbp = await getKeysByPattern(company_phone, client_phone, conversation_type_category)
if(lst_services_cbp && lst_services_cbp.length > 0){
for(const item of lst_services_cbp){
if(!item.split(':').includes(conversation_type_category)){
await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model)
}
}
}else{
await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model)
}
console.log('_contact_to_exist: ', _contact_to_exist)
}
}
// MESSAGE
if (req.body.object) {
if (
@ -377,9 +422,11 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
} else if (!isOfficial) {
phoneNumberId = "";
wabaId = "";
number = "";
//number = "";
}
if(!number){
number = getNumberFromName(name)
}
let invalidPhoneName = validatePhoneName(name);
if (invalidPhoneName) {
@ -479,9 +526,11 @@ export const update = async (
} else if (!isOfficial) {
whatsappData.phoneNumberId = "";
whatsappData.wabaId = "";
whatsappData.number = "";
//whatsappData.number = "";
}
if(!whatsappData?.number){
whatsappData.number = getNumberFromName(whatsappData.name)
}
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
whatsappData,
whatsappId
@ -626,3 +675,56 @@ const checkWhatsAppData = ({
return { message: "urlApi is required!" };
}
};
async function setCBP(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, billable:string, pricing_model:string) {
const message = await Message.findByPk(msg_id)
if (message) {
await setCBPWhatsappOfficial(company_phone, client_phone, conversation_type_category, msg_id, `${message.ticketId}`)
await sendToAPIUsage(msg_id,
company_phone,
client_phone,
conversation_type_category,
`${message.ticketId}`,
billable,
pricing_model
)
}
}
async function sendToAPIUsage(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, ticketId: any, billable:string, pricing_model:string) {
const data = JSON.stringify({
"companyId": process.env.COMPANY_ID || company_phone,
"companyPhone": company_phone,
"clientPhone": client_phone,
"provider": "meta",
"product": "whatsapp",
"type": conversation_type_category,
"msgId": msg_id,
"ticketId": `${ticketId}`,
"ticketUrl": `${process.env.FRONTEND_URL}/tickets/${ticketId}`,
"billable": billable,
"pricing_model": pricing_model
});
const config = {
method: 'post',
url: 'http://172.31.187.24:6008/api/v1/billing/usage-whatsapp',
headers: {
'Authorization': 'Bearer 2ivck10D3o9qAZi0pkKudVDl9bdEVXY2s8gdxZ0jYgL1DZWTgDz6wDiIjlWgYmJtVOoqf0b42ZTLBRrfo8WoAaScRsujz3jQUNXdchSg0o43YilZGmVhheGJNAeIQRknHEll4nRJ7avcFgmDGoYbEey7TSC8EHS4Z3gzeufYYSfnKNDBwwzBURIQrTOxYFe3tBHsGOzwnuD2lU5tnEx7tr2XRO4zRNYeNY4lMBOFM0mRuyAe4kuqTrKXmJ8As200',
'Content-Type': 'application/json'
},
data: data
};
try {
const response = await axios(config);
console.log('Response from whatsapp api usage: ',JSON.stringify(response.data));
} catch (error) {
console.log('Error on try register the whatsapp usage: ', error);
}
}

View File

@ -158,6 +158,46 @@ export async function findObject(
return result;
}
export async function setCBPWhatsappOfficial(
company_phone:string,
client_phone:string,
conversation_type:string,
msg_id: string,
ticketId?: string
) {
const key = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}`;
const result = await redis.hmset(
key,
"company_phone",
company_phone,
"client_phone",
client_phone,
"conversation_type",
conversation_type,
"msg_id",
msg_id,
"ticketId",
ticketId
);
await redis.expire(key, 86400);
}
export async function getKeysByPattern(company_phone:string, client_phone:string, conversation_type:string,) {
const pattern = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}*`;
const keys = [];
let cursor = "0";
do {
const result = await redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
cursor = result[0];
keys.push(...result[1]);
} while (cursor !== "0");
return keys;
}
export async function deleteObject(
whatsappId: string,
contactId: string,

View File

@ -29,23 +29,23 @@ async function controllByNumber() {
number = JSON.parse(number);
ticketId = JSON.parse(ticketId);
const index = controll.findIndex((c: any) => c.number == number);
const index = controll?.findIndex((c: any) => c.number == number);
if (index == -1) {
controll.push({ ticketId, number });
controll?.push({ ticketId, number });
}
}
const ticketIds = controll.map((c: any) => c.ticketId);
const ticketIds = controll?.map((c: any) => c.ticketId);
console.log("=======> ticketIds: ", ticketIds);
//console.log("=======> ticketIds: ", ticketIds);
for (const ticketId of ticketIds) {
const ticket: any = await Ticket.findByPk(ticketId);
if(ticket){
const { status } = ticket;
if (status == "pending") {
if (status && status == "pending") {
await UpdateTicketService({
ticketData: { statusChatEnd: uuidv4() },
ticketId: ticket.id

View File

@ -3,6 +3,9 @@ import { Server } from "http";
import AppError from "../errors/AppError";
import { logger } from "../utils/logger";
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from 'redis';
import { v4 as uuidv4 } from "uuid";
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
import {
@ -27,6 +30,7 @@ import {
} from "../services/WbotServices/wbotMessageListener";
import { join } from "path";
import Whatsapp from "../models/Whatsapp";
import { get } from "../helpers/RedisClient"
let count: number = 0;
let listOnline: any[] = [];
@ -42,16 +46,32 @@ let dateTime = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
);
const pubClient = createClient({ url: 'redis://172.31.187.29:6379' });
const subClient = pubClient.duplicate();
pubClient.connect().catch(console.error);
subClient.connect().catch(console.error);
export const initIO = (httpServer: Server): SocketIO => {
io = new SocketIO(httpServer, {
cors: {
origin: process.env.FRONTEND_URL
origin: process.env.FRONTEND_URL,
//allowedHeaders: ["my-custom-header"],
//credentials: true
},
maxHttpBufferSize: 1e8
maxHttpBufferSize: 1e8,
// pingInterval: 25000,
// pingTimeout: 60000,
// adapter: createAdapter(pubClient, subClient)
});
io.on("connection", socket => {
//logger.info("Client Connected");
logger.info("Client Connected");
socket.on("joinWhatsSession", (whatsappId: string) => {
//logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`);
@ -107,6 +127,7 @@ export const initIO = (httpServer: Server): SocketIO => {
socket.on("online", (userId: any) => {
// console.log('userId: ', userId)
return
obj.uuid = uuidv4();
if (userId.logoutUserId) {
@ -233,13 +254,18 @@ export const initIO = (httpServer: Server): SocketIO => {
if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_"))
return;
let whatsappIds: any = await Whatsapp.findAll({
attributes: ["id"],
raw: true
let whatsappIds = await get({
key: "whatsapp:*",
parse: true
});
// let whatsappIds: any = await Whatsapp.findAll({
// attributes: ["id"],
// raw: true
// });
if (whatsappIds && whatsappIds.length > 0) {
whatsappIds = whatsappIds.map((e: any) => `${e.id}`);
// whatsappIds = whatsappIds.map((e: any) => `${e.id}`);
console.log(
"whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ",

View File

@ -1,5 +1,6 @@
import { getIO } from "../../libs/socket";
import Contact from "../../models/Contact";
const { Op } = require('sequelize');
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
import { tr } from "date-fns/locale";
@ -35,15 +36,37 @@ const CreateOrUpdateContactService = async ({
const io = getIO();
let contact: Contact | null;
const firstFourDigits = number.slice(0, 4);
const lastEightDigits = number.slice(-8);
contact = await Contact.findOne({ where: { number } });
//const numberFormat = number?.length === 13 && number[4] == '9' ? number.slice(0, 4) + number.slice(0, 4) : number;
//contact = await Contact.findOne({ where: { number } });
contact = await Contact.findOne({
where: {
[Op.and]: [
{
number: {
[Op.like]: `%${firstFourDigits}%`
}
},
{
number: {
[Op.like]: `%${lastEightDigits}%`
}
}
]
}
});
if (contact) {
contact.update({ profilePicUrl });
// TEST DEL
if(contact.number == number){
contact.update({ profilePicUrl });
await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl })
//
} else{
contact.update({ profilePicUrl, number });
await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl, number })
}
io.emit("contact", {
action: "update",

View File

@ -101,8 +101,6 @@ const FindOrCreateTicketServiceBot = async (
unreadMessages
});
console.log("lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
await dialogFlowStartContext(contact, ticket, botInfo);
}
}
@ -128,8 +126,6 @@ const FindOrCreateTicketServiceBot = async (
phoneNumberId
});
console.log("yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy");
await dialogFlowStartContext(contact, ticket, botInfo);
}

View File

@ -613,6 +613,15 @@ const transferTicket = async (
} else if (typeof queueName == "number") {
queue = queues[queueName];
}
const whatsapp: any = await whatsappInfo(ticket?.whatsappId);
const outService = await outOfService(whatsapp?.number);
if (outService.length > 0) {
const { type, msg: msgOutService } = outService[0];
console.log(`${type} message ignored on queue`);
botSendMessage(ticket, `\u200e${msgOutService}`);
return;
}
if (queue) {
await assingContactByQueue(ticket, queue.id);
@ -752,8 +761,6 @@ const handleMessage = async (
// console.log('----------> chat: ', JSON.parse(JSON.stringify(chat)))
console
if (chat.isGroup) {
// let msgGroupContact;
@ -1235,7 +1242,11 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any, ticket:
let option = data.find((o: any) => o.id == currentMenu[3]);
response = data.find((o: any) => o.id == option.idnext);
if (response) response.value = `Seja bem-vindo(a) ao WhatsApp Gertec.\nQual o seu nome?`;
if (response){
const whatsapp = await whatsappCache(ticket.whatsappId);
if (whatsapp.number === '551121736500') response.value = `Seja bem-vindo(a) ao WhatsApp Gertec.\nQual o seu nome?`;
else response.value = `Seja bem-vindo(a) ao WhatsApp GéRun.\nQual o seu nome?`;
}
}else response = data.find((o: any) => o.idmaster == menuOption.id);
if (response) {

View File

@ -43,7 +43,7 @@
"yup": "^0.32.8"
},
"scripts": {
"start": "react-scripts start",
"start": "PORT=3331 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

View File

@ -45,7 +45,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
const ResponsiveTimePickers = (props) => {
@ -63,7 +63,7 @@ const ResponsiveTimePickers = (props) => {
<Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}>
<TimePicker
variant="outline"
label={props.title}

View File

@ -11,6 +11,7 @@ import { TimePicker, DatePicker } from 'formik-material-ui-pickers'
import DateFnsUtils from '@date-io/date-fns'
import ptBrLocale from "date-fns/locale/pt-BR"
import esLocale from 'date-fns/locale/es';
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
@ -257,7 +258,7 @@ const ConfigModal = ({ open, onClose, change }) => {
}}
>
{({ values, touched, errors, isSubmitting }) => (
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}>
<Form>
<DialogContent dividers>
@ -299,7 +300,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field
component={TimePicker}
name="startTimeBus"
label="Inicio atendimento"
label={i18n.t('configModal.titles.startService')}
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
@ -309,7 +310,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field
component={TimePicker}
name="endTimeBus"
label="Fim atendimento"
label={i18n.t('configModal.titles.endService')}
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
@ -325,13 +326,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.businessTimeEnable}
/>
}
label={'Ativar/Desativar'} />
label={i18n.t('configModal.titles.enableDisable')} />
</div>
<div>
<Field
as={TextField}
label={'Mensagem fora do horário de atendimento'}
label={i18n.t('configModal.titles.outOfHours')}
type="messageBus"
multiline
rows={5}
@ -355,7 +356,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field
component={TimePicker}
name="startTimeBusSaturday"
label="Inicio atendimentos"
label={i18n.t('configModal.titles.startService')}
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
@ -365,7 +366,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field
component={TimePicker}
name="endTimeBusSaturday"
label="Fim atendimento"
label={i18n.t('configModal.titles.endService')}
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
@ -381,13 +382,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.businessTimeEnableSaturday}
/>
}
label={'Ativar/Desativar'} />
label={i18n.t('configModal.titles.enableDisable')} />
</div>
<div>
<Field
as={TextField}
label={'Mensagem fora do horário de atendimento sábado'}
label={i18n.t('configModal.titles.outOfHoursSaturday')}
type="messageBusSaturday"
multiline
rows={5}
@ -430,13 +431,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.enableWeekendMessage}
/>
}
label={'Ativar/Desativar'}
label={i18n.t('configModal.titles.enableDisable')}
/>
</div>
<div>
<Field
as={TextField}
label={'Mensagem para final de semana'}
label={i18n.t('configModal.titles.forTheWeekend')}
type="weekendMessage"
multiline
rows={5}
@ -461,7 +462,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field
component={DatePicker}
name="holidayDate"
label="Data do feriado"
label={i18n.t('configModal.titles.holiday')}
format="dd/MM/yyyy"
fullWidth
/>
@ -475,13 +476,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.holidayDateEnable}
/>
}
label={'Ativar/Desativar'}
label={i18n.t('configModal.titles.enableDisable')}
/>
</div>
<div>
<Field
as={TextField}
label={'Mensagem para feriado'}
label={i18n.t('configModal.titles.holidayMessage')}
type="holidayDateMessage"
multiline
rows={5}
@ -524,13 +525,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.ticketExpirationEnable}
/>
}
label={'Ativar/Desativar'}
label={i18n.t('configModal.titles.enableDisable')}
/>
</div>
<div>
<Field
as={TextField}
label={'Mensagem por falta de atividade no atendimento'}
label={i18n.t('configModal.titles.inactivityMessage')}
type="ticketExpirationMsg"
multiline
rows={5}
@ -569,7 +570,7 @@ const ConfigModal = ({ open, onClose, change }) => {
size={24}
className={classes.buttonProgress}
/>
) : 'Salvar'}
) : i18n.t('configModal.titles.save')}
</Button>
</DialogActions>
</Form>

View File

@ -199,7 +199,7 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
style={{
background: id !== itemHover ? "white" : color,
}}
>{name[0].toUpperCase() + name.slice(1).toLowerCase()}</MenuItem>
>{name}</MenuItem>
))}
</Select>
</FormControl>

View File

@ -23,6 +23,8 @@ import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import ErrorIcon from "@material-ui/icons/Error";
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
import { i18n } from "../../translate/i18n";
const CardUser = ({ classes, usersOnlineInfo, logout }) => {
const [search, setSearch] = React.useState("");
@ -46,14 +48,14 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
color="primary"
style={{ marginBottom: "16px" }}
>
Lista de Usuários
{i18n.t('dashboard.titles.listUser')}
</Typography>
</Grid>
<Grid item sx={8} width="100%">
<Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}>
<TextField
id="outlined-basic"
label="Usuário"
label={i18n.t('dashboard.titles.user')}
variant="standard"
value={search}
onChange={handlesearch}
@ -70,7 +72,7 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
<MenuItem value={null}>Todos</MenuItem>
<MenuItem value={"online"}>Online</MenuItem>
<MenuItem value={"offline"}>Offline</MenuItem>
<MenuItem value={"not"}>Não entrou</MenuItem>
<MenuItem value={"not"}>{i18n.t('dashboard.titles.notEnter')}</MenuItem>
</Select>
</FormControl>
</Box>
@ -161,7 +163,7 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
<Typography component="p" color="textPrimary" paragraph>
{user.sumOnlineTime && user.sumOnlineTime.sum
? user.sumOnlineTime.sum
: "Não entrou Hoje"}
: i18n.t('dashboard.titles.notEnterToday')}
</Typography>
</Typography>
</CardContent>

View File

@ -75,7 +75,7 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
<MenuItem value={null}>Todos</MenuItem>
<MenuItem value={"online"}>Online</MenuItem>
<MenuItem value={"offline"}>Offline</MenuItem>
<MenuItem value={"not"}>Não entrou</MenuItem>
<MenuItem value={"not"}>{i18n.t('dashboard.titles.notEnter')}</MenuItem>
</Select>
</FormControl>
</Box>
@ -221,7 +221,7 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
</div>
</TableCell>
<TableCell>
{user.sumOnlineTime ? user.sumOnlineTime.sum : "Não entrou"}
{user.sumOnlineTime ? user.sumOnlineTime.sum : i18n.t('dashboard.titles.notEnter')}
</TableCell>
<TableCell>
{user.statusOnline && user.statusOnline.status === "online" ? (

View File

@ -1,7 +1,9 @@
import React, { useContext, useState, useEffect, useReducer, useRef } from "react"
import { isSameDay, parseISO, format } from "date-fns"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import clsx from "clsx"
import { AuthContext } from "../../context/Auth/AuthContext"
@ -438,11 +440,18 @@ const MessagesList = ({ ticketId, isGroup }) => {
}, [pageNumber, ticketId])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("connect", () => socket.emit("joinChatBox", ticketId))
const onConnectMessagesList = () => {
socket.emit("joinChatBox", ticketId)
}
socket.on("appMessage", (data) => {
onConnectMessagesList()
socket.on("connect", onConnectMessagesList)
const onAppMessageMessagesList = (data) => {
if (+data.message.ticketId !== +ticketId) return
if (data.action === "create") {
@ -454,10 +463,14 @@ const MessagesList = ({ ticketId, isGroup }) => {
if (data.action === "update") {
dispatch({ type: "UPDATE_MESSAGE", payload: data.message })
}
})
}
socket.on("appMessage", onAppMessageMessagesList)
return () => {
socket.disconnect()
socket.emit("leaveChatBox", ticketId)
socket.off("connect", onConnectMessagesList)
socket.off("appMessage", onAppMessageMessagesList)
}
}, [ticketId])

View File

@ -13,7 +13,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDateDatePicker(data){
return String(new Date(data).getFullYear())+'-'+
@ -50,7 +50,7 @@ function ResponsiveDatePickers(props) {
return (
<Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}>
<KeyboardDatePicker
// autoOk

View File

@ -45,7 +45,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDate(strDate){
const date = strDate.split(' ')[0].split('/')
@ -70,7 +70,7 @@ const ResponsiveTimePickers = (props) => {
<Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}>
<TimePicker
variant="outline"
label={props.title}

View File

@ -2,7 +2,8 @@ import React, { useState, useRef, useEffect, useContext } from "react"
import { useHistory } from "react-router-dom"
import { format } from "date-fns"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import useSound from "use-sound"
import Popover from "@material-ui/core/Popover"
@ -132,7 +133,7 @@ const NotificationsPopOver = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("reload_page", (data) => {
@ -193,7 +194,8 @@ const NotificationsPopOver = () => {
return () => {
socket.disconnect()
socket.removeAllListeners('reload_page');
socket.removeAllListeners('onlineStatus');
}
}, [user.id, handleLogout, user.profile])
@ -201,12 +203,17 @@ const NotificationsPopOver = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("connect", () => socket.emit("joinNotification"))
const onConnectNotifications = () => {
socket.emit("joinNotification")
}
onConnectNotifications()
socket.on("ticket", data => {
socket.on("connect", onConnectNotifications)
const onTicketNotifications = data => {
if (data.action === "updateUnread" || data.action === "delete") {
@ -232,25 +239,18 @@ const NotificationsPopOver = () => {
return prevState
})
}
})
socket.on("appMessage", data => {
}
socket.on("ticket", onTicketNotifications)
const onAppMessageNotifications = data => {
if (
data.action === "create" &&
!data.message.read &&
(data.ticket.userId === user?.id || !data.ticket.userId)
) {
setNotifications(prevState => {
// prevState.forEach((e)=>{
//
// })
@ -265,8 +265,6 @@ const NotificationsPopOver = () => {
return [data.ticket, ...prevState]
})
const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") ||
(data.ticket.userId && data.ticket.userId !== user?.id) ||
data.ticket.isGroup || !data.ticket.userId
@ -275,20 +273,25 @@ const NotificationsPopOver = () => {
handleNotifications(data)
}
})
}
socket.on('notifyPeding', data =>{
if(settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data);
socket.on("appMessage", onAppMessageNotifications)
socket.on('notifyPeding', data => {
if (settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data);
});
return () => {
socket.disconnect()
socket.off('connect', onConnectNotifications);
socket.off('ticket', onTicketNotifications);
socket.off('appMessage', onAppMessageNotifications);
socket.removeAllListeners('notifyPeding');
}
}, [user, settings])
const handleNotifications = (data, notify) => {
let isQueue = false;
if(!notify){
if (!notify) {
const { message, contact, ticket } = data
const options = {
@ -319,15 +322,15 @@ const NotificationsPopOver = () => {
}
return [notification, ...prevState]
})
}else{
user.queues.forEach(queue =>{
if(queue.id === notify.data?.queue?.id){
} else {
user.queues.forEach(queue => {
if (queue.id === notify.data?.queue?.id) {
isQueue = true;
}
})
if(!isQueue){
if (!isQueue) {
return;
}else {
} else {
const notification = new Notification(`${i18n.t("tickets.notification.messagePeding")} ${notify.data?.queue?.name}`);
notification.onclick = e => {
e.preventDefault()

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup"
import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify"
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import {
makeStyles,
@ -87,9 +87,9 @@ const PositionModal = ({
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsPosition = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -98,10 +98,12 @@ const PositionModal = ({
return aux
})
}
})
}
socket.on('settings', onSettingsPosition)
return () => {
socket.disconnect()
socket.off("settings", onSettingsPosition)
}
}, [])
@ -191,7 +193,7 @@ const PositionModal = ({
<div className={classes.textQuickAnswerContainer}>
<Field
as={TextField}
label={'Nome'}
label={i18n.t('dashboard.titles.name')}
name="name"
autoFocus
error={touched.name && Boolean(errors.name)}

View File

@ -1,6 +1,8 @@
import React, { useEffect, useState, useContext } from "react";
import QRCode from "qrcode.react";
import openSocket from "socket.io-client";
//import openSocket from "socket.io-client";
import { socket } from "../../services/socket";
import toastError from "../../errors/toastError";
import { Dialog, DialogContent, Paper, Typography } from "@material-ui/core";
@ -31,9 +33,9 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => {
useEffect(() => {
if (!whatsAppId) return;
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
socket.on("whatsappSession", data => {
const onWhatsAppSessionQrCode = data => {
if (data.action === "update" && data.session.id === whatsAppId) {
setQrCode(data.session.qrcode);
}
@ -46,17 +48,19 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => {
console.log('user.profile: ', user.profile)
if(user.profile === 'master'){
if (user.profile === 'master') {
alert(data.msg)
}
}
});
}
socket.on("whatsappSession", onWhatsAppSessionQrCode);
return () => {
socket.disconnect();
socket.off("whatsappSession", onWhatsAppSessionQrCode);
};
}, [whatsAppId, onClose, user.profile]);

View File

@ -23,8 +23,8 @@ import { IconButton, InputAdornment } from "@material-ui/core"
import { Colorize } from "@material-ui/icons"
import { AuthContext } from '../../context/Auth/AuthContext'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
const useStyles = makeStyles(theme => ({
@ -92,9 +92,9 @@ const QueueModal = ({ open, onClose, queueId }) => {
}, [setting])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsQueueModal = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -103,10 +103,12 @@ const QueueModal = ({ open, onClose, queueId }) => {
return aux
})
}
})
}
socket.on('settings', onSettingsQueueModal)
return () => {
socket.disconnect()
socket.off("settings", onSettingsQueueModal)
}
}, [])

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup"
import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify"
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import {
makeStyles,
@ -101,9 +101,9 @@ const QuickAnswersModal = ({
}, [open,])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsQuickAnswersModal = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -112,10 +112,12 @@ const QuickAnswersModal = ({
return aux
})
}
})
}
socket.on('settings', onSettingsQuickAnswersModal)
return () => {
socket.disconnect()
socket.off("settings", onSettingsQuickAnswersModal)
}
}, [])

View File

@ -15,7 +15,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDateDatePicker(data){
return String(new Date(data).getFullYear())+'-'+
@ -52,7 +52,7 @@ function ResponsiveDatePickers(props) {
return (
<Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}>
<KeyboardDatePicker
// autoOk

View File

@ -52,7 +52,7 @@ const Modal = (props) => {
const dataChat = props.data.map((dt) => {
return {
'fromMe': dt.fromMe ? 'Atendente' : 'Cliente',
'fromMe': dt.fromMe ? i18n.t('dashboard.titles.attendant') : 'Cliente',
'body': dt.body,
'createdAt': dt.createdAt
}

View File

@ -12,6 +12,7 @@ import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import { i18n } from "../../translate/i18n";
@ -56,11 +57,11 @@ useEffect(()=>{
open={open}
onClose={handleClose}
>
<DialogTitle>Relatórios</DialogTitle>
<DialogTitle>{i18n.t('dashboard.titles.dialogTitle')}</DialogTitle>
<DialogContent>
<DialogContentText>
Escolha uma opção de relatório abaixo
{i18n.t('dashboard.titles.dialogContentText')}
</DialogContentText>
<Box

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup"
import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify"
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import {
makeStyles,
@ -91,9 +91,9 @@ const StatusChatEndModal = ({
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsStatusChatEndModal = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -102,10 +102,12 @@ const StatusChatEndModal = ({
return aux
})
}
})
}
socket.on('settings', onSettingsStatusChatEndModal)
return () => {
socket.disconnect()
socket.off("settings", onSettingsStatusChatEndModal)
}
}, [])

View File

@ -2,7 +2,9 @@ import React, { useState, useEffect } from "react"
import { useParams, useHistory } from "react-router-dom"
import { toast } from "react-toastify"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import clsx from "clsx"
import { Paper, makeStyles } from "@material-ui/core"
@ -132,22 +134,32 @@ const Ticket = () => {
}, [])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("connect", () => socket.emit("joinChatBox", ticketId))
const onConnectTicket = () => socket.emit("joinChatBox", ticketId)
onConnectTicket()
socket.on("connect", onConnectTicket)
const onTicketTicket = (data) => {
const isSameTicket = +data?.ticket?.id === +ticketId || +data.ticketId === +ticketId
if (!isSameTicket) return
socket.on("ticket", (data) => {
if (data.action === "update") {
setTicket(data.ticket)
}
if (data.action === "delete") {
if (data.action === "deleteForever") {
console.log('delete forever')
toast.success("Ticket deleted sucessfully.")
history.push("/tickets")
}
})
}
socket.on("contact", (data) => {
socket.on("ticket", onTicketTicket)
const onContactTicket = (data) => {
if (data.action === "update") {
setContact((prevState) => {
if (prevState.id === data.contact?.id) {
@ -156,9 +168,11 @@ const Ticket = () => {
return prevState
})
}
})
}
socket.on("remoteTickesControllIdleOpen", (data) => {
socket.on("contact", onContactTicket)
const onRemoteTicketsControllIdleOpenTicket = (data) => {
if (data.action === "update") {
let url_ticketId
try {
@ -175,10 +189,15 @@ const Ticket = () => {
console.log('error on try do the send seen: ', error)
}
}
})
}
socket.on("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket)
return () => {
socket.disconnect()
socket.off("connect", onConnectTicket)
socket.off("ticket", onTicketTicket)
socket.off("contact", onContactTicket)
socket.off("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket)
}
}, [ticketId, history])

View File

@ -22,7 +22,8 @@ import MarkdownWrapper from "../MarkdownWrapper"
import { Tooltip } from "@material-ui/core"
import { AuthContext } from "../../context/Auth/AuthContext"
import toastError from "../../errors/toastError"
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
const useStyles = makeStyles(theme => ({
ticket: {
@ -151,17 +152,18 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('remoteTickesControll', (data) => {
const onRemoteTickesControllTicketListItem = (data) => {
console.log('REMOTE TICKETS CONTROLL UPDATE2: ', data.tickets)
if (data.action === 'update') {
setRemoteTicketsControll(data.tickets)
}
})
}
socket.on('remoteTickesControll', onRemoteTickesControllTicketListItem)
socket.on('settings', (data) => {
const onSettingsTicketListItem = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -170,11 +172,13 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => {
return aux
})
}
})
}
socket.on('settings', onSettingsTicketListItem)
return () => {
socket.disconnect()
socket.off('remoteTickesControll', onRemoteTickesControllTicketListItem);
socket.off('settings', onSettingsTicketListItem);
}
}, [])

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useReducer, useContext } from "react"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { makeStyles } from "@material-ui/core/styles"
import List from "@material-ui/core/List"
@ -243,27 +243,29 @@ const TicketsList = (props) => {
// if (tab=='search')return
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const shouldUpdateTicket = ticket =>
(status === ticket.status) &&
(!ticket.userId || ticket.userId === user?.id || showAll) &&
(!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1)
const notBelongsToUserQueues = ticket =>
ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1
socket.on("connect", () => {
const onConnectTicketList = () => {
if (status) {
socket.emit("joinTickets", status)
} else {
socket.emit("joinNotification")
}
}
})
onConnectTicketList()
socket.on("connect", onConnectTicketList)
socket.on("ticket", data => {
const onTicketTicketList = data => {
if (data.action === "updateUnread") {
@ -292,10 +294,11 @@ const TicketsList = (props) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_TICKET", payload: data.ticketId })
}
})
}
socket.on("ticket", onTicketTicketList)
socket.on("appMessage", data => {
const onAppMessageTicketList = data => {
if (data.action === "create" && shouldUpdateTicket(data.ticket)) {
@ -307,7 +310,9 @@ const TicketsList = (props) => {
payload: data,
})
}
})
}
socket.on("appMessage", onAppMessageTicketList)
socket.on("contact", data => {
if (data.action === "update") {
@ -318,16 +323,16 @@ const TicketsList = (props) => {
}
})
socket.on('remoteTickesControll', (data) => {
const onRemoteTickesControllTicketList = (data) => {
console.log('REMOTE TICKETS CONTROLL UPDATE 1: ', data.tickets)
if (data.action === 'update') {
setRemoteTicketsControll(data.tickets)
}
})
}
socket.on('remoteTickesControll', onRemoteTickesControllTicketList)
socket.on('settings', (data) => {
const onSettingsTicketList = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -336,11 +341,17 @@ const TicketsList = (props) => {
return aux
})
}
})
}
socket.on('settings', onSettingsTicketList)
return () => {
socket.disconnect()
socket.off("ticket", onTicketTicketList)
socket.off('appMessage', onAppMessageTicketList);
socket.removeAllListeners("contact")
socket.off('connect', onConnectTicketList);
socket.off('settings', onSettingsTicketList);
socket.off('remoteTickesControll', onRemoteTickesControllTicketList);
}
}, [status, showAll, user, selectedQueueIds, tab])
@ -349,7 +360,7 @@ const TicketsList = (props) => {
if (typeof updateCount === "function") {
updateCount(ticketsList.length)
}
if (ticketsList && status === "pending"){
if (ticketsList && status === "pending") {
setTickets(ticketsList)
}
// else{

View File

@ -19,7 +19,6 @@ import FindInPageIcon from '@material-ui/icons/FindInPage'
import FormControlLabel from "@material-ui/core/FormControlLabel"
import Switch from "@material-ui/core/Switch"
import openSocket from "socket.io-client"
import NewTicketModal from "../NewTicketModal"
import TicketsList from "../TicketsList"
@ -153,7 +152,7 @@ const TicketsManager = () => {
const [openCount, setOpenCount] = useState(0)
const [pendingCount, setPendingCount] = useState(0)
const userQueueIds = user.queues.map((q) => q.id)
const userQueueIds = user?.queues?.map((q) => q?.id)
const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || [])
const [showContentSearch, setShowContentSearch] = useState(false)
@ -178,9 +177,9 @@ const TicketsManager = () => {
}, [setting])
useEffect(() => {
if (user.profile.toUpperCase() === "ADMIN" ||
user.profile.toUpperCase() === "SUPERVISOR" ||
user.profile.toUpperCase() === "MASTER") {
if (user?.profile?.toUpperCase() === "ADMIN" ||
user?.profile?.toUpperCase() === "SUPERVISOR" ||
user?.profile?.toUpperCase() === "MASTER") {
setShowAllTickets(true)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -203,11 +202,11 @@ const TicketsManager = () => {
if (tickets.length > 0) {
const now = new Date()
const differenceTime = tickets?.map(ticket => {
const createdAt = new Date(ticket.createdAt)
const createdAt = new Date(ticket?.createdAt)
const difference = now - createdAt
return difference
})
const sumDifferences = differenceTime.reduce((total, difference) => total + difference, 0)
const sumDifferences = differenceTime?.reduce((total, difference) => total + difference, 0)
const averageTimeMilliseconds = sumDifferences / tickets?.length
let hours = Math.floor(averageTimeMilliseconds / 3600000)
const minutes = Math.floor((averageTimeMilliseconds % 3600000) / 60000)

View File

@ -1,6 +1,7 @@
import React, { useState, useContext, useMemo, useEffect } from "react"
import { useHistory } from "react-router-dom"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import Button from "@material-ui/core/Button"
import Dialog from "@material-ui/core/Dialog"
@ -71,7 +72,12 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
if (!whatsApps) return []
const whatsAppsQueues = whatsApps.map(({ queues }) => queues)
//const whatsAppsQueues = whatsApps.filter(({ status }) => status === "CONNECTED" ).map(({ queues }) => queues)
const uniqueQueuesAvailable = queueArraysToOneArray(whatsAppsQueues)
const uniqueQueuesAvailable = queueArraysToOneArray(whatsAppsQueues);
uniqueQueuesAvailable.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
return uniqueQueuesAvailable
}, [whatsApps])
@ -91,6 +97,11 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
const { id, color, name } = q
return { id, color, name }
})
userQueues.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
setQueues(userQueues)
setSelectedQueue('')
@ -110,9 +121,9 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsTransferTicketModal = (data) => {
console.log('settings updated ----------------------------xxxxxxxxxxxx')
if (data.action === 'update') {
@ -123,10 +134,12 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
return aux
})
}
})
}
socket.on('settings', onSettingsTransferTicketModal)
return () => {
socket.disconnect()
socket.off("settings", onSettingsTransferTicketModal)
}
}, [])
@ -194,7 +207,16 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
const { data } = await api.get(`/users/all`, {
params: { userId: user.id },
})
data.queues.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
data.users.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
setUsers(data.users)
setQueuesByWhats(data.queues)
setQueues(data.queues)
@ -205,6 +227,12 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
params: { profile: 'user', transferToOtherQueues: user.transferToOtherQueues },
})
data.users.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
});
setUsers(data.users)
setQueues(_queues2)
}
@ -228,7 +256,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
{i18n.t("transferTicketModal.title")}
</DialogTitle>
<DialogContent dividers >
<FormControl variant="outlined" className={classes.maxWidth} style={{marginBottom: '8px'}}>
<FormControl variant="outlined" className={classes.maxWidth} style={{ marginBottom: '8px' }}>
{/* <InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel> */}
<InputLabel>{'Usuário'}</InputLabel>
@ -259,7 +287,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
required
>
<MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem>
{queues.map((queue) => (
{queues?.map((queue) => (
<MenuItem
key={queue.id}
value={queue.id}

View File

@ -262,7 +262,7 @@ const UserModal = ({ open, onClose, userId, }) => {
/>
<div className={classes.multFieldLine}>
<label style={{display: 'flex', alignItems:'center'}}>
Transferir para outras filas
{i18n.t('dashboard.titles.transfer')}
<Switch
name= 'transferToOtherQueues'
checked={checked}

View File

@ -1,6 +1,7 @@
import { useState, useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { toast } from 'react-toastify'
@ -62,7 +63,7 @@ const useAuth = () => {
useEffect(() => {
const token = localStorage.getItem('token')
;(async () => {
; (async () => {
if (token) {
try {
const { data } = await api.post('/auth/refresh_token')
@ -90,7 +91,7 @@ const useAuth = () => {
}, [])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('user', (data) => {
if (data.action === 'update' && data.user.id === user.id) {
@ -98,7 +99,7 @@ const useAuth = () => {
}
})
socket.on('settings', (data) => {
const onSettingsAuth = (data) => {
if (data.action === 'update') {
setSetting((prevState) => {
const aux = [...prevState]
@ -107,10 +108,13 @@ const useAuth = () => {
return aux
})
}
})
}
socket.on('settings', onSettingsAuth)
return () => {
socket.disconnect()
socket.removeAllListeners('user');
socket.off('settings', onSettingsAuth);
}
}, [user])

View File

@ -1,5 +1,7 @@
import { useState, useEffect, useReducer } from "react";
import openSocket from "socket.io-client";
//import openSocket from "socket.io-client";
import { socket } from "../../services/socket";
import toastError from "../../errors/toastError";
@ -126,7 +128,7 @@ const useWhatsApps = () => {
}, []);
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
socket.on("whatsapp", data => {
if (data.action === "update") {
@ -158,7 +160,9 @@ const useWhatsApps = () => {
return () => {
socket.disconnect();
socket.removeAllListeners('whatsapp');
socket.removeAllListeners('whatsappSession');
socket.removeAllListeners('whatsappSessionMonit');
};
}, []);

View File

@ -31,7 +31,8 @@ import { i18n } from '../translate/i18n'
import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext'
import { AuthContext } from '../context/Auth/AuthContext'
import { Can } from '../components/Can'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../services/socket'
import api from '../services/api'
@ -118,9 +119,9 @@ const MainListItems = (props) => {
}
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsMainListItem = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -129,10 +130,12 @@ const MainListItems = (props) => {
return aux
})
}
})
}
socket.on('settings', onSettingsMainListItem)
return () => {
socket.disconnect()
socket.off('settings', onSettingsMainListItem);
}
}, [])
@ -189,7 +192,7 @@ const MainListItems = (props) => {
/>
<ListItemLink
to="/report"
primary="Relatório"
primary={i18n.t("mainDrawer.listItems.reports")}
icon={<ReportOutlinedIcon />}
/>
</>
@ -242,7 +245,7 @@ const MainListItems = (props) => {
(getSettingValue('hasCampaign') === 'enabled' || user.profile === 'master') && (
<ListItemLink
to="/campaign"
primary="Campanha"
primary={i18n.t("mainDrawer.listItems.campaign") || 'Campaign'}
icon={<CampaignIcon />}
/>
)

View File

@ -1,7 +1,8 @@
import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react'
import { toast } from 'react-toastify'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors'
@ -296,10 +297,9 @@ const Campaign = () => {
}
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
const onContactsBulkCampaing = (data) => {
if (data.action === 'update') {
if (String(data.insertOnQueue.adminId) === String(user.id)) {
@ -312,19 +312,24 @@ const Campaign = () => {
}
}
})
}
socket.on('campaign', (data) => {
socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing)
const onCampaignCampaign = (data) => {
if (data.action === 'update') {
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
}
})
}
socket.on('campaign', onCampaignCampaign)
return () => {
socket.disconnect()
socket.off("campaign", onCampaignCampaign)
socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing)
}
}, [user.id])

View File

@ -2,7 +2,8 @@ import React, { useState, useCallback, useEffect, useContext } from 'react'
import { toast } from 'react-toastify'
import { format, parseISO } from 'date-fns'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { makeStyles } from '@material-ui/core/styles'
import { green, red, yellow, grey } from '@material-ui/core/colors'
@ -451,15 +452,17 @@ const Connections = () => {
}, [])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('diskSpaceMonit', (data) => {
const onDiskSpaceMonitConnections = (data) => {
if (data.action === 'update') {
setDiskSpaceInfo(data.diskSpace)
}
})
}
socket.on('settings', (data) => {
socket.on('diskSpaceMonit', onDiskSpaceMonitConnections)
const onSettingsConnections = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -468,10 +471,13 @@ const Connections = () => {
return aux
})
}
})
}
socket.on('settings', onSettingsConnections)
return () => {
socket.disconnect()
socket.off("settings", onSettingsConnections)
socket.off("diskSpaceMonit", onDiskSpaceMonitConnections)
}
}, [])

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect, useReducer, useCallback, useContext } from "react"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { toast } from "react-toastify"
import { useHistory } from "react-router-dom"
@ -260,9 +261,9 @@ const Contacts = () => {
}, [searchParam, pageNumber])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
const onContactsBulkContacts = (data) => {
if (data.action === 'update') {
if (String(data.insertOnQueue.adminId) === String(user.id)) {
@ -278,9 +279,11 @@ const Contacts = () => {
}
}
})
}
socket.on("contact", (data) => {
socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkContacts)
const onContactContacts = (data) => {
if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact })
}
@ -288,10 +291,13 @@ const Contacts = () => {
if (data.action === "delete") {
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId })
}
})
}
socket.on("contact", onContactContacts)
return () => {
socket.disconnect()
socket.off("contact", onContactContacts)
socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkContacts)
}
}, [user, history])

View File

@ -5,6 +5,8 @@ import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip }
import Title from './Title';
import { i18n } from "../../translate/i18n";
const generateDataExample = (amount) => {
const arr = []
for (let i = 1; i <= amount; i++) {
@ -76,7 +78,7 @@ const PieChart = ({ data = dataExample }) => {
>
<Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
<Box sx={{ position: "absolute" }}>
<Title>Tickets encerramento</Title>
<Title>{i18n.t('dashboard.titles.title')}</Title>
</Box>
<ResponsiveContainer width="100%" height="100%">
<RechartsPieChart width={400} height={400}>

View File

@ -14,10 +14,11 @@ import Info from "@material-ui/icons/Info"
import SelectField from "../../components/Report/SelectField"
import { AuthContext } from "../../context/Auth/AuthContext"
// import { i18n } from "../../translate/i18n";
import { i18n } from "../../translate/i18n";
import Chart from "./Chart"
import PieChart from "./PieChart"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import api from "../../services/api"
import { Can } from "../../components/Can"
@ -356,46 +357,54 @@ const Dashboard = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("ticketStatus", (data) => {
const onTicketsStatusDashboard = (data) => {
if (data.action === "update") {
setStatus("")
setStatus(data.ticketStatus.status)
}
})
}
socket.on("onlineStatus", (data) => {
socket.on("ticketStatus", onTicketsStatusDashboard)
const onOnlineStatusDashboard = (data) => {
if (data.action === "logout" || data.action === "update") {
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
} else if (data.action === "delete") {
dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
}
})
}
socket.on("user", (data) => {
socket.on("onlineStatus", onOnlineStatusDashboard)
const onUserDashboard = (data) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
})
}
socket.on("user", onUserDashboard)
return () => {
socket.disconnect()
socket.off("user", onUserDashboard)
socket.off("onlineStatus", onOnlineStatusDashboard)
socket.off("ticketStatus", onTicketsStatusDashboard)
}
}, [])
const handleSelectedQueue = useCallback((queueSelected) => {
if(queueSelected !== 'All'){
if (queueSelected !== 'All') {
const queueIndex = user?.queues?.findIndex((q) => q.id === parseInt(queueSelected));
const queueIds = []
queueIds.push(user?.queues[queueIndex]?.id);
setSelectedQueue(queueIds);
}else{
} else {
const queueIds = user?.queues?.map((queue) => queue.id);
setSelectedQueue(queueIds);
}
},[user, setSelectedQueue])
}, [user, setSelectedQueue])
useEffect(() => {
if (ticketStatusChange === "") return
@ -472,7 +481,7 @@ const Dashboard = () => {
func={handleSelectedQueue}
textBoxFieldSelected={'All'}
emptyField={false}
header={'Filas'}
header={i18n.t('dashboard.titles.selectQueues')}
currencies={user.queues.map((obj) => {
return { 'value': obj.id, 'label': obj.name }
})} />
@ -485,7 +494,7 @@ const Dashboard = () => {
variant="outlined"
>
<Typography component="h3" variant="h6" color="primary" paragraph>
Aguardando
{i18n.t('dashboard.titles.waiting')}
</Typography>
<Grid item>
<Typography component="h1" variant="h4">
@ -501,7 +510,7 @@ const Dashboard = () => {
variant="outlined"
>
<Typography component="h3" variant="h6" color="primary" style={{ marginBottom: "0" }} paragraph>
Em Atendimento
{i18n.t('dashboard.titles.inService')}
</Typography>
<Typography paragraph style={{ fontSize: "12px", margin: "0px" }}>Hoje/Todo Periodo</Typography>
@ -520,7 +529,7 @@ const Dashboard = () => {
variant="outlined"
>
<Typography component="h3" variant="h6" color="primary" paragraph>
Fechados
{i18n.t('dashboard.titles.ticketsClosed')}
</Typography>
<Grid item>
<Typography component="h1" variant="h4">
@ -532,7 +541,7 @@ const Dashboard = () => {
<Grid item container spacing={3}>
<Grid item xs={12} sm={12} md={6} lg={6}>
<Paper className={classes.fixedHeightPaper} variant="outlined">
<Chart allTickets={usersOnlineInfo} selectedQueue = {selectedQueue}/>
<Chart allTickets={usersOnlineInfo} selectedQueue={selectedQueue} />
</Paper>
</Grid>
<Grid item xs={12} sm={12} md={6} lg={6}>
@ -551,7 +560,7 @@ const Dashboard = () => {
color="primary"
style={{ marginBottom: "16px" }}
>
Usuários
{i18n.t('dashboard.titles.users')}
<Tooltip
title={`Os dados informados abaixo é baseado na data: ${new Date().toLocaleDateString(
"pt-BR",

View File

@ -1,5 +1,6 @@
import React, { useState, useContext, useEffect, useReducer } from "react"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import {
Button,
@ -125,9 +126,9 @@ const Position = () => {
}, [searchParam, pageNumber])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("position", (data) => {
const onPositionPosition = (data) => {
if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_POSITIONS", payload: data.position })
}
@ -138,10 +139,12 @@ const Position = () => {
payload: +data.positionId,
})
}
})
}
socket.on("position", onPositionPosition)
return () => {
socket.disconnect()
socket.off("position", onPositionPosition)
}
}, [])

View File

@ -1,6 +1,7 @@
import React, { useEffect, useReducer, useState, useContext } from 'react'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import {
Button,
@ -123,9 +124,9 @@ const Queues = () => {
}, [])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('queue', (data) => {
const onQueueQueues = (data) => {
if (data.action === 'update' || data.action === 'create') {
dispatch({ type: 'UPDATE_QUEUES', payload: data.queue })
}
@ -133,9 +134,11 @@ const Queues = () => {
if (data.action === 'delete') {
dispatch({ type: 'DELETE_QUEUE', payload: data.queueId })
}
})
}
socket.on('settings', (data) => {
socket.on('queue', onQueueQueues)
const onSettingsQueues = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -144,10 +147,13 @@ const Queues = () => {
return aux
})
}
})
}
socket.on('settings', onSettingsQueues)
return () => {
socket.disconnect()
socket.off("settings", onSettingsQueues)
socket.off("queue", onQueueQueues)
}
}, [])

View File

@ -1,5 +1,6 @@
import React, { useState, useContext, useEffect, useReducer } from "react"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import {
Button,
@ -125,9 +126,9 @@ const QuickAnswers = () => {
}, [searchParam, pageNumber])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("quickAnswer", (data) => {
const onQuickAnswerQuickAnswers = (data) => {
if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_QUICK_ANSWERS", payload: data.quickAnswer })
}
@ -138,10 +139,11 @@ const QuickAnswers = () => {
payload: +data.quickAnswerId,
})
}
})
}
socket.on("quickAnswer", onQuickAnswerQuickAnswers)
return () => {
socket.disconnect()
socket.off("quickAnswer", onQuickAnswerQuickAnswers)
}
}, [])

View File

@ -18,23 +18,24 @@ import MaterialTable from 'material-table'
import LogoutIcon from '@material-ui/icons/CancelOutlined'
import apiBroker from "../../services/apiBroker"
import fileDownload from 'js-file-download'
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { i18n } from "../../translate/i18n"
import Switch from '@mui/material/Switch'
const label = { inputProps: { 'aria-label': 'Size switch demo' } }
const report = [
{ 'value': '1', 'label': 'Atendimento por atendentes' },
{ 'value': '2', 'label': 'Usuários online/offline' },
{ 'value': '3', 'label': 'Relatorio de atendimento por numeros' },
{ 'value': '4', 'label': 'Relatorio de atendimento por filas' },
{ 'value': '1', 'label': `${i18n.t("reports.listTitles.title1_1")}` },
{ 'value': '2', 'label': `${i18n.t("reports.listTitles.title3_1")}` },
{ 'value': '3', 'label': `${i18n.t("reports.listTitles.title4_1")}` },
{ 'value': '4', 'label': `${i18n.t("reports.listTitles.title5_1")}` },
]
const reportOptType = [
{ 'value': '1', 'label': 'Padrão' },
{ 'value': '2', 'label': 'Sintético' },
{ 'value': '3', 'label': 'Analítico' }
{ 'value': '1', 'label': i18n.t('reportOptType.listTitles.title1') },
{ 'value': '2', 'label': i18n.t('reportOptType.listTitles.title2') },
{ 'value': '3', 'label': i18n.t('reportOptType.listTitles.title3') }
]
@ -591,9 +592,9 @@ const Report = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("queryOnQueueStatus", (data) => {
const onQueryOnQueueStatusReport = (data) => {
if (data.action === 'update') {
if (String(data.queryOnQueue.adminId) === String(userA.id)) {
@ -604,12 +605,11 @@ const Report = () => {
}
}
})
}
if (reportOption === '2') {
socket.on("queryOnQueueStatus", onQueryOnQueueStatusReport)
socket.on("onlineStatus", (data) => {
const onOnlineStatusReport = (data) => {
let date = new Date().toLocaleDateString('pt-BR').split('/')
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
@ -624,15 +624,20 @@ const Report = () => {
dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
}
})
}
socket.on("user", (data) => {
const onUserReport = (data) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
})
}
if (reportOption === '2') {
socket.on("onlineStatus", onOnlineStatusReport)
socket.on("user", onUserReport)
}
else if (reportOption === "1") {
@ -641,7 +646,9 @@ const Report = () => {
}
return () => {
socket.disconnect()
socket.off("onlineStatus", onOnlineStatusReport)
socket.off("user", onUserReport)
socket.off("queryOnQueueStatus", onQueryOnQueueStatusReport)
}
@ -687,7 +694,7 @@ const Report = () => {
const renderSwitch = (param) => {
if(userA.profile !== 'supervisor'){
if (userA.profile !== 'supervisor') {
switch (param) {
case 'empty':
return (
@ -838,11 +845,11 @@ const Report = () => {
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', }}>
<FormControlLabel
control={<Checkbox checked={selectedValue === 'created'} onChange={() => handleCheckBoxChange('created')} />}
label="Criado"
label="Creado"
/>
<FormControlLabel
control={<Checkbox checked={selectedValue === 'updated'} onChange={() => handleCheckBoxChange('updated')} />}
label="Atualizado"
label="Actualizado"
/>
</Box> :
@ -880,7 +887,7 @@ const Report = () => {
<>
<MTable data={query}
columns={userA.profile !== 'supervisor' ? columnsData : columnsDataSuper}
hasChild={userA.profile !== 'supervisor' ? true :false}
hasChild={userA.profile !== 'supervisor' ? true : false}
removeClickRow={false}
handleScroll={handleScroll}
@ -896,7 +903,7 @@ const Report = () => {
localization={{
header: {
actions: 'Deslogar'
actions: 'Unidad'
},
}}
@ -906,7 +913,7 @@ const Report = () => {
[
// { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
{ title: 'Nome', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: 'Nombre', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{
title: 'Status', field: 'statusOnline.status',
@ -935,11 +942,11 @@ const Report = () => {
},
{ title: 'Tempo online', field: 'sumOnlineTime.sum' },
{ title: `${i18n.t('reports.onlineTime')}`, field: 'sumOnlineTime.sum' },
{ title: `${i18n.t("reports.dateStart")}`, field: 'startDate' },
{ title: `${i18n.t("reports.dateEnd")}`, field: 'endDate' },
{ title: 'Em atendimento', field: 'sumOpen.count' },
{ title: 'Finalizado', field: 'sumClosed.count' },
{ title: `${i18n.t('reports.inService')}`, field: 'sumOpen.count' },
{ title: `${i18n.t('reports.finished')}`, field: 'sumClosed.count' },
]
}
@ -1001,20 +1008,20 @@ const Report = () => {
title={i18n.t("reports.listTitles.title4_1")}
columns={
!checkedRemote ? [
{ title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: 'Conversas recebidas', field: 'startedByClient' },
{ title: `Conversas finalizadas`, field: 'closedChat' },
{ title: `Tempo médio de espera`, field: 'avgChatWaitingTime' },
{ title: 'Aguardando', field: 'pendingChat' }
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_6'), field: 'avgChatWaitingTime' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' }
] :
[
{ title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: 'Conversas respondidas', field: 'startedByClient' },
{ title: `Conversas finalizadas`, field: 'closedChat' },
{ title: 'Aguardando', field: 'pendingChat' }
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' }
]
}
@ -1054,9 +1061,9 @@ const Report = () => {
columns={
!checkedRemote ? [
{ title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{
title: 'Fila', field: 'queueName',
title: i18n.t('reports.listColumns.column3_2'), field: 'queueName',
cellStyle: (evt, rowData) => {
return {
whiteSpace: 'nowrap',
@ -1066,19 +1073,19 @@ const Report = () => {
}
},
{ title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: 'Conversas recebidas', field: 'startedByClient' },
{ title: `Conversas finalizadas`, field: 'closedChat' },
{ title: `Tempo médio de espera`, field: 'avgChatWaitingTime' },
{ title: 'Aguardando', field: 'pendingChat' }
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_6'), field: 'avgChatWaitingTime' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' }
] :
[
{ title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{
title: 'Fila', field: 'queueName',
title: i18n.t('reports.listColumns.column3_2'), field: 'queueName',
cellStyle: (evt, rowData) => {
return {
whiteSpace: 'nowrap',
@ -1088,10 +1095,10 @@ const Report = () => {
}
},
{ title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: 'Conversas respondidas', field: 'startedByClient' },
{ title: `Conversas finalizadas`, field: 'closedChat' },
{ title: 'Aguardando', field: 'pendingChat' }
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' }
]
}

View File

@ -28,8 +28,8 @@ import { render } from '@testing-library/react'
// import Modal from "../../../..ChatEnd/ModalChatEnd";
import Modal from "../../components/ModalUpdateScheduleReminder"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
@ -204,11 +204,9 @@ const SchedulesReminder = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("schedulingNotify", (data) => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSchedulingNotifySchedulesRemider = (data) => {
setLoading(true)
@ -228,10 +226,12 @@ const SchedulesReminder = () => {
setLoading(false)
})
}
socket.on("schedulingNotify", onSchedulingNotifySchedulesRemider)
return () => {
socket.disconnect()
socket.off("schedulingNotify", onSchedulingNotifySchedulesRemider)
}
}, [])

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect, useContext } from 'react'
import openSocket from 'socket.io-client'
//import openSocket from 'socket.io-client'
import { socket } from '../../services/socket.js'
import { makeStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
@ -124,9 +125,9 @@ const Settings = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('settings', (data) => {
const onSettingsSettings = (data) => {
console.log('settings updated ----------------------------')
if (data.action === 'update') {
@ -137,10 +138,12 @@ const Settings = () => {
return aux
})
}
})
}
socket.on('settings', onSettingsSettings)
return () => {
socket.disconnect()
socket.off("settings", onSettingsSettings)
}
}, [])
@ -179,7 +182,11 @@ const Settings = () => {
}
const getSettingValue = (key, _obj = false) => {
const { value, obj } = settings.find((s) => s.key === key)
//const { value, obj } = settings.find((s) => s.key === key)
const setting = settings.find((s) => s.key === key)
const value = setting?.value || ""
const obj = setting?.obj || null
if (_obj)
return obj

View File

@ -1,5 +1,6 @@
import React, { useState, useContext, useEffect, useReducer } from "react"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import {
Button,
@ -131,9 +132,9 @@ const StatusChatEnd = () => {
}, [searchParam, pageNumber])
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("statusChatEnd", (data) => {
const onStatusChatEndStatusChatEnd = (data) => {
if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_STATUS_CHAT_END", payload: data.statusChatEnd })
}
@ -144,10 +145,12 @@ const StatusChatEnd = () => {
payload: +data.statusChatEndId,
})
}
})
}
socket.on("statusChatEnd", onStatusChatEndStatusChatEnd)
return () => {
socket.disconnect()
socket.off("statusChatEnd", onStatusChatEndStatusChatEnd)
}
}, [])
@ -217,7 +220,7 @@ const StatusChatEnd = () => {
<ConfirmationModal
title={
deletingStatusChatEnds &&
`Você tem certeza que quer excluir esta Status de encerramento: ${deletingStatusChatEnds.name
`${i18n.t('dashboard.titles.confirmationModal')} ${deletingStatusChatEnds.name
}?`
}
open={confirmModalOpen}
@ -233,7 +236,7 @@ const StatusChatEnd = () => {
statusChatEndId={selectedStatusChatEnd && selectedStatusChatEnd.id}
></StatusChatEndModal>
<MainHeader>
<Title>{"Status de encerramento"}</Title>
<Title>{i18n.t('dashboard.titles.status')}</Title>
<MainHeaderButtonsWrapper>
<TextField
placeholder={i18n.t("quickAnswers.searchPlaceholder")}
@ -266,13 +269,13 @@ const StatusChatEnd = () => {
<TableHead>
<TableRow>
<TableCell align="center">
{"Status de encerramento"}
{i18n.t('dashboard.titles.status')}
</TableCell>
<TableCell align="center">
{"Mensagem de despedida"}
{i18n.t('quickAnswers.table.farewellMessage')}
</TableCell>
<TableCell align="center">
{"Padrão"}
{i18n.t('quickAnswers.table.standard')}
</TableCell>
<TableCell align="center">
{i18n.t("quickAnswers.table.actions")}

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect, useReducer, useContext } from "react"
import { toast } from "react-toastify"
import openSocket from "socket.io-client"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { makeStyles } from "@material-ui/core/styles"
import Paper from "@material-ui/core/Paper"
@ -165,9 +166,9 @@ const Users = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("user", (data) => {
const onUserUsers = (data) => {
if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_USERS", payload: data.user })
}
@ -175,10 +176,11 @@ const Users = () => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
})
}
socket.on("user", onUserUsers)
socket.on('settings', (data) => {
const onSettingsUsers = (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
@ -187,10 +189,12 @@ const Users = () => {
return aux
})
}
})
}
socket.on('settings', onSettingsUsers)
return () => {
socket.disconnect()
socket.off("settings", onSettingsUsers)
socket.off("user", onUserUsers)
}
}, [])

View File

@ -1,9 +1,14 @@
import React, { useContext } from "react";
import React, { useContext, Suspense, lazy } from "react";
import { Route as RouterRoute, Redirect } from "react-router-dom";
import { AuthContext } from "../context/Auth/AuthContext";
import BackdropLoading from "../components/BackdropLoading";
// Exemplo de como você carregaria componentes de forma lazy
const Dashboard = lazy(() => import("../pages/Dashboard"));
const Login = lazy(() => import("../pages/Login"));
const Signup = lazy(() => import("../pages/Signup"));
const Route = ({ component: Component, isPrivate = false, ...rest }) => {
const { isAuth, loading } = useContext(AuthContext);
@ -20,7 +25,7 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => {
return (
<>
{loading && <BackdropLoading />}
<Redirect to={{ pathname: "/", state: { from: rest.location } }} />;
<Redirect to={{ pathname: "/", state: { from: rest.location } }} />
</>
);
}
@ -28,7 +33,9 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => {
return (
<>
{loading && <BackdropLoading />}
<Suspense fallback={<BackdropLoading />}>
<RouterRoute {...rest} component={Component} />
</Suspense>
</>
);
};

View File

@ -1,34 +1,34 @@
import React from 'react'
import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Switch } from 'react-router-dom'
import { ToastContainer } from 'react-toastify'
import LoggedInLayout from '../layout'
import Dashboard from '../pages/Dashboard/'
import Report from '../pages/Report/'
import SchedulesReminder from '../pages/SchedulesReminder/'
import Tickets from '../pages/Tickets/'
import Signup from '../pages/Signup/'
import Login from '../pages/Login/'
import Connections from '../pages/Connections/'
import Campaign from '../pages/Campaign'
import Settings from '../pages/Settings/'
import Users from '../pages/Users'
import Contacts from '../pages/Contacts/'
import QuickAnswers from '../pages/QuickAnswers/'
import StatusChatEnd from '../pages/StatusChatEnd/'
import Position from '../pages/Position/'
import Queues from '../pages/Queues/'
import { AuthProvider } from '../context/Auth/AuthContext'
import { WhatsAppsProvider } from '../context/WhatsApp/WhatsAppsContext'
import LoggedInLayout from '../layout'
import Route from './Route'
import BackdropLoading from "../components/BackdropLoading";
const Dashboard = lazy(() => import('../pages/Dashboard/'));
const Report = lazy(() => import('../pages/Report/'));
const SchedulesReminder = lazy(() => import('../pages/SchedulesReminder/'));
const Tickets = lazy(() => import('../pages/Tickets/'));
const Signup = lazy(() => import('../pages/Signup/'));
const Login = lazy(() => import('../pages/Login/'));
const Connections = lazy(() => import('../pages/Connections/'));
const Campaign = lazy(() => import('../pages/Campaign/'));
const Settings = lazy(() => import('../pages/Settings/'));
const Users = lazy(() => import('../pages/Users/'));
const Contacts = lazy(() => import('../pages/Contacts/'));
const QuickAnswers = lazy(() => import('../pages/QuickAnswers/'));
const StatusChatEnd = lazy(() => import('../pages/StatusChatEnd/'));
const Position = lazy(() => import('../pages/Position/'));
const Queues = lazy(() => import('../pages/Queues/'));
const Routes = () => {
return (
<BrowserRouter>
<AuthProvider>
<Suspense fallback={<BackdropLoading />}>
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/signup" component={Signup} />
@ -41,25 +41,20 @@ const Routes = () => {
component={Tickets}
isPrivate
/>
<Route
exact
path="/connections"
component={Connections}
isPrivate
/>
<Route exact path="/report" component={Report} isPrivate />
<Route exact path="/contacts" component={Contacts} isPrivate />
<Route
exact
path="/schedulesReminder"
component={SchedulesReminder}
isPrivate
/>
<Route exact path="/users" component={Users} isPrivate />
<Route
exact
@ -73,22 +68,18 @@ const Routes = () => {
component={StatusChatEnd}
isPrivate
/>
<Route
exact
path="/position"
component={Position}
isPrivate
/>
<Route exact path="/position" component={Position} isPrivate />
<Route exact path="/Settings" component={Settings} isPrivate />
<Route exact path="/Queues" component={Queues} isPrivate />
<Route exact path="/campaign" component={Campaign} isPrivate />
</LoggedInLayout>
</WhatsAppsProvider>
</Switch>
</Suspense>
<ToastContainer autoClose={3000} />
</AuthProvider>
</BrowserRouter>
)
);
}
export default Routes

View File

@ -0,0 +1,14 @@
import { io } from 'socket.io-client';
// "undefined" means the URL will be computed from the `window.location` object
const URL = process.env.REACT_APP_BACKEND_URL
export const socket = io(URL,
//{
// withCredentials: true,
// extraHeaders: {
// "my-custom-header": "abcd"
// },
// transports: ['websocket', 'polling']
//}
);

View File

@ -51,7 +51,7 @@ const messages = {
}
},
table_users:{
table_users: {
title: 'User List',
column0: 'Name',
column1: 'In Service/Finished',
@ -59,6 +59,45 @@ const messages = {
column3: 'Closed by Queue',
column4: 'Online time',
column5: 'Actions',
},
titles: {
selectQueues: 'Queues',
waiting: 'In Waiting',
inService: 'In Service',
users: 'Users',
name: 'Name',
attendant: 'Attendant',
dialogContentText: 'Choose a reporting option below.',
transfer: 'Transfer to other queues',
title: 'Closing tickets',
confirmationModal: 'Are you sure you want to remove this closing state: ',
status: 'Closing status',
listUser: 'List user',
user: 'user',
notEnter: 'Did not enter',
notEnterToday: 'Did not enter today',
ticketsClosed: 'Closed'
}
},
reportOptType: {
listTitles: {
title1: 'Standard',
title2: 'Synthetic',
title3: 'Analytical'
}
},
configModal: {
titles: {
startService: 'Start Service',
endService: 'End Service',
enableDisable: 'Enable/Disable',
outOfHours: 'Message outside opening hours',
outOfHoursSaturday: 'Message outside opening hours Saturday',
forTheWeekend: 'Weekend message',
holiday: 'Holiday date',
holidayMessage: 'Message for holidays',
inactivityMessage: 'Message due to lack of service activity',
save: 'Save'
}
},
connections: {
@ -295,7 +334,8 @@ const messages = {
administration: "Administration",
users: "Users",
settings: "Settings",
schedules: "Schedules"
schedules: "Schedules",
reports: "Reports"
},
appBar: {
user: {
@ -309,9 +349,11 @@ const messages = {
title0_1: "Reminders/Schedulings",
title1_1: "Calls by attendants",
title2_1: "Whatsapp chat",
title3_1: "Users online/offline"
title3_1: "Users online/offline",
title4_1: "Attendance report by numbers",
title5_1: "Queue service report"
},
listColumns:{
listColumns: {
column0_1: 'Actions',
column0_2: 'Pic',
column0_3: 'Name',
@ -330,13 +372,22 @@ const messages = {
column1_9: 'Closing status',
column2_1: 'Attendant/Client',
column3_1: 'Unit',
column3_2: 'Row',
column3_3: 'Conversations started',
column3_4: 'Incoming conversations',
column3_5: 'Finished conversations',
column3_6: 'Average waiting time',
column3_7: 'Waiting',
},
search: 'Number/Name...',
dateStart: 'Start date',
dateEnd: 'End date',
user: 'User'
user: 'User',
onlineTime: 'Online time',
inService: 'In service',
finished: 'Finished'
},
notifications: {
noTickets: "No notifications.",
@ -367,6 +418,8 @@ const messages = {
shortcut: "Shortcut",
message: "Quick Reply",
actions: "Actions",
farewellMessage: "Farewell message",
standard: "Standard"
},
buttons: {
add: "Add Quick Reply",

View File

@ -52,7 +52,7 @@ const messages = {
}
},
table_users:{
table_users: {
title: 'Lista de usuarios',
column0: 'Nombre',
@ -61,6 +61,46 @@ const messages = {
column3: 'Cerrado por cola',
column4: 'Tiempo Online',
column5: 'Actions',
},
titles: {
selectQueues: 'Colas',
waiting: 'En espera',
inService: 'En Atendimiento',
users: 'Usuarios',
name: 'Nombre',
attendant: 'Agente',
dialogTitle: 'Reportes',
dialogContentText: 'Escoja una opción de reporte abajo.',
transfer: 'Transferir para otras Colas',
title: 'Cierre de Tickets',
confirmationModal: 'Está seguro de que desea eliminar este estado de cierre: ',
status: 'Status de cierre',
listUser: 'Lista de Usuarios',
user: 'Usuario',
notEnter: 'No ingresó',
notEnterToday: 'No ingresó hoy',
ticketsClosed: 'Cerrados'
}
},
reportOptType: {
listTitles: {
title1: 'Patrón',
title2: 'Sintético',
title3: 'Analítico'
}
},
configModal: {
titles: {
startService: 'Inicio atención',
endService: 'Fin atención',
enableDisable: 'Activar/Desactivar',
outOfHours: 'Mensaje fuera de horario de atención',
outOfHoursSaturday: 'Mensaje fuera del horario de atención sábado',
forTheWeekend: 'Mensaje fin de semana',
holiday: 'Día Festivo',
holidayMessage: 'Mensaje para Festivos',
inactivityMessage: 'Mensaje por falta de actividad',
save: 'Guardar'
}
},
connections: {
@ -237,7 +277,7 @@ const messages = {
},
},
ticketsQueueSelect: {
placeholder: "Linhas",
placeholder: "Líneas",
},
tickets: {
toasts: {
@ -296,11 +336,13 @@ const messages = {
tickets: "Tickets",
contacts: "Contactos",
quickAnswers: "Respuestas rápidas",
queues: "Linhas",
queues: "Líneas",
administration: "Administración",
users: "Usuarios",
settings: "Configuración",
schedules: "Recordatorio"
schedules: "Recordatorio",
reports: "Reportes",
campain: "Campañas"
},
appBar: {
user: {
@ -312,11 +354,13 @@ const messages = {
reports: {
listTitles: {
title0_1: "Recordatorios/Programación",
title1_1: "Llamadas de asistentes",
title1_1: "Atención por agentes",
title2_1: "Chat de whatsapp",
title3_1: "Usuarios online/offline"
title3_1: "Usuarios online/offline",
title4_1: "Reporte de atención por números",
title5_1: "Reporte de atención por colas"
},
listColumns:{
listColumns: {
column0_1: 'Acción',
column0_2: 'Pic',
column0_3: 'Nombre',
@ -335,18 +379,28 @@ const messages = {
column1_9: 'Estado de cierre',
column2_1: 'Secretario/Cliente',
column3_1: 'Unidad',
column3_2: 'Cola',
column3_3: 'Chats iniciados',
column3_4: 'Chats Recibidos',
column3_5: 'Chats Finalizados',
column3_6: 'Tiempo medio de espera',
column3_7: 'En Espera',
},
search: 'Número/Nombre...',
dateStart: 'Fecha de inicio',
dateEnd: 'Fecha final',
user: 'Usuario'
user: 'Usuario',
onlineTime: 'Tiempo online',
inService: 'En servicio',
finished: 'Finalizado'
},
notifications: {
noTickets: "Sin notificaciones.",
},
queues: {
title: "Linhas",
title: "Líneas",
table: {
name: "Nombre",
color: "Color",
@ -363,7 +417,7 @@ const messages = {
},
},
queueSelect: {
inputLabel: "Linhas",
inputLabel: "Líneas",
},
quickAnswers: {
title: "Respuestas rápidas",
@ -371,6 +425,8 @@ const messages = {
shortcut: "Atajo",
message: "Respuesta rápida",
actions: "Acciones",
farewellMessage: "Mensaje de despedida",
standard: "Patrón"
},
buttons: {
add: "Agregar respuesta rápida",

View File

@ -59,6 +59,46 @@ const messages = {
column3: 'Fechados Por Fila',
column4: 'Tempo Online',
column5: 'Ações',
},
titles: {
selectQueues: 'Filas',
waiting: 'Em espera',
inService: 'Em Atendimento',
users: 'Usuários',
name: 'Nome',
attendant: 'Atendente',
dialogTitle: 'Relatórios',
dialogContentText: 'Escolha uma opção de relatório abaixo.',
transfer: 'Transferir para outras filas',
title: 'Tickets encerramento',
confirmationModal: 'Você tem certeza que quer excluir esta Status de encerramento: ' ,
status: 'Status de encerramento',
listUser: 'Lista de Usuarios',
user: 'Usuario',
notEnter: 'Não entrou',
notEnterToday: 'Não entrou hoje',
ticketsClosed: 'Fechados'
}
},
reportOptType: {
listTitles: {
title1: 'Padrão',
title2: 'Sintético',
title3: 'Analítico'
}
},
configModal: {
titles: {
startService: 'Início atendimento',
endService: 'Fim atendimento',
enableDisable: 'Ativar/Desativar',
outOfHours: 'Mensagem fora do horário de atendimento',
outOfHoursSaturday: 'Mensagem fora do horário de atendimento sábado',
forTheWeekend: 'Mensagem fim de semana',
holiday: 'Data do feriado',
holidayMessage: 'Mensagem para feriados',
inactivityMessage: 'Mensagem por falta de atividade no atendimento',
save: 'Salvar'
}
},
connections: {
@ -299,7 +339,9 @@ const messages = {
administration: "Administração",
users: "Usuários",
settings: "Configurações",
schedules: "Lembretes"
schedules: "Lembretes",
reports: "Relatórios",
campaign: "Campanha"
},
appBar: {
user: {
@ -337,13 +379,21 @@ const messages = {
column2_1: 'Atendente/Cliente',
column3_1: 'Unidade',
column3_2: 'Fila',
column3_3: 'Conversas iniciadas',
column3_4: 'Conversas recebidas',
column3_5: 'Conversas finalizadas',
column3_6: 'Tempo médio de espera',
column3_7: 'Aguardando',
},
search: 'Numer/Nome...',
dateStart: 'Data início',
dateEnd: 'Data fim',
user: 'Usuário'
user: 'Usuário',
onlineTime: 'Tempo online',
inService: 'Em atendimento',
finished: 'Finalizado'
},
notifications: {
noTickets: "Nenhuma notificação.",
@ -374,6 +424,8 @@ const messages = {
shortcut: "Atalho",
message: "Resposta Rápida",
actions: "Ações",
farewellMessage: "Mensagem de despedida",
standard: "Padrão"
},
buttons: {
add: "Adicionar Resposta Rápida",

2
package-lock.json generated
View File

@ -1,5 +1,5 @@
{
"name": "whaticket",
"name": "projeto-hit",
"lockfileVersion": 2,
"requires": true,
"packages": {