fix: Correct bug in editing official WhatsApp and implement solution to validate number using remote WhatsApp API

feat-scaling-ticket-remote-creation
adriano 2024-03-06 11:00:03 -03:00
parent 6c5b89fd28
commit 943d121ab1
8 changed files with 158 additions and 116 deletions

View File

@ -124,22 +124,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
newContact.number = addStartPhoneNumber(newContact.number);
const validNumber = await CheckIsValidContact(newContact.number);
// const validNumber: any = await CheckContactNumber(newContact.number)
const validNumber = await CheckIsValidContact(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}`)
const profilePicUrl = await GetProfilePicUrl(validNumber);
let name = newContact.name;
let number = validNumber;

View File

@ -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) {
@ -572,5 +573,5 @@ const checkWhatsAppData = ({
return { message: "Phone number is required!" };
} else if (!isOfficial && (!urlApi || urlApi.trim() == "")) {
return { message: "urlApi is required!" };
}
}
};

View File

@ -6,27 +6,26 @@ import UserQueue from "../models/UserQueue";
import { Op, where } from "sequelize";
import wbotByUserQueue from "../helpers/GetWbotByUserQueue";
import wbotByUserQueue from "../helpers/GetWbotByUserQueue";
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
}: Request): Promise<any> => {
// test del
queueId,
ignoreNoWhatsappFound = false
}: Request): Promise<any> => {
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;
//
return defaultWhatsapp;
};
export default GetDefaultWhatsApp;

View File

@ -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')

View File

@ -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 { data } = await axios.post(
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/validate`,
{ mobile: number },
{
headers: {
"Content-Type": "application/json"
}
}
);
// const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
isValidNumber = data;
}
if (ignoreThrow) return isValidNumber?.number;
if (!isValidNumber || isValidNumber && !isValidNumber.data.isValid) {
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;

View File

@ -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
});
let profilePicUrl;
const defaultWhatsapp = await GetDefaultWhatsApp({});
if (defaultWhatsapp) {
const wbot_url = await getWbot(defaultWhatsapp.id);
const wbot_url = await getWbot(defaultWhatsapp.id);
const {data} = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, {
number: `${number}`
});
let profilePicUrl = 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;
}
}
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
return null;
};
export default GetProfilePicUrl;

View File

@ -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 {
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

View File

@ -87,7 +87,7 @@ const WhatsAppModal = ({ open, onClose, whatsAppId, whatsAppOfficial }) => {
if (!whatsAppId) return
try {
const { data } = await api.get(`whatsapp/${whatsAppId}`)
const { data } = await api.get(`whatsapp/${whatsAppId}`)
setWhatsApp(data)
setIsOfficial(data?.isOfficial)