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: any = await CheckContactNumber(newContact.number)
|
||||
|
||||
if (!validNumber) {
|
||||
throw new AppError("ERR_WAPP_CHECK_CONTACT");
|
||||
}
|
||||
|
||||
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 number = validNumber;
|
||||
let email = newContact.email;
|
||||
|
|
|
@ -421,13 +421,14 @@ export const update = async (
|
|||
return res.status(200).json({ message: invalidPhoneName });
|
||||
}
|
||||
|
||||
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData;
|
||||
const { urlApi, isOfficial, phoneNumberId, number, wabaId } = whatsappData;
|
||||
|
||||
const invalid = checkWhatsAppData({
|
||||
urlApi,
|
||||
isOfficial,
|
||||
phoneNumberId,
|
||||
wabaId
|
||||
wabaId,
|
||||
number
|
||||
});
|
||||
|
||||
if (invalid) {
|
||||
|
|
|
@ -13,20 +13,19 @@ import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
|||
interface Request {
|
||||
userId?: string | number;
|
||||
queueId?: string | number;
|
||||
ignoreNoWhatsappFound?: boolean
|
||||
}
|
||||
|
||||
//const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
|
||||
|
||||
const GetDefaultWhatsApp = async ({
|
||||
userId,
|
||||
queueId
|
||||
queueId,
|
||||
ignoreNoWhatsappFound = false
|
||||
}: Request): Promise<any> => {
|
||||
// test del
|
||||
let defaultWhatsapp = await Whatsapp.findOne({
|
||||
where: { isDefault: true }
|
||||
});
|
||||
|
||||
if (!defaultWhatsapp) {
|
||||
if (!defaultWhatsapp && !ignoreNoWhatsappFound) {
|
||||
if (userId) {
|
||||
let whatsapps = await wbotByUserQueue({ userId, queueId });
|
||||
|
||||
|
@ -56,17 +55,16 @@ const GetDefaultWhatsApp = async ({
|
|||
}
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
return defaultWhatsapp;
|
||||
//
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -102,12 +103,13 @@ const FindOrCreateTicketServiceBot = async (
|
|||
}
|
||||
|
||||
ticket = await Ticket.create({
|
||||
contactId: groupContact ? groupContact.id : contact.id,
|
||||
status: status,
|
||||
userId: botInfo.userIdBot,
|
||||
isGroup: !!groupContact,
|
||||
unreadMessages,
|
||||
whatsappId
|
||||
contactId: groupContact ? groupContact.id : contact.id,
|
||||
status: status,
|
||||
userId: botInfo.userIdBot,
|
||||
isGroup: !!groupContact,
|
||||
unreadMessages,
|
||||
whatsappId,
|
||||
phoneNumberId
|
||||
});
|
||||
|
||||
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
||||
|
|
|
@ -1,27 +1,54 @@
|
|||
import axios from "axios";
|
||||
import AppError from "../../errors/AppError";
|
||||
import endPointQuery from "../../helpers/EndPointQuery";
|
||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||
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;
|
||||
|
||||
// console.log('isValidNumber.data.number: ', isValidNumber.data.number)
|
||||
if (data?.isValid) {
|
||||
isValidNumber = data;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if (isValidNumber && isValidNumber?.isValid) return isValidNumber.number;
|
||||
} catch (err: any) {
|
||||
if (err.message === "invalidNumber") {
|
||||
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");
|
||||
}
|
||||
|
||||
if (isValidNumber && isValidNumber.data.isValid)
|
||||
return isValidNumber.data.number
|
||||
|
||||
};
|
||||
|
||||
export default CheckIsValidContact;
|
||||
|
|
|
@ -1,23 +1,47 @@
|
|||
import axios from "axios";
|
||||
import endPointQuery from "../../helpers/EndPointQuery";
|
||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||
import { getWbot } from "../../libs/wbot";
|
||||
|
||||
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 (profilePicUrl && profilePicUrl.data.data) {
|
||||
return profilePicUrl.data.data;
|
||||
if (data?.data) {
|
||||
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;
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import React, { useState, useEffect, useRef } from "react";
|
||||
import React, { useState, useEffect, useRef } from "react"
|
||||
|
||||
import * as Yup from "yup";
|
||||
import { Formik, FieldArray, Form, Field } from "formik";
|
||||
import { toast } from "react-toastify";
|
||||
import * as Yup from "yup"
|
||||
import { Formik, FieldArray, Form, Field } from "formik"
|
||||
import { toast } from "react-toastify"
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { green } from "@material-ui/core/colors";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { green } from "@material-ui/core/colors"
|
||||
import Button from "@material-ui/core/Button"
|
||||
import TextField from "@material-ui/core/TextField"
|
||||
import Dialog from "@material-ui/core/Dialog"
|
||||
import DialogActions from "@material-ui/core/DialogActions"
|
||||
import DialogContent from "@material-ui/core/DialogContent"
|
||||
import DialogTitle from "@material-ui/core/DialogTitle"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import IconButton from "@material-ui/core/IconButton"
|
||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
|
||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
||||
|
||||
import { i18n } from "../../translate/i18n";
|
||||
import { i18n } from "../../translate/i18n"
|
||||
|
||||
import api from "../../services/api";
|
||||
import toastError from "../../errors/toastError";
|
||||
import api from "../../services/api"
|
||||
import toastError from "../../errors/toastError"
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
|
@ -50,7 +50,7 @@ const useStyles = makeStyles(theme => ({
|
|||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
}));
|
||||
}))
|
||||
|
||||
const ContactSchema = Yup.object().shape({
|
||||
name: Yup.string()
|
||||
|
@ -60,75 +60,77 @@ const ContactSchema = Yup.object().shape({
|
|||
number: Yup.string().min(8, "Too Short!").max(50, "Too Long!"),
|
||||
|
||||
email: Yup.string().min(2, "Too Short!")
|
||||
.max(50, "Too Long!"),
|
||||
.max(50, "Too Long!"),
|
||||
|
||||
// email: Yup.string().email("Invalid email"),
|
||||
});
|
||||
})
|
||||
|
||||
const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
||||
const classes = useStyles();
|
||||
const isMounted = useRef(true);
|
||||
const classes = useStyles()
|
||||
const isMounted = useRef(true)
|
||||
|
||||
const initialState = {
|
||||
name: "",
|
||||
number: "",
|
||||
email: "",
|
||||
useDialogflow: true,
|
||||
};
|
||||
}
|
||||
|
||||
const [contact, setContact] = useState(initialState);
|
||||
const [contact, setContact] = useState(initialState)
|
||||
const [isSaving, setSaving] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
isMounted.current = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const fetchContact = async () => {
|
||||
if (initialValues) {
|
||||
setContact(prevState => {
|
||||
return { ...prevState, ...initialValues };
|
||||
});
|
||||
return { ...prevState, ...initialValues }
|
||||
})
|
||||
}
|
||||
|
||||
if (!contactId) return;
|
||||
if (!contactId) return
|
||||
|
||||
try {
|
||||
const { data } = await api.get(`/contacts/${contactId}`);
|
||||
const { data } = await api.get(`/contacts/${contactId}`)
|
||||
if (isMounted.current) {
|
||||
setContact(data);
|
||||
setContact(data)
|
||||
}
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fetchContact();
|
||||
}, [contactId, open, initialValues]);
|
||||
fetchContact()
|
||||
}, [contactId, open, initialValues])
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
setContact(initialState);
|
||||
};
|
||||
onClose()
|
||||
setContact(initialState)
|
||||
}
|
||||
|
||||
const handleSaveContact = async values => {
|
||||
try {
|
||||
if (contactId) {
|
||||
await api.put(`/contacts/${contactId}`, values);
|
||||
handleClose();
|
||||
await api.put(`/contacts/${contactId}`, values)
|
||||
handleClose()
|
||||
} else {
|
||||
const { data } = await api.post("/contacts", values);
|
||||
const { data } = await api.post("/contacts", values)
|
||||
if (onSave) {
|
||||
onSave(data);
|
||||
onSave(data)
|
||||
}
|
||||
handleClose();
|
||||
handleClose()
|
||||
}
|
||||
toast.success(i18n.t("contactModal.success"));
|
||||
toast.success(i18n.t("contactModal.success"))
|
||||
setSaving(false)
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
toastError(err)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
|
@ -143,10 +145,11 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
|||
enableReinitialize={true}
|
||||
validationSchema={ContactSchema}
|
||||
onSubmit={(values, actions) => {
|
||||
setSaving(true)
|
||||
setTimeout(() => {
|
||||
handleSaveContact(values);
|
||||
actions.setSubmitting(false);
|
||||
}, 400);
|
||||
handleSaveContact(values)
|
||||
actions.setSubmitting(false)
|
||||
}, 400)
|
||||
}}
|
||||
>
|
||||
{({ values, errors, touched, isSubmitting }) => (
|
||||
|
@ -256,14 +259,14 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
|||
<Button
|
||||
type="submit"
|
||||
color="primary"
|
||||
disabled={isSubmitting}
|
||||
disabled={isSaving}
|
||||
variant="contained"
|
||||
className={classes.btnWrapper}
|
||||
>
|
||||
{contactId
|
||||
? `${i18n.t("contactModal.buttons.okEdit")}`
|
||||
: `${i18n.t("contactModal.buttons.okAdd")}`}
|
||||
{isSubmitting && (
|
||||
{isSaving && (
|
||||
<CircularProgress
|
||||
size={24}
|
||||
className={classes.buttonProgress}
|
||||
|
@ -276,7 +279,7 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
|
|||
</Formik>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default ContactModal;
|
||||
export default ContactModal
|
||||
|
|
Loading…
Reference in New Issue