chore: update reports tab for supervisors, add reminders functionality, and include user roles
Details: - Updated the reports tab to enhance functionality for supervisors. - Implemented a reminders feature for improved user experience. - Added user roles to enhance user management capabilities.pull/22/head
parent
0751374fb7
commit
6a5a51ff3f
|
@ -1,14 +0,0 @@
|
||||||
NODE_ENV=
|
|
||||||
BACKEND_URL=http://localhost
|
|
||||||
FRONTEND_URL=http://localhost:3000
|
|
||||||
PROXY_PORT=8080
|
|
||||||
PORT=8080
|
|
||||||
|
|
||||||
DB_DIALECT=
|
|
||||||
DB_HOST=
|
|
||||||
DB_USER=
|
|
||||||
DB_PASS=
|
|
||||||
DB_NAME=
|
|
||||||
|
|
||||||
JWT_SECRET=
|
|
||||||
JWT_REFRESH_SECRET=
|
|
|
@ -34,6 +34,7 @@ type IndexQuery = {
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
|
userQueues: [];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ReportOnQueue = {
|
type ReportOnQueue = {
|
||||||
|
@ -52,12 +53,11 @@ export const reportUserByDateStartDateEnd = async (req: Request, res: Response):
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userId, startDate, endDate, pageNumber } = req.query as IndexQuery
|
const { userId, startDate, endDate, pageNumber, userQueues } = req.query as IndexQuery
|
||||||
|
|
||||||
console.log("userId, startDate, endDate, pageNumber: ", userId, startDate, endDate, pageNumber);
|
console.log("userId, startDate, endDate, pageNumber: ", userId, startDate, endDate, pageNumber);
|
||||||
|
|
||||||
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
||||||
|
|
||||||
// console.log('kkkkkkkkkkkkkkkkkk tickets: ', JSON.stringify(tickets, null, 6))
|
// console.log('kkkkkkkkkkkkkkkkkk tickets: ', JSON.stringify(tickets, null, 6))
|
||||||
|
|
||||||
return res.status(200).json({ tickets, count, hasMore });
|
return res.status(200).json({ tickets, count, hasMore });
|
||||||
|
|
|
@ -134,7 +134,7 @@ export const all = async (req: Request, res: Response): Promise<Response> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password, name, profile, queueIds } = req.body;
|
const { email, password, name, profile, positionCompany, queueIds } = req.body;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
req.url === "/signup" &&
|
req.url === "/signup" &&
|
||||||
|
@ -149,6 +149,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
|
positionCompany,
|
||||||
profile,
|
profile,
|
||||||
queueIds
|
queueIds
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { convertBytes } from "./ConvertBytes";
|
||||||
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
||||||
import SchedulingNotify from "../models/SchedulingNotify";
|
import SchedulingNotify from "../models/SchedulingNotify";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
|
import User from "../models/User";
|
||||||
import { Sequelize, Op } from "sequelize";
|
import { Sequelize, Op } from "sequelize";
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,12 +66,21 @@ const monitor = async () => {
|
||||||
if (_ticket) continue
|
if (_ticket) continue
|
||||||
|
|
||||||
if (ticket.dataValues.status == 'closed') {
|
if (ticket.dataValues.status == 'closed') {
|
||||||
await ticket.update({ status: 'pending' })
|
await ticket.update({ status: 'open' })
|
||||||
|
}
|
||||||
|
const userId: number = ticket.getDataValue('userId');
|
||||||
|
let userN = '';
|
||||||
|
if(userId){
|
||||||
|
const useer = await User.findByPk(userId);
|
||||||
|
if(useer){
|
||||||
|
const userName: string = useer.getDataValue('name');
|
||||||
|
userN = `*${userName}:* \n`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise(f => setTimeout(f, 3000));
|
await new Promise(f => setTimeout(f, 3000));
|
||||||
await SendWhatsAppMessage({
|
await SendWhatsAppMessage({
|
||||||
body: schedulingNotifies[i].message, ticket
|
body: userN+schedulingNotifies[i].message, ticket
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,33 +90,33 @@ const monitor = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exec("df -h /", (error: any, stdout: any, stderr: any) => {
|
// exec("df -h /", (error: any, stdout: any, stderr: any) => {
|
||||||
|
|
||||||
if (error) {
|
// if (error) {
|
||||||
console.log(`exec error: ${error.message}`);
|
// console.log(`exec error: ${error.message}`);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
if (stderr) {
|
// if (stderr) {
|
||||||
console.log(`exec stderr: ${stderr}`);
|
// console.log(`exec stderr: ${stderr}`);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
stdout = stdout.split(/\r?\n/)
|
// stdout = stdout.split(/\r?\n/)
|
||||||
stdout = stdout[1].trim().split(/\s+/)
|
// stdout = stdout[1].trim().split(/\s+/)
|
||||||
|
|
||||||
// DISK SPACE MONITORING
|
// // DISK SPACE MONITORING
|
||||||
const io = getIO();
|
// const io = getIO();
|
||||||
io.emit("diskSpaceMonit", {
|
// io.emit("diskSpaceMonit", {
|
||||||
action: "update",
|
// action: "update",
|
||||||
diskSpace: {
|
// diskSpace: {
|
||||||
size: stdout[1],
|
// size: stdout[1],
|
||||||
used: stdout[2],
|
// used: stdout[2],
|
||||||
available: stdout[3],
|
// available: stdout[3],
|
||||||
use: stdout[4]
|
// use: stdout[4]
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import User from "../models/User";
|
||||||
interface SerializedUser {
|
interface SerializedUser {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
positionCompany: string;
|
||||||
email: string;
|
email: string;
|
||||||
profile: string;
|
profile: string;
|
||||||
queues: Queue[];
|
queues: Queue[];
|
||||||
|
@ -13,6 +14,7 @@ export const SerializeUser = (user: User): SerializedUser => {
|
||||||
return {
|
return {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
positionCompany: user.positionCompany,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
profile: user.profile,
|
profile: user.profile,
|
||||||
queues: user.queues
|
queues: user.queues
|
||||||
|
|
|
@ -42,6 +42,9 @@ class User extends Model<User> {
|
||||||
@Column
|
@Column
|
||||||
tokenVersion: number;
|
tokenVersion: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
positionCompany: string;
|
||||||
|
|
||||||
@Default("admin")
|
@Default("admin")
|
||||||
@Column
|
@Column
|
||||||
profile: string;
|
profile: string;
|
||||||
|
@ -51,7 +54,6 @@ class User extends Model<User> {
|
||||||
|
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
@HasMany(() => Ticket)
|
@HasMany(() => Ticket)
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Queue from "../../models/Queue";
|
||||||
interface SerializedUser {
|
interface SerializedUser {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
positionCompany: string;
|
||||||
email: string;
|
email: string;
|
||||||
profile: string;
|
profile: string;
|
||||||
queues: Queue[];
|
queues: Queue[];
|
||||||
|
|
|
@ -8,6 +8,7 @@ interface Request {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
positionCompany?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
profile?: string;
|
profile?: string;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +16,7 @@ interface Request {
|
||||||
interface Response {
|
interface Response {
|
||||||
email: string;
|
email: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
positionCompany: string;
|
||||||
id: number;
|
id: number;
|
||||||
profile: string;
|
profile: string;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +25,7 @@ const CreateUserService = async ({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
|
positionCompany,
|
||||||
queueIds = [],
|
queueIds = [],
|
||||||
profile = "master"
|
profile = "master"
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
|
@ -70,6 +73,7 @@ const CreateUserService = async ({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
|
positionCompany,
|
||||||
profile
|
profile
|
||||||
},
|
},
|
||||||
{ include: ["queues"] }
|
{ include: ["queues"] }
|
||||||
|
|
|
@ -40,7 +40,7 @@ const ListUser = async ({ profile, userId, raw, userIds, profiles }: Request): P
|
||||||
const users = await User.findAll({
|
const users = await User.findAll({
|
||||||
where: where_clause,
|
where: where_clause,
|
||||||
raw,
|
raw,
|
||||||
attributes: ["id", "name", "email"],
|
attributes: ["id", "name", "email", "positionCompany"],
|
||||||
|
|
||||||
include: [
|
include: [
|
||||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
||||||
|
|
|
@ -63,7 +63,7 @@ const ListUsersService = async ({
|
||||||
|
|
||||||
const { count, rows: users } = await User.findAndCountAll({
|
const { count, rows: users } = await User.findAndCountAll({
|
||||||
where: whereCondition,
|
where: whereCondition,
|
||||||
attributes: ["name", "id", "email", "profile", "createdAt"],
|
attributes: ["name", "id", "email","positionCompany", "profile", "createdAt"],
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
order: [["createdAt", "DESC"]],
|
order: [["createdAt", "DESC"]],
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
REACT_APP_BACKEND_URL = http://localhost:8080/
|
|
|
@ -84,6 +84,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
|
position: "",
|
||||||
profile: "user",
|
profile: "user",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -220,10 +221,9 @@ const UserModal = ({ open, onClose, userId }) => {
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.multFieldLine}>
|
|
||||||
<Field
|
<Field
|
||||||
as={TextField}
|
as={TextField}
|
||||||
label={i18n.t("userModal.form.email")}
|
label='Login'
|
||||||
name="email"
|
name="email"
|
||||||
error={touched.email && Boolean(errors.email)}
|
error={touched.email && Boolean(errors.email)}
|
||||||
helperText={touched.email && errors.email}
|
helperText={touched.email && errors.email}
|
||||||
|
@ -231,6 +231,18 @@ const UserModal = ({ open, onClose, userId }) => {
|
||||||
margin="dense"
|
margin="dense"
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
<div className={classes.multFieldLine}>
|
||||||
|
<Field
|
||||||
|
as={TextField}
|
||||||
|
label="Cargo"
|
||||||
|
autoFocus
|
||||||
|
name="positionCompany"
|
||||||
|
error={touched.name && Boolean(errors.name)}
|
||||||
|
helperText={touched.name && errors.name}
|
||||||
|
variant="outlined"
|
||||||
|
margin="dense"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
<FormControl
|
<FormControl
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
className={classes.formControl}
|
className={classes.formControl}
|
||||||
|
@ -262,6 +274,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Can
|
<Can
|
||||||
role={loggedInUser.profile}
|
role={loggedInUser.profile}
|
||||||
perform="user-modal:editQueues"
|
perform="user-modal:editQueues"
|
||||||
|
|
|
@ -221,6 +221,19 @@ let columnsData = [
|
||||||
{ 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' }]
|
||||||
|
|
||||||
|
let columnsDataSuper = [
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' },
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_2")}`, field: 'user.name' },
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'contact.name' },
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_5")}`, field: 'queue.name' },
|
||||||
|
|
||||||
|
{ title: 'Status', field: 'status' },
|
||||||
|
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
||||||
|
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// function convertAndFormatDate(dateString) {
|
// function convertAndFormatDate(dateString) {
|
||||||
|
@ -245,7 +258,6 @@ let columnsData = [
|
||||||
const Report = () => {
|
const Report = () => {
|
||||||
|
|
||||||
const { user: userA } = useContext(AuthContext)
|
const { user: userA } = useContext(AuthContext)
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
const [searchParam] = useState("")
|
const [searchParam] = useState("")
|
||||||
|
|
||||||
|
@ -316,14 +328,21 @@ const Report = () => {
|
||||||
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: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
|
// const { data } = await api.get("/reports/", { params: { userId: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
|
||||||
|
|
||||||
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, })
|
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, userQueues: userA.queues})
|
||||||
|
|
||||||
|
|
||||||
|
let ticketsQueue = data.tickets;
|
||||||
|
let userQueues = userA.queues;
|
||||||
|
let filterQueuesTickets = [];
|
||||||
|
if(userQueues.length > 1){
|
||||||
|
filterQueuesTickets = ticketsQueue.filter(ticket => userQueues.some(queue => queue.name === ticket.queue.name));
|
||||||
|
}else if(userQueues.length > 0) {
|
||||||
|
filterQueuesTickets = ticketsQueue.filter(ticket => ticket.queue.name === userQueues[0].name);
|
||||||
|
}
|
||||||
|
data.tickets = filterQueuesTickets;
|
||||||
dispatchQ({ type: "LOAD_QUERY", payload: data.tickets })
|
dispatchQ({ type: "LOAD_QUERY", payload: data.tickets })
|
||||||
|
|
||||||
setHasMore(data.hasMore)
|
setHasMore(data.hasMore)
|
||||||
|
@ -684,7 +703,7 @@ const Report = () => {
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<MTable data={query}
|
<MTable data={query}
|
||||||
columns={columnsData}
|
columns={userA.profile !== 'supervisor' ?columnsData:columnsDataSuper}
|
||||||
hasChild={true}
|
hasChild={true}
|
||||||
removeClickRow={false}
|
removeClickRow={false}
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,9 @@ const Users = () => {
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{i18n.t("users.table.profile")}
|
{i18n.t("users.table.profile")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
Cargo
|
||||||
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{i18n.t("users.table.actions")}
|
{i18n.t("users.table.actions")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -281,6 +283,7 @@ const Users = () => {
|
||||||
<TableCell align="center">{user.name}</TableCell>
|
<TableCell align="center">{user.name}</TableCell>
|
||||||
<TableCell align="center">{user.email}</TableCell>
|
<TableCell align="center">{user.email}</TableCell>
|
||||||
<TableCell align="center">{user.profile}</TableCell>
|
<TableCell align="center">{user.profile}</TableCell>
|
||||||
|
<TableCell align="center">{user.positionCompany}</TableCell>
|
||||||
|
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue