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;
|
||||
endDate: string;
|
||||
pageNumber: string;
|
||||
userQueues: [];
|
||||
};
|
||||
|
||||
type ReportOnQueue = {
|
||||
|
@ -52,12 +53,11 @@ export const reportUserByDateStartDateEnd = async (req: Request, res: Response):
|
|||
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);
|
||||
|
||||
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 });
|
||||
|
|
|
@ -134,7 +134,7 @@ export const all = 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 (
|
||||
req.url === "/signup" &&
|
||||
|
@ -149,6 +149,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
email,
|
||||
password,
|
||||
name,
|
||||
positionCompany,
|
||||
profile,
|
||||
queueIds
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ import { convertBytes } from "./ConvertBytes";
|
|||
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
||||
import SchedulingNotify from "../models/SchedulingNotify";
|
||||
import Ticket from "../models/Ticket";
|
||||
import User from "../models/User";
|
||||
import { Sequelize, Op } from "sequelize";
|
||||
|
||||
|
||||
|
@ -65,12 +66,21 @@ const monitor = async () => {
|
|||
if (_ticket) continue
|
||||
|
||||
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 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) {
|
||||
console.log(`exec error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`exec stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
// if (error) {
|
||||
// console.log(`exec error: ${error.message}`);
|
||||
// return;
|
||||
// }
|
||||
// if (stderr) {
|
||||
// console.log(`exec stderr: ${stderr}`);
|
||||
// return;
|
||||
// }
|
||||
|
||||
stdout = stdout.split(/\r?\n/)
|
||||
stdout = stdout[1].trim().split(/\s+/)
|
||||
// stdout = stdout.split(/\r?\n/)
|
||||
// stdout = stdout[1].trim().split(/\s+/)
|
||||
|
||||
// DISK SPACE MONITORING
|
||||
const io = getIO();
|
||||
io.emit("diskSpaceMonit", {
|
||||
action: "update",
|
||||
diskSpace: {
|
||||
size: stdout[1],
|
||||
used: stdout[2],
|
||||
available: stdout[3],
|
||||
use: stdout[4]
|
||||
}
|
||||
});
|
||||
// // DISK SPACE MONITORING
|
||||
// const io = getIO();
|
||||
// io.emit("diskSpaceMonit", {
|
||||
// action: "update",
|
||||
// diskSpace: {
|
||||
// size: stdout[1],
|
||||
// used: stdout[2],
|
||||
// available: stdout[3],
|
||||
// use: stdout[4]
|
||||
// }
|
||||
// });
|
||||
|
||||
});
|
||||
// });
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import User from "../models/User";
|
|||
interface SerializedUser {
|
||||
id: number;
|
||||
name: string;
|
||||
positionCompany: string;
|
||||
email: string;
|
||||
profile: string;
|
||||
queues: Queue[];
|
||||
|
@ -13,6 +14,7 @@ export const SerializeUser = (user: User): SerializedUser => {
|
|||
return {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
positionCompany: user.positionCompany,
|
||||
email: user.email,
|
||||
profile: user.profile,
|
||||
queues: user.queues
|
||||
|
|
|
@ -42,6 +42,9 @@ class User extends Model<User> {
|
|||
@Column
|
||||
tokenVersion: number;
|
||||
|
||||
@Column
|
||||
positionCompany: string;
|
||||
|
||||
@Default("admin")
|
||||
@Column
|
||||
profile: string;
|
||||
|
@ -51,7 +54,6 @@ class User extends Model<User> {
|
|||
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
|
||||
@HasMany(() => Ticket)
|
||||
tickets: Ticket[];
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import Queue from "../../models/Queue";
|
|||
interface SerializedUser {
|
||||
id: number;
|
||||
name: string;
|
||||
positionCompany: string;
|
||||
email: string;
|
||||
profile: string;
|
||||
queues: Queue[];
|
||||
|
|
|
@ -8,6 +8,7 @@ interface Request {
|
|||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
positionCompany?: string;
|
||||
queueIds?: number[];
|
||||
profile?: string;
|
||||
}
|
||||
|
@ -15,6 +16,7 @@ interface Request {
|
|||
interface Response {
|
||||
email: string;
|
||||
name: string;
|
||||
positionCompany: string;
|
||||
id: number;
|
||||
profile: string;
|
||||
}
|
||||
|
@ -23,6 +25,7 @@ const CreateUserService = async ({
|
|||
email,
|
||||
password,
|
||||
name,
|
||||
positionCompany,
|
||||
queueIds = [],
|
||||
profile = "master"
|
||||
}: Request): Promise<Response> => {
|
||||
|
@ -70,6 +73,7 @@ const CreateUserService = async ({
|
|||
email,
|
||||
password,
|
||||
name,
|
||||
positionCompany,
|
||||
profile
|
||||
},
|
||||
{ include: ["queues"] }
|
||||
|
|
|
@ -40,7 +40,7 @@ const ListUser = async ({ profile, userId, raw, userIds, profiles }: Request): P
|
|||
const users = await User.findAll({
|
||||
where: where_clause,
|
||||
raw,
|
||||
attributes: ["id", "name", "email"],
|
||||
attributes: ["id", "name", "email", "positionCompany"],
|
||||
|
||||
include: [
|
||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
||||
|
|
|
@ -63,7 +63,7 @@ const ListUsersService = async ({
|
|||
|
||||
const { count, rows: users } = await User.findAndCountAll({
|
||||
where: whereCondition,
|
||||
attributes: ["name", "id", "email", "profile", "createdAt"],
|
||||
attributes: ["name", "id", "email","positionCompany", "profile", "createdAt"],
|
||||
limit,
|
||||
offset,
|
||||
order: [["createdAt", "DESC"]],
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
REACT_APP_BACKEND_URL = http://localhost:8080/
|
|
@ -84,6 +84,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
position: "",
|
||||
profile: "user",
|
||||
};
|
||||
|
||||
|
@ -220,10 +221,9 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.multFieldLine}>
|
||||
<Field
|
||||
as={TextField}
|
||||
label={i18n.t("userModal.form.email")}
|
||||
label='Login'
|
||||
name="email"
|
||||
error={touched.email && Boolean(errors.email)}
|
||||
helperText={touched.email && errors.email}
|
||||
|
@ -231,6 +231,18 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||
margin="dense"
|
||||
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
|
||||
variant="outlined"
|
||||
className={classes.formControl}
|
||||
|
@ -262,6 +274,7 @@ const UserModal = ({ open, onClose, userId }) => {
|
|||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<Can
|
||||
role={loggedInUser.profile}
|
||||
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_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) {
|
||||
|
@ -245,7 +258,6 @@ let columnsData = [
|
|||
const Report = () => {
|
||||
|
||||
const { user: userA } = useContext(AuthContext)
|
||||
|
||||
//--------
|
||||
const [searchParam] = useState("")
|
||||
|
||||
|
@ -316,14 +328,21 @@ const Report = () => {
|
|||
setLoading(true)
|
||||
const fetchQueries = async () => {
|
||||
try {
|
||||
|
||||
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, 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 })
|
||||
|
||||
setHasMore(data.hasMore)
|
||||
|
@ -684,7 +703,7 @@ const Report = () => {
|
|||
<>
|
||||
|
||||
<MTable data={query}
|
||||
columns={columnsData}
|
||||
columns={userA.profile !== 'supervisor' ?columnsData:columnsDataSuper}
|
||||
hasChild={true}
|
||||
removeClickRow={false}
|
||||
|
||||
|
|
|
@ -267,7 +267,9 @@ const Users = () => {
|
|||
<TableCell align="center">
|
||||
{i18n.t("users.table.profile")}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
Cargo
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
{i18n.t("users.table.actions")}
|
||||
</TableCell>
|
||||
|
@ -281,6 +283,7 @@ const Users = () => {
|
|||
<TableCell align="center">{user.name}</TableCell>
|
||||
<TableCell align="center">{user.email}</TableCell>
|
||||
<TableCell align="center">{user.profile}</TableCell>
|
||||
<TableCell align="center">{user.positionCompany}</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
|
||||
|
|
Loading…
Reference in New Issue