mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-20 20:59:16 +00:00
Merge pull request #383 from ricardoapaes/feature/multiple-tickets-for-contacts
User default whatsapp and multiple tickets per contact
This commit is contained in:
@@ -4,6 +4,7 @@ import AppError from "../errors/AppError";
|
|||||||
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
||||||
import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead";
|
import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead";
|
||||||
import Message from "../models/Message";
|
import Message from "../models/Message";
|
||||||
|
import Whatsapp from "../models/Whatsapp";
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
||||||
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
||||||
import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
||||||
@@ -13,6 +14,10 @@ import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
|||||||
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
||||||
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
||||||
|
|
||||||
|
type WhatsappData = {
|
||||||
|
whatsappId: number;
|
||||||
|
}
|
||||||
|
|
||||||
type MessageData = {
|
type MessageData = {
|
||||||
body: string;
|
body: string;
|
||||||
fromMe: boolean;
|
fromMe: boolean;
|
||||||
@@ -24,7 +29,10 @@ interface ContactData {
|
|||||||
number: string;
|
number: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createContact = async (newContact: string) => {
|
const createContact = async (
|
||||||
|
whatsappId: number | undefined,
|
||||||
|
newContact: string
|
||||||
|
) => {
|
||||||
await CheckIsValidContact(newContact);
|
await CheckIsValidContact(newContact);
|
||||||
|
|
||||||
const validNumber: any = await CheckContactNumber(newContact);
|
const validNumber: any = await CheckContactNumber(newContact);
|
||||||
@@ -42,11 +50,21 @@ const createContact = async (newContact: string) => {
|
|||||||
|
|
||||||
const contact = await CreateOrUpdateContactService(contactData);
|
const contact = await CreateOrUpdateContactService(contactData);
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
let whatsapp:Whatsapp | null;
|
||||||
|
|
||||||
|
if(whatsappId === undefined) {
|
||||||
|
whatsapp = await GetDefaultWhatsApp();
|
||||||
|
} else {
|
||||||
|
whatsapp = await Whatsapp.findByPk(whatsappId);
|
||||||
|
|
||||||
|
if(whatsapp === null) {
|
||||||
|
throw new AppError(`whatsapp #${whatsappId} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const createTicket = await FindOrCreateTicketService(
|
const createTicket = await FindOrCreateTicketService(
|
||||||
contact,
|
contact,
|
||||||
defaultWhatsapp.id,
|
whatsapp.id,
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -59,6 +77,7 @@ const createContact = async (newContact: string) => {
|
|||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const newContact: ContactData = req.body;
|
const newContact: ContactData = req.body;
|
||||||
|
const { whatsappId }: WhatsappData = req.body;
|
||||||
const { body, quotedMsg }: MessageData = req.body;
|
const { body, quotedMsg }: MessageData = req.body;
|
||||||
const medias = req.files as Express.Multer.File[];
|
const medias = req.files as Express.Multer.File[];
|
||||||
|
|
||||||
@@ -76,7 +95,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contactAndTicket = await createContact(newContact.number);
|
const contactAndTicket = await createContact(whatsappId, newContact.number);
|
||||||
|
|
||||||
if (medias) {
|
if (medias) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { Request, Response } from "express";
|
|||||||
import ImportContactsService from "../services/WbotServices/ImportContactsService";
|
import ImportContactsService from "../services/WbotServices/ImportContactsService";
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
await ImportContactsService();
|
const userId:number = parseInt(req.user.id);
|
||||||
|
await ImportContactsService(userId);
|
||||||
|
|
||||||
return res.status(200).json({ message: "contacts imported" });
|
return res.status(200).json({ message: "contacts imported" });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password, name, profile, queueIds } = req.body;
|
const { email, password, name, profile, queueIds, whatsappId } = req.body;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
req.url === "/signup" &&
|
req.url === "/signup" &&
|
||||||
@@ -43,7 +43,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
profile,
|
profile,
|
||||||
queueIds
|
queueIds,
|
||||||
|
whatsappId
|
||||||
});
|
});
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { QueryInterface, DataTypes } from "sequelize";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
up: (queryInterface: QueryInterface) => {
|
||||||
|
return queryInterface.addColumn("Users", "whatsappId", {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
references: { model: "Whatsapps", key: "id" },
|
||||||
|
onUpdate: "CASCADE",
|
||||||
|
onDelete: "SET NULL",
|
||||||
|
allowNull: true
|
||||||
|
},);
|
||||||
|
},
|
||||||
|
|
||||||
|
down: (queryInterface: QueryInterface) => {
|
||||||
|
return queryInterface.removeColumn("Users", "whatsappId");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,9 +2,12 @@ import { Op } from "sequelize";
|
|||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
|
|
||||||
const CheckContactOpenTickets = async (contactId: number): Promise<void> => {
|
const CheckContactOpenTickets = async (
|
||||||
|
contactId: number,
|
||||||
|
whatsappId: number
|
||||||
|
): Promise<void> => {
|
||||||
const ticket = await Ticket.findOne({
|
const ticket = await Ticket.findOne({
|
||||||
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
|
where: { contactId, whatsappId, status: { [Op.or]: ["open", "pending"] } }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ticket) {
|
if (ticket) {
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
import GetDefaultWhatsAppByUser from "./GetDefaultWhatsAppByUser";
|
||||||
|
|
||||||
|
const GetDefaultWhatsApp = async (
|
||||||
|
userId?: number
|
||||||
|
): Promise<Whatsapp> => {
|
||||||
|
if(userId) {
|
||||||
|
const whatsappByUser = await GetDefaultWhatsAppByUser(userId);
|
||||||
|
if(whatsappByUser !== null) {
|
||||||
|
return whatsappByUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const GetDefaultWhatsApp = async (): Promise<Whatsapp> => {
|
|
||||||
const defaultWhatsapp = await Whatsapp.findOne({
|
const defaultWhatsapp = await Whatsapp.findOne({
|
||||||
where: { isDefault: true }
|
where: { isDefault: true }
|
||||||
});
|
});
|
||||||
|
|||||||
20
backend/src/helpers/GetDefaultWhatsAppByUser.ts
Normal file
20
backend/src/helpers/GetDefaultWhatsAppByUser.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import User from "../models/User";
|
||||||
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
import { logger } from "../utils/logger";
|
||||||
|
|
||||||
|
const GetDefaultWhatsAppByUser = async (
|
||||||
|
userId: number
|
||||||
|
): Promise<Whatsapp | null> => {
|
||||||
|
const user = await User.findByPk(userId, {include: ["whatsapp"]});
|
||||||
|
if( user === null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(user.whatsapp !== null) {
|
||||||
|
logger.info(`Found whatsapp linked to user '${user.name}' is '${user.whatsapp.name}'.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.whatsapp;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GetDefaultWhatsAppByUser;
|
||||||
@@ -5,7 +5,7 @@ import Ticket from "../models/Ticket";
|
|||||||
|
|
||||||
const GetTicketWbot = async (ticket: Ticket): Promise<Session> => {
|
const GetTicketWbot = async (ticket: Ticket): Promise<Session> => {
|
||||||
if (!ticket.whatsappId) {
|
if (!ticket.whatsappId) {
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
const defaultWhatsapp = await GetDefaultWhatsApp(ticket.user.id);
|
||||||
|
|
||||||
await ticket.$set("whatsapp", defaultWhatsapp);
|
await ticket.$set("whatsapp", defaultWhatsapp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Queue from "../models/Queue";
|
import Queue from "../models/Queue";
|
||||||
import User from "../models/User";
|
import User from "../models/User";
|
||||||
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
|
||||||
interface SerializedUser {
|
interface SerializedUser {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -7,6 +8,7 @@ interface SerializedUser {
|
|||||||
email: string;
|
email: string;
|
||||||
profile: string;
|
profile: string;
|
||||||
queues: Queue[];
|
queues: Queue[];
|
||||||
|
whatsapp: Whatsapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SerializeUser = (user: User): SerializedUser => {
|
export const SerializeUser = (user: User): SerializedUser => {
|
||||||
@@ -15,6 +17,7 @@ export const SerializeUser = (user: User): SerializedUser => {
|
|||||||
name: user.name,
|
name: user.name,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
profile: user.profile,
|
profile: user.profile,
|
||||||
queues: user.queues
|
queues: user.queues,
|
||||||
|
whatsapp: user.whatsapp
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ import {
|
|||||||
AutoIncrement,
|
AutoIncrement,
|
||||||
Default,
|
Default,
|
||||||
HasMany,
|
HasMany,
|
||||||
BelongsToMany
|
BelongsToMany,
|
||||||
|
ForeignKey,
|
||||||
|
BelongsTo
|
||||||
} from "sequelize-typescript";
|
} from "sequelize-typescript";
|
||||||
import { hash, compare } from "bcryptjs";
|
import { hash, compare } from "bcryptjs";
|
||||||
import Ticket from "./Ticket";
|
import Ticket from "./Ticket";
|
||||||
import Queue from "./Queue";
|
import Queue from "./Queue";
|
||||||
import UserQueue from "./UserQueue";
|
import UserQueue from "./UserQueue";
|
||||||
|
import Whatsapp from "./Whatsapp";
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
class User extends Model<User> {
|
class User extends Model<User> {
|
||||||
@@ -45,6 +48,13 @@ class User extends Model<User> {
|
|||||||
@Column
|
@Column
|
||||||
profile: string;
|
profile: string;
|
||||||
|
|
||||||
|
@ForeignKey(() => Whatsapp)
|
||||||
|
@Column
|
||||||
|
whatsappId: number;
|
||||||
|
|
||||||
|
@BelongsTo(() => Whatsapp)
|
||||||
|
whatsapp: Whatsapp;
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
|||||||
@@ -2,30 +2,39 @@ import AppError from "../../errors/AppError";
|
|||||||
import CheckContactOpenTickets from "../../helpers/CheckContactOpenTickets";
|
import CheckContactOpenTickets from "../../helpers/CheckContactOpenTickets";
|
||||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||||
import Ticket from "../../models/Ticket";
|
import Ticket from "../../models/Ticket";
|
||||||
|
import User from "../../models/User";
|
||||||
import ShowContactService from "../ContactServices/ShowContactService";
|
import ShowContactService from "../ContactServices/ShowContactService";
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
contactId: number;
|
contactId: number;
|
||||||
status: string;
|
status: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
|
queueId ?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateTicketService = async ({
|
const CreateTicketService = async ({
|
||||||
contactId,
|
contactId,
|
||||||
status,
|
status,
|
||||||
userId
|
userId,
|
||||||
|
queueId
|
||||||
}: Request): Promise<Ticket> => {
|
}: Request): Promise<Ticket> => {
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||||
|
|
||||||
await CheckContactOpenTickets(contactId);
|
await CheckContactOpenTickets(contactId, defaultWhatsapp.id);
|
||||||
|
|
||||||
const { isGroup } = await ShowContactService(contactId);
|
const { isGroup } = await ShowContactService(contactId);
|
||||||
|
|
||||||
|
if(queueId === undefined) {
|
||||||
|
const user = await User.findByPk(userId, { include: ["queues"]});
|
||||||
|
queueId = user?.queues.length === 1 ? user.queues[0].id : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const { id }: Ticket = await defaultWhatsapp.$create("ticket", {
|
const { id }: Ticket = await defaultWhatsapp.$create("ticket", {
|
||||||
contactId,
|
contactId,
|
||||||
status,
|
status,
|
||||||
isGroup,
|
isGroup,
|
||||||
userId
|
userId,
|
||||||
|
queueId
|
||||||
});
|
});
|
||||||
|
|
||||||
const ticket = await Ticket.findByPk(id, { include: ["contact"] });
|
const ticket = await Ticket.findByPk(id, { include: ["contact"] });
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ const FindOrCreateTicketService = async (
|
|||||||
status: {
|
status: {
|
||||||
[Op.or]: ["open", "pending"]
|
[Op.or]: ["open", "pending"]
|
||||||
},
|
},
|
||||||
contactId: groupContact ? groupContact.id : contact.id
|
contactId: groupContact ? groupContact.id : contact.id,
|
||||||
|
whatsappId: whatsappId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,7 +27,8 @@ const FindOrCreateTicketService = async (
|
|||||||
if (!ticket && groupContact) {
|
if (!ticket && groupContact) {
|
||||||
ticket = await Ticket.findOne({
|
ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
contactId: groupContact.id
|
contactId: groupContact.id,
|
||||||
|
whatsappId: whatsappId
|
||||||
},
|
},
|
||||||
order: [["updatedAt", "DESC"]]
|
order: [["updatedAt", "DESC"]]
|
||||||
});
|
});
|
||||||
@@ -46,7 +48,8 @@ const FindOrCreateTicketService = async (
|
|||||||
updatedAt: {
|
updatedAt: {
|
||||||
[Op.between]: [+subHours(new Date(), 2), +new Date()]
|
[Op.between]: [+subHours(new Date(), 2), +new Date()]
|
||||||
},
|
},
|
||||||
contactId: contact.id
|
contactId: contact.id,
|
||||||
|
whatsappId: whatsappId
|
||||||
},
|
},
|
||||||
order: [["updatedAt", "DESC"]]
|
order: [["updatedAt", "DESC"]]
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Contact from "../../models/Contact";
|
|||||||
import Message from "../../models/Message";
|
import Message from "../../models/Message";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import ShowUserService from "../UserServices/ShowUserService";
|
import ShowUserService from "../UserServices/ShowUserService";
|
||||||
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
searchParam?: string;
|
searchParam?: string;
|
||||||
@@ -50,6 +51,11 @@ const ListTicketsService = async ({
|
|||||||
model: Queue,
|
model: Queue,
|
||||||
as: "queue",
|
as: "queue",
|
||||||
attributes: ["id", "name", "color"]
|
attributes: ["id", "name", "color"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Whatsapp,
|
||||||
|
as: "whatsapp",
|
||||||
|
attributes: ["name"]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ interface TicketData {
|
|||||||
status?: string;
|
status?: string;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
queueId?: number;
|
queueId?: number;
|
||||||
|
whatsappId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
@@ -27,16 +28,20 @@ const UpdateTicketService = async ({
|
|||||||
ticketData,
|
ticketData,
|
||||||
ticketId
|
ticketId
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
const { status, userId, queueId } = ticketData;
|
const { status, userId, queueId, whatsappId } = ticketData;
|
||||||
|
|
||||||
const ticket = await ShowTicketService(ticketId);
|
const ticket = await ShowTicketService(ticketId);
|
||||||
await SetTicketMessagesAsRead(ticket);
|
await SetTicketMessagesAsRead(ticket);
|
||||||
|
|
||||||
|
if(whatsappId && ticket.whatsappId !== whatsappId) {
|
||||||
|
await CheckContactOpenTickets(ticket.contactId, whatsappId);
|
||||||
|
}
|
||||||
|
|
||||||
const oldStatus = ticket.status;
|
const oldStatus = ticket.status;
|
||||||
const oldUserId = ticket.user?.id;
|
const oldUserId = ticket.user?.id;
|
||||||
|
|
||||||
if (oldStatus === "closed") {
|
if (oldStatus === "closed") {
|
||||||
await CheckContactOpenTickets(ticket.contact.id);
|
await CheckContactOpenTickets(ticket.contact.id, ticket.whatsappId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ticket.update({
|
await ticket.update({
|
||||||
@@ -46,6 +51,11 @@ const UpdateTicketService = async ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if(whatsappId) {
|
||||||
|
await ticket.update({
|
||||||
|
whatsappId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await ticket.reload();
|
await ticket.reload();
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ interface Request {
|
|||||||
name: string;
|
name: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
profile?: string;
|
profile?: string;
|
||||||
|
whatsappId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
@@ -24,7 +25,8 @@ const CreateUserService = async ({
|
|||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
queueIds = [],
|
queueIds = [],
|
||||||
profile = "admin"
|
profile = "admin",
|
||||||
|
whatsappId
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string().required().min(2),
|
name: Yup.string().required().min(2),
|
||||||
@@ -56,18 +58,17 @@ const CreateUserService = async ({
|
|||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
profile
|
profile,
|
||||||
|
whatsappId: whatsappId ? whatsappId : null
|
||||||
},
|
},
|
||||||
{ include: ["queues"] }
|
{ include: ["queues", "whatsapp"] }
|
||||||
);
|
);
|
||||||
|
|
||||||
await user.$set("queues", queueIds);
|
await user.$set("queues", queueIds);
|
||||||
|
|
||||||
await user.reload();
|
await user.reload();
|
||||||
|
|
||||||
const serializedUser = SerializeUser(user);
|
return SerializeUser(user);
|
||||||
|
|
||||||
return serializedUser;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateUserService;
|
export default CreateUserService;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Sequelize, Op } from "sequelize";
|
import { Sequelize, Op } from "sequelize";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
searchParam?: string;
|
searchParam?: string;
|
||||||
@@ -39,7 +40,8 @@ const ListUsersService = async ({
|
|||||||
offset,
|
offset,
|
||||||
order: [["createdAt", "DESC"]],
|
order: [["createdAt", "DESC"]],
|
||||||
include: [
|
include: [
|
||||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] },
|
||||||
|
{ model: Whatsapp, as: "whatsapp", attributes: ["id", "name"] },
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
|
|
||||||
const ShowUserService = async (id: string | number): Promise<User> => {
|
const ShowUserService = async (id: string | number): Promise<User> => {
|
||||||
const user = await User.findByPk(id, {
|
const user = await User.findByPk(id, {
|
||||||
attributes: ["name", "id", "email", "profile", "tokenVersion"],
|
attributes: ["name", "id", "email", "profile", "tokenVersion", "whatsappId"],
|
||||||
include: [
|
include: [
|
||||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] },
|
||||||
|
{ model: Whatsapp, as: "whatsapp", attributes: ["id", "name"] },
|
||||||
],
|
],
|
||||||
order: [ [ { model: Queue, as: "queues"}, 'name', 'asc' ] ]
|
order: [ [ { model: Queue, as: "queues"}, 'name', 'asc' ] ]
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
|
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
|
import { SerializeUser } from "../../helpers/SerializeUser";
|
||||||
import ShowUserService from "./ShowUserService";
|
import ShowUserService from "./ShowUserService";
|
||||||
|
|
||||||
interface UserData {
|
interface UserData {
|
||||||
@@ -9,6 +10,7 @@ interface UserData {
|
|||||||
name?: string;
|
name?: string;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
|
whatsappId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
@@ -36,7 +38,7 @@ const UpdateUserService = async ({
|
|||||||
password: Yup.string()
|
password: Yup.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
const { email, password, profile, name, queueIds = [] } = userData;
|
const { email, password, profile, name, queueIds = [], whatsappId } = userData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await schema.validate({ email, password, profile, name });
|
await schema.validate({ email, password, profile, name });
|
||||||
@@ -48,22 +50,15 @@ const UpdateUserService = async ({
|
|||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
profile,
|
profile,
|
||||||
name
|
name,
|
||||||
|
whatsappId: whatsappId ? whatsappId : null
|
||||||
});
|
});
|
||||||
|
|
||||||
await user.$set("queues", queueIds);
|
await user.$set("queues", queueIds);
|
||||||
|
|
||||||
await user.reload();
|
await user.reload();
|
||||||
|
|
||||||
const serializedUser = {
|
return SerializeUser(user);
|
||||||
id: user.id,
|
|
||||||
name: user.name,
|
|
||||||
email: user.email,
|
|
||||||
profile: user.profile,
|
|
||||||
queues: user.queues
|
|
||||||
};
|
|
||||||
|
|
||||||
return serializedUser;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UpdateUserService;
|
export default UpdateUserService;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { getWbot } from "../../libs/wbot";
|
|||||||
import Contact from "../../models/Contact";
|
import Contact from "../../models/Contact";
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
|
|
||||||
const ImportContactsService = async (): Promise<void> => {
|
const ImportContactsService = async (userId:number): Promise<void> => {
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||||
|
|
||||||
const wbot = getWbot(defaultWhatsapp.id);
|
const wbot = getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,21 @@ const useStyles = makeStyles(theme => ({
|
|||||||
top: "0%",
|
top: "0%",
|
||||||
left: "0%",
|
left: "0%",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
userTag: {
|
||||||
|
position: "absolute",
|
||||||
|
marginRight: 5,
|
||||||
|
right: 5,
|
||||||
|
bottom: 5,
|
||||||
|
background:"#2576D2",
|
||||||
|
color: "#ffffff",
|
||||||
|
border:"1px solid #CCC",
|
||||||
|
padding: 1,
|
||||||
|
paddingLeft: 5,
|
||||||
|
paddingRight: 5,
|
||||||
|
borderRadius: 10,
|
||||||
|
fontSize: "1em"
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const TicketListItem = ({ ticket }) => {
|
const TicketListItem = ({ ticket }) => {
|
||||||
@@ -196,6 +211,9 @@ const TicketListItem = ({ ticket }) => {
|
|||||||
)}
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
{ticket.whatsappId && (
|
||||||
|
<div className={classes.userTag} title={i18n.t("ticketsList.connectionTitle")}>{ticket.whatsapp.name}</div>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
secondary={
|
secondary={
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ const TicketOptionsMenu = ({ ticket, menuOpen, handleClose, anchorEl }) => {
|
|||||||
modalOpen={transferTicketModalOpen}
|
modalOpen={transferTicketModalOpen}
|
||||||
onClose={handleCloseTransferTicketModal}
|
onClose={handleCloseTransferTicketModal}
|
||||||
ticketid={ticket.id}
|
ticketid={ticket.id}
|
||||||
|
ticketWhatsappId={ticket.whatsappId}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
@@ -23,6 +23,9 @@ import api from "../../services/api";
|
|||||||
import ButtonWithSpinner from "../ButtonWithSpinner";
|
import ButtonWithSpinner from "../ButtonWithSpinner";
|
||||||
import toastError from "../../errors/toastError";
|
import toastError from "../../errors/toastError";
|
||||||
import useQueues from "../../hooks/useQueues";
|
import useQueues from "../../hooks/useQueues";
|
||||||
|
import useWhatsApps from "../../hooks/useWhatsApps";
|
||||||
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
import { Can } from "../Can";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
@@ -34,7 +37,7 @@ const filterOptions = createFilterOptions({
|
|||||||
trim: true,
|
trim: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
const TransferTicketModal = ({ modalOpen, onClose, ticketid, ticketWhatsappId }) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([]);
|
||||||
const [queues, setQueues] = useState([]);
|
const [queues, setQueues] = useState([]);
|
||||||
@@ -43,8 +46,12 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
|||||||
const [searchParam, setSearchParam] = useState("");
|
const [searchParam, setSearchParam] = useState("");
|
||||||
const [selectedUser, setSelectedUser] = useState(null);
|
const [selectedUser, setSelectedUser] = useState(null);
|
||||||
const [selectedQueue, setSelectedQueue] = useState('');
|
const [selectedQueue, setSelectedQueue] = useState('');
|
||||||
|
const [selectedWhatsapp, setSelectedWhatsapp] = useState(ticketWhatsappId);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { findAll: findAllQueues } = useQueues();
|
const { findAll: findAllQueues } = useQueues();
|
||||||
|
const { loadingWhatsapps, whatsApps } = useWhatsApps();
|
||||||
|
|
||||||
|
const { user: loggedInUser } = useContext(AuthContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadQueues = async () => {
|
const loadQueues = async () => {
|
||||||
@@ -107,6 +114,10 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(selectedWhatsapp) {
|
||||||
|
data.whatsappId = selectedWhatsapp;
|
||||||
|
}
|
||||||
|
|
||||||
await api.put(`/tickets/${ticketid}`, data);
|
await api.put(`/tickets/${ticketid}`, data);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -177,6 +188,24 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
<Can
|
||||||
|
role={loggedInUser.profile}
|
||||||
|
perform="ticket-options:transferWhatsapp"
|
||||||
|
yes={() => (!loadingWhatsapps &&
|
||||||
|
<FormControl variant="outlined" className={classes.maxWidth} style={{ marginTop: 20 }}>
|
||||||
|
<InputLabel>{i18n.t("transferTicketModal.fieldConnectionLabel")}</InputLabel>
|
||||||
|
<Select
|
||||||
|
value={selectedWhatsapp}
|
||||||
|
onChange={(e) => setSelectedWhatsapp(e.target.value)}
|
||||||
|
label={i18n.t("transferTicketModal.fieldConnectionPlaceholder")}
|
||||||
|
>
|
||||||
|
{whatsApps.map((whasapp) => (
|
||||||
|
<MenuItem key={whasapp.id} value={whasapp.id}>{whasapp.name}</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import toastError from "../../errors/toastError";
|
|||||||
import QueueSelect from "../QueueSelect";
|
import QueueSelect from "../QueueSelect";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
import { Can } from "../Can";
|
import { Can } from "../Can";
|
||||||
|
import useWhatsApps from "../../hooks/useWhatsApps";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
root: {
|
root: {
|
||||||
@@ -79,7 +80,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
profile: "user",
|
profile: "user"
|
||||||
};
|
};
|
||||||
|
|
||||||
const { user: loggedInUser } = useContext(AuthContext);
|
const { user: loggedInUser } = useContext(AuthContext);
|
||||||
@@ -87,7 +88,8 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||||||
const [user, setUser] = useState(initialState);
|
const [user, setUser] = useState(initialState);
|
||||||
const [selectedQueueIds, setSelectedQueueIds] = useState([]);
|
const [selectedQueueIds, setSelectedQueueIds] = useState([]);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [whatsappId, setWhatsappId] = useState(false);
|
||||||
|
const {loading, whatsApps} = useWhatsApps();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchUser = async () => {
|
const fetchUser = async () => {
|
||||||
@@ -99,6 +101,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||||||
});
|
});
|
||||||
const userQueueIds = data.queues?.map(queue => queue.id);
|
const userQueueIds = data.queues?.map(queue => queue.id);
|
||||||
setSelectedQueueIds(userQueueIds);
|
setSelectedQueueIds(userQueueIds);
|
||||||
|
setWhatsappId(data.whatsappId ? data.whatsappId : '');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err);
|
||||||
}
|
}
|
||||||
@@ -113,7 +116,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveUser = async values => {
|
const handleSaveUser = async values => {
|
||||||
const userData = { ...values, queueIds: selectedQueueIds };
|
const userData = { ...values, whatsappId, queueIds: selectedQueueIds };
|
||||||
try {
|
try {
|
||||||
if (userId) {
|
if (userId) {
|
||||||
await api.put(`/users/${userId}`, userData);
|
await api.put(`/users/${userId}`, userData);
|
||||||
@@ -242,6 +245,26 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Can
|
||||||
|
role={loggedInUser.profile}
|
||||||
|
perform="user-modal:editQueues"
|
||||||
|
yes={() => (!loading &&
|
||||||
|
<FormControl variant="outlined" margin="dense" className={classes.maxWidth} fullWidth>
|
||||||
|
<InputLabel>{i18n.t("userModal.form.whatsapp")}</InputLabel>
|
||||||
|
<Field
|
||||||
|
as={Select}
|
||||||
|
value={whatsappId}
|
||||||
|
onChange={(e) => setWhatsappId(e.target.value)}
|
||||||
|
label={i18n.t("userModal.form.whatsapp")}
|
||||||
|
>
|
||||||
|
<MenuItem value={''}> </MenuItem>
|
||||||
|
{whatsApps.map((whatsapp) => (
|
||||||
|
<MenuItem key={whatsapp.id} value={whatsapp.id}>{whatsapp.name}</MenuItem>
|
||||||
|
))}
|
||||||
|
</Field>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ const Users = () => {
|
|||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{i18n.t("users.table.profile")}
|
{i18n.t("users.table.profile")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{i18n.t("users.table.whatsapp")}
|
||||||
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{i18n.t("users.table.actions")}
|
{i18n.t("users.table.actions")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -255,6 +258,7 @@ const Users = () => {
|
|||||||
<TableCell align="center">{user.name}</TableCell>
|
<TableCell align="center">{user.name}</TableCell>
|
||||||
<TableCell align="center">{user.email}</TableCell>
|
<TableCell align="center">{user.email}</TableCell>
|
||||||
<TableCell align="center">{user.profile}</TableCell>
|
<TableCell align="center">{user.profile}</TableCell>
|
||||||
|
<TableCell align="center">{user.whatsapp?.name}</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const rules = {
|
|||||||
"user-modal:editProfile",
|
"user-modal:editProfile",
|
||||||
"user-modal:editQueues",
|
"user-modal:editQueues",
|
||||||
"ticket-options:deleteTicket",
|
"ticket-options:deleteTicket",
|
||||||
|
"ticket-options:transferWhatsapp",
|
||||||
"contacts-page:deleteContact",
|
"contacts-page:deleteContact",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ const messages = {
|
|||||||
email: "Email",
|
email: "Email",
|
||||||
password: "Password",
|
password: "Password",
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
|
whatsapp: "Default Connection",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
okAdd: "Add",
|
okAdd: "Add",
|
||||||
@@ -248,7 +249,9 @@ const messages = {
|
|||||||
title: "Transfer Ticket",
|
title: "Transfer Ticket",
|
||||||
fieldLabel: "Type to search for users",
|
fieldLabel: "Type to search for users",
|
||||||
fieldQueueLabel: "Transfer to queue",
|
fieldQueueLabel: "Transfer to queue",
|
||||||
|
fieldConnectionLabel: "Transfer to connection",
|
||||||
fieldQueuePlaceholder: "Please select a queue",
|
fieldQueuePlaceholder: "Please select a queue",
|
||||||
|
fieldConnectionPlaceholder: "Please select a connection",
|
||||||
noOptions: "No user found with this name",
|
noOptions: "No user found with this name",
|
||||||
buttons: {
|
buttons: {
|
||||||
ok: "Transfer",
|
ok: "Transfer",
|
||||||
@@ -260,6 +263,7 @@ const messages = {
|
|||||||
assignedHeader: "Working on",
|
assignedHeader: "Working on",
|
||||||
noTicketsTitle: "Nothing here!",
|
noTicketsTitle: "Nothing here!",
|
||||||
noTicketsMessage: "No tickets found with this status or search term.",
|
noTicketsMessage: "No tickets found with this status or search term.",
|
||||||
|
connectionTitle: "Connection that is currently being used.",
|
||||||
buttons: {
|
buttons: {
|
||||||
accept: "Accept",
|
accept: "Accept",
|
||||||
},
|
},
|
||||||
@@ -340,6 +344,7 @@ const messages = {
|
|||||||
name: "Name",
|
name: "Name",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
|
whatsapp: "Default Connection",
|
||||||
actions: "Actions",
|
actions: "Actions",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ const messages = {
|
|||||||
email: "Correo Electrónico",
|
email: "Correo Electrónico",
|
||||||
password: "Contraseña",
|
password: "Contraseña",
|
||||||
profile: "Perfil",
|
profile: "Perfil",
|
||||||
|
whatsapp: "Conexión estándar",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
okAdd: "Agregar",
|
okAdd: "Agregar",
|
||||||
@@ -251,7 +252,9 @@ const messages = {
|
|||||||
title: "Transferir Ticket",
|
title: "Transferir Ticket",
|
||||||
fieldLabel: "Escriba para buscar usuarios",
|
fieldLabel: "Escriba para buscar usuarios",
|
||||||
fieldQueueLabel: "Transferir a la cola",
|
fieldQueueLabel: "Transferir a la cola",
|
||||||
|
fieldConnectionLabel: "Transferir to conexión",
|
||||||
fieldQueuePlaceholder: "Seleccione una cola",
|
fieldQueuePlaceholder: "Seleccione una cola",
|
||||||
|
fieldConnectionPlaceholder: "Seleccione una conexión",
|
||||||
noOptions: "No se encontraron usuarios con ese nombre",
|
noOptions: "No se encontraron usuarios con ese nombre",
|
||||||
buttons: {
|
buttons: {
|
||||||
ok: "Transferir",
|
ok: "Transferir",
|
||||||
@@ -262,6 +265,7 @@ const messages = {
|
|||||||
pendingHeader: "Cola",
|
pendingHeader: "Cola",
|
||||||
assignedHeader: "Trabajando en",
|
assignedHeader: "Trabajando en",
|
||||||
noTicketsTitle: "¡Nada acá!",
|
noTicketsTitle: "¡Nada acá!",
|
||||||
|
connectionTitle: "Conexión que se está utilizando actualmente.",
|
||||||
noTicketsMessage:
|
noTicketsMessage:
|
||||||
"No se encontraron tickets con este estado o término de búsqueda",
|
"No se encontraron tickets con este estado o término de búsqueda",
|
||||||
buttons: {
|
buttons: {
|
||||||
@@ -345,6 +349,7 @@ const messages = {
|
|||||||
name: "Nombre",
|
name: "Nombre",
|
||||||
email: "Correo Electrónico",
|
email: "Correo Electrónico",
|
||||||
profile: "Perfil",
|
profile: "Perfil",
|
||||||
|
whatsapp: "Conexión estándar",
|
||||||
actions: "Acciones",
|
actions: "Acciones",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ const messages = {
|
|||||||
email: "Email",
|
email: "Email",
|
||||||
password: "Senha",
|
password: "Senha",
|
||||||
profile: "Perfil",
|
profile: "Perfil",
|
||||||
|
whatsapp: "Conexão Padrão",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
okAdd: "Adicionar",
|
okAdd: "Adicionar",
|
||||||
@@ -250,7 +251,9 @@ const messages = {
|
|||||||
title: "Transferir Ticket",
|
title: "Transferir Ticket",
|
||||||
fieldLabel: "Digite para buscar usuários",
|
fieldLabel: "Digite para buscar usuários",
|
||||||
fieldQueueLabel: "Transferir para fila",
|
fieldQueueLabel: "Transferir para fila",
|
||||||
|
fieldConnectionLabel: "Transferir para conexão",
|
||||||
fieldQueuePlaceholder: "Selecione uma fila",
|
fieldQueuePlaceholder: "Selecione uma fila",
|
||||||
|
fieldConnectionPlaceholder: "Selecione uma conexão",
|
||||||
noOptions: "Nenhum usuário encontrado com esse nome",
|
noOptions: "Nenhum usuário encontrado com esse nome",
|
||||||
buttons: {
|
buttons: {
|
||||||
ok: "Transferir",
|
ok: "Transferir",
|
||||||
@@ -263,6 +266,7 @@ const messages = {
|
|||||||
noTicketsTitle: "Nada aqui!",
|
noTicketsTitle: "Nada aqui!",
|
||||||
noTicketsMessage:
|
noTicketsMessage:
|
||||||
"Nenhum ticket encontrado com esse status ou termo pesquisado",
|
"Nenhum ticket encontrado com esse status ou termo pesquisado",
|
||||||
|
connectionTitle: "Conexão que está sendo utilizada atualmente.",
|
||||||
buttons: {
|
buttons: {
|
||||||
accept: "Aceitar",
|
accept: "Aceitar",
|
||||||
},
|
},
|
||||||
@@ -344,6 +348,7 @@ const messages = {
|
|||||||
name: "Nome",
|
name: "Nome",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
profile: "Perfil",
|
profile: "Perfil",
|
||||||
|
whatsapp: "Conexão Padrão",
|
||||||
actions: "Ações",
|
actions: "Ações",
|
||||||
},
|
},
|
||||||
buttons: {
|
buttons: {
|
||||||
|
|||||||
Reference in New Issue
Block a user