fix: Correct bug in editing official WhatsApp and implement solution to validate number using remote WhatsApp API
parent
6c5b89fd28
commit
943d121ab1
|
@ -126,21 +126,12 @@ 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;
|
||||||
|
|
|
@ -421,13 +421,14 @@ export const update = async (
|
||||||
return res.status(200).json({ message: invalidPhoneName });
|
return res.status(200).json({ message: invalidPhoneName });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData;
|
const { urlApi, isOfficial, phoneNumberId, number, wabaId } = whatsappData;
|
||||||
|
|
||||||
const invalid = checkWhatsAppData({
|
const invalid = checkWhatsAppData({
|
||||||
urlApi,
|
urlApi,
|
||||||
isOfficial,
|
isOfficial,
|
||||||
phoneNumberId,
|
phoneNumberId,
|
||||||
wabaId
|
wabaId,
|
||||||
|
number
|
||||||
});
|
});
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
|
|
|
@ -13,20 +13,19 @@ 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 }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!defaultWhatsapp) {
|
if (!defaultWhatsapp && !ignoreNoWhatsappFound) {
|
||||||
if (userId) {
|
if (userId) {
|
||||||
let whatsapps = await wbotByUserQueue({ userId, queueId });
|
let whatsapps = await wbotByUserQueue({ userId, queueId });
|
||||||
|
|
||||||
|
@ -56,17 +55,16 @@ const GetDefaultWhatsApp = async ({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultWhatsapp = await Whatsapp.findOne({
|
defaultWhatsapp = await Whatsapp.findOne({
|
||||||
where: { status: "CONNECTED" }
|
where: { status: "CONNECTED", isOfficial: false }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultWhatsapp) {
|
if (!defaultWhatsapp && !ignoreNoWhatsappFound) {
|
||||||
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;
|
||||||
|
|
|
@ -29,7 +29,8 @@ const FindOrCreateTicketServiceBot = async (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
const { queues, greetingMessage, phoneNumberId } =
|
||||||
|
await ShowWhatsAppService(whatsappId);
|
||||||
|
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
|
@ -102,12 +103,13 @@ const FindOrCreateTicketServiceBot = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket = await Ticket.create({
|
ticket = await Ticket.create({
|
||||||
contactId: groupContact ? groupContact.id : contact.id,
|
contactId: groupContact ? groupContact.id : contact.id,
|
||||||
status: status,
|
status: status,
|
||||||
userId: botInfo.userIdBot,
|
userId: botInfo.userIdBot,
|
||||||
isGroup: !!groupContact,
|
isGroup: !!groupContact,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
whatsappId
|
whatsappId,
|
||||||
|
phoneNumberId
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
||||||
|
|
|
@ -1,27 +1,54 @@
|
||||||
|
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 (number: string, ignoreThrow?:boolean): Promise<any> => {
|
const CheckIsValidContact = async (
|
||||||
|
number: string,
|
||||||
|
ignoreThrow?: boolean
|
||||||
|
): Promise<any> => {
|
||||||
|
const defaultWhatsapp = await GetDefaultWhatsApp({
|
||||||
|
ignoreNoWhatsappFound: true
|
||||||
|
});
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
let isValidNumber;
|
||||||
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
if (defaultWhatsapp) {
|
||||||
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
const isValidNumber = await endPointQuery(`${wbot_url}/api/validate`, { mobile: `${number}`, })
|
let { data } = await endPointQuery(`${wbot_url}/api/validate`, {
|
||||||
|
mobile: `${number}`
|
||||||
|
});
|
||||||
|
|
||||||
if(ignoreThrow) return isValidNumber?.data?.number;
|
if (data?.isValid) {
|
||||||
|
isValidNumber = data;
|
||||||
// console.log('isValidNumber.data.number: ', isValidNumber.data.number)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (!isValidNumber) {
|
||||||
|
|
||||||
// const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
|
const { data } = await axios.post(
|
||||||
|
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/validate`,
|
||||||
|
{ mobile: number },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!isValidNumber || isValidNumber && !isValidNumber.data.isValid) {
|
isValidNumber = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreThrow) return isValidNumber?.number;
|
||||||
|
|
||||||
|
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");
|
||||||
|
@ -29,10 +56,6 @@ const CheckIsValidContact = async (number: string, ignoreThrow?:boolean): Promis
|
||||||
|
|
||||||
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,23 +1,47 @@
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
let profilePicUrl;
|
||||||
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
if (defaultWhatsapp) {
|
||||||
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, })
|
const {data} = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, {
|
||||||
|
number: `${number}`
|
||||||
|
});
|
||||||
|
|
||||||
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data)
|
if (data?.data) {
|
||||||
|
profilePicUrl = data.data;
|
||||||
if (profilePicUrl && profilePicUrl.data.data) {
|
}
|
||||||
return profilePicUrl.data.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
try {
|
||||||
|
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;
|
||||||
|
|
|
@ -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()
|
||||||
|
@ -60,75 +60,77 @@ const ContactSchema = Yup.object().shape({
|
||||||
number: Yup.string().min(8, "Too Short!").max(50, "Too Long!"),
|
number: Yup.string().min(8, "Too Short!").max(50, "Too Long!"),
|
||||||
|
|
||||||
email: Yup.string().min(2, "Too Short!")
|
email: Yup.string().min(2, "Too Short!")
|
||||||
.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"))
|
||||||
|
setSaving(false)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
@ -143,10 +145,11 @@ 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 }) => (
|
||||||
|
@ -256,14 +259,14 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={isSubmitting}
|
disabled={isSaving}
|
||||||
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")}`}
|
||||||
{isSubmitting && (
|
{isSaving && (
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
size={24}
|
size={24}
|
||||||
className={classes.buttonProgress}
|
className={classes.buttonProgress}
|
||||||
|
@ -276,7 +279,7 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||||
</Formik>
|
</Formik>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ContactModal;
|
export default ContactModal
|
||||||
|
|
Loading…
Reference in New Issue