projeto-hit/frontend/src/pages/Campaign/index.js

706 lines
24 KiB
JavaScript
Raw Normal View History

import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react'
import { toast } from 'react-toastify'
import { format, parseISO } from 'date-fns'
import openSocket from 'socket.io-client'
import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors'
import {
Button,
TableBody,
TableRow,
TableCell,
IconButton,
Table,
TableHead,
Paper,
Tooltip,
Typography,
CircularProgress,
} from '@material-ui/core'
import {
Edit,
CheckCircle,
SignalCellularConnectedNoInternet2Bar,
SignalCellularConnectedNoInternet0Bar,
SignalCellular4Bar,
CropFree,
DeleteOutline,
// Restore
} from '@material-ui/icons'
import MainContainer from '../../components/MainContainer'
import MainHeader from '../../components/MainHeader'
import MainHeaderButtonsWrapper from '../../components/MainHeaderButtonsWrapper'
import Title from '../../components/Title'
import TableRowSkeleton from '../../components/TableRowSkeleton'
import api from '../../services/api'
import CampaignModal from '../../components/CampaignModal'
import ConfirmationModal from '../../components/ConfirmationModal'
import QrcodeModal from '../../components/QrcodeModal'
import { i18n } from '../../translate/i18n'
// import { WhatsAppsContext } from '../../context/WhatsApp/WhatsAppsContext'
import toastError from '../../errors/toastError'
//--------
import { AuthContext } from '../../context/Auth/AuthContext'
import { Can } from '../../components/Can'
import apiBroker from '../../services/apiBroker'
const reducer = (state, action) => {
if (action.type === "LOAD_CAMPAIGNS") {
const campaigns = action.payload
return [...state, ...campaigns]
}
if (action.type === "UPDATE_CAMPAIGNS") {
console.log('STATE: ', state)
const campaign = action.payload
const campaignIndex = state.findIndex((c) => c.id === campaign.id)
if (campaignIndex !== -1) {
2023-08-14 09:48:39 +00:00
state[campaignIndex] = { ...state[campaignIndex], ...campaign }
return [...state]
2023-08-14 09:48:39 +00:00
// state[campaignIndex] = campaign
// return [...state]
} else {
return [campaign, ...state]
}
}
if (action.type === "DELETE_CAMPAIGN") {
const campaignId = action.payload
const campaignIndex = state.findIndex((c) => c.id === campaignId)
if (campaignIndex !== -1) {
state.splice(campaignIndex, 1)
}
return [...state]
}
if (action.type === "RESET") {
return []
}
}
const useStyles = makeStyles((theme) => ({
mainPaper: {
flex: 1,
padding: theme.spacing(1),
overflowY: 'scroll',
...theme.scrollbarStyles,
},
customTableCell: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
tooltip: {
backgroundColor: '#f5f5f9',
color: 'rgba(0, 0, 0, 0.87)',
fontSize: theme.typography.pxToRem(14),
border: '1px solid #dadde9',
maxWidth: 450,
},
tooltipPopper: {
textAlign: 'center',
},
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 = () => {
//--------
const { user } = useContext(AuthContext)
const classes = useStyles()
// const { whatsApps } = useContext(WhatsAppsContext)
// console.log('------------> whatsApps: ', whatsApps)
// 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)
const confirmationModalInitialState = {
action: '',
title: '',
message: '',
campaignId: '',
2023-08-14 09:48:39 +00:00
csv_original_file_name: '',
open: false,
}
const [confirmModalInfo, setConfirmModalInfo] = useState(
confirmationModalInitialState
)
useEffect(() => {
dispatch({ type: "RESET" })
}, [])
useEffect(() => {
setLoading(true)
const delayDebounceFn = setTimeout(() => {
const fetchContacts = async () => {
try {
console.log('process.env.REACT_APP_BACKEND_URL_PRIVATE: ', process.env.REACT_APP_BACKEND_URL_PRIVATE)
const { data } = await apiBroker.get('/campaign', {
params: {
adminId: user.id,
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
identifier: 'campaign'
}
})
2023-08-14 09:48:39 +00:00
console.log('data.campaign : ', data.campaign)
dispatch({ type: "LOAD_CAMPAIGNS", payload: data.campaign })
setLoading(false)
} catch (err) {
toastError(err)
}
}
fetchContacts()
}, 500)
return () => clearTimeout(delayDebounceFn)
}, [])
useEffect(() => {
const fetchSession = async () => {
try {
// const test = await apiBroker.get('/contacts/status/insert/onqueue', {
// params: {
// adminId: user.id,
// baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
// identifier: 'campaign',
// },
// })
// console.log('-------------------> test: ', test)
// const { data } = await api.get('/settings')
// setSettings(data)
} catch (err) {
toastError(err)
}
}
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)
setCampaignModalOpen(true)
}
const handleCloseCampaignModal = useCallback(() => {
setCampaignModalOpen(false)
setSelectedCampaign(null)
}, [setSelectedCampaign, setCampaignModalOpen])
const handleOpenQrModal = (campaign) => {
setSelectedCampaign(campaign)
setQrModalOpen(true)
}
2023-08-14 09:48:39 +00:00
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)
}, [setQrModalOpen, setSelectedCampaign])
const handleEditCampaign = (campaign) => {
setSelectedCampaign(campaign)
setCampaignModalOpen(true)
}
const handleOpenConfirmationModal = (action, campaignId) => {
if (action === 'disconnect') {
setConfirmModalInfo({
action: action,
title: i18n.t('connections.confirmationModal.disconnectTitle'),
message: i18n.t('connections.confirmationModal.disconnectMessage'),
campaignId: campaignId,
})
}
if (action === 'delete') {
setConfirmModalInfo({
action: action,
title: i18n.t('connections.confirmationModal.deleteTitle'),
message: i18n.t('connections.confirmationModal.deleteMessage'),
campaignId: campaignId,
})
}
setConfirmModalOpen(true)
}
const handleSubmitConfirmationModal = async () => {
if (confirmModalInfo.action === 'disconnect') {
try {
await api.delete(`/whatsappsession/${confirmModalInfo.campaignId}`)
} catch (err) {
toastError(err)
}
}
if (confirmModalInfo.action === 'delete') {
2023-08-14 09:48:39 +00:00
try {
await apiBroker.delete(`/campaign/${confirmModalInfo.campaignId}`, {
params: {
adminId: user.id,
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
identifier: 'campaign',
},
})
2023-08-14 09:48:39 +00:00
dispatch({ type: "DELETE_CAMPAIGN", payload: confirmModalInfo.campaignId })
toast.success('Campanha deletada com sucesso')
} catch (err) {
toastError(err)
}
}
setConfirmModalInfo(confirmationModalInitialState)
}
const renderActionButtons = (campaign) => {
return (
2023-08-14 09:48:39 +00:00
<>
{campaign.status === 'stopped' && (
<Button
size="small"
variant="contained"
color="primary"
onClick={() => handleStart(campaign)}
>
Start
</Button>
)}
2023-08-14 09:48:39 +00:00
{campaign.status === 'running' && (
<Button
size="small"
variant="contained"
color="primary"
onClick={() => handleStop(campaign)}
>
Stop
</Button>
)}
</>
)
}
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)
2023-08-14 09:48:39 +00:00
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)
}
})
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()
}
}, [])
return (
<Can
role={user.profile}
perform="connections-view:show"
yes={() => (
<MainContainer>
<ConfirmationModal
title={confirmModalInfo.title}
open={confirmModalOpen}
onClose={setConfirmModalOpen}
onConfirm={handleSubmitConfirmationModal}
>
{confirmModalInfo.message}
</ConfirmationModal>
<QrcodeModal
open={qrModalOpen}
onClose={handleCloseQrModal}
campaignId={!campaignModalOpen && selectedCampaign?.id}
/>
<CampaignModal
open={campaignModalOpen}
onClose={handleCloseCampaignModal}
campaignId={selectedCampaign?.id}
dispatch={dispatch}
/>
<MainHeader>
<Title>Campanhas</Title>
<MainHeaderButtonsWrapper>
<Can
role={user.profile}
perform="btn-add-whatsapp"
updatedAt
yes={() => (
<Button
variant="contained"
color="primary"
onClick={handleOpenCampaignModal}
>
criar campanha
</Button>
)}
/>
</MainHeaderButtonsWrapper>
</MainHeader>
<Paper className={classes.mainPaper} variant="outlined">
<>
<Table size="small">
<TableHead>
<TableRow>
<TableCell align="center">
2023-08-14 09:48:39 +00:00
Name
</TableCell>
<TableCell align="center">
Status
</TableCell>
2023-08-14 09:48:39 +00:00
<TableCell align="center">
Sent
</TableCell>
<TableCell align="center">
Read
</TableCell>
<TableCell align="center">
Start/stop
</TableCell>
<TableCell align="center">
2023-08-14 09:48:39 +00:00
Sender
</TableCell>
<TableCell align="center">
2023-08-14 09:48:39 +00:00
Message
</TableCell>
<TableCell align="center">
{i18n.t('connections.table.actions')}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{loading ? (
<TableRowSkeleton />
) : (
<>
{campaigns?.length > 0 &&
campaigns.map((campaign) => (
<TableRow key={campaign.id}>
<TableCell align="center">
{campaign.name}
</TableCell>
<TableCell align="center">
2023-08-14 09:48:39 +00:00
{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>
2023-08-14 09:48:39 +00:00
<TableCell align="center">
{renderActionButtons(campaign)}
</TableCell>
<TableCell align="center">
{campaign.whatsapp_sender}
</TableCell>
<TableCell align="center">
{campaign.message}
</TableCell>
<TableCell align="center">
2023-08-14 09:48:39 +00:00
{campaign.status != 'success' && (
<IconButton
size="small"
onClick={() =>
handleEditCampaign(campaign)
}
>
<Edit />
</IconButton>)}
<IconButton
size="small"
onClick={(e) => {
handleOpenConfirmationModal(
'delete',
campaign.id
)
}}
>
<DeleteOutline />
</IconButton>
</TableCell>
</TableRow>
))}
</>
)}
</TableBody>
</Table>
</>
</Paper>
</MainContainer>
)}
/>
)
}
export default Campaign