git commit -m "feat: Implement online/offline status handling and enhance ticket creation"
parent
605e4035b9
commit
52619bfd26
|
@ -8,18 +8,19 @@ import ShowContactService from "../services/ContactServices/ShowContactService";
|
||||||
import UpdateContactService from "../services/ContactServices/UpdateContactService";
|
import UpdateContactService from "../services/ContactServices/UpdateContactService";
|
||||||
import DeleteContactService from "../services/ContactServices/DeleteContactService";
|
import DeleteContactService from "../services/ContactServices/DeleteContactService";
|
||||||
|
|
||||||
import CheckContactNumber from "../services/WbotServices/CheckNumber"
|
import CheckContactNumber from "../services/WbotServices/CheckNumber";
|
||||||
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
||||||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
|
|
||||||
|
import {
|
||||||
import { searchContactCache, insertContactsCache, escapeCharCache } from '../helpers/ContactsCache'
|
searchContactCache,
|
||||||
|
insertContactsCache,
|
||||||
|
escapeCharCache
|
||||||
|
} from "../helpers/ContactsCache";
|
||||||
|
|
||||||
import { off } from "process";
|
import { off } from "process";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
|
@ -39,42 +40,46 @@ interface ContactData {
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
let { searchParam, pageNumber } = req.query as IndexQuery;
|
let { searchParam, pageNumber } = req.query as IndexQuery;
|
||||||
|
|
||||||
console.log('PAGE NUMBER CONTACT: ', pageNumber)
|
console.log("PAGE NUMBER CONTACT: ", pageNumber);
|
||||||
|
|
||||||
if (pageNumber === undefined || pageNumber.trim().length == 0) {
|
if (pageNumber === undefined || pageNumber.trim().length == 0) {
|
||||||
pageNumber = '1'
|
pageNumber = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST DEL
|
// TEST DEL
|
||||||
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const offset = 20 * (+pageNumber - 1);
|
const offset = 20 * (+pageNumber - 1);
|
||||||
|
|
||||||
searchParam = searchParam.replace(/\s+/g, ' ').trim().toLowerCase();
|
searchParam = searchParam.replace(/\s+/g, " ").trim().toLowerCase();
|
||||||
|
|
||||||
const data = await searchContactCache(searchParam, offset, 20)
|
const data = await searchContactCache(searchParam, offset, 20);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
console.log("QUERY CONTACTS FROM CACHE SEARCH PARAM: ", searchParam);
|
||||||
|
|
||||||
console.log('QUERY CONTACTS FROM CACHE SEARCH PARAM: ', searchParam)
|
console.log("QUERY CONTACTS FROM CACHE QUERY LENGTH: ", data.length);
|
||||||
|
|
||||||
console.log('QUERY CONTACTS FROM CACHE QUERY LENGTH: ', data.length)
|
return res.json({
|
||||||
|
contacts: data,
|
||||||
return res.json({ contacts: data, count: data.length, hasMore: data.length > 0 ? true : false });
|
count: data.length,
|
||||||
|
hasMore: data.length > 0 ? true : false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('There was an error on search ContactController.ts search cache: ', error)
|
console.log(
|
||||||
|
"There was an error on search ContactController.ts search cache: ",
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('QUERY CONTACTS FROM DATABASE SEARCH PARAM: ', searchParam)
|
console.log("QUERY CONTACTS FROM DATABASE SEARCH PARAM: ", searchParam);
|
||||||
|
|
||||||
const { contacts, count, hasMore } = await ListContactsService({ searchParam, pageNumber });
|
const { contacts, count, hasMore } = await ListContactsService({
|
||||||
|
searchParam,
|
||||||
|
pageNumber
|
||||||
|
});
|
||||||
|
|
||||||
return res.json({ contacts, count, hasMore });
|
return res.json({ contacts, count, hasMore });
|
||||||
};
|
};
|
||||||
|
@ -83,6 +88,8 @@ 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(" ", "");
|
||||||
|
|
||||||
|
throw new AppError("ERR_NO_ADD_CONTACT");
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string().required(),
|
name: Yup.string().required(),
|
||||||
number: Yup.string()
|
number: Yup.string()
|
||||||
|
@ -109,25 +116,24 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||||
|
|
||||||
console.log('xxxxxxxxxxx profilePicUrl: ', profilePicUrl)
|
console.log("xxxxxxxxxxx profilePicUrl: ", profilePicUrl);
|
||||||
|
|
||||||
|
|
||||||
// console.log(`newContact.name: ${newContact.name}\n
|
// console.log(`newContact.name: ${newContact.name}\n
|
||||||
// newContact.number: ${newContact.number}\n
|
// newContact.number: ${newContact.number}\n
|
||||||
// newContact.email: ${newContact.email}\n
|
// newContact.email: ${newContact.email}\n
|
||||||
// newContact.extraInfo: ${newContact.extraInfo}`)
|
// 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;
|
||||||
let extraInfo = newContact.extraInfo
|
let extraInfo = newContact.extraInfo;
|
||||||
|
|
||||||
const contact = await CreateContactService({
|
const contact = await CreateContactService({
|
||||||
name,
|
name,
|
||||||
number,
|
number,
|
||||||
email,
|
email,
|
||||||
profilePicUrl: profilePicUrl,
|
profilePicUrl: profilePicUrl,
|
||||||
extraInfo,
|
extraInfo
|
||||||
});
|
});
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -155,8 +161,10 @@ export const update = async (
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string(),
|
name: Yup.string(),
|
||||||
number: Yup.string()
|
number: Yup.string().matches(
|
||||||
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
/^\d+$/,
|
||||||
|
"Invalid number format. Only numbers is allowed."
|
||||||
|
)
|
||||||
// .matches(/^55\d+$/, "The number must start with 55.")
|
// .matches(/^55\d+$/, "The number must start with 55.")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -200,13 +208,14 @@ export const remove = async (
|
||||||
return res.status(200).json({ message: "Contact deleted" });
|
return res.status(200).json({ message: "Contact deleted" });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const contacsBulkInsertOnQueue = async (
|
||||||
|
req: Request,
|
||||||
export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Promise<Response> => {
|
res: Response
|
||||||
|
): Promise<Response> => {
|
||||||
// console.log('THE BODY: ', req.body)
|
// console.log('THE BODY: ', req.body)
|
||||||
|
|
||||||
const { adminId, identifier, queueStatus, file, contacts_inserted } = req.body
|
const { adminId, identifier, queueStatus, file, contacts_inserted } =
|
||||||
|
req.body;
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("contactsBulkInsertOnQueueStatus", {
|
io.emit("contactsBulkInsertOnQueueStatus", {
|
||||||
|
@ -219,24 +228,19 @@ export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Pro
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (process.env.CACHE && contacts_inserted) {
|
if (process.env.CACHE && contacts_inserted) {
|
||||||
|
await insertContactsCache(contacts_inserted);
|
||||||
await insertContactsCache(contacts_inserted)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).json({ message: 'ok' })
|
return res.status(200).json({ message: "ok" });
|
||||||
};
|
};
|
||||||
|
|
||||||
function addStartPhoneNumber(phoneNumber: string) {
|
function addStartPhoneNumber(phoneNumber: string) {
|
||||||
|
|
||||||
const regex = /^55/;
|
const regex = /^55/;
|
||||||
|
|
||||||
if (!regex.test(phoneNumber)) {
|
if (!regex.test(phoneNumber)) {
|
||||||
phoneNumber = '55' + phoneNumber;
|
phoneNumber = "55" + phoneNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
return phoneNumber
|
return phoneNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import AuthUserService from "../services/UserServices/AuthUserService";
|
||||||
import { SendRefreshToken } from "../helpers/SendRefreshToken";
|
import { SendRefreshToken } from "../helpers/SendRefreshToken";
|
||||||
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
|
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
|
||||||
|
|
||||||
|
import createOrUpdateOnlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password } = req.body;
|
const { email, password } = req.body;
|
||||||
|
|
||||||
|
@ -13,6 +15,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
password
|
password
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("serializedUser.id: ", serializedUser.id);
|
||||||
|
|
||||||
|
const userOnline = await createOrUpdateOnlineUserService({
|
||||||
|
userId: serializedUser.id,
|
||||||
|
status: "online"
|
||||||
|
});
|
||||||
|
|
||||||
SendRefreshToken(res, refreshToken);
|
SendRefreshToken(res, refreshToken);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
|
@ -47,5 +56,11 @@ export const remove = async (
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
res.clearCookie("jrt");
|
res.clearCookie("jrt");
|
||||||
|
|
||||||
|
const { userId } = req.params;
|
||||||
|
|
||||||
|
const userOnline = await createOrUpdateOnlineUserService({
|
||||||
|
userId,
|
||||||
|
status: "offline"
|
||||||
|
});
|
||||||
return res.send();
|
return res.send();
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,7 +108,7 @@ const monitor = async () => {
|
||||||
el.onlineTime = userOnline.onlineTime
|
el.onlineTime = userOnline.onlineTime
|
||||||
el.updatedAt = userOnline.updatedAt,
|
el.updatedAt = userOnline.updatedAt,
|
||||||
|
|
||||||
console.log(' * CREATED OR UPDATED USER TO ONLINE: ', userOnline.userId)
|
console.log('* CREATED OR UPDATED USER TO ONLINE: ', userOnline.userId)
|
||||||
|
|
||||||
lstOnline.push({ 'id': el.id, 'status': 'online' })
|
lstOnline.push({ 'id': el.id, 'status': 'online' })
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,12 +47,6 @@ export const initIO = (httpServer: Server): SocketIO => {
|
||||||
io.on("connection", socket => {
|
io.on("connection", socket => {
|
||||||
logger.info("Client Connected");
|
logger.info("Client Connected");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
socket.on("joinWhatsSession", (whatsappId: string) => {
|
socket.on("joinWhatsSession", (whatsappId: string) => {
|
||||||
logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`);
|
logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`);
|
||||||
socket.join(`session_${whatsappId}`);
|
socket.join(`session_${whatsappId}`);
|
||||||
|
@ -82,15 +76,6 @@ export const initIO = (httpServer: Server): SocketIO => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
socket.on("online", (userId: any) => {
|
socket.on("online", (userId: any) => {
|
||||||
|
|
||||||
// console.log('userId: ', userId)
|
// console.log('userId: ', userId)
|
||||||
|
@ -179,6 +164,8 @@ export const initIO = (httpServer: Server): SocketIO => {
|
||||||
|
|
||||||
e.try += 1
|
e.try += 1
|
||||||
|
|
||||||
|
console.log("try.......: ", e.try);
|
||||||
|
|
||||||
if (e.try > 1) {
|
if (e.try > 1) {
|
||||||
e.status = 'waiting...'
|
e.status = 'waiting...'
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@ authRoutes.post("/login", SessionController.store);
|
||||||
|
|
||||||
authRoutes.post("/refresh_token", SessionController.update);
|
authRoutes.post("/refresh_token", SessionController.update);
|
||||||
|
|
||||||
authRoutes.delete("/logout", isAuth, SessionController.remove);
|
authRoutes.delete("/logout/:userId", isAuth, SessionController.remove);
|
||||||
|
|
||||||
export default authRoutes;
|
export default authRoutes;
|
||||||
|
|
|
@ -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,29 +63,29 @@ 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: "",
|
||||||
};
|
}
|
||||||
|
|
||||||
const [contact, setContact] = useState(initialState);
|
const [contact, setContact] = useState(initialState)
|
||||||
const [phone, setPhone] = useState('')
|
const [phone, setPhone] = useState('')
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
isMounted.current = false;
|
isMounted.current = false
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// console.log('1 Contact: ', contact)
|
// console.log('1 Contact: ', contact)
|
||||||
|
@ -103,64 +103,66 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
const fetchContact = async () => {
|
const fetchContact = async () => {
|
||||||
if (initialValues) {
|
if (initialValues) {
|
||||||
|
|
||||||
|
if (initialValues?.number)
|
||||||
|
setPhone(initialValues.number)
|
||||||
|
|
||||||
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) {
|
||||||
|
|
||||||
setPhone(data.number)
|
setPhone(data.number)
|
||||||
|
|
||||||
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);
|
console.log('INITIAL STATE: ', initialState)
|
||||||
};
|
setContact(initialState)
|
||||||
|
}
|
||||||
|
|
||||||
const handleSaveContact = async values => {
|
const handleSaveContact = async values => {
|
||||||
|
|
||||||
values = { ...values, number: phone };
|
values = { ...values, number: phone }
|
||||||
|
|
||||||
console.log('submit values', 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)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
|
|
||||||
const regex = /^[0-9\b]+$/; // Regular expression to match only numbers
|
const regex = /^[0-9\b]+$/ // Regular expression to match only numbers
|
||||||
|
|
||||||
setPhone(event.target.value);
|
setPhone(event.target.value)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
||||||
|
@ -174,9 +176,9 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
|
|
||||||
setPhone(newValue)
|
setPhone(newValue)
|
||||||
|
|
||||||
}, 100);
|
}, 100)
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
@ -192,12 +194,12 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
validationSchema={ContactSchema}
|
validationSchema={ContactSchema}
|
||||||
onSubmit={(values, actions) => {
|
onSubmit={(values, actions) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleSaveContact(values);
|
handleSaveContact(values)
|
||||||
actions.setSubmitting(false);
|
actions.setSubmitting(false)
|
||||||
}, 400);
|
}, 400)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values, errors, touched, isSubmitting }) => (
|
{({ values, errors, touched, isSubmitting, resetForm }) => (
|
||||||
<Form>
|
<Form>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Typography variant="subtitle1" gutterBottom>
|
<Typography variant="subtitle1" gutterBottom>
|
||||||
|
@ -298,7 +300,9 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleClose}
|
onClick={()=>{
|
||||||
|
handleClose()
|
||||||
|
}}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -328,7 +332,7 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
</Formik>
|
</Formik>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ContactModal;
|
export default ContactModal
|
||||||
|
|
|
@ -1,256 +1,154 @@
|
||||||
import React, { useState, useEffect, useContext } from "react";
|
import React, { useState, useEffect, useContext } from "react"
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom"
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button"
|
||||||
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 Autocomplete, {
|
import Autocomplete, {
|
||||||
// createFilterOptions,
|
createFilterOptions,
|
||||||
// } from "@material-ui/lab/Autocomplete";
|
} from "@material-ui/lab/Autocomplete"
|
||||||
// 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 ButtonWithSpinner from "../ButtonWithSpinner";
|
import ButtonWithSpinner from "../ButtonWithSpinner"
|
||||||
import ContactModal from "../ContactModal";
|
import ContactModal from "../ContactModal"
|
||||||
import toastError from "../../errors/toastError";
|
import toastError from "../../errors/toastError"
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||||
|
|
||||||
// const filter = createFilterOptions({
|
const filter = createFilterOptions({
|
||||||
// trim: true,
|
trim: true,
|
||||||
// });
|
})
|
||||||
|
|
||||||
const NewTicketModal = ({ modalOpen, onClose }) => {
|
const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
const history = useHistory();
|
const history = useHistory()
|
||||||
|
|
||||||
// const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([])
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false)
|
||||||
const [searchParam, setSearchParam] = useState("");
|
const [searchParam, setSearchParam] = useState("")
|
||||||
const [selectedContact, setSelectedContact] = useState(null);
|
const [selectedContact, setSelectedContact] = useState(null)
|
||||||
// const [newContact, setNewContact] = useState({});
|
const [newContact, setNewContact] = useState({})
|
||||||
const [contactModalOpen, setContactModalOpen] = useState(false);
|
const [contactModalOpen, setContactModalOpen] = useState(false)
|
||||||
const { user } = useContext(AuthContext);
|
const { user } = useContext(AuthContext)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!modalOpen || searchParam.length < 3) {
|
||||||
|
setLoading(false)
|
||||||
const regex = /^[0-9\b]+$/; // Regular expression to match only numbers
|
return
|
||||||
if (searchParam && !searchParam.match(regex)) return
|
|
||||||
|
|
||||||
if (searchParam && searchParam.length > 9) {
|
|
||||||
setSelectedContact({})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setSelectedContact(null)
|
|
||||||
}
|
}
|
||||||
|
setLoading(true)
|
||||||
|
const delayDebounceFn = setTimeout(() => {
|
||||||
|
const fetchContacts = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await api.get("contacts", {
|
||||||
|
params: { searchParam },
|
||||||
|
})
|
||||||
|
setOptions(data.contacts)
|
||||||
|
setLoading(false)
|
||||||
|
} catch (err) {
|
||||||
|
setLoading(false)
|
||||||
|
toastError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!modalOpen || searchParam.length < 5) {
|
fetchContacts()
|
||||||
setLoading(false);
|
}, 500)
|
||||||
return;
|
return () => clearTimeout(delayDebounceFn)
|
||||||
}
|
}, [searchParam, modalOpen])
|
||||||
// setLoading(true);
|
|
||||||
// const delayDebounceFn = setTimeout(() => {
|
|
||||||
// const fetchContacts = async () => {
|
|
||||||
// try {
|
|
||||||
// const { data } = await api.get("contacts", {
|
|
||||||
// params: { searchParam },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // console.log('data.contacts: ', data.contacts)
|
|
||||||
|
|
||||||
// setOptions(data.contacts);
|
|
||||||
// setLoading(false);
|
|
||||||
// } catch (err) {
|
|
||||||
// setLoading(false);
|
|
||||||
// toastError(err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// };
|
|
||||||
|
|
||||||
// fetchContacts();
|
|
||||||
// }, 500);
|
|
||||||
|
|
||||||
// return () => clearTimeout(delayDebounceFn);
|
|
||||||
}, [searchParam, modalOpen]);
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose()
|
||||||
setSearchParam("");
|
setSearchParam("")
|
||||||
setSelectedContact(null);
|
setSelectedContact(null)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleSaveTicket = async contactId => {
|
const handleSaveTicket = async contactId => {
|
||||||
|
if (!contactId) return
|
||||||
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { data: data0 } = await api.get("/contacts/", { params: { searchParam, pageNumber: "1" }, });
|
|
||||||
|
|
||||||
if (data0 && data0.contacts.length > 0) {
|
|
||||||
console.log('-----> data: ', data0.contacts[0].id)
|
|
||||||
contactId = data0.contacts[0].id
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log('NO CONTACT whith this searchParam: ', searchParam)
|
|
||||||
|
|
||||||
const values = {
|
|
||||||
name: searchParam,
|
|
||||||
number: searchParam,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data: data1 } = await api.post("/contacts", values);
|
|
||||||
|
|
||||||
console.log('data1: ', data1)
|
|
||||||
|
|
||||||
contactId = data1.id
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data: ticket } = await api.post("/tickets", {
|
const { data: ticket } = await api.post("/tickets", {
|
||||||
contactId: contactId,
|
contactId: contactId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
status: "open",
|
status: "open",
|
||||||
});
|
})
|
||||||
|
history.push(`/tickets/${ticket.id}`)
|
||||||
window.location.reload();
|
|
||||||
history.push(`/tickets/${ticket.id}`);
|
|
||||||
window.location.reload();
|
|
||||||
|
|
||||||
setLoading(false);
|
|
||||||
handleClose();
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setLoading(false);
|
toastError(err)
|
||||||
toastError(err);
|
|
||||||
}
|
}
|
||||||
|
setLoading(false)
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
// if (!contactId) return;
|
|
||||||
// setLoading(true);
|
|
||||||
// try {
|
|
||||||
// const { data: ticket } = await api.post("/tickets", {
|
|
||||||
// contactId: contactId,
|
|
||||||
// userId: user.id,
|
|
||||||
// status: "open",
|
|
||||||
// });
|
|
||||||
|
|
||||||
// window.location.reload();
|
|
||||||
// history.push(`/tickets/${ticket.id}`);
|
|
||||||
// window.location.reload();
|
|
||||||
|
|
||||||
// } catch (err) {
|
|
||||||
// toastError(err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleChange = (number) => {
|
|
||||||
|
|
||||||
const regex = /^[0-9\b]+$/; // Regular expression to match only numbers
|
|
||||||
|
|
||||||
setSearchParam(number)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
|
|
||||||
let newValue = ''
|
|
||||||
|
|
||||||
for (const char of number) {
|
|
||||||
|
|
||||||
// console.log('char: ', char)
|
|
||||||
|
|
||||||
if (char.match(regex)) {
|
|
||||||
newValue += char
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('newValue: ', newValue)
|
|
||||||
|
|
||||||
setSearchParam(newValue)
|
|
||||||
|
|
||||||
}, 30);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// const handleSelectOption = (e, newValue) => {
|
// const handleSelectOption = (e, newValue) => {
|
||||||
|
|
||||||
|
|
||||||
// if (newValue?.number) {
|
// if (newValue?.number) {
|
||||||
|
// setSelectedContact(newValue)
|
||||||
// console.log('newValue: ', newValue)
|
|
||||||
|
|
||||||
// setSelectedContact(newValue);
|
|
||||||
|
|
||||||
// } else if (newValue?.name) {
|
// } else if (newValue?.name) {
|
||||||
|
// setNewContact({ name: newValue.name })
|
||||||
// // console.log('newValue?.name: ', newValue?.name)
|
// setContactModalOpen(true)
|
||||||
|
|
||||||
// const regex = /^[0-9\b]+$/; // Regular expression to match only numbers
|
|
||||||
|
|
||||||
// if (newValue.name.match(regex)) {
|
|
||||||
|
|
||||||
// console.log('==========> newValue.name', newValue.name)
|
|
||||||
// setNewContact({ name: newValue.name, number: newValue.name });
|
|
||||||
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
|
|
||||||
// setNewContact({ name: newValue.name });
|
|
||||||
// setContactModalOpen(true);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// }
|
// }
|
||||||
// };
|
// }
|
||||||
|
|
||||||
|
const handleSelectOption = (e, newValue) => {
|
||||||
|
if (newValue?.number) {
|
||||||
|
setSelectedContact(newValue)
|
||||||
|
} else if (newValue?.name) {
|
||||||
|
|
||||||
|
if (/^-?\d+(\.\d+)?$/.test(newValue?.name)){
|
||||||
|
setNewContact({ number: newValue.name })
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setNewContact({ name: newValue.name })
|
||||||
|
}
|
||||||
|
|
||||||
|
setContactModalOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleCloseContactModal = () => {
|
const handleCloseContactModal = () => {
|
||||||
setContactModalOpen(false);
|
setContactModalOpen(false)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleAddNewContactTicket = contact => {
|
const handleAddNewContactTicket = contact => {
|
||||||
handleSaveTicket(contact.id);
|
handleSaveTicket(contact.id)
|
||||||
};
|
}
|
||||||
|
|
||||||
// const createAddContactOption = (filterOptions, params) => {
|
const createAddContactOption = (filterOptions, params) => {
|
||||||
// const filtered = filter(filterOptions, params);
|
const filtered = filter(filterOptions, params)
|
||||||
|
|
||||||
// if (params.inputValue !== "" && !loading && searchParam.length >= 3) {
|
if (params.inputValue !== "" && !loading && searchParam.length >= 3) {
|
||||||
// filtered.push({
|
filtered.push({
|
||||||
// name: `${params.inputValue}`,
|
name: `${params.inputValue}`,
|
||||||
// });
|
})
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return filtered;
|
return filtered
|
||||||
// };
|
}
|
||||||
|
|
||||||
// const renderOption = option => {
|
const renderOption = option => {
|
||||||
// if (option.number) {
|
if (option.number) {
|
||||||
// return `${option.name} - ${option.number}`;
|
return `${option.name} - ${option.number}`
|
||||||
// } else {
|
} else {
|
||||||
// return `${i18n.t("newTicketModal.add")} ${option.name}`;
|
return `${i18n.t("newTicketModal.add")} ${option.name}`
|
||||||
// }
|
}
|
||||||
// };
|
}
|
||||||
|
|
||||||
// const renderOptionLabel = option => {
|
const renderOptionLabel = option => {
|
||||||
// if (option.number) {
|
if (option.number) {
|
||||||
// return `${option.name} - ${option.number}`;
|
return `${option.name} - ${option.number}`
|
||||||
// } else {
|
} else {
|
||||||
// return `${option.name}`;
|
return `${option.name}`
|
||||||
// }
|
}
|
||||||
// };
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ContactModal
|
<ContactModal
|
||||||
open={contactModalOpen}
|
open={contactModalOpen}
|
||||||
// initialValues={newContact}
|
initialValues={newContact}
|
||||||
onClose={handleCloseContactModal}
|
onClose={handleCloseContactModal}
|
||||||
onSave={handleAddNewContactTicket}
|
onSave={handleAddNewContactTicket}
|
||||||
></ContactModal>
|
></ContactModal>
|
||||||
|
@ -258,29 +156,7 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
<DialogTitle id="form-dialog-title">
|
<DialogTitle id="form-dialog-title">
|
||||||
{i18n.t("newTicketModal.title")}
|
{i18n.t("newTicketModal.title")}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
|
|
||||||
<TextField
|
|
||||||
label={i18n.t("newTicketModal.fieldLabel")}
|
|
||||||
variant="outlined"
|
|
||||||
autoFocus
|
|
||||||
|
|
||||||
value={searchParam}
|
|
||||||
onChange={e => handleChange(e.target.value)}
|
|
||||||
|
|
||||||
// onChange={e => setSearchParam(e.target.value)}
|
|
||||||
onKeyPress={e => {
|
|
||||||
if (loading || !selectedContact) return;
|
|
||||||
else if (e.key === "Enter") {
|
|
||||||
handleSaveTicket(selectedContact.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
|
|
||||||
{/* <DialogContent dividers>
|
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
options={options}
|
options={options}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
@ -301,9 +177,9 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
autoFocus
|
autoFocus
|
||||||
onChange={e => setSearchParam(e.target.value)}
|
onChange={e => setSearchParam(e.target.value)}
|
||||||
onKeyPress={e => {
|
onKeyPress={e => {
|
||||||
if (loading || !selectedContact) return;
|
if (loading || !selectedContact) return
|
||||||
else if (e.key === "Enter") {
|
else if (e.key === "Enter") {
|
||||||
handleSaveTicket(selectedContact.id);
|
handleSaveTicket(selectedContact.id)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
|
@ -320,7 +196,7 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</DialogContent> */}
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
|
@ -343,7 +219,7 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default NewTicketModal;
|
export default NewTicketModal
|
||||||
|
|
|
@ -105,8 +105,10 @@ const useAuth = () => {
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
|
console.log('USER: ', user)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.delete("/auth/logout");
|
await api.delete(`/auth/logout/${user.id}`);
|
||||||
setIsAuth(false);
|
setIsAuth(false);
|
||||||
setUser({});
|
setUser({});
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
|
|
|
@ -280,7 +280,7 @@ const messages = {
|
||||||
},
|
},
|
||||||
newTicketModal: {
|
newTicketModal: {
|
||||||
title: "Criar Ticket",
|
title: "Criar Ticket",
|
||||||
fieldLabel: "Digite o numero para criar um ticket",
|
fieldLabel: "Digite o numero/nome para criar um ticket",
|
||||||
add: "Adicionar",
|
add: "Adicionar",
|
||||||
buttons: {
|
buttons: {
|
||||||
ok: "Salvar",
|
ok: "Salvar",
|
||||||
|
@ -491,6 +491,7 @@ const messages = {
|
||||||
"A criação do usuário foi desabilitada pelo administrador.",
|
"A criação do usuário foi desabilitada pelo administrador.",
|
||||||
ERR_NO_PERMISSION: "Você não tem permissão para acessar este recurso.",
|
ERR_NO_PERMISSION: "Você não tem permissão para acessar este recurso.",
|
||||||
ERR_DUPLICATED_CONTACT: "Já existe um contato com este número.",
|
ERR_DUPLICATED_CONTACT: "Já existe um contato com este número.",
|
||||||
|
ERR_NO_ADD_CONTACT: "Não é permitido adicionar um novo contado na agenda.",
|
||||||
ERR_NO_SETTING_FOUND: "Nenhuma configuração encontrada com este ID.",
|
ERR_NO_SETTING_FOUND: "Nenhuma configuração encontrada com este ID.",
|
||||||
ERR_NO_CONTACT_FOUND: "Nenhum contato encontrado com este ID.",
|
ERR_NO_CONTACT_FOUND: "Nenhum contato encontrado com este ID.",
|
||||||
ERR_NO_TICKET_FOUND: "Nenhum tíquete encontrado com este ID.",
|
ERR_NO_TICKET_FOUND: "Nenhum tíquete encontrado com este ID.",
|
||||||
|
|
Loading…
Reference in New Issue