Compare commits
No commits in common. "d6ec5972a5a5aa856b2d40567dc1dc0feb19581c" and "bc7fb4424cb7c72a1280518e6b01365fb21076ad" have entirely different histories.
d6ec5972a5
...
bc7fb4424c
|
@ -40,10 +40,7 @@ WWebJS
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.env.save
|
|
||||||
nano.save
|
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
|
|
|
@ -183,17 +183,11 @@ socketIo.on('connect_error', async function (err) {
|
||||||
})
|
})
|
||||||
//
|
//
|
||||||
|
|
||||||
const wwebVersion = '2.2402.5';
|
|
||||||
|
|
||||||
|
|
||||||
//NOVA OPÇÃO MD
|
//NOVA OPÇÃO MD
|
||||||
client = new Client({
|
client = new Client({
|
||||||
authStrategy: new LocalAuth({ clientId: 'omnihit_sesssion' }),
|
authStrategy: new LocalAuth({ clientId: 'omnihit_sesssion' }),
|
||||||
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
|
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
|
||||||
webVersionCache: {
|
|
||||||
type: 'remote',
|
|
||||||
remotePath: `https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/${wwebVersion}.html`,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
client.initialize()
|
client.initialize()
|
||||||
|
|
|
@ -20,18 +20,12 @@ import {
|
||||||
} from "../helpers/ContactsCache";
|
} from "../helpers/ContactsCache";
|
||||||
|
|
||||||
import { off } from "process";
|
import { off } from "process";
|
||||||
import GetContactService from "../services/ContactServices/GetContactService"
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IndexGetContactQuery = {
|
|
||||||
name: string;
|
|
||||||
number: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ExtraInfo {
|
interface ExtraInfo {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -90,20 +84,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
return res.json({ contacts, count, hasMore });
|
return res.json({ contacts, count, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getContact = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { name, number } = req.body as IndexGetContactQuery;
|
|
||||||
|
|
||||||
const contact = await GetContactService({
|
|
||||||
name,
|
|
||||||
number
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json(contact);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const newContact: ContactData = req.body;
|
const newContact: ContactData = req.body;
|
||||||
newContact.number = newContact.number.replace("-", "").replace(" ", "");
|
newContact.number = newContact.number.replace("-", "").replace(" ", "");
|
||||||
|
@ -126,12 +106,21 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
const validNumber = await CheckIsValidContact(newContact.number);
|
const validNumber = await CheckIsValidContact(newContact.number);
|
||||||
|
|
||||||
|
// const validNumber: any = await CheckContactNumber(newContact.number)
|
||||||
|
|
||||||
if (!validNumber) {
|
if (!validNumber) {
|
||||||
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
||||||
}
|
}
|
||||||
|
|
||||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||||
|
|
||||||
|
console.log("xxxxxxxxxxx profilePicUrl: ", profilePicUrl);
|
||||||
|
|
||||||
|
// console.log(`newContact.name: ${newContact.name}\n
|
||||||
|
// newContact.number: ${newContact.number}\n
|
||||||
|
// newContact.email: ${newContact.email}\n
|
||||||
|
// newContact.extraInfo: ${newContact.extraInfo}`)
|
||||||
|
|
||||||
let name = newContact.name;
|
let name = newContact.name;
|
||||||
let number = validNumber;
|
let number = validNumber;
|
||||||
let email = newContact.email;
|
let email = newContact.email;
|
||||||
|
|
|
@ -1,494 +0,0 @@
|
||||||
import { Request, Response } from "express";
|
|
||||||
import { getIO } from "../libs/socket";
|
|
||||||
import { Op } from "sequelize";
|
|
||||||
import CreateUserService from "../services/UserServices/CreateUserService";
|
|
||||||
import UpdateUserService from "../services/UserServices/UpdateUserService";
|
|
||||||
import DeleteUserService from "../services/UserServices/DeleteUserService";
|
|
||||||
import { del, get, set } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
import {
|
|
||||||
startWhoIsOnlineMonitor,
|
|
||||||
stopWhoIsOnlineMonitor
|
|
||||||
} from "../helpers/WhoIsOnlineMonitor";
|
|
||||||
|
|
||||||
import User from "../models/User";
|
|
||||||
|
|
||||||
export const createUser = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id, user_first_name, user_tax_id, user_email, user_title }: any =
|
|
||||||
req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, [
|
|
||||||
"user_id",
|
|
||||||
"user_tax_id",
|
|
||||||
"user_first_name"
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res.status(400).json(response("1", `${invalid}`, "0", "createUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const auxUser = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (auxUser) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(
|
|
||||||
response("1", `The user ${user_id} already exist`, "0", "createUser")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await CreateUserService({
|
|
||||||
email: user_tax_id || user_email,
|
|
||||||
password: "12345",
|
|
||||||
name: user_first_name,
|
|
||||||
positionCompany: user_title,
|
|
||||||
profile: "user",
|
|
||||||
ignoreThrow: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (user?.error) {
|
|
||||||
return res
|
|
||||||
.status(user?.status)
|
|
||||||
.json(response("0", `${user?.msg}`, "0", "createUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user?.error) {
|
|
||||||
const _user = await User.findByPk(user.id);
|
|
||||||
_user?.update({ secondaryId: user_id });
|
|
||||||
|
|
||||||
const { id, name } = user;
|
|
||||||
await set(`user:${id}`, { id, name });
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("user", {
|
|
||||||
action: "create",
|
|
||||||
user
|
|
||||||
});
|
|
||||||
|
|
||||||
await startWhoIsOnlineMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(response("1", `User ${user_id} created`, "1", "createUser"));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteUser = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id }: any = req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res.status(400).json(response("1", `${invalid}`, "0", "deleteUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (_user) {
|
|
||||||
const user = await DeleteUserService(_user.id, true);
|
|
||||||
|
|
||||||
if (user?.error) {
|
|
||||||
return res
|
|
||||||
.status(user?.status)
|
|
||||||
.json(response("0", `${user?.msg}`, "0", "deleteUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user?.error) {
|
|
||||||
del(`user:${_user.id}`);
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("user", {
|
|
||||||
action: "delete",
|
|
||||||
userId: _user.id
|
|
||||||
});
|
|
||||||
|
|
||||||
await stopWhoIsOnlineMonitor();
|
|
||||||
|
|
||||||
io.emit("onlineStatus", {
|
|
||||||
action: "delete",
|
|
||||||
userOnlineTime: _user.id
|
|
||||||
});
|
|
||||||
|
|
||||||
await startWhoIsOnlineMonitor();
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(response("1", `User ${user_id} deleted`, "1", "deleteUser"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json(response("0", "Internal server error", "0", "deleteUser"));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const listAllUsers = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const _users: any = await User.findAll({
|
|
||||||
where: {
|
|
||||||
secondaryId: {
|
|
||||||
[Op.ne]: ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attributes: ["secondaryId", "name"]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_users) {
|
|
||||||
const user_list = _users.map((user: any) => {
|
|
||||||
const { secondaryId, name } = user;
|
|
||||||
return { user_id: secondaryId, full_name: name };
|
|
||||||
});
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(response("1", "Success", user_list, "listAllUsers"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json(response("0", "Internal server error", [], "listAllUsers"));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkUser = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id }: any = req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res.status(400).json(response("1", `${invalid}`, "0", "checkUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (_user) {
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(response("1", `User ${user_id} exist`, "1", "checkUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(404)
|
|
||||||
.json(response("1", `User ${user_id} not exist`, "0", "checkUser"));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateUser = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id, user_first_name, user_tax_id, user_email, user_title }: any =
|
|
||||||
req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res.status(400).json(response("1", `${invalid}`, "0", "checkUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user: any = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (!_user)
|
|
||||||
return res
|
|
||||||
.status(404)
|
|
||||||
.json(response("1", `User ${user_id} not exist`, "0", "updateUser"));
|
|
||||||
|
|
||||||
const userData = {
|
|
||||||
email: user_tax_id || user_email,
|
|
||||||
name: user_first_name,
|
|
||||||
positionCompany: user_title
|
|
||||||
};
|
|
||||||
|
|
||||||
let user: any = await UpdateUserService({
|
|
||||||
userData,
|
|
||||||
userId: _user.id,
|
|
||||||
ignoreThrow: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (user?.error) {
|
|
||||||
return res
|
|
||||||
.status(user?.status)
|
|
||||||
.json(response("0", `${user?.msg}`, "0", "updateUser"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user) {
|
|
||||||
const { id, name } = user;
|
|
||||||
await set(`user:${id}`, { id, name });
|
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("user", {
|
|
||||||
action: "update",
|
|
||||||
user
|
|
||||||
});
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(response("1", `User ${user_id} updated`, "1", "updateUser"));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resetPassword = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id, user_password }: any = req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id", "user_password"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(response("1", `${invalid}`, "0", "resetPassword"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (!_user) {
|
|
||||||
return res
|
|
||||||
.status(404)
|
|
||||||
.json(response("1", `User ${user_id} not exist`, "0", "resetPassword"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const userData = {
|
|
||||||
password: user_password,
|
|
||||||
email: _user.email
|
|
||||||
};
|
|
||||||
|
|
||||||
let user: any = await UpdateUserService({
|
|
||||||
userData,
|
|
||||||
userId: _user.id,
|
|
||||||
ignoreThrow: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (user?.error) {
|
|
||||||
return res
|
|
||||||
.status(user?.status)
|
|
||||||
.json(response("0", `${user?.msg}`, "0", "resetPassword"));
|
|
||||||
}
|
|
||||||
|
|
||||||
await logoutUser(_user.id);
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(
|
|
||||||
response("1", `User ${user_id} password updated`, "1", "resetPassword")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const linkUserAndUserRight = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id, user_right_id, user_right_title }: any = req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id", "user_right_id"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(response("1", `${invalid}`, "0", "linkUserAndUserRight"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(user_right_id &&
|
|
||||||
!["admin", "user", "supervisor"].includes(
|
|
||||||
user_right_id?.trim().toLocaleLowerCase()
|
|
||||||
)) ||
|
|
||||||
(user_right_title &&
|
|
||||||
!["admin", "user", "supervisor"].includes(
|
|
||||||
user_right_title?.trim().toLocaleLowerCase()
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(
|
|
||||||
response(
|
|
||||||
"1",
|
|
||||||
`The user profile ${
|
|
||||||
user_right_title || user_right_id
|
|
||||||
} provided by the property user_right_title or user_right_id does not match the following profiles: admin, user, supervisor`,
|
|
||||||
"0",
|
|
||||||
"linkUserAndUserRight"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user: any = await User.findOne({ where: { secondaryId: user_id } });
|
|
||||||
|
|
||||||
if (!_user)
|
|
||||||
return res
|
|
||||||
.status(404)
|
|
||||||
.json(
|
|
||||||
response("1", `User ${user_id} not exist`, "0", "linkUserAndUserRight")
|
|
||||||
);
|
|
||||||
|
|
||||||
const userData = {
|
|
||||||
profile: user_right_title || user_right_id,
|
|
||||||
email: _user.email
|
|
||||||
};
|
|
||||||
|
|
||||||
let user: any = await UpdateUserService({
|
|
||||||
userData,
|
|
||||||
userId: _user.id,
|
|
||||||
ignoreThrow: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (user?.error) {
|
|
||||||
return res
|
|
||||||
.status(user?.status)
|
|
||||||
.json(response("0", `${user?.msg}`, "0", "linkUserAndUserRight"));
|
|
||||||
}
|
|
||||||
|
|
||||||
await logoutUser(_user.id);
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(
|
|
||||||
response(
|
|
||||||
"1",
|
|
||||||
`User ${user_id} associated with ${
|
|
||||||
user_right_title || user_right_id
|
|
||||||
} profile`,
|
|
||||||
"1",
|
|
||||||
"linkUserAndUserRight"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkUserRight = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { user_id, user_right_id, user_right_title }: any = req.body;
|
|
||||||
|
|
||||||
const invalid = invalidProperties(req.body, ["user_id", "user_right_id"]);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(response("1", `${invalid}`, "0", "checkUserRight"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(user_right_id &&
|
|
||||||
!["admin", "user", "supervisor"].includes(
|
|
||||||
user_right_id?.trim().toLocaleLowerCase()
|
|
||||||
)) ||
|
|
||||||
(user_right_title &&
|
|
||||||
!["admin", "user", "supervisor"].includes(
|
|
||||||
user_right_title?.trim().toLocaleLowerCase()
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json(
|
|
||||||
response(
|
|
||||||
"1",
|
|
||||||
`The user profile ${
|
|
||||||
user_right_title || user_right_id
|
|
||||||
} provided by the property user_right_title or user_right_id does not match the following profiles: admin, user, supervisor`,
|
|
||||||
"0",
|
|
||||||
"checkUserRight"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const _user: any = await User.findOne({
|
|
||||||
where: {
|
|
||||||
secondaryId: user_id
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!_user)
|
|
||||||
return res
|
|
||||||
.status(404)
|
|
||||||
.json(response("1", `User ${user_id} not exist`, "0", "checkUserRight"));
|
|
||||||
|
|
||||||
if (
|
|
||||||
(user_right_id && _user.profile != user_right_id) ||
|
|
||||||
(user_right_title && _user.profile != user_right_title)
|
|
||||||
) {
|
|
||||||
return res
|
|
||||||
.status(403)
|
|
||||||
.json(
|
|
||||||
response(
|
|
||||||
"1",
|
|
||||||
`User ${user_id} does not have this profile`,
|
|
||||||
"0",
|
|
||||||
"checkUserRight"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.json(
|
|
||||||
response(
|
|
||||||
"1",
|
|
||||||
`User ${user_id} has ${user_right_title || user_right_id} profile`,
|
|
||||||
"1",
|
|
||||||
"checkUserRight"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
async function logoutUser(userId: any) {
|
|
||||||
await stopWhoIsOnlineMonitor();
|
|
||||||
|
|
||||||
let onlineTime = {
|
|
||||||
userId: `${userId}`,
|
|
||||||
status: "logout..."
|
|
||||||
};
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("onlineStatus", {
|
|
||||||
action: "logout",
|
|
||||||
userOnlineTime: onlineTime
|
|
||||||
});
|
|
||||||
|
|
||||||
await startWhoIsOnlineMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
function response(code: string, msg: string, obj: any, type: string) {
|
|
||||||
let payload = { return_code: code, return_msg: msg };
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "createUser":
|
|
||||||
return { ...payload, user_created: obj };
|
|
||||||
case "deleteUser":
|
|
||||||
return { ...payload, user_removed: obj };
|
|
||||||
case "listAllUsers":
|
|
||||||
return { ...payload, user_list: obj };
|
|
||||||
case "checkUser":
|
|
||||||
return { ...payload, user_exists: obj };
|
|
||||||
case "updateUser":
|
|
||||||
return { ...payload, user_updated: obj };
|
|
||||||
case "resetPassword":
|
|
||||||
return { ...payload, password_set: obj };
|
|
||||||
case "linkUserAndUserRight":
|
|
||||||
return { ...payload, user_right_linked: obj };
|
|
||||||
case "checkUserRight":
|
|
||||||
return { ...payload, user_right_exists: obj };
|
|
||||||
default:
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function invalidProperties(body: any, pros: any[]) {
|
|
||||||
for (const field of pros) {
|
|
||||||
console.log("body[field]: ", body[field], " field: ", field);
|
|
||||||
if (!body[field]) {
|
|
||||||
return `${field} is required`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOffici
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
|
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import { get } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
|
@ -100,8 +99,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = params.find((p: any) => p?.template_name);
|
const name = params.find((p: any) => p?.template_name);
|
||||||
const { language }: any =
|
const { language }: any = params.find((p: any) => p?.language);
|
||||||
params?.find((p: any) => p?.language) || "pt_BR";
|
|
||||||
|
|
||||||
const { template_name } = name;
|
const { template_name } = name;
|
||||||
|
|
||||||
|
@ -114,10 +112,9 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("TEMPLATE: ", template);
|
|
||||||
|
|
||||||
sendWhatsAppMessageOfficialAPI(ticket, body, null, template);
|
sendWhatsAppMessageOfficialAPI(ticket, body, null, template);
|
||||||
|
|
||||||
|
console.log("TEMPLATE: ", template);
|
||||||
return res.send();
|
return res.send();
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
|
@ -5,12 +5,11 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService";
|
||||||
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
||||||
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
||||||
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
||||||
import Queue from "../models/Queue";
|
import Queue from "../models/Queue"
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError"
|
||||||
import { del, get, set } from "../helpers/RedisClient";
|
import { get, set } from "../helpers/RedisClient";
|
||||||
import { Op } from "sequelize";
|
|
||||||
import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService";
|
|
||||||
import Whatsapp from "../models/Whatsapp";
|
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const queues = await ListQueuesService();
|
const queues = await ListQueuesService();
|
||||||
|
@ -18,58 +17,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
return res.status(200).json(queues);
|
return res.status(200).json(queues);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const listQueues = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const whatsapps = await Whatsapp.findAll({
|
|
||||||
where: {
|
|
||||||
name: { [Op.ne]: "botqueue" },
|
|
||||||
number: { [Op.ne]: "" },
|
|
||||||
phoneNumberId: false
|
|
||||||
},
|
|
||||||
attributes: ["number"],
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Queue,
|
|
||||||
as: "queues",
|
|
||||||
attributes: ["id", "name"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const whats = whatsapps
|
|
||||||
?.filter((w: any) => w?.queues?.length > 0)
|
|
||||||
?.map((w: any) => {
|
|
||||||
const { number, queues } = w;
|
|
||||||
return {
|
|
||||||
number,
|
|
||||||
queues: queues?.map((q: any) => {
|
|
||||||
const { id, name } = q;
|
|
||||||
return { id, name };
|
|
||||||
})
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
let _queues: any = [];
|
|
||||||
|
|
||||||
for (const w of whats) {
|
|
||||||
const { queues } = w;
|
|
||||||
|
|
||||||
for (const q of queues) {
|
|
||||||
const { id: queueId, name } = q;
|
|
||||||
|
|
||||||
const auxQueue = _queues.findIndex((q: any) => q.queueId == queueId);
|
|
||||||
|
|
||||||
if (auxQueue == -1) {
|
|
||||||
_queues.push({ queueId, name });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json(_queues);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { name, color, greetingMessage } = req.body;
|
const { name, color, greetingMessage } = req.body;
|
||||||
|
|
||||||
|
@ -178,7 +125,7 @@ export const customization = async (
|
||||||
|
|
||||||
await set("ura", ura);
|
await set("ura", ura);
|
||||||
|
|
||||||
const _ura = await get({ key: "ura", parse: true });
|
const _ura = await get("ura");
|
||||||
console.log("_URA: ", _ura);
|
console.log("_URA: ", _ura);
|
||||||
|
|
||||||
return res.status(200).json({ new_queues });
|
return res.status(200).json({ new_queues });
|
||||||
|
@ -217,8 +164,6 @@ export const remove = async (
|
||||||
|
|
||||||
await DeleteQueueService(queueId);
|
await DeleteQueueService(queueId);
|
||||||
|
|
||||||
await del(`queue:${queueId}`);
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("queue", {
|
io.emit("queue", {
|
||||||
action: "delete",
|
action: "delete",
|
||||||
|
|
|
@ -4,30 +4,35 @@ import { Request, Response } from "express";
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import ShowTicketReport from "../services/TicketServices/ShowTicketReport";
|
import ShowTicketReport from "../services/TicketServices/ShowTicketReport";
|
||||||
import ShowMessageReport from "../services/MessageServices/ShowMessageReport";
|
import ShowMessageReport from "../services/MessageServices/ShowMessageReport";
|
||||||
|
|
||||||
import onlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
|
import onlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
|
||||||
import User from "../models/User";
|
import User from "../models/User";
|
||||||
import Queue from "../models/Queue";
|
import Queue from "../models/Queue";
|
||||||
import UserOnlineTime from "../models/UserOnlineTime";
|
import UserOnlineTime from "../models/UserOnlineTime";
|
||||||
|
|
||||||
import { Op, Sequelize, literal } from "sequelize";
|
import { Op, Sequelize, literal } from "sequelize";
|
||||||
import format from "date-fns/format";
|
import format from 'date-fns/format';
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
import ptBR from 'date-fns/locale/pt-BR';
|
||||||
import { splitDateTime } from "../helpers/SplitDateTime";
|
import { splitDateTime } from "../helpers/SplitDateTime";
|
||||||
import ListUserOnlineOffline from "../services/UserServices/ListUsersOnlineOfflineService";
|
import ListUserOnlineOffline from "../services/UserServices/ListUsersOnlineOfflineService";
|
||||||
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
|
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
|
||||||
|
|
||||||
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
|
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
|
||||||
|
|
||||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||||
|
|
||||||
import ShowQueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
import ShowQueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
||||||
|
|
||||||
|
|
||||||
|
// import { filter } from "bluebird";
|
||||||
|
|
||||||
import { getIO } from "../libs/socket";
|
import { getIO } from "../libs/socket";
|
||||||
import { Json } from "sequelize/types/lib/utils";
|
import { Json } from "sequelize/types/lib/utils";
|
||||||
import ReportByNumberQueueService from "../services/ReportServices/ReportByNumberQueueService";
|
|
||||||
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
userId: string;
|
userId: string;
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
createdOrUpdated: string;
|
|
||||||
queueId: string;
|
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
userQueues: [];
|
userQueues: [];
|
||||||
};
|
};
|
||||||
|
@ -35,12 +40,11 @@ type IndexQuery = {
|
||||||
type ReportOnQueue = {
|
type ReportOnQueue = {
|
||||||
userId: string;
|
userId: string;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
export const reportUserByDateStartDateEnd = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
if (
|
if (
|
||||||
req.user.profile !== "master" &&
|
req.user.profile !== "master" &&
|
||||||
req.user.profile !== "admin" &&
|
req.user.profile !== "admin" &&
|
||||||
|
@ -49,42 +53,23 @@ export const reportUserByDateStartDateEnd = async (
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { userId, startDate, endDate, pageNumber, userQueues } = req.query as IndexQuery
|
||||||
userId,
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
pageNumber,
|
|
||||||
userQueues,
|
|
||||||
createdOrUpdated,
|
|
||||||
queueId
|
|
||||||
} = req.query as IndexQuery;
|
|
||||||
|
|
||||||
const { tickets, count, hasMore } = await ShowTicketReport({
|
console.log("userId, startDate, endDate, pageNumber: ", userId, startDate, endDate, pageNumber);
|
||||||
userId,
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
pageNumber,
|
|
||||||
createdOrUpdated,
|
|
||||||
queueId
|
|
||||||
});
|
|
||||||
|
|
||||||
const queues = await Queue.findAll({ attributes: ["id", "name"] });
|
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
||||||
|
// console.log('kkkkkkkkkkkkkkkkkk tickets: ', JSON.stringify(tickets, null, 6))
|
||||||
|
|
||||||
return res.status(200).json({ tickets, count, hasMore, queues });
|
return res.status(200).json({ tickets, count, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reportUserService = async (
|
|
||||||
req: Request,
|
export const reportUserService = async (req: Request, res: Response): Promise<Response> => {
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
if (req.user.profile !== "master" && req.user.profile !== "admin" && req.user.profile !=="supervisor") {
|
||||||
if (
|
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
const { userId, startDate, endDate } = req.query as IndexQuery;
|
const { userId, startDate, endDate } = req.query as IndexQuery
|
||||||
|
|
||||||
// let usersProfile = await ListUserParamiterService({ profile: 'user' })
|
// let usersProfile = await ListUserParamiterService({ profile: 'user' })
|
||||||
let usersProfile = await ListUserParamiterService({
|
let usersProfile = await ListUserParamiterService({
|
||||||
|
@ -92,89 +77,55 @@ export const reportUserService = async (
|
||||||
raw: true
|
raw: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const sumUserOlineTime = await ShowUserServiceReport({
|
const sumUserOlineTime = await ShowUserServiceReport({ startDate, endDate, userId });
|
||||||
startDate,
|
const closedByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'closed', userId });
|
||||||
endDate,
|
const openByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'open', userId });
|
||||||
userId
|
|
||||||
});
|
|
||||||
const closedByUser = await ShowUserServiceReport({
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
ticketStatus: "closed",
|
|
||||||
userId
|
|
||||||
});
|
|
||||||
const openByUser = await ShowUserServiceReport({
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
ticketStatus: "open",
|
|
||||||
userId
|
|
||||||
});
|
|
||||||
|
|
||||||
let dateTime = splitDateTime(
|
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
const onlineUsers = await ListUserOnlineOffline({ date: dateTime.fullDate })
|
||||||
);
|
|
||||||
const onlineUsers = await ListUserOnlineOffline({ date: dateTime.fullDate });
|
|
||||||
|
|
||||||
const openByUserOnQueue = await CountTicketsByUserQueue({
|
const openByUserOnQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: true })
|
||||||
startDate: startDate,
|
const openByUserOutQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: false })
|
||||||
endDate: endDate,
|
|
||||||
status: "open",
|
|
||||||
clientChatStart: true
|
|
||||||
});
|
|
||||||
const openByUserOutQueue = await CountTicketsByUserQueue({
|
|
||||||
startDate: startDate,
|
|
||||||
endDate: endDate,
|
|
||||||
status: "open",
|
|
||||||
clientChatStart: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const closedByUserOnQueue = await CountTicketsByUserQueue({
|
const closedByUserOnQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: true })
|
||||||
startDate: startDate,
|
const closedUserOutQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: false })
|
||||||
endDate: endDate,
|
|
||||||
status: "closed",
|
|
||||||
clientChatStart: true
|
|
||||||
});
|
|
||||||
const closedUserOutQueue = await CountTicketsByUserQueue({
|
|
||||||
startDate: startDate,
|
|
||||||
endDate: endDate,
|
|
||||||
status: "closed",
|
|
||||||
clientChatStart: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// let openQueueInOut = openByUserOnQueue.concat(openByUserOutQueue)
|
// let openQueueInOut = openByUserOnQueue.concat(openByUserOutQueue)
|
||||||
// let closedQueueInOut = closedByUserOnQueue.concat(closedUserOutQueue)
|
// let closedQueueInOut = closedByUserOnQueue.concat(closedUserOutQueue)
|
||||||
|
|
||||||
const queuesByUser = await ShowQueuesByUser({ profile: "user" });
|
|
||||||
|
|
||||||
let openCloseOnQueue = openByUserOnQueue.concat(closedByUserOnQueue);
|
const queuesByUser = await ShowQueuesByUser({ profile: 'user' })
|
||||||
let openCloseOutQueue = openByUserOutQueue.concat(closedUserOutQueue);
|
|
||||||
|
let openCloseOnQueue = openByUserOnQueue.concat(closedByUserOnQueue)
|
||||||
|
let openCloseOutQueue = openByUserOutQueue.concat(closedUserOutQueue)
|
||||||
|
|
||||||
|
|
||||||
// console.log('onlineUsers: ',JSON.parse(JSON.stringify(onlineUsers)))
|
// console.log('onlineUsers: ',JSON.parse(JSON.stringify(onlineUsers)))
|
||||||
// console.log('sumUserOlineTime: ', JSON.parse(JSON.stringify(sumUserOlineTime)))
|
// console.log('sumUserOlineTime: ', JSON.parse(JSON.stringify(sumUserOlineTime)))
|
||||||
|
|
||||||
for (let i = 0; i < queuesByUser.length; i++) {
|
for (let i = 0; i < queuesByUser.length; i++) {
|
||||||
queuesByUser[i].countOpen = 0;
|
|
||||||
queuesByUser[i].countClosed = 0;
|
queuesByUser[i].countOpen = 0
|
||||||
|
queuesByUser[i].countClosed = 0
|
||||||
|
|
||||||
for (let x = 0; x < openCloseOnQueue.length; x++) {
|
for (let x = 0; x < openCloseOnQueue.length; x++) {
|
||||||
if (
|
if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||||
queuesByUser[i].userId == openCloseOnQueue[x].userId &&
|
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'open')) {
|
||||||
queuesByUser[i].queueId == openCloseOnQueue[x].queueId &&
|
queuesByUser[i].countOpen = openCloseOnQueue[x].totAttendance
|
||||||
openCloseOnQueue[x].status == "open"
|
|
||||||
) {
|
|
||||||
queuesByUser[i].countOpen = openCloseOnQueue[x].totAttendance;
|
|
||||||
} else if (
|
|
||||||
queuesByUser[i].userId == openCloseOnQueue[x].userId &&
|
|
||||||
queuesByUser[i].queueId == openCloseOnQueue[x].queueId &&
|
|
||||||
openCloseOnQueue[x].status == "closed"
|
|
||||||
) {
|
|
||||||
queuesByUser[i].countClosed = openCloseOnQueue[x].totAttendance;
|
|
||||||
}
|
}
|
||||||
|
else if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||||
|
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'closed')) {
|
||||||
|
queuesByUser[i].countClosed = openCloseOnQueue[x].totAttendance
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
usersProfile.map((user: any) => {
|
usersProfile.map((user: any) => {
|
||||||
let index = sumUserOlineTime.findIndex((e: any) => e.userId == user.id);
|
|
||||||
|
let index = sumUserOlineTime.findIndex((e: any) => e.userId == user.id)
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
user.sumOnlineTime = sumUserOlineTime[index];
|
user.sumOnlineTime = sumUserOlineTime[index];
|
||||||
|
@ -182,67 +133,68 @@ export const reportUserService = async (
|
||||||
// console.log('user.sumOlineTime: 'user.sumOnlineTime)
|
// console.log('user.sumOlineTime: 'user.sumOnlineTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
index = closedByUser.findIndex((e: any) => e.userId == user.id);
|
index = closedByUser.findIndex((e: any) => e.userId == user.id)
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
user.sumClosed = closedByUser[index];
|
user.sumClosed = closedByUser[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
index = openByUser.findIndex((e: any) => e.userId == user.id);
|
index = openByUser.findIndex((e: any) => e.userId == user.id)
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
user.sumOpen = openByUser[index];
|
user.sumOpen = openByUser[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// OPEN, CLOSED TICKETS STARTED BY USERS
|
// OPEN, CLOSED TICKETS STARTED BY USERS
|
||||||
let openClosedOutQueue = {};
|
let openClosedOutQueue = {}
|
||||||
let open = openCloseOutQueue.filter(
|
let open = openCloseOutQueue.filter((e) => e.userId == user.id && e.status == 'open')
|
||||||
e => e.userId == user.id && e.status == "open"
|
let closed = openCloseOutQueue.filter((e) => e.userId == user.id && e.status == 'closed')
|
||||||
);
|
|
||||||
let closed = openCloseOutQueue.filter(
|
|
||||||
e => e.userId == user.id && e.status == "closed"
|
|
||||||
);
|
|
||||||
|
|
||||||
openClosedOutQueue = {
|
openClosedOutQueue = {
|
||||||
...openClosedOutQueue,
|
...openClosedOutQueue,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
countOpen: open && open.length > 0 ? open[0].totAttendance : 0,
|
countOpen: open && open.length > 0 ? open[0].totAttendance : 0,
|
||||||
countClosed: closed && closed.length > 0 ? closed[0].totAttendance : 0
|
countClosed: closed && closed.length > 0 ? closed[0].totAttendance : 0
|
||||||
};
|
}
|
||||||
|
|
||||||
|
user.openClosedOutQueue = openClosedOutQueue
|
||||||
|
|
||||||
user.openClosedOutQueue = openClosedOutQueue;
|
|
||||||
|
|
||||||
// OPEN, CLOSED TICKETS STARTED BY CLIENTS
|
// OPEN, CLOSED TICKETS STARTED BY CLIENTS
|
||||||
let openClosedInQueue = queuesByUser.filter(e => e.userId == user.id);
|
let openClosedInQueue = queuesByUser.filter((e) => e.userId == user.id)
|
||||||
|
|
||||||
if (openClosedInQueue && openClosedInQueue.length > 0) {
|
if (openClosedInQueue && openClosedInQueue.length > 0) {
|
||||||
user.openClosedInQueue = openClosedInQueue;
|
user.openClosedInQueue = openClosedInQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
index = onlineUsers.findIndex((e: any) => e.userId == user.id);
|
|
||||||
|
index = onlineUsers.findIndex((e: any) => e.userId == user.id)
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
user.statusOnline = onlineUsers[index];
|
user.statusOnline = onlineUsers[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startDate.length > 0 && startDate.split("-").length == 3) {
|
if (startDate.length > 0 && startDate.split('-').length == 3) {
|
||||||
let date = startDate.split("-");
|
let date = startDate.split('-')
|
||||||
user.startDate = `${date[2]}/${date[1]}/${date[0]}`;
|
user.startDate = `${date[2]}/${date[1]}/${date[0]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endDate.length > 0 && endDate.split("-").length == 3) {
|
if (endDate.length > 0 && endDate.split('-').length == 3) {
|
||||||
let date = endDate.split("-");
|
let date = endDate.split('-')
|
||||||
user.endDate = `${date[2]}/${date[1]}/${date[0]}`;
|
user.endDate = `${date[2]}/${date[1]}/${date[0]}`
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
})
|
||||||
|
|
||||||
return res.status(200).json({usersProfile: usersProfile});
|
return res.status(200).json({usersProfile: usersProfile});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reportMessagesUserByDateStartDateEnd = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
export const reportMessagesUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
||||||
): Promise<Response> => {
|
|
||||||
if (
|
if (
|
||||||
req.user.profile !== "master" &&
|
req.user.profile !== "master" &&
|
||||||
req.user.profile !== "admin" &&
|
req.user.profile !== "admin" &&
|
||||||
|
@ -251,30 +203,35 @@ export const reportMessagesUserByDateStartDateEnd = async (
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userId, startDate, endDate } = req.query as IndexQuery;
|
const { userId, startDate, endDate } = req.query as IndexQuery
|
||||||
|
|
||||||
let data_query_messages = await ShowMessageReport(userId, startDate, endDate);
|
let data_query_messages = await ShowMessageReport(userId, startDate, endDate);
|
||||||
|
|
||||||
for (var i = 0; i < data_query_messages.length; i++) {
|
for (var i = 0; i < data_query_messages.length; i++) {
|
||||||
|
|
||||||
if (data_query_messages[i].fromMe) {
|
if (data_query_messages[i].fromMe) {
|
||||||
data_query_messages[i].fromMe = "Atendente";
|
data_query_messages[i].fromMe = 'Atendente'
|
||||||
} else {
|
}
|
||||||
data_query_messages[i].fromMe = "Cliente";
|
else {
|
||||||
|
data_query_messages[i].fromMe = 'Cliente'
|
||||||
}
|
}
|
||||||
|
|
||||||
data_query_messages[i].id = i + 1;
|
data_query_messages[i].id = (i + 1)
|
||||||
|
|
||||||
|
console.log('data_query_messages: ', data_query_messages[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).json(data_query_messages);
|
return res.status(200).json(data_query_messages);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reportOnQueue = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
export const reportOnQueue = async (req: Request, res: Response): Promise<Response> => {
|
||||||
): Promise<Response> => {
|
|
||||||
// console.log(req.body)
|
// console.log(req.body)
|
||||||
|
|
||||||
const { adminId, identifier, queueStatus, file } = req.body;
|
const { adminId, identifier, queueStatus, file } = req.body
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("queryOnQueueStatus", {
|
io.emit("queryOnQueueStatus", {
|
||||||
|
@ -287,80 +244,10 @@ export const reportOnQueue = async (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ message: "ok" });
|
return res.status(200).json({ message: 'ok' })
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reportService = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
if (
|
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { startDate, endDate, queueId } = req.query as IndexQuery;
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`startDate: ${startDate} | endDate: ${endDate} | queueId: ${queueId}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const reportService = await ReportByNumberQueueService({
|
|
||||||
startDate,
|
|
||||||
endDate
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json({ reportService });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reportServiceByQueue = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
if (
|
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { startDate, endDate, queueId } = req.query as IndexQuery;
|
|
||||||
|
|
||||||
const reportService = await ReportByNumberQueueService({
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
queue: true
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json({ reportService });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reportTicksCountByStatusChatEnds = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
if (
|
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { startDate, endDate } = req.query as IndexQuery;
|
|
||||||
|
|
||||||
const dateToday = splitDateTime(
|
|
||||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
|
||||||
);
|
|
||||||
|
|
||||||
const reportStatusChatEnd = await CountStatusChatEndService(
|
|
||||||
startDate || dateToday.fullDate,
|
|
||||||
endDate || dateToday.fullDate
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).json({ reportStatusChatEnd });
|
|
||||||
};
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
// const config = await SettingTicket.findAll();
|
// const config = await SettingTicket.findAll();
|
||||||
|
|
||||||
return res.status(200).json({ settings });
|
return res.status(200).json({ settings, });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ticketSettings = async (
|
export const ticketSettings = async (
|
||||||
|
@ -40,7 +40,6 @@ export const updateTicketSettings = async (
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
number,
|
number,
|
||||||
saturdayBusinessTime,
|
|
||||||
outBusinessHours,
|
outBusinessHours,
|
||||||
ticketExpiration,
|
ticketExpiration,
|
||||||
weekend,
|
weekend,
|
||||||
|
@ -59,14 +58,6 @@ export const updateTicketSettings = async (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saturdayBusinessTime && Object.keys(saturdayBusinessTime).length > 0) {
|
|
||||||
await updateSettingTicket({
|
|
||||||
...saturdayBusinessTime,
|
|
||||||
key: "saturdayBusinessTime",
|
|
||||||
number
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
|
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...ticketExpiration,
|
...ticketExpiration,
|
||||||
|
|
|
@ -22,7 +22,7 @@ import format from "date-fns/format";
|
||||||
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
|
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
|
||||||
|
|
||||||
import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
|
import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
|
||||||
import { Op, where } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
|
@ -68,15 +68,6 @@ import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsA
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
|
||||||
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
|
||||||
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
|
||||||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
|
||||||
import CreateContactService from "../services/ContactServices/CreateContactService";
|
|
||||||
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
|
|
||||||
import WhatsappQueue from "../models/WhatsappQueue";
|
|
||||||
import { get } from "../helpers/RedisClient";
|
|
||||||
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
|
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
|
@ -95,7 +86,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
let queueIds: number[] = [];
|
let queueIds: number[] = [];
|
||||||
|
|
||||||
if (queueIdsStringified && queueIdsStringified.trim().length > 0) {
|
if (queueIdsStringified) {
|
||||||
queueIds = JSON.parse(queueIdsStringified);
|
queueIds = JSON.parse(queueIdsStringified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,158 +106,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
return res.status(200).json({ tickets, count, hasMore });
|
return res.status(200).json({ tickets, count, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remoteTicketCreation = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
let { queueId, contact_from, contact_to, msg, contact_name }: any = req.body;
|
|
||||||
|
|
||||||
let whatsappId: any;
|
|
||||||
|
|
||||||
if (!queueId && !contact_from) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json({ error: `Property 'queueId' or 'contact_from' is required.` });
|
|
||||||
}
|
|
||||||
|
|
||||||
const validate = ["contact_to", "msg"];
|
|
||||||
const validateOnlyNumber = ["queueId", "contact_to", "contact_from"];
|
|
||||||
|
|
||||||
for (let prop of validate) {
|
|
||||||
if (!req.body[prop])
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json({ error: `Property '${prop}' is undefined.` });
|
|
||||||
|
|
||||||
if (validateOnlyNumber.includes(prop)) {
|
|
||||||
if (!/^\d+$/.test(req.body[prop])) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json({ error: `The property '${prop}' must be a number` });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queueId) {
|
|
||||||
const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");
|
|
||||||
|
|
||||||
if (!whatsapps || whatsapps?.length == 0) {
|
|
||||||
return res.status(500).json({
|
|
||||||
msg: `queueId ${queueId} does not have a WhatsApp number associated with it or the number's session is disconnected.`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = whatsapps[0];
|
|
||||||
|
|
||||||
whatsappId = id;
|
|
||||||
} else if (contact_from) {
|
|
||||||
const whatsapp = await Whatsapp.findOne({
|
|
||||||
where: { number: contact_from, status: "CONNECTED" }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!whatsapp) {
|
|
||||||
return res.status(404).json({
|
|
||||||
msg: `Whatsapp number ${contact_from} not found or disconnected!`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = whatsapp;
|
|
||||||
|
|
||||||
const { queues } = await ShowWhatsAppService(id);
|
|
||||||
|
|
||||||
if (!queues || queues.length == 0) {
|
|
||||||
return res.status(500).json({
|
|
||||||
msg: `The WhatsApp number ${contact_from} is not associated with any queue! `
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
queueId = queues[0].id;
|
|
||||||
whatsappId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// const validNumber = await CheckIsValidContact(contact_to, true);
|
|
||||||
const validNumber = contact_to;
|
|
||||||
|
|
||||||
if (validNumber) {
|
|
||||||
let contact = await Contact.findOne({ where: { number: validNumber } });
|
|
||||||
|
|
||||||
if (!contact) {
|
|
||||||
// const profilePicUrl = await GetProfilePicUrl(validNumber);
|
|
||||||
|
|
||||||
contact = await CreateContactService({
|
|
||||||
name: contact_name ? contact_name : contact_to,
|
|
||||||
number: validNumber
|
|
||||||
// profilePicUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("contact", {
|
|
||||||
action: "create",
|
|
||||||
contact
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id: contactId } = contact;
|
|
||||||
|
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
|
||||||
|
|
||||||
let ticket = await Ticket.findOne({
|
|
||||||
where: {
|
|
||||||
[Op.or]: [
|
|
||||||
{ contactId, status: "queueChoice" },
|
|
||||||
{ contactId, status: "open", userId: botInfo.userIdBot }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
|
|
||||||
if (ticket) {
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { status: "closed" },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
ticket = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ticket) {
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { status: "closed" },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ticket) {
|
|
||||||
ticket = await FindOrCreateTicketService(
|
|
||||||
contact,
|
|
||||||
whatsappId,
|
|
||||||
0,
|
|
||||||
undefined,
|
|
||||||
queueId
|
|
||||||
);
|
|
||||||
botSendMessage(ticket, `${msg}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.to(ticket.status).emit("ticket", {
|
|
||||||
action: "update",
|
|
||||||
ticket
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 200 | MSG: success`
|
|
||||||
);
|
|
||||||
return res.status(200).json({ msg: "success" });
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: The number ${contact_to} does not exist on WhatsApp`
|
|
||||||
);
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json({ msg: `The number ${contact_to} does not exist on WhatsApp` });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
||||||
req.body;
|
req.body;
|
||||||
|
@ -372,8 +211,7 @@ export const update = async (
|
||||||
ticketData: {
|
ticketData: {
|
||||||
status: status,
|
status: status,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
statusChatEnd: statusChatEndName.name,
|
statusChatEnd: statusChatEndName.name
|
||||||
statusChatEndId: statusChatEndName.id
|
|
||||||
},
|
},
|
||||||
ticketId
|
ticketId
|
||||||
});
|
});
|
||||||
|
@ -431,6 +269,7 @@ export const update = async (
|
||||||
for (const w of whatsappsByqueue) {
|
for (const w of whatsappsByqueue) {
|
||||||
let whats = await ListWhatsAppsNumber(w.id);
|
let whats = await ListWhatsAppsNumber(w.id);
|
||||||
|
|
||||||
|
console.log("-------> WHATS: ", JSON.stringify(whats, null, 6));
|
||||||
const ticket = await Ticket.findOne({
|
const ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
[Op.and]: [
|
[Op.and]: [
|
||||||
|
@ -587,3 +426,10 @@ export const remove = async (
|
||||||
|
|
||||||
return res.status(200).json({ message: "ticket deleted" });
|
return res.status(200).json({ message: "ticket deleted" });
|
||||||
};
|
};
|
||||||
|
// export async function setMessageAsRead(ticket: Ticket) {
|
||||||
|
// const wbot_url = await getWbot(ticket.whatsappId);
|
||||||
|
|
||||||
|
// console.log('wbot_url: ', wbot_url, ' | ticket.contact.number: ', ticket.contact.number);
|
||||||
|
|
||||||
|
// await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
||||||
|
// }
|
||||||
|
|
|
@ -12,7 +12,7 @@ import DeleteUserService from "../services/UserServices/DeleteUserService";
|
||||||
|
|
||||||
import ListUser from "../services/UserServices/ListUserParamiterService";
|
import ListUser from "../services/UserServices/ListUserParamiterService";
|
||||||
import User from "../models/User";
|
import User from "../models/User";
|
||||||
import { del, get, set } from "../helpers/RedisClient";
|
import { get, set } from "../helpers/RedisClient";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
startWhoIsOnlineMonitor,
|
startWhoIsOnlineMonitor,
|
||||||
|
@ -27,7 +27,6 @@ import { splitDateTime } from "../helpers/SplitDateTime";
|
||||||
import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService";
|
import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService";
|
||||||
import { json } from "sequelize";
|
import { json } from "sequelize";
|
||||||
import { getSettingValue } from "../helpers/WhaticketSettings";
|
import { getSettingValue } from "../helpers/WhaticketSettings";
|
||||||
import { setBotInfo } from "../helpers/SetBotInfo";
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
|
@ -100,7 +99,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
// };
|
// };
|
||||||
|
|
||||||
export const all = async (req: Request, res: Response): Promise<Response> => {
|
export const all = async (req: Request, res: Response): Promise<Response> => {
|
||||||
let { userId, profile }: any = req.query as IndexQuery;
|
const { userId, profile } = req.query as IndexQuery;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"userId: ",
|
"userId: ",
|
||||||
|
@ -112,8 +111,6 @@ export const all = async (req: Request, res: Response): Promise<Response> => {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") {
|
if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") {
|
||||||
if (!userId) return res.json({ users: [], queues: [] });
|
|
||||||
|
|
||||||
const obj = await ListUserByWhatsappQueuesService(
|
const obj = await ListUserByWhatsappQueuesService(
|
||||||
userId,
|
userId,
|
||||||
'"admin", "user", "supervisor"'
|
'"admin", "user", "supervisor"'
|
||||||
|
@ -167,11 +164,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
queueIds
|
queueIds
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user) {
|
|
||||||
const { id, name } = user;
|
|
||||||
await set(`user:${id}`, { id, name });
|
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("user", {
|
io.emit("user", {
|
||||||
action: "create",
|
action: "create",
|
||||||
|
@ -275,11 +267,34 @@ export const update = async (
|
||||||
|
|
||||||
let user: any = await UpdateUserService({ userData, userId });
|
let user: any = await UpdateUserService({ userData, userId });
|
||||||
|
|
||||||
await setBotInfo(user);
|
if (user?.name?.trim() == "botqueue") {
|
||||||
|
let botInfo;
|
||||||
|
|
||||||
if (user) {
|
if (
|
||||||
const { id, name } = user;
|
user?.queues?.length > 0 &&
|
||||||
await set(`user:${id}`, { id, name });
|
user.queues[0]?.name?.trim() == "botqueue"
|
||||||
|
) {
|
||||||
|
botInfo = JSON.stringify({
|
||||||
|
userId: user.id,
|
||||||
|
queueId: user.queues[0].id,
|
||||||
|
botIsOnQueue: true
|
||||||
|
});
|
||||||
|
botInfo = JSON.parse(botInfo);
|
||||||
|
|
||||||
|
await set("botInfo", botInfo);
|
||||||
|
} else if (
|
||||||
|
user?.queues?.length == 0 ||
|
||||||
|
user.queues[0]?.name?.trim() != "botqueue"
|
||||||
|
) {
|
||||||
|
botInfo = JSON.stringify({
|
||||||
|
userId: user.id,
|
||||||
|
queueId: 0,
|
||||||
|
botIsOnQueue: false
|
||||||
|
});
|
||||||
|
botInfo = JSON.parse(botInfo);
|
||||||
|
|
||||||
|
await set("botInfo", botInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -305,8 +320,6 @@ export const remove = async (
|
||||||
|
|
||||||
await DeleteUserService(userId);
|
await DeleteUserService(userId);
|
||||||
|
|
||||||
del(`user:${userId}`);
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("user", {
|
io.emit("user", {
|
||||||
action: "delete",
|
action: "delete",
|
||||||
|
|
|
@ -42,7 +42,6 @@ import { getSettingValue } from "../helpers/WhaticketSettings";
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||||
import SettingTicket from "../models/SettingTicket";
|
import SettingTicket from "../models/SettingTicket";
|
||||||
import { Op } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
import { del, get, set } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
interface WhatsappData {
|
interface WhatsappData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -55,7 +54,6 @@ interface WhatsappData {
|
||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
isOfficial?: boolean;
|
isOfficial?: boolean;
|
||||||
phoneNumberId?: string;
|
phoneNumberId?: string;
|
||||||
number?: string;
|
|
||||||
wabaId?: string;
|
wabaId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,25 +228,6 @@ export const weebhook = async (
|
||||||
req.body.entry[0].changes[0].value.metadata.display_phone_number;
|
req.body.entry[0].changes[0].value.metadata.display_phone_number;
|
||||||
let type = message.type;
|
let type = message.type;
|
||||||
|
|
||||||
const contact_to_exist = await get({
|
|
||||||
key: "whatsapp:*",
|
|
||||||
value: `${contact_to}`
|
|
||||||
});
|
|
||||||
|
|
||||||
if (contact_to_exist == null) {
|
|
||||||
console.log(
|
|
||||||
"WHATSAPP OFFICIAL",
|
|
||||||
" | CONCTACT_FROM: ",
|
|
||||||
contact_from,
|
|
||||||
" | CONTACT_TO: ",
|
|
||||||
contact_to
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
"NUMBER IGNORED. WHATSAPP NUMBER FROM ANOTHER OMNIHIT APPLICATION!"
|
|
||||||
);
|
|
||||||
return res.status(403).json({ error: "Unauthorized" });
|
|
||||||
}
|
|
||||||
|
|
||||||
let wbot = {};
|
let wbot = {};
|
||||||
let msg = {};
|
let msg = {};
|
||||||
let contacts = req.body.entry[0].changes[0].value.contacts[0];
|
let contacts = req.body.entry[0].changes[0].value.contacts[0];
|
||||||
|
@ -268,10 +247,6 @@ export const weebhook = async (
|
||||||
});
|
});
|
||||||
|
|
||||||
if (type == "text") {
|
if (type == "text") {
|
||||||
if (!message?.text?.body) {
|
|
||||||
return res.status(400).json({ error: "body not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
type = "chat";
|
type = "chat";
|
||||||
msg = {
|
msg = {
|
||||||
...msg,
|
...msg,
|
||||||
|
@ -279,10 +254,6 @@ export const weebhook = async (
|
||||||
type
|
type
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (!message[message?.type]?.id) {
|
|
||||||
return res.status(400).json({ error: "id not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const mediaId = message[message.type].id;
|
const mediaId = message[message.type].id;
|
||||||
const mimetype = message[message.type].mime_type;
|
const mimetype = message[message.type].mime_type;
|
||||||
|
|
||||||
|
@ -351,8 +322,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
urlApi,
|
urlApi,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId,
|
||||||
isOfficial,
|
isOfficial
|
||||||
number
|
|
||||||
}: WhatsappData = req.body;
|
}: WhatsappData = req.body;
|
||||||
|
|
||||||
if (req.user.profile !== "master") {
|
if (req.user.profile !== "master") {
|
||||||
|
@ -363,8 +333,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
urlApi,
|
urlApi,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId
|
||||||
number
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
|
@ -377,7 +346,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
} else if (!isOfficial) {
|
} else if (!isOfficial) {
|
||||||
phoneNumberId = "";
|
phoneNumberId = "";
|
||||||
wabaId = "";
|
wabaId = "";
|
||||||
number = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let invalidPhoneName = validatePhoneName(name);
|
let invalidPhoneName = validatePhoneName(name);
|
||||||
|
@ -397,8 +365,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
queueIds,
|
queueIds,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId,
|
||||||
isOfficial,
|
isOfficial
|
||||||
number
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("whatsapp.id: ", whatsapp.id);
|
console.log("whatsapp.id: ", whatsapp.id);
|
||||||
|
@ -410,16 +377,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
number: getNumberFromName(name),
|
number: getNumberFromName(name),
|
||||||
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await set(
|
|
||||||
`whatsapp:${whatsapp.id}`,
|
|
||||||
JSON.stringify({
|
|
||||||
number: whatsapp?.number,
|
|
||||||
id: whatsapp?.id,
|
|
||||||
greetingMessage: whatsapp?.greetingMessage,
|
|
||||||
phoneNumberId: whatsapp?.phoneNumberId
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -459,14 +416,13 @@ export const update = async (
|
||||||
return res.status(200).json({ message: invalidPhoneName });
|
return res.status(200).json({ message: invalidPhoneName });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { urlApi, isOfficial, phoneNumberId, number, wabaId } = whatsappData;
|
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData;
|
||||||
|
|
||||||
const invalid = checkWhatsAppData({
|
const invalid = checkWhatsAppData({
|
||||||
urlApi,
|
urlApi,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId
|
||||||
number
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
|
@ -479,7 +435,6 @@ export const update = async (
|
||||||
} else if (!isOfficial) {
|
} else if (!isOfficial) {
|
||||||
whatsappData.phoneNumberId = "";
|
whatsappData.phoneNumberId = "";
|
||||||
whatsappData.wabaId = "";
|
whatsappData.wabaId = "";
|
||||||
whatsappData.number = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
|
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
|
||||||
|
@ -494,16 +449,6 @@ export const update = async (
|
||||||
number: getNumberFromName(whatsapp.name),
|
number: getNumberFromName(whatsapp.name),
|
||||||
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await set(
|
|
||||||
`whatsapp:${whatsapp.id}`,
|
|
||||||
JSON.stringify({
|
|
||||||
number: whatsapp?.number,
|
|
||||||
id: whatsapp?.id,
|
|
||||||
greetingMessage: whatsapp?.greetingMessage,
|
|
||||||
phoneNumberId: whatsapp?.phoneNumberId
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -541,8 +486,6 @@ export const remove = async (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await del(`whatsapp:${whatsappId}`);
|
|
||||||
|
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||||
|
|
||||||
// Remove tickets business hours config
|
// Remove tickets business hours config
|
||||||
|
@ -606,22 +549,18 @@ interface WhatsappDataValidate {
|
||||||
isOfficial?: boolean;
|
isOfficial?: boolean;
|
||||||
phoneNumberId?: string;
|
phoneNumberId?: string;
|
||||||
wabaId?: string;
|
wabaId?: string;
|
||||||
number?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkWhatsAppData = ({
|
const checkWhatsAppData = ({
|
||||||
urlApi,
|
urlApi,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId
|
||||||
number
|
|
||||||
}: WhatsappDataValidate) => {
|
}: WhatsappDataValidate) => {
|
||||||
if (isOfficial && (!phoneNumberId || phoneNumberId.trim() == "")) {
|
if (isOfficial && (!phoneNumberId || phoneNumberId.trim() == "")) {
|
||||||
return { message: "Phone number Id is required!" };
|
return { message: "Phone number Id is required!" };
|
||||||
} else if (isOfficial && (!wabaId || wabaId.trim() == "")) {
|
} else if (isOfficial && (!wabaId || wabaId.trim() == "")) {
|
||||||
return { message: "WABA ID is required!" };
|
return { message: "WABA ID is required!" };
|
||||||
} else if (isOfficial && (!number || number.trim() == "")) {
|
|
||||||
return { message: "Phone number is required!" };
|
|
||||||
} else if (!isOfficial && (!urlApi || urlApi.trim() == "")) {
|
} else if (!isOfficial && (!urlApi || urlApi.trim() == "")) {
|
||||||
return { message: "urlApi is required!" };
|
return { message: "urlApi is required!" };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Messages", "fromAgent", {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Messages", "fromAgent");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Users", "secondaryId", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Users", "secondaryId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Tickets", "statusChatEndId", {
|
|
||||||
type: DataTypes.INTEGER,
|
|
||||||
references: { model: "StatusChatEnds", key: "id" },
|
|
||||||
onUpdate: "CASCADE",
|
|
||||||
onDelete: "SET NULL",
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Tickets", "statusChatEndId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { QueryInterface } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkInsert(
|
|
||||||
"SettingTickets",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
message: "",
|
|
||||||
startTime: new Date(),
|
|
||||||
endTime: new Date(),
|
|
||||||
value: "disabled",
|
|
||||||
key: "saturdayBusinessTime",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkDelete("SettingTickets", {});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,5 +1,5 @@
|
||||||
class AppError {
|
class AppError {
|
||||||
public message: string;
|
public readonly message: string;
|
||||||
|
|
||||||
public readonly statusCode: number;
|
public readonly statusCode: number;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ import ListUsersService from "../services/UserServices/ListUsersService";
|
||||||
import { get } from "./RedisClient";
|
import { get } from "./RedisClient";
|
||||||
|
|
||||||
const _botIsOnQueue = async (botName: string) => {
|
const _botIsOnQueue = async (botName: string) => {
|
||||||
const botInfo = await get({ key: "botInfo", parse: true });
|
|
||||||
|
const botInfo = await get("botInfo");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
botInfo &&
|
botInfo &&
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Op } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
import User from "../models/User";
|
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||||
import { getSettingValue } from "./WhaticketSettings";
|
import { getSettingValue } from "./WhaticketSettings";
|
||||||
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
|
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
|
||||||
|
@ -16,9 +15,9 @@ const CheckContactOpenTickets = async (
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||||
|
|
||||||
// console.log("contactId: ", contactId, " | whatsappId: ", whatsappId);
|
console.log("contactId: ", contactId, " | whatsappId: ", whatsappId);
|
||||||
|
|
||||||
// console.log("WHATS: ", JSON.stringify(whats, null, 6));
|
console.log("WHATS: ", JSON.stringify(whats, null, 6));
|
||||||
|
|
||||||
ticket = await Ticket.findOne({
|
ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
|
@ -39,13 +38,8 @@ const CheckContactOpenTickets = async (
|
||||||
|
|
||||||
if (ticket) {
|
if (ticket) {
|
||||||
if (handle) return true;
|
if (handle) return true;
|
||||||
const userName = await User.findOne({
|
|
||||||
where:{ id: ticket.userId }
|
|
||||||
});
|
|
||||||
const error = new AppError("ERR_OTHER_OPEN_TICKET");
|
|
||||||
error.message = `Erro: já existe um ticket criado com esse contato. Responsável: ${userName? userName.name.toUpperCase() : 'Aguardando'}`;
|
|
||||||
|
|
||||||
throw error;
|
throw new AppError("ERR_OTHER_OPEN_TICKET");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,15 @@ import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
||||||
interface Request {
|
interface Request {
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
queueId?: string | number;
|
queueId?: string | number;
|
||||||
ignoreNoWhatsappFound?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
|
||||||
|
|
||||||
const GetDefaultWhatsApp = async ({
|
const GetDefaultWhatsApp = async ({
|
||||||
userId,
|
userId,
|
||||||
queueId,
|
queueId
|
||||||
ignoreNoWhatsappFound = false
|
|
||||||
}: Request): Promise<any> => {
|
}: Request): Promise<any> => {
|
||||||
|
// test del
|
||||||
let defaultWhatsapp = await Whatsapp.findOne({
|
let defaultWhatsapp = await Whatsapp.findOne({
|
||||||
where: { isDefault: true }
|
where: { isDefault: true }
|
||||||
});
|
});
|
||||||
|
@ -55,16 +56,17 @@ const GetDefaultWhatsApp = async ({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultWhatsapp = await Whatsapp.findOne({
|
defaultWhatsapp = await Whatsapp.findOne({
|
||||||
where: { status: "CONNECTED", isOfficial: false }
|
where: { status: "CONNECTED" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultWhatsapp && !ignoreNoWhatsappFound) {
|
if (!defaultWhatsapp) {
|
||||||
throw new AppError("ERR_NO_DEF_WAPP_FOUND");
|
throw new AppError("ERR_NO_DEF_WAPP_FOUND");
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultWhatsapp;
|
return defaultWhatsapp;
|
||||||
|
//
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GetDefaultWhatsApp;
|
export default GetDefaultWhatsApp;
|
||||||
|
|
|
@ -15,9 +15,9 @@ async function omnihitDashboardSession(data: any) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log(
|
console.log(
|
||||||
// `Post request error to ${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor`
|
`Post request error to ${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor`
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,101 +6,27 @@ type WhatsappData = {
|
||||||
contactId: string | number;
|
contactId: string | number;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
history?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type getData = {
|
export async function set(key: string, value: string, expire: boolean = false) {
|
||||||
key: string;
|
await redis.set(key, JSON.stringify(value));
|
||||||
value?: string;
|
|
||||||
parse?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function set(key: string, value: string | object) {
|
if (expire) await redis.expire(key, 300);
|
||||||
if (typeof value == "object") await redis.set(key, JSON.stringify(value));
|
|
||||||
else {
|
|
||||||
await redis.set(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSimple(key: string) {
|
export async function get(key: string) {
|
||||||
const value: any = await redis.get(key);
|
const value: any = await redis.get(key);
|
||||||
return value;
|
return JSON.parse(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get({ key, value, parse }: getData) {
|
|
||||||
if (key.includes("*")) {
|
|
||||||
const keys = await redis.keys(key);
|
|
||||||
if (keys.length > 0) {
|
|
||||||
for (const key of keys) {
|
|
||||||
const val = await redis.get(key);
|
|
||||||
if (val.includes(value)) {
|
|
||||||
if (parse) return JSON.parse(val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
const value: any = await redis.get(key);
|
|
||||||
|
|
||||||
if (parse) return JSON.parse(value);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function del(key: string) {
|
export async function del(key: string) {
|
||||||
await redis.del(key);
|
await redis.del(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clearAllKeys(...keys: string[]) {
|
|
||||||
for (const key of keys) {
|
|
||||||
// Retrieve all keys matching the pattern '*'
|
|
||||||
const del_keys = await redis.keys(key);
|
|
||||||
|
|
||||||
// If there are keys, delete them
|
|
||||||
if (del_keys.length > 0) {
|
|
||||||
console.log("del_keys: ", del_keys);
|
|
||||||
await redis.del(...del_keys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function findByContain(
|
|
||||||
key: string,
|
|
||||||
keyName: string,
|
|
||||||
substring: string
|
|
||||||
) {
|
|
||||||
// const keys = await redis.keys("*" + substring + "*");
|
|
||||||
// const keys = await redis.keys("user:*");
|
|
||||||
|
|
||||||
const keys = await redis.keys(key);
|
|
||||||
|
|
||||||
const results: any[] = [];
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
const value = await redis.get(key);
|
|
||||||
if (value) {
|
|
||||||
const obj = JSON.parse(value);
|
|
||||||
if (
|
|
||||||
substring
|
|
||||||
?.trim()
|
|
||||||
?.toLowerCase()
|
|
||||||
.includes(obj[keyName]?.trim()?.toLowerCase())
|
|
||||||
) {
|
|
||||||
results.push(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createObject({
|
export async function createObject({
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier,
|
identifier,
|
||||||
value,
|
value
|
||||||
history = ""
|
|
||||||
}: WhatsappData) {
|
}: WhatsappData) {
|
||||||
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
||||||
const result = await redis.hmset(
|
const result = await redis.hmset(
|
||||||
|
@ -112,9 +38,7 @@ export async function createObject({
|
||||||
"identifier",
|
"identifier",
|
||||||
identifier,
|
identifier,
|
||||||
"value",
|
"value",
|
||||||
value,
|
value
|
||||||
"history",
|
|
||||||
history
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await redis.expire(key, 300);
|
await redis.expire(key, 300);
|
||||||
|
@ -142,8 +66,7 @@ export async function findObject(
|
||||||
"whatsappId",
|
"whatsappId",
|
||||||
"contactId",
|
"contactId",
|
||||||
"identifier",
|
"identifier",
|
||||||
"value",
|
"value"
|
||||||
"history"
|
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { get, set } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
export async function setBotInfo(user: any) {
|
|
||||||
if (user?.name?.trim() == "botqueue") {
|
|
||||||
let botInfo;
|
|
||||||
|
|
||||||
if (
|
|
||||||
user?.queues?.length > 0 &&
|
|
||||||
user.queues[0]?.name?.trim() == "botqueue"
|
|
||||||
) {
|
|
||||||
botInfo = JSON.stringify({
|
|
||||||
userId: user.id,
|
|
||||||
queueId: user.queues[0].id,
|
|
||||||
botIsOnQueue: true
|
|
||||||
});
|
|
||||||
botInfo = JSON.parse(botInfo);
|
|
||||||
|
|
||||||
await set("botInfo", botInfo);
|
|
||||||
} else if (
|
|
||||||
user?.queues?.length == 0 ||
|
|
||||||
user.queues[0]?.name?.trim() != "botqueue"
|
|
||||||
) {
|
|
||||||
botInfo = JSON.stringify({
|
|
||||||
userId: user.id,
|
|
||||||
queueId: 0,
|
|
||||||
botIsOnQueue: false
|
|
||||||
});
|
|
||||||
botInfo = JSON.parse(botInfo);
|
|
||||||
|
|
||||||
await set("botInfo", botInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -62,8 +62,21 @@ const isWeekend = async (number: string | number) => {
|
||||||
weekend.value == "enabled" &&
|
weekend.value == "enabled" &&
|
||||||
weekend.message?.trim()?.length > 0
|
weekend.message?.trim()?.length > 0
|
||||||
) {
|
) {
|
||||||
|
// Specify your desired timezone
|
||||||
|
const brazilTimeZone = "America/Sao_Paulo";
|
||||||
|
|
||||||
|
const currentDateUtc = new Date();
|
||||||
|
|
||||||
|
// Convert UTC date to Brazil time zone
|
||||||
|
const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);
|
||||||
|
|
||||||
|
// Format the date using the desired format
|
||||||
|
const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");
|
||||||
|
|
||||||
|
const parsedDate = parseISO(formattedDate);
|
||||||
|
|
||||||
// Convert parsed date to Brazil time zone
|
// Convert parsed date to Brazil time zone
|
||||||
const localDate = localDateConvert();
|
const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
|
||||||
|
|
||||||
// Check if it's Saturday or Sunday
|
// Check if it's Saturday or Sunday
|
||||||
if (isSaturday(localDate)) {
|
if (isSaturday(localDate)) {
|
||||||
|
@ -160,104 +173,8 @@ async function isOutBusinessTime(number: string | number) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isOutBusinessTimeSaturday(number: string | number) {
|
export {
|
||||||
let obj = { set: false, msg: "" };
|
isWeekend,
|
||||||
|
isHoliday,
|
||||||
// Convert parsed date to Brazil time zone
|
isOutBusinessTime
|
||||||
const localDate = localDateConvert();
|
};
|
||||||
|
|
||||||
// Check if it's Saturday or Sunday
|
|
||||||
if (!isSaturday(localDate)) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
const outBusinessHoursSaturday = await SettingTicket.findOne({
|
|
||||||
where: { key: "saturdayBusinessTime", number }
|
|
||||||
});
|
|
||||||
|
|
||||||
let isWithinRange = false;
|
|
||||||
|
|
||||||
if (
|
|
||||||
outBusinessHoursSaturday &&
|
|
||||||
outBusinessHoursSaturday.value == "enabled" &&
|
|
||||||
outBusinessHoursSaturday?.message?.trim()?.length > 0
|
|
||||||
) {
|
|
||||||
const ticketDateTimeUpdate = splitDateTime(
|
|
||||||
new Date(
|
|
||||||
_format(new Date(), "yyyy-MM-dd HH:mm:ss", {
|
|
||||||
locale: ptBR
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const startTime = splitDateTime(
|
|
||||||
new Date(
|
|
||||||
_format(
|
|
||||||
new Date(outBusinessHoursSaturday.startTime),
|
|
||||||
"yyyy-MM-dd HH:mm:ss",
|
|
||||||
{
|
|
||||||
locale: ptBR
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const endTime = splitDateTime(
|
|
||||||
new Date(
|
|
||||||
_format(
|
|
||||||
new Date(outBusinessHoursSaturday.endTime),
|
|
||||||
"yyyy-MM-dd HH:mm:ss",
|
|
||||||
{
|
|
||||||
locale: ptBR
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const format = "HH:mm:ss";
|
|
||||||
const parsedStartTime = parse(
|
|
||||||
ticketDateTimeUpdate.fullTime,
|
|
||||||
format,
|
|
||||||
new Date()
|
|
||||||
);
|
|
||||||
const parsedEndTime = parse(startTime.fullTime, format, new Date());
|
|
||||||
const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
|
|
||||||
const timeInterval = { start: parsedStartTime, end: parsedEndTime };
|
|
||||||
|
|
||||||
// If the time range spans across different days, handle the date part
|
|
||||||
if (parsedEndTime < parsedStartTime) {
|
|
||||||
const nextDay = new Date(parsedStartTime);
|
|
||||||
nextDay.setDate(nextDay.getDate() + 1);
|
|
||||||
timeInterval.end = nextDay;
|
|
||||||
}
|
|
||||||
|
|
||||||
isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);
|
|
||||||
|
|
||||||
if (!isWithinRange) {
|
|
||||||
obj.set = true;
|
|
||||||
obj.msg = outBusinessHoursSaturday.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function localDateConvert() {
|
|
||||||
const brazilTimeZone = "America/Sao_Paulo";
|
|
||||||
|
|
||||||
const currentDateUtc = new Date();
|
|
||||||
|
|
||||||
// Convert UTC date to Brazil time zone
|
|
||||||
const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);
|
|
||||||
|
|
||||||
// Format the date using the desired format
|
|
||||||
const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");
|
|
||||||
|
|
||||||
const parsedDate = parseISO(formattedDate);
|
|
||||||
|
|
||||||
// Convert parsed date to Brazil time zone
|
|
||||||
const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
|
|
||||||
return localDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { isWeekend, isHoliday, isOutBusinessTime, isOutBusinessTimeSaturday };
|
|
||||||
|
|
|
@ -21,14 +21,6 @@ const isAuth = (req: Request, res: Response, next: NextFunction): void => {
|
||||||
|
|
||||||
const [, token] = authHeader.split(" ");
|
const [, token] = authHeader.split(" ");
|
||||||
|
|
||||||
if (
|
|
||||||
(req.originalUrl == "/queue/remote/list" ||
|
|
||||||
req.originalUrl == "/tickets/remote/create") &&
|
|
||||||
token === process.env.TOKEN_REMOTE_TICKET_CREATION
|
|
||||||
) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = verify(token, authConfig.secret);
|
const decoded = verify(token, authConfig.secret);
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { Request, Response, NextFunction } from "express";
|
|
||||||
import AppError from "../errors/AppError";
|
|
||||||
const verifyAPIKey = (req: Request, res: Response, next: NextFunction): void => {
|
|
||||||
const authHeader = req.headers.authorization;
|
|
||||||
|
|
||||||
if (!authHeader) {
|
|
||||||
throw new AppError("ERR_SESSION_EXPIRED", 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [, token] = authHeader.split(" ");
|
|
||||||
|
|
||||||
const apiKeyIsValid = token === process.env.TOKEN_IAM_HORACIUS_EL
|
|
||||||
if (!apiKeyIsValid) {
|
|
||||||
throw new AppError(
|
|
||||||
"Invalid token",
|
|
||||||
401
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyAPIKey;
|
|
|
@ -31,10 +31,6 @@ class Message extends Model<Message> {
|
||||||
@Column
|
@Column
|
||||||
fromMe: boolean;
|
fromMe: boolean;
|
||||||
|
|
||||||
@Default(false)
|
|
||||||
@Column
|
|
||||||
fromAgent: boolean;
|
|
||||||
|
|
||||||
@Column(DataType.TEXT)
|
@Column(DataType.TEXT)
|
||||||
body: string;
|
body: string;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
} from "sequelize-typescript";
|
} from "sequelize-typescript";
|
||||||
|
|
||||||
import SchedulingNotify from "./SchedulingNotify";
|
import SchedulingNotify from "./SchedulingNotify";
|
||||||
import Ticket from "./Ticket"
|
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
class StatusChatEnd extends Model<StatusChatEnd> {
|
class StatusChatEnd extends Model<StatusChatEnd> {
|
||||||
|
@ -30,9 +29,6 @@ import Ticket from "./Ticket"
|
||||||
|
|
||||||
@HasMany(() => SchedulingNotify)
|
@HasMany(() => SchedulingNotify)
|
||||||
SchedulingNotifies: SchedulingNotify[];
|
SchedulingNotifies: SchedulingNotify[];
|
||||||
|
|
||||||
@HasMany(() => Ticket)
|
|
||||||
tickets: Ticket[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StatusChatEnd;
|
export default StatusChatEnd;
|
||||||
|
|
|
@ -21,7 +21,6 @@ import User from "./User";
|
||||||
import Whatsapp from "./Whatsapp";
|
import Whatsapp from "./Whatsapp";
|
||||||
|
|
||||||
import SchedulingNotify from "./SchedulingNotify";
|
import SchedulingNotify from "./SchedulingNotify";
|
||||||
import StatusChatEnd from "./StatusChatEnd"
|
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
class Ticket extends Model<Ticket> {
|
class Ticket extends Model<Ticket> {
|
||||||
|
@ -43,10 +42,6 @@ class Ticket extends Model<Ticket> {
|
||||||
@Column
|
@Column
|
||||||
isGroup: boolean;
|
isGroup: boolean;
|
||||||
|
|
||||||
@ForeignKey(() => StatusChatEnd)
|
|
||||||
@Column
|
|
||||||
statusChatEndId: number;
|
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
statusChatEnd: string;
|
statusChatEnd: string;
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,6 @@ class User extends Model<User> {
|
||||||
@Column
|
@Column
|
||||||
positionCompany: string;
|
positionCompany: string;
|
||||||
|
|
||||||
@Column
|
|
||||||
secondaryId: string;
|
|
||||||
|
|
||||||
@Default("admin")
|
@Default("admin")
|
||||||
@Column
|
@Column
|
||||||
profile: string;
|
profile: string;
|
||||||
|
|
|
@ -16,8 +16,6 @@ contactRoutes.get("/contacts/:contactId", isAuth, ContactController.show);
|
||||||
|
|
||||||
contactRoutes.post("/contacts", isAuth, ContactController.store);
|
contactRoutes.post("/contacts", isAuth, ContactController.store);
|
||||||
|
|
||||||
contactRoutes.post("/contact", isAuth, ContactController.getContact);
|
|
||||||
|
|
||||||
contactRoutes.put("/contacts/:contactId", isAuth, ContactController.update);
|
contactRoutes.put("/contacts/:contactId", isAuth, ContactController.update);
|
||||||
|
|
||||||
contactRoutes.delete("/contacts/:contactId", isAuth, ContactController.remove);
|
contactRoutes.delete("/contacts/:contactId", isAuth, ContactController.remove);
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
|
|
||||||
import * as IAMControllerEL from "../controllers/IAMControllerEL";
|
|
||||||
import verifyAPIKey from "../middleware/verifyAPIKey";
|
|
||||||
|
|
||||||
const iamRoutesEL = Router();
|
|
||||||
|
|
||||||
iamRoutesEL.post(
|
|
||||||
"/iam/horacius/createUser",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.createUser
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.put(
|
|
||||||
"/iam/horacius/updateUser",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.updateUser
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.delete(
|
|
||||||
"/iam/horacius/deleteUser",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.deleteUser
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.get(
|
|
||||||
"/iam/horacius/listAllUsers",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.listAllUsers
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.get(
|
|
||||||
"/iam/horacius/checkUser",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.checkUser
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.patch(
|
|
||||||
"/iam/horacius/linkUserAndUserRight",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.linkUserAndUserRight
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.post(
|
|
||||||
"/iam/horacius/linkUserAndUserRight",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.checkUserRight
|
|
||||||
);
|
|
||||||
|
|
||||||
iamRoutesEL.patch(
|
|
||||||
"/iam/horacius/resetPassword",
|
|
||||||
verifyAPIKey,
|
|
||||||
IAMControllerEL.resetPassword
|
|
||||||
);
|
|
||||||
|
|
||||||
export default iamRoutesEL;
|
|
|
@ -15,12 +15,10 @@ import schedulingNotifiyRoutes from "./SchedulingNotifyRoutes";
|
||||||
import statusChatEndRoutes from "./statusChatEndRoutes";
|
import statusChatEndRoutes from "./statusChatEndRoutes";
|
||||||
import hitRoutes from "./hitRoutes";
|
import hitRoutes from "./hitRoutes";
|
||||||
import wbotMonitorRoutes from "./wbotMonitorRoutes";
|
import wbotMonitorRoutes from "./wbotMonitorRoutes";
|
||||||
import iamRoutesEL from "./iamRoutesEL";
|
|
||||||
|
|
||||||
const routes = Router();
|
const routes = Router();
|
||||||
|
|
||||||
|
|
||||||
routes.use(iamRoutesEL);
|
|
||||||
routes.use(userRoutes);
|
routes.use(userRoutes);
|
||||||
routes.use("/auth", authRoutes);
|
routes.use("/auth", authRoutes);
|
||||||
routes.use(settingRoutes);
|
routes.use(settingRoutes);
|
||||||
|
|
|
@ -11,8 +11,6 @@ queueRoutes.post("/queue", isAuth, QueueController.store);
|
||||||
|
|
||||||
queueRoutes.post("/queue/customization", QueueController.customization);
|
queueRoutes.post("/queue/customization", QueueController.customization);
|
||||||
|
|
||||||
queueRoutes.get("/queue/remote/list", isAuth, QueueController.listQueues);
|
|
||||||
|
|
||||||
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
||||||
|
|
||||||
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
||||||
|
|
|
@ -7,42 +7,12 @@ import * as ReportController from "../controllers/ReportController";
|
||||||
|
|
||||||
const reportRoutes = express.Router();
|
const reportRoutes = express.Router();
|
||||||
|
|
||||||
reportRoutes.get(
|
reportRoutes.get("/reports", isAuth, ReportController.reportUserByDateStartDateEnd);
|
||||||
"/reports",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportUserByDateStartDateEnd
|
|
||||||
);
|
|
||||||
|
|
||||||
reportRoutes.post("/reports/onqueue", ReportController.reportOnQueue);
|
reportRoutes.post("/reports/onqueue", ReportController.reportOnQueue);
|
||||||
|
|
||||||
reportRoutes.get(
|
reportRoutes.get("/reports/user/services", isAuth, ReportController.reportUserService);
|
||||||
"/reports/user/services",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportUserService
|
|
||||||
);
|
|
||||||
|
|
||||||
reportRoutes.get(
|
reportRoutes.get("/reports/messages", isAuth, ReportController.reportMessagesUserByDateStartDateEnd);
|
||||||
"/reports/services/numbers",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportService
|
|
||||||
);
|
|
||||||
|
|
||||||
reportRoutes.get(
|
|
||||||
"/reports/services/queues",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportServiceByQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
reportRoutes.get(
|
|
||||||
"/reports/messages",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportMessagesUserByDateStartDateEnd
|
|
||||||
);
|
|
||||||
|
|
||||||
reportRoutes.get(
|
|
||||||
"/reports/count/statusChatEnd",
|
|
||||||
isAuth,
|
|
||||||
ReportController.reportTicksCountByStatusChatEnds
|
|
||||||
);
|
|
||||||
|
|
||||||
export default reportRoutes;
|
export default reportRoutes;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import * as TicketController from "../controllers/TicketController";
|
||||||
|
|
||||||
const ticketRoutes = express.Router();
|
const ticketRoutes = express.Router();
|
||||||
|
|
||||||
|
|
||||||
// ticketRoutes.get("/tickets/cache", isAuth, TicketController.ticketsCache);
|
// ticketRoutes.get("/tickets/cache", isAuth, TicketController.ticketsCache);
|
||||||
|
|
||||||
ticketRoutes.get("/tickets/count", isAuth, TicketController.count);
|
ticketRoutes.get("/tickets/count", isAuth, TicketController.count);
|
||||||
|
@ -13,11 +14,6 @@ ticketRoutes.get("/tickets", isAuth, TicketController.index);
|
||||||
|
|
||||||
ticketRoutes.get("/tickets/:ticketId", isAuth, TicketController.show);
|
ticketRoutes.get("/tickets/:ticketId", isAuth, TicketController.show);
|
||||||
|
|
||||||
ticketRoutes.post(
|
|
||||||
"/tickets/remote/create", isAuth,
|
|
||||||
TicketController.remoteTicketCreation
|
|
||||||
);
|
|
||||||
|
|
||||||
ticketRoutes.post("/tickets", isAuth, TicketController.store);
|
ticketRoutes.post("/tickets", isAuth, TicketController.store);
|
||||||
|
|
||||||
ticketRoutes.put("/tickets/:ticketId", isAuth, TicketController.update);
|
ticketRoutes.put("/tickets/:ticketId", isAuth, TicketController.update);
|
||||||
|
|
|
@ -23,11 +23,6 @@ import fs from "fs";
|
||||||
import dir from "path";
|
import dir from "path";
|
||||||
import { getSettingValue } from "./helpers/WhaticketSettings";
|
import { getSettingValue } from "./helpers/WhaticketSettings";
|
||||||
import loadSettings from "./helpers/LoadSettings";
|
import loadSettings from "./helpers/LoadSettings";
|
||||||
import { clearAllKeys, get, set } from "./helpers/RedisClient";
|
|
||||||
import ShowUserService from "./services/UserServices/ShowUserService";
|
|
||||||
import { json } from "sequelize";
|
|
||||||
import { setBotInfo } from "./helpers/SetBotInfo";
|
|
||||||
import Queue from "./models/Queue";
|
|
||||||
|
|
||||||
const server = app.listen(process.env.PORT, () => {
|
const server = app.listen(process.env.PORT, () => {
|
||||||
logger.info(`Server started on port: ${process.env.PORT}`);
|
logger.info(`Server started on port: ${process.env.PORT}`);
|
||||||
|
@ -48,54 +43,18 @@ gracefulShutdown(server);
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log("os.tmpdir(): ", os.tmpdir());
|
console.log("os.tmpdir(): ", os.tmpdir());
|
||||||
|
|
||||||
await clearAllKeys("user:*", "whatsapp:*", "queue:*");
|
|
||||||
|
|
||||||
const users = await User.findAll();
|
|
||||||
|
|
||||||
for (const user of users) {
|
|
||||||
const { id, name } = user;
|
|
||||||
|
|
||||||
if (name == "botqueue") {
|
|
||||||
const userService = await ShowUserService(id);
|
|
||||||
await setBotInfo(userService);
|
|
||||||
}
|
|
||||||
|
|
||||||
await set(`user:${id}`, { id, name });
|
|
||||||
}
|
|
||||||
|
|
||||||
// const queues = await Queue.findAll();
|
|
||||||
|
|
||||||
// for (const queue of queues) {
|
|
||||||
// const { id, greetingMessage, name } = queue;
|
|
||||||
// await set(`queue:${id}`, { id, name, greetingMessage });
|
|
||||||
// }
|
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
let whatsapps: any = await Whatsapp.findAll({
|
let whatsapps: any = await Whatsapp.findAll({
|
||||||
attributes: ["id", "url", "phoneNumberId", "number", "greetingMessage"]
|
attributes: ["id", "url", "phoneNumberId"]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (whatsapps && whatsapps.length > 0) {
|
if (whatsapps && whatsapps.length > 0) {
|
||||||
for (let i = 0; i < whatsapps.length; i++) {
|
for (let i = 0; i < whatsapps.length; i++) {
|
||||||
try {
|
try {
|
||||||
const { phoneNumberId, id, greetingMessage } = whatsapps[i];
|
const { phoneNumberId } = whatsapps[i];
|
||||||
|
|
||||||
if (phoneNumberId) {
|
if (phoneNumberId) continue;
|
||||||
await set(
|
|
||||||
`whatsapp:${whatsapps[i].dataValues.id}`,
|
|
||||||
JSON.stringify({
|
|
||||||
number: whatsapps[i].dataValues.number,
|
|
||||||
id,
|
|
||||||
greetingMessage,
|
|
||||||
phoneNumberId
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phoneNumberId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`
|
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import AppError from "../../errors/AppError";
|
|
||||||
import Contact from "../../models/Contact";
|
|
||||||
import CreateContactService from "./CreateContactService";
|
|
||||||
|
|
||||||
interface ExtraInfo {
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Request {
|
|
||||||
name: string;
|
|
||||||
number: string;
|
|
||||||
email?: string;
|
|
||||||
profilePicUrl?: string;
|
|
||||||
extraInfo?: ExtraInfo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const GetContactService = async ({ name, number }: Request): Promise<Contact> => {
|
|
||||||
const numberExists = await Contact.findOne({
|
|
||||||
where: { number }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!numberExists) {
|
|
||||||
const contact = await CreateContactService({
|
|
||||||
name,
|
|
||||||
number,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (contact == null)
|
|
||||||
throw new AppError("CONTACT_NOT_FIND")
|
|
||||||
else
|
|
||||||
return contact
|
|
||||||
}
|
|
||||||
|
|
||||||
return numberExists
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GetContactService;
|
|
|
@ -13,7 +13,6 @@ interface MessageData {
|
||||||
read?: boolean;
|
read?: boolean;
|
||||||
mediaType?: string;
|
mediaType?: string;
|
||||||
mediaUrl?: string;
|
mediaUrl?: string;
|
||||||
fromAgent?: boolean;
|
|
||||||
}
|
}
|
||||||
interface Request {
|
interface Request {
|
||||||
messageData: MessageData;
|
messageData: MessageData;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import { set } from "../../helpers/RedisClient";
|
|
||||||
|
|
||||||
interface QueueData {
|
interface QueueData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -10,7 +9,9 @@ interface QueueData {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
|
const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { color, name } = queueData;
|
const { color, name } = queueData;
|
||||||
|
|
||||||
const queueSchema = Yup.object().shape({
|
const queueSchema = Yup.object().shape({
|
||||||
|
@ -63,14 +64,13 @@ const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
|
||||||
|
|
||||||
const queue = await Queue.create(queueData);
|
const queue = await Queue.create(queueData);
|
||||||
|
|
||||||
// const { id, greetingMessage } = queue;
|
|
||||||
// await set(`queue:${id}`, { id, name, greetingMessage });
|
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on CreateQueueService.ts file: \n", error);
|
console.error('===> Error on CreateQueueService.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateQueueService;
|
export default CreateQueueService;
|
||||||
|
|
|
@ -3,7 +3,6 @@ import * as Yup from "yup";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import ShowQueueService from "./ShowQueueService";
|
import ShowQueueService from "./ShowQueueService";
|
||||||
import { set } from "../../helpers/RedisClient"
|
|
||||||
|
|
||||||
interface QueueData {
|
interface QueueData {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
@ -15,7 +14,9 @@ const UpdateQueueService = async (
|
||||||
queueId: number | string,
|
queueId: number | string,
|
||||||
queueData: QueueData
|
queueData: QueueData
|
||||||
): Promise<Queue> => {
|
): Promise<Queue> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { color, name } = queueData;
|
const { color, name } = queueData;
|
||||||
|
|
||||||
const queueSchema = Yup.object().shape({
|
const queueSchema = Yup.object().shape({
|
||||||
|
@ -69,14 +70,13 @@ const UpdateQueueService = async (
|
||||||
|
|
||||||
await queue.update(queueData);
|
await queue.update(queueData);
|
||||||
|
|
||||||
// const { id, greetingMessage } = queue;
|
|
||||||
// await set(`queue:${id}`, { id, name, greetingMessage });
|
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on UpdateQueueService.ts file: \n", error);
|
console.error('===> Error on UpdateQueueService.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UpdateQueueService;
|
export default UpdateQueueService;
|
||||||
|
|
|
@ -1,333 +0,0 @@
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
|
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
const { QueryTypes } = require("sequelize");
|
|
||||||
|
|
||||||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
|
||||||
import format from "date-fns/format";
|
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
|
||||||
import { number } from "yup";
|
|
||||||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
|
||||||
|
|
||||||
interface Request {
|
|
||||||
startDate: string | number;
|
|
||||||
endDate: string;
|
|
||||||
queue?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReportByNumberQueueService = async ({
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
queue = false
|
|
||||||
}: Request): Promise<any[]> => {
|
|
||||||
let reportServiceData: any[] = [];
|
|
||||||
|
|
||||||
const whatsapps = await Whatsapp.findAll();
|
|
||||||
|
|
||||||
if (!queue) {
|
|
||||||
for (const whatsapp of whatsapps) {
|
|
||||||
const { id, name, number } = whatsapp;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!number ||
|
|
||||||
reportServiceData.findIndex((w: any) => w?.number == number) != -1
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
console.log("NUMBER: ", number);
|
|
||||||
|
|
||||||
// CHAT STARTED BY AGENT
|
|
||||||
const startedByAgent: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromAgent = 1
|
|
||||||
AND w.number = ${number};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT STARTED BY CLIENT
|
|
||||||
const startedByClient: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromMe = 0
|
|
||||||
AND w.number = ${number};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT CLOSED
|
|
||||||
const closedChat: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND t.status = 'closed'
|
|
||||||
AND w.number = ${number};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT WAINTING TIME
|
|
||||||
const avgChatWaitingTime: any = await sequelize.query(
|
|
||||||
`
|
|
||||||
SELECT TIME_FORMAT(
|
|
||||||
SEC_TO_TIME(
|
|
||||||
TIMESTAMPDIFF(
|
|
||||||
SECOND,
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromMe = 0
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromAgent = 1
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
), '%H:%i:%s') AS WAITING_TIME
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromMe = 0
|
|
||||||
-- AND q.id = 2
|
|
||||||
AND w.number = ${number}
|
|
||||||
AND t.status IN ('open', 'closed')
|
|
||||||
HAVING WAITING_TIME IS NOT NULL
|
|
||||||
ORDER BY
|
|
||||||
WAITING_TIME;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT PENDING
|
|
||||||
const pendingChat: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND t.status = 'pending'
|
|
||||||
AND w.number = ${number};`,
|
|
||||||
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
reportServiceData.push({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
number,
|
|
||||||
startedByAgent: startedByAgent[0]?.ticket_count,
|
|
||||||
startedByClient: startedByClient[0]?.ticket_count,
|
|
||||||
closedChat: closedChat[0]?.ticket_count,
|
|
||||||
avgChatWaitingTime: avg(avgChatWaitingTime),
|
|
||||||
pendingChat: pendingChat[0]?.ticket_count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const whatsapp of whatsapps) {
|
|
||||||
const { id, name, number } = whatsapp;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!number ||
|
|
||||||
reportServiceData.findIndex((w: any) => w?.number == number) != -1
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const data = await ShowWhatsAppService(id);
|
|
||||||
|
|
||||||
const queues: any = data.queues.map((q: any) => {
|
|
||||||
const { id, name, color } = q;
|
|
||||||
return { id, name, color };
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("NUMBER 2: ", number);
|
|
||||||
|
|
||||||
for (const q of queues) {
|
|
||||||
// CHAT STARTED BY AGENT
|
|
||||||
const startedByAgent: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromAgent = 1
|
|
||||||
AND q.id = ${q.id};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT STARTED BY CLIENT
|
|
||||||
const startedByClient: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromMe = 0
|
|
||||||
AND q.id = ${q.id};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT CLOSED
|
|
||||||
const closedChat: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND t.status = 'closed'
|
|
||||||
AND q.id = ${q.id};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT WAINTING TIME
|
|
||||||
const avgChatWaitingTime: any = await sequelize.query(
|
|
||||||
`SELECT TIME_FORMAT(
|
|
||||||
SEC_TO_TIME(
|
|
||||||
TIMESTAMPDIFF(
|
|
||||||
SECOND,
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromMe = 0
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromAgent = 1
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
), '%H:%i:%s') AS WAITING_TIME
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromMe = 0
|
|
||||||
AND q.id = ${q.id}
|
|
||||||
AND t.status IN ('open', 'closed')
|
|
||||||
HAVING WAITING_TIME IS NOT NULL
|
|
||||||
ORDER BY
|
|
||||||
WAITING_TIME;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
// CHAT PENDING
|
|
||||||
const pendingChat: any = await sequelize.query(
|
|
||||||
`SELECT COUNT(DISTINCT t.id) AS ticket_count
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND t.status = 'pending'
|
|
||||||
AND q.id = ${q.id};`,
|
|
||||||
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
reportServiceData.push({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
number,
|
|
||||||
queueName: q.name,
|
|
||||||
queueColor: q.color,
|
|
||||||
startedByAgent: startedByAgent[0]?.ticket_count,
|
|
||||||
startedByClient: startedByClient[0]?.ticket_count,
|
|
||||||
closedChat: closedChat[0]?.ticket_count,
|
|
||||||
avgChatWaitingTime: avg(avgChatWaitingTime),
|
|
||||||
pendingChat: pendingChat[0]?.ticket_count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reportServiceData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ReportByNumberQueueService;
|
|
||||||
|
|
||||||
function avg(avgChatWaitingTime: any) {
|
|
||||||
let waitingAVG: any = avgChatWaitingTime
|
|
||||||
.filter((t: any) => t?.WAITING_TIME)
|
|
||||||
.map((t: any) => t.WAITING_TIME)
|
|
||||||
|
|
||||||
if (waitingAVG.length > 0) {
|
|
||||||
let midIndex = Math.floor((0 + waitingAVG.length) / 2)
|
|
||||||
|
|
||||||
if (waitingAVG.length % 2 == 1) {
|
|
||||||
waitingAVG = waitingAVG[midIndex]
|
|
||||||
} else {
|
|
||||||
waitingAVG = calculateAverageTime(
|
|
||||||
waitingAVG[midIndex - 1],
|
|
||||||
waitingAVG[midIndex]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingAVG = 0
|
|
||||||
}
|
|
||||||
return waitingAVG
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateAverageTime(time1: string, time2: string) {
|
|
||||||
// Function to parse time string to seconds
|
|
||||||
function timeStringToSeconds(timeString: string) {
|
|
||||||
const [hours, minutes, seconds] = timeString.split(":").map(Number);
|
|
||||||
return hours * 3600 + minutes * 60 + seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to convert seconds to time string
|
|
||||||
function secondsToTimeString(seconds: number) {
|
|
||||||
const hours = Math.floor(seconds / 3600);
|
|
||||||
const minutes = Math.floor((seconds % 3600) / 60);
|
|
||||||
const remainingSeconds = seconds % 60;
|
|
||||||
return `${hours.toString().padStart(2, "0")}:${minutes
|
|
||||||
.toString()
|
|
||||||
.padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert time strings to seconds
|
|
||||||
const time1Seconds = timeStringToSeconds(time1);
|
|
||||||
const time2Seconds = timeStringToSeconds(time2);
|
|
||||||
|
|
||||||
// Calculate average seconds
|
|
||||||
const averageSeconds = Math.round((time1Seconds + time2Seconds) / 2);
|
|
||||||
|
|
||||||
// Convert average seconds back to time string
|
|
||||||
const averageTime = secondsToTimeString(averageSeconds);
|
|
||||||
|
|
||||||
return averageTime;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import StatusChatEnd from "../../models/StatusChatEnd";
|
|
||||||
import AppError from "../../errors/AppError";
|
|
||||||
|
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
import { splitDateTime } from "../../helpers/SplitDateTime"
|
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
|
||||||
import { format } from "date-fns"
|
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
const { QueryTypes } = require("sequelize");
|
|
||||||
|
|
||||||
const CountStatusChatEndService = async (
|
|
||||||
startDate: string,
|
|
||||||
endDate: string
|
|
||||||
) => {
|
|
||||||
|
|
||||||
const countStatusChatEnd: any = await sequelize.query(
|
|
||||||
`select t.id, s.name, count(t.id) as count from Tickets t join StatusChatEnds s on
|
|
||||||
t.statusChatEndId = s.id and DATE(t.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
group by s.id;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
return countStatusChatEnd;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CountStatusChatEndService;
|
|
|
@ -14,11 +14,14 @@ const FindOrCreateTicketService = async (
|
||||||
whatsappId: number,
|
whatsappId: number,
|
||||||
unreadMessages: number,
|
unreadMessages: number,
|
||||||
groupContact?: Contact,
|
groupContact?: Contact,
|
||||||
queueId?: number | string
|
|
||||||
): Promise<Ticket> => {
|
): Promise<Ticket> => {
|
||||||
try {
|
try {
|
||||||
let ticket;
|
let ticket;
|
||||||
|
|
||||||
|
// else if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||||
|
|
||||||
|
@ -42,8 +45,7 @@ const FindOrCreateTicketService = async (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { queues, greetingMessage, phoneNumberId } =
|
const { queues, greetingMessage, phoneNumberId } = await ShowWhatsAppService(whatsappId);
|
||||||
await ShowWhatsAppService(whatsappId);
|
|
||||||
|
|
||||||
const botInfo = { isOnQueue: false };
|
const botInfo = { isOnQueue: false };
|
||||||
|
|
||||||
|
@ -95,7 +97,7 @@ const FindOrCreateTicketService = async (
|
||||||
if (!ticket) {
|
if (!ticket) {
|
||||||
let status = "pending";
|
let status = "pending";
|
||||||
|
|
||||||
if (queues.length > 1 && !botInfo.isOnQueue && !queueId) {
|
if (queues.length > 1 && !botInfo.isOnQueue) {
|
||||||
status = "queueChoice";
|
status = "queueChoice";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +105,6 @@ const FindOrCreateTicketService = async (
|
||||||
contactId: groupContact ? groupContact.id : contact.id,
|
contactId: groupContact ? groupContact.id : contact.id,
|
||||||
status: status,
|
status: status,
|
||||||
isGroup: !!groupContact,
|
isGroup: !!groupContact,
|
||||||
queueId,
|
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
whatsappId,
|
whatsappId,
|
||||||
phoneNumberId
|
phoneNumberId
|
||||||
|
|
|
@ -29,8 +29,7 @@ const FindOrCreateTicketServiceBot = async (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queues, greetingMessage, phoneNumberId } =
|
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
||||||
await ShowWhatsAppService(whatsappId);
|
|
||||||
|
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
|
@ -108,8 +107,7 @@ const FindOrCreateTicketServiceBot = async (
|
||||||
userId: botInfo.userIdBot,
|
userId: botInfo.userIdBot,
|
||||||
isGroup: !!groupContact,
|
isGroup: !!groupContact,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
whatsappId,
|
whatsappId
|
||||||
phoneNumberId
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
||||||
|
|
|
@ -61,6 +61,11 @@ const ListTicketsService = async ({
|
||||||
|
|
||||||
console.log('PAGE NUMBER TICKET: ', pageNumber)
|
console.log('PAGE NUMBER TICKET: ', pageNumber)
|
||||||
|
|
||||||
|
//TEST DEL
|
||||||
|
// const url = await getWbot(46)
|
||||||
|
// console.log('---------> URL: ', url)
|
||||||
|
//
|
||||||
|
|
||||||
if (pageNumber.trim().length == 0) {
|
if (pageNumber.trim().length == 0) {
|
||||||
pageNumber = '1'
|
pageNumber = '1'
|
||||||
}
|
}
|
||||||
|
@ -131,14 +136,15 @@ const ListTicketsService = async ({
|
||||||
whereCondition = { ...whereCondition, status };
|
whereCondition = { ...whereCondition, status };
|
||||||
|
|
||||||
|
|
||||||
if (unlimited === "current" && status !== "pending") {
|
if (unlimited === 'true' && status !== 'pending') {
|
||||||
|
|
||||||
whereCondition = {
|
whereCondition = {
|
||||||
...whereCondition,
|
...whereCondition,
|
||||||
createdAt: {
|
createdAt: {
|
||||||
[Op.gte]: dateToday.fullDate + " 00:00:00.000000",
|
[Op.gte]: dateToday.fullDate + ' 00:00:00.000000',
|
||||||
[Op.lte]: dateToday.fullDate + " 23:59:59.999999"
|
[Op.lte]: dateToday.fullDate + ' 23:59:59.999999'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,8 +196,8 @@ const ListTicketsService = async ({
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userProfile.dataValues.profile != "admin" &&
|
userProfile.dataValues.profile != "admin" &&
|
||||||
userProfile.dataValues.profile != "master" &&
|
userProfile.dataValues.profile != "master"
|
||||||
userProfile.dataValues.profile != "supervisor"
|
// userProfile.dataValues.profile != "supervisor"
|
||||||
) {
|
) {
|
||||||
whereCondition = { ...whereCondition, userId };
|
whereCondition = { ...whereCondition, userId };
|
||||||
}
|
}
|
||||||
|
@ -218,10 +224,9 @@ const ListTicketsService = async ({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const limit = unlimited === "current" || unlimited === "all" ? 100000 : 40;
|
const limit = unlimited === 'true' ? 100000 : 40;
|
||||||
const offset = limit * (+pageNumber - 1);
|
const offset = limit * (+pageNumber - 1);
|
||||||
|
|
||||||
console.log("kkkkkkkkk limit: ", limit);
|
|
||||||
|
|
||||||
const { count, rows: tickets } = await Ticket.findAndCountAll({
|
const { count, rows: tickets } = await Ticket.findAndCountAll({
|
||||||
where: whereCondition,
|
where: whereCondition,
|
||||||
|
|
|
@ -7,28 +7,23 @@ import Queue from "../../models/Queue";
|
||||||
import Message from "../../models/Message";
|
import Message from "../../models/Message";
|
||||||
import { userInfo } from "os";
|
import { userInfo } from "os";
|
||||||
|
|
||||||
import { Op, QueryTypes, json, where } from "sequelize";
|
import { Op, where } from "sequelize";
|
||||||
|
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import moment from "moment";
|
import moment from 'moment';
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
|
|
||||||
import { startOfDay, endOfDay, parseISO, getDate} from "date-fns";
|
import { startOfDay, endOfDay, parseISO, getDate} from "date-fns";
|
||||||
import { string } from "yup/lib/locale";
|
import { string } from "yup/lib/locale";
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query";
|
|
||||||
import { te } from "date-fns/locale";
|
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
userId: string | number;
|
userId: string | number;
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
createdOrUpdated?: string;
|
|
||||||
queueId?: string;
|
|
||||||
pageNumber?: string;
|
pageNumber?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
count: number;
|
count: number;
|
||||||
|
@ -40,81 +35,42 @@ const ShowTicketReport = async ({
|
||||||
userId,
|
userId,
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
pageNumber = "1",
|
pageNumber = "1"
|
||||||
createdOrUpdated = "created",
|
|
||||||
queueId
|
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
// let where_clause: any = {};
|
|
||||||
// let query = "";
|
|
||||||
|
|
||||||
// if (userId !== "0") {
|
let where_clause = {}
|
||||||
// where_clause.userid = userId;
|
|
||||||
// query = `AND t.userId = ${userId}`;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (queueId) {
|
if(userId=='0'){
|
||||||
// where_clause.queueId = queueId;
|
|
||||||
// query = `AND t.queueId = ${queueId}`;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const createdAtOrUpdatedAt =
|
|
||||||
createdOrUpdated == "created" ? "createdAt" : "updatedAt";
|
|
||||||
|
|
||||||
let where_clause = {};
|
|
||||||
|
|
||||||
if (queueId) {
|
|
||||||
where_clause = {
|
where_clause = {
|
||||||
queueId: queueId,
|
updatedAt: {
|
||||||
[createdAtOrUpdatedAt]: {
|
[Op.gte]: startDate+' 00:00:00.000000',
|
||||||
[Op.gte]: startDate + " 00:00:00.000000",
|
[Op.lte]: endDate +' 23:59:59.999999'
|
||||||
[Op.lte]: endDate + " 23:59:59.999999"
|
},
|
||||||
}
|
}
|
||||||
};
|
|
||||||
} else if (userId == "0") {
|
|
||||||
where_clause = {
|
|
||||||
[createdAtOrUpdatedAt]: {
|
|
||||||
[Op.gte]: startDate + " 00:00:00.000000",
|
|
||||||
[Op.lte]: endDate + " 23:59:59.999999"
|
|
||||||
}
|
}
|
||||||
};
|
else{
|
||||||
} else if (userId != "0") {
|
|
||||||
where_clause = {
|
where_clause = {
|
||||||
userid: userId,
|
userid: userId,
|
||||||
[createdAtOrUpdatedAt]: {
|
updatedAt: {
|
||||||
[Op.gte]: startDate + " 00:00:00.000000",
|
[Op.gte]: startDate+' 00:00:00.000000',
|
||||||
[Op.lte]: endDate + " 23:59:59.999999"
|
[Op.lte]: endDate +' 23:59:59.999999'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const limit = 40;
|
const limit = 40;
|
||||||
const offset = limit * (+pageNumber - 1);
|
const offset = limit * (+pageNumber - 1);
|
||||||
|
|
||||||
let { count, rows: tickets }: any = await Ticket.findAndCountAll({
|
const {count, rows: tickets} = await Ticket.findAndCountAll({
|
||||||
|
|
||||||
where: where_clause ,
|
where: where_clause ,
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
attributes: [
|
//attributes: ['id', 'status', 'createdAt', 'updatedAt'],
|
||||||
"id",
|
|
||||||
"status",
|
attributes: ['id', 'status', 'statusChatEnd', [Sequelize.fn("DATE_FORMAT",Sequelize.col("Ticket.createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"],
|
||||||
"statusChatEnd",
|
[Sequelize.fn("DATE_FORMAT",Sequelize.col("Ticket.updatedAt"),"%d/%m/%Y %H:%i:%s"),"updatedAt"]],
|
||||||
[
|
|
||||||
Sequelize.fn(
|
|
||||||
"DATE_FORMAT",
|
|
||||||
Sequelize.col("Ticket.createdAt"),
|
|
||||||
"%d/%m/%Y %H:%i:%s"
|
|
||||||
),
|
|
||||||
"createdAt"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Sequelize.fn(
|
|
||||||
"DATE_FORMAT",
|
|
||||||
Sequelize.col("Ticket.updatedAt"),
|
|
||||||
"%d/%m/%Y %H:%i:%s"
|
|
||||||
),
|
|
||||||
"updatedAt"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
|
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
@ -122,99 +78,45 @@ const ShowTicketReport = async ({
|
||||||
required:true,
|
required:true,
|
||||||
separate: true,
|
separate: true,
|
||||||
|
|
||||||
attributes: [
|
// attributes: ['body', 'read', 'mediaType','fromMe', 'mediaUrl','createdAt'],
|
||||||
"body",
|
|
||||||
"read",
|
attributes: ['body', 'read', 'mediaType','fromMe', 'mediaUrl', [Sequelize.fn("DATE_FORMAT",Sequelize.col("createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"]],
|
||||||
"mediaType",
|
|
||||||
"fromMe",
|
order: [
|
||||||
"mediaUrl",
|
['createdAt', 'ASC']
|
||||||
[
|
|
||||||
Sequelize.fn(
|
|
||||||
"DATE_FORMAT",
|
|
||||||
Sequelize.col("createdAt"),
|
|
||||||
"%d/%m/%Y %H:%i:%s"
|
|
||||||
),
|
|
||||||
"createdAt"
|
|
||||||
]
|
]
|
||||||
],
|
|
||||||
order: [["createdAt", "ASC"]]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Contact,
|
model: Contact,
|
||||||
attributes: ["name", "number"]
|
attributes: ['name', 'number']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: User,
|
model: User,
|
||||||
attributes: ["name", "email"]
|
attributes: ['name', 'email']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Queue,
|
model: Queue,
|
||||||
attributes: ["name"]
|
attributes: ['name']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Whatsapp,
|
model: Whatsapp,
|
||||||
attributes: ["name"]
|
attributes: ['name']
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
order: [["updatedAt", "DESC"]]
|
|
||||||
|
order: [
|
||||||
|
['id', 'ASC']
|
||||||
|
]
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasMore = count > offset + tickets.length;
|
const hasMore = count > offset + tickets.length;
|
||||||
|
|
||||||
|
|
||||||
if (!tickets) {
|
if (!tickets) {
|
||||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tickets.length > 0) {
|
|
||||||
const waiting_time: any = await sequelize.query(
|
|
||||||
`SELECT t.id as ticketId, t.status, TIME_FORMAT(
|
|
||||||
SEC_TO_TIME(
|
|
||||||
TIMESTAMPDIFF(
|
|
||||||
SECOND,
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromMe = 0
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SELECT createdAt
|
|
||||||
FROM Messages
|
|
||||||
WHERE ticketId = m.ticketId
|
|
||||||
AND fromAgent = 1
|
|
||||||
ORDER BY createdAt ASC
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
), '%H:%i:%s') AS WAITING_TIME
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Messages m ON t.id = m.ticketId
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
JOIN Queues q ON q.id = t.queueId
|
|
||||||
WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
|
||||||
AND t.id IN (${tickets.map((t: any) => t.id).join()})
|
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
|
||||||
AND m.fromMe = 0
|
|
||||||
AND t.status IN ('open', 'closed')
|
|
||||||
HAVING WAITING_TIME IS NOT NULL
|
|
||||||
ORDER BY
|
|
||||||
WAITING_TIME;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let w of waiting_time) {
|
|
||||||
const { ticketId, status, WAITING_TIME } = w;
|
|
||||||
|
|
||||||
const index = tickets.findIndex((t: any) => +t?.id == +ticketId);
|
|
||||||
|
|
||||||
if (index != -1) {
|
|
||||||
tickets[index].dataValues.waiting_time = WAITING_TIME;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {tickets, count, hasMore};
|
return {tickets, count, hasMore};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
||||||
import { deleteObject } from "../../helpers/RedisClient";
|
import { deleteObject } from "../../helpers/RedisClient"
|
||||||
var flatten = require("flat");
|
var flatten = require("flat");
|
||||||
|
|
||||||
interface TicketData {
|
interface TicketData {
|
||||||
|
@ -18,7 +18,6 @@ interface TicketData {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
queueId?: number;
|
queueId?: number;
|
||||||
statusChatEnd?: string;
|
statusChatEnd?: string;
|
||||||
statusChatEndId?: number;
|
|
||||||
unreadMessages?: number;
|
unreadMessages?: number;
|
||||||
whatsappId?: string | number;
|
whatsappId?: string | number;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,6 @@ const UpdateTicketService = async ({
|
||||||
queueId,
|
queueId,
|
||||||
statusChatEnd,
|
statusChatEnd,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
statusChatEndId,
|
|
||||||
whatsappId
|
whatsappId
|
||||||
} = ticketData;
|
} = ticketData;
|
||||||
|
|
||||||
|
@ -75,7 +73,6 @@ const UpdateTicketService = async ({
|
||||||
userId,
|
userId,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
statusChatEnd,
|
statusChatEnd,
|
||||||
statusChatEndId,
|
|
||||||
whatsappId
|
whatsappId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -83,7 +80,7 @@ const UpdateTicketService = async ({
|
||||||
|
|
||||||
if (msg?.trim().length > 0) {
|
if (msg?.trim().length > 0) {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
sendWhatsAppMessageSocket(ticket, `\u200e${msg}`);
|
sendWhatsAppMessageSocket(ticket, msg);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ interface Request {
|
||||||
positionCompany?: string;
|
positionCompany?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
profile?: string;
|
profile?: string;
|
||||||
ignoreThrow?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
|
@ -28,17 +27,15 @@ const CreateUserService = async ({
|
||||||
name,
|
name,
|
||||||
positionCompany,
|
positionCompany,
|
||||||
queueIds = [],
|
queueIds = [],
|
||||||
profile = "master",
|
profile = "master"
|
||||||
ignoreThrow = false
|
}: Request): Promise<Response> => {
|
||||||
}: Request): Promise<Response | any> => {
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string().required().min(2),
|
name: Yup.string().required().min(2),
|
||||||
|
|
||||||
email: Yup.string()
|
email: Yup.string().required().trim().test(
|
||||||
.required()
|
|
||||||
.trim()
|
|
||||||
.test(
|
|
||||||
"Check-email",
|
"Check-email",
|
||||||
"An user with this email already exists.",
|
"An user with this email already exists.",
|
||||||
async value => {
|
async value => {
|
||||||
|
@ -68,8 +65,6 @@ const CreateUserService = async ({
|
||||||
try {
|
try {
|
||||||
await schema.validate({ email, password, name });
|
await schema.validate({ email, password, name });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (ignoreThrow) return { error: true, msg: err.message, status: 400 };
|
|
||||||
|
|
||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +86,12 @@ const CreateUserService = async ({
|
||||||
const serializedUser = SerializeUser(user);
|
const serializedUser = SerializeUser(user);
|
||||||
|
|
||||||
return serializedUser;
|
return serializedUser;
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on CreateUserService.ts file: \n", error);
|
console.error('===> Error on CreateUserService.ts file: \n', error)
|
||||||
|
|
||||||
if (ignoreThrow)
|
|
||||||
return { error: true, msg: "Create user error", status: 500 };
|
|
||||||
|
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateUserService;
|
export default CreateUserService;
|
||||||
|
|
|
@ -2,24 +2,14 @@ import User from "../../models/User";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Ticket from "../../models/Ticket";
|
import Ticket from "../../models/Ticket";
|
||||||
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
||||||
import { set } from "../../helpers/RedisClient";
|
import { set } from "../../helpers/RedisClient"
|
||||||
|
|
||||||
const DeleteUserService = async (
|
const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
id: string | number,
|
|
||||||
ignoreThrow = false
|
|
||||||
): Promise<void | any> => {
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
where: { id }
|
where: { id }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
if (ignoreThrow)
|
|
||||||
return {
|
|
||||||
error: true,
|
|
||||||
msg: `No user found with this id ${id}`,
|
|
||||||
status: 404
|
|
||||||
};
|
|
||||||
|
|
||||||
throw new AppError("ERR_NO_USER_FOUND", 404);
|
throw new AppError("ERR_NO_USER_FOUND", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Op, Sequelize } from "sequelize";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
import UserQueue from "../../models/UserQueue";
|
import UserQueue from "../../models/UserQueue";
|
||||||
import { List } from "whatsapp-web.js";
|
import { List } from "whatsapp-web.js"
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
|
@ -12,13 +12,7 @@ interface Request {
|
||||||
userIds?: string | number;
|
userIds?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListUser = async ({
|
const ListUser = async ({ profile, userId, raw, userIds, profiles }: Request): Promise<User[]> => {
|
||||||
profile,
|
|
||||||
userId,
|
|
||||||
raw,
|
|
||||||
userIds,
|
|
||||||
profiles
|
|
||||||
}: Request): Promise<User[]> => {
|
|
||||||
let where_clause = {};
|
let where_clause = {};
|
||||||
|
|
||||||
if (userId && profile) {
|
if (userId && profile) {
|
||||||
|
@ -53,7 +47,7 @@ const ListUser = async ({
|
||||||
],
|
],
|
||||||
|
|
||||||
order: [["id", "ASC"]],
|
order: [["id", "ASC"]],
|
||||||
group: userIds ? undefined : ["User.id"]
|
group: ["User.id"]
|
||||||
});
|
});
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { Op, Sequelize } from "sequelize";
|
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
|
||||||
import WhatsappQueue from "../../models/WhatsappQueue";
|
|
||||||
import { List } from "whatsapp-web.js";
|
|
||||||
import UserQueue from "../../models/UserQueue";
|
|
||||||
import Queue from "../../models/Queue";
|
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const { QueryTypes } = require("sequelize");
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
|
|
||||||
const ListWhatsappQueuesByUserQueue = async (userId: string | number) => {
|
|
||||||
try {
|
|
||||||
let userQueue: any = await UserQueue.findAll({
|
|
||||||
where: { userId },
|
|
||||||
attributes: ["queueId"],
|
|
||||||
raw: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (userQueue && userQueue.length > 0) {
|
|
||||||
userQueue = userQueue.map((u: any) => u.queueId);
|
|
||||||
|
|
||||||
const result = await sequelize.query(
|
|
||||||
`select w.id, w.number, wq.whatsappId, wq.queueId, q.id, q.name from WhatsappQueues wq join Queues q on
|
|
||||||
wq.queueId = q.id join Whatsapps w
|
|
||||||
on wq.whatsappId = w.id where q.id in (${userQueue.join()})`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching joined data:", error);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ListWhatsappQueuesByUserQueue;
|
|
|
@ -16,7 +16,6 @@ interface UserData {
|
||||||
interface Request {
|
interface Request {
|
||||||
userData: UserData;
|
userData: UserData;
|
||||||
userId: string | number;
|
userId: string | number;
|
||||||
ignoreThrow?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
|
@ -28,10 +27,11 @@ interface Response {
|
||||||
|
|
||||||
const UpdateUserService = async ({
|
const UpdateUserService = async ({
|
||||||
userData,
|
userData,
|
||||||
userId,
|
userId
|
||||||
ignoreThrow = false
|
}: Request): Promise<Response | undefined> => {
|
||||||
}: Request): Promise<Response | undefined | any> => {
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const user = await ShowUserService(userId);
|
const user = await ShowUserService(userId);
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
|
@ -40,41 +40,28 @@ const UpdateUserService = async ({
|
||||||
profile: Yup.string(),
|
profile: Yup.string(),
|
||||||
password: Yup.string(),
|
password: Yup.string(),
|
||||||
|
|
||||||
email: Yup.string()
|
email: Yup.string().trim().required().test(
|
||||||
.trim()
|
|
||||||
.required()
|
|
||||||
.test(
|
|
||||||
"Check-email",
|
"Check-email",
|
||||||
"An user with this email already exists.",
|
"An user with this email already exists.",
|
||||||
async value => {
|
async value => {
|
||||||
|
|
||||||
if (!value) return false;
|
if (!value) return false;
|
||||||
|
|
||||||
const emailExists = await User.findOne({
|
const emailExists = await User.findOne({ where: { email: value }, raw: true, attributes: ['email', 'id'] });
|
||||||
where: { email: value },
|
|
||||||
raw: true,
|
|
||||||
attributes: ["email", "id"]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (emailExists && user.id != emailExists?.id) {
|
if (emailExists && user.id != emailExists?.id) {
|
||||||
console.error(
|
|
||||||
"The email already exists in another user profile!"
|
console.error('The email already exists in another user profile!')
|
||||||
);
|
|
||||||
return !emailExists;
|
return !emailExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const { email, password, profile, name, positionCompany, queueIds = [] } = userData;
|
||||||
email,
|
|
||||||
password,
|
|
||||||
profile,
|
|
||||||
name,
|
|
||||||
positionCompany,
|
|
||||||
queueIds = []
|
|
||||||
} = userData;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await schema.validate({ email, password, profile, name });
|
await schema.validate({ email, password, profile, name });
|
||||||
|
@ -82,6 +69,7 @@ const UpdateUserService = async ({
|
||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await user.update({
|
await user.update({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
|
@ -103,18 +91,13 @@ const UpdateUserService = async ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return serializedUser;
|
return serializedUser;
|
||||||
} catch (err: any) {
|
|
||||||
console.error("===> Error on UpdateUserService.ts file: \n", err);
|
|
||||||
|
|
||||||
if (ignoreThrow)
|
} catch (error: any) {
|
||||||
return {
|
console.error('===> Error on UpdateUserService.ts file: \n', error)
|
||||||
error: true,
|
throw new AppError(error.message);
|
||||||
msg: err.message,
|
|
||||||
status: 500
|
|
||||||
};
|
|
||||||
|
|
||||||
throw new AppError(err.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UpdateUserService;
|
export default UpdateUserService;
|
||||||
|
|
|
@ -1,60 +1,25 @@
|
||||||
import axios from "axios";
|
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import endPointQuery from "../../helpers/EndPointQuery";
|
import endPointQuery from "../../helpers/EndPointQuery";
|
||||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||||
import { getWbot } from "../../libs/wbot";
|
import { getWbot } from "../../libs/wbot";
|
||||||
|
|
||||||
const CheckIsValidContact = async (
|
const CheckIsValidContact = async (number: string): Promise<any> => {
|
||||||
number: string,
|
|
||||||
ignoreThrow?: boolean
|
|
||||||
): Promise<any> => {
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({
|
|
||||||
ignoreNoWhatsappFound: true
|
|
||||||
});
|
|
||||||
|
|
||||||
let isValidNumber;
|
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
||||||
|
|
||||||
if (defaultWhatsapp) {
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
let { data } = await endPointQuery(`${wbot_url}/api/validate`, {
|
const isValidNumber = await endPointQuery(`${wbot_url}/api/validate`, { mobile: `${number}`, })
|
||||||
mobile: `${number}`
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data?.isValid) {
|
// console.log('isValidNumber.data.number: ', isValidNumber.data.number)
|
||||||
isValidNumber = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let _status: any;
|
|
||||||
|
|
||||||
if (!isValidNumber) {
|
// const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
|
||||||
|
|
||||||
const { data, status } = await axios.post(
|
if (!isValidNumber || isValidNumber && !isValidNumber.data.isValid) {
|
||||||
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/validate`,
|
|
||||||
{ mobile: number },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
isValidNumber = data;
|
|
||||||
_status = status;
|
|
||||||
}
|
|
||||||
if (ignoreThrow) return isValidNumber?.number;
|
|
||||||
|
|
||||||
console.log('_status: ', _status)
|
|
||||||
|
|
||||||
if (_status && _status == 422) throw new AppError("ERR_NO_WAPP_FOUND");
|
|
||||||
|
|
||||||
if (!isValidNumber || (isValidNumber && !isValidNumber.isValid)) {
|
|
||||||
throw new AppError("invalidNumber");
|
throw new AppError("invalidNumber");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidNumber && isValidNumber?.isValid) return isValidNumber.number;
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.message === "invalidNumber") {
|
if (err.message === "invalidNumber") {
|
||||||
throw new AppError("ERR_WAPP_INVALID_CONTACT");
|
throw new AppError("ERR_WAPP_INVALID_CONTACT");
|
||||||
|
@ -62,6 +27,10 @@ const CheckIsValidContact = async (
|
||||||
|
|
||||||
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isValidNumber && isValidNumber.data.isValid)
|
||||||
|
return isValidNumber.data.number
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CheckIsValidContact;
|
export default CheckIsValidContact;
|
||||||
|
|
|
@ -1,47 +1,23 @@
|
||||||
import axios from "axios";
|
|
||||||
import endPointQuery from "../../helpers/EndPointQuery";
|
import endPointQuery from "../../helpers/EndPointQuery";
|
||||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||||
import { getWbot } from "../../libs/wbot";
|
import { getWbot } from "../../libs/wbot";
|
||||||
|
|
||||||
const GetProfilePicUrl = async (number: string): Promise<any> => {
|
const GetProfilePicUrl = async (number: string): Promise<any> => {
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({
|
|
||||||
ignoreNoWhatsappFound: true
|
|
||||||
});
|
|
||||||
|
|
||||||
let profilePicUrl;
|
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
||||||
|
|
||||||
if (defaultWhatsapp) {
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
const {data} = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, {
|
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, })
|
||||||
number: `${number}`
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data?.data) {
|
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data)
|
||||||
profilePicUrl = data.data;
|
|
||||||
}
|
if (profilePicUrl && profilePicUrl.data.data) {
|
||||||
|
return profilePicUrl.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return null
|
||||||
if (!profilePicUrl) {
|
|
||||||
const { data } = await axios.post(
|
|
||||||
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/GetProfilePicUrl`,
|
|
||||||
{ number },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
profilePicUrl = data?.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profilePicUrl) {
|
|
||||||
return profilePicUrl;
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GetProfilePicUrl;
|
export default GetProfilePicUrl;
|
||||||
|
|
|
@ -10,7 +10,6 @@ import path from "path";
|
||||||
import {
|
import {
|
||||||
isHoliday,
|
isHoliday,
|
||||||
isOutBusinessTime,
|
isOutBusinessTime,
|
||||||
isOutBusinessTimeSaturday,
|
|
||||||
isWeekend
|
isWeekend
|
||||||
} from "../../helpers/TicketConfig";
|
} from "../../helpers/TicketConfig";
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ import FindOrCreateTicketService from "../TicketServices/FindOrCreateTicketServi
|
||||||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||||
import { debounce } from "../../helpers/Debounce";
|
import { debounce } from "../../helpers/Debounce";
|
||||||
import UpdateTicketService from "../TicketServices/UpdateTicketService";
|
import UpdateTicketService from "../TicketServices/UpdateTicketService";
|
||||||
import { date, name } from "faker";
|
import { date } from "faker";
|
||||||
|
|
||||||
import ShowQueueService from "../QueueService/ShowQueueService";
|
import ShowQueueService from "../QueueService/ShowQueueService";
|
||||||
import ShowTicketMessage from "../TicketServices/ShowTicketMessage";
|
import ShowTicketMessage from "../TicketServices/ShowTicketMessage";
|
||||||
|
@ -85,9 +84,10 @@ import {
|
||||||
} from "../../helpers/WhatsappIdMultiSessionControl";
|
} from "../../helpers/WhatsappIdMultiSessionControl";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import { setMessageAsRead } from "../../helpers/SetMessageAsRead";
|
import { setMessageAsRead } from "../../helpers/SetMessageAsRead";
|
||||||
|
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot";
|
||||||
import { getSettingValue } from "../../helpers/WhaticketSettings";
|
import { getSettingValue } from "../../helpers/WhaticketSettings";
|
||||||
|
|
||||||
import { Op, json } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
|
|
||||||
import SettingTicket from "../../models/SettingTicket";
|
import SettingTicket from "../../models/SettingTicket";
|
||||||
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
||||||
|
@ -95,19 +95,12 @@ import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
||||||
import {
|
import {
|
||||||
createObject,
|
createObject,
|
||||||
del,
|
del,
|
||||||
findByContain,
|
|
||||||
findObject,
|
findObject,
|
||||||
get,
|
get,
|
||||||
getSimple,
|
|
||||||
set
|
set
|
||||||
} from "../../helpers/RedisClient";
|
} from "../../helpers/RedisClient";
|
||||||
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot";
|
|
||||||
import ShowTicketService from "../TicketServices/ShowTicketService";
|
|
||||||
import ShowQueuesByUser from "../UserServices/ShowQueuesByUser";
|
|
||||||
import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue";
|
|
||||||
import CreateContactService from "../ContactServices/CreateContactService";
|
|
||||||
import { number } from "yup";
|
|
||||||
import ShowContactCustomFieldService from "../ContactServices/ShowContactCustomFieldsService";
|
import ShowContactCustomFieldService from "../ContactServices/ShowContactCustomFieldsService";
|
||||||
|
import ShowTicketService from "../TicketServices/ShowTicketService"
|
||||||
|
|
||||||
var lst: any[] = getWhatsappIds();
|
var lst: any[] = getWhatsappIds();
|
||||||
|
|
||||||
|
@ -184,14 +177,9 @@ const verifyMediaMessage = async (
|
||||||
mediaUrl: media.filename,
|
mediaUrl: media.filename,
|
||||||
mediaType: media.mimetype.split("/")[0],
|
mediaType: media.mimetype.split("/")[0],
|
||||||
quotedMsgId: quotedMsg,
|
quotedMsgId: quotedMsg,
|
||||||
phoneNumberId: msg?.phoneNumberId,
|
phoneNumberId: msg?.phoneNumberId
|
||||||
fromAgent: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (msg?.fromMe) {
|
|
||||||
messageData = { ...messageData, fromAgent: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ticket?.phoneNumberId) {
|
if (!ticket?.phoneNumberId) {
|
||||||
if (!media.filename) {
|
if (!media.filename) {
|
||||||
const ext = media.mimetype.split("/")[1].split(";")[0];
|
const ext = media.mimetype.split("/")[1].split(";")[0];
|
||||||
|
@ -227,43 +215,20 @@ const verifyMessage = async (
|
||||||
contact: Contact,
|
contact: Contact,
|
||||||
quotedMsg?: any
|
quotedMsg?: any
|
||||||
) => {
|
) => {
|
||||||
let messageData = {
|
const messageData = {
|
||||||
id: msg.id.id,
|
id: msg.id.id,
|
||||||
ticketId: ticket.id,
|
ticketId: ticket.id,
|
||||||
contactId: msg.fromMe ? undefined : contact.id,
|
contactId: msg.fromMe ? undefined : contact.id,
|
||||||
body: msg.body,
|
body: msg.body,
|
||||||
fromMe: msg.fromMe,
|
fromMe: msg.fromMe,
|
||||||
fromAgent: false,
|
|
||||||
mediaType: msg.type,
|
mediaType: msg.type,
|
||||||
read: msg.fromMe,
|
read: msg.fromMe,
|
||||||
quotedMsgId: quotedMsg,
|
quotedMsgId: quotedMsg,
|
||||||
phoneNumberId: msg?.phoneNumberId
|
phoneNumberId: msg?.phoneNumberId
|
||||||
};
|
};
|
||||||
|
|
||||||
if (msg?.fromMe) {
|
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
|
||||||
|
|
||||||
if (botInfo.isOnQueue) {
|
|
||||||
const ura: any = await get({ key: "ura" });
|
|
||||||
|
|
||||||
if (ura && !ura.includes(JSON.stringify(msg?.body))) {
|
|
||||||
messageData = { ...messageData, fromAgent: true };
|
|
||||||
}
|
|
||||||
} else if (msg?.body?.trim().length > 0 && !/\u200e/.test(msg.body[0])) {
|
|
||||||
messageData = { ...messageData, fromAgent: true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await ticket.update({ lastMessage: msg.body });
|
await ticket.update({ lastMessage: msg.body });
|
||||||
|
|
||||||
if (!msg?.fromMe && msg?.vCards && msg?.vCards?.length > 0) {
|
|
||||||
if (msg.vCards.length == 1) {
|
|
||||||
messageData = { ...messageData, body: msg.vCards[0] };
|
|
||||||
} else {
|
|
||||||
messageData = { ...messageData, body: JSON.stringify(msg.vCards) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await CreateMessageService({ messageData });
|
await CreateMessageService({ messageData });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -656,15 +621,14 @@ const verifyQueue = async (
|
||||||
selectedOption = 1;
|
selectedOption = 1;
|
||||||
choosenQueue = queues[+selectedOption - 1];
|
choosenQueue = queues[+selectedOption - 1];
|
||||||
} else {
|
} else {
|
||||||
selectedOption = msg?.body;
|
selectedOption = msg.body;
|
||||||
|
|
||||||
if (selectedOption && selectedOption.trim().length > 0) {
|
|
||||||
//////////////// EXTRAIR APENAS O NÚMERO ///////////////////
|
//////////////// EXTRAIR APENAS O NÚMERO ///////////////////
|
||||||
selectedOption = selectedOption.replace(/[^1-9]/g, "");
|
selectedOption = selectedOption.replace(/[^1-9]/g, "");
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
|
||||||
choosenQueue = queues[+selectedOption - 1];
|
choosenQueue = queues[+selectedOption - 1];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (choosenQueue) {
|
if (choosenQueue) {
|
||||||
// Atualizando o status do ticket para mostrar notificação para o atendente da fila escolhida pelo usuário. De queueChoice para pending
|
// Atualizando o status do ticket para mostrar notificação para o atendente da fila escolhida pelo usuário. De queueChoice para pending
|
||||||
|
@ -687,14 +651,13 @@ const verifyQueue = async (
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await get({ key: "ura", parse: true });
|
const data = await get("ura");
|
||||||
|
|
||||||
await createObject({
|
await createObject({
|
||||||
whatsappId: `${ticket.whatsappId}`,
|
whatsappId: `${ticket.whatsappId}`,
|
||||||
contactId: `${ticket.contactId}`,
|
contactId: `${ticket.contactId}`,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: data[1].id,
|
value: data[1].id
|
||||||
history: `|${data[1].id}`
|
|
||||||
});
|
});
|
||||||
|
|
||||||
botSendMessage(ticket, data[1].value);
|
botSendMessage(ticket, data[1].value);
|
||||||
|
@ -709,7 +672,7 @@ const verifyQueue = async (
|
||||||
if (outService.length > 0) {
|
if (outService.length > 0) {
|
||||||
const { type, msg: msgOutService } = outService[0];
|
const { type, msg: msgOutService } = outService[0];
|
||||||
console.log(`${type} message ignored on queue`);
|
console.log(`${type} message ignored on queue`);
|
||||||
botSendMessage(ticket, `\u200e${msgOutService}`);
|
botSendMessage(ticket, msgOutService);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,7 +689,7 @@ const verifyQueue = async (
|
||||||
//test del transfere o atendimento se entrar na ura infinita
|
//test del transfere o atendimento se entrar na ura infinita
|
||||||
const repet: any = await mostRepeatedPhrase(ticket.id);
|
const repet: any = await mostRepeatedPhrase(ticket.id);
|
||||||
|
|
||||||
if (repet.occurrences > 10) {
|
if (repet.occurrences > 4) {
|
||||||
await UpdateTicketService({
|
await UpdateTicketService({
|
||||||
ticketData: { status: "pending", queueId: queues[0].id },
|
ticketData: { status: "pending", queueId: queues[0].id },
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
|
@ -831,7 +794,6 @@ const isValidMsg = (msg: any): boolean => {
|
||||||
msg.type === "image" ||
|
msg.type === "image" ||
|
||||||
msg.type === "document" ||
|
msg.type === "document" ||
|
||||||
msg.type === "vcard" ||
|
msg.type === "vcard" ||
|
||||||
msg.type === "multi_vcard" ||
|
|
||||||
msg.type === "sticker"
|
msg.type === "sticker"
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
|
@ -850,14 +812,10 @@ const queuesOutBot = async (wbot: Session, botId: string | number) => {
|
||||||
return { queues, greetingMessage };
|
return { queues, greetingMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
const transferTicket = async (
|
const transferTicket = async (queueName: any, wbot: any, ticket: Ticket) => {
|
||||||
queueName: any,
|
|
||||||
wbot: any,
|
|
||||||
ticket: Ticket,
|
|
||||||
sendGreetingMessage?: boolean
|
|
||||||
) => {
|
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
const io = getIO();
|
|
||||||
|
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
|
||||||
|
|
||||||
const queuesWhatsGreetingMessage = await queuesOutBot(
|
const queuesWhatsGreetingMessage = await queuesOutBot(
|
||||||
wbot,
|
wbot,
|
||||||
|
@ -868,48 +826,27 @@ const transferTicket = async (
|
||||||
|
|
||||||
const queues = queuesWhatsGreetingMessage.queues;
|
const queues = queuesWhatsGreetingMessage.queues;
|
||||||
|
|
||||||
|
// console.log("queues ---> ", console.log(JSON.stringify(queues, null, 6)));
|
||||||
|
|
||||||
if (typeof queueName == "string") {
|
if (typeof queueName == "string") {
|
||||||
queue = queues.find(
|
queue = queues.find(
|
||||||
(q: any) => q?.name?.toLowerCase() == queueName.trim().toLowerCase()
|
(q: any) => q?.name?.toLowerCase() == queueName.trim().toLowerCase()
|
||||||
);
|
);
|
||||||
|
// await deleteObject(wbot.id, `${ticket.contactId}`, "ura");
|
||||||
} else if (typeof queueName == "number") {
|
} else if (typeof queueName == "number") {
|
||||||
queue = queues[queueName];
|
queue = queues[queueName];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue) await botTransferTicket(queue, ticket, sendGreetingMessage);
|
if (queue) await botTransferTicket(queue, ticket);
|
||||||
io.emit("notifyPeding", { data: { ticket, queue } });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const botTransferTicket = async (
|
const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
|
||||||
queues: Queue,
|
|
||||||
ticket: Ticket,
|
|
||||||
sendGreetingMessage?: boolean
|
|
||||||
) => {
|
|
||||||
await ticket.update({ userId: null });
|
await ticket.update({ userId: null });
|
||||||
|
|
||||||
await UpdateTicketService({
|
await UpdateTicketService({
|
||||||
ticketData: { status: "pending", queueId: queues.id },
|
ticketData: { status: "pending", queueId: queues.id },
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sendGreetingMessage && queues?.greetingMessage?.length > 0) {
|
|
||||||
botSendMessage(ticket, queues.greetingMessage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const botTransferTicketToUser = async (
|
|
||||||
userId: number,
|
|
||||||
ticket: Ticket,
|
|
||||||
queueId?: number | undefined
|
|
||||||
) => {
|
|
||||||
console.log("USER ID: ", userId);
|
|
||||||
|
|
||||||
// await ticket.update({ userId: userId });
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { status: "open", userId, queueId },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const botSendMessage = (ticket: Ticket, msg: string) => {
|
const botSendMessage = (ticket: Ticket, msg: string) => {
|
||||||
|
@ -972,20 +909,31 @@ const handleMessage = async (
|
||||||
// let groupContact: Contact | undefined;
|
// let groupContact: Contact | undefined;
|
||||||
|
|
||||||
if (msg.fromMe) {
|
if (msg.fromMe) {
|
||||||
|
const whatsapp = await whatsappInfo(wbot.id);
|
||||||
|
|
||||||
|
if (whatsapp?.number) {
|
||||||
|
const ticketExpiration = await SettingTicket.findOne({
|
||||||
|
where: { key: "ticketExpiration", number: whatsapp.number }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
ticketExpiration &&
|
||||||
|
ticketExpiration.value == "enabled" &&
|
||||||
|
ticketExpiration?.message.trim() == msg.body.trim()
|
||||||
|
) {
|
||||||
|
console.log("*********** TICKET EXPIRATION");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// messages sent automatically by wbot have a special character in front of it
|
// messages sent automatically by wbot have a special character in front of it
|
||||||
// if so, this message was already been stored in database;
|
// if so, this message was already been stored in database;
|
||||||
if (/\u200e/.test(msg.body[0])) return;
|
// if (/\u200e/.test(msg.body[0])) return;
|
||||||
|
|
||||||
// media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
|
// media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
|
||||||
// in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
|
// in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
|
||||||
|
|
||||||
if (
|
if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard") return;
|
||||||
!msg.hasMedia &&
|
|
||||||
msg.type !== "chat" &&
|
|
||||||
msg.type !== "vcard" &&
|
|
||||||
msg.type !== "multi_vcard"
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
|
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
|
||||||
Parcial msg and msgContact info:
|
Parcial msg and msgContact info:
|
||||||
|
@ -1114,55 +1062,11 @@ const handleMessage = async (
|
||||||
await verifyQueue(wbot, msg, ticket, contact);
|
await verifyQueue(wbot, msg, ticket, contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.type === "vcard" || msg.type === "multi_vcard") {
|
|
||||||
await vcard(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
|
||||||
|
|
||||||
// Transfer to agent
|
|
||||||
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
||||||
if (
|
|
||||||
!msg.fromMe &&
|
|
||||||
((ticket.status == "open" &&
|
|
||||||
botInfo &&
|
|
||||||
ticket.userId == +botInfo.userIdBot) ||
|
|
||||||
ticket.status == "pending" ||
|
|
||||||
ticket.status == "queueChoice")
|
|
||||||
) {
|
|
||||||
const filteredUsers = await findByContain("user:*", "name", msg?.body);
|
|
||||||
|
|
||||||
if (filteredUsers && filteredUsers.length > 0) {
|
//Habilitar esse caso queira usar o bot
|
||||||
if (botInfo.isOnQueue) {
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
transferTicket(filteredUsers[0].name, wbot, ticket, true);
|
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const whatsappQueues = await ListWhatsappQueuesByUserQueue(
|
|
||||||
+filteredUsers[0].id
|
|
||||||
);
|
|
||||||
|
|
||||||
const obj: any = whatsappQueues.find(
|
|
||||||
(ob: any) => ob.whatsappId == wbot.id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (obj) {
|
|
||||||
await botTransferTicketToUser(
|
|
||||||
+filteredUsers[0].id,
|
|
||||||
ticket,
|
|
||||||
+obj.queueId
|
|
||||||
);
|
|
||||||
|
|
||||||
await botSendMessage(
|
|
||||||
ticket,
|
|
||||||
`Você foi transferido para falar com o agente ${filteredUsers[0].name}, aguarde.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
botInfo.isOnQueue &&
|
botInfo.isOnQueue &&
|
||||||
|
@ -1173,7 +1077,7 @@ const handleMessage = async (
|
||||||
|
|
||||||
console.log("repet.occurrences: ", repet.occurrences);
|
console.log("repet.occurrences: ", repet.occurrences);
|
||||||
|
|
||||||
if (repet.occurrences > 10) {
|
if (repet.occurrences > 4) {
|
||||||
await transferTicket(0, wbot, ticket);
|
await transferTicket(0, wbot, ticket);
|
||||||
|
|
||||||
await SendWhatsAppMessage({
|
await SendWhatsAppMessage({
|
||||||
|
@ -1201,9 +1105,9 @@ const handleMessage = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let query = await get({
|
let query = await get(
|
||||||
key: `whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`
|
`whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`
|
||||||
});
|
);
|
||||||
|
|
||||||
if (query && msg?.body?.trim() != "0") {
|
if (query && msg?.body?.trim() != "0") {
|
||||||
query = JSON.parse(query);
|
query = JSON.parse(query);
|
||||||
|
@ -1221,6 +1125,7 @@ const handleMessage = async (
|
||||||
await set(
|
await set(
|
||||||
`whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`,
|
`whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`,
|
||||||
JSON.stringify({ ...query, value: msg.body }),
|
JSON.stringify({ ...query, value: msg.body }),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,6 +1156,11 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
menuMsg?.transferToQueue &&
|
menuMsg?.transferToQueue &&
|
||||||
menuMsg.transferToQueue.trim().length > 0
|
menuMsg.transferToQueue.trim().length > 0
|
||||||
) {
|
) {
|
||||||
|
console.log(
|
||||||
|
"YYYYYYYYYYYYYYYYYYYY menuMsg.transferToQueue: ",
|
||||||
|
menuMsg.transferToQueue
|
||||||
|
);
|
||||||
|
|
||||||
transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
|
transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
|
||||||
} else if (menuMsg?.query) {
|
} else if (menuMsg?.query) {
|
||||||
await set(
|
await set(
|
||||||
|
@ -1266,6 +1176,7 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
queryMsgInvalidParam: menuMsg?.queryMsgInvalidParam,
|
queryMsgInvalidParam: menuMsg?.queryMsgInvalidParam,
|
||||||
optionsMenu: menuMsg?.optionsMenu
|
optionsMenu: menuMsg?.optionsMenu
|
||||||
}),
|
}),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1277,7 +1188,6 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
ticket.status == "pending" &&
|
ticket.status == "pending" &&
|
||||||
ticket.queueId
|
ticket.queueId
|
||||||
) {
|
) {
|
||||||
if (botInfo.isOnQueue) {
|
|
||||||
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
||||||
|
|
||||||
await UpdateTicketService({
|
await UpdateTicketService({
|
||||||
|
@ -1290,40 +1200,8 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
});
|
});
|
||||||
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
||||||
await botSendMessage(ticket, menuMsg.value);
|
await botSendMessage(ticket, menuMsg.value);
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (
|
|
||||||
!msg.fromMe &&
|
|
||||||
msg.body == "#" &&
|
|
||||||
ticket.status == "pending" &&
|
|
||||||
ticket.queueId &&
|
|
||||||
botInfo.isOnQueue
|
|
||||||
) {
|
|
||||||
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: {
|
|
||||||
status: "open",
|
|
||||||
userId: botInfo.userIdBot,
|
|
||||||
queueId: choosenQueue.id
|
|
||||||
},
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
// const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
|
||||||
// await botSendMessage(ticket, menuMsg.value);
|
|
||||||
|
|
||||||
// const data: any = await get({ key: "ura", parse: true });
|
|
||||||
|
|
||||||
// return await backUra(ticket.whatsappId, ticket.contactId, data);
|
|
||||||
|
|
||||||
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
|
||||||
|
|
||||||
console.log("menuMsg: ", menuMsg);
|
|
||||||
|
|
||||||
await botSendMessage(ticket, menuMsg.value);
|
|
||||||
|
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg && !msg.fromMe && ticket.status == "pending") {
|
if (msg && !msg.fromMe && ticket.status == "pending") {
|
||||||
|
@ -1349,7 +1227,7 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
botSendMessage(ticket, `\u200e${msgOutService}`);
|
botSendMessage(ticket, msgOutService);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1362,7 +1240,7 @@ dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/tick
|
||||||
|
|
||||||
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
let lastId = await findObject(whatsappId, contactId, "ura");
|
let lastId = await findObject(whatsappId, contactId, "ura");
|
||||||
const data: any = await get({ key: "ura", parse: true });
|
const data: any = await get("ura");
|
||||||
|
|
||||||
console.log("lastId[0]: ", lastId[0]);
|
console.log("lastId[0]: ", lastId[0]);
|
||||||
|
|
||||||
|
@ -1371,8 +1249,7 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: data[1].id,
|
value: data[1].id
|
||||||
history: `|${data[1].id}`
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,7 +1259,7 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
lastId &&
|
lastId &&
|
||||||
(lastId.length == 4 || lastId.length == 5) &&
|
lastId.length == 4 &&
|
||||||
lastId[3] &&
|
lastId[3] &&
|
||||||
lastId[3].trim().length > 0
|
lastId[3].trim().length > 0
|
||||||
) {
|
) {
|
||||||
|
@ -1392,48 +1269,23 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
o.value.toLowerCase() == userTyped.toLowerCase()
|
o.value.toLowerCase() == userTyped.toLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!option && userTyped != "0" && userTyped != "#") {
|
// TEST DEL
|
||||||
|
console.log("OPTION: ", option);
|
||||||
|
|
||||||
|
if (!option && userTyped != "0") {
|
||||||
if (!existSubMenu()) {
|
if (!existSubMenu()) {
|
||||||
const response = await mainOptionsMenu(userTyped);
|
const response = await mainOptionsMenu(userTyped);
|
||||||
if (response) return response;
|
if (response) return response;
|
||||||
else {
|
else {
|
||||||
let uraOptionSelected = await findObject(
|
console.log("kkkkkkkkkkkkkkkkkkk");
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
"ura"
|
|
||||||
);
|
|
||||||
|
|
||||||
uraOptionSelected = uraOptionSelected[4].split("|");
|
|
||||||
|
|
||||||
if (uraOptionSelected.length == 1) {
|
|
||||||
await createObject({
|
await createObject({
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: data[1].id,
|
value: data[1].id
|
||||||
history: `|${data[1].id}`
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return data[1];
|
return data[1];
|
||||||
} else if (uraOptionSelected.length > 1) {
|
|
||||||
const id = uraOptionSelected[uraOptionSelected.length - 1];
|
|
||||||
|
|
||||||
console.log(" ID FROM THE MENU/SUBMENU: ", id);
|
|
||||||
|
|
||||||
const history = await historyUra(whatsappId, contactId, id);
|
|
||||||
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: id,
|
|
||||||
history
|
|
||||||
});
|
|
||||||
|
|
||||||
let response: any = data.find((o: any) => o.id == id);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1441,16 +1293,19 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
|
|
||||||
if (option) {
|
if (option) {
|
||||||
let response: any = data.find((o: any) => o.idmaster == option.id);
|
let response: any = data.find((o: any) => o.idmaster == option.id);
|
||||||
console.log(" RESPONSE OPTION: ", response, " | OPTION: ", option);
|
|
||||||
|
|
||||||
let history: any = await historyUra(whatsappId, contactId, response.id);
|
console.log(
|
||||||
|
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
|
||||||
|
response,
|
||||||
|
" | option: ",
|
||||||
|
option
|
||||||
|
);
|
||||||
|
|
||||||
await createObject({
|
await createObject({
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: response.id,
|
value: response.id
|
||||||
history
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -1459,8 +1314,7 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: data[1].id,
|
value: data[1].id
|
||||||
history: `|${data[1].id}`
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await del(
|
await del(
|
||||||
|
@ -1468,8 +1322,21 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return data[1];
|
return data[1];
|
||||||
} else if (userTyped == "#") {
|
} else {
|
||||||
return await backUra(whatsappId, contactId, data);
|
console.log("INVALID SEARCH");
|
||||||
|
|
||||||
|
let response = await existSubMenu();
|
||||||
|
if (response) return response;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: data.find((o: any) => o.id == lastId[3])?.value
|
||||||
|
};
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// value: `Você digitou uma opçao inválida!\n\n${
|
||||||
|
// data.find((o: any) => o.id == lastId[3])?.value
|
||||||
|
// }\n\nDigite 0 para voltar ao menu `
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1482,29 +1349,18 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mainOptionsMenu(userTyped: any) {
|
async function mainOptionsMenu(userTyped: any) {
|
||||||
let currentMenu = await findObject(whatsappId, contactId, "ura");
|
|
||||||
|
|
||||||
const menuValues = data
|
|
||||||
.filter((m: any) => m.idmaster == currentMenu[3])
|
|
||||||
.map((m: any) => m.value);
|
|
||||||
|
|
||||||
let menuOption = data.find(
|
let menuOption = data.find(
|
||||||
(o: any) =>
|
(o: any) => o.value.toLowerCase() == userTyped.toLowerCase()
|
||||||
o.value.toLowerCase() == userTyped.toLowerCase() &&
|
|
||||||
menuValues.includes(userTyped.toLowerCase())
|
|
||||||
);
|
);
|
||||||
|
console.log("============> menuOption OPTION: ", menuOption);
|
||||||
if (menuOption) {
|
if (menuOption) {
|
||||||
let response = data.find((o: any) => o.idmaster == menuOption.id);
|
let response = data.find((o: any) => o.idmaster == menuOption.id);
|
||||||
if (response) {
|
if (response) {
|
||||||
let history = await historyUra(whatsappId, contactId, response.id);
|
|
||||||
|
|
||||||
await createObject({
|
await createObject({
|
||||||
whatsappId,
|
whatsappId,
|
||||||
contactId,
|
contactId,
|
||||||
identifier: "ura",
|
identifier: "ura",
|
||||||
value: response.id,
|
value: response.id
|
||||||
history
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -1584,13 +1440,6 @@ const outOfService = async (number: string) => {
|
||||||
objs.push({ type: "holiday", msg: holiday.msg });
|
objs.push({ type: "holiday", msg: holiday.msg });
|
||||||
}
|
}
|
||||||
|
|
||||||
// MESSAGE TO SATURDAY BUSINESS TIME
|
|
||||||
const businessTimeSaturday = await isOutBusinessTimeSaturday(number);
|
|
||||||
|
|
||||||
if (businessTimeSaturday && businessTimeSaturday.set) {
|
|
||||||
objs.push({ type: "saturdayBusinessTime", msg: businessTimeSaturday.msg });
|
|
||||||
}
|
|
||||||
|
|
||||||
// MESSAGES TO SATURDAY OR SUNDAY
|
// MESSAGES TO SATURDAY OR SUNDAY
|
||||||
const weekend: any = await isWeekend(number);
|
const weekend: any = await isWeekend(number);
|
||||||
|
|
||||||
|
@ -1617,119 +1466,8 @@ export {
|
||||||
verifyMediaMessage,
|
verifyMediaMessage,
|
||||||
verifyContact,
|
verifyContact,
|
||||||
isValidMsg,
|
isValidMsg,
|
||||||
mediaTypeWhatsappOfficial,
|
mediaTypeWhatsappOfficial
|
||||||
botSendMessage
|
|
||||||
};
|
};
|
||||||
async function vcard(msg: any) {
|
|
||||||
let array: any[] = [];
|
|
||||||
let contact: any;
|
|
||||||
let obj: any[] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const multi_vcard = msg?.vCards?.length === 0 ? false : true;
|
|
||||||
|
|
||||||
if (multi_vcard) {
|
|
||||||
array = msg?.vCards;
|
|
||||||
contact = [];
|
|
||||||
} else {
|
|
||||||
array = msg.body.split("\n");
|
|
||||||
contact = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let index = 0; index < array.length; index++) {
|
|
||||||
const v = array[index];
|
|
||||||
const values = v.split(":");
|
|
||||||
for (let ind = 0; ind < values.length; ind++) {
|
|
||||||
if (values[ind].indexOf("+") !== -1) {
|
|
||||||
obj.push({ number: values[ind] });
|
|
||||||
}
|
|
||||||
if (values[ind].indexOf("FN") !== -1) {
|
|
||||||
if (multi_vcard)
|
|
||||||
contact.push({ name: values[ind + 1].split("\n")[0] });
|
|
||||||
else contact = values[ind + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const i in obj) {
|
|
||||||
let data: any = {};
|
|
||||||
|
|
||||||
if (multi_vcard) {
|
|
||||||
data = {
|
|
||||||
name: contact[i].name,
|
|
||||||
number: obj[i].number.replace(/\D/g, "")
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = {
|
|
||||||
name: contact,
|
|
||||||
number: obj[i].number.replace(/\D/g, "")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const cont = await CreateContactService(data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function backUra(whatsappId: any, contactId: any, data: any) {
|
|
||||||
let uraOptionSelected = await findObject(whatsappId, contactId, "ura");
|
|
||||||
|
|
||||||
uraOptionSelected = uraOptionSelected[4].split("|").filter(Boolean);
|
|
||||||
|
|
||||||
let id = uraOptionSelected[0];
|
|
||||||
|
|
||||||
let history = `|${uraOptionSelected[0]}`;
|
|
||||||
|
|
||||||
if (uraOptionSelected.length > 1) {
|
|
||||||
const idRemove = uraOptionSelected[uraOptionSelected.length - 1];
|
|
||||||
|
|
||||||
history = await historyUra(whatsappId, contactId, idRemove, true);
|
|
||||||
|
|
||||||
const lstIds = history.split("|").filter(Boolean);
|
|
||||||
|
|
||||||
id = lstIds[lstIds.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: id,
|
|
||||||
history
|
|
||||||
});
|
|
||||||
|
|
||||||
let response: any = data.find((o: any) => o.id == id);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function historyUra(
|
|
||||||
whatsappId: any,
|
|
||||||
contactId: any,
|
|
||||||
id: any,
|
|
||||||
remove?: boolean
|
|
||||||
) {
|
|
||||||
let uraOptionSelected = await findObject(whatsappId, contactId, "ura");
|
|
||||||
let history = "";
|
|
||||||
|
|
||||||
console.log("SELECED OPTION uraOptionSelected: ", uraOptionSelected);
|
|
||||||
|
|
||||||
if (remove) {
|
|
||||||
return uraOptionSelected[4]?.replace(`|${id}`, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uraOptionSelected && uraOptionSelected.length == 5) {
|
|
||||||
if (!uraOptionSelected[4]?.includes(`${id}`))
|
|
||||||
history += `${uraOptionSelected[4]}|${id}`;
|
|
||||||
else history = `${uraOptionSelected[4]}`;
|
|
||||||
} else {
|
|
||||||
history = `|${id}`;
|
|
||||||
}
|
|
||||||
return history;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function whatsappInfo(whatsappId: string | number) {
|
async function whatsappInfo(whatsappId: string | number) {
|
||||||
return await Whatsapp.findByPk(whatsappId);
|
return await Whatsapp.findByPk(whatsappId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ interface Request {
|
||||||
phoneNumberId?: string;
|
phoneNumberId?: string;
|
||||||
wabaId?: string;
|
wabaId?: string;
|
||||||
isOfficial?: boolean;
|
isOfficial?: boolean;
|
||||||
number?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
|
@ -35,8 +34,7 @@ const CreateWhatsAppService = async ({
|
||||||
isDefault = false,
|
isDefault = false,
|
||||||
isOfficial = false,
|
isOfficial = false,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId
|
||||||
number
|
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
try {
|
try {
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
|
@ -100,7 +98,6 @@ const CreateWhatsAppService = async ({
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
number,
|
|
||||||
classification
|
classification
|
||||||
},
|
},
|
||||||
{ include: ["queues"] }
|
{ include: ["queues"] }
|
||||||
|
|
|
@ -6,30 +6,17 @@ const { QueryTypes } = require("sequelize");
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
const sequelize = new Sequelize(dbConfig);
|
||||||
|
|
||||||
const ListWhatsAppsForQueueService = async (
|
const ListWhatsAppsForQueueService = async (queueId: number | string): Promise<any> => {
|
||||||
queueId: number | string,
|
const distinctWhatsapps = await sequelize.query(
|
||||||
status?: string
|
`SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId
|
||||||
): Promise<any> => {
|
FROM Whatsapps w
|
||||||
let distinctWhatsapps: any;
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
distinctWhatsapps = await sequelize.query(
|
|
||||||
`SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId FROM Whatsapps w
|
|
||||||
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId} AND w.status = '${status}'
|
|
||||||
AND phoneNumberId = false
|
|
||||||
GROUP BY w.number;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
distinctWhatsapps = await sequelize.query(
|
|
||||||
`SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId FROM Whatsapps w
|
|
||||||
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
|
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
|
||||||
GROUP BY w.number;`,
|
GROUP BY w.number;`,
|
||||||
{ type: QueryTypes.SELECT }
|
{ type: QueryTypes.SELECT }
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return distinctWhatsapps;
|
return distinctWhatsapps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListWhatsAppsForQueueService;
|
export default ListWhatsAppsForQueueService;
|
||||||
|
|
|
@ -22,7 +22,6 @@ interface WhatsappData {
|
||||||
greetingMessage?: string;
|
greetingMessage?: string;
|
||||||
farewellMessage?: string;
|
farewellMessage?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
number?:string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
|
@ -53,7 +52,6 @@ const UpdateWhatsAppService = async ({
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
number,
|
|
||||||
url,
|
url,
|
||||||
urlApi,
|
urlApi,
|
||||||
session,
|
session,
|
||||||
|
@ -118,7 +116,6 @@ const UpdateWhatsAppService = async ({
|
||||||
isOfficial,
|
isOfficial,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId,
|
wabaId,
|
||||||
number,
|
|
||||||
classification
|
classification
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
import { Button } from "@material-ui/core";
|
|
||||||
import React, { useRef } from "react";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
const LS_NAME = 'audioMessageRate';
|
|
||||||
|
|
||||||
export default function({url}) {
|
|
||||||
const audioRef = useRef(null);
|
|
||||||
const [audioRate, setAudioRate] = useState( parseFloat(localStorage.getItem(LS_NAME) || "1") );
|
|
||||||
const [showButtonRate, setShowButtonRate] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
audioRef.current.playbackRate = audioRate;
|
|
||||||
localStorage.setItem(LS_NAME, audioRate);
|
|
||||||
}, [audioRate]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
audioRef.current.onplaying = () => {
|
|
||||||
setShowButtonRate(true);
|
|
||||||
};
|
|
||||||
audioRef.current.onpause = () => {
|
|
||||||
setShowButtonRate(false);
|
|
||||||
};
|
|
||||||
audioRef.current.onended = () => {
|
|
||||||
setShowButtonRate(false);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const toogleRate = () => {
|
|
||||||
let newRate = null;
|
|
||||||
|
|
||||||
switch(audioRate) {
|
|
||||||
case 0.5:
|
|
||||||
newRate = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
newRate = 1.5;
|
|
||||||
break;
|
|
||||||
case 1.5:
|
|
||||||
newRate = 2;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
newRate = 0.5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
newRate = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAudioRate(newRate);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<audio ref={audioRef} controls>
|
|
||||||
<source src={url} type="audio/ogg"></source>
|
|
||||||
</audio>
|
|
||||||
{showButtonRate && <Button style={{marginLeft: "5px", marginTop: "-45px"}} onClick={toogleRate}>{audioRate}x</Button>}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -77,16 +77,8 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
const initialState = {
|
const initialState = {
|
||||||
startTimeBus: new Date(),
|
startTimeBus: new Date(),
|
||||||
endTimeBus: new Date(),
|
endTimeBus: new Date(),
|
||||||
|
|
||||||
startTimeBusSaturday: new Date(),
|
|
||||||
endTimeBusSaturday: new Date(),
|
|
||||||
|
|
||||||
messageBus: '',
|
messageBus: '',
|
||||||
messageBusSaturday: '',
|
|
||||||
|
|
||||||
businessTimeEnable: false,
|
businessTimeEnable: false,
|
||||||
businessTimeEnableSaturday: false,
|
|
||||||
|
|
||||||
ticketTimeExpiration: new Date(),
|
ticketTimeExpiration: new Date(),
|
||||||
ticketExpirationMsg: '',
|
ticketExpirationMsg: '',
|
||||||
ticketExpirationEnable: false,
|
ticketExpirationEnable: false,
|
||||||
|
@ -130,9 +122,6 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
|
const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
|
||||||
|
|
||||||
const saturdayBusinessTime = data.config.find((c) => c.key === "saturdayBusinessTime")
|
|
||||||
|
|
||||||
const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
|
const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
|
||||||
const saturday = data.config.find((c) => c.key === "saturday")
|
const saturday = data.config.find((c) => c.key === "saturday")
|
||||||
const sunday = data.config.find((c) => c.key === "sunday")
|
const sunday = data.config.find((c) => c.key === "sunday")
|
||||||
|
@ -145,11 +134,6 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
messageBus: outBusinessHours.message,
|
messageBus: outBusinessHours.message,
|
||||||
businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false,
|
businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false,
|
||||||
|
|
||||||
startTimeBusSaturday: saturdayBusinessTime.startTime,
|
|
||||||
endTimeBusSaturday: saturdayBusinessTime.endTime,
|
|
||||||
messageBusSaturday: saturdayBusinessTime.message,
|
|
||||||
businessTimeEnableSaturday: saturdayBusinessTime.value === 'enabled' ? true : false,
|
|
||||||
|
|
||||||
ticketTimeExpiration: ticketExpiration.startTime,
|
ticketTimeExpiration: ticketExpiration.startTime,
|
||||||
ticketExpirationMsg: ticketExpiration.message,
|
ticketExpirationMsg: ticketExpiration.message,
|
||||||
ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false,
|
ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false,
|
||||||
|
@ -181,14 +165,6 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
message: values.messageBus,
|
message: values.messageBus,
|
||||||
value: values.businessTimeEnable ? 'enabled' : 'disabled'
|
value: values.businessTimeEnable ? 'enabled' : 'disabled'
|
||||||
},
|
},
|
||||||
|
|
||||||
saturdayBusinessTime: {
|
|
||||||
startTime: values.startTimeBusSaturday,
|
|
||||||
endTime: values.endTimeBusSaturday,
|
|
||||||
message: values.messageBusSaturday,
|
|
||||||
value: values.businessTimeEnableSaturday ? 'enabled' : 'disabled'
|
|
||||||
},
|
|
||||||
|
|
||||||
ticketExpiration: {
|
ticketExpiration: {
|
||||||
startTime: values.ticketTimeExpiration,
|
startTime: values.ticketTimeExpiration,
|
||||||
message: values.ticketExpirationMsg,
|
message: values.ticketExpirationMsg,
|
||||||
|
@ -349,61 +325,6 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<br />
|
|
||||||
{/* SABADO INICIO */}
|
|
||||||
<div className={classes.multFieldLine}>
|
|
||||||
<Field
|
|
||||||
component={TimePicker}
|
|
||||||
name="startTimeBusSaturday"
|
|
||||||
label="Inicio atendimentos"
|
|
||||||
ampm={false}
|
|
||||||
openTo="hours"
|
|
||||||
views={['hours', 'minutes',]}
|
|
||||||
format="HH:mm"
|
|
||||||
/>
|
|
||||||
{' '}
|
|
||||||
<Field
|
|
||||||
component={TimePicker}
|
|
||||||
name="endTimeBusSaturday"
|
|
||||||
label="Fim atendimento"
|
|
||||||
ampm={false}
|
|
||||||
openTo="hours"
|
|
||||||
views={['hours', 'minutes',]}
|
|
||||||
format="HH:mm"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Field
|
|
||||||
as={Switch}
|
|
||||||
color="primary"
|
|
||||||
name="businessTimeEnableSaturday"
|
|
||||||
checked={values.businessTimeEnableSaturday}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={'Ativar/Desativar'} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Field
|
|
||||||
as={TextField}
|
|
||||||
label={'Mensagem fora do horário de atendimento sábado'}
|
|
||||||
type="messageBusSaturday"
|
|
||||||
multiline
|
|
||||||
rows={5}
|
|
||||||
fullWidth
|
|
||||||
name="messageBusSaturday"
|
|
||||||
error={
|
|
||||||
touched.messageBusSaturday && Boolean(errors.messageBusSaturday)
|
|
||||||
}
|
|
||||||
helperText={
|
|
||||||
touched.messageBusSaturday && errors.messageBusSaturday
|
|
||||||
}
|
|
||||||
variant="outlined"
|
|
||||||
margin="dense"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* SABADO FIM */}
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
|
|
||||||
const { data } = await api.get("/whatsapp/official/matchQueue", { params: { userId: user.id, queueId: selectedQueue }, })
|
const { data } = await api.get("/whatsapp/official/matchQueue", { params: { userId: user.id, queueId: selectedQueue }, })
|
||||||
|
|
||||||
// console.log('WHATSAPP DATA: ', data)
|
console.log('WHATSAPP DATA: ', data)
|
||||||
|
|
||||||
setWhatsQueue(data)
|
setWhatsQueue(data)
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import React, { useState, useEffect, useRef } from "react"
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
|
|
||||||
import * as Yup from "yup"
|
import * as Yup from "yup";
|
||||||
import { Formik, FieldArray, Form, Field } from "formik"
|
import { Formik, FieldArray, Form, Field } from "formik";
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { green } from "@material-ui/core/colors"
|
import { green } from "@material-ui/core/colors";
|
||||||
import Button from "@material-ui/core/Button"
|
import Button from "@material-ui/core/Button";
|
||||||
import TextField from "@material-ui/core/TextField"
|
import TextField from "@material-ui/core/TextField";
|
||||||
import Dialog from "@material-ui/core/Dialog"
|
import Dialog from "@material-ui/core/Dialog";
|
||||||
import DialogActions from "@material-ui/core/DialogActions"
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent"
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle"
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import Typography from "@material-ui/core/Typography"
|
import Typography from "@material-ui/core/Typography";
|
||||||
import IconButton from "@material-ui/core/IconButton"
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
|
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n"
|
import { i18n } from "../../translate/i18n";
|
||||||
|
|
||||||
import api from "../../services/api"
|
import api from "../../services/api";
|
||||||
import toastError from "../../errors/toastError"
|
import toastError from "../../errors/toastError";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
root: {
|
root: {
|
||||||
|
@ -50,7 +50,7 @@ const useStyles = makeStyles(theme => ({
|
||||||
marginTop: -12,
|
marginTop: -12,
|
||||||
marginLeft: -12,
|
marginLeft: -12,
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const ContactSchema = Yup.object().shape({
|
const ContactSchema = Yup.object().shape({
|
||||||
name: Yup.string()
|
name: Yup.string()
|
||||||
|
@ -63,74 +63,72 @@ const ContactSchema = Yup.object().shape({
|
||||||
.max(50, "Too Long!"),
|
.max(50, "Too Long!"),
|
||||||
|
|
||||||
// email: Yup.string().email("Invalid email"),
|
// email: Yup.string().email("Invalid email"),
|
||||||
})
|
});
|
||||||
|
|
||||||
const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const isMounted = useRef(true)
|
const isMounted = useRef(true);
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
name: "",
|
name: "",
|
||||||
number: "",
|
number: "",
|
||||||
email: "",
|
email: "",
|
||||||
useDialogflow: true,
|
useDialogflow: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
const [contact, setContact] = useState(initialState)
|
const [contact, setContact] = useState(initialState);
|
||||||
const [isSaving, setSaving] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
isMounted.current = false
|
isMounted.current = false;
|
||||||
}
|
};
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchContact = async () => {
|
const fetchContact = async () => {
|
||||||
if (initialValues) {
|
if (initialValues) {
|
||||||
setContact(prevState => {
|
setContact(prevState => {
|
||||||
return { ...prevState, ...initialValues }
|
return { ...prevState, ...initialValues };
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!contactId) return
|
if (!contactId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get(`/contacts/${contactId}`)
|
const { data } = await api.get(`/contacts/${contactId}`);
|
||||||
if (isMounted.current) {
|
if (isMounted.current) {
|
||||||
setContact(data)
|
setContact(data);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fetchContact()
|
fetchContact();
|
||||||
}, [contactId, open, initialValues])
|
}, [contactId, open, initialValues]);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose()
|
onClose();
|
||||||
setContact(initialState)
|
setContact(initialState);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSaveContact = async values => {
|
const handleSaveContact = async values => {
|
||||||
try {
|
try {
|
||||||
if (contactId) {
|
if (contactId) {
|
||||||
await api.put(`/contacts/${contactId}`, values)
|
await api.put(`/contacts/${contactId}`, values);
|
||||||
handleClose()
|
handleClose();
|
||||||
} else {
|
} else {
|
||||||
const { data } = await api.post("/contacts", values)
|
const { data } = await api.post("/contacts", values);
|
||||||
if (onSave) {
|
if (onSave) {
|
||||||
onSave(data)
|
onSave(data);
|
||||||
}
|
}
|
||||||
handleClose()
|
handleClose();
|
||||||
}
|
}
|
||||||
toast.success(i18n.t("contactModal.success"))
|
toast.success(i18n.t("contactModal.success"));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
|
||||||
setSaving(false)
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
@ -145,11 +143,10 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
enableReinitialize={true}
|
enableReinitialize={true}
|
||||||
validationSchema={ContactSchema}
|
validationSchema={ContactSchema}
|
||||||
onSubmit={(values, actions) => {
|
onSubmit={(values, actions) => {
|
||||||
setSaving(true)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleSaveContact(values)
|
handleSaveContact(values);
|
||||||
actions.setSubmitting(false)
|
actions.setSubmitting(false);
|
||||||
}, 400)
|
}, 400);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values, errors, touched, isSubmitting }) => (
|
{({ values, errors, touched, isSubmitting }) => (
|
||||||
|
@ -259,14 +256,14 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={isSaving}
|
disabled={isSubmitting}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
className={classes.btnWrapper}
|
className={classes.btnWrapper}
|
||||||
>
|
>
|
||||||
{contactId
|
{contactId
|
||||||
? `${i18n.t("contactModal.buttons.okEdit")}`
|
? `${i18n.t("contactModal.buttons.okEdit")}`
|
||||||
: `${i18n.t("contactModal.buttons.okAdd")}`}
|
: `${i18n.t("contactModal.buttons.okAdd")}`}
|
||||||
{isSaving && (
|
{isSubmitting && (
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
size={24}
|
size={24}
|
||||||
className={classes.buttonProgress}
|
className={classes.buttonProgress}
|
||||||
|
@ -279,7 +276,7 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
</Formik>
|
</Formik>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ContactModal
|
export default ContactModal;
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import toastError from "../../errors/toastError";
|
|
||||||
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import Grid from "@material-ui/core/Grid";
|
|
||||||
|
|
||||||
import { Button, Divider, } from "@material-ui/core";
|
|
||||||
|
|
||||||
const LocationPreview = ({ image, link, description }) => {
|
|
||||||
useEffect(() => {}, [image, link, description]);
|
|
||||||
|
|
||||||
const handleLocation = async() => {
|
|
||||||
try {
|
|
||||||
window.open(link);
|
|
||||||
} catch (err) {
|
|
||||||
toastError(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div style={{
|
|
||||||
minWidth: "250px",
|
|
||||||
}}>
|
|
||||||
<div>
|
|
||||||
<div style={{ float: "left" }}>
|
|
||||||
<img src={image} onClick={handleLocation} style={{ width: "100px" }} />
|
|
||||||
</div>
|
|
||||||
{ description && (
|
|
||||||
<div style={{ display: "flex", flexWrap: "wrap" }}>
|
|
||||||
<Typography style={{ marginTop: "12px", marginLeft: "15px", marginRight: "15px", float: "left" }} variant="subtitle1" color="primary" gutterBottom>
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: description.replace('\\n', '<br />') }}></div>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div style={{ display: "block", content: "", clear: "both" }}></div>
|
|
||||||
<div>
|
|
||||||
<Divider />
|
|
||||||
<Button
|
|
||||||
fullWidth
|
|
||||||
color="primary"
|
|
||||||
onClick={handleLocation}
|
|
||||||
disabled={!link}
|
|
||||||
>Visualizar</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LocationPreview;
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react"
|
import React from "react";
|
||||||
import Markdown from "markdown-to-jsx"
|
import Markdown from "markdown-to-jsx";
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
"a",
|
"a",
|
||||||
|
@ -139,32 +139,25 @@ const elements = [
|
||||||
"svg",
|
"svg",
|
||||||
"text",
|
"text",
|
||||||
"tspan",
|
"tspan",
|
||||||
]
|
];
|
||||||
|
|
||||||
const allowedElements = ["a", "b", "strong", "em", "u", "code", "del"]
|
const allowedElements = ["a", "b", "strong", "em", "u", "code", "del"];
|
||||||
|
|
||||||
const CustomLink = ({ children, ...props }) => (
|
const CustomLink = ({ children, ...props }) => (
|
||||||
<a {...props} target="_blank" rel="noopener noreferrer">
|
<a {...props} target="_blank" rel="noopener noreferrer">
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)
|
);
|
||||||
|
|
||||||
const MarkdownWrapper = ({ children }) => {
|
const MarkdownWrapper = ({ children }) => {
|
||||||
const boldRegex = /\*(.*?)\*/g
|
const boldRegex = /\*(.*?)\*/g;
|
||||||
const tildaRegex = /~(.*?)~/g
|
const tildaRegex = /~(.*?)~/g;
|
||||||
|
|
||||||
if (children && children.includes('BEGIN:VCARD'))
|
|
||||||
//children = "Diga olá ao seu novo contato clicando em *conversar*!";
|
|
||||||
children = null
|
|
||||||
|
|
||||||
if (children && children.includes('data:image/'))
|
|
||||||
children = null
|
|
||||||
|
|
||||||
if (children && boldRegex.test(children)) {
|
if (children && boldRegex.test(children)) {
|
||||||
children = children.replace(boldRegex, "**$1**")
|
children = children.replace(boldRegex, "**$1**");
|
||||||
}
|
}
|
||||||
if (children && tildaRegex.test(children)) {
|
if (children && tildaRegex.test(children)) {
|
||||||
children = children.replace(tildaRegex, "~~$1~~")
|
children = children.replace(tildaRegex, "~~$1~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = React.useMemo(() => {
|
const options = React.useMemo(() => {
|
||||||
|
@ -174,20 +167,20 @@ const MarkdownWrapper = ({ children }) => {
|
||||||
overrides: {
|
overrides: {
|
||||||
a: { component: CustomLink },
|
a: { component: CustomLink },
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
if (!allowedElements.includes(element)) {
|
if (!allowedElements.includes(element)) {
|
||||||
markdownOptions.overrides[element] = el => el.children || null
|
markdownOptions.overrides[element] = el => el.children || null;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return markdownOptions
|
return markdownOptions;
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
if (!children) return null
|
if (!children) return null;
|
||||||
|
|
||||||
return <Markdown options={options}>{children}</Markdown>
|
return <Markdown options={options}>{children}</Markdown>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default MarkdownWrapper
|
export default MarkdownWrapper;
|
||||||
|
|
|
@ -312,6 +312,8 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
|
|
||||||
const handleSendMessage = async (templateParams = null) => {
|
const handleSendMessage = async (templateParams = null) => {
|
||||||
|
|
||||||
|
console.log('templateParams: ', templateParams, ' | inputMessage: ', inputMessage)
|
||||||
|
|
||||||
if (inputMessage.trim() === "") return
|
if (inputMessage.trim() === "") return
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
|
@ -322,6 +324,8 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
if (templateParams) {
|
if (templateParams) {
|
||||||
for (let key in templateParams) {
|
for (let key in templateParams) {
|
||||||
if (templateParams.hasOwnProperty(key)) {
|
if (templateParams.hasOwnProperty(key)) {
|
||||||
|
// let value = templateParams[key]
|
||||||
|
// console.log('key: ', key, ' | ', 'VALUE: ', value)
|
||||||
|
|
||||||
if (key === '_reactName') {
|
if (key === '_reactName') {
|
||||||
templateParams = null
|
templateParams = null
|
||||||
|
@ -367,11 +371,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
|
|
||||||
if (!params) return
|
if (!params) return
|
||||||
|
|
||||||
const body_params = params?.find(p => p?.type === 'BODY')
|
const body_params = params.find(p => p?.type === 'BODY')
|
||||||
|
|
||||||
console.log('------------> body_params: ', body_params)
|
|
||||||
|
|
||||||
if(!body_params) return
|
|
||||||
|
|
||||||
let { text } = body_params
|
let { text } = body_params
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import React, { useContext, useState, useEffect, useReducer, useRef } from "react"
|
import React, { useContext, useState, useEffect, useReducer, useRef } from "react";
|
||||||
|
|
||||||
import { isSameDay, parseISO, format } from "date-fns"
|
import { isSameDay, parseISO, format } from "date-fns";
|
||||||
import openSocket from "socket.io-client"
|
import openSocket from "socket.io-client";
|
||||||
import clsx from "clsx"
|
import clsx from "clsx";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
|
||||||
import { green } from "@material-ui/core/colors"
|
import { green } from "@material-ui/core/colors";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Divider,
|
Divider,
|
||||||
IconButton,
|
IconButton,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
} from "@material-ui/core"
|
} from "@material-ui/core";
|
||||||
import {
|
import {
|
||||||
AccessTime,
|
AccessTime,
|
||||||
Block,
|
Block,
|
||||||
|
@ -20,20 +20,15 @@ import {
|
||||||
DoneAll,
|
DoneAll,
|
||||||
ExpandMore,
|
ExpandMore,
|
||||||
GetApp,
|
GetApp,
|
||||||
} from "@material-ui/icons"
|
} from "@material-ui/icons";
|
||||||
|
|
||||||
import MarkdownWrapper from "../MarkdownWrapper"
|
import MarkdownWrapper from "../MarkdownWrapper";
|
||||||
import VcardPreview from "../VcardPreview"
|
import ModalImageCors from "../ModalImageCors";
|
||||||
import LocationPreview from "../LocationPreview"
|
import MessageOptionsMenu from "../MessageOptionsMenu";
|
||||||
import Audio from "../Audio"
|
import whatsBackground from "../../assets/wa-background.png";
|
||||||
|
|
||||||
|
import api from "../../services/api";
|
||||||
import ModalImageCors from "../ModalImageCors"
|
import toastError from "../../errors/toastError";
|
||||||
import MessageOptionsMenu from "../MessageOptionsMenu"
|
|
||||||
import whatsBackground from "../../assets/wa-background.png"
|
|
||||||
|
|
||||||
import api from "../../services/api"
|
|
||||||
import toastError from "../../errors/toastError"
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
messagesListWrapper: {
|
messagesListWrapper: {
|
||||||
|
@ -262,78 +257,78 @@ const useStyles = makeStyles((theme) => ({
|
||||||
backgroundColor: "inherit",
|
backgroundColor: "inherit",
|
||||||
padding: 10,
|
padding: 10,
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const reducer = (state, action) => {
|
const reducer = (state, action) => {
|
||||||
if (action.type === "LOAD_MESSAGES") {
|
if (action.type === "LOAD_MESSAGES") {
|
||||||
const messages = action.payload
|
const messages = action.payload;
|
||||||
const newMessages = []
|
const newMessages = [];
|
||||||
|
|
||||||
messages.forEach((message) => {
|
messages.forEach((message) => {
|
||||||
const messageIndex = state.findIndex((m) => m.id === message.id)
|
const messageIndex = state.findIndex((m) => m.id === message.id);
|
||||||
if (messageIndex !== -1) {
|
if (messageIndex !== -1) {
|
||||||
state[messageIndex] = message
|
state[messageIndex] = message;
|
||||||
} else {
|
} else {
|
||||||
newMessages.push(message)
|
newMessages.push(message);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return [...newMessages, ...state]
|
return [...newMessages, ...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "ADD_MESSAGE") {
|
if (action.type === "ADD_MESSAGE") {
|
||||||
const newMessage = action.payload
|
const newMessage = action.payload;
|
||||||
const messageIndex = state.findIndex((m) => m.id === newMessage.id)
|
const messageIndex = state.findIndex((m) => m.id === newMessage.id);
|
||||||
|
|
||||||
if (messageIndex !== -1) {
|
if (messageIndex !== -1) {
|
||||||
state[messageIndex] = newMessage
|
state[messageIndex] = newMessage;
|
||||||
} else {
|
} else {
|
||||||
state.push(newMessage)
|
state.push(newMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "UPDATE_MESSAGE") {
|
if (action.type === "UPDATE_MESSAGE") {
|
||||||
const messageToUpdate = action.payload
|
const messageToUpdate = action.payload;
|
||||||
const messageIndex = state.findIndex((m) => m.id === messageToUpdate.id)
|
const messageIndex = state.findIndex((m) => m.id === messageToUpdate.id);
|
||||||
|
|
||||||
if (messageIndex !== -1) {
|
if (messageIndex !== -1) {
|
||||||
state[messageIndex] = messageToUpdate
|
state[messageIndex] = messageToUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "RESET") {
|
if (action.type === "RESET") {
|
||||||
return []
|
return [];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const MessagesList = ({ ticketId, isGroup }) => {
|
const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
|
|
||||||
const [messagesList, dispatch] = useReducer(reducer, [])
|
const [messagesList, dispatch] = useReducer(reducer, []);
|
||||||
const [pageNumber, setPageNumber] = useState(1)
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
const [hasMore, setHasMore] = useState(false)
|
const [hasMore, setHasMore] = useState(false);
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false);
|
||||||
const lastMessageRef = useRef()
|
const lastMessageRef = useRef();
|
||||||
|
|
||||||
const [selectedMessage, setSelectedMessage] = useState({})
|
const [selectedMessage, setSelectedMessage] = useState({});
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const messageOptionsMenuOpen = Boolean(anchorEl)
|
const messageOptionsMenuOpen = Boolean(anchorEl);
|
||||||
const currentTicketId = useRef(ticketId)
|
const currentTicketId = useRef(ticketId);
|
||||||
const [sendSeen, setSendSeen] = useState(false)
|
const [sendSeen, setSendSeen] = useState(false)
|
||||||
|
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({ type: "RESET" })
|
dispatch({ type: "RESET" });
|
||||||
setPageNumber(1)
|
setPageNumber(1);
|
||||||
|
|
||||||
currentTicketId.current = ticketId
|
currentTicketId.current = ticketId;
|
||||||
}, [ticketId])
|
}, [ticketId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
@ -359,7 +354,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get("/messages/" + ticketId, {
|
const { data } = await api.get("/messages/" + ticketId, {
|
||||||
params: { pageNumber },
|
params: { pageNumber },
|
||||||
})
|
});
|
||||||
|
|
||||||
setSendSeen(false)
|
setSendSeen(false)
|
||||||
|
|
||||||
|
@ -382,239 +377,138 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
sendSeenMessage()
|
sendSeenMessage();
|
||||||
}, 500)
|
}, 500);
|
||||||
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(delayDebounceFn)
|
clearTimeout(delayDebounceFn);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}, [sendSeen, pageNumber, ticketId, user.id])
|
}, [sendSeen, pageNumber, ticketId, user.id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
const delayDebounceFn = setTimeout(() => {
|
const delayDebounceFn = setTimeout(() => {
|
||||||
const fetchMessages = async () => {
|
const fetchMessages = async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get("/messages/" + ticketId, {
|
const { data } = await api.get("/messages/" + ticketId, {
|
||||||
params: { pageNumber },
|
params: { pageNumber },
|
||||||
})
|
});
|
||||||
|
|
||||||
if (currentTicketId.current === ticketId) {
|
if (currentTicketId.current === ticketId) {
|
||||||
dispatch({ type: "LOAD_MESSAGES", payload: data.messages })
|
dispatch({ type: "LOAD_MESSAGES", payload: data.messages });
|
||||||
setHasMore(data.hasMore)
|
setHasMore(data.hasMore);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pageNumber === 1 && data.messages.length > 1) {
|
if (pageNumber === 1 && data.messages.length > 1) {
|
||||||
scrollToBottom()
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
fetchMessages()
|
fetchMessages();
|
||||||
}, 500)
|
}, 500);
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(delayDebounceFn)
|
clearTimeout(delayDebounceFn);
|
||||||
}
|
};
|
||||||
}, [pageNumber, ticketId])
|
}, [pageNumber, ticketId]);
|
||||||
|
|
||||||
useEffect(() => {
|
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))
|
socket.on("connect", () => socket.emit("joinChatBox", ticketId));
|
||||||
|
|
||||||
socket.on("appMessage", (data) => {
|
socket.on("appMessage", (data) => {
|
||||||
|
|
||||||
if (data.action === "create") {
|
if (data.action === "create") {
|
||||||
|
|
||||||
dispatch({ type: "ADD_MESSAGE", payload: data.message })
|
dispatch({ type: "ADD_MESSAGE", payload: data.message });
|
||||||
|
|
||||||
scrollToBottom()
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.action === "update") {
|
if (data.action === "update") {
|
||||||
dispatch({ type: "UPDATE_MESSAGE", payload: data.message })
|
dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect()
|
socket.disconnect();
|
||||||
}
|
};
|
||||||
}, [ticketId])
|
}, [ticketId]);
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
setPageNumber((prevPageNumber) => prevPageNumber + 1)
|
setPageNumber((prevPageNumber) => prevPageNumber + 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
if (lastMessageRef.current) {
|
if (lastMessageRef.current) {
|
||||||
|
|
||||||
setSendSeen(true)
|
setSendSeen(true)
|
||||||
|
|
||||||
lastMessageRef.current.scrollIntoView({})
|
lastMessageRef.current.scrollIntoView({});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleScroll = (e) => {
|
const handleScroll = (e) => {
|
||||||
if (!hasMore) return
|
if (!hasMore) return;
|
||||||
const { scrollTop } = e.currentTarget
|
const { scrollTop } = e.currentTarget;
|
||||||
|
|
||||||
if (scrollTop === 0) {
|
if (scrollTop === 0) {
|
||||||
document.getElementById("messagesList").scrollTop = 1
|
document.getElementById("messagesList").scrollTop = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollTop < 50) {
|
if (scrollTop < 50) {
|
||||||
loadMore()
|
loadMore();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleOpenMessageOptionsMenu = (e, message) => {
|
const handleOpenMessageOptionsMenu = (e, message) => {
|
||||||
setAnchorEl(e.currentTarget)
|
setAnchorEl(e.currentTarget);
|
||||||
setSelectedMessage(message)
|
setSelectedMessage(message);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCloseMessageOptionsMenu = (e) => {
|
const handleCloseMessageOptionsMenu = (e) => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
// const checkMessageMedia = (message) => {
|
|
||||||
// if (message.mediaType === "image") {
|
|
||||||
// return <ModalImageCors imageUrl={message.mediaUrl} />;
|
|
||||||
// }
|
|
||||||
// if (message.mediaType === "audio") {
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <audio controls>
|
|
||||||
// <source src={message.mediaUrl} type="audio/ogg"></source>
|
|
||||||
// </audio>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (message.mediaType === "video") {
|
|
||||||
// return (
|
|
||||||
// <video
|
|
||||||
// className={classes.messageMedia}
|
|
||||||
// src={message.mediaUrl}
|
|
||||||
// controls
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// <div className={classes.downloadMedia}>
|
|
||||||
// <Button
|
|
||||||
// startIcon={<GetApp />}
|
|
||||||
// color="primary"
|
|
||||||
// variant="outlined"
|
|
||||||
// target="_blank"
|
|
||||||
// href={message.mediaUrl}
|
|
||||||
// >
|
|
||||||
// Download
|
|
||||||
// </Button>
|
|
||||||
// </div>
|
|
||||||
// <Divider />
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
const checkMessageMedia = (message) => {
|
const checkMessageMedia = (message) => {
|
||||||
if (message.mediaType === "location" && message.body.split('|').length >= 2) {
|
if (message.mediaType === "image") {
|
||||||
let locationParts = message.body.split('|')
|
return <ModalImageCors imageUrl={message.mediaUrl} />;
|
||||||
let imageLocation = locationParts[0]
|
}
|
||||||
let linkLocation = locationParts[1]
|
if (message.mediaType === "audio") {
|
||||||
|
|
||||||
let descriptionLocation = null
|
|
||||||
|
|
||||||
if (locationParts.length > 2)
|
|
||||||
descriptionLocation = message.body.split('|')[2]
|
|
||||||
|
|
||||||
return <LocationPreview image={imageLocation} link={linkLocation} description={descriptionLocation} />
|
|
||||||
}
|
|
||||||
else if (message.mediaType === "vcard") {
|
|
||||||
let array = message.body.split("\n")
|
|
||||||
let obj = []
|
|
||||||
let contact = ""
|
|
||||||
for (let index = 0; index < array.length; index++) {
|
|
||||||
const v = array[index]
|
|
||||||
let values = v.split(":")
|
|
||||||
for (let ind = 0; ind < values.length; ind++) {
|
|
||||||
if (values[ind].indexOf("+") !== -1) {
|
|
||||||
obj.push({ number: values[ind] })
|
|
||||||
}
|
|
||||||
if (values[ind].indexOf("FN") !== -1) {
|
|
||||||
contact = values[ind + 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return <VcardPreview contact={contact} numbers={obj[0]?.number} />
|
|
||||||
}
|
|
||||||
else if (message.mediaType === "multi_vcard") {
|
|
||||||
if (message.body !== null && message.body !== "") {
|
|
||||||
let newBody = JSON.parse(message.body)
|
|
||||||
|
|
||||||
let multi_vcard = newBody.map(v => {
|
|
||||||
let array = v.split("\n")
|
|
||||||
let obj = []
|
|
||||||
let contact = ""
|
|
||||||
for (let index = 0; index < array.length; index++) {
|
|
||||||
const v = array[index]
|
|
||||||
let values = v.split(":")
|
|
||||||
for (let ind = 0; ind < values.length; ind++) {
|
|
||||||
if (values[ind].indexOf("+") !== -1) {
|
|
||||||
obj.push({ number: values[ind] })
|
|
||||||
}
|
|
||||||
if (values[ind].indexOf("FN") !== -1) {
|
|
||||||
contact = values[ind + 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { name: contact, number: obj[0]?.number }
|
|
||||||
})
|
|
||||||
return (
|
return (
|
||||||
<>
|
<audio controls>
|
||||||
{
|
<source src={message.mediaUrl} type="audio/ogg"></source>
|
||||||
multi_vcard.map((v, index) => (
|
</audio>
|
||||||
<>
|
);
|
||||||
<VcardPreview contact={v.name} numbers={v.number} multi_vCard={true} id={v.number} />
|
}
|
||||||
|
|
||||||
{((index + 1) <= multi_vcard.length - 1) && <Divider />}
|
if (message.mediaType === "video") {
|
||||||
</>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
} else return (<></>)
|
|
||||||
}
|
|
||||||
else if (/^.*\.(jpe?g|png|gif)?$/i.exec(message.mediaUrl) && message.mediaType === "image") {
|
|
||||||
return <ModalImageCors imageUrl={message.mediaUrl} />
|
|
||||||
} else if (message.mediaType === "audio") {
|
|
||||||
return <Audio url={message.mediaUrl} />
|
|
||||||
} else if (message.mediaType === "video") {
|
|
||||||
return (
|
return (
|
||||||
<video
|
<video
|
||||||
className={classes.messageMedia}
|
className={classes.messageMedia}
|
||||||
src={message.mediaUrl}
|
src={message.mediaUrl}
|
||||||
controls
|
controls
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -631,24 +525,24 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderMessageAck = (message) => {
|
const renderMessageAck = (message) => {
|
||||||
if (message.ack === 0) {
|
if (message.ack === 0) {
|
||||||
return <AccessTime fontSize="small" className={classes.ackIcons} />
|
return <AccessTime fontSize="small" className={classes.ackIcons} />;
|
||||||
}
|
}
|
||||||
if (message.ack === 1) {
|
if (message.ack === 1) {
|
||||||
return <Done fontSize="small" className={classes.ackIcons} />
|
return <Done fontSize="small" className={classes.ackIcons} />;
|
||||||
}
|
}
|
||||||
if (message.ack === 2) {
|
if (message.ack === 2) {
|
||||||
return <DoneAll fontSize="small" className={classes.ackIcons} />
|
return <DoneAll fontSize="small" className={classes.ackIcons} />;
|
||||||
}
|
}
|
||||||
if (message.ack === 3 || message.ack === 4) {
|
if (message.ack === 3 || message.ack === 4) {
|
||||||
return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />
|
return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderDailyTimestamps = (message, index) => {
|
const renderDailyTimestamps = (message, index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
|
@ -661,12 +555,12 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
|
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < messagesList.length - 1) {
|
if (index < messagesList.length - 1) {
|
||||||
let messageDay = parseISO(messagesList[index].createdAt)
|
let messageDay = parseISO(messagesList[index].createdAt);
|
||||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt)
|
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||||
|
|
||||||
if (!isSameDay(messageDay, previousMessageDay)) {
|
if (!isSameDay(messageDay, previousMessageDay)) {
|
||||||
|
|
||||||
|
@ -679,14 +573,14 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
|
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index === messagesList.length - 1) {
|
if (index === messagesList.length - 1) {
|
||||||
|
|
||||||
let messageDay = parseISO(messagesList[index].createdAt)
|
let messageDay = parseISO(messagesList[index].createdAt);
|
||||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt)
|
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -706,24 +600,24 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
style={{ float: "left", clear: "both" }}
|
style={{ float: "left", clear: "both" }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderMessageDivider = (message, index) => {
|
const renderMessageDivider = (message, index) => {
|
||||||
if (index < messagesList.length && index > 0) {
|
if (index < messagesList.length && index > 0) {
|
||||||
let messageUser = messagesList[index].fromMe
|
let messageUser = messagesList[index].fromMe;
|
||||||
let previousMessageUser = messagesList[index - 1].fromMe
|
let previousMessageUser = messagesList[index - 1].fromMe;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (messageUser !== previousMessageUser) {
|
if (messageUser !== previousMessageUser) {
|
||||||
return (
|
return (
|
||||||
<span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span>
|
<span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderQuotedMessage = (message) => {
|
const renderQuotedMessage = (message) => {
|
||||||
return (
|
return (
|
||||||
|
@ -746,90 +640,8 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
{message.quotedMsg?.body}
|
{message.quotedMsg?.body}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
// const renderMessages = () => {
|
|
||||||
// if (messagesList.length > 0) {
|
|
||||||
// const viewMessagesList = messagesList.map((message, index) => {
|
|
||||||
// if (!message.fromMe) {
|
|
||||||
// return (
|
|
||||||
// <React.Fragment key={message.id}>
|
|
||||||
// {renderDailyTimestamps(message, index)}
|
|
||||||
// {renderMessageDivider(message, index)}
|
|
||||||
// <div className={classes.messageLeft}>
|
|
||||||
// <IconButton
|
|
||||||
// variant="contained"
|
|
||||||
// size="small"
|
|
||||||
// id="messageActionsButton"
|
|
||||||
// disabled={message.isDeleted}
|
|
||||||
// className={classes.messageActionsButton}
|
|
||||||
// onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
|
|
||||||
// >
|
|
||||||
// <ExpandMore />
|
|
||||||
// </IconButton>
|
|
||||||
// {isGroup && (
|
|
||||||
// <span className={classes.messageContactName}>
|
|
||||||
// {message.contact?.name}
|
|
||||||
// </span>
|
|
||||||
// )}
|
|
||||||
// {message.mediaUrl && checkMessageMedia(message)}
|
|
||||||
// <div className={classes.textContentItem}>
|
|
||||||
// {message.quotedMsg && renderQuotedMessage(message)}
|
|
||||||
// <MarkdownWrapper>{message.body}</MarkdownWrapper>
|
|
||||||
// <span className={classes.timestamp}>
|
|
||||||
// {format(parseISO(message.createdAt), "HH:mm")}
|
|
||||||
// </span>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </React.Fragment>
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// return (
|
|
||||||
// <React.Fragment key={message.id}>
|
|
||||||
// {renderDailyTimestamps(message, index)}
|
|
||||||
// {renderMessageDivider(message, index)}
|
|
||||||
// <div className={classes.messageRight}>
|
|
||||||
// <IconButton
|
|
||||||
// variant="contained"
|
|
||||||
// size="small"
|
|
||||||
// id="messageActionsButton"
|
|
||||||
// disabled={message.isDeleted}
|
|
||||||
// className={classes.messageActionsButton}
|
|
||||||
// onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
|
|
||||||
// >
|
|
||||||
// <ExpandMore />
|
|
||||||
// </IconButton>
|
|
||||||
// {message.mediaUrl && checkMessageMedia(message)}
|
|
||||||
// <div
|
|
||||||
// className={clsx(classes.textContentItem, {
|
|
||||||
// [classes.textContentItemDeleted]: message.isDeleted,
|
|
||||||
// })}
|
|
||||||
// >
|
|
||||||
// {message.isDeleted && (
|
|
||||||
// <Block
|
|
||||||
// color="disabled"
|
|
||||||
// fontSize="small"
|
|
||||||
// className={classes.deletedIcon}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// {message.quotedMsg && renderQuotedMessage(message)}
|
|
||||||
// <MarkdownWrapper>{message.body}</MarkdownWrapper>
|
|
||||||
// <span className={classes.timestamp}>
|
|
||||||
// {format(parseISO(message.createdAt), "HH:mm")}
|
|
||||||
// {renderMessageAck(message)}
|
|
||||||
// </span>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </React.Fragment>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// return viewMessagesList;
|
|
||||||
// } else {
|
|
||||||
// return <div>Say hello to your new contact!</div>;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
const renderMessages = () => {
|
const renderMessages = () => {
|
||||||
if (messagesList.length > 0) {
|
if (messagesList.length > 0) {
|
||||||
|
@ -855,9 +667,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
{message.contact?.name}
|
{message.contact?.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard"
|
{message.mediaUrl && checkMessageMedia(message)}
|
||||||
|| message.mediaType === "multi_vcard"
|
|
||||||
) && checkMessageMedia(message)}
|
|
||||||
<div className={classes.textContentItem}>
|
<div className={classes.textContentItem}>
|
||||||
{message.quotedMsg && renderQuotedMessage(message)}
|
{message.quotedMsg && renderQuotedMessage(message)}
|
||||||
<MarkdownWrapper>{message.body}</MarkdownWrapper>
|
<MarkdownWrapper>{message.body}</MarkdownWrapper>
|
||||||
|
@ -867,7 +677,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={message.id}>
|
<React.Fragment key={message.id}>
|
||||||
|
@ -884,9 +694,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
>
|
>
|
||||||
<ExpandMore />
|
<ExpandMore />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard"
|
{message.mediaUrl && checkMessageMedia(message)}
|
||||||
// || message.mediaType === "multi_vcard"
|
|
||||||
) && checkMessageMedia(message)}
|
|
||||||
<div
|
<div
|
||||||
className={clsx(classes.textContentItem, {
|
className={clsx(classes.textContentItem, {
|
||||||
[classes.textContentItemDeleted]: message.isDeleted,
|
[classes.textContentItemDeleted]: message.isDeleted,
|
||||||
|
@ -908,14 +716,14 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return viewMessagesList
|
return viewMessagesList;
|
||||||
} else {
|
} else {
|
||||||
return <div>Say hello to your new contact!</div>
|
return <div>Say hello to your new contact!</div>;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.messagesListWrapper}>
|
<div className={classes.messagesListWrapper}>
|
||||||
|
@ -938,7 +746,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default MessagesList
|
export default MessagesList;
|
|
@ -16,8 +16,6 @@ const ModalTemplate = ({ templates, modal_header, func }) => {
|
||||||
|
|
||||||
templates = [{}, ...templates]
|
templates = [{}, ...templates]
|
||||||
|
|
||||||
// console.log('TEMPLATES: ', templates)
|
|
||||||
|
|
||||||
const [open, setOpen] = useState(true)
|
const [open, setOpen] = useState(true)
|
||||||
const [scroll, /*setScroll*/] = useState('body')
|
const [scroll, /*setScroll*/] = useState('body')
|
||||||
const [templateId, setTemplateId] = useState(null)
|
const [templateId, setTemplateId] = useState(null)
|
||||||
|
@ -36,25 +34,7 @@ const ModalTemplate = ({ templates, modal_header, func }) => {
|
||||||
const handleChatEnd = () => {
|
const handleChatEnd = () => {
|
||||||
|
|
||||||
console.log('PARAMS TO SEND TO MESSAGE INPUT: ', params)
|
console.log('PARAMS TO SEND TO MESSAGE INPUT: ', params)
|
||||||
console.log('templateComponents: ', templateComponents)
|
|
||||||
|
|
||||||
if (params && params.length === 1) {
|
|
||||||
|
|
||||||
const bodyObject = templateComponents.find(obj => obj?.type === 'BODY')
|
|
||||||
|
|
||||||
if (bodyObject) {
|
|
||||||
const { text } = bodyObject
|
|
||||||
func([...params, {
|
|
||||||
"type": "BODY",
|
|
||||||
"text": text,
|
|
||||||
"language": "pt_BR",
|
|
||||||
}])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
func(params)
|
func(params)
|
||||||
}
|
|
||||||
|
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +127,7 @@ const ModalTemplate = ({ templates, modal_header, func }) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('---------> PARAMS: ', params)
|
console.log('---------> PARAMS: ', params)
|
||||||
console.log('---------> templateComponents: ', templateComponents)
|
}, [params])
|
||||||
|
|
||||||
}, [params, templateComponents])
|
|
||||||
|
|
||||||
const dinamicTextField = (replicateItems, func, type, text, language) => {
|
const dinamicTextField = (replicateItems, func, type, text, language) => {
|
||||||
|
|
||||||
|
@ -226,7 +204,7 @@ const ModalTemplate = ({ templates, modal_header, func }) => {
|
||||||
{text &&
|
{text &&
|
||||||
<div style={{ margin: 0, padding: 0, 'marginBottom': '15px' }}>
|
<div style={{ margin: 0, padding: 0, 'marginBottom': '15px' }}>
|
||||||
<p style={{ margin: 0, padding: 0, fontSize: 12 }}>{text}</p>
|
<p style={{ margin: 0, padding: 0, fontSize: 12 }}>{text}</p>
|
||||||
{type && (type === 'BODY') && body_params && dinamicTextField(body_params.length, handleTextChange, type, text, language)}
|
{type && (type === 'BODY') && dinamicTextField(body_params.length, handleTextChange, type, text, language)}
|
||||||
</div>}
|
</div>}
|
||||||
{buttons && <div>{buttons.map((b) => {
|
{buttons && <div>{buttons.map((b) => {
|
||||||
const { type, text, url } = b
|
const { type, text, url } = b
|
||||||
|
|
|
@ -41,28 +41,6 @@ const useStyles = makeStyles(theme => ({
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
let _fifo
|
|
||||||
|
|
||||||
// const onlineEmitter = async (socket, user) => {
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// clearInterval(_fifo);
|
|
||||||
|
|
||||||
// socket.emit("online", user.id)
|
|
||||||
|
|
||||||
// } catch (error) {
|
|
||||||
// console.log('error on onlineEmitter: ', error)
|
|
||||||
// }
|
|
||||||
// finally {
|
|
||||||
// _fifo = setInterval(onlineEmitter, 3000);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _fifo = setInterval(onlineEmitter, 3000);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const NotificationsPopOver = () => {
|
const NotificationsPopOver = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
|
@ -87,8 +65,6 @@ const NotificationsPopOver = () => {
|
||||||
// const [lastRef] = useState(+history.location.pathname.split("/")[2])
|
// const [lastRef] = useState(+history.location.pathname.split("/")[2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
soundAlertRef.current = play
|
soundAlertRef.current = play
|
||||||
|
|
||||||
|
@ -104,9 +80,6 @@ const NotificationsPopOver = () => {
|
||||||
}, [tickets])
|
}, [tickets])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ticketIdRef.current = ticketIdUrl
|
ticketIdRef.current = ticketIdUrl
|
||||||
}, [ticketIdUrl])
|
}, [ticketIdUrl])
|
||||||
|
|
||||||
|
@ -130,8 +103,6 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
if (data.action === "logout") {
|
if (data.action === "logout") {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (`${user.id}` === data.userOnlineTime['userId']) {
|
if (`${user.id}` === data.userOnlineTime['userId']) {
|
||||||
|
|
||||||
socket.emit("online", { logoutUserId: user.id })
|
socket.emit("online", { logoutUserId: user.id })
|
||||||
|
@ -140,7 +111,6 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// socket.on("isOnline", (data) => {
|
// socket.on("isOnline", (data) => {
|
||||||
|
@ -159,21 +129,24 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
if (user.profile === 'user') {
|
if (user.profile === 'user') {
|
||||||
|
|
||||||
if (_fifo) {
|
// if (_fifo) {
|
||||||
clearInterval(_fifo)
|
// clearInterval(_fifo);
|
||||||
}
|
// }
|
||||||
|
|
||||||
_fifo = setInterval(() => {
|
// _fifo = setInterval(() => {
|
||||||
|
// socket.emit("online", user.id)
|
||||||
|
// }, 3000);
|
||||||
|
|
||||||
|
const intID = setInterval(() => {
|
||||||
|
console.log('emitting the online')
|
||||||
socket.emit("online", user.id)
|
socket.emit("online", user.id)
|
||||||
}, 3000)
|
}, 3000)
|
||||||
|
|
||||||
|
return () => clearInterval(intID)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect()
|
socket.disconnect()
|
||||||
}
|
}
|
||||||
|
@ -191,8 +164,6 @@ const NotificationsPopOver = () => {
|
||||||
socket.on("ticket", data => {
|
socket.on("ticket", data => {
|
||||||
if (data.action === "updateUnread" || data.action === "delete") {
|
if (data.action === "updateUnread" || data.action === "delete") {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setNotifications(prevState => {
|
setNotifications(prevState => {
|
||||||
const ticketIndex = prevState.findIndex(t => t.id === data.ticketId)
|
const ticketIndex = prevState.findIndex(t => t.id === data.ticketId)
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
|
@ -218,25 +189,14 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
socket.on("appMessage", data => {
|
socket.on("appMessage", data => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
data.action === "create" &&
|
data.action === "create" &&
|
||||||
!data.message.read &&
|
!data.message.read &&
|
||||||
(data.ticket.userId === user?.id || !data.ticket.userId)
|
(data.ticket.userId === user?.id || !data.ticket.userId)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setNotifications(prevState => {
|
setNotifications(prevState => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// prevState.forEach((e)=>{
|
|
||||||
//
|
|
||||||
// })
|
|
||||||
|
|
||||||
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id)
|
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id)
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
|
|
||||||
|
@ -247,16 +207,12 @@ const NotificationsPopOver = () => {
|
||||||
return [data.ticket, ...prevState]
|
return [data.ticket, ...prevState]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") ||
|
const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") ||
|
||||||
(data.ticket.userId && data.ticket.userId !== user?.id) ||
|
(data.ticket.userId && data.ticket.userId !== user?.id) ||
|
||||||
data.ticket.isGroup || !data.ticket.userId
|
data.ticket.isGroup || !data.ticket.userId
|
||||||
|
|
||||||
if (shouldNotNotificate) return
|
if (shouldNotNotificate) return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
handleNotifications(data)
|
handleNotifications(data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
import React, { useState, useEffect } from "react"
|
|
||||||
import Box from '@mui/material/Box'
|
|
||||||
import Button from '@mui/material/Button'
|
|
||||||
import Dialog from '@mui/material/Dialog'
|
|
||||||
import DialogActions from '@mui/material/DialogActions'
|
|
||||||
import DialogContent from '@mui/material/DialogContent'
|
|
||||||
import DialogContentText from '@mui/material/DialogContentText'
|
|
||||||
import DialogTitle from '@mui/material/DialogTitle'
|
|
||||||
import FormControl from '@mui/material/FormControl'
|
|
||||||
|
|
||||||
import InputLabel from '@mui/material/InputLabel'
|
|
||||||
import MenuItem from '@mui/material/MenuItem'
|
|
||||||
import Select from '@mui/material/Select'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function MaxWidthDialog(props) {
|
|
||||||
const [open, setOpen] = useState(false)
|
|
||||||
const [fullWidth,] = useState(true)
|
|
||||||
const [currency, setCurrency] = useState(props.reportOption)
|
|
||||||
const [textOption, setTextOption] = useState('')
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
// props.func(currency)
|
|
||||||
|
|
||||||
if(currency === '2' || currency === '3'){
|
|
||||||
setTextOption('Retorna apenas tickets com status: fechado')
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
setTextOption('Retorna todos os tickets com status: aberto, fechado, pendente')
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [currency, props])
|
|
||||||
|
|
||||||
|
|
||||||
const handleClickOpen = () => {
|
|
||||||
setOpen(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
|
|
||||||
props.func(currency)
|
|
||||||
|
|
||||||
setOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMaxWidthChange = (event) => {
|
|
||||||
|
|
||||||
setCurrency(event.target.value)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Button variant="outlined" onClick={handleClickOpen}>
|
|
||||||
CSV ALL
|
|
||||||
</Button>
|
|
||||||
<Dialog
|
|
||||||
fullWidth={fullWidth}
|
|
||||||
maxWidth={'sm'}
|
|
||||||
open={open}
|
|
||||||
onClose={null}
|
|
||||||
>
|
|
||||||
<DialogTitle>Relatórios</DialogTitle>
|
|
||||||
|
|
||||||
<DialogContent>
|
|
||||||
<DialogContentText>
|
|
||||||
Escolha uma opção do tipo de relatório abaixo
|
|
||||||
</DialogContentText>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
noValidate
|
|
||||||
component="form"
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
m: 'auto',
|
|
||||||
width: 'fit-content',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormControl sx={{ mt: 2, minWidth: 420 }}>
|
|
||||||
|
|
||||||
<InputLabel htmlFor="opcoes">opcoes</InputLabel>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
autoFocus
|
|
||||||
value={currency}
|
|
||||||
onChange={handleMaxWidthChange}
|
|
||||||
label="opcoes"
|
|
||||||
inputProps={{
|
|
||||||
name: 'opcoes',
|
|
||||||
id: 'opcoes',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
|
|
||||||
{props.currencies.map((option, index) => (
|
|
||||||
<MenuItem key={index} value={option.value}> {option.label} </MenuItem>
|
|
||||||
))}
|
|
||||||
|
|
||||||
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{/* <FormControlLabel
|
|
||||||
sx={{ mt: 1 }}
|
|
||||||
control={
|
|
||||||
<Switch checked={fullWidth} onChange={handleFullWidthChange} />
|
|
||||||
}
|
|
||||||
label="Full width"
|
|
||||||
/> */}
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<div style={{ display: 'flex', justifyContent: "center" }}>{textOption}</div>
|
|
||||||
|
|
||||||
<div style={{ display: 'flex', justifyContent: "right" }}>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => setOpen(false)}>Cancelar</Button>
|
|
||||||
</DialogActions>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleClose}>Ok</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Dialog>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,20 +1,20 @@
|
||||||
import React, { useState, useEffect, useReducer, useContext } from "react"
|
import React, { useState, useEffect, useReducer, useContext } from "react";
|
||||||
|
|
||||||
|
|
||||||
import openSocket from "socket.io-client"
|
import openSocket from "socket.io-client";
|
||||||
|
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import List from "@material-ui/core/List"
|
import List from "@material-ui/core/List";
|
||||||
import Paper from "@material-ui/core/Paper"
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
|
||||||
import TicketListItem from "../TicketListItem"
|
import TicketListItem from "../TicketListItem";
|
||||||
import TicketsListSkeleton from "../TicketsListSkeleton"
|
import TicketsListSkeleton from "../TicketsListSkeleton";
|
||||||
|
|
||||||
import useTickets from "../../hooks/useTickets"
|
import useTickets from "../../hooks/useTickets";
|
||||||
import { i18n } from "../../translate/i18n"
|
import { i18n } from "../../translate/i18n";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
|
||||||
import { SearchTicketContext } from "../../context/SearchTicket/SearchTicket"
|
import { SearchTicketContext } from "../../context/SearchTicket/SearchTicket";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
ticketsListWrapper: {
|
ticketsListWrapper: {
|
||||||
|
@ -73,64 +73,64 @@ const useStyles = makeStyles(theme => ({
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const reducer = (state, action) => {
|
const reducer = (state, action) => {
|
||||||
if (action.type === "LOAD_TICKETS") {
|
if (action.type === "LOAD_TICKETS") {
|
||||||
const newTickets = action.payload
|
const newTickets = action.payload;
|
||||||
|
|
||||||
|
|
||||||
newTickets.forEach(ticket => {
|
newTickets.forEach(ticket => {
|
||||||
|
|
||||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id)
|
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
state[ticketIndex] = ticket
|
state[ticketIndex] = ticket;
|
||||||
if (+ticket.unreadMessages > 0) {
|
if (+ticket.unreadMessages > 0) {
|
||||||
state.unshift(state.splice(ticketIndex, 1)[0])
|
state.unshift(state.splice(ticketIndex, 1)[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.push(ticket)
|
state.push(ticket);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "RESET_UNREAD") {
|
if (action.type === "RESET_UNREAD") {
|
||||||
const ticketId = action.payload
|
const ticketId = action.payload;
|
||||||
|
|
||||||
const ticketIndex = state.findIndex(t => +t.id === +ticketId)
|
const ticketIndex = state.findIndex(t => +t.id === +ticketId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
state[ticketIndex].unreadMessages = 0
|
state[ticketIndex].unreadMessages = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "UPDATE_TICKET") {
|
if (action.type === "UPDATE_TICKET") {
|
||||||
const ticket = action.payload
|
const ticket = action.payload;
|
||||||
|
|
||||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id)
|
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||||
|
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
state[ticketIndex] = ticket
|
state[ticketIndex] = ticket;
|
||||||
} else {
|
} else {
|
||||||
state.unshift(ticket)
|
state.unshift(ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") {
|
if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") {
|
||||||
|
|
||||||
const message = action.payload.message
|
const message = action.payload.message
|
||||||
|
|
||||||
const ticket = action.payload.ticket
|
const ticket = action.payload.ticket;
|
||||||
|
|
||||||
const ticketIndex = state.findIndex(t => +t.id === +ticket.id)
|
const ticketIndex = state.findIndex(t => +t.id === +ticket.id);
|
||||||
|
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
|
|
||||||
|
@ -142,55 +142,55 @@ const reducer = (state, action) => {
|
||||||
ticket.unreadMessages += 1
|
ticket.unreadMessages += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
state[ticketIndex] = ticket
|
state[ticketIndex] = ticket;
|
||||||
state.unshift(state.splice(ticketIndex, 1)[0])
|
state.unshift(state.splice(ticketIndex, 1)[0]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
state.unshift(ticket)
|
state.unshift(ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "UPDATE_TICKET_CONTACT") {
|
if (action.type === "UPDATE_TICKET_CONTACT") {
|
||||||
const contact = action.payload
|
const contact = action.payload;
|
||||||
const ticketIndex = state.findIndex(t => +t.contactId === +contact.id)
|
const ticketIndex = state.findIndex(t => +t.contactId === +contact.id);
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
state[ticketIndex].contact = contact
|
state[ticketIndex].contact = contact;
|
||||||
}
|
}
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "DELETE_TICKET") {
|
if (action.type === "DELETE_TICKET") {
|
||||||
const ticketId = action.payload
|
const ticketId = action.payload;
|
||||||
const ticketIndex = state.findIndex(t => +t.id === +ticketId)
|
const ticketIndex = state.findIndex(t => +t.id === +ticketId);
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
state.splice(ticketIndex, 1)
|
state.splice(ticketIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...state]
|
return [...state];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "RESET") {
|
if (action.type === "RESET") {
|
||||||
return []
|
return [];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const TicketsList = (props) => {
|
const TicketsList = (props) => {
|
||||||
const { status, searchParam, searchParamContent, showAll, selectedQueueIds, updateCount, style, tab } = props
|
const { status, searchParam, searchParamContent, showAll, selectedQueueIds, updateCount, style, tab } = props;
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const [pageNumber, setPageNumber] = useState(1)
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
const [ticketsList, dispatch] = useReducer(reducer, [])
|
const [ticketsList, dispatch] = useReducer(reducer, []);
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext);
|
||||||
|
|
||||||
const { searchTicket } = useContext(SearchTicketContext)
|
const { searchTicket } = useContext(SearchTicketContext)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
dispatch({ type: "RESET" })
|
dispatch({ type: "RESET" });
|
||||||
setPageNumber(1)
|
setPageNumber(1);
|
||||||
|
|
||||||
}, [status, searchParam, searchParamContent, showAll, selectedQueueIds, searchTicket])
|
}, [status, searchParam, searchParamContent, showAll, selectedQueueIds, searchTicket]);
|
||||||
|
|
||||||
const { tickets, hasMore, loading } = useTickets({
|
const { tickets, hasMore, loading } = useTickets({
|
||||||
pageNumber,
|
pageNumber,
|
||||||
|
@ -199,13 +199,12 @@ const TicketsList = (props) => {
|
||||||
status,
|
status,
|
||||||
showAll,
|
showAll,
|
||||||
queueIds: JSON.stringify(selectedQueueIds),
|
queueIds: JSON.stringify(selectedQueueIds),
|
||||||
tab,
|
tab
|
||||||
unlimited: status === 'open' ? "all" : "false"
|
});
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
if (!status && !searchParam) return
|
if (!status && !searchParam) return;
|
||||||
|
|
||||||
// if (searchParam) {
|
// if (searchParam) {
|
||||||
//
|
//
|
||||||
|
@ -218,31 +217,31 @@ const TicketsList = (props) => {
|
||||||
dispatch({ type: "RESET" })
|
dispatch({ type: "RESET" })
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({ type: "LOAD_TICKETS", payload: tickets, })
|
dispatch({ type: "LOAD_TICKETS", payload: tickets, });
|
||||||
|
|
||||||
}, [tickets, status, searchParam, pageNumber])
|
}, [tickets, status, searchParam, pageNumber]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
// if (tab=='search')return
|
// 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 =>
|
const shouldUpdateTicket = ticket =>
|
||||||
(!ticket.userId || ticket.userId === user?.id || showAll) &&
|
(!ticket.userId || ticket.userId === user?.id || showAll) &&
|
||||||
(!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1)
|
(!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1);
|
||||||
|
|
||||||
const notBelongsToUserQueues = ticket =>
|
const notBelongsToUserQueues = ticket =>
|
||||||
ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1
|
ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1;
|
||||||
|
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
if (status) {
|
if (status) {
|
||||||
socket.emit("joinTickets", status)
|
socket.emit("joinTickets", status);
|
||||||
} else {
|
} else {
|
||||||
socket.emit("joinNotification")
|
socket.emit("joinNotification");
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,7 +254,7 @@ const TicketsList = (props) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "RESET_UNREAD",
|
type: "RESET_UNREAD",
|
||||||
payload: data.ticketId,
|
payload: data.ticketId,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.action === "update" && shouldUpdateTicket(data.ticket)) {
|
if (data.action === "update" && shouldUpdateTicket(data.ticket)) {
|
||||||
|
@ -265,17 +264,17 @@ const TicketsList = (props) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "UPDATE_TICKET",
|
type: "UPDATE_TICKET",
|
||||||
payload: data.ticket,
|
payload: data.ticket,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.action === "update" && notBelongsToUserQueues(data.ticket)) {
|
if (data.action === "update" && notBelongsToUserQueues(data.ticket)) {
|
||||||
dispatch({ type: "DELETE_TICKET", payload: data.ticket.id })
|
dispatch({ type: "DELETE_TICKET", payload: data.ticket.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.action === "delete") {
|
if (data.action === "delete") {
|
||||||
dispatch({ type: "DELETE_TICKET", payload: data.ticketId })
|
dispatch({ type: "DELETE_TICKET", payload: data.ticketId });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
socket.on("appMessage", data => {
|
socket.on("appMessage", data => {
|
||||||
|
@ -288,49 +287,51 @@ const TicketsList = (props) => {
|
||||||
type: "UPDATE_TICKET_UNREAD_MESSAGES",
|
type: "UPDATE_TICKET_UNREAD_MESSAGES",
|
||||||
// payload: data.ticket,
|
// payload: data.ticket,
|
||||||
payload: data,
|
payload: data,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
socket.on("contact", data => {
|
socket.on("contact", data => {
|
||||||
if (data.action === "update") {
|
if (data.action === "update") {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "UPDATE_TICKET_CONTACT",
|
type: "UPDATE_TICKET_CONTACT",
|
||||||
payload: data.contact,
|
payload: data.contact,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect()
|
socket.disconnect();
|
||||||
}
|
};
|
||||||
}, [status, showAll, user, selectedQueueIds, tab])
|
}, [status, showAll, user, selectedQueueIds, tab]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (typeof updateCount === "function") {
|
if (typeof updateCount === "function") {
|
||||||
updateCount(ticketsList.length)
|
updateCount(ticketsList.length);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [ticketsList])
|
}, [ticketsList]);
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
setPageNumber(prevState => prevState + 1)
|
setPageNumber(prevState => prevState + 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleScroll = e => {
|
const handleScroll = e => {
|
||||||
|
|
||||||
if (!hasMore || loading) return
|
if (!hasMore || loading) return;
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget
|
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||||
|
|
||||||
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
loadMore()
|
loadMore();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className={classes.ticketsListWrapper} style={style}>
|
<Paper className={classes.ticketsListWrapper} style={style}>
|
||||||
|
@ -362,7 +363,7 @@ const TicketsList = (props) => {
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default TicketsList
|
export default TicketsList;
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
import React, { useEffect, useState, useContext } from 'react'
|
|
||||||
import { useHistory } from "react-router-dom"
|
|
||||||
import toastError from "../../errors/toastError"
|
|
||||||
import api from "../../services/api"
|
|
||||||
|
|
||||||
import Avatar from "@material-ui/core/Avatar"
|
|
||||||
import Typography from "@material-ui/core/Typography"
|
|
||||||
import Grid from "@material-ui/core/Grid"
|
|
||||||
|
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
|
||||||
|
|
||||||
import { Button, Divider, } from "@material-ui/core"
|
|
||||||
|
|
||||||
const VcardPreview = ({ contact, numbers, multi_vCard }) => {
|
|
||||||
const history = useHistory()
|
|
||||||
const { user } = useContext(AuthContext)
|
|
||||||
|
|
||||||
const [selectedContact, setContact] = useState({
|
|
||||||
name: "",
|
|
||||||
number: 0,
|
|
||||||
profilePicUrl: ""
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const delayDebounceFn = setTimeout(() => {
|
|
||||||
const fetchContacts = async () => {
|
|
||||||
try {
|
|
||||||
let contactObj = {
|
|
||||||
name: contact,
|
|
||||||
// number: numbers.replace(/\D/g, ""),
|
|
||||||
number: numbers !== undefined && numbers.replace(/\D/g, ""),
|
|
||||||
email: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data } = await api.post("/contact", contactObj)
|
|
||||||
|
|
||||||
setContact(data)
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
toastError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchContacts()
|
|
||||||
}, 500)
|
|
||||||
return () => clearTimeout(delayDebounceFn)
|
|
||||||
}, [contact, numbers])
|
|
||||||
|
|
||||||
const handleNewChat = async () => {
|
|
||||||
try {
|
|
||||||
const { data: ticket } = await api.post("/tickets", {
|
|
||||||
contactId: selectedContact.id,
|
|
||||||
userId: user.id,
|
|
||||||
status: "open",
|
|
||||||
})
|
|
||||||
history.push(`/tickets/${ticket.id}`)
|
|
||||||
} catch (err) {
|
|
||||||
toastError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div style={{
|
|
||||||
minWidth: "250px",
|
|
||||||
}}>
|
|
||||||
<Grid container spacing={1}>
|
|
||||||
<Grid item xs={2}>
|
|
||||||
<Avatar src={selectedContact.profilePicUrl} />
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={9}>
|
|
||||||
<Typography style={{ marginTop: "12px", marginLeft: "10px" }} variant="subtitle1" color="primary" gutterBottom>
|
|
||||||
{selectedContact.name}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
{!multi_vCard && <Divider />}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
fullWidth
|
|
||||||
color="primary"
|
|
||||||
onClick={handleNewChat}
|
|
||||||
disabled={!selectedContact.number}
|
|
||||||
>Conversar</Button>
|
|
||||||
|
|
||||||
{/* {multi_vCard && <Divider />} */}
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default VcardPreview
|
|
|
@ -70,7 +70,6 @@ const WhatsAppModal = ({ open, onClose, whatsAppId, whatsAppOfficial }) => {
|
||||||
farewellMessage: '',
|
farewellMessage: '',
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
isOfficial: false,
|
isOfficial: false,
|
||||||
number: '',
|
|
||||||
phoneNumberId: '',
|
phoneNumberId: '',
|
||||||
wabaId: ''
|
wabaId: ''
|
||||||
}
|
}
|
||||||
|
@ -110,7 +109,6 @@ const WhatsAppModal = ({ open, onClose, whatsAppId, whatsAppOfficial }) => {
|
||||||
if (!isOfficial) {
|
if (!isOfficial) {
|
||||||
values.phoneNumberId = ''
|
values.phoneNumberId = ''
|
||||||
values.wabaId = ''
|
values.wabaId = ''
|
||||||
values.number = ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -278,18 +276,6 @@ const WhatsAppModal = ({ open, onClose, whatsAppId, whatsAppOfficial }) => {
|
||||||
margin="dense"
|
margin="dense"
|
||||||
className={classes.textField}
|
className={classes.textField}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field
|
|
||||||
as={TextField}
|
|
||||||
label="Phone number"
|
|
||||||
autoFocus
|
|
||||||
name="number"
|
|
||||||
error={touched.name && Boolean(errors.name)}
|
|
||||||
helperText={touched.name && errors.name}
|
|
||||||
variant="outlined"
|
|
||||||
margin="dense"
|
|
||||||
className={classes.textField}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ const LoggedInLayout = ({ children }) => {
|
||||||
className={classes.title}
|
className={classes.title}
|
||||||
>
|
>
|
||||||
|
|
||||||
OMNIHIT
|
OMNIHIT Espaçolaser - Lojas
|
||||||
|
|
||||||
</Typography>
|
</Typography>
|
||||||
{user.id && <NotificationsPopOver />}
|
{user.id && <NotificationsPopOver />}
|
||||||
|
|
|
@ -20,7 +20,7 @@ const Chart = (props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const date = useRef(new Date().toISOString());
|
const date = useRef(new Date().toISOString());
|
||||||
let { tickets } = useTickets({ date: date.current, unlimited: "current" });
|
let { tickets } = useTickets({ date: date.current, unlimited: "true" });
|
||||||
|
|
||||||
const [chartData, setChartData] = useState([
|
const [chartData, setChartData] = useState([
|
||||||
{ time: "08:00", amount: 0 },
|
{ time: "08:00", amount: 0 },
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
import { Box } from '@material-ui/core';
|
|
||||||
import React from 'react';
|
|
||||||
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
|
||||||
import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';
|
|
||||||
|
|
||||||
import Title from './Title';
|
|
||||||
|
|
||||||
const generateDataExample = (amount) => {
|
|
||||||
const arr = []
|
|
||||||
for (let i = 1; i <= amount; i++) {
|
|
||||||
arr.push({
|
|
||||||
"id": i,
|
|
||||||
"name": `Exemplo ${i}`,
|
|
||||||
"count": Math.floor(Math.random() * 10 + 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataExample = generateDataExample(20)
|
|
||||||
|
|
||||||
const COLORS = [
|
|
||||||
'#0088FE', // Azul escuro
|
|
||||||
'#00C49F', // Verde menta
|
|
||||||
'#FFBB28', // Laranja escuro
|
|
||||||
'#FF8042', // Vermelho escuro
|
|
||||||
'#9D38BD', // Roxo escuro
|
|
||||||
'#FFD166', // Laranja claro
|
|
||||||
'#331F00', // Marrom escuro
|
|
||||||
'#C0FFC0', // Verde Claro
|
|
||||||
'#C4E538', // Verde-amarelo vibrante
|
|
||||||
'#A2A2A2', // Cinza claro
|
|
||||||
'#FFF700', // Amarelo Canário
|
|
||||||
'#FF69B4', // Rosa Flamingo
|
|
||||||
'#87CEEB', // Azul Celeste
|
|
||||||
'#228B22', // Verde Esmeralda
|
|
||||||
'#9B59B6', // Roxo Ametista
|
|
||||||
'#FF9933', // Laranja Tangerina
|
|
||||||
'#FF7F50', // Coral Vivo
|
|
||||||
'#00CED1', // Verde Água
|
|
||||||
'#000080', // Azul Marinho
|
|
||||||
'#FFDB58', // Amarelo Mostarda
|
|
||||||
];
|
|
||||||
|
|
||||||
const RADIAN = Math.PI / 180;
|
|
||||||
|
|
||||||
const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, count }) => {
|
|
||||||
const radius = innerRadius + (outerRadius - innerRadius) * 0.80;
|
|
||||||
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
|
||||||
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<text x={x} y={y} fill="white" textAnchor={x > cx ? 'start' : 'end'} dominantBaseline="central">
|
|
||||||
{count}
|
|
||||||
</text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param data array de objetos no formato
|
|
||||||
* {
|
|
||||||
"id": number | string,
|
|
||||||
"name": string,
|
|
||||||
"count": number
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
const PieChart = ({ data = dataExample }) => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
position="relative"
|
|
||||||
display="flex"
|
|
||||||
sx={{ overflowY: "scroll" }}
|
|
||||||
>
|
|
||||||
<Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
|
|
||||||
<Box sx={{ position: "absolute" }}>
|
|
||||||
<Title>Tickets encerramento</Title>
|
|
||||||
</Box>
|
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
|
||||||
<RechartsPieChart width={400} height={400}>
|
|
||||||
<Pie
|
|
||||||
data={data}
|
|
||||||
cx="25%"
|
|
||||||
cy="60%"
|
|
||||||
labelLine={false}
|
|
||||||
label={renderCustomizedLabel}
|
|
||||||
outerRadius={100}
|
|
||||||
fill="#8884d8"
|
|
||||||
dataKey="count"
|
|
||||||
>
|
|
||||||
{data.map((entry, index) => (
|
|
||||||
<Cell key={`cell-${entry.id}`} fill={COLORS[index % COLORS.length]} />
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Tooltip />
|
|
||||||
</RechartsPieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
component="ul"
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
top: 0, right: 0,
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "4px",
|
|
||||||
maxWidth: "60%",
|
|
||||||
minWidth: "50%",
|
|
||||||
zIndex: 0,
|
|
||||||
}}>
|
|
||||||
{data.map((entry, index) => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
component="li"
|
|
||||||
key={entry.id}
|
|
||||||
sx={{
|
|
||||||
display: "flex", gap: "2px",
|
|
||||||
color: COLORS[index % COLORS.length],
|
|
||||||
alignItems: "center"
|
|
||||||
}}>
|
|
||||||
<FiberManualRecordIcon fill={COLORS[index % COLORS.length]} />
|
|
||||||
<text style={{ color: 'black' }}>{entry.name}</text>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
</Box >
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PieChart
|
|
|
@ -15,7 +15,6 @@ import Info from "@material-ui/icons/Info"
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||||
// import { i18n } from "../../translate/i18n";
|
// import { i18n } from "../../translate/i18n";
|
||||||
import Chart from "./Chart"
|
import Chart from "./Chart"
|
||||||
import PieChart from "./PieChart"
|
|
||||||
import openSocket from "socket.io-client"
|
import openSocket from "socket.io-client"
|
||||||
import api from "../../services/api"
|
import api from "../../services/api"
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ const useStyles = makeStyles((theme) => ({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
height: 280,
|
height: 240,
|
||||||
},
|
},
|
||||||
customFixedHeightPaper: {
|
customFixedHeightPaper: {
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
|
@ -258,7 +257,7 @@ const Dashboard = () => {
|
||||||
const [usersOnlineInfo, dispatch] = useReducer(reducer, [])
|
const [usersOnlineInfo, dispatch] = useReducer(reducer, [])
|
||||||
const [ticketStatusChange, setStatus] = useState()
|
const [ticketStatusChange, setStatus] = useState()
|
||||||
const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 })
|
const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 })
|
||||||
const [ticketStatusChatEnd, setTicketStatusChatEnd] = useState([])
|
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -289,15 +288,10 @@ const Dashboard = () => {
|
||||||
params: { userId: null, startDate: dateToday, endDate: dateToday },
|
params: { userId: null, startDate: dateToday, endDate: dateToday },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// console.log('data.data: ', data.usersProfile)
|
||||||
|
|
||||||
dispatch({ type: "RESET" })
|
dispatch({ type: "RESET" })
|
||||||
dispatch({ type: "LOAD_QUERY", payload: data.usersProfile })
|
dispatch({ type: "LOAD_QUERY", payload: data.usersProfile })
|
||||||
|
|
||||||
const { data: ticketStatusChatEndData } = await api.get("/reports/count/statusChatEnd", {
|
|
||||||
params: { startDate: dateToday, endDate: dateToday },
|
|
||||||
})
|
|
||||||
|
|
||||||
setTicketStatusChatEnd(ticketStatusChatEndData.reportStatusChatEnd)
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -503,18 +497,11 @@ const Dashboard = () => {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item container spacing={3}>
|
<Grid item xs={12}>
|
||||||
<Grid item xs={12} sm={12} md={6} lg={6}>
|
|
||||||
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
||||||
<Chart allTickets={usersOnlineInfo} />
|
<Chart allTickets={usersOnlineInfo} />
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={12} md={6} lg={6}>
|
|
||||||
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
|
||||||
<PieChart data={ticketStatusChatEnd} />
|
|
||||||
</Paper>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper className={classes.containerPaperFix} style={{ marginTop: "21px" }} sx={12}>
|
<Paper className={classes.containerPaperFix} style={{ marginTop: "21px" }} sx={12}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useReducer, useContext, useCallback } from "react"
|
import React, { useState, useEffect, useReducer, useContext } from "react"
|
||||||
import MainContainer from "../../components/MainContainer"
|
import MainContainer from "../../components/MainContainer"
|
||||||
import api from "../../services/api"
|
import api from "../../services/api"
|
||||||
import SelectField from "../../components/Report/SelectField"
|
import SelectField from "../../components/Report/SelectField"
|
||||||
|
@ -9,35 +9,24 @@ import PropTypes from 'prop-types'
|
||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||||
import { Can } from "../../components/Can"
|
import { Can } from "../../components/Can"
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel"
|
|
||||||
import Checkbox from '@mui/material/Checkbox'
|
|
||||||
import { Button } from "@material-ui/core"
|
import { Button } from "@material-ui/core"
|
||||||
|
|
||||||
import ReportModal from "../../components/ReportModal"
|
import ReportModal from "../../components/ReportModal"
|
||||||
import ReportModalType from "../../components/ReportModalType"
|
|
||||||
import MaterialTable from 'material-table'
|
import MaterialTable from 'material-table'
|
||||||
|
|
||||||
import LogoutIcon from '@material-ui/icons/CancelOutlined'
|
import LogoutIcon from '@material-ui/icons/CancelOutlined'
|
||||||
|
|
||||||
import apiBroker from "../../services/apiBroker"
|
import apiBroker from "../../services/apiBroker"
|
||||||
import fileDownload from 'js-file-download'
|
import fileDownload from 'js-file-download'
|
||||||
|
|
||||||
|
|
||||||
import openSocket from "socket.io-client"
|
import openSocket from "socket.io-client"
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n"
|
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' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const reportOptType = [
|
|
||||||
{ 'value': '1', 'label': 'Padrão' },
|
|
||||||
{ 'value': '2', 'label': 'Sintético' },
|
|
||||||
{ 'value': '3', 'label': 'Analítico' }
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
|
const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }]
|
||||||
|
|
||||||
|
|
||||||
const reducerQ = (state, action) => {
|
const reducerQ = (state, action) => {
|
||||||
|
@ -59,13 +48,9 @@ const reducerQ = (state, action) => {
|
||||||
|
|
||||||
if (action.type === 'LOAD_QUERY') {
|
if (action.type === 'LOAD_QUERY') {
|
||||||
|
|
||||||
let queries = action.payload
|
const queries = action.payload
|
||||||
const newQueries = []
|
const newQueries = []
|
||||||
|
|
||||||
if (queries?.hasOwnProperty('usersProfile')) {
|
|
||||||
queries = queries.usersProfile
|
|
||||||
}
|
|
||||||
|
|
||||||
queries.forEach((query) => {
|
queries.forEach((query) => {
|
||||||
|
|
||||||
const queryIndex = state.findIndex((q) => q.id === query.id)
|
const queryIndex = state.findIndex((q) => q.id === query.id)
|
||||||
|
@ -234,10 +219,7 @@ let columnsData = [
|
||||||
|
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }]
|
||||||
{ title: `Espera`, field: 'waiting_time' },
|
|
||||||
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
|
||||||
]
|
|
||||||
|
|
||||||
let columnsDataSuper = [
|
let columnsDataSuper = [
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' },
|
{ title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' },
|
||||||
|
@ -249,9 +231,7 @@ let columnsDataSuper = [
|
||||||
|
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }
|
||||||
{ title: `Espera`, field: 'waiting_time' },
|
|
||||||
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -285,27 +265,23 @@ const Report = () => {
|
||||||
const [hasMore, setHasMore] = useState(false)
|
const [hasMore, setHasMore] = useState(false)
|
||||||
const [pageNumberTickets, setTicketsPageNumber] = useState(1)
|
const [pageNumberTickets, setTicketsPageNumber] = useState(1)
|
||||||
const [totalCountTickets, setTotalCountTickets] = useState(0)
|
const [totalCountTickets, setTotalCountTickets] = useState(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [pageNumber, setPageNumber] = useState(1)
|
const [pageNumber, setPageNumber] = useState(1)
|
||||||
const [users, dispatch] = useReducer(reducer, [])
|
const [users, dispatch] = useReducer(reducer, [])
|
||||||
const [startDate, setDatePicker1] = useState(new Date())
|
const [startDate, setDatePicker1] = useState(new Date())
|
||||||
const [endDate, setDatePicker2] = useState(new Date())
|
const [endDate, setDatePicker2] = useState(new Date())
|
||||||
const [userId, setUser] = useState(null)
|
const [userId, setUser] = useState(null)
|
||||||
const [query, dispatchQ] = useReducer(reducerQ, [])
|
const [query, dispatchQ] = useReducer(reducerQ, [])
|
||||||
|
|
||||||
const [reportOption, setReport] = useState('1')
|
const [reportOption, setReport] = useState('1')
|
||||||
const [reporList,] = useState(report)
|
const [reporList,] = useState(report)
|
||||||
const [profile, setProfile] = useState('')
|
const [profile, setProfile] = useState('')
|
||||||
const [dataRows, setData] = useState([])
|
const [dataRows, setData] = useState([])
|
||||||
|
|
||||||
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
||||||
const [csvFile, setCsvFile] = useState()
|
const [csvFile, setCsvFile] = useState()
|
||||||
const [selectedValue, setSelectedValue] = useState('created')
|
|
||||||
const [checked, setChecked] = useState(true)
|
|
||||||
const [queues, setQueues] = useState([])
|
|
||||||
const [queueId, setQueue] = useState(null)
|
|
||||||
|
|
||||||
const [reportTypeList,] = useState(reportOptType)
|
|
||||||
const [reportType, setReportType] = useState('1')
|
|
||||||
const [firstLoad, setFirstLoad] = useState(true)
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({ type: "RESET" })
|
dispatch({ type: "RESET" })
|
||||||
|
@ -315,14 +291,6 @@ const Report = () => {
|
||||||
}, [searchParam, profile])
|
}, [searchParam, profile])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (firstLoad) {
|
|
||||||
setFirstLoad(false)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}, [firstLoad])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//setLoading(true);
|
//setLoading(true);
|
||||||
|
|
||||||
|
@ -354,35 +322,32 @@ const Report = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
//setLoading(true);
|
//setLoading(true);
|
||||||
if (firstLoad) return
|
|
||||||
|
|
||||||
const delayDebounceFn = setTimeout(() => {
|
const delayDebounceFn = setTimeout(() => {
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const fetchQueries = async () => {
|
const fetchQueries = async () => {
|
||||||
try {
|
try {
|
||||||
if (reportOption === '1') {
|
if (reportOption === '1') {
|
||||||
|
|
||||||
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues })
|
// const { data } = await api.get("/reports/", { params: { userId: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
|
||||||
|
|
||||||
let ticketsQueue = data.tickets
|
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, userQueues: userA.queues})
|
||||||
let userQueues = userA.queues
|
|
||||||
let filterQueuesTickets = []
|
let ticketsQueue = data.tickets;
|
||||||
|
let userQueues = userA.queues;
|
||||||
|
let filterQueuesTickets = [];
|
||||||
if(userQueues.length > 1){
|
if(userQueues.length > 1){
|
||||||
filterQueuesTickets = ticketsQueue.filter(ticket => userQueues.some(queue => queue?.name === ticket?.queue?.name))
|
filterQueuesTickets = ticketsQueue.filter(ticket => userQueues.some(queue => queue?.name === ticket?.queue?.name));
|
||||||
}else if(userQueues.length > 0) {
|
}else if(userQueues.length > 0) {
|
||||||
filterQueuesTickets = ticketsQueue.filter(ticket => ticket?.queue?.name === userQueues[0]?.name)
|
filterQueuesTickets = ticketsQueue.filter(ticket => ticket?.queue?.name === userQueues[0]?.name);
|
||||||
}
|
}
|
||||||
data.tickets = filterQueuesTickets
|
data.tickets = filterQueuesTickets;
|
||||||
const tickets = data.tickets.map(ticket => ({
|
dispatchQ({ type: "LOAD_QUERY", payload: data.tickets })
|
||||||
...ticket,
|
|
||||||
messagesToFilter: ticket.messages.map(message => message.body).join(' '),
|
|
||||||
}))
|
|
||||||
dispatchQ({ type: "LOAD_QUERY", payload: tickets })
|
|
||||||
console.log(tickets)
|
|
||||||
setHasMore(data.hasMore)
|
setHasMore(data.hasMore)
|
||||||
setTotalCountTickets(data.count)
|
setTotalCountTickets(data.count)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
setQueues(data.queues)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -394,20 +359,6 @@ const Report = () => {
|
||||||
//setLoading(false);
|
//setLoading(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (reportOption === '3') {
|
|
||||||
const dataQuery = await api.get("/reports/services/numbers", { params: { startDate, endDate }, })
|
|
||||||
|
|
||||||
dispatchQ({ type: "RESET" })
|
|
||||||
dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService })
|
|
||||||
}
|
|
||||||
else if (reportOption === '4') {
|
|
||||||
const dataQuery = await api.get("/reports/services/queues", { params: { startDate, endDate }, })
|
|
||||||
|
|
||||||
console.log(' dataQuery?.data?.reportService: ', dataQuery?.data?.reportService)
|
|
||||||
|
|
||||||
dispatchQ({ type: "RESET" })
|
|
||||||
dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService })
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
@ -419,13 +370,9 @@ const Report = () => {
|
||||||
}, 500)
|
}, 500)
|
||||||
return () => clearTimeout(delayDebounceFn)
|
return () => clearTimeout(delayDebounceFn)
|
||||||
|
|
||||||
}, [userId, queueId, checked, startDate, endDate, reportOption, pageNumberTickets, totalCountTickets, selectedValue])
|
}, [userId, startDate, endDate, reportOption, pageNumberTickets, totalCountTickets])
|
||||||
|
|
||||||
|
|
||||||
const handleCheckBoxChange = (value) => {
|
|
||||||
setSelectedValue(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get from child 1
|
// Get from child 1
|
||||||
const datePicker1Value = (data) => {
|
const datePicker1Value = (data) => {
|
||||||
|
|
||||||
|
@ -440,35 +387,18 @@ const Report = () => {
|
||||||
|
|
||||||
// Get from child 3
|
// Get from child 3
|
||||||
const textFieldSelectUser = (data) => {
|
const textFieldSelectUser = (data) => {
|
||||||
setQueue(null)
|
|
||||||
setUser(data)
|
setUser(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const textFieldSelectQueue = (data) => {
|
|
||||||
setUser(0)
|
|
||||||
setQueue(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get from report option
|
// Get from report option
|
||||||
const reportValue = (data) => {
|
const reportValue = (data) => {
|
||||||
if (data === '2') {
|
|
||||||
setChecked(true)
|
|
||||||
}
|
|
||||||
setReport(data)
|
setReport(data)
|
||||||
}
|
|
||||||
|
|
||||||
// Get from report type option
|
|
||||||
const reportTypeValue = (data) => {
|
|
||||||
let type = '1'
|
|
||||||
if (data === '1') type = 'default'
|
|
||||||
if (data === '2') type = 'synthetic'
|
|
||||||
if (data === '3') type = 'analytic'
|
|
||||||
|
|
||||||
handleCSVMessages(type)
|
|
||||||
|
|
||||||
setReportType(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -545,7 +475,7 @@ const Report = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleCSVMessages = (type = 'default') => {
|
const handleCSVMessages = () => {
|
||||||
|
|
||||||
const fetchQueries = async () => {
|
const fetchQueries = async () => {
|
||||||
|
|
||||||
|
@ -560,12 +490,10 @@ const Report = () => {
|
||||||
identifier: 'csv'
|
identifier: 'csv'
|
||||||
},
|
},
|
||||||
query_params: {
|
query_params: {
|
||||||
queueId: queueId,
|
|
||||||
userId: userId,
|
userId: userId,
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate
|
endDate: endDate
|
||||||
},
|
}
|
||||||
query_type: type
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const onQueueStatus = querySavedOnQueue.data.queueStatus
|
const onQueueStatus = querySavedOnQueue.data.queueStatus
|
||||||
|
@ -639,7 +567,7 @@ const Report = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}, [reportOption, startDate, endDate, userId, queueId, checked, userA, selectedValue])
|
}, [reportOption, startDate, endDate, userId, userA])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -685,10 +613,7 @@ const Report = () => {
|
||||||
case 'empty':
|
case 'empty':
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{query && query.length > 0 &&
|
<Button
|
||||||
<ReportModalType currencies={reportTypeList} func={reportTypeValue} reportOption={reportType} />
|
|
||||||
}
|
|
||||||
{/* <Button
|
|
||||||
disabled={query && query.length > 0 ? false : true}
|
disabled={query && query.length > 0 ? false : true}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -697,8 +622,7 @@ const Report = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{"CSV ALL"}
|
{"CSV ALL"}
|
||||||
|
</Button>
|
||||||
</Button> */}
|
|
||||||
</>)
|
</>)
|
||||||
|
|
||||||
case 'pending' || 'processing':
|
case 'pending' || 'processing':
|
||||||
|
@ -733,10 +657,6 @@ const Report = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleChange = (event) => {
|
|
||||||
setChecked(event.target.checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Can
|
<Can
|
||||||
|
@ -745,72 +665,16 @@ const Report = () => {
|
||||||
yes={() => (
|
yes={() => (
|
||||||
|
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 2fr) repeat(2, 1fr)', gap: '8px' }}>
|
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', alignItems: 'center', }}>
|
<Item><SelectField func={textFieldSelectUser} emptyField={true} header={i18n.t("reports.user")} currencies={users.map((obj) => {
|
||||||
|
|
||||||
{(reportOption === '1' || reportOption === '2') &&
|
|
||||||
<>
|
|
||||||
{checked ?
|
|
||||||
<SelectField
|
|
||||||
func={textFieldSelectUser}
|
|
||||||
emptyField={true}
|
|
||||||
header={i18n.t("reports.user")}
|
|
||||||
currencies={users.map((obj) => {
|
|
||||||
return { 'value': obj.id, 'label': obj.name }
|
return { 'value': obj.id, 'label': obj.name }
|
||||||
})} /> :
|
})} /></Item>
|
||||||
<SelectField
|
|
||||||
func={textFieldSelectQueue}
|
|
||||||
emptyField={true}
|
|
||||||
header={'Filas'}
|
|
||||||
currencies={queues.map((obj) => {
|
|
||||||
return { 'value': obj.id, 'label': obj.name }
|
|
||||||
})} />
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
{reportOption === '1' &&
|
|
||||||
<div>
|
|
||||||
<label>
|
|
||||||
Filas
|
|
||||||
<Switch
|
|
||||||
checked={checked}
|
|
||||||
onChange={handleChange}
|
|
||||||
inputProps={{ 'aria-label': 'controlled' }}
|
|
||||||
/>
|
|
||||||
Usuarios
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
<Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateStart")} /></Item>
|
||||||
|
<Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateEnd")} /></Item>
|
||||||
|
|
||||||
|
<Item sx={{ display: 'grid', gridColumn: '4 / 5', }}>
|
||||||
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
||||||
<DatePicker1 func={datePicker1Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateStart")} />
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateEnd")} /></Box>
|
|
||||||
|
|
||||||
{reportOption === '1' ?
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', }}>
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox checked={selectedValue === 'created'} onChange={() => handleCheckBoxChange('created')} />}
|
|
||||||
label="Criado"
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox checked={selectedValue === 'updated'} onChange={() => handleCheckBoxChange('updated')} />}
|
|
||||||
label="Atualizado"
|
|
||||||
/>
|
|
||||||
</Box> :
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', }}>
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', gap: '8px', width: '100px', alignItems: 'center' }}>
|
|
||||||
|
|
||||||
<ReportModal currencies={reporList} func={reportValue} reportOption={reportOption} />
|
<ReportModal currencies={reporList} func={reportValue} reportOption={reportOption} />
|
||||||
|
|
||||||
|
@ -824,7 +688,7 @@ const Report = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
</Item>
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
@ -837,6 +701,7 @@ const Report = () => {
|
||||||
{reportOption === '1' &&
|
{reportOption === '1' &&
|
||||||
|
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<MTable data={query}
|
<MTable data={query}
|
||||||
columns={userA.profile !== 'supervisor' ?columnsData:columnsDataSuper}
|
columns={userA.profile !== 'supervisor' ?columnsData:columnsDataSuper}
|
||||||
hasChild={true}
|
hasChild={true}
|
||||||
|
@ -845,6 +710,7 @@ const Report = () => {
|
||||||
handleScroll={handleScroll}
|
handleScroll={handleScroll}
|
||||||
|
|
||||||
table_title={i18n.t("reports.listTitles.title1_1")} />
|
table_title={i18n.t("reports.listTitles.title1_1")} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -953,111 +819,6 @@ const Report = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
}
|
}
|
||||||
{reportOption === '3' &&
|
|
||||||
|
|
||||||
<MaterialTable
|
|
||||||
|
|
||||||
title={i18n.t("reports.listTitles.title4_1")}
|
|
||||||
columns={
|
|
||||||
[
|
|
||||||
{ 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' }
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
data={dataRows}
|
|
||||||
|
|
||||||
options={
|
|
||||||
{
|
|
||||||
search: true,
|
|
||||||
selection: false,
|
|
||||||
paging: false,
|
|
||||||
padding: 'dense',
|
|
||||||
sorting: true,
|
|
||||||
searchFieldStyle: {
|
|
||||||
width: 300,
|
|
||||||
},
|
|
||||||
|
|
||||||
pageSize: 20,
|
|
||||||
headerStyle: {
|
|
||||||
position: "sticky",
|
|
||||||
top: "0"
|
|
||||||
},
|
|
||||||
maxBodyHeight: "400px",
|
|
||||||
|
|
||||||
rowStyle: {
|
|
||||||
fontSize: 14,
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
}
|
|
||||||
{reportOption === '4' &&
|
|
||||||
|
|
||||||
<MaterialTable
|
|
||||||
|
|
||||||
title={i18n.t("reports.listTitles.title5_1")}
|
|
||||||
columns={
|
|
||||||
[
|
|
||||||
|
|
||||||
{ title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
|
|
||||||
{
|
|
||||||
title: 'Fila', field: 'queueName',
|
|
||||||
cellStyle: (evt, rowData) => {
|
|
||||||
return {
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
backgroundColor: rowData?.queueColor || 'inherit',
|
|
||||||
color: 'white'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
{ 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' }
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
data={dataRows}
|
|
||||||
|
|
||||||
options={
|
|
||||||
{
|
|
||||||
search: true,
|
|
||||||
selection: false,
|
|
||||||
paging: false,
|
|
||||||
padding: 'dense',
|
|
||||||
sorting: true,
|
|
||||||
searchFieldStyle: {
|
|
||||||
width: 300,
|
|
||||||
},
|
|
||||||
|
|
||||||
pageSize: 20,
|
|
||||||
headerStyle: {
|
|
||||||
position: "sticky",
|
|
||||||
top: "0"
|
|
||||||
},
|
|
||||||
maxBodyHeight: "400px",
|
|
||||||
|
|
||||||
rowStyle: {
|
|
||||||
fontSize: 14,
|
|
||||||
}
|
|
||||||
|
|
||||||
// rowStyle: rowData => ({
|
|
||||||
// backgroundColor: rowData.queueColor || 'inherit',
|
|
||||||
// fontSize: 14
|
|
||||||
// })
|
|
||||||
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,6 @@ const messages = {
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
message: "Message from",
|
message: "Message from",
|
||||||
messagePeding: "new ticket in queue",
|
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
open: { title: "Inbox" },
|
open: { title: "Inbox" },
|
||||||
|
|
|
@ -245,7 +245,6 @@ const messages = {
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
message: "Mensaje de",
|
message: "Mensaje de",
|
||||||
messagePeding: "Nuevo billete en cola",
|
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
open: { title: "Bandeja" },
|
open: { title: "Bandeja" },
|
||||||
|
|
|
@ -244,7 +244,6 @@ const messages = {
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
message: "Mensagem de",
|
message: "Mensagem de",
|
||||||
messagePeding: "Novo ticket na fila",
|
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
open: { title: "Inbox" },
|
open: { title: "Inbox" },
|
||||||
|
@ -313,9 +312,7 @@ const messages = {
|
||||||
title0_1: "Lembretes/Agendamentos",
|
title0_1: "Lembretes/Agendamentos",
|
||||||
title1_1: "Atendimento por atendentes",
|
title1_1: "Atendimento por atendentes",
|
||||||
title2_1: "Chat do atendimento pelo Whatsapp",
|
title2_1: "Chat do atendimento pelo Whatsapp",
|
||||||
title3_1: "Usuários online/offline",
|
title3_1: "Usuários online/offline"
|
||||||
title4_1: "Relatório de atendimento por números",
|
|
||||||
title5_1: "Relatório de atendimento por filas"
|
|
||||||
},
|
},
|
||||||
listColumns:{
|
listColumns:{
|
||||||
column0_1: 'Ações',
|
column0_1: 'Ações',
|
||||||
|
|
|
@ -2,155 +2,5 @@
|
||||||
"name": "whaticket",
|
"name": "whaticket",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {}
|
||||||
"": {
|
|
||||||
"dependencies": {
|
|
||||||
"natural": "^6.10.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/afinn-165": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/afinn-165/-/afinn-165-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-7+Wlx3BImrK0HiG6y3lU4xX7SpBPSSu8T9iguPMlaueRFxjbYwAQrp9lqZUuFikqKbd/en8lVREILvP2J80uJA==",
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/afinn-165-financialmarketnews": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/afinn-165-financialmarketnews/-/afinn-165-financialmarketnews-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==",
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/apparatus": {
|
|
||||||
"version": "0.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz",
|
|
||||||
"integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==",
|
|
||||||
"dependencies": {
|
|
||||||
"sylvester": ">= 0.0.8"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.2.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/natural": {
|
|
||||||
"version": "6.10.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/natural/-/natural-6.10.4.tgz",
|
|
||||||
"integrity": "sha512-PpqKTyRwNsYrTQ7/2El9X96pt7OCKynwGahl9oIBQEz9d71jxnHQ0KkuWg7xOC7ZvG0gRSkJ56q7Ygr5zfof2w==",
|
|
||||||
"dependencies": {
|
|
||||||
"afinn-165": "^1.0.2",
|
|
||||||
"afinn-165-financialmarketnews": "^3.0.0",
|
|
||||||
"apparatus": "^0.0.10",
|
|
||||||
"safe-stable-stringify": "^2.2.0",
|
|
||||||
"stopwords-iso": "^1.1.0",
|
|
||||||
"sylvester": "^0.0.12",
|
|
||||||
"underscore": "^1.9.1",
|
|
||||||
"wordnet-db": "^3.1.11"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/safe-stable-stringify": {
|
|
||||||
"version": "2.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
|
|
||||||
"integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/stopwords-iso": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/stopwords-iso/-/stopwords-iso-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sylvester": {
|
|
||||||
"version": "0.0.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/sylvester/-/sylvester-0.0.12.tgz",
|
|
||||||
"integrity": "sha512-SzRP5LQ6Ts2G5NyAa/jg16s8e3R7rfdFjizy1zeoecYWw+nGL+YA1xZvW/+iJmidBGSdLkuvdwTYEyJEb+EiUw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.2.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/underscore": {
|
|
||||||
"version": "1.13.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
|
|
||||||
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A=="
|
|
||||||
},
|
|
||||||
"node_modules/wordnet-db": {
|
|
||||||
"version": "3.1.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz",
|
|
||||||
"integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"afinn-165": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/afinn-165/-/afinn-165-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-7+Wlx3BImrK0HiG6y3lU4xX7SpBPSSu8T9iguPMlaueRFxjbYwAQrp9lqZUuFikqKbd/en8lVREILvP2J80uJA=="
|
|
||||||
},
|
|
||||||
"afinn-165-financialmarketnews": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/afinn-165-financialmarketnews/-/afinn-165-financialmarketnews-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw=="
|
|
||||||
},
|
|
||||||
"apparatus": {
|
|
||||||
"version": "0.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz",
|
|
||||||
"integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==",
|
|
||||||
"requires": {
|
|
||||||
"sylvester": ">= 0.0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"natural": {
|
|
||||||
"version": "6.10.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/natural/-/natural-6.10.4.tgz",
|
|
||||||
"integrity": "sha512-PpqKTyRwNsYrTQ7/2El9X96pt7OCKynwGahl9oIBQEz9d71jxnHQ0KkuWg7xOC7ZvG0gRSkJ56q7Ygr5zfof2w==",
|
|
||||||
"requires": {
|
|
||||||
"afinn-165": "^1.0.2",
|
|
||||||
"afinn-165-financialmarketnews": "^3.0.0",
|
|
||||||
"apparatus": "^0.0.10",
|
|
||||||
"safe-stable-stringify": "^2.2.0",
|
|
||||||
"stopwords-iso": "^1.1.0",
|
|
||||||
"sylvester": "^0.0.12",
|
|
||||||
"underscore": "^1.9.1",
|
|
||||||
"wordnet-db": "^3.1.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"safe-stable-stringify": {
|
|
||||||
"version": "2.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
|
|
||||||
"integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g=="
|
|
||||||
},
|
|
||||||
"stopwords-iso": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/stopwords-iso/-/stopwords-iso-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg=="
|
|
||||||
},
|
|
||||||
"sylvester": {
|
|
||||||
"version": "0.0.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/sylvester/-/sylvester-0.0.12.tgz",
|
|
||||||
"integrity": "sha512-SzRP5LQ6Ts2G5NyAa/jg16s8e3R7rfdFjizy1zeoecYWw+nGL+YA1xZvW/+iJmidBGSdLkuvdwTYEyJEb+EiUw=="
|
|
||||||
},
|
|
||||||
"underscore": {
|
|
||||||
"version": "1.13.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
|
|
||||||
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A=="
|
|
||||||
},
|
|
||||||
"wordnet-db": {
|
|
||||||
"version": "3.1.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz",
|
|
||||||
"integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"natural": "^6.10.4"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue