Modulo campanha basico finalizado

pull/21/head
adriano 2023-08-14 06:48:39 -03:00
parent ff0d2c3630
commit 75eb24fe62
5 changed files with 334 additions and 332 deletions

View File

@ -8,18 +8,19 @@ import ShowContactService from "../services/ContactServices/ShowContactService";
import UpdateContactService from "../services/ContactServices/UpdateContactService";
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 GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import AppError from "../errors/AppError";
import { searchContactCache, insertContactsCache, escapeCharCache } from '../helpers/ContactsCache'
import {
searchContactCache,
insertContactsCache,
escapeCharCache
} from "../helpers/ContactsCache";
import { off } from "process";
type IndexQuery = {
searchParam: string;
pageNumber: string;
@ -39,42 +40,46 @@ interface ContactData {
export const index = async (req: Request, res: Response): Promise<Response> => {
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) {
pageNumber = '1'
pageNumber = "1";
}
// TEST DEL
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
try {
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) {
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, count: data.length, hasMore: data.length > 0 ? true : false });
return res.json({
contacts: data,
count: data.length,
hasMore: data.length > 0 ? true : false
});
}
} 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 });
};
@ -101,31 +106,30 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
// const validNumber: any = await CheckContactNumber(newContact.number)
if(!validNumber){
if (!validNumber) {
throw new AppError("ERR_WAPP_CHECK_CONTACT");
}
const profilePicUrl = await GetProfilePicUrl(validNumber);
console.log('xxxxxxxxxxx profilePicUrl: ',profilePicUrl)
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
let extraInfo = newContact.extraInfo
let name = newContact.name;
let number = validNumber;
let email = newContact.email;
let extraInfo = newContact.extraInfo;
const contact = await CreateContactService({
name,
number,
email,
profilePicUrl: profilePicUrl,
extraInfo,
extraInfo
});
const io = getIO();
@ -154,7 +158,7 @@ export const update = async (
const schema = Yup.object().shape({
name: Yup.string(),
number: Yup.string()
.matches(/^\d+$/,"Invalid number format. Only numbers is allowed.")
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
.matches(/^55\d+$/, "The number must start with 55.")
});
@ -196,13 +200,20 @@ export const remove = async (
return res.status(200).json({ message: "Contact deleted" });
};
export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Promise<Response> => {
export const contacsBulkInsertOnQueue = async (
req: Request,
res: Response
): Promise<Response> => {
// console.log('THE BODY: ', req.body)
const { adminId, identifier, queueStatus, file, contacts_inserted } = req.body
const {
adminId,
identifier,
queueStatus,
file,
contacts_inserted,
campaign
} = req.body;
const io = getIO();
io.emit("contactsBulkInsertOnQueueStatus", {
@ -211,17 +222,14 @@ export const contacsBulkInsertOnQueue = async (req: Request, res: Response): Pro
adminId: adminId,
identifier: identifier,
queueStatus: queueStatus,
file: file
file: file,
campaign
}
});
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" });
};

View File

@ -3,37 +3,44 @@ import { Server } from "http";
import AppError from "../errors/AppError";
import { logger } from "../utils/logger";
import { v4 as uuidv4 } from 'uuid';
import { v4 as uuidv4 } from "uuid";
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
import { addHours, addMinutes, addSeconds, intervalToDuration, add } from "date-fns";
import {
addHours,
addMinutes,
addSeconds,
intervalToDuration,
add
} from "date-fns";
let io: SocketIO;
//test del
import createOrUpdateOnlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
import { splitDateTime } from "../helpers/SplitDateTime";
import format from 'date-fns/format';
import ptBR from 'date-fns/locale/pt-BR';
import format from "date-fns/format";
import ptBR from "date-fns/locale/pt-BR";
import ListUserOnlineOffline from "../services/UserServices/ListUsersOnlineOfflineService";
import { handleMessage, handleMsgAck } from "../services/WbotServices/wbotMessageListener";
import {
handleMessage,
handleMsgAck
} from "../services/WbotServices/wbotMessageListener";
import { join } from "path";
import Whatsapp from "../models/Whatsapp";
let count: number = 0
let listOnline: any[] = []
let listOnlineAux: any[] = []
let countOnline: number = 0
let obj: any = { listOnline: [], uuid: null, listOnlineAux: [] }
let count: number = 0;
let listOnline: any[] = [];
let listOnlineAux: any[] = [];
let countOnline: number = 0;
let obj: any = { listOnline: [], uuid: null, listOnlineAux: [] };
let lstOnline: any[] = [];
let lstOnlineAux: any[] = [];
let lstTry: any[] = [];
let lstOnline: any[] = []
let lstOnlineAux: any[] = []
let lstTry: any[] = []
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
let dateTime = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
);
export const initIO = (httpServer: Server): SocketIO => {
io = new SocketIO(httpServer, {
@ -43,180 +50,157 @@ export const initIO = (httpServer: Server): SocketIO => {
maxHttpBufferSize: 1e8
});
io.on("connection", socket => {
logger.info("Client Connected");
socket.on("joinWhatsSession", (whatsappId: string) => {
logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`);
socket.join(`session_${whatsappId}`);
});
socket.on("message_from_client", () => {
socket.emit('message_from_server', 'Sent an event from the server!');
})
socket.on("message_create", async (data: any) => {
handleMessage(data.msg, data);
socket.emit("message_from_server", "Sent an event from the server!");
});
socket.on("message_create", async (data: any) => {
handleMessage(data.msg, data);
});
socket.on("media_uploaded", async (data: any) => {
handleMessage(data.msg, data);
});
socket.on("message_ack", async (data: any) => {
handleMsgAck(data.id, data.ack)
handleMsgAck(data.id, data.ack);
});
socket.on("campaign_message_sent", async (data: any) => {
console.log("campaign_message_sent: ", data);
const io = getIO();
let campaign = {};
if (data?.read) {
campaign = {
id: data.id,
read: data.read
};
} else if (data?.sent) {
campaign = {
id: data.id,
sent: data.sent
};
} else if (data?.status) {
campaign = {
id: data.id,
status: data.status
};
}
io.emit("campaign", {
action: "update",
campaign
});
});
socket.on("online", (userId: any) => {
// console.log('userId: ', userId)
obj.uuid = uuidv4()
obj.uuid = uuidv4();
if (userId.logoutUserId) {
let index = lstOnline.findIndex((x: any) => x.id == userId.logoutUserId)
let index = lstOnline.findIndex(
(x: any) => x.id == userId.logoutUserId
);
if (index != -1) {
lstOnline.splice(index, 1)
lstOnline.splice(index, 1);
}
index = lstOnlineAux.findIndex((x: any) => x.id == userId.logoutUserId)
index = lstOnlineAux.findIndex((x: any) => x.id == userId.logoutUserId);
if (index != -1) {
lstOnlineAux.splice(index, 1)
lstOnlineAux.splice(index, 1);
}
return
return;
}
if (lstOnline.length == 0) {
const index = listOnlineAux.findIndex((e: any) => e.id == userId)
const index = listOnlineAux.findIndex((e: any) => e.id == userId);
if (index == -1) {
listOnlineAux.push({ 'id': userId })
}
else {
return
listOnlineAux.push({ id: userId });
} else {
return;
}
lstOnline.push({ 'id': userId, 'status': 'online', 'try': 0 })
lstOnline.push({ id: userId, status: "online", try: 0 });
lstOnlineAux.push({ 'id': userId })
console.log(' 1 PUSHED NEW USER ID 1: ', userId)
lstOnlineAux.push({ id: userId });
console.log(" 1 PUSHED NEW USER ID 1: ", userId);
obj.listOnline = lstOnline
}
else {
const indexAux = lstOnlineAux.findIndex((e: any) => e.id == userId)
obj.listOnline = lstOnline;
} else {
const indexAux = lstOnlineAux.findIndex((e: any) => e.id == userId);
if (indexAux == -1) {
lstOnlineAux.push({ 'id': userId })
lstOnlineAux.push({ id: userId });
}
const index = lstOnline.findIndex((e: any) => e.id == userId)
const index = lstOnline.findIndex((e: any) => e.id == userId);
if (index == -1) {
lstOnline.push({ id: userId, status: "online", try: 0 });
console.log(" 2 PUSHED NEW USER ID: ", userId);
lstOnline.push({ 'id': userId, 'status': 'online', 'try': 0 })
console.log(' 2 PUSHED NEW USER ID: ', userId)
obj.listOnline = lstOnline
}
else {
if (countOnline > (lstOnline.length - 1)) {
obj.listOnline = lstOnline;
} else {
if (countOnline > lstOnline.length - 1) {
lstOnline.forEach((x: any) => {
if (lstOnlineAux.map((e: any) => e.id).includes(x.id)) {
x.try = 0
x.status = 'online'
x.try = 0;
x.status = "online";
}
})
var difference = lstOnline.filter((x: any) => !lstOnlineAux.map((e: any) => e.id).includes(x.id));
});
var difference = lstOnline.filter(
(x: any) => !lstOnlineAux.map((e: any) => e.id).includes(x.id)
);
if (difference.length > 0) {
difference.forEach((e) => {
e.try += 1
difference.forEach(e => {
e.try += 1;
if (e.try > 1) {
e.status = 'waiting...'
e.status = "waiting...";
}
if (e.try > 3) {
const index = lstOnline.findIndex((x: any) => x.id == e.id)
const index = lstOnline.findIndex((x: any) => x.id == e.id);
if (index != -1) {
lstOnline.splice(index, 1);
}
}
});
}
obj.listOnline = lstOnline;
obj.listOnlineAux = lstOnlineAux;
lstOnline.splice(index, 1)
lstOnlineAux = [];
listOnlineAux = [];
countOnline = -1;
}
countOnline++;
}
}
})
}
obj.listOnline = lstOnline
obj.listOnlineAux = lstOnlineAux
lstOnlineAux = []
listOnlineAux = []
countOnline = -1
}
countOnline++
}
}
exports.ob = obj
exports.ob = obj;
});
socket.on("joinChatBox", (ticketId: string) => {
@ -239,49 +223,51 @@ export const initIO = (httpServer: Server): SocketIO => {
});
socket.on("disconnecting", async () => {
console.log('socket.rooms: ', socket.rooms); // the Set contains at least the socket ID
console.log("socket.rooms: ", socket.rooms); // the Set contains at least the socket ID
let rooms = socket.rooms
let rooms = socket.rooms;
console.log('rooms: ', rooms, ' | rooms.size: ', rooms.size)
console.log("rooms: ", rooms, " | rooms.size: ", rooms.size);
if(rooms && rooms.size==1) return
if(rooms && rooms.size==2 && !([...rooms][1].startsWith('session_'))) return
if (rooms && rooms.size == 1) return;
if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_"))
return;
let whatsappIds: any = await Whatsapp.findAll({ attributes: ['id'], raw: true })
let whatsappIds: any = await Whatsapp.findAll({
attributes: ["id"],
raw: true
});
if (whatsappIds && whatsappIds.length > 0) {
whatsappIds = whatsappIds.map((e: any) => `${e.id}`);
whatsappIds = whatsappIds.map((e: any) => `${e.id}`)
console.log(
"whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ",
whatsappIds
);
console.log('whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ',whatsappIds)
if (
rooms &&
rooms.size == 2 &&
[...rooms][1].startsWith("session_") &&
whatsappIds.includes([...rooms][1].replace("session_", ""))
) {
console.log([...rooms][1]);
if (rooms && rooms.size == 2 &&
[...rooms][1].startsWith('session_') &&
whatsappIds.includes([...rooms][1].replace('session_', ''))) {
let whatsappId = [...rooms][1].replace("session_", "");
console.log([...rooms][1])
let whatsappId = [...rooms][1].replace('session_', '')
const whatsapp = await Whatsapp.findByPk(whatsappId, {})
const whatsapp = await Whatsapp.findByPk(whatsappId, {});
if (whatsapp) {
await whatsapp.update({ status: 'OPENING' });
await whatsapp.update({ status: "OPENING" });
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
}
}
}
});
});
return io;
@ -294,12 +280,9 @@ export const getIO = (): SocketIO => {
return io;
};
function writeFileAsync(arg0: any, data: any, arg2: string) {
throw new Error("Function not implemented.");
}
// exports.listOnlineUsers = listUserId
// exports.listUserId

View File

@ -12,11 +12,11 @@ import { Can } from '../../components/Can'
import apiBroker from '../../services/apiBroker'
import Select from "@material-ui/core/Select"
import MenuItem from "@material-ui/core/MenuItem";
import MenuItem from "@material-ui/core/MenuItem"
import SelectField from "../../components/Report/SelectField"
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext";
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
import {
Dialog,
@ -74,13 +74,14 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
const initialState = {
name: '',
message: '',
status: 'pending',
whatsapp_sender: '',
csv_original_file_name: '',
}
const { user } = useContext(AuthContext)
const { whatsApps } = useContext(WhatsAppsContext);
const { whatsApps } = useContext(WhatsAppsContext)
console.log('------------> whatsApps: ', whatsApps)
@ -88,7 +89,7 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
// const [selectedQueueIds, setSelectedQueueIds] = useState([])
const [file, setFile] = useState()
const [selectedNumber, setSelectedNumber] = useState('');
const [selectedNumber, setSelectedNumber] = useState('')
const [itemHover, setItemHover] = useState(-1)
@ -175,6 +176,7 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
onClose()
setCampaign(initialState)
setSelectedNumber('')
setFile(null)
}
async function handleChange(event) {

View File

@ -2,7 +2,7 @@ import { toast } from "react-toastify";
import { i18n } from "../translate/i18n";
const toastError = err => {
const errorMsg = err.response?.data?.message || err.response.data.error;
const errorMsg = err.response?.data?.message || err?.response?.data?.error || `${err?.message}`;
if (errorMsg) {
if (i18n.exists(`backendErrors.${errorMsg}`)) {
toast.error(i18n.t(`backendErrors.${errorMsg}`), {

View File

@ -69,8 +69,14 @@ const reducer = (state, action) => {
const campaignIndex = state.findIndex((c) => c.id === campaign.id)
if (campaignIndex !== -1) {
state[campaignIndex] = campaign
state[campaignIndex] = { ...state[campaignIndex], ...campaign }
return [...state]
// state[campaignIndex] = campaign
// return [...state]
} else {
return [campaign, ...state]
}
@ -174,7 +180,7 @@ const Campaign = () => {
title: '',
message: '',
campaignId: '',
csv_original_file_name:'',
csv_original_file_name: '',
open: false,
}
const [confirmModalInfo, setConfirmModalInfo] = useState(
@ -203,6 +209,8 @@ const Campaign = () => {
}
})
console.log('data.campaign : ', data.campaign)
dispatch({ type: "LOAD_CAMPAIGNS", payload: data.campaign })
setLoading(false)
@ -284,6 +292,40 @@ const Campaign = () => {
setQrModalOpen(true)
}
const handleStart = async (campaign) => {
console.log('start')
try {
const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`)
console.log('==============> data.campaign: ', data.campaign)
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
toast.success('Campanha iniciada com sucesso')
} catch (err) {
toastError(err)
}
}
const handleStop = async (campaign) => {
console.log('stop')
try {
const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`)
console.log('==============> data.campaign: ', data.campaign)
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
toast.success('Campanha parada com sucesso')
} catch (err) {
toastError(err)
}
}
const handleCloseQrModal = useCallback(() => {
setSelectedCampaign(null)
setQrModalOpen(false)
@ -347,63 +389,28 @@ const Campaign = () => {
const renderActionButtons = (campaign) => {
return (
<Can
role={user.profile}
perform="connection-button:show"
yes={() => (
<>
{campaign.status === 'qrcode' && (
{campaign.status === 'stopped' && (
<Button
size="small"
variant="contained"
color="primary"
onClick={() => handleOpenQrModal(campaign)}
onClick={() => handleStart(campaign)}
>
{i18n.t('connections.buttons.qrcode')}
Start
</Button>
)}
{campaign.status === 'DISCONNECTED' && (
<>
{campaign.status === 'running' && (
<Button
size="small"
variant="outlined"
variant="contained"
color="primary"
onClick={() => handleStartWhatsAppSession(campaign.id)}
onClick={() => handleStop(campaign)}
>
{i18n.t('connections.buttons.tryAgain')}
</Button>{' '}
<Button
size="small"
variant="outlined"
color="secondary"
onClick={() => handleRequestNewQrCode(campaign.id)}
>
{i18n.t('connections.buttons.newQr')}
</Button>
</>
)}
{(campaign.status === 'CONNECTED' ||
campaign.status === 'PAIRING' ||
campaign.status === 'TIMEOUT') && (
<Button
size="small"
variant="outlined"
color="secondary"
onClick={() => {
handleOpenConfirmationModal('disconnect', campaign.id)
}}
>
{i18n.t('connections.buttons.disconnect')}
</Button>
)}
{campaign.status === 'OPENING' && (
<Button size="small" variant="outlined" disabled color="default">
{i18n.t('connections.buttons.connecting')}
Stop
</Button>
)}
</>
)}
/>
)
}
@ -483,6 +490,31 @@ const Campaign = () => {
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
if (data.action === 'update') {
if (String(data.insertOnQueue.adminId) === String(user.id)) {
if (data?.insertOnQueue?.campaign?.status === "stopped") {
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.insertOnQueue.campaign })
}
}
}
})
socket.on('campaign', (data) => {
console.log('------------> CAMPAIGN: ', data)
if (data.action === 'update') {
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
}
})
socket.on('diskSpaceMonit', (data) => {
if (data.action === 'update') {
setDiskSpaceInfo(data.diskSpace)
@ -560,30 +592,32 @@ const Campaign = () => {
<TableHead>
<TableRow>
<TableCell align="center">
Nome
Name
</TableCell>
<TableCell align="center">
Status
</TableCell>
<Can
role={user.profile}
perform="connection-button:show"
yes={() => (
<TableCell align="center">
{i18n.t('connections.table.session')}
Sent
</TableCell>
)}
/>
<TableCell align="center">
Whatsapp sender
Read
</TableCell>
<TableCell align="center">
Start/stop
</TableCell>
<TableCell align="center">
Sender
</TableCell>
<TableCell align="center">
Mensagem
Message
</TableCell>
<TableCell align="center">
@ -604,18 +638,20 @@ const Campaign = () => {
</TableCell>
<TableCell align="center">
Status
{campaign.status}
</TableCell>
<TableCell align="center">
{campaign.status === 'stopped' || campaign.status === 'running' || campaign.status === 'success' ? `${campaign.sent}/${campaign.all}` : '0/0'}
</TableCell>
<TableCell align="center">
{campaign.status === 'stopped' || campaign.status === 'running' || campaign.status === 'success' ? `${campaign.read}` : '0'}
</TableCell>
<Can
role={user.profile}
perform="connection-button:show"
yes={() => (
<TableCell align="center">
{renderActionButtons(campaign)}
</TableCell>
)}
/>
<TableCell align="center">
{campaign.whatsapp_sender}
@ -626,24 +662,8 @@ const Campaign = () => {
</TableCell>
<TableCell align="center">
<Can
role={user.profile}
perform="show-icon-edit-whatsapp"
yes={() => (
<div
style={{
margin: 0,
padding: 0,
border: 'none',
display: 'inline',
}}
>
{(settings &&
settings.length > 0 &&
getSettingValue('editURA') &&
getSettingValue('editURA') ===
'enabled') |
(user.profile === 'master') ? (
{campaign.status != 'success' && (
<IconButton
size="small"
onClick={() =>
@ -651,18 +671,9 @@ const Campaign = () => {
}
>
<Edit />
</IconButton>
) : (
<div></div>
)}
</div>
)}
/>
</IconButton>)}
<Can
role={user.profile}
perform="btn-remove-whatsapp"
yes={() => (
<IconButton
size="small"
onClick={(e) => {
@ -674,8 +685,6 @@ const Campaign = () => {
>
<DeleteOutline />
</IconButton>
)}
/>
</TableCell>