Finalização do modulo campanha

pull/21/head
adriano 2023-08-14 15:39:05 -03:00
parent 75eb24fe62
commit 5907fc6cb2
4 changed files with 149 additions and 299 deletions

View File

@ -75,7 +75,7 @@ export const initIO = (httpServer: Server): SocketIO => {
});
socket.on("campaign_message_sent", async (data: any) => {
console.log("campaign_message_sent: ", data);
// console.log("campaign_message_sent: ", data);
const io = getIO();

View File

@ -1,21 +1,19 @@
import React, { useState, useEffect, useContext, createContext } from 'react'
import React, { useState, useEffect, useContext, } from 'react'
import * as Yup from 'yup'
import { Formik, Form, Field } from 'formik'
import { Formik, Form, Field, } from 'formik'
import { toast } from 'react-toastify'
import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors'
import { AuthContext } from '../../context/Auth/AuthContext'
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 SelectField from "../../components/Report/SelectField"
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
import {
@ -25,15 +23,11 @@ import {
Button,
DialogActions,
CircularProgress,
TextField,
Switch,
FormControlLabel,
TextField,
} from '@material-ui/core'
import api from '../../services/api'
import { i18n } from '../../translate/i18n'
import toastError from '../../errors/toastError'
import QueueSelect from '../QueueSelect'
import toastError from '../../errors/toastError'
const useStyles = makeStyles((theme) => ({
root: {
@ -67,6 +61,23 @@ const SessionSchema = Yup.object().shape({
.min(2, 'Too Short!')
.max(100, 'Too Long!')
.required('Required'),
secondStart: Yup.number()
.required('Min time is required')
.min(3, 'Min time must be 3')
.max(3600, 'Min must be less than 3600'),
secondEnd: Yup.number()
.required('Max time is required')
.min(3, 'Min time must be 3')
.max(3600, 'Max must be less than 3600')
.test('higher-than-lower', 'Tempo final deve ser maior que tempo inicio!', function (
secondEnd
) {
const secondStart = this.resolve(Yup.ref('secondStart'))
return secondStart === undefined || secondEnd === undefined || secondEnd > secondStart
}),
})
const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
@ -77,27 +88,21 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
status: 'pending',
whatsapp_sender: '',
csv_original_file_name: '',
secondStart: '3',
secondEnd: '15',
textToSeconds: true,
}
const { user } = useContext(AuthContext)
const { whatsApps } = useContext(WhatsAppsContext)
console.log('------------> whatsApps: ', whatsApps)
const { whatsApps } = useContext(WhatsAppsContext)
const [campaign, setCampaign] = useState(initialState)
// const [selectedQueueIds, setSelectedQueueIds] = useState([])
const [file, setFile] = useState()
const [selectedNumber, setSelectedNumber] = useState('')
const [itemHover, setItemHover] = useState(-1)
useEffect(() => {
console.log('selectedNumber: ', selectedNumber)
}, [selectedNumber])
useEffect(() => {
const fetchSession = async () => {
@ -122,7 +127,7 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
}
}
fetchSession()
}, [campaignId])
}, [campaignId, user.id])
const handleSaveCampaign = async (values) => {
let response = null
@ -135,6 +140,9 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
formData.append('file', file)
formData.append('name', values.name)
formData.append('whatsapp_sender', selectedNumber)
formData.append('secondStart', values.secondStart)
formData.append('secondEnd', values.secondEnd)
formData.append('textToSeconds', values.textToSeconds)
formData.append('message', values.message)
formData.append('csv_original_file_name', file?.name)
@ -185,15 +193,15 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
alert('Arquivo não pode ser maior que 4 MB!')
return
}
console.log('event.target.files[0]: ', event.target.files[0])
setFile(event.target.files[0])
} catch (err) {
toastError(err)
}
}
return (
<div className={classes.root}>
<Dialog
@ -221,51 +229,41 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
<Form>
<DialogContent dividers>
<Can
role={user.profile}
perform="url-remote-session:show"
yes={() => (
<>
<div>
<div className={classes.multFieldLine}>
<Field
as={TextField}
label={i18n.t('whatsappModal.form.name')}
autoFocus
name="name"
error={touched.name && Boolean(errors.name)}
helperText={touched.name && errors.name}
variant="outlined"
margin="dense"
className={classes.textField}
/>
<div>
<div className={classes.multFieldLine}>
<Field
as={TextField}
label={i18n.t('whatsappModal.form.name')}
autoFocus
name="name"
error={touched.name && Boolean(errors.name)}
helperText={touched.name && errors.name}
variant="outlined"
margin="dense"
className={classes.textField}
/>
<Select
value={selectedNumber}
onChange={(e) => setSelectedNumber(e.target.value)}
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
required
>
<MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem>
{whatsApps.map((whatsapp) => (
<MenuItem
key={whatsapp.id}
value={whatsapp.number}
onMouseEnter={() => setItemHover(whatsapp.id)}
onMouseLeave={() => setItemHover(-1)}
>{whatsapp.number}
</MenuItem>
))}
</Select>
</div>
<Select
value={selectedNumber}
onChange={(e) => setSelectedNumber(e.target.value)}
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
required
>
<MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem>
{whatsApps.map((whatsapp) => (
<MenuItem
key={whatsapp.id}
value={whatsapp.number}
>{whatsapp.number}
</MenuItem>
))}
</Select>
</div>
<div className={classes.multFieldLine}>
<div className={classes.multFieldLine}>
</div>
</div>
</>
)}
/>
</div>
</div>
<div>
<Field
@ -309,6 +307,39 @@ const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
<h3>{file?.name || campaign?.csv_original_file_name}</h3>
</div>
<div className={classes.multFieldLine} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Field
as={TextField}
label='Inicio em segundos'
autoFocus
name="secondStart"
error={touched.secondStart && Boolean(errors.secondStart)}
helperText={touched.secondStart && errors.secondStart}
variant="outlined"
margin="dense"
className={classes.textField}
/>
<Field
as={TextField}
label='Fim em segundos'
autoFocus
name="secondEnd"
error={touched.secondEnd && Boolean(errors.secondEnd)}
helperText={touched.secondEnd && errors.secondEnd}
variant="outlined"
margin="dense"
className={classes.textField}
/>
<label>
<Field type="checkbox" name="textToSeconds"/>
Tamanho do texto para segundos
</label>
</div>
</DialogContent>
<DialogActions>
<Button

View File

@ -9,7 +9,10 @@ import Divider from '@material-ui/core/Divider'
import { Badge } from '@material-ui/core'
import DashboardOutlinedIcon from '@material-ui/icons/DashboardOutlined'
import ReportOutlinedIcon from '@material-ui/icons/ReportOutlined'
import ReportOutlinedIcon from '@material-ui/icons/ReportOutlined'
import CampaignIcon from '@material-ui/icons/Send';
import SendOutlined from '@material-ui/icons/SendOutlined'
//import ReportOutlined from "@bit/mui-org.material-ui-icons.report-outlined";
@ -145,7 +148,7 @@ const MainListItems = (props) => {
<ListItemLink
to="/campaign"
primary="Campanha"
icon={<ReportOutlinedIcon />}
icon={<CampaignIcon />}
/>
<Can

View File

@ -1,6 +1,5 @@
import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react'
import { toast } from 'react-toastify'
import { format, parseISO } from 'date-fns'
import { toast } from 'react-toastify'
import openSocket from 'socket.io-client'
@ -14,19 +13,11 @@ import {
IconButton,
Table,
TableHead,
Paper,
Tooltip,
Typography,
CircularProgress,
Paper,
} from '@material-ui/core'
import {
Edit,
CheckCircle,
SignalCellularConnectedNoInternet2Bar,
SignalCellularConnectedNoInternet0Bar,
SignalCellular4Bar,
CropFree,
DeleteOutline,
Edit,
DeleteOutline,
// Restore
} from '@material-ui/icons'
@ -61,9 +52,7 @@ const reducer = (state, action) => {
const campaigns = action.payload
return [...state, ...campaigns]
}
if (action.type === "UPDATE_CAMPAIGNS") {
console.log('STATE: ', state)
if (action.type === "UPDATE_CAMPAIGNS") {
const campaign = action.payload
const campaignIndex = state.findIndex((c) => c.id === campaign.id)
@ -121,31 +110,7 @@ const useStyles = makeStyles((theme) => ({
buttonProgress: {
color: green[500],
},
}))
const CustomToolTip = ({ title, content, children }) => {
const classes = useStyles()
return (
<Tooltip
arrow
classes={{
tooltip: classes.tooltip,
popper: classes.tooltipPopper,
}}
title={
<React.Fragment>
<Typography gutterBottom color="inherit">
{title}
</Typography>
{content && <Typography>{content}</Typography>}
</React.Fragment>
}
>
{children}
</Tooltip>
)
}
}))
const Campaign = () => {
//--------
@ -153,24 +118,14 @@ const Campaign = () => {
const classes = useStyles()
// const { whatsApps } = useContext(WhatsAppsContext)
// console.log('------------> whatsApps: ', whatsApps)
// const { whatsApps } = useContext(WhatsAppsContext)
// const { campaigns, loading } = useContext(WhatsAppsContext)
const [campaignModalOpen, setCampaignModalOpen] = useState(false)
const [qrModalOpen, setQrModalOpen] = useState(false)
const [selectedCampaign, setSelectedCampaign] = useState(null)
const [confirmModalOpen, setConfirmModalOpen] = useState(false)
const [diskSpaceInfo, setDiskSpaceInfo] = useState({})
const [disabled, setDisabled] = useState(true)
const [settings, setSettings] = useState([])
const [buttons, setClicks] = useState([])
const [campaigns, dispatch] = useReducer(reducer, [])
const [loading, setLoading] = useState(true)
@ -198,8 +153,7 @@ const Campaign = () => {
const delayDebounceFn = setTimeout(() => {
const fetchContacts = async () => {
try {
console.log('process.env.REACT_APP_BACKEND_URL_PRIVATE: ', process.env.REACT_APP_BACKEND_URL_PRIVATE)
try {
const { data } = await apiBroker.get('/campaign', {
params: {
@ -207,9 +161,7 @@ const Campaign = () => {
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
identifier: 'campaign'
}
})
console.log('data.campaign : ', data.campaign)
})
dispatch({ type: "LOAD_CAMPAIGNS", payload: data.campaign })
setLoading(false)
@ -222,7 +174,7 @@ const Campaign = () => {
fetchContacts()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [])
}, [user.id])
useEffect(() => {
const fetchSession = async () => {
@ -245,37 +197,8 @@ const Campaign = () => {
}
}
fetchSession()
}, [])
const getSettingValue = (key) => {
const { value } = settings.find((s) => s.key === key)
return value
}
const handleStartWhatsAppSession = async (campaignId) => {
try {
await api.post(`/whatsappsession/${campaignId}`)
} catch (err) {
toastError(err)
}
}
// useEffect(() => {
// for (let i = 0; i < campaigns.length; i++) {
// if (buttons.includes(campaigns[i].id)) {
// campaigns[i].disabled = true
// }
// }
// }, [campaigns, buttons])
const handleRequestNewQrCode = async (campaignId) => {
try {
await api.put(`/whatsappsession/${campaignId}`)
} catch (err) {
toastError(err)
}
}
}, [])
const handleOpenCampaignModal = () => {
setSelectedCampaign(null)
@ -285,20 +208,12 @@ const Campaign = () => {
const handleCloseCampaignModal = useCallback(() => {
setCampaignModalOpen(false)
setSelectedCampaign(null)
}, [setSelectedCampaign, setCampaignModalOpen])
}, [setSelectedCampaign, setCampaignModalOpen])
const handleOpenQrModal = (campaign) => {
setSelectedCampaign(campaign)
setQrModalOpen(true)
}
const handleStart = async (campaign) => {
console.log('start')
const handleStart = async (campaign) => {
try {
const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`)
console.log('==============> data.campaign: ', data.campaign)
const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`)
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
@ -309,13 +224,10 @@ const Campaign = () => {
}
}
const handleStop = async (campaign) => {
console.log('stop')
const handleStop = async (campaign) => {
try {
const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`)
console.log('==============> data.campaign: ', data.campaign)
const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`)
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
@ -412,80 +324,7 @@ const Campaign = () => {
)}
</>
)
}
const renderStatusToolTips = (campaign) => {
return (
<div className={classes.customTableCell}>
{campaign.status === 'DISCONNECTED' && (
<CustomToolTip
title={i18n.t('connections.toolTips.disconnected.title')}
content={i18n.t('connections.toolTips.disconnected.content')}
>
<SignalCellularConnectedNoInternet0Bar color="secondary" />
</CustomToolTip>
)}
{campaign.status === 'OPENING' && (
<CircularProgress size={24} className={classes.buttonProgress} />
)}
{campaign.status === 'qrcode' && (
<CustomToolTip
title={i18n.t('connections.toolTips.qrcode.title')}
content={i18n.t('connections.toolTips.qrcode.content')}
>
<CropFree />
</CustomToolTip>
)}
{campaign.status === 'CONNECTED' && (
<CustomToolTip title={i18n.t('connections.toolTips.connected.title')}>
<SignalCellular4Bar style={{ color: green[500] }} />
</CustomToolTip>
)}
{(campaign.status === 'TIMEOUT' || campaign.status === 'PAIRING') && (
<CustomToolTip
title={i18n.t('connections.toolTips.timeout.title')}
content={i18n.t('connections.toolTips.timeout.content')}
>
<SignalCellularConnectedNoInternet2Bar color="secondary" />
</CustomToolTip>
)}
{/* {campaign.status === "RESTORING" && (
<CustomToolTip
title={i18n.t("connections.toolTips.disconnected.title")}
content={i18n.t("connections.toolTips.disconnected.content")}
>
<Restore color="secondary" />
</CustomToolTip>
)} */}
</div>
)
}
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
const fetchQueries = async () => {
try {
await api.post(`/restartwhatsappsession/0`, {
params: { status: 'status' },
})
setDisabled(false)
setClicks((buttons) =>
buttons.map((e) => {
return { id: e.id, disabled: false }
})
)
} catch (err) {
console.log(err)
}
}
fetchQueries()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [])
}
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
@ -506,36 +345,19 @@ const Campaign = () => {
}
})
socket.on('campaign', (data) => {
console.log('------------> CAMPAIGN: ', data)
socket.on('campaign', (data) => {
if (data.action === 'update') {
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
}
})
})
socket.on('diskSpaceMonit', (data) => {
if (data.action === 'update') {
setDiskSpaceInfo(data.diskSpace)
}
})
socket.on('settings', (data) => {
if (data.action === 'update') {
setSettings((prevState) => {
const aux = [...prevState]
const settingIndex = aux.findIndex((s) => s.key === data.setting.key)
aux[settingIndex].value = data.setting.value
return aux
})
}
})
return () => {
socket.disconnect()
}
}, [])
}, [user.id])
return (
<Can
@ -569,20 +391,13 @@ const Campaign = () => {
<Title>Campanhas</Title>
<MainHeaderButtonsWrapper>
<Can
role={user.profile}
perform="btn-add-whatsapp"
updatedAt
yes={() => (
<Button
variant="contained"
color="primary"
onClick={handleOpenCampaignModal}
>
criar campanha
</Button>
)}
/>
<Button
variant="contained"
color="primary"
onClick={handleOpenCampaignModal}
>
criar campanha
</Button>
</MainHeaderButtonsWrapper>
</MainHeader>
@ -661,17 +476,17 @@ const Campaign = () => {
{campaign.message}
</TableCell>
<TableCell align="center">
{campaign.status !== 'running' ? <TableCell align="center">
{campaign.status != 'success' && (
<IconButton
size="small"
onClick={() =>
handleEditCampaign(campaign)
}
>
<Edit />
</IconButton>)}
{campaign.status !== 'success' && (
<IconButton
size="small"
onClick={() =>
handleEditCampaign(campaign)
}
>
<Edit />
</IconButton>)}
<IconButton
@ -685,7 +500,8 @@ const Campaign = () => {
>
<DeleteOutline />
</IconButton>
</TableCell>
</TableCell> : <TableCell align="center"></TableCell>}
</TableRow>